Sun, 13 Mar 2016 20:54:42 +0100
Continued porting the web browser.
- continued porting the AdBlock code
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockDialog.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,325 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the AdBlock configuration dialog. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, Qt, QTimer, QCoreApplication +from PyQt5.QtWidgets import QDialog, QMenu, QToolButton + +from E5Gui import E5MessageBox + +from .Ui_AdBlockDialog import Ui_AdBlockDialog + +import UI.PixmapCache +import Preferences + + +class AdBlockDialog(QDialog, Ui_AdBlockDialog): + """ + Class implementing the AdBlock configuration dialog. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object (QWidget) + """ + super(AdBlockDialog, self).__init__(parent) + self.setupUi(self) + self.setWindowFlags(Qt.Window) + + self.iconLabel.setPixmap(UI.PixmapCache.getPixmap("adBlockPlus48.png")) + + self.updateSpinBox.setValue(Preferences.getHelp("AdBlockUpdatePeriod")) + + self.searchEdit.setInactiveText(self.tr("Search...")) + + from WebBrowser.WebBrowserWindow import WebBrowserWindow + self.__manager = WebBrowserWindow.adBlockManager() + self.adBlockGroup.setChecked(self.__manager.isEnabled()) + self.__manager.requiredSubscriptionLoaded.connect(self.addSubscription) + + self.__currentTreeWidget = None + self.__currentSubscription = None + self.__loaded = False + + menu = QMenu(self) + menu.aboutToShow.connect(self.__aboutToShowActionMenu) + self.actionButton.setMenu(menu) + self.actionButton.setIcon(UI.PixmapCache.getIcon("adBlockAction.png")) + self.actionButton.setPopupMode(QToolButton.InstantPopup) + + self.__load() + + self.buttonBox.setFocus() + + def __loadSubscriptions(self): + """ + Private slot to load the AdBlock subscription rules. + """ + for index in range(self.subscriptionsTabWidget.count()): + tree = self.subscriptionsTabWidget.widget(index) + tree.refresh() + + def __load(self): + """ + Private slot to populate the tab widget with subscriptions. + """ + if self.__loaded or not self.adBlockGroup.isChecked(): + return + + from .AdBlockTreeWidget import AdBlockTreeWidget + for subscription in self.__manager.subscriptions(): + tree = AdBlockTreeWidget(subscription, self.subscriptionsTabWidget) + if subscription.isEnabled(): + icon = UI.PixmapCache.getIcon("adBlockPlus.png") + else: + icon = UI.PixmapCache.getIcon("adBlockPlusDisabled.png") + self.subscriptionsTabWidget.addTab( + tree, icon, subscription.title()) + + self.__loaded = True + QCoreApplication.processEvents() + + QTimer.singleShot(50, self.__loadSubscriptions) + + def addSubscription(self, subscription, refresh=True): + """ + Public slot adding a subscription to the list. + + @param subscription reference to the subscription to be + added (AdBlockSubscription) + @param refresh flag indicating to refresh the tree (boolean) + """ + from .AdBlockTreeWidget import AdBlockTreeWidget + tree = AdBlockTreeWidget(subscription, self.subscriptionsTabWidget) + index = self.subscriptionsTabWidget.insertTab( + self.subscriptionsTabWidget.count() - 1, tree, + subscription.title()) + self.subscriptionsTabWidget.setCurrentIndex(index) + QCoreApplication.processEvents() + if refresh: + tree.refresh() + self.__setSubscriptionEnabled(subscription, True) + + def __aboutToShowActionMenu(self): + """ + Private slot to show the actions menu. + """ + subscriptionEditable = self.__currentSubscription and \ + self.__currentSubscription.canEditRules() + subscriptionRemovable = self.__currentSubscription and \ + self.__currentSubscription.canBeRemoved() + subscriptionEnabled = self.__currentSubscription and \ + self.__currentSubscription.isEnabled() + + menu = self.actionButton.menu() + menu.clear() + + menu.addAction(self.tr("Add Rule"), self.__addCustomRule)\ + .setEnabled(subscriptionEditable) + menu.addAction(self.tr("Remove Rule"), self.__removeCustomRule)\ + .setEnabled(subscriptionEditable) + menu.addSeparator() + menu.addAction( + self.tr("Browse Subscriptions..."), self.__browseSubscriptions) + menu.addAction( + self.tr("Remove Subscription"), self.__removeSubscription)\ + .setEnabled(subscriptionRemovable) + if self.__currentSubscription: + menu.addSeparator() + if subscriptionEnabled: + txt = self.tr("Disable Subscription") + else: + txt = self.tr("Enable Subscription") + menu.addAction(txt, self.__switchSubscriptionEnabled) + menu.addSeparator() + menu.addAction( + self.tr("Update Subscription"), self.__updateSubscription)\ + .setEnabled(not subscriptionEditable) + menu.addAction( + self.tr("Update All Subscriptions"), + self.__updateAllSubscriptions) + menu.addSeparator() + menu.addAction(self.tr("Learn more about writing rules..."), + self.__learnAboutWritingFilters) + + def addCustomRule(self, filter): + """ + Public slot to add a custom AdBlock rule. + + @param filter filter to be added (string) + """ + self.subscriptionsTabWidget.setCurrentIndex( + self.subscriptionsTabWidget.count() - 1) + self.__currentTreeWidget.addRule(filter) + + def __addCustomRule(self): + """ + Private slot to add a custom AdBlock rule. + """ + self.__currentTreeWidget.addRule() + + def __removeCustomRule(self): + """ + Private slot to remove a custom AdBlock rule. + """ + self.__currentTreeWidget.removeRule() + + def __updateSubscription(self): + """ + Private slot to update the selected subscription. + """ + self.__currentSubscription.updateNow() + + def __updateAllSubscriptions(self): + """ + Private slot to update all subscriptions. + """ + self.__manager.updateAllSubscriptions() + + def __browseSubscriptions(self): + """ + Private slot to browse the list of available AdBlock subscriptions. + """ + from WebBrowser.WebBrowserWindow import WebBrowserWindow + mw = WebBrowserWindow.mainWindow() + mw.newTab("http://adblockplus.org/en/subscriptions") + mw.raise_() + + def __learnAboutWritingFilters(self): + """ + Private slot to show the web page about how to write filters. + """ + from WebBrowser.WebBrowserWindow import WebBrowserWindow + mw = WebBrowserWindow.mainWindow() + mw.newTab("http://adblockplus.org/en/filters") + mw.raise_() + + def __removeSubscription(self): + """ + Private slot to remove the selected subscription. + """ + requiresTitles = [] + requiresSubscriptions = \ + self.__manager.getRequiresSubscriptions(self.__currentSubscription) + for subscription in requiresSubscriptions: + requiresTitles.append(subscription.title()) + if requiresTitles: + message = self.tr( + "<p>Do you really want to remove subscription" + " <b>{0}</b> and all subscriptions requiring it?</p>" + "<ul><li>{1}</li></ul>").format( + self.__currentSubscription.title(), + "</li><li>".join(requiresTitles)) + else: + message = self.tr( + "<p>Do you really want to remove subscription" + " <b>{0}</b>?</p>").format(self.__currentSubscription.title()) + res = E5MessageBox.yesNo( + self, + self.tr("Remove Subscription"), + message) + + if res: + removeSubscription = self.__currentSubscription + removeTrees = [self.__currentTreeWidget] + for index in range(self.subscriptionsTabWidget.count()): + tree = self.subscriptionsTabWidget.widget(index) + if tree.subscription() in requiresSubscriptions: + removeTrees.append(tree) + for tree in removeTrees: + self.subscriptionsTabWidget.removeTab( + self.subscriptionsTabWidget.indexOf(tree)) + self.__manager.removeSubscription(removeSubscription) + + def __switchSubscriptionEnabled(self): + """ + Private slot to switch the enabled state of the selected subscription. + """ + newState = not self.__currentSubscription.isEnabled() + self.__setSubscriptionEnabled(self.__currentSubscription, newState) + + def __setSubscriptionEnabled(self, subscription, enable): + """ + Private slot to set the enabled state of a subscription. + + @param subscription subscription to set the state for + (AdBlockSubscription) + @param enable state to set to (boolean) + """ + if enable: + # enable required one as well + sub = self.__manager.subscription(subscription.requiresLocation()) + requiresSubscriptions = [] if sub is None else [sub] + icon = UI.PixmapCache.getIcon("adBlockPlus.png") + else: + # disable dependent ones as well + requiresSubscriptions = \ + self.__manager.getRequiresSubscriptions(subscription) + icon = UI.PixmapCache.getIcon("adBlockPlusDisabled.png") + requiresSubscriptions.append(subscription) + for sub in requiresSubscriptions: + sub.setEnabled(enable) + + for index in range(self.subscriptionsTabWidget.count()): + tree = self.subscriptionsTabWidget.widget(index) + if tree.subscription() in requiresSubscriptions: + self.subscriptionsTabWidget.setTabIcon( + self.subscriptionsTabWidget.indexOf(tree), icon) + + @pyqtSlot(int) + def on_updateSpinBox_valueChanged(self, value): + """ + Private slot to handle changes of the update period. + + @param value update period (integer) + """ + if value != Preferences.getWebBrowser("AdBlockUpdatePeriod"): + Preferences.setWebBrowser("AdBlockUpdatePeriod", value) + + from WebBrowser.WebBrowserWindow import WebBrowserWindow + manager = WebBrowserWindow.adBlockManager() + for subscription in manager.subscriptions(): + subscription.checkForUpdate() + + @pyqtSlot(int) + def on_subscriptionsTabWidget_currentChanged(self, index): + """ + Private slot handling the selection of another tab. + + @param index index of the new current tab (integer) + """ + if index != -1: + self.__currentTreeWidget = \ + self.subscriptionsTabWidget.widget(index) + self.__currentSubscription = \ + self.__currentTreeWidget.subscription() + + @pyqtSlot(str) + def on_searchEdit_textChanged(self, filter): + """ + Private slot to set a new filter on the current widget. + + @param filter filter to be set (string) + """ + if self.__currentTreeWidget and self.adBlockGroup.isChecked(): + self.__currentTreeWidget.filterString(filter) + + @pyqtSlot(bool) + def on_adBlockGroup_toggled(self, state): + """ + Private slot handling the enabling/disabling of AdBlock. + + @param state state of the toggle (boolean) + """ + self.__manager.setEnabled(state) + + if state: + self.__load()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockDialog.ui Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,194 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AdBlockDialog</class> + <widget class="QDialog" name="AdBlockDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>650</width> + <height>600</height> + </rect> + </property> + <property name="windowTitle"> + <string>AdBlock Configuration</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QGroupBox" name="adBlockGroup"> + <property name="title"> + <string>Enable AdBlock</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <property name="horizontalSpacing"> + <number>20</number> + </property> + <item row="0" column="0" rowspan="2"> + <widget class="QLabel" name="iconLabel"> + <property name="minimumSize"> + <size> + <width>48</width> + <height>48</height> + </size> + </property> + <property name="text"> + <string notr="true">Icon</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="E5ClearableLineEdit" name="searchEdit"> + <property name="toolTip"> + <string>Enter search term for subscriptions and rules</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QTabWidget" name="subscriptionsTabWidget"> + <property name="documentMode"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QToolButton" name="actionButton"> + <property name="text"> + <string>Actions</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Default Update Period (days):</string> + </property> + </widget> + </item> + <item> + <widget class="QSpinBox" name="updateSpinBox"> + <property name="toolTip"> + <string>Enter the update period (1 to 14 days)</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string/> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>14</number> + </property> + <property name="value"> + <number>7</number> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5ClearableLineEdit</class> + <extends>QLineEdit</extends> + <header>E5Gui/E5LineEdit.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>adBlockGroup</tabstop> + <tabstop>searchEdit</tabstop> + <tabstop>subscriptionsTabWidget</tabstop> + <tabstop>actionButton</tabstop> + <tabstop>updateSpinBox</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AdBlockDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>252</x> + <y>445</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AdBlockDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>320</x> + <y>445</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockExceptionsDialog.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to configure the AdBlock exceptions. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import pyqtSlot, Qt +from PyQt5.QtWidgets import QDialog + +from .Ui_AdBlockExceptionsDialog import Ui_AdBlockExceptionsDialog + +import UI.PixmapCache + + +class AdBlockExceptionsDialog(QDialog, Ui_AdBlockExceptionsDialog): + """ + Class implementing a dialog to configure the AdBlock exceptions. + """ + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent widget (QWidget) + """ + super(AdBlockExceptionsDialog, self).__init__(parent) + self.setupUi(self) + self.setWindowFlags(Qt.Window) + + self.iconLabel.setPixmap( + UI.PixmapCache.getPixmap("adBlockPlusGreen48.png")) + + self.hostEdit.setInactiveText(self.tr("Enter host to be added...")) + + self.buttonBox.setFocus() + + def load(self, hosts): + """ + Public slot to load the list of excepted hosts. + + @param hosts list of excepted hosts + """ + self.hostList.clear() + self.hostList.addItems(hosts) + + @pyqtSlot(str) + def on_hostEdit_textChanged(self, txt): + """ + Private slot to handle changes of the host edit. + + @param txt text of the edit (string) + """ + self.addButton.setEnabled(bool(txt)) + + @pyqtSlot() + def on_addButton_clicked(self): + """ + Private slot to handle a click of the add button. + """ + self.hostList.addItem(self.hostEdit.text()) + self.hostEdit.clear() + + @pyqtSlot() + def on_hostList_itemSelectionChanged(self): + """ + Private slot handling a change of the number of selected items. + """ + self.deleteButton.setEnabled(len(self.hostList.selectedItems()) > 0) + + @pyqtSlot() + def on_deleteButton_clicked(self): + """ + Private slot handling a click of the delete button. + """ + for itm in self.hostList.selectedItems(): + row = self.hostList.row(itm) + removedItem = self.hostList.takeItem(row) + del removedItem + + def accept(self): + """ + Public slot handling the acceptance of the dialog. + """ + hosts = [] + for row in range(self.hostList.count()): + hosts.append(self.hostList.item(row).text()) + + from WebBrowser.WebBrowserWindow import WebBrowserWindow + WebBrowserWindow.adBlockManager().setExceptions(hosts) + + super(AdBlockExceptionsDialog, self).accept()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockExceptionsDialog.ui Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>AdBlockExceptionsDialog</class> + <widget class="QDialog" name="AdBlockExceptionsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>550</width> + <height>450</height> + </rect> + </property> + <property name="windowTitle"> + <string>AdBlock Exceptions</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" rowspan="2"> + <widget class="QLabel" name="iconLabel"> + <property name="minimumSize"> + <size> + <width>48</width> + <height>48</height> + </size> + </property> + <property name="text"> + <string notr="true">Icon</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>188</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="E5ClearableLineEdit" name="hostEdit"> + <property name="toolTip"> + <string>Enter a host to block AdBlock for</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QPushButton" name="addButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to add the host</string> + </property> + <property name="text"> + <string>&Add</string> + </property> + </widget> + </item> + <item row="2" column="0" rowspan="2" colspan="2"> + <widget class="QListWidget" name="hostList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QPushButton" name="deleteButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="toolTip"> + <string>Press to delete the selected hosts</string> + </property> + <property name="text"> + <string>&Delete</string> + </property> + </widget> + </item> + <item row="3" column="2"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>148</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>E5ClearableLineEdit</class> + <extends>QLineEdit</extends> + <header>E5Gui/E5LineEdit.h</header> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>hostEdit</tabstop> + <tabstop>addButton</tabstop> + <tabstop>hostList</tabstop> + <tabstop>deleteButton</tabstop> + <tabstop>buttonBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>AdBlockExceptionsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>AdBlockExceptionsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockIcon.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the AdBlock icon for the main window status bar. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QAction, QMenu + +from E5Gui.E5ClickableLabel import E5ClickableLabel + +import UI.PixmapCache + + +class AdBlockIcon(E5ClickableLabel): + """ + Class implementing the AdBlock icon for the main window status bar. + """ + def __init__(self, parent): + """ + Constructor + + @param parent reference to the parent widget (HelpWindow) + """ + super(AdBlockIcon, self).__init__(parent) + + self.__mw = parent + self.__menuAction = None + self.__enabled = False + + self.setMaximumHeight(16) + self.setCursor(Qt.PointingHandCursor) + self.setToolTip(self.tr( + "AdBlock lets you block unwanted content on web pages.")) + + self.clicked.connect(self.__showMenu) + + def setEnabled(self, enabled): + """ + Public slot to set the enabled state. + + @param enabled enabled state (boolean) + """ + self.__enabled = enabled + if enabled: + self.currentChanged() + else: + self.setPixmap( + UI.PixmapCache.getPixmap("adBlockPlusDisabled16.png")) + + def __createMenu(self, menu=None): + """ + Private slot to create the context menu. + + @param menu parent menu (QMenu) + """ + if menu is None: + menu = self.sender() + if menu is None: + return + + menu.clear() + + manager = self.__mw.adBlockManager() + + if manager.isEnabled(): + menu.addAction( + UI.PixmapCache.getIcon("adBlockPlusDisabled.png"), + self.tr("Disable AdBlock"), + self.__enableAdBlock).setData(False) + else: + menu.addAction( + UI.PixmapCache.getIcon("adBlockPlus.png"), + self.tr("Enable AdBlock"), + self.__enableAdBlock).setData(True) + menu.addSeparator() + if manager.isEnabled() and self.__mw.currentBrowser().url().host(): + if self.__isCurrentHostExcepted(): + menu.addAction( + UI.PixmapCache.getIcon("adBlockPlus.png"), + self.tr("Remove AdBlock Exception"), + self.__setException).setData(False) + else: + menu.addAction( + UI.PixmapCache.getIcon("adBlockPlusGreen.png"), + self.tr("Add AdBlock Exception"), + self.__setException).setData(True) + menu.addAction( + UI.PixmapCache.getIcon("adBlockPlusGreen.png"), + self.tr("AdBlock Exceptions..."), manager.showExceptionsDialog) + menu.addSeparator() + menu.addAction( + UI.PixmapCache.getIcon("adBlockPlus.png"), + self.tr("AdBlock Configuration..."), manager.showDialog) + + def menuAction(self): + """ + Public method to get a reference to the menu action. + + @return reference to the menu action (QAction) + """ + if not self.__menuAction: + self.__menuAction = QAction(self.tr("AdBlock")) + self.__menuAction.setMenu(QMenu()) + self.__menuAction.menu().aboutToShow.connect(self.__createMenu) + + if self.__enabled: + self.__menuAction.setIcon( + UI.PixmapCache.getIcon("adBlockPlus.png")) + else: + self.__menuAction.setIcon( + UI.PixmapCache.getIcon("adBlockPlusDisabled.png")) + + return self.__menuAction + + def __showMenu(self, pos): + """ + Private slot to show the context menu. + + @param pos position the context menu should be shown (QPoint) + """ + menu = QMenu() + self.__createMenu(menu) + menu.exec_(pos) + + def __enableAdBlock(self): + """ + Private slot to enable or disable AdBlock. + """ + act = self.sender() + if act is not None: + self.__mw.adBlockManager().setEnabled(act.data()) + + def __isCurrentHostExcepted(self): + """ + Private method to check, if the host of the current browser is + excepted. + + @return flag indicating an exception (boolean) + """ + browser = self.__mw.currentBrowser() + if browser is None: + return False + + urlHost = browser.page().url().host() + + return urlHost and \ + self.__mw.adBlockManager().isHostExcepted(urlHost) + + def currentChanged(self): + """ + Public slot to handle a change of the current browser tab. + """ + if self.__enabled: + if self.__isCurrentHostExcepted(): + self.setPixmap( + UI.PixmapCache.getPixmap("adBlockPlusGreen16.png")) + else: + self.setPixmap(UI.PixmapCache.getPixmap("adBlockPlus16.png")) + + def __setException(self): + """ + Private slot to add or remove the current host from the list of + exceptions. + """ + act = self.sender() + if act is not None: + urlHost = self.__mw.currentBrowser().url().host() + if act.data(): + self.__mw.adBlockManager().addException(urlHost) + else: + self.__mw.adBlockManager().removeException(urlHost) + self.currentChanged() + + def sourceChanged(self, browser, url): + """ + Public slot to handle URL changes. + + @param browser reference to the browser (HelpBrowser) + @param url new URL (QUrl) + """ + if browser == self.__mw.currentBrowser(): + self.currentChanged()
--- a/WebBrowser/AdBlock/AdBlockManager.py Sun Mar 13 14:56:13 2016 +0100 +++ b/WebBrowser/AdBlock/AdBlockManager.py Sun Mar 13 20:54:42 2016 +0100 @@ -11,9 +11,14 @@ import os -from PyQt5.QtCore import pyqtSignal, QObject, QUrl, QFile +from PyQt5.QtCore import pyqtSignal, QObject, QUrl, QUrlQuery, QFile, \ + QByteArray +from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInfo + +from E5Gui import E5MessageBox from .AdBlockSubscription import AdBlockSubscription +from .AdBlockUrlInterceptor import AdBlockUrlInterceptor from Utilities.AutoSaver import AutoSaver import Utilities @@ -56,6 +61,20 @@ bytes(self.__customSubscriptionUrl().toEncoded()).decode() self.rulesChanged.connect(self.__saveTimer.changeOccurred) + self.rulesChanged.connect(self.__rulesChanged) + + self.__interceptor = AdBlockUrlInterceptor(self) + + from WebBrowser.WebBrowserWindow import WebBrowserWindow + WebBrowserWindow.networkManager().installUrlInterceptor( + self.__interceptor) + + def __rulesChanged(self): + """ + Private slot handling a change of the AdBlock rules. + """ + from WebBrowser.WebBrowserWindow import WebBrowserWindow + WebBrowserWindow.mainWindow().reloadUserStyleSheet() def close(self): """ @@ -94,17 +113,61 @@ if enabled: self.__loadSubscriptions() self.rulesChanged.emit() -## -## def network(self): -## """ -## Public method to get a reference to the network block object. -## -## @return reference to the network block object (AdBlockNetwork) -## """ -## if self.__adBlockNetwork is None: -## from .AdBlockNetwork import AdBlockNetwork -## self.__adBlockNetwork = AdBlockNetwork(self) -## return self.__adBlockNetwork + + def block(self, info): + """ + Public method to check, if a request should be blocked. + + @param info request info aobject + @type QWebEngineUrlRequestInfo + @return flag indicating to block the request + @rtype bool + """ + urlString = bytes(info.requestUrl().toEncoded()).decode().lower() + urlDomain = info.requestUrl().host().lower() + urlScheme = info.requestUrl().scheme().lower() + refererHost = info.firstPartyUrl().host().lower() + + if not self.isEnabled() or not self.__canRunOnScheme(urlScheme): + return False + + if self.isHostExcepted(urlDomain) or self.isHostExcepted(refererHost): + return False + + res = False + + for subscription in self.subscriptions(): + if subscription.isEnabled(): + if subscription.adBlockDisabledForUrl(info.requestUrl()): + continue + + blockedRule = subscription.match(info, urlDomain, urlString) + if blockedRule: + res = True + if info.resourceType() == \ + QWebEngineUrlRequestInfo.ResourceTypeMainFrame: + url = QUrl("eric:adblock") + query = QUrlQuery() + query.addQueryItem("rule", blockedRule.filter()) + query.addQueryItem( + "subscription", blockedRule.subscription().title()) + url.setQuery(query) + info.redirect(url) + res = False + else: + info.block(True) + break + + return res + + def __canRunOnScheme(self, scheme): + """ + Private method to check, if AdBlock can be performed on the scheme. + + @param scheme scheme to check (string) + @return flag indicating, that AdBlock can be performed (boolean) + """ + return scheme not in ["data", "eric", "qthelp", "qrc", "file", "abp"] def page(self): """ @@ -218,6 +281,42 @@ except ValueError: pass + def addSubscriptionFromUrl(self, url): + """ + Public method to ad an AdBlock subscription given the abp URL: + + @param url URL to subscribe an AdBlock subscription + @type QUrl + @return flag indicating success + @rtype bool + """ + if url.path() != "subscribe": + return False + + title = QUrl.fromPercentEncoding( + QByteArray(QUrlQuery(url).queryItemValue("title").encode())) + if not title: + return False + + res = E5MessageBox.yesNo( + None, + self.tr("Subscribe?"), + self.tr( + """<p>Subscribe to this AdBlock subscription?</p>""" + """<p>{0}</p>""").format(title)) + if res: + from .AdBlockSubscription import AdBlockSubscription + from WebBrowser.WebBrowserWindow import WebBrowserWindow + + dlg = WebBrowserWindow.adBlockManager().showDialog() + subscription = AdBlockSubscription( + url, False, + WebBrowserWindow.adBlockManager()) + WebBrowserWindow.adBlockManager().addSubscription(subscription) + dlg.addSubscription(subscription, False) + dlg.setFocus() + dlg.raise_() + def addSubscription(self, subscription): """ Public method to add an AdBlock subscription. @@ -271,8 +370,13 @@ self.__loaded = True self.__enabled = Preferences.getWebBrowser("AdBlockEnabled") +## if (!m_enabled) { +## mApp->networkManager()->removeUrlInterceptor(m_interceptor); +## return; +## } if self.__enabled: self.__loadSubscriptions() +## mApp->networkManager()->installUrlInterceptor(m_interceptor); def __loadSubscriptions(self): """ @@ -362,23 +466,13 @@ self.__adBlockDialog.show() return self.__adBlockDialog - def showRule(self): - """ - Public slot to show an AdBlock rule. - """ - act = self.sender() - if act is not None: - rule = act.data() - if rule: - self.showDialog().showRule(rule) - def elementHidingRules(self): """ Public method to get the element hiding rules. @return element hiding rules (string) """ - if not self.__enabled: + if not self.isEnabled(): return "" rules = "" @@ -399,7 +493,7 @@ @param url URL to get hiding rules for (QUrl) @return element hiding rules (string) """ - if not self.__enabled: + if not self.isEnabled(): return "" rules = "" @@ -432,7 +526,7 @@ @param hosts list of excepted hosts (list of string) """ - self.__exceptedHosts = hosts[:] + self.__exceptedHosts = [host.lower() for host in hosts] Preferences.setWebBrowser("AdBlockExceptions", self.__exceptedHosts) def addException(self, host): @@ -441,6 +535,7 @@ @param host to be excepted (string) """ + host = host.lower() if host and host not in self.__exceptedHosts: self.__exceptedHosts.append(host) Preferences.setWebBrowser( @@ -452,6 +547,7 @@ @param host to be removed from the list of exceptions (string) """ + host = host.lower() if host in self.__exceptedHosts: self.__exceptedHosts.remove(host) Preferences.setWebBrowser( @@ -464,6 +560,7 @@ @param host host to check (string) @return flag indicating an exception (boolean) """ + host = host.lower() return host in self.__exceptedHosts def showExceptionsDialog(self):
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockRule.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,662 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2009 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing the AdBlock rule class. +""" + +from __future__ import unicode_literals + +import re + +from PyQt5.QtCore import Qt, QRegExp, QUrl +from PyQt5.QtNetwork import QNetworkRequest +from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInfo + + +def toSecondLevelDomain(url): + """ + Module function to get a second level domain from the given URL. + + @param url URL to extract domain from (QUrl) + @return name of second level domain (string) + """ + topLevelDomain = url.topLevelDomain() + urlHost = url.host() + + if not topLevelDomain or not urlHost: + return "" + + domain = urlHost[:len(urlHost) - len(topLevelDomain)] + if domain.count(".") == 0: + return urlHost + + while domain.count(".") != 0: + domain = domain[domain.find(".") + 1:] + + return domain + topLevelDomain + + +class AdBlockRule(object): + """ + Class implementing the AdBlock rule. + """ + def __init__(self, filter="", subscription=None): + """ + Constructor + + @param filter filter string of the rule (string) + @param subscription reference to the subscription object + (AdBlockSubscription) + """ + self.__subscription = subscription + + self.__regExp = QRegExp() + self.__options = [] + self.__blockedDomains = [] + self.__allowedDomains = [] + + self.__enabled = True + self.__cssRule = False + self.__exception = False + self.__internalDisabled = False + self.__domainRestricted = False + self.__useRegExp = False + self.__useDomainMatch = False + self.__useEndsMatch = False + self.__thirdParty = False + self.__thirdPartyException = False + self.__object = False + self.__objectException = False + self.__subdocument = False + self.__subdocumentException = False + self.__xmlhttprequest = False + self.__xmlhttprequestException = False + self.__document = False + self.__elemhide = False + self.__caseSensitivity = Qt.CaseInsensitive + self.__image = False + self.__imageException = False + self.__script = False + self.__scriptException = False + self.__stylesheet = False + self.__stylesheetException = False + self.__objectSubrequest = False + self.__objectSubrequestException = False + + self.setFilter(filter) + + def subscription(self): + """ + Public method to get the subscription this rule belongs to. + + @return subscription of the rule (AdBlockSubscription) + """ + return self.__subscription + + def filter(self): + """ + Public method to get the rule filter string. + + @return rule filter string (string) + """ + return self.__filter + + def setFilter(self, filter): + """ + Public method to set the rule filter string. + + @param filter rule filter string (string) + """ + self.__filter = filter + self.__parseFilter() + + def __parseFilter(self): + """ + Private method to parse the filter pattern. + """ + parsedLine = self.__filter + + # empty rule or just a comment + if not parsedLine.strip() or parsedLine.startswith(("!", "[Adblock")): + self.__enabled = False + return + + # CSS element hiding rule + if "##" in parsedLine or "#@#" in parsedLine: + self.__cssRule = True + pos = parsedLine.find("#") + + # domain restricted rule + if not parsedLine.startswith("##"): + domains = parsedLine[:pos] + self.__parseDomains(domains, ",") + + self.__exception = parsedLine[pos + 1] == "@" + + if self.__exception: + self.__cssSelector = parsedLine[pos + 3:] + else: + self.__cssSelector = parsedLine[pos + 2:] + # CSS rule cannot have more options -> stop parsing + return + + # Exception always starts with @@ + if parsedLine.startswith("@@"): + self.__exception = True + parsedLine = parsedLine[2:] + + # Parse all options following '$' character + optionsIndex = parsedLine.find("$") + if optionsIndex >= 0: + options = parsedLine[optionsIndex + 1:].split(",") + + handledOptions = 0 + for option in options: + if option.startswith("domain="): + self.__parseDomains(option[7:], "|") + handledOptions += 1 + elif option == "match-case": + self.__caseSensitivity = Qt.CaseSensitive + handledOptions += 1 + elif option.endswith("third-party"): + self.__thirdParty = True + self.__thirdPartyException = option.startswith("~") + handledOptions += 1 + elif option.endswith("object"): + self.__object = True + self.__objectException = option.startswith("~") + handledOptions += 1 + elif option.endswith("subdocument"): + self.__subdocument = True + self.__subdocumentException = option.startswith("~") + handledOptions += 1 + elif option.endswith("xmlhttprequest"): + self.__xmlhttprequest = True + self.__xmlhttprequestException = option.startswith("~") + handledOptions += 1 + elif option.endswith("image"): + self.__image = True + self.__imageException = option.startswith("~") + elif option.endswith("script"): + self.__script = True + self.__scriptException = option.startswith("~") + elif option.endswith("stylesheet"): + self.__stylesheet = True + self.__stylesheetException = option.startswith("~") + elif option.endswith("object-subrequest"): + self.__objectSubrequest = True + self.__objectSubrequestException = option.startswith("~") + elif option == "document" and self.__exception: + self.__document = True + handledOptions += 1 + elif option == "elemhide" and self.__exception: + self.__elemhide = True + handledOptions += 1 + elif option == "collapse": + # Hiding placeholders of blocked elements + handledOptions += 1 + + # If we don't handle all options, it's safer to just disable + # this rule + if handledOptions != len(options): + self.__internalDisabled = True + return + + parsedLine = parsedLine[:optionsIndex] + + # Rule is classic regexp + if parsedLine.startswith("/") and parsedLine.endswith("/"): + parsedLine = parsedLine[1:-1] + self.__useRegExp = True + self.__regExp = QRegExp(parsedLine, self.__caseSensitivity, + QRegExp.RegExp) + return + + # Remove starting / ending wildcards + if parsedLine.startswith("*"): + parsedLine = parsedLine[1:] + if parsedLine.endswith("*"): + parsedLine = parsedLine[:-1] + + # Fast string matching for domain can be used + if parsedLine.startswith("||") and \ + parsedLine.endswith("^") and \ + QRegExp("[/:?=&\\*]").indexIn(parsedLine) == -1: + parsedLine = parsedLine[2:-1] + self.__useDomainMatch = True + self.__matchString = parsedLine + return + + # If rule contains '|' only at the end, string matching can be used + if parsedLine.endswith("|") and \ + QRegExp("[\\^\\*]").indexIn(parsedLine) == -1 and \ + parsedLine.count("|") == 1: + parsedLine = parsedLine[:-1] + self.__useEndsMatch = True + self.__matchString = parsedLine + return + + # If there is still a wildcard (*) or separator (^) or (|), + # the rule must be modified to comply with QRegExp. + if "*" in parsedLine or "^" in parsedLine or "|" in parsedLine: + pattern = self.__convertPatternToRegExp(parsedLine) + self.__useRegExp = True + self.__regExp = QRegExp(pattern, self.__caseSensitivity, + QRegExp.RegExp) + return + + # no regexp required + self.__useRegExp = False + self.__matchString = parsedLine + + def __parseDomains(self, domains, separator): + """ + Private method to parse a string with a domain list. + + @param domains list of domains (string) + @param separator separator character used by the list (string) + """ + domainsList = domains.split(separator) + + for domain in domainsList: + if not domain: + continue + if domain.startswith("~"): + self.__blockedDomains.append(domain[1:]) + else: + self.__allowedDomains.append(domain) + + self.__domainRestricted = \ + bool(self.__blockedDomains) or bool(self.__allowedDomains) + + def networkMatch(self, request, domain, encodedUrl): + """ + Public method to check the rule for a match. + + @param request reference to the network request + @type QWebEngineUrlRequestInfo + @param domain domain name + @type str + @param encodedUrl string encoded URL to be checked + @type str + @return flag indicating a match + @rtype bool + """ + if self.__cssRule or not self.__enabled or self.__internalDisabled: + return False + + matched = False + + if self.__useRegExp: + matched = self.__regExp.indexIn(encodedUrl) != -1 + elif self.__useDomainMatch: + matched = domain.endswith(self.__matchString) + elif self.__useEndsMatch: + if self.__caseSensitivity == Qt.CaseInsensitive: + matched = encodedUrl.lower().endswith( + self.__matchString.lower()) + else: + matched = encodedUrl.endswith(self.__matchString) + else: + if self.__caseSensitivity == Qt.CaseInsensitive: + matched = self.__matchString.lower() in encodedUrl.lower() + else: + matched = self.__matchString in encodedUrl + + if matched: + # check domain restrictions + if self.__domainRestricted and \ + not self.matchDomain(request.firstPartyUrl().host()): + return False + + # check third-party restrictions + if self.__thirdParty and not self.matchThirdParty(request): + return False + + # check object restrictions + if self.__object and not self.matchObject(request): + return False + + # check subdocument restrictions + if self.__subdocument and not self.matchSubdocument(request): + return False + + # check xmlhttprequest restriction + if self.__xmlhttprequest and not self.matchXmlHttpRequest(request): + return False + + # check image restriction + if self.__image and not self.matchImage(request): + return False + + # check script restriction + if self.__script and not self.matchScript(request): + return False + + # check stylesheet restriction + if self.__stylesheet and not self.matchStyleSheet(request): + return False + + # check object-subrequest restriction + if self.__objectSubrequest and \ + not self.matchObjectSubrequest(request): + return False + + return matched + + def urlMatch(self, url): + """ + Public method to check an URL against the rule. + + @param url URL to check (QUrl) + @return flag indicating a match (boolean) + """ + if not self.__document and not self.__elemhide: + return False + + encodedUrl = bytes(url.toEncoded()).decode() + domain = url.host() + return self.networkMatch(QNetworkRequest(url), domain, encodedUrl) + + def matchDomain(self, domain): + """ + Public method to match a domain. + + @param domain domain name to check (string) + @return flag indicating a match (boolean) + """ + if not self.__enabled: + return False + + if not self.__domainRestricted: + return True + + if len(self.__blockedDomains) == 0: + for dom in self.__allowedDomains: + if domain.endswith(dom): + return True + elif len(self.__allowedDomains) == 0: + for dom in self.__blockedDomains: + if domain.endswith(dom): + return False + return True + else: + for dom in self.__blockedDomains: + if domain.endswith(dom): + return False + for dom in self.__allowedDomains: + if domain.endswith(dom): + return True + + return False + + def matchThirdParty(self, req): + """ + Public slot to match a third-party rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + # Third-party matching should be performed on second-level domains + firstPartyHost = toSecondLevelDomain(req.firstPartyUrl()) + host = toSecondLevelDomain(req.requestUrl()) + + match = firstPartyHost != host + + if self.__thirdPartyException: + return not match + else: + return match + + def matchObject(self, req): + """ + Public slot to match an object rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == QWebEngineUrlRequestInfo.ResourceTypeObject) + + if self.__objectException: + return not match + else: + return match + + def matchSubdocument(self, req): + """ + Public slot to match a sub-document rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == + QWebEngineUrlRequestInfo.ResourceTypeSubFrame) + + if self.__subdocumentException: + return not match + else: + return match + + def matchXmlHttpRequest(self, req): + """ + Public slot to match a XmlHttpRequest rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == QWebEngineUrlRequestInfo.ResourceTypeXhr) + + if self.__xmlhttprequestException: + return not match + else: + return match + + def matchImage(self, req): + """ + Public slot to match an Image rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == QWebEngineUrlRequestInfo.ResourceTypeImage) + + if self.__imageException: + return not match + else: + return match + + def matchScript(self, req): + """ + Public slot to match a Script rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == QWebEngineUrlRequestInfo.ResourceTypeScript) + + if self.__scriptException: + return not match + else: + return match + + def matchStyleSheet(self, req): + """ + Public slot to match a StyleSheet rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == + QWebEngineUrlRequestInfo.ResourceTypeStylesheet) + + if self.__stylesheetException: + return not match + else: + return match + + def matchObjectSubrequest(self, req): + """ + Public slot to match an Object Subrequest rule. + + @param req request object to check (QWebEngineUrlRequestInfo) + @return flag indicating a match (boolean) + """ + match = ( + req.resourceType() == + QWebEngineUrlRequestInfo.ResourceTypeSubResource) + + if self.__objectSubrequestException: + return not match + else: + return match + + def isException(self): + """ + Public method to check, if the rule defines an exception. + + @return flag indicating an exception (boolean) + """ + return self.__exception + + def setException(self, exception): + """ + Public method to set the rule's exception flag. + + @param exception flag indicating an exception rule (boolean) + """ + self.__exception = exception + + def isEnabled(self): + """ + Public method to check, if the rule is enabled. + + @return flag indicating enabled state (boolean) + """ + return self.__enabled + + def setEnabled(self, enabled): + """ + Public method to set the rule's enabled state. + + @param enabled flag indicating the new enabled state (boolean) + """ + self.__enabled = enabled + if not enabled: + self.__filter = "!" + self.__filter + else: + self.__filter = self.__filter[1:] + + def isCSSRule(self): + """ + Public method to check, if the rule is a CSS rule. + + @return flag indicating a CSS rule (boolean) + """ + return self.__cssRule + + def cssSelector(self): + """ + Public method to get the CSS selector of the rule. + + @return CSS selector (string) + """ + return self.__cssSelector + + def isDocument(self): + """ + Public method to check, if this is a document rule. + + @return flag indicating a document rule (boolean) + """ + return self.__document + + def isElementHiding(self): + """ + Public method to check, if this is an element hiding rule. + + @return flag indicating an element hiding rule (boolean) + """ + return self.__elemhide + + def isDomainRestricted(self): + """ + Public method to check, if this rule is restricted by domain. + + @return flag indicating a domain restriction (boolean) + """ + return self.__domainRestricted + + def isComment(self): + """ + Public method to check, if this is a comment. + + @return flag indicating a comment (boolean) + """ + return self.__filter.startswith("!") + + def isHeader(self): + """ + Public method to check, if this is a header. + + @return flag indicating a header (boolean) + """ + return self.__filter.startswith("[Adblock") + + def isSlow(self): + """ + Public method to check, if this is a slow rule. + + @return flag indicating a slow rule (boolean) + """ + return self.__useRegExp + + def isInternalDisabled(self): + """ + Public method to check, if this rule was disabled internally. + + @return flag indicating an internally disabled rule (boolean) + """ + return self.__internalDisabled + + def __convertPatternToRegExp(self, wildcardPattern): + """ + Private method to convert a wildcard pattern to a regular expression. + + @param wildcardPattern string containing the wildcard pattern (string) + @return string containing a regular expression (string) + """ + pattern = wildcardPattern + + # remove multiple wildcards + pattern = re.sub(r"\*+", "*", pattern) + # remove anchors following separator placeholder + pattern = re.sub(r"\^\|$", "^", pattern) + # remove leading wildcards + pattern = re.sub(r"^(\*)", "", pattern) + # remove trailing wildcards + pattern = re.sub(r"(\*)$", "", pattern) + # escape special symbols + pattern = re.sub(r"(\W)", r"\\\1", pattern) + # process extended anchor at expression start + pattern = re.sub( + r"^\\\|\\\|", + r"^[\w\-]+:\/+(?!\/)(?:[^\/]+\.)?", pattern) + # process separator placeholders + pattern = re.sub(r"\\\^", r"(?:[^\w\d\-.%]|$)", pattern) + # process anchor at expression start + pattern = re.sub(r"^\\\|", "^", pattern) + # process anchor at expression end + pattern = re.sub(r"\\\|$", "$", pattern) + # replace wildcards by .* + pattern = re.sub(r"\\\*", ".*", pattern) + + return pattern
--- a/WebBrowser/AdBlock/AdBlockSubscription.py Sun Mar 13 14:56:13 2016 +0100 +++ b/WebBrowser/AdBlock/AdBlockSubscription.py Sun Mar 13 20:54:42 2016 +0100 @@ -128,10 +128,9 @@ self.__requiresTitle = QUrl.fromPercentEncoding( QByteArray(urlQuery.queryItemValue("requiresTitle").encode())) if self.__requiresLocation and self.__requiresTitle: - import Helpviewer.HelpWindow - Helpviewer.HelpWindow.HelpWindow.adBlockManager()\ - .loadRequiredSubscription(self.__requiresLocation, - self.__requiresTitle) + from WebBrowser.WebBrowserWindow import WebBrowserWindow + WebBrowserWindow.adBlockManager().loadRequiredSubscription( + self.__requiresLocation, self.__requiresTitle) lastUpdateString = urlQuery.queryItemValue("lastUpdate") self.__lastUpdate = QDateTime.fromString(lastUpdateString, @@ -499,7 +498,7 @@ """ Public method to check the subscription for a matching rule. - @param req reference to the network request (QNetworkRequest) + @param req reference to the network request (QWebEngineUrlRequestInfo) @param urlDomain domain of the URL (string) @param urlString URL (string) @return reference to the rule object or None (AdBlockRule)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockTreeWidget.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,273 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a tree widget for the AdBlock configuration dialog. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QFont, QColor +from PyQt5.QtWidgets import QAbstractItemView, QTreeWidgetItem, QInputDialog, \ + QLineEdit, QMenu, QApplication + +from E5Gui.E5TreeWidget import E5TreeWidget + + +class AdBlockTreeWidget(E5TreeWidget): + """ + Class implementing a tree widget for the AdBlock configuration dialog. + """ + def __init__(self, subscription, parent=None): + """ + Constructor + + @param subscription reference to the subscription (AdBlockSubscription) + @param parent reference to the parent widget (QWidget) + """ + super(AdBlockTreeWidget, self).__init__(parent) + + self.__subscription = subscription + self.__topItem = None + self.__ruleToBeSelected = "" + self.__itemChangingBlock = False + + self.setContextMenuPolicy(Qt.CustomContextMenu) + self.setDefaultItemShowMode(E5TreeWidget.ItemsExpanded) + self.setHeaderHidden(True) + self.setAlternatingRowColors(True) + + self.customContextMenuRequested.connect(self.__contextMenuRequested) + self.itemChanged.connect(self.__itemChanged) + self.__subscription.changed.connect(self.__subscriptionChanged) + self.__subscription.rulesChanged.connect(self.__subscriptionChanged) + + def subscription(self): + """ + Public method to get a reference to the subscription. + + @return reference to the subscription (AdBlockSubscription) + """ + return self.__subscription + + def showRule(self, rule): + """ + Public method to highlight the given rule. + + @param rule AdBlock rule to be shown (AdBlockRule) + """ + if rule: + self.__ruleToBeSelected = rule.filter() + if not self.__topItem: + return + if self.__ruleToBeSelected: + items = self.findItems(self.__ruleToBeSelected, Qt.MatchRecursive) + if items: + item = items[0] + self.setCurrentItem(item) + self.scrollToItem(item, QAbstractItemView.PositionAtCenter) + + self.__ruleToBeSelected = "" + + def refresh(self): + """ + Public method to refresh the tree. + """ + QApplication.setOverrideCursor(Qt.WaitCursor) + self.__itemChangingBlock = True + self.clear() + + boldFont = QFont() + boldFont.setBold(True) + + self.__topItem = QTreeWidgetItem(self) + self.__topItem.setText(0, self.__subscription.title()) + self.__topItem.setFont(0, boldFont) + self.addTopLevelItem(self.__topItem) + + allRules = self.__subscription.allRules() + + index = 0 + for rule in allRules: + item = QTreeWidgetItem(self.__topItem) + item.setText(0, rule.filter()) + item.setData(0, Qt.UserRole, index) + if self.__subscription.canEditRules(): + item.setFlags(item.flags() | Qt.ItemIsEditable) + self.__adjustItemFeatures(item, rule) + index += 1 + + self.expandAll() + self.showRule(None) + self.__itemChangingBlock = False + QApplication.restoreOverrideCursor() + QApplication.processEvents() + + def addRule(self, filter=""): + """ + Public slot to add a new rule. + + @param filter filter to be added (string) + """ + if not self.__subscription.canEditRules(): + return + + if not filter: + filter = QInputDialog.getText( + self, + self.tr("Add Custom Rule"), + self.tr("Write your rule here:"), + QLineEdit.Normal) + if filter == "": + return + + from .AdBlockRule import AdBlockRule + rule = AdBlockRule(filter, self.__subscription) + offset = self.__subscription.addRule(rule) + + item = QTreeWidgetItem() + item.setText(0, filter) + item.setData(0, Qt.UserRole, offset) + item.setFlags(item.flags() | Qt.ItemIsEditable) + + self.__itemChangingBlock = True + self.__topItem.addChild(item) + self.__itemChangingBlock = False + + self.__adjustItemFeatures(item, rule) + + def removeRule(self): + """ + Public slot to remove the current rule. + """ + item = self.currentItem() + if item is None or \ + not self.__subscription.canEditRules() or \ + item == self.__topItem: + return + + offset = item.data(0, Qt.UserRole) + self.__subscription.removeRule(offset) + self.deleteItem(item) + + def __contextMenuRequested(self, pos): + """ + Private slot to show the context menu. + + @param pos position for the menu (QPoint) + """ + if not self.__subscription.canEditRules(): + return + + item = self.itemAt(pos) + if item is None: + return + + menu = QMenu() + menu.addAction(self.tr("Add Rule"), self.addRule) + menu.addSeparator() + act = menu.addAction(self.tr("Remove Rule"), self.removeRule) + if item.parent() is None: + act.setDisabled(True) + + menu.exec_(self.viewport().mapToGlobal(pos)) + + def __itemChanged(self, itm): + """ + Private slot to handle the change of an item. + + @param itm changed item (QTreeWidgetItem) + """ + if itm is None or self.__itemChangingBlock: + return + + self.__itemChangingBlock = True + + offset = itm.data(0, Qt.UserRole) + oldRule = self.__subscription.rule(offset) + + if itm.checkState(0) == Qt.Unchecked and oldRule.isEnabled(): + # Disable rule + rule = self.__subscription.setRuleEnabled(offset, False) + self.__adjustItemFeatures(itm, rule) + elif itm.checkState(0) == Qt.Checked and not oldRule.isEnabled(): + # Enable rule + rule = self.__subscription.setRuleEnabled(offset, True) + self.__adjustItemFeatures(itm, rule) + elif self.__subscription.canEditRules(): + from .AdBlockRule import AdBlockRule + # Custom rule has been changed + rule = self.__subscription.replaceRule( + AdBlockRule(itm.text(0), self.__subscription), offset) + self.__adjustItemFeatures(itm, rule) + + self.__itemChangingBlock = False + + def __copyFilter(self): + """ + Private slot to copy the current filter to the clipboard. + """ + item = self.currentItem() + if item is not None: + QApplication.clipboard().setText(item.text(0)) + + def __subscriptionChanged(self): + """ + Private slot handling a subscription change. + """ + self.refresh() + + self.__itemChangingBlock = True + self.__topItem.setText( + 0, self.tr("{0} (recently updated)").format( + self.__subscription.title())) + self.__itemChangingBlock = False + + def __adjustItemFeatures(self, itm, rule): + """ + Private method to adjust an item. + + @param itm item to be adjusted (QTreeWidgetItem) + @param rule rule for the adjustment (AdBlockRule) + """ + if not rule.isEnabled(): + font = QFont() + font.setItalic(True) + itm.setForeground(0, QColor(Qt.gray)) + + if not rule.isComment() and not rule.isHeader(): + itm.setFlags(itm.flags() | Qt.ItemIsUserCheckable) + itm.setCheckState(0, Qt.Unchecked) + itm.setFont(0, font) + + return + + itm.setFlags(itm.flags() | Qt.ItemIsUserCheckable) + itm.setCheckState(0, Qt.Checked) + + if rule.isCSSRule(): + itm.setForeground(0, QColor(Qt.darkBlue)) + itm.setFont(0, QFont()) + elif rule.isException(): + itm.setForeground(0, QColor(Qt.darkGreen)) + itm.setFont(0, QFont()) + else: + itm.setForeground(0, QColor()) + itm.setFont(0, QFont()) + + def keyPressEvent(self, evt): + """ + Protected method handling key presses. + + @param evt key press event (QKeyEvent) + """ + if evt.key() == Qt.Key_C and \ + evt.modifiers() & Qt.ControlModifier: + self.__copyFilter() + elif evt.key() == Qt.Key_Delete: + self.removeRule() + else: + super(AdBlockTreeWidget, self).keyPressEvent(evt)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/AdBlock/AdBlockUrlInterceptor.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an URL interceptor base class. +""" + +from __future__ import unicode_literals + +from ..Network.UrlInterceptor import UrlInterceptor + +class AdBlockUrlInterceptor(UrlInterceptor): + """ + Class implementing an URL interceptor for AdBlock. + """ + def __init__(self, manager, parent=None): + """ + Constructor + + @param manager reference to the AdBlock manager + @type AdBlockManager + @param parent referemce to the parent object + @type QObject + """ + super(AdBlockUrlInterceptor, self).__init__(parent) + + self.__manager = manager + + def interceptRequest(self, info): + """ + Public method to intercept a request. + + @param info request info object + @type QWebEngineUrlRequestInfo + """ + if self.__manager.block(info): + info.block(True)
--- a/WebBrowser/GreaseMonkey/GreaseMonkeyUrlInterceptor.py Sun Mar 13 14:56:13 2016 +0100 +++ b/WebBrowser/GreaseMonkey/GreaseMonkeyUrlInterceptor.py Sun Mar 13 20:54:42 2016 +0100 @@ -34,6 +34,6 @@ @param info request info object @type QWebEngineUrlRequestInfo """ - if info.requestUrl().toString.endswith(".user.js"): + if info.requestUrl().toString().endswith(".user.js"): self.__manager.downloadScript(info.requestUrl()) info.block(True)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/Network/EricSchemeHandler.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a scheme handler for the eric: scheme. +""" + +from __future__ import unicode_literals + +from PyQt5.QtCore import QByteArray, QBuffer, QIODevice, QTextStream, \ + QUrlQuery +from PyQt5.QtWebEngineCore import QWebEngineUrlSchemeHandler + +from ..Tools.WebBrowserTools import readAllFileContents + +class EricSchemeHandler(QWebEngineUrlSchemeHandler): + """ + Class implementing a scheme handler for the eric: scheme. + """ + SupportedPages = [ + "adblock", # error page for URLs blocked by AdBlock + ] + + def __init__(self, parent=None): + """ + Constructor + + @param parent reference to the parent object + @type QObject + """ + super(EricSchemeHandler, self).__init__(parent) + + def requestStarted(self, job): + """ + Public method handling the URL request. + + @param job URL request job + @type QWebEngineUrlRequestJob + """ + if job.requestUrl().path() in self.SupportedPages: + job.reply(b"text/html", EricSchemeReply(job)) + else: + job.reply(QByteArray(), QBuffer()) + # job.fail(QWebEngineUrlRequestJob.UrlNotFound) + + +class EricSchemeReply(QIODevice): + """ + Class implementing a reply for a requested eric: page. + """ + # TODO: SchemeHandler: debug this further + def __init__(self, job, parent=None): + """ + Constructor + + @param job reference to the URL request + @type QWebEngineUrlRequestJob + @param parent reference to the parent object + @type QObject + """ + super(EricSchemeReply, self).__init__(parent) + + self.__loaded = False + self.__job = job + + self.__pageName = self.__job.requestUrl().path() + self.__buffer = QBuffer() + + self.open(QIODevice.ReadOnly) + self.__buffer.open(QIODevice.ReadWrite) + self.__loadPage() + + def __loadPage(self): + """ + Private method to load the requested page. + """ + if self.__loaded: + return + + stream = QTextStream(self.__buffer) + stream.setCodec("utf-8") + + if self.__pageName == "adblock": + stream << self.__adBlockPage() + + stream.flush() + self.__buffer.reset() + self.__loaded = True + + def bytesAvailable(self): + """ + Public method to get the number of available bytes. + + @return number of available bytes + @rtype int + """ + print("bytesAvailable", self.__buffer.bytesAvailable()) + return self.__buffer.bytesAvailable() + + def readData(self, maxlen): + """ + Public method to retrieve data from the reply object. + + @param maxlen maximum number of bytes to read (integer) + @return string containing the data (bytes) + """ + print("readData") + self.__loadPage() + return self.__buffer.read(maxlen) + + def writeData(self, data, len): + return 0 + + def __adBlockPage(self): + """ + Private method to build the AdBlock page. + + @return built AdBlock page + @rtype str + """ + query = QUrlQuery(self.__job.requestUrl()) + rule = query.queryItemValue("rule") + subscription = query.queryItemValue("subscription") + title = self.tr("Content blocked by AdBlock Plus") + message = self.tr( + "Blocked by rule: <i>{0} ({1})</i>").format(rule, subscription) + + page = readAllFileContents(":/html/adblockPage.html") + page = page.replace( + "@FAVICON@", "qrc:icons/adBlockPlus16.png") + page = page.replace( + "@IMAGE@", "qrc:icons/adBlockPlus64.png") + page = page.replace("@TITLE@", title) + page = page.replace("@MESSAGE@", message) + + return page
--- a/WebBrowser/Network/NetworkManager.py Sun Mar 13 14:56:13 2016 +0100 +++ b/WebBrowser/Network/NetworkManager.py Sun Mar 13 20:54:42 2016 +0100 @@ -11,7 +11,7 @@ import json -from PyQt5.QtCore import pyqtSignal +from PyQt5.QtCore import pyqtSignal, QByteArray from PyQt5.QtWidgets import QDialog from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkProxy @@ -74,6 +74,10 @@ lambda reply, auth: self.authentication(reply.url(), auth)) # TODO: install network scheme handlers + from .EricSchemeHandler import EricSchemeHandler + self.__ericSchemeHandler = EricSchemeHandler() + WebBrowserWindow.webProfile().installUrlSchemeHandler( + QByteArray(b"eric"), self.__ericSchemeHandler) self.__interceptor = NetworkUrlInterceptor(self) WebBrowserWindow.webProfile().setRequestInterceptor(self.__interceptor) @@ -265,9 +269,8 @@ WebBrowserLanguagesDialog.defaultAcceptLanguages())) self.__acceptLanguage = WebBrowserLanguagesDialog.httpString(languages) - # TODO: Qt 5.6 -## WebBrowserWindow.webProfile().setHttpAcceptLanguage( -## self.__acceptLanguage) + WebBrowserWindow.webProfile().setHttpAcceptLanguage( + self.__acceptLanguage) def installUrlInterceptor(self, interceptor): """ @@ -276,8 +279,7 @@ @param interceptor URL interceptor to be installed @type UrlInterceptor """ - # TODO: Qt 5.6 -## self.__interceptor.installUrlInterceptor(interceptor) + self.__interceptor.installUrlInterceptor(interceptor) def removeUrlInterceptor(self, interceptor): """ @@ -286,12 +288,10 @@ @param interceptor URL interceptor to be removed @type UrlInterceptor """ - # TODO: Qt 5.6 -## self.__interceptor.removeUrlInterceptor(interceptor) + self.__interceptor.removeUrlInterceptor(interceptor) def preferencesChanged(self): """ Public slot to handle a change of preferences. """ - # TODO: Qt 5.6 -## self.__interceptor.preferencesChanged() + self.__interceptor.preferencesChanged()
--- a/WebBrowser/WebBrowserLanguagesDialog.py Sun Mar 13 14:56:13 2016 +0100 +++ b/WebBrowser/WebBrowserLanguagesDialog.py Sun Mar 13 20:54:42 2016 +0100 @@ -9,7 +9,7 @@ from __future__ import unicode_literals -from PyQt5.QtCore import pyqtSlot, QByteArray, QLocale, QStringListModel +from PyQt5.QtCore import pyqtSlot, QLocale, QStringListModel from PyQt5.QtWidgets import QDialog from .Ui_WebBrowserLanguagesDialog import Ui_WebBrowserLanguagesDialog @@ -144,7 +144,7 @@ if qvalue > 0.1: qvalue -= 0.1 - return QByteArray(", ".join(processed).encode("utf-8")) + return ", ".join(processed) @classmethod def defaultAcceptLanguages(cls):
--- a/WebBrowser/WebBrowserWindow.py Sun Mar 13 14:56:13 2016 +0100 +++ b/WebBrowser/WebBrowserWindow.py Sun Mar 13 20:54:42 2016 +0100 @@ -53,7 +53,7 @@ from UI.Info import Version ## ##from .data import icons_rc # __IGNORE_WARNING__ -##from .data import html_rc # __IGNORE_WARNING__ +from .data import html_rc # __IGNORE_WARNING__ from .data import javascript_rc # __IGNORE_WARNING__ @@ -89,7 +89,7 @@ _bookmarksManager = None _historyManager = None _passwordManager = None -## _adblockManager = None + _adblockManager = None _downloadManager = None _feedsManager = None ## _userAgentsManager = None @@ -155,8 +155,7 @@ ## from .HelpSearchWidget import HelpSearchWidget from .WebBrowserView import WebBrowserView from .WebBrowserTabWidget import WebBrowserTabWidget - # TODO: AdBlock -## from .AdBlock.AdBlockIcon import AdBlockIcon + from .AdBlock.AdBlockIcon import AdBlockIcon from .VirusTotal.VirusTotalApi import VirusTotalAPI # TODO: allow using Qt Help even if not called from eric6 @@ -286,16 +285,15 @@ self.__tabWidget.newBrowser(home) self.__tabWidget.currentBrowser().setFocus() - # TODO: AdBlock -## self.__adBlockIcon = AdBlockIcon(self) -## self.statusBar().addPermanentWidget(self.__adBlockIcon) -## self.__adBlockIcon.setEnabled( -## Preferences.getWebBrowser("AdBlockEnabled")) -## self.__tabWidget.currentChanged[int].connect( -## self.__adBlockIcon.currentChanged) -## self.__tabWidget.sourceChanged.connect( -## self.__adBlockIcon.sourceChanged) -## + self.__adBlockIcon = AdBlockIcon(self) + self.statusBar().addPermanentWidget(self.__adBlockIcon) + self.__adBlockIcon.setEnabled( + Preferences.getWebBrowser("AdBlockEnabled")) + self.__tabWidget.currentChanged[int].connect( + self.__adBlockIcon.currentChanged) + self.__tabWidget.sourceChanged.connect( + self.__adBlockIcon.sourceChanged) + self.networkIcon = E5NetworkIcon(self) self.statusBar().addPermanentWidget(self.networkIcon) @@ -2553,9 +2551,8 @@ self.passwordManager().close() - # TODO: AdBlock -## self.adBlockManager().close() -## + self.adBlockManager().close() + # TODO: UserAgents ## self.userAgentsManager().close() ## @@ -2633,7 +2630,8 @@ """ Private slot called to handle the reload action. """ - self.currentBrowser().reloadBypassingCache() +## self.currentBrowser().reloadBypassingCache() + self.currentBrowser().reload() def __stopLoading(self): """ @@ -3577,28 +3575,27 @@ return cls._passwordManager - # TODO: AdBlock -## @classmethod -## def adBlockManager(cls): -## """ -## Class method to get a reference to the AdBlock manager. -## -## @return reference to the AdBlock manager (AdBlockManager) -## """ -## if cls._adblockManager is None: -## from .AdBlock.AdBlockManager import AdBlockManager -## cls._adblockManager = AdBlockManager() -## -## return cls._adblockManager -## -## def adBlockIcon(self): -## """ -## Public method to get a reference to the AdBlock icon. -## -## @return reference to the AdBlock icon (AdBlockIcon) -## """ -## return self.__adBlockIcon -## + @classmethod + def adBlockManager(cls): + """ + Class method to get a reference to the AdBlock manager. + + @return reference to the AdBlock manager (AdBlockManager) + """ + if cls._adblockManager is None: + from .AdBlock.AdBlockManager import AdBlockManager + cls._adblockManager = AdBlockManager() + + return cls._adblockManager + + def adBlockIcon(self): + """ + Public method to get a reference to the AdBlock icon. + + @return reference to the AdBlock icon (AdBlockIcon) + """ + return self.__adBlockIcon + @classmethod def downloadManager(cls): """
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/data/html.qrc Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,6 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> +<qresource> + <file>html/adblockPage.html</file> +</qresource> +</RCC>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/data/html/adblockPage.html Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<meta http-equiv="content-type" content="text/html; charset=utf-8"> +<title>@TITLE@</title> +<link rel="icon" href="@FAVICON@" type="image/x-icon" /> +<style> +body { + padding: 3em 0em; + background: -webkit-gradient(linear, left top, left bottom, from(#85784A), to(#FDFDFD), color-stop(0.5, #FDFDFD)); + background-repeat: repeat-x; +} +#box { + background: white; + border: 1px solid #85784A; + max-width: 600px; + height: 50%; + padding: 40px; + padding-bottom: 10px; + margin: auto; + border-radius: 0.8em; + text-align: center; + vertical-align: middle; + margin: auto; +} +h1 { + font-size: 130%; + font-weight: bold; + border-bottom: 1px solid #85784A; + margin-bottom: 0px; +} +</style> +</head> +<body> + <div id="box"> + <img src="@IMAGE@" width="64" height="64"/> + <h1>AdBlock Plus</h1> + <p>@MESSAGE@</p> + </div> +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/data/html_rc.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.6.0) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\x00\x00\x03\x7c\ +\x3c\ +\x21\x44\x4f\x43\x54\x59\x50\x45\x20\x68\x74\x6d\x6c\x3e\x0a\x3c\ +\x68\x74\x6d\x6c\x3e\x0a\x3c\x68\x65\x61\x64\x3e\x0a\x3c\x6d\x65\ +\x74\x61\x20\x63\x68\x61\x72\x73\x65\x74\x3d\x22\x75\x74\x66\x2d\ +\x38\x22\x3e\x20\x0a\x3c\x6d\x65\x74\x61\x20\x68\x74\x74\x70\x2d\ +\x65\x71\x75\x69\x76\x3d\x22\x63\x6f\x6e\x74\x65\x6e\x74\x2d\x74\ +\x79\x70\x65\x22\x20\x63\x6f\x6e\x74\x65\x6e\x74\x3d\x22\x74\x65\ +\x78\x74\x2f\x68\x74\x6d\x6c\x3b\x20\x63\x68\x61\x72\x73\x65\x74\ +\x3d\x75\x74\x66\x2d\x38\x22\x3e\x0a\x3c\x74\x69\x74\x6c\x65\x3e\ +\x40\x54\x49\x54\x4c\x45\x40\x3c\x2f\x74\x69\x74\x6c\x65\x3e\x0a\ +\x3c\x6c\x69\x6e\x6b\x20\x72\x65\x6c\x3d\x22\x69\x63\x6f\x6e\x22\ +\x20\x68\x72\x65\x66\x3d\x22\x40\x46\x41\x56\x49\x43\x4f\x4e\x40\ +\x22\x20\x74\x79\x70\x65\x3d\x22\x69\x6d\x61\x67\x65\x2f\x78\x2d\ +\x69\x63\x6f\x6e\x22\x20\x2f\x3e\x0a\x3c\x73\x74\x79\x6c\x65\x3e\ +\x0a\x62\x6f\x64\x79\x20\x7b\x0a\x20\x20\x70\x61\x64\x64\x69\x6e\ +\x67\x3a\x20\x33\x65\x6d\x20\x30\x65\x6d\x3b\x0a\x20\x20\x62\x61\ +\x63\x6b\x67\x72\x6f\x75\x6e\x64\x3a\x20\x2d\x77\x65\x62\x6b\x69\ +\x74\x2d\x67\x72\x61\x64\x69\x65\x6e\x74\x28\x6c\x69\x6e\x65\x61\ +\x72\x2c\x20\x6c\x65\x66\x74\x20\x74\x6f\x70\x2c\x20\x6c\x65\x66\ +\x74\x20\x62\x6f\x74\x74\x6f\x6d\x2c\x20\x66\x72\x6f\x6d\x28\x23\ +\x38\x35\x37\x38\x34\x41\x29\x2c\x20\x74\x6f\x28\x23\x46\x44\x46\ +\x44\x46\x44\x29\x2c\x20\x63\x6f\x6c\x6f\x72\x2d\x73\x74\x6f\x70\ +\x28\x30\x2e\x35\x2c\x20\x23\x46\x44\x46\x44\x46\x44\x29\x29\x3b\ +\x0a\x20\x20\x62\x61\x63\x6b\x67\x72\x6f\x75\x6e\x64\x2d\x72\x65\ +\x70\x65\x61\x74\x3a\x20\x72\x65\x70\x65\x61\x74\x2d\x78\x3b\x0a\ +\x7d\x0a\x23\x62\x6f\x78\x20\x7b\x0a\x20\x20\x62\x61\x63\x6b\x67\ +\x72\x6f\x75\x6e\x64\x3a\x20\x77\x68\x69\x74\x65\x3b\x0a\x20\x20\ +\x62\x6f\x72\x64\x65\x72\x3a\x20\x31\x70\x78\x20\x73\x6f\x6c\x69\ +\x64\x20\x23\x38\x35\x37\x38\x34\x41\x3b\x0a\x20\x20\x6d\x61\x78\ +\x2d\x77\x69\x64\x74\x68\x3a\x20\x36\x30\x30\x70\x78\x3b\x0a\x20\ +\x20\x68\x65\x69\x67\x68\x74\x3a\x20\x35\x30\x25\x3b\x0a\x20\x20\ +\x70\x61\x64\x64\x69\x6e\x67\x3a\x20\x34\x30\x70\x78\x3b\x0a\x20\ +\x20\x70\x61\x64\x64\x69\x6e\x67\x2d\x62\x6f\x74\x74\x6f\x6d\x3a\ +\x20\x31\x30\x70\x78\x3b\x0a\x20\x20\x6d\x61\x72\x67\x69\x6e\x3a\ +\x20\x61\x75\x74\x6f\x3b\x0a\x20\x20\x62\x6f\x72\x64\x65\x72\x2d\ +\x72\x61\x64\x69\x75\x73\x3a\x20\x30\x2e\x38\x65\x6d\x3b\x0a\x20\ +\x20\x74\x65\x78\x74\x2d\x61\x6c\x69\x67\x6e\x3a\x20\x63\x65\x6e\ +\x74\x65\x72\x3b\x0a\x20\x20\x76\x65\x72\x74\x69\x63\x61\x6c\x2d\ +\x61\x6c\x69\x67\x6e\x3a\x20\x6d\x69\x64\x64\x6c\x65\x3b\x0a\x20\ +\x20\x6d\x61\x72\x67\x69\x6e\x3a\x20\x61\x75\x74\x6f\x3b\x0a\x7d\ +\x0a\x68\x31\x20\x7b\x0a\x20\x20\x66\x6f\x6e\x74\x2d\x73\x69\x7a\ +\x65\x3a\x20\x31\x33\x30\x25\x3b\x0a\x20\x20\x66\x6f\x6e\x74\x2d\ +\x77\x65\x69\x67\x68\x74\x3a\x20\x62\x6f\x6c\x64\x3b\x0a\x20\x20\ +\x62\x6f\x72\x64\x65\x72\x2d\x62\x6f\x74\x74\x6f\x6d\x3a\x20\x31\ +\x70\x78\x20\x73\x6f\x6c\x69\x64\x20\x23\x38\x35\x37\x38\x34\x41\ +\x3b\x0a\x20\x20\x6d\x61\x72\x67\x69\x6e\x2d\x62\x6f\x74\x74\x6f\ +\x6d\x3a\x20\x30\x70\x78\x3b\x0a\x7d\x0a\x3c\x2f\x73\x74\x79\x6c\ +\x65\x3e\x0a\x3c\x2f\x68\x65\x61\x64\x3e\x0a\x3c\x62\x6f\x64\x79\ +\x3e\x0a\x20\x20\x3c\x64\x69\x76\x20\x69\x64\x3d\x22\x62\x6f\x78\ +\x22\x3e\x0a\x20\x20\x20\x20\x3c\x69\x6d\x67\x20\x73\x72\x63\x3d\ +\x22\x40\x49\x4d\x41\x47\x45\x40\x22\x20\x77\x69\x64\x74\x68\x3d\ +\x22\x36\x34\x22\x20\x68\x65\x69\x67\x68\x74\x3d\x22\x36\x34\x22\ +\x2f\x3e\x0a\x20\x20\x20\x20\x3c\x68\x31\x3e\x41\x64\x42\x6c\x6f\ +\x63\x6b\x20\x50\x6c\x75\x73\x3c\x2f\x68\x31\x3e\x0a\x20\x20\x20\ +\x20\x3c\x70\x3e\x40\x4d\x45\x53\x53\x41\x47\x45\x40\x3c\x2f\x70\ +\x3e\x0a\x20\x20\x3c\x2f\x64\x69\x76\x3e\x0a\x3c\x2f\x62\x6f\x64\ +\x79\x3e\x0a\x3c\x2f\x68\x74\x6d\x6c\x3e\x0a\ +" + +qt_resource_name = b"\ +\x00\x04\ +\x00\x06\xfb\x3c\ +\x00\x68\ +\x00\x74\x00\x6d\x00\x6c\ +\x00\x10\ +\x0b\xe9\x1d\x9c\ +\x00\x61\ +\x00\x64\x00\x62\x00\x6c\x00\x6f\x00\x63\x00\x6b\x00\x50\x00\x61\x00\x67\x00\x65\x00\x2e\x00\x68\x00\x74\x00\x6d\x00\x6c\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ +\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/data/icons.qrc Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,7 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> +<qresource> + <file>icons/adBlockPlus16.png</file> + <file>icons/adBlockPlus64.png</file> +</qresource> +</RCC>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebBrowser/data/icons_rc.py Sun Mar 13 20:54:42 2016 +0100 @@ -0,0 +1,614 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.6.0) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\x00\x00\x20\x26\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x40\x00\x00\x00\x40\x08\x06\x00\x00\x00\xaa\x69\x71\xde\ +\x00\x00\x00\x01\x73\x52\x47\x42\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\ +\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x13\x00\x00\x0b\x13\x01\ +\x00\x9a\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\xdc\x02\x15\ +\x0e\x23\x2f\xab\xc9\xe5\x0b\x00\x00\x00\x1d\x69\x54\x58\x74\x43\ +\x6f\x6d\x6d\x65\x6e\x74\x00\x00\x00\x00\x00\x43\x72\x65\x61\x74\ +\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4d\x50\x64\x2e\x65\x07\ +\x00\x00\x1f\x7d\x49\x44\x41\x54\x78\xda\xcd\x9b\x69\x90\x5d\xd7\ +\x71\xdf\x7f\x7d\xee\xfa\x96\xd9\x07\xc4\x00\x33\x18\x02\x03\xae\ +\x22\x45\x53\x0b\x25\xd2\x91\x44\x53\x8a\x2d\x89\x91\x17\xad\xa4\ +\x2c\x5b\x52\x12\xc9\xf1\x56\x72\xca\xa9\xe4\x4b\x2a\x1f\x52\x89\ +\xbf\x38\x49\x39\x72\xe2\x4d\x92\x63\x4b\xb1\x55\x12\x4d\x49\xb4\ +\xc5\x45\x24\x41\x10\xa0\x44\x09\x80\x28\x42\x22\x41\x12\xfb\x3a\ +\x33\x00\x66\x06\xb3\xbf\xed\xde\x7b\x4e\xe7\xc3\xb9\x6f\x30\x00\ +\x41\xed\x76\xe5\x56\xdd\x79\x6f\xee\xf6\x4e\xf7\xe9\xfe\x77\xf7\ +\xff\xf4\x85\x1f\x73\x7b\xf1\xc5\x17\xf9\xff\x65\xfb\x49\xc6\x12\ +\xfe\x34\x06\x70\xe0\xc0\x81\xde\x9e\x9e\x9e\x9f\x37\xc6\xbc\x4e\ +\x44\x7a\x01\xfb\x8f\x24\x6b\xa0\xaa\xcb\xce\xb9\xef\xac\xac\xac\ +\x3c\x7e\xf3\xcd\x37\x2f\xff\xa4\x0f\x94\x1f\xe7\xa6\x3d\x7b\xf6\ +\x70\xfb\xed\xb7\x03\xf0\xf5\xaf\x7f\xbd\x32\x3a\x3a\x7a\x6f\xad\ +\x56\xfb\x70\x14\x45\x37\x1b\x63\x22\x40\x45\x04\x91\x2b\x3f\xfe\ +\xf2\xe3\xaa\xfa\x8a\xbf\xa5\xaa\xeb\xcf\x8b\x73\x2e\xcf\xf3\xfc\ +\x40\xa3\xd1\xf8\xdc\xd4\xd4\xd4\x17\xde\xfc\xe6\x37\xb7\x2e\x1f\ +\xd3\x3f\xea\xf6\xe0\x83\x0f\xae\x7d\x7f\xe0\x81\x07\x92\xe3\xc7\ +\x8f\x7f\xe8\xdc\xb9\x73\xdf\x5c\x5c\x5c\x6c\xaf\x36\x1a\xda\x6c\ +\xb5\xb4\xd5\x6e\x6b\xbb\xd3\xd1\x4e\xb9\x67\x59\xe6\xf7\x3c\xd7\ +\x2c\xcf\x35\xcf\x73\x2d\x8a\x42\xf3\xa2\xf0\x9f\xeb\x8e\x67\x79\ +\xbe\x76\x7d\xa7\xd3\xd1\x76\xbb\xad\xad\x56\x4b\x5b\xad\x96\x36\ +\x5b\x2d\x5d\x5d\x5d\xd5\x85\x85\x85\xf6\xb9\x73\xe7\xbe\x79\xfc\ +\xf8\xf1\x0f\x3d\xf0\xc0\x03\xc9\x95\xc6\xf6\x8f\xb2\xed\xd9\xb3\ +\x67\xed\xfb\xfd\xf7\xdf\x9f\x1e\x3e\x7c\xf8\xdd\xd3\xd3\xd3\x7b\ +\x16\x16\x16\x8a\x46\xa3\xa1\xed\x2c\xd3\x8e\xb5\x2e\x73\x4e\x73\ +\xa7\x5a\xa8\xdf\x6d\xb9\xbb\x72\xbf\xd2\xe6\xd6\xed\xdd\xeb\x0b\ +\x55\xcd\x55\x35\x73\x4e\x33\xe7\xb4\x63\xad\x6b\x67\x99\x36\x1a\ +\x0d\x5d\x58\x58\x28\xa6\xa7\xa7\xf7\x1c\x3e\x7c\xf8\xdd\xf7\xdf\ +\x7f\x7f\x7a\xa5\x31\xfe\x54\x5d\x60\xff\xfe\xfd\xbc\xe6\x35\xaf\ +\x01\x60\xe7\xce\x9d\xb5\xcd\x9b\x37\xbf\xa5\x5e\xaf\xff\xa7\x4a\ +\xb5\x7a\x47\x9a\x24\x88\x88\xae\x9c\x3c\xc1\xe2\xb1\xe3\x92\x35\ +\x56\x41\x04\xb8\xd4\x0d\x8c\xc8\xda\x2f\x0a\x82\x5e\xb4\x73\x7f\ +\x5c\x41\xfd\x1f\x7f\x4e\xb5\xbc\x46\x41\x95\xb8\x56\xa3\x6f\xfb\ +\x76\xed\xdd\xba\x0d\x55\x95\x76\xa7\x43\xab\xd9\xfc\xd6\xea\xea\ +\xea\x7f\x39\x7b\xf6\xec\x53\x77\xdd\x75\x57\xe3\xf2\xb1\xfe\x54\ +\x14\xf0\xdd\xef\x7e\x97\x5b\x6f\xbd\xb5\xeb\xf3\xf5\x91\x91\x91\ +\xb7\x56\xab\xd5\xff\x90\x56\x2a\xff\x2c\x89\x63\x44\x55\x57\xcf\ +\x9c\x91\x43\x9f\xfe\x33\x0e\xff\xcd\xe7\x58\x99\x5d\xea\xca\xb3\ +\xf6\xd9\xfd\x31\x53\xfe\xaf\x57\x18\x88\x00\xee\xb2\xeb\xd7\x3f\ +\xa3\x77\x43\x1f\xd7\xfe\xda\x87\xb9\xfe\xe3\xbf\x45\x6d\xcb\x16\ +\x45\x44\xda\xed\x36\xed\x76\xfb\xe9\x56\xab\xf5\x87\xe7\xcf\x9f\ +\xdf\xf9\xa6\x37\xbd\x69\xf5\xf2\x31\xff\xd8\x0a\x78\xee\xb9\xe7\ +\x00\xb8\xe5\x96\x5b\xba\xc2\xf7\x8c\x8c\x8c\xdc\x5d\xad\x56\x7f\ +\x2f\x4d\xd3\x3b\x92\x24\x51\x50\x56\x4f\x9d\x92\x83\x9f\xfe\x14\ +\x8b\x0f\xfd\x3d\x3d\x4b\x33\xf4\xd7\x13\x50\xc1\xb5\x1d\x61\xcd\ +\x80\x03\x2d\x20\x88\x04\x13\x09\xae\x50\x34\x57\x4c\xc5\x5b\x84\ +\x6d\x28\x26\x11\x24\x14\x5c\xee\x70\x05\x98\x00\x54\xa0\x58\x75\ +\x04\x55\x03\xa2\x2c\xae\x76\x58\xe9\xbb\x8a\xfe\xbb\x7f\x89\xeb\ +\x3f\xf6\x1b\xd4\xc7\xb7\xaa\x0a\x74\x3a\x1d\xe9\x74\x3a\xdf\x6a\ +\x36\x9b\x9f\x3c\x77\xee\xdc\xc3\x6f\x7e\xf3\x9b\x57\xae\x34\xfe\ +\x9f\x28\x0c\x3e\xf9\xe4\x93\x7d\x23\x23\x23\xbf\x52\xad\x56\xff\ +\x4d\x9a\xa6\x77\xc4\x71\x8c\x3a\xc7\xea\x99\xd3\x1c\xfa\xf4\x9f\ +\xb3\xf2\xe8\x57\xe9\x59\x9c\xa5\x1e\x45\x68\x0e\xa2\x10\x24\x01\ +\x61\x2a\xa0\x82\x6d\x39\xd4\x2a\xd6\x2a\x88\x60\x52\x83\xa9\x88\ +\x9f\xdd\x4c\xd1\x42\xa1\xf0\xf3\x6d\x22\x21\x48\x05\x54\x71\x99\ +\x57\x1e\x02\xf5\x20\x86\xc5\x39\x56\x1e\xff\x2a\x07\x51\xae\xff\ +\xd8\x6f\x52\x1f\x1f\x27\x8e\x63\x44\xe4\x0e\x11\x61\x64\x64\x24\ +\x7d\xf2\xc9\x27\x1f\xb8\xeb\xae\xbb\x96\x7e\x22\x17\x58\x6f\x42\ +\x4f\x3d\xf5\x54\xff\xe8\xe8\xe8\xfb\x2a\x95\xca\x47\x93\x24\xb9\ +\x2d\x8a\xe3\x58\x40\x9b\x53\x53\xf2\xe2\xff\xfa\x24\xab\x3b\x1e\ +\xa6\x67\x71\x81\x6a\x28\x84\x89\xc1\x84\x02\x4e\xd0\x8e\x12\xd6\ +\x0d\x58\x50\xab\x98\x48\x30\xa1\x17\xc8\x15\x8a\x49\xbd\xe1\xdb\ +\xa6\xc3\x24\x06\x13\x94\x16\x60\x15\x29\xa7\xa6\x68\x94\x96\x62\ +\x14\x97\x2b\x79\xe6\x68\x5a\x65\xa5\x67\x80\xfa\xdb\xee\xe6\x55\ +\x9f\xf8\x04\xd5\xd1\x31\x75\xaa\x92\x67\x59\x96\x65\xd9\xb7\x5b\ +\xad\xd6\x5f\x4f\x4d\x4d\xdd\xff\x96\xb7\xbc\x65\xf1\x07\xb9\x83\ +\xb9\xd2\xc1\xbd\x7b\xf7\xae\xdd\xb0\x7b\xf7\xee\xbe\x4d\x9b\x36\ +\xbd\x2f\x49\x92\x8f\xc4\x71\xfc\xda\x30\x0c\x63\x13\x04\xb4\x67\ +\xce\xf1\xfc\x27\xff\x88\x95\x47\x1e\xa2\x6f\x79\x81\x9a\x11\xa2\ +\xc0\x10\xc6\x86\xb0\x12\x78\x45\x58\x10\x27\x88\x13\x0c\x42\x18\ +\x1b\xa2\x6a\xf7\x9c\xc1\x38\x83\x71\x10\x60\x88\x12\x43\x54\xf3\ +\x0a\x0c\xf0\xe7\xc5\x09\xc6\xf9\xfb\xc2\x34\xf0\xf7\x07\x86\x2a\ +\x42\xef\xca\x02\x2b\x8f\x3e\xc4\x81\x4f\xfe\x11\xed\xf3\xe7\x08\ +\xc2\x80\x28\x8a\xe2\x38\x8e\x5f\x9b\x24\xc9\x47\x36\x6d\xda\xf4\ +\xbe\xdd\xbb\x77\xf7\x01\xdc\x7a\xeb\xad\xec\xdd\xbb\xf7\x87\xb3\ +\x80\xf5\x09\xc5\x13\x4f\x3c\xd1\x3b\x36\x36\xf6\x9e\x5a\xad\xf6\ +\xb1\x24\x49\x5e\x1b\x45\x51\x25\xae\x56\x59\x3a\x76\x4c\x5f\xf8\ +\xe3\xff\x29\xab\x0f\xfd\x03\xfd\xed\x15\xfa\x7a\x22\x0c\x7e\xd6\ +\x25\x10\x82\x48\xbc\xdf\xe7\x4a\x54\x37\xa8\x13\xef\xf3\x81\xf7\ +\x73\xb5\x0a\x0e\x4c\xd5\xc3\x9b\x6d\x80\x09\x81\x40\xd0\x42\x51\ +\xa7\x48\xe4\xcf\x15\x2b\x8a\x24\xa0\x06\x5c\xae\xa8\x55\x34\x00\ +\xe7\x1c\xcb\xab\x39\x8b\x69\x2f\xb5\x77\xfe\x22\x37\xfd\xde\xbf\ +\xd5\xde\xed\xdb\x25\x6b\x36\x29\xf2\xbc\xd5\xe9\x74\x9e\x6d\x34\ +\x1a\x9f\x99\x9c\x9c\xfc\xf2\xdb\xde\xf6\xb6\xe5\x57\x4a\x96\xcc\ +\xe5\x49\x4e\xf7\x82\xa7\x9f\x7e\xba\x3e\x3a\x3a\x7a\x77\xb5\x5a\ +\xfd\x8d\x24\x49\x6e\x8b\xa2\xa8\x12\x55\xab\xcc\x1f\x3c\xa8\x2f\ +\xfd\xe9\x9f\xc8\xfc\xfd\x5f\x64\xa0\xb9\x44\x5f\x35\x22\x4c\x02\ +\x82\xc4\x60\x8c\x60\x1c\x48\xe1\xf7\x30\x31\x84\xa9\x21\xaa\x08\ +\x41\x28\x88\x03\x32\x10\x2b\x04\x89\x10\x56\x84\x30\xed\x9e\x13\ +\x24\x53\xc4\x79\xb0\x8c\xaa\x42\x58\x09\x30\xdd\x73\x16\xc4\x82\ +\x09\x84\xa8\x62\x88\xd2\x80\xde\x34\x62\xa0\xb9\xc4\xfc\x97\xbf\ +\xc0\x4b\x7f\xf6\x27\x32\x7f\xf0\xa0\x46\x95\x0a\x61\x14\x55\x92\ +\x24\xb9\xad\x5a\xad\xfe\xc6\xe8\xe8\xe8\xdd\x4f\x3f\xfd\x74\x1d\ +\xe0\xf6\xdb\x6f\x7f\x59\xb2\xb4\xa6\x80\x1d\x3b\x76\xf0\xae\x77\ +\xbd\xab\x3b\xf3\xb5\xc1\xc1\xc1\xb7\x56\x2a\x95\x4f\x24\x49\x72\ +\x47\x18\x86\xb1\x09\x43\x96\x8e\x1e\xd5\x43\x9f\xfe\x94\x9c\xfb\ +\xec\xa7\xd9\x12\x5b\xfa\x7b\x52\x0c\x5e\x30\xb1\x42\x60\x84\x20\ +\x36\x04\xa9\x21\x48\x0c\x62\x05\xca\x3d\x10\xf1\xca\xa8\x1b\xc2\ +\x54\x10\xdb\xdd\x0d\x81\x7a\xd3\x8f\xea\x86\x30\x11\x8c\x0a\xe4\ +\xfe\xb9\xc6\x79\x25\x45\x15\xe3\x5d\x47\x04\x0a\x4a\xb7\x32\xf4\ +\xf7\x24\x6c\x49\x95\x73\x9f\xfd\x34\x47\x3e\xfd\x29\x59\x3a\x76\ +\x4c\x4d\x10\x10\x86\x61\x9c\x24\xc9\x1d\x95\x4a\xe5\x13\x83\x83\ +\x83\x6f\x7d\xe2\x89\x27\x6a\x00\xef\x7a\xd7\xbb\xd8\xb1\x63\xc7\ +\x45\x17\xd8\xbd\x7b\x37\x00\x77\xde\x79\x27\x00\xf7\xdd\x77\x5f\ +\x7a\xe3\x8d\x37\xbe\xb5\x56\xab\xfd\xc7\x4a\xa5\xf2\xb3\x69\x9a\ +\x02\x68\x7b\x76\x96\xe7\xff\xfb\xff\x90\xa5\xaf\x7c\x81\x2d\xa9\ +\xa3\xb7\x9e\xe0\x1c\xb8\x86\x62\x62\x81\x42\x08\x13\x21\xac\x1b\ +\x4c\x22\x60\xa1\x98\x71\x04\x35\x0f\x82\x12\x42\xd8\x13\x10\x54\ +\x05\xd7\x56\x8a\x79\x87\x24\x94\xb1\x4e\x09\x07\x0c\x92\x0a\xb6\ +\xa9\x14\xcb\x16\xb5\x20\x06\x6c\x1b\x82\x61\x41\x02\xc5\x76\x94\ +\x62\xc5\x61\x33\x07\x81\x0f\xa7\xa6\x06\xc6\x08\x4b\xab\x1d\xce\ +\xb4\x84\xbe\x77\xdf\xc3\xab\x7f\xff\xdf\x69\xb2\x61\x18\x10\xe9\ +\x74\x3a\xb4\x5a\xad\x6f\x36\x1a\x8d\x3f\x78\xe9\xa5\x97\x76\x7e\ +\xe0\x03\x1f\x68\x97\xd8\xc6\x9d\x77\xde\x79\x29\x06\x7c\xe6\x33\ +\x9f\x49\xde\xf0\x86\x37\xdc\x5d\xab\xd5\xfe\x7d\xa5\x52\xf1\x71\ +\x5e\x95\xd6\xb9\x73\xf2\xd2\xff\xfe\x24\xcd\x47\x1e\x62\xb0\xb9\ +\x44\x5f\x6f\xea\xfd\x59\x3d\xa2\x87\x35\x3f\xdb\x02\x98\xd8\x5b\ +\x01\x16\xdc\xaa\x12\x0d\x1a\xb0\x3e\x22\x98\x54\xbc\x72\x3a\x8a\ +\x6b\x83\xe9\xf3\x3f\x6f\x97\x1c\xa6\x66\x90\x08\x5c\x47\xd1\xcc\ +\x63\x80\x33\x4a\x7e\xc1\x11\xf4\x79\x7c\xb0\x6d\x87\xcb\x14\x35\ +\x8a\x0a\xd8\x86\x2b\xf1\x41\xb0\x99\x63\x69\xb9\xcd\x7c\xb5\x8f\ +\xea\x3b\xfe\x05\x37\xfc\xee\x27\xa8\x6c\x1c\x51\x44\xe8\x74\x3a\ +\xd2\x6e\xb7\xbf\xd5\x68\x34\xfe\xdb\xbe\x7d\xfb\x1e\xfe\xd8\xc7\ +\x3e\xd6\xe9\x82\x7d\xd0\x15\xfe\xf3\x9f\xff\x7c\xed\x96\x5b\x6e\ +\x79\x6f\xad\x56\xfb\xfd\x34\x4d\x6f\x4f\xd2\x04\x51\xa5\x71\xe6\ +\x0c\x87\xff\xe2\x4f\xa5\xfd\xe4\xa3\x0c\x76\x96\xa9\x47\x31\x64\ +\x52\x9a\xbe\x10\x24\x86\xb0\x62\x08\x22\x83\x58\xaf\x10\x29\x40\ +\x72\x21\xac\x05\x04\x35\xe3\x7d\xdc\xfa\xe3\x74\x4a\x77\xa9\x1b\ +\x82\x9a\xf8\x90\x59\x78\xa5\xd0\xf1\x85\xb4\x89\xbb\xe7\xfc\x73\ +\x34\xf7\x80\xaa\x39\x98\x50\x08\x6a\x06\x91\x12\x4c\x73\x0f\x9c\ +\xb6\x05\x49\x12\x12\x49\x87\xd5\xe9\x29\x96\x66\xe7\xe9\xb9\xe6\ +\x5a\xe2\xde\x5e\x82\x20\x10\x60\x0b\xb0\x75\x78\x78\xb8\x71\xe7\ +\x9d\x77\x1e\xfb\xd2\x97\xbe\x94\x7f\xfc\xe3\x1f\xf7\x0a\xd8\xb5\ +\x6b\x57\xff\xf8\xf8\xf8\xfb\x6b\xb5\xda\x6f\x56\x2a\x95\x37\x24\ +\x69\x2a\xa2\xaa\xab\xa7\x4f\xc9\xd1\xbf\xfc\x8c\x34\x1f\x7f\x84\ +\xbe\xd5\x45\x6a\x12\x10\x88\x4f\x52\xc2\xd4\x20\x81\xf7\xd3\xc0\ +\x78\x7f\x36\xf8\xe3\x41\x45\x08\x02\x41\xb2\xae\x80\xa5\xcf\xa6\ +\x86\xb0\xba\xee\x98\xc1\x03\x63\x2e\x84\x55\x7f\x9f\x98\x12\x2c\ +\xd5\x2b\xcd\xb5\x14\x53\xf7\x96\x23\x94\xd1\xc5\x51\x46\x19\x90\ +\x58\x30\xb1\xf7\x24\x51\x21\x44\x30\xad\x16\xab\xa7\x27\x59\x5e\ +\x5e\x91\xda\xb6\x09\x89\xfb\xfb\x35\x8c\x22\x11\x91\xcd\xc6\x98\ +\xd1\x81\x81\x81\xce\xbd\xf7\xde\x7b\xe2\x4d\x6f\x7a\x53\xdb\x00\ +\xd4\x6a\xb5\xb7\xa7\x69\xfa\x91\x24\x49\x5e\x1b\xc5\xb1\x41\x55\ +\x57\x4f\x9f\x96\x63\x7f\xf5\x97\x34\xbf\xf6\x10\x3d\x0b\xf3\xd4\ +\xc4\xc7\x64\x29\xe3\x79\x10\x1b\x82\xa8\x1c\xac\x05\x32\x45\x80\ +\x20\x16\x6f\x11\x15\x03\xb9\x9f\x6d\x29\x04\x03\x84\xa9\x10\xf6\ +\xfa\x88\x21\x19\x98\x42\x90\x5c\x30\x85\x10\xa4\xa6\x3c\xb7\x2e\ +\x22\x14\x3e\xaa\x84\x69\x69\x65\xa9\xf1\x4a\xe8\x00\x85\x07\xc8\ +\xa0\x74\xb9\x30\xf1\x2e\x69\x0a\xf1\x79\xc2\xd2\x02\xad\xc7\x1e\ +\xe6\xf8\x67\xff\x92\xc6\xe9\xd3\x82\x53\x8d\xe2\xd8\x24\x49\xf2\ +\xda\x34\x4d\x3f\x52\xab\xd5\xde\xde\x4d\x85\x0d\xf0\xfa\x28\x8a\ +\x6e\x8a\xa2\x28\x0e\xc2\x90\xe5\x63\xc7\x38\xfe\x57\xff\x87\xd5\ +\x47\x1e\xa4\x6f\x71\x9e\x5a\x1a\x12\xc6\x81\x0f\x71\x5a\x9a\x24\ +\x3e\xdd\x35\x81\x1f\x84\x84\x7e\x76\xc8\x40\xb5\x74\x8f\x14\x82\ +\xe4\xe2\x71\xc9\xbc\xcf\x4b\xee\x05\x36\x55\x01\x2d\x5d\xa6\x34\ +\x7f\x29\x84\x20\x02\x62\x5f\x2d\x9a\x96\x81\x36\xa8\x51\xc8\x7c\ +\x2e\x61\x22\xc1\xa1\x60\x9d\x77\x0d\x29\x9f\x6f\xf0\x96\x47\x40\ +\xcd\x29\x6e\xfe\x02\xcb\x0f\x3d\xc8\x51\x07\x13\x1f\xfd\x57\xf4\ +\x4c\x6c\x27\x8a\xa2\xb8\x28\x8a\x9b\x80\xd7\x03\x7f\x17\x02\x71\ +\x51\x14\x7d\x22\x12\x19\x63\x40\x44\xdb\x27\x4f\xca\xfc\xdf\x7d\ +\x91\xe1\xa2\x45\x3d\x8e\x09\x23\x1f\x8f\x8d\x08\xb4\x0a\x74\x39\ +\x43\xe3\xd2\x4c\x43\x90\x24\xc2\x44\x31\x14\xa1\x9f\x71\x01\x71\ +\xbe\xc0\x09\x2a\x5e\x68\x2d\x1c\x34\xdb\xd0\x74\x5e\x71\xc9\xc5\ +\xf2\x58\x0a\x41\x0b\x01\xe3\x43\x1b\x49\x80\xd4\x0c\x8a\xa2\x2b\ +\xde\xc7\xc5\x78\x1c\x30\x36\x83\xb8\x40\x2d\x68\xcb\xa2\x4e\x71\ +\x01\xd8\x86\x85\x48\x90\x54\x10\x15\x02\x31\xd4\xa3\x00\x5d\x9c\ +\xe3\xc2\xdf\x7d\x91\xd6\xcf\xdd\x25\x3d\xd7\x5c\xa3\xc6\x18\x11\ +\x91\xa8\x28\x8a\x3e\x20\x0e\x81\x38\xcb\x32\x51\xf5\xc4\x93\x82\ +\x84\xed\x26\xfd\x0b\xf3\xf4\x8e\x0c\x60\xd4\x9b\x96\xcf\xe7\x0b\ +\xc2\xc1\x61\xd2\x89\x09\xa2\x81\x3a\xb8\xb2\xc4\x35\x19\x6e\x7a\ +\x1a\x37\x77\x01\x43\x41\x90\x78\xd3\x27\x2f\x77\xeb\x08\x7a\x87\ +\x08\xb6\x6c\xc1\x0c\xf4\x41\xe1\x6f\x34\xf5\xb2\x34\x9e\x2f\x50\ +\xcd\x20\x6b\xe1\x66\xe7\x71\xf3\x0b\x68\x2b\x47\x82\x32\x1d\xae\ +\x7b\x73\x93\xb4\x8a\x6c\xbc\x0e\x33\xba\x09\x57\x14\xc4\xab\x0e\ +\x35\x40\x00\x45\xcb\xe2\x6c\x81\xda\x36\xf9\xe2\x22\x3a\x3d\x8b\ +\x2e\x2e\xd0\x5b\x8d\x29\xce\xcf\x13\xb6\x5b\x94\x46\x8b\xaa\x6a\ +\x96\x65\x02\x44\x21\x10\xe4\x79\x1e\x38\xe7\xa4\xcb\xbf\xc5\x81\ +\xa1\xaf\x16\x78\x40\x52\xef\x6f\xea\x14\xbb\xda\xa6\xfe\xd6\xdb\ +\xd9\xf4\x5f\xff\x80\x78\xf3\x96\xb5\xba\xbd\x38\x7f\x96\xe5\x4f\ +\xfd\x39\xd9\xce\xbf\xc7\xb4\x67\x30\x95\x08\xb1\x06\xb7\x02\x18\ +\x41\xdb\x16\xee\xb8\x85\xe4\x77\x7e\x9f\xf8\x96\x9f\x59\x47\x84\ +\xf8\x64\x5c\x5b\x0d\x74\xf9\x02\x6e\x6e\x0a\xfb\xec\x33\xe4\x4f\ +\xee\xc2\x1e\x3e\x88\x5b\x6d\xf9\x7a\x22\x35\x38\x2d\x30\x9b\x46\ +\xa8\x7e\xe8\xb7\xa9\xbd\xf3\xfd\x5c\x89\x45\xb4\xab\xab\xe4\x67\ +\xa7\x69\xbf\x74\x80\x95\xa7\x76\xb1\xfa\xf4\x4e\xb2\xb9\x19\xfa\ +\xeb\x01\x49\x68\xd6\xf8\x45\xe7\x9c\xe4\x79\x1e\x00\x61\x57\x01\ +\x62\xad\x5d\x77\x81\xa2\x0e\xcf\xd9\xa8\xf7\xb9\x30\x16\x6c\x54\ +\x25\xdc\xb6\x95\x78\xf3\x96\x4b\x0a\x09\x73\xd5\x46\x82\x6d\x5b\ +\xa1\xa7\x17\x6d\xcc\xf8\x4a\xb0\x4c\x5b\x83\x41\xa1\xdd\x50\x5a\ +\x81\x12\xa9\x12\x5f\x46\x92\xa0\x20\x95\x1a\xa6\x52\x23\xd8\x38\ +\x4e\x78\xd3\x1d\x84\x3f\x77\x37\xd9\xfd\x7f\x41\xbe\xeb\x61\xf4\ +\x78\x03\x71\xe0\x54\xc8\x33\x25\x2a\xf4\x15\xcb\xd8\xb0\x5e\x27\ +\xbc\xf6\x3a\x2a\xd7\x5e\x47\xcf\x5b\x7f\x81\xe5\x1d\x0f\x73\xfe\ +\xcf\xff\x98\x7c\xe1\x19\x9c\x73\x6b\xf2\x59\x6b\xc9\xf3\x5c\x80\ +\xc0\x5c\x89\x95\x55\xa7\x68\x07\x5c\xc7\x97\xad\x18\x50\x57\x10\ +\x5d\x37\x41\x72\xc3\x75\x2f\xe7\xaa\xc5\x10\x6d\x1b\xc7\x0c\x6f\ +\xc4\xb5\x42\xdc\xac\x43\x97\x94\xa0\xcf\x63\x84\x8b\xa1\x48\x15\ +\x17\xac\x11\x5c\xa8\xb5\x74\x1a\xab\x74\x9a\xab\x14\xad\x16\xea\ +\xdc\x9a\x60\xc1\xe6\xad\x84\xef\xb8\x07\x19\xdb\x82\xe9\x0d\xb0\ +\xf3\x8a\x9d\x71\xe4\x8b\x0e\xdb\xd1\x4b\x18\x63\xe7\x1c\xce\x59\ +\x5c\x79\xff\x7a\x65\xf4\xbd\xfd\x5d\xf4\xbe\xfd\x97\x09\x7a\x36\ +\x78\x17\x5e\xc7\x30\x77\x3f\xc3\x4b\x14\x50\x5e\x20\x02\x12\x81\ +\x89\x7d\xfc\x56\x0b\x2e\xcb\x49\xb6\x6c\x27\xdc\x76\xed\x95\xcb\ +\xca\x8d\x63\x98\xf1\xab\xe1\xe4\x0b\x04\xd9\xaa\x0f\x57\x6d\xa0\ +\xe2\x93\x1f\xb2\x92\xef\x2a\x85\x6c\x2e\x2d\x70\xe0\xef\xef\xc7\ +\x39\x4b\xda\x3b\xc0\xc6\x57\xdd\xcc\xf0\xc4\x35\xc4\x95\x2a\x12\ +\x04\x04\x9b\xae\xc6\x8d\xbf\x0a\xf7\x9d\x93\x04\xbd\x0e\x75\x86\ +\xa2\x66\x20\x94\xf5\x9c\x39\xf3\xa7\x4f\x32\x7f\xfa\x14\xce\x39\ +\xea\xc3\x1b\xe8\xdf\x3c\x4a\xb5\x7f\x00\x63\x0c\x26\xad\x30\xf0\ +\xcb\xef\x66\xe1\xe1\x87\x20\x0a\xd7\x94\xbc\x5e\x11\x21\x50\x6a\ +\xd1\xa1\x5a\x2a\xc3\xf8\x8c\x4b\x82\x92\xd4\xb4\x8a\xd3\x80\x78\ +\x6c\x2b\xe9\xd8\x38\x00\xce\x5a\xb2\x56\x8b\xb8\x52\xc1\x04\x01\ +\xe1\xc6\x51\xc2\xf1\x71\x8a\x81\x3a\x2c\xad\x22\x2a\xb0\x02\xb4\ +\x15\x6d\xe3\x51\x7e\x9d\xa1\xe5\x8b\x0b\x5c\xf8\xca\xe7\x20\xcf\ +\x28\xf2\x80\xe5\xdb\x6f\xc3\xdc\xf3\x51\x46\x5e\xfd\x7a\x7f\x41\ +\x94\x90\x0f\x6e\x01\x35\x44\x69\xc9\x2b\x24\xc6\x87\xdb\x35\x4b\ +\x75\x4c\x7f\xeb\x29\x0e\x7f\xf9\xf3\x34\xe6\xe6\x49\x37\x6f\x63\ +\xeb\x3f\x7f\x07\xd7\xbf\xf3\x9d\xf4\x8f\x6c\x46\x44\xa8\x4c\x5c\ +\x43\xb4\x6d\x2b\x54\x52\xaf\x00\xbd\x68\x39\x6b\x0a\x58\xf3\xff\ +\x2e\x07\x6b\x3d\x45\xe5\x72\xc5\x00\x06\x87\xd9\x34\x42\xb2\x75\ +\x1b\x51\x5f\x3f\x00\x59\xb3\xc9\xd9\x03\xcf\x33\x34\x31\x41\x7d\ +\xc3\x55\x44\x3d\x75\xc2\x4d\xe3\x14\xb5\x21\xf4\xdc\x39\x1c\xea\ +\x79\x81\x58\x7c\x9c\x0f\x29\x99\x62\xaf\x87\x48\x0b\xb6\x15\x33\ +\x24\x45\x46\x73\x36\x23\x7b\x21\xc6\x4e\x4f\x52\xdc\xf4\x3a\x42\ +\xe3\x73\x80\x4e\x1c\x11\x05\xa0\x2d\x87\x16\x0e\xd7\xe3\xc0\xae\ +\x77\x57\x25\x9a\x9b\xa3\xff\xe8\x11\xa2\xc9\xb3\x74\x4e\x9c\xe2\ +\x82\x38\xe6\xc6\xc7\xe8\x1f\xd9\xbc\xce\xa5\xc6\xd0\xb4\xba\x26\ +\x63\x17\x07\x5e\xa6\x80\xf5\x2c\xb5\xb3\x0a\xae\x54\x88\x58\xc2\ +\xed\xdb\x09\xb7\x8c\x23\x71\xe4\x15\xb0\xba\xc2\xe4\x53\x4f\x42\ +\x91\x53\xe9\xeb\x27\x4a\x53\xcc\xc6\x51\x18\x1e\xc3\x1d\x3a\x84\ +\xb1\x0e\x8d\xd5\xc7\x65\x2b\x10\xc0\x3a\x92\x9b\x00\x65\xb4\x2a\ +\xd4\x9c\x21\x6f\xa5\xac\xf6\x0e\x10\x26\xd5\x35\x23\x51\x55\x5a\ +\x8b\xe7\x09\x70\xb8\x0e\x3e\xee\x77\x4a\xee\xb0\x0b\xa2\x0a\x3d\ +\x61\xc4\xd5\xd5\x1a\x59\xb5\xce\xaa\x16\x64\xe7\x4f\x53\x4c\x9d\ +\x59\x7b\x86\x88\xe0\x7a\xfa\x21\x8a\xbc\x60\xe5\xf1\x4b\x14\xd0\ +\x45\xc8\xf5\x3c\x91\x04\xa5\x0b\x38\xc1\x59\x88\xc6\x27\x08\x47\ +\x46\x51\x13\xe0\x54\xc9\x97\x16\x59\xd9\xfb\x14\x0b\x3d\x3d\x8c\ +\xdc\xf2\x33\x84\x69\x8a\x8c\x8c\x22\xdb\x26\xd0\xef\x7d\x1d\x69\ +\xb4\xd0\x1c\x5c\x53\x71\x6d\xc5\x15\x0e\x67\x1d\x0a\x38\x55\x88\ +\x12\x64\xe2\x67\xb0\x6a\x91\xb1\x0a\xb5\x5b\xdf\x88\xd9\x3a\x81\ +\x31\x82\x05\x5a\x17\xe6\x68\x1f\x3c\x44\x3d\x2b\x90\x44\x20\x14\ +\x24\x16\x54\xbc\x1a\x7d\xa4\x72\x88\x58\xc2\xc8\x4b\xd2\x53\x80\ +\x86\x29\xf5\x4a\xa5\xbc\xc6\x21\x41\x40\x3b\xeb\x90\xd8\xe2\xe2\ +\x04\x5c\xee\x02\x97\xad\xbf\x79\x0c\x08\x40\x4a\x53\xd4\xb0\x4a\ +\x3c\xba\x95\x70\x70\x08\x44\xc8\xda\x6d\x9a\x67\x27\x89\x8e\xbd\ +\x48\x3e\x36\x81\x6d\xb6\x70\x7d\xfd\x04\x57\x6d\x24\xd8\xba\x15\ +\xdb\x57\x41\x8a\x16\x7a\x41\xb1\x40\xd1\xf6\x4a\x50\xa7\x9e\xf7\ +\xb7\x05\x66\xe8\x2a\xa2\x8f\xfd\x67\x54\x14\x89\xab\x04\xbd\x7d\ +\x48\xad\x8e\x5a\xcb\xca\xec\x0c\xd3\x5f\xdf\x05\x07\x8f\x20\xb9\ +\x85\xbe\xb2\x68\x4a\x14\x0d\xfd\x33\x9c\x3a\x54\x1d\x84\x01\x54\ +\x62\x4c\x5f\x42\xa0\x75\xa2\x89\x9b\xa8\x4e\x5c\x8b\x2d\x31\xc2\ +\x04\x01\xad\xf3\xd3\x04\xad\x66\xb9\x18\xa3\x2f\x07\xc1\xae\x39\ +\xac\x73\x2d\x9c\x53\x9c\x2a\x62\x95\x60\xeb\x16\xc2\xb1\x51\x24\ +\x4d\x51\xa0\x39\x7f\x81\xd9\xfd\xcf\x30\x94\x77\x60\xf2\x0c\x8d\ +\xd9\xf3\x04\x83\x83\x04\x49\x42\xb0\x61\x33\xb2\x61\x0b\x6e\x66\ +\x1e\x50\x82\x01\xc1\x34\x58\xe3\xf1\x1c\xe0\xac\x83\x30\x46\xae\ +\xbe\xc6\x27\x42\xea\xf1\x41\x8c\xa1\xbd\xba\xca\xf4\xb3\x7b\x39\ +\xf5\xe0\xff\xe5\x3a\xbd\x80\x29\x7c\x14\xc2\xe9\x1a\x9b\xec\x95\ +\xe8\xad\x36\x1c\xd9\x0c\x37\xdd\x8a\x1b\x6f\x52\x7f\xcd\xcf\x52\ +\xb9\xeb\xe7\x89\xb7\x4d\xe0\xb2\x0c\x55\xa5\x68\xb7\x29\x26\x27\ +\xa1\xd9\xf2\x18\x54\x0a\x7e\x65\x17\xd0\x8b\x20\x68\xdb\x8a\x69\ +\x3b\x50\x25\xda\xba\x0d\xd9\xb4\x19\x17\x45\x38\xa0\x7d\xe1\x02\ +\x17\xf6\x7c\x9b\xcd\x0d\xa1\x68\x2e\xb0\x78\xe2\x08\xc9\xe8\x18\ +\x95\x38\xc1\xf6\x5f\x45\x67\xf8\x7a\xcc\xdc\xb3\xa4\x83\xa1\x1f\ +\xac\x51\x48\x1c\x4e\x1c\xb6\x34\xdd\x35\xb0\x59\xf3\x39\x1f\x59\ +\x82\xb4\xc2\xf8\xeb\xdf\xc8\x55\xed\x0f\x23\x5f\xf8\x33\x68\xcf\ +\x52\xcc\x5a\xb2\x8e\x23\x37\x8e\xb8\x65\x4b\x25\xfa\xc5\x82\x9e\ +\x9f\x7b\x27\xbc\xe5\x17\x3c\x28\x18\x03\x81\x41\xad\xc3\x8a\xa0\ +\x45\xc1\x91\x5d\x4f\xd2\x38\x72\x9c\x81\xac\xc0\x18\xb3\x86\x77\ +\x97\xb8\xc0\xe5\x18\x20\xe2\xab\x3b\x89\x05\xd4\x10\x8f\x6d\x25\ +\xda\x30\x82\x44\x31\xce\x29\xc5\xfc\x2c\xee\xe0\x77\x08\x22\x47\ +\xfb\xdc\x0c\xed\x63\x47\xb0\xaf\xb9\x0d\xed\x1b\x20\xd8\xb8\x91\ +\xe8\xd5\x37\x52\x3c\xea\x17\x43\x24\x16\x6c\xc7\x2b\xd4\x59\xb7\ +\x06\x60\x9d\x95\x65\x26\x9f\xfd\x36\xea\x2c\x51\xa5\x4e\xff\xf8\ +\x38\xd5\xa1\x61\xc2\x38\x26\xe8\x1d\xa0\xf2\xc6\xb7\xd2\x39\x7d\ +\x92\xe2\xc4\x17\xa0\xa7\x8d\xa9\x0b\x52\xf7\x96\xa4\xeb\x73\x97\ +\x20\x44\xa2\xe8\xb2\xfc\x52\xb1\x79\xce\xd2\xd4\x24\xa7\xbf\xfa\ +\x65\xc2\xe9\xd3\x04\x5d\x8e\xed\x95\x30\xe0\x12\x96\x5c\x00\xe3\ +\x57\x70\x64\x68\x98\x68\xcb\x38\xa6\x56\x03\x11\x3a\x8d\x06\xf9\ +\xf2\x12\x7d\x7d\xbd\x44\x1b\x37\x12\x65\x06\x1a\x6d\x5c\x27\xc3\ +\xda\x02\x53\xeb\x21\xbe\x7a\x2b\xf9\x55\x43\xd8\xe3\x17\x10\xe3\ +\x28\x5a\xea\xa9\x2c\xab\xde\x77\x81\xe6\xcc\x0c\x2f\x7c\xf2\x0f\ +\x21\xcf\x50\x0c\xf5\x1b\xaf\x63\xfc\x17\xee\x66\xec\xb6\x37\x51\ +\x19\x18\x42\xeb\xfd\xd8\x57\xbd\x91\x9c\xfb\x89\xa2\x32\x22\x45\ +\x0a\x81\x4f\xd5\xbb\x02\xd8\xa2\x83\x2d\x0a\xbf\x8a\x64\x1d\x45\ +\x96\xd1\x59\x5d\xe1\xc2\xb1\x63\x9c\x7a\xf4\x61\xec\xd3\xbb\xa9\ +\xb5\x57\x09\x4c\x77\x61\x56\x5e\x9e\x09\x5e\xb4\x80\x75\x28\x59\ +\x28\xce\x7a\x1f\x0b\xb6\x6c\x81\x24\xc6\x15\x05\x36\xcf\x48\xc7\ +\xc6\xd9\xfc\xaf\x7f\x97\x38\x8a\x89\x73\x07\xa3\x63\x98\x4a\x15\ +\x9b\xe7\xbe\x2c\xee\x1f\xc6\x4e\xdc\x84\x9c\xd8\x45\x18\x19\x5f\ +\x4c\x19\x8f\x29\xea\xbc\x1b\x98\xbc\xcd\xe8\x85\x63\xc4\x79\x46\ +\xb6\x6c\x69\xce\x4f\xb3\xda\xd3\x4b\x63\x6c\x82\xb4\x7f\x08\x15\ +\x41\xae\x9e\xc0\xd6\x6b\x48\x63\x99\x22\xf7\x69\xb0\x2b\xdc\xda\ +\x78\x9d\x73\x9c\x3f\x74\x88\xb9\x43\x07\xc9\x5b\x2d\x6c\x9e\x93\ +\xaf\x2c\xd1\x3a\x7f\x8e\xd6\x91\xa3\xd8\x17\x0f\xb0\xa1\xb5\x42\ +\x54\xb8\x4b\x00\xee\xfb\x24\x42\xeb\xf2\x80\x02\xac\x1a\xe2\x91\ +\x51\xc2\xcd\xa3\x10\x46\xd8\xa2\xc0\x88\x50\xdd\xb2\x15\x19\xbb\ +\x1a\x05\x12\xca\x04\x27\x08\x70\x85\xf7\x4b\x57\xef\x87\x9b\x6e\ +\xc3\xee\x7c\x82\x30\x0d\xc1\x81\x0b\x40\x71\x6b\xb3\x17\x18\xd8\ +\x36\x54\xa7\x52\x74\xc8\x8d\x63\x31\xcb\xe9\xcc\xce\xe2\x96\x97\ +\x70\x28\x2a\x42\xd0\xdf\x4f\xde\xd7\x0f\x0b\xe7\xb0\x1d\x87\x6d\ +\x2b\x36\x2f\x05\x50\xc5\x15\x05\x8b\xcf\x7d\x97\xe9\x7f\xf8\x32\ +\xed\xb9\x79\x04\x07\x59\x0b\x5d\x5a\x22\x5e\x5c\x66\xd0\x2a\xf5\ +\x28\xf4\x39\x84\xbb\x58\x80\xfe\xc0\x3c\x40\x7d\x11\x08\x95\x0a\ +\xd1\x96\x71\xc2\x81\x41\xd4\x18\x70\x0e\x09\x43\x4c\x9c\xbc\xac\ +\x1c\x53\xeb\x50\x67\xb1\x45\x8e\xd4\xea\x44\x37\xdc\x4c\x3b\x48\ +\x08\xda\x4a\xd1\x76\xe5\xcc\x95\xc5\x8b\xfa\xff\xf3\x95\x8c\xb0\ +\xc8\x71\x6d\x4b\xb5\x56\x23\x19\x1e\x24\xa9\x56\xb1\x85\x2d\x81\ +\x52\x68\x4b\x40\x50\xae\xab\xab\x28\xaa\xae\x4c\xdd\xbd\x35\x85\ +\xf3\xb3\xf4\x9f\x3c\x44\x7e\x76\x06\x11\x43\x10\x08\x91\x18\xe2\ +\x20\xc0\x04\x1e\x17\xf2\x2b\xb4\xdd\x7c\xff\x3c\x40\x14\x8d\x04\ +\x19\x1e\x24\x9a\x98\x40\x92\xc4\x87\x94\x4e\x87\x4e\xa3\x41\xd1\ +\x69\xaf\xa5\xb5\xdd\x94\x2c\x8c\x63\xa2\x6a\x95\x30\x4e\x90\x28\ +\x26\xda\xb8\x89\xc6\xa6\xab\x29\xa6\x8f\x53\x34\x2c\xb6\xe3\x13\ +\x21\xd7\x15\x40\x05\x1b\x0d\x92\x4b\x86\xf4\x0b\xe6\xc6\xed\x04\ +\xaf\x7d\x1d\x66\xc3\x46\x5c\x91\xfb\x59\x6a\xb7\x69\xcd\x5c\xa0\ +\x12\x58\xbf\x86\x10\x2b\x1a\x5c\x54\xa2\xaa\xa3\x16\x1b\x92\x9e\ +\x14\xd7\xaa\x50\xb4\xf0\x8a\x2e\x93\x2d\x4f\x9f\xfb\xda\x06\xb9\ +\x72\xdf\xd1\x95\xf3\x00\xa7\x38\x0c\x3a\x38\x4c\xb0\x6d\x3b\x1a\ +\x04\x88\x31\xcc\x1d\x3f\xc6\x81\xaf\x7c\x89\x33\xdf\xde\x43\x10\ +\x45\x65\xd7\x12\x60\x2c\xc3\x37\xdc\xc4\x0d\xef\xf8\x45\x46\x6f\ +\x7d\x0d\x61\x10\xe2\x92\x94\xe2\xf5\xb7\x11\xee\x38\xe9\x31\x40\ +\xf4\x62\xd1\x55\x14\x04\x83\x43\xa4\xbf\xf5\x7b\x04\xce\x41\x5a\ +\xc7\x8c\x8f\x23\xc3\x1b\x21\xad\xe0\xac\xc5\xda\x82\xe5\xa9\xd3\ +\x98\x95\x65\x30\x0e\xeb\xc0\xe6\x65\x1e\xe0\x1c\xea\x9c\x27\x69\ +\x0a\xbf\xe4\x6e\x33\xc5\xa9\x40\xd0\x5d\x49\x2e\x6b\x1a\x51\xac\ +\x5b\x17\x71\xbb\xe4\xc9\xf7\x77\x01\xc5\x3a\x43\x30\xb8\x91\x74\ +\xfc\x6a\x08\x02\xd4\x18\x96\x8f\x1d\x41\x9f\xfe\x06\x63\x07\x5e\ +\x24\x4a\x22\x44\xfc\xb2\x95\x09\x1c\x79\x7b\x85\xec\xba\xeb\xc9\ +\xae\xbb\x1e\x93\xa6\x90\x26\xc4\x6f\xbc\x03\xbb\xf3\x7e\x9c\x71\ +\x68\x54\x9a\xb0\x75\xa8\x75\x50\xad\x11\xfe\xec\x5d\x17\xa3\x4f\ +\x18\xfa\x38\x0e\x20\x86\xce\xf2\x32\x87\xbe\xf4\x79\x36\x6b\x93\ +\xce\xbc\xc5\x15\x96\x3c\xb5\xd8\xce\xc5\x38\xae\xce\xe1\xda\x8e\ +\x7c\xd9\xe1\x56\x1d\x92\x1a\x24\x2e\x59\x6a\x05\x9b\xf9\x88\x63\ +\xf3\x2e\xea\xcb\x95\x5d\xe0\x65\xc5\x90\x31\xc8\x60\x1f\xf1\xab\ +\x6e\x24\xac\x54\x10\x63\xc8\x0b\x8b\x9e\x3a\x4d\xcf\xd9\x29\x7a\ +\x13\x25\xaa\x94\xa1\xa9\x80\x30\x14\x16\xcf\x4e\xc1\xd4\x24\xb6\ +\xd5\xf2\x1d\x40\x71\x42\xe5\xda\xeb\x59\xee\x1d\xc0\x2e\x2c\x63\ +\x33\x8b\x77\xeb\x92\x08\x15\x83\x24\xe9\x25\x21\x49\xfd\x09\x16\ +\xcf\x4e\x73\x7a\xc7\x43\x98\x3d\xbb\x30\x2b\x6d\xcf\x1d\x5a\x45\ +\x52\xf5\x33\x2c\xdd\xe7\x08\x9a\x80\x54\xbc\x7b\x38\xa7\x90\x7b\ +\xf3\x77\xae\x24\x72\xe4\xe5\xed\x38\x3f\x44\x31\x24\xb8\x34\xa5\ +\x55\xad\x32\x73\xf2\x24\x26\x8c\x68\x2c\xcc\xb3\x7a\xf0\x30\x49\ +\xab\x45\x1c\x19\x8c\x94\x99\x65\x01\xd2\x86\xb8\xdd\x24\x3f\x7a\ +\x8c\xb9\x17\x0f\xb0\xda\x69\x21\x4e\x61\x65\x85\x4e\xcf\x26\x8a\ +\xce\x24\xed\xc5\x06\x8b\xd3\x53\xe4\x27\x8e\xe1\xda\xed\x75\xf8\ +\xe1\xf3\xfa\xac\xb9\x42\x67\x71\x81\xa5\x93\x27\x59\xdc\xbf\x1f\ +\x79\xe1\x79\xc6\x16\xe6\x30\x56\x3d\x00\x2b\x58\x2d\x58\x99\x9f\ +\xc5\x1e\x3d\x8a\xeb\xb4\x21\x2f\xe8\x2c\x2c\x80\x2d\x20\x04\xd7\ +\x71\xd8\xac\xeb\x6e\xde\xfc\xdd\xba\xe8\xe6\x09\xce\x2b\x58\x00\ +\x5d\x98\x28\x19\x91\x70\x60\x40\x64\xe3\x26\x8e\x7c\xf9\x4b\xb4\ +\x1f\x7f\x1c\x4c\x80\x74\x9a\x0c\x9c\x99\x64\x28\x2f\x70\xa1\xff\ +\x91\xf2\x79\x88\x40\x12\x05\x2c\xbc\xf0\x1c\x53\x4b\x0b\x74\x7a\ +\x7b\x11\x20\xca\x2d\xa3\x33\xa7\x49\x43\xa1\x79\xfa\x04\x67\xff\ +\xf6\xaf\x29\x1e\xec\x87\x52\xfb\xdd\x2e\x10\xcd\x14\x8a\x0e\xd2\ +\x69\x22\xf3\xf3\xc4\x73\xb3\x0c\xda\x0e\x3d\x71\x0c\x45\xd7\x94\ +\x85\xf6\xec\x3c\xb3\x0f\xfd\x03\x2b\xcf\x7c\x1b\xb5\x16\x93\x2b\ +\x23\x33\x53\xf4\x2c\x37\x90\x42\x71\xca\x25\xd5\xa2\x07\x42\xa8\ +\xde\x7c\x23\xe1\xe0\x20\x65\x25\x24\xeb\xfa\xb5\xbc\x02\xf2\x3c\ +\x6f\x34\x9b\xcd\x22\xcb\x32\xc2\x38\x96\x74\xeb\x36\xbd\xea\x97\ +\x7e\x59\x2e\x7c\xee\xaf\x59\x7d\x7a\x0f\x0a\x54\x42\x88\xd2\x18\ +\x09\x23\x0a\x27\x18\xd5\x72\x61\x04\x34\x12\x82\x28\x20\xba\x30\ +\x43\x38\x79\x86\x5c\x9d\x27\x22\x82\x80\x70\xb8\x4a\x14\x85\x54\ +\x96\x2e\xd0\x3a\x3b\x8d\x5a\xbb\x56\x6e\xfb\x16\x19\xd0\xa6\x12\ +\x8a\xef\x30\xa9\x06\x21\xbd\x69\x48\xad\xc7\x87\xda\xa2\xed\x28\ +\xda\xe5\xd2\x57\xd6\x24\x98\x79\x1e\xf3\xbd\x67\xfc\xac\xb6\x15\ +\x4d\x13\x5c\x12\x43\xee\x85\x27\xf4\x5c\x86\x53\x87\x4a\x40\x65\ +\xfb\x35\x6c\xb8\xe7\x5e\xd2\x6d\x13\x8a\x73\x92\x65\x19\xcd\x66\ +\xb3\xc8\xf3\xbc\xd1\x55\x80\xce\xcc\xcc\xbc\x34\x39\x39\x79\x32\ +\x4d\xd3\x9e\x8d\x41\x10\x56\x47\x46\xd8\xf4\xde\xf7\x91\x0a\xcc\ +\xdd\x77\x1f\xed\x93\xc7\x11\x57\x78\x9a\x1c\xc5\xaa\x2f\x35\x05\ +\xf1\x09\x46\xee\x4d\xa1\x1e\x84\xf4\xf4\x44\x7e\xcd\x4f\x7d\x4d\ +\x61\xc4\x40\xa6\xf4\x07\x01\x83\x3d\x35\x24\xe8\x22\xb2\x10\x94\ +\x3d\x9e\x36\x2a\x01\xca\x74\x13\x16\xf5\xb3\x2e\x42\xd1\x2d\xd2\ +\x14\x12\x23\x6c\xae\xa4\x8c\x06\x09\xaa\x50\xc4\xd6\x27\x6d\x65\ +\x5f\xa1\xba\x6e\x06\xeb\xd0\x20\x22\xdd\x3a\xc1\xf0\xfb\x3e\x40\ +\xff\xaf\xbc\x07\xed\x1f\xa0\xd9\x6a\x32\x3b\x3b\x5b\x4c\x4e\x4e\ +\x9e\x9c\x99\x99\x79\x09\x9f\x9f\x91\x2c\x2d\x2d\x35\x92\x24\x89\ +\xa3\x28\xda\x98\x26\xc9\x50\xa5\x52\x91\xa0\x56\xd3\xca\xb6\x09\ +\x31\x81\xa1\x3d\x39\x45\xb1\xb4\x84\x2b\xac\xaf\x0f\x42\x5f\x57\ +\x28\xfe\x07\xd5\xe1\x5b\x5b\x04\x24\x12\x4c\x59\x9b\x14\x6d\x8f\ +\xc2\x9a\x79\xbe\x91\x08\x24\x36\x28\x50\xb4\x7c\x32\x53\xe4\x3e\ +\xbb\x33\x69\x49\x78\xa8\xc3\xe5\x8a\xcd\x1d\xd6\x2a\x2e\x73\xbe\ +\x49\x2a\x2a\xc1\xab\xbc\xde\x5a\x1f\x02\x25\x04\x82\x2e\xcd\xa5\ +\xd8\xc2\x41\x10\x92\x5e\xbd\x9d\x0d\xf7\xdc\x43\xff\x7b\xde\x83\ +\xeb\xeb\xd3\x4e\xa7\x23\x67\xcf\x9e\xd5\x43\x87\x0e\x1d\x79\xe6\ +\x99\x67\x1e\x7c\xec\xb1\xc7\x1e\x9b\x9d\x9d\x9d\x0f\x80\x60\x76\ +\x76\x36\x3f\x72\xe4\xc8\x5c\xa5\x52\x21\x8a\xa2\x91\x38\x8e\x07\ +\x7b\x7a\x7b\xc5\x54\x2a\x5a\x9d\xb8\x06\x11\x95\xec\xec\x34\xf9\ +\xc2\x22\x58\x77\x91\xdb\x2b\x57\x6a\x25\x10\x14\xf1\x40\xda\xf5\ +\x41\xeb\x97\xb3\x25\x64\xcd\x27\x11\x0f\x33\x2e\x2f\x41\x28\xea\ +\xc6\x64\x5d\x2b\xd5\xbb\x35\x88\x1a\x01\x51\x6c\xc1\x9a\x65\xd8\ +\xdc\xb7\xda\x69\xd9\x57\xe1\x4d\x1d\xd4\x09\xb6\xcc\x0f\x30\x01\ +\x95\x6d\x13\x0c\xbf\xff\xfd\x0c\xbe\xf7\xfd\xea\x7a\xfb\xc8\xad\ +\x95\xd3\xa7\x4e\x71\xe0\xc0\x81\x63\xdf\xfc\xe6\x37\x1f\xb8\xef\ +\xbe\xfb\x1e\x3a\x7d\xfa\xf4\x19\xa0\x15\x74\xd7\x67\x5a\xad\x56\ +\x7e\xf4\xe8\xd1\xf3\x49\x92\xb4\xe2\x38\xde\x14\xc7\xf1\x50\x5f\ +\x7f\x3f\x52\x49\xa9\xdd\x70\xa3\x18\x55\x3a\x93\xa7\xc9\xe6\x2e\ +\xac\x09\xae\x56\x3d\x6d\x66\xc0\x18\xf5\x1d\x23\xb9\x4f\x42\x5c\ +\xee\xdb\xe2\x24\x34\xe0\xb3\x68\x5c\xae\x14\x1d\x3f\x53\x12\x97\ +\x4d\x51\x52\x0a\x97\x95\x25\x73\xb9\x0e\x21\x21\x68\xd9\x03\x50\ +\x74\x1c\x45\xae\xb8\x52\x19\x84\x5d\xc1\xfd\x33\xbb\x33\xef\xd4\ +\x51\xd9\x3e\xc1\x86\x0f\x7c\x90\xc1\x0f\x7e\x08\x5b\xaf\x53\x58\ +\xcb\x89\xe3\xc7\xe5\xb9\xe7\x9e\x3b\xf2\x8d\x6f\x7c\xe3\x8b\x5f\ +\xf9\xca\x57\xbe\xb6\xb4\xb4\x34\x89\xe7\xac\x9b\xdd\x06\x09\x07\ +\xd8\x2c\xcb\xf2\x53\xa7\x4e\xcd\x85\x61\xb8\x9c\xa6\xe9\x58\x1c\ +\xc7\x43\xbd\xfd\xfd\x22\x49\xa2\x3d\x37\xbf\x1a\x51\xa4\x79\xf4\ +\x18\xf9\xfc\x05\x4c\x14\x96\x83\xd7\xb5\x19\x52\xe7\x85\x92\xd0\ +\xcf\x9e\x2b\xd4\x77\x7f\xba\x8b\x33\x29\x51\x49\x4b\x59\x20\xf4\ +\x94\x9b\xed\xf8\xf5\x3d\xc2\x12\xa8\x9d\xef\x1d\x76\x40\xd1\xb4\ +\xde\x52\x02\x59\x8b\xef\x5d\x58\x28\x0a\x8f\xf2\x2a\x8a\xed\x74\ +\x48\xc7\xaf\x66\xe4\xd7\x3f\xca\xf0\xaf\xff\xba\x16\x69\x4a\x6e\ +\xad\x74\x85\x7f\xea\xa9\xa7\xfe\xe6\x91\x47\x1e\xd9\xb9\xb2\xb2\ +\x32\x09\x2c\x02\x2d\xc0\x76\x2d\xc0\x89\x88\x05\x6c\xa7\xd3\xc9\ +\xce\x9f\x3f\xbf\x14\xc7\xf1\x6a\x9a\xa6\x9b\x2a\x69\x3a\x54\xad\ +\xd5\x24\xa8\x56\xa5\x76\xdd\x75\x1a\x55\x2a\xd2\x38\x74\x90\x6c\ +\x61\xbe\x64\x5f\x14\xe7\x04\x6b\x3d\xe5\x2c\xeb\x92\x0f\x97\x97\ +\xa0\x54\xb6\xbe\x11\x78\x41\xbd\x39\x7b\x8e\xc0\xe6\x1e\xb4\x24\ +\xf4\x1c\x84\x73\x4a\x51\x5c\xea\xeb\x5d\xc5\x38\xf5\xee\x51\xe4\ +\xba\x66\xf2\x8a\x62\xdb\x1d\xe2\xd1\x51\xc6\x7e\xf3\xb7\x19\xba\ +\xf7\x83\x6a\x6b\x35\x69\xb7\x5a\x32\x79\xe6\x0c\xcf\x3f\xff\xfc\ +\xe1\xa7\x9f\x7e\xfa\x0b\x3b\x76\xec\xd8\xbd\xb8\xb8\x78\x1a\x58\ +\x14\x91\x06\x90\xe3\xf9\x95\x8b\x15\x40\xa9\x04\xd7\x6a\xb5\x3a\ +\x33\x33\x33\x0b\x95\x4a\x25\x8b\xa2\x68\x43\x25\x4d\xfb\xd2\x38\ +\x0e\xe2\xa1\x21\xa9\x6c\xbd\x5a\xa3\x9e\x1e\x69\x1e\x3d\x4a\xbe\ +\xb0\xe0\x99\xf3\xb2\x5f\x68\xad\xde\xee\x22\xb2\x2b\xc1\xf2\x22\ +\xc3\xee\xf9\x46\xeb\xcf\xa9\x78\xcc\x70\x76\x5d\xfc\xb6\x25\x06\ +\x94\x4f\xb2\xa5\x85\x75\x85\x2f\xd7\x36\x7c\xc1\xe3\x7c\x5a\x9d\ +\x8e\x5f\xcd\x96\xdf\xfa\x1d\x06\xde\xfb\x5e\x65\x68\x48\x56\x17\ +\x17\x99\x9a\x9a\xca\x9f\x7f\xfe\xf9\x23\x7b\xf7\xee\xfd\xf2\xe3\ +\x8f\x3f\xfe\xc4\xdc\xdc\xdc\xa9\xae\xf0\xaa\x9a\x77\xd3\xb0\xe0\ +\xb2\x2c\x71\x4d\x09\x8d\x46\x23\x9b\x99\x99\xb9\x50\xa9\x54\x5c\ +\x1c\xc7\x43\x95\x4a\xa5\x2f\x0a\x82\x20\x1d\x1a\x96\xea\xf6\x6b\ +\x34\x88\x22\x69\x9d\x3e\x43\xbe\xbc\xe4\xeb\x70\xfc\xb4\xbb\x6e\ +\x58\x2a\x0f\xad\x37\x79\xe7\x74\x4d\x40\xa4\x34\x79\xf1\xdc\x83\ +\xb3\x9e\x2c\xed\x0a\x4f\xe8\xc3\xa2\x2d\x13\x1c\x57\x86\x38\xd5\ +\x12\x14\x71\x38\x0c\x95\xad\xdb\xd9\xfc\xd1\x7f\xc9\xd0\x3d\x1f\ +\x54\x06\x87\x64\xf9\xc2\x1c\x67\xcf\x9e\xcd\x0e\x1c\x38\x70\x74\ +\xdf\xbe\x7d\x0f\x3e\xf6\xd8\x63\x8f\x9e\x3f\x7f\xfe\xf4\x95\x84\ +\xbf\x92\x02\xba\x4a\x70\x7e\xb5\x79\xb5\x33\x37\x37\x37\x97\x24\ +\x89\x89\xe3\x78\x30\x4d\xd3\xbe\x24\x0c\x83\xa8\xb7\x57\x7a\x6e\ +\x7c\x95\xaa\x75\xd2\x99\x9e\x26\x5f\x5a\x42\x0b\xeb\x05\x2f\x53\ +\x4f\x5f\x72\x7a\x25\x38\x57\xe6\xfb\xee\x22\x25\xdd\x6d\x8b\x77\ +\x0e\x4f\x94\x96\xd7\xbb\x2e\x75\x8e\x77\x07\x6b\x75\xcd\x9a\xdc\ +\xc5\xe5\x6d\x34\x88\xa8\x6c\x9b\x60\xe4\xde\x0f\xb2\xf1\xc3\x1f\ +\x51\x5b\xab\xc9\xca\xc2\x02\x53\x53\x53\xd9\x0b\x2f\xbc\x70\x74\ +\xef\xde\xbd\x5f\xdb\xb1\x63\xc7\x23\xd3\xd3\xd3\xa7\x80\x05\x11\ +\x69\x5e\x2e\xfc\x2b\x29\xa0\x9b\xa5\x5b\xc0\x2e\x2f\x2f\xb7\x66\ +\x66\x66\xe6\xa2\x28\x92\x28\x8a\x86\xd2\x34\x1d\xa8\x56\xab\xc6\ +\x24\x09\xf5\x1b\x6f\x14\xa3\x8e\xf6\xe4\x14\xd9\xe2\x92\x6f\x50\ +\x30\xbe\x27\x00\x29\x73\x83\x12\xb8\x5c\xb9\xe6\xe8\x43\xa6\x9f\ +\x59\xd5\x75\x16\x51\xce\xb8\x67\x7a\xdc\xda\x71\x67\x3d\x76\x78\ +\x32\x44\xb1\xd6\xc7\xf9\xca\xc4\x04\x9b\xee\xb9\x97\x0d\xbf\xf6\ +\x6b\xd8\x34\xa5\xd5\x6c\xca\x99\x33\x67\x8a\x03\x07\x0e\x1c\xd9\ +\xb3\x67\xcf\x23\x3b\x76\xec\x78\x78\x6a\x6a\xea\x78\x09\x78\x0d\ +\xdf\xe5\xf0\xf2\xb6\x82\xef\xa7\x00\xd7\x7d\x7f\x61\x65\x65\xa5\ +\x31\x37\x37\x37\x17\x86\xa1\x0b\x82\x60\x43\x9a\xa6\xc3\x7d\x7d\ +\x7d\x62\x92\x44\xeb\xd7\x5e\x87\xc1\x48\x6b\x72\x92\xce\xc2\xfc\ +\x1a\xf3\xeb\x5c\x59\xfa\xae\x95\x18\xac\x2d\xbe\x6a\xd7\x15\xd6\ +\x7a\x11\xbc\xc7\x3b\x55\x6c\xd7\x55\xba\xee\xd4\xcd\xe9\x9d\x17\ +\x5e\x4d\x40\x75\xfb\xb5\x6c\xbe\xf7\x57\xd9\x70\xcf\x3d\xea\x6a\ +\x35\xf2\xa2\x90\x13\x27\x4e\xf0\xbd\xef\x7d\xef\xf0\xde\xbd\x7b\ +\xbf\xba\x73\xe7\xce\x47\xa6\xa7\xa7\x8f\x77\x43\x5d\x17\xf0\xae\ +\xf8\x1a\xda\x0f\x68\xa7\xef\x2a\xc1\xae\xac\xac\xb4\x2e\x5c\xb8\ +\x30\x63\x8c\xe9\xa8\xea\xc6\x30\x0c\x87\x87\x86\x86\x90\x34\xa5\ +\xb6\x7d\xbb\x04\x41\x40\x7b\x6a\x8a\xf6\xcc\x9c\x4f\x56\xba\xb4\ +\x9a\xf1\x4d\x53\x97\x08\xee\xca\xc6\xa6\xf2\xb5\x99\xae\x95\x58\ +\xab\x17\x5d\x48\x64\xcd\x0d\x9c\xfa\x64\xc9\x39\xa8\x5f\x77\x3d\ +\xa3\xbf\xfa\x21\x36\xbc\xef\x7d\x68\x6f\x2f\x85\xb5\x1c\x3c\x78\ +\x50\x9e\x7d\xf6\xd9\x43\xfb\xf6\xed\xbb\x7f\xf7\xee\xdd\x5f\x9b\ +\x9e\x9e\x3e\x09\x2c\x95\xc2\x67\xaf\x24\xfc\x0f\xa3\x80\xcb\x95\ +\xd0\x39\x7f\xfe\xfc\x9c\x31\x66\x25\x08\x82\xd1\x20\x08\x86\x07\ +\x07\x07\x25\xa8\xd5\xb4\xb6\x7d\xbb\x04\x61\x48\xeb\xc4\x71\x1a\ +\x8b\x8b\xd8\xf2\xfd\x87\xc2\x2a\x85\xf3\xbb\x75\x17\xbf\x17\xd6\ +\xef\xd6\x2a\x79\x79\x6e\xfd\xf9\xbc\x3c\x5f\xa8\x5f\x10\xb6\x40\ +\xef\xb6\xad\x6c\xf9\xc8\x47\xd9\xf0\x81\xf7\xa3\x7d\xfd\x9a\xe5\ +\xb9\xbc\xf8\xe2\x8b\xb2\x7f\xff\xfe\xc3\x7b\xf6\xec\xf9\xdb\x5d\ +\xbb\x76\x3d\xd1\x05\xbc\x32\xce\xe7\xdf\x4f\xf8\x1f\xf6\x8d\x11\ +\x05\x0a\x11\x69\xa9\x2a\x73\x73\x73\x6e\xf7\xee\xdd\x3b\xad\xb5\ +\xd6\x39\xf7\x11\xe0\xba\xeb\x6f\xb8\x41\xaa\x03\x03\x3a\xfc\x9e\ +\xf7\x30\x74\xfb\xed\xe2\x96\x97\xaf\xdc\x8f\x2f\xeb\x8f\xe8\x2b\ +\x74\xee\xeb\x25\x2f\x0d\x5d\xb2\x64\xd9\xdb\x8b\x6c\xde\xac\x32\ +\x30\x40\xab\xd9\x92\x43\x07\x0f\xf2\xec\xb3\xcf\x1e\xde\xb3\x67\ +\xcf\x67\xbf\xf1\x8d\x6f\xec\x9e\x9f\x9f\x3f\x0d\x2c\x97\x63\x2d\ +\x7e\x90\xf0\x3f\xca\x2b\x33\x4e\x55\x73\x11\xdf\x4c\x36\x3f\x3f\ +\x7f\x6a\xe7\xce\x9d\x4f\x1a\x63\x22\x11\xf9\xd5\x30\x0c\xaf\xd9\ +\xba\x6d\x9b\xe9\xdd\xb8\x91\x78\x7c\x5c\x83\x20\x90\x4b\x49\xd3\ +\xf5\x0b\x37\x3f\x68\x4c\xf2\xf2\x37\xad\x4a\xaa\xda\x5a\xab\x59\ +\xa7\x23\xcb\x8b\x8b\x9c\x3c\x71\xc2\xed\xdf\xbf\xff\xe8\xbe\x7d\ +\xfb\x3e\xbf\x73\xe7\xce\x27\x57\x57\x57\xcf\xfc\xa8\xc2\xff\xa8\ +\xaf\xce\xaa\xaa\xae\x59\xc2\xea\xea\xea\xe4\xe3\x8f\x3f\xfe\x68\ +\x10\x04\x49\x18\x86\xef\x06\xae\x19\xdb\xb2\x25\x4c\xd3\x6e\x91\ +\xaf\xfc\x54\x37\xaf\x50\x69\xb7\xdb\x4c\x9e\x39\x53\xec\xdf\xbf\ +\xff\xe8\x33\xcf\x3c\xf3\x95\xc7\x1f\x7f\xfc\xd1\x46\xa3\x31\xf5\ +\xe3\x08\xff\xe3\xbc\x3b\xac\xa5\x25\xa0\xaa\xd2\x68\x34\xd8\xb5\ +\x6b\xd7\x83\xc6\x18\x03\xbc\x73\x69\x69\x69\x6b\x4f\x4f\x4f\xa8\ +\xfa\xd3\x96\x7e\x6d\xcd\x52\x56\x56\x56\x8a\xe3\xc7\x8f\x9f\xdc\ +\xb7\x6f\xdf\x23\xbb\x76\xed\x7a\xf0\x32\xe1\xf3\x7f\x92\x77\x87\ +\xcb\x2d\x06\x52\xa0\x77\x6c\x6c\x6c\xeb\xeb\x5e\xf7\xba\x3b\xfb\ +\xfb\xfb\x5f\x15\x04\x41\xdd\x39\xa7\x3f\xe1\xb3\xaf\xa8\x7c\x63\ +\x8c\x58\x6b\x57\x17\x17\x17\x5f\xfc\xce\x77\xbe\xb3\x7b\x72\x72\ +\xf2\x24\xb0\x8c\x6f\xc7\xca\xfe\xc9\x5e\x9e\x5e\x77\x6f\x58\xf6\ +\x81\xd5\x81\x1e\xa0\x56\x2a\x26\x58\xf7\x2e\xe4\x4f\x45\xf8\x75\ +\xc9\x59\x56\x26\x36\x2b\xc0\x6a\x89\xf6\x3f\x92\xd9\xaf\xdf\xfe\ +\x1f\xba\xc9\xa0\xf1\xd3\x43\x85\x2f\x00\x00\x00\x00\x49\x45\x4e\ +\x44\xae\x42\x60\x82\ +\x00\x00\x03\x30\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x10\x00\x00\x00\x10\x08\x06\x00\x00\x00\x1f\xf3\xff\x61\ +\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\ +\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0e\x4d\x00\x00\x0e\x9c\ +\x01\xde\xf6\x9c\x57\x00\x00\x02\xd2\x49\x44\x41\x54\x38\x8d\x6d\ +\x93\x4d\x68\x5c\x55\x14\x80\xbf\x73\xdf\x9b\xe9\xc4\x21\xcc\x4c\ +\x4c\xc6\x2a\x22\xb6\xa9\x93\x44\x0c\xa3\x62\xc1\x2c\x14\x9d\xd2\ +\x12\x35\x85\x52\x5a\x11\x6c\xa5\x1b\x71\x57\xe8\xce\xc5\x74\x37\ +\x82\x2e\xa5\x4b\x05\xcb\x20\xc6\x45\xdd\x48\x4a\xf0\x27\xf1\x07\ +\x69\xa4\x86\xc2\x98\xd0\xc4\x50\x14\x1a\x4d\x9b\x57\xf3\x63\xe0\ +\xbd\xe4\xdd\xf7\xee\xbd\x2e\x06\xa7\xb1\x7a\x56\xe7\x1c\x38\x1f\ +\x87\xc3\x77\x84\x7b\x62\x69\x69\xc9\x69\xad\xef\x6d\x03\x90\xcd\ +\x66\xa9\x54\x2a\xb2\xbb\xe7\xef\x2e\x5a\xad\x96\xdb\xba\xd0\xc0\ +\x9f\xbe\x8c\x12\xc1\xcb\x08\xce\x82\xb5\x0e\xa7\x1c\x5b\xcf\x8f\ +\xd1\x6a\xb5\x5c\xb5\x5a\xed\x40\x3a\xc9\xcc\xcc\x8c\x53\xcd\x0b\ +\xdc\xf7\xed\x57\x78\x22\x74\xed\xf5\x31\xeb\x16\x44\xf0\xef\x57\ +\x6c\xdf\x4a\x30\xc6\x12\xd5\x0e\x63\x4e\x9f\x65\x64\x64\x44\x3a\ +\x80\xe9\xe9\x69\xe7\x35\x3f\xa0\x77\x76\x8a\x6c\xc6\xc3\xf7\x05\ +\x3f\xeb\xa1\x3c\x01\x0b\x56\x1c\x26\xb5\x24\x3b\x16\x9d\x1a\xd6\ +\x0e\x1e\x22\x3d\xf5\x26\xb5\x5a\x4d\x64\x62\x62\xc2\x75\x7d\xfa\ +\x11\xe5\xab\xdf\xb3\x99\x11\x36\x8d\x63\xef\x9e\x0c\x7b\xba\x3d\ +\x82\x6d\x8b\x00\xbd\x5d\x42\x12\x59\x56\xa2\x04\x8b\xa3\x94\x3a\ +\xf4\xb3\x2f\x12\xbf\x76\x06\x15\x04\x01\x3d\x3f\x7c\x83\x38\x21\ +\x1e\x3d\xc6\xd8\x42\xc0\xce\xcb\x27\x59\x13\xc7\xa1\xd9\xdf\x79\ +\xe1\xc7\xdf\x28\xbc\x7b\x91\x2b\x5b\x09\x47\x17\x02\x8e\xce\xdf\ +\x22\x7f\xfe\x3d\xf4\x77\x5f\xb3\xba\xba\x8a\x0a\xc3\x10\x25\xa0\ +\xb2\x42\xe1\xf1\xa7\xd8\xd9\xdc\xa0\xfb\x89\x2a\x6e\xbb\x7d\x9e\ +\xcf\xde\x38\xc6\xc3\x07\x9f\x23\xdf\xdf\x0f\xc0\xf8\xe9\x93\x3c\ +\xfd\xfa\x19\x36\x4a\xbd\x84\x61\xd8\x06\x58\x0b\x6b\x91\xa1\x6f\ +\xb8\x4a\xeb\xd2\x38\xbd\x83\xc3\xfc\xa9\x0c\x69\x9a\xf2\xcc\x5b\ +\xe7\xb8\x73\x63\x91\x70\xf9\x0f\xd2\x34\x25\xd7\x53\x20\x35\x06\ +\x67\xcc\x5d\x80\x01\xee\x28\x45\x71\x7f\x85\x6b\x1f\x5f\xa4\x7b\ +\x5f\x3f\xb7\xb7\x1c\x71\x1c\xb3\x7c\x6d\x96\x5c\xdf\x83\xa8\x62\ +\x81\x38\x8e\x39\xf2\xce\xfb\xfc\xd4\xfc\x90\xe2\xe6\x3a\x51\x14\ +\xe1\x87\x61\x48\x92\x18\xa2\x47\x2b\x58\xa5\x38\xde\xbc\x84\x01\ +\x72\xfb\x0f\xa0\xb5\xe6\xe7\x4f\x9a\x0c\xbe\x7a\x0a\x3f\x5f\x44\ +\x6b\xcd\xf8\x93\xfb\x18\x44\xe8\x43\xda\x1b\x44\x51\x84\x4e\x0c\ +\xde\xc0\x10\x2b\x73\x2d\xa6\xce\xbf\xcd\xed\xeb\xf3\x94\x2a\x43\ +\x68\xad\x39\xf1\xf9\x14\x37\xaf\x5e\x61\xe3\xfa\x3c\x5a\x6b\x4a\ +\x0a\xf2\x16\x92\x24\x25\x8a\x22\xa4\x5e\xaf\xbb\x07\xa6\x26\xc9\ +\x2d\x2d\xe0\x7b\x8a\x03\x39\x9f\x65\xe7\x40\x14\x4a\xb5\x45\xe9\ +\x51\x0a\x27\x8e\x20\x4a\x29\x88\xa3\xa8\x60\xee\x91\x01\x56\x6a\ +\xa3\x6d\x91\xea\xf5\xba\x2b\x7f\x39\x49\x75\xe5\x17\x24\x01\x25\ +\x42\xae\xe0\x63\x22\x07\x80\x97\x17\xe2\xbf\x0c\xd6\x39\x5c\xc6\ +\xd1\x7a\x68\x80\xd5\xc3\x2f\xd1\x68\x34\xa4\xa3\x72\xbd\x5e\x77\ +\xe5\x2f\x2e\x33\xf8\xeb\x02\x9e\x08\xa2\xa4\x6d\xa2\x03\xac\xc3\ +\xe2\x48\x8d\x63\xb1\x7f\x88\xe0\xc8\x2b\x34\x1a\x8d\xbb\x2a\xef\ +\x86\x94\x26\x27\x78\x6c\x71\x0e\x2f\xeb\xe1\x2c\xe0\x40\x7c\x30\ +\xb1\xe1\xc6\xd0\x30\xeb\xa3\x63\x9d\xe1\xff\x00\xfe\x81\x04\x41\ +\xf0\xbf\xef\x5c\x2e\x97\xff\x35\x0c\xf0\x37\x5c\xfc\x53\xd5\x3a\ +\x96\xb0\xec\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ +" + +qt_resource_name = b"\ +\x00\x05\ +\x00\x6f\xa6\x53\ +\x00\x69\ +\x00\x63\x00\x6f\x00\x6e\x00\x73\ +\x00\x11\ +\x0c\x49\x94\x07\ +\x00\x61\ +\x00\x64\x00\x42\x00\x6c\x00\x6f\x00\x63\x00\x6b\x00\x50\x00\x6c\x00\x75\x00\x73\x00\x36\x00\x34\x00\x2e\x00\x70\x00\x6e\x00\x67\ +\ +\x00\x11\ +\x0c\x97\x94\x07\ +\x00\x61\ +\x00\x64\x00\x42\x00\x6c\x00\x6f\x00\x63\x00\x6b\x00\x50\x00\x6c\x00\x75\x00\x73\x00\x31\x00\x36\x00\x2e\x00\x70\x00\x6e\x00\x67\ +\ +" + +qt_resource_struct = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\ +\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x20\x2a\ +" + +def qInitResources(): + QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources()
--- a/eric6.e4p Sun Mar 13 14:56:13 2016 +0100 +++ b/eric6.e4p Sun Mar 13 20:54:42 2016 +0100 @@ -1266,9 +1266,15 @@ <Source>ViewManager/BookmarkedFilesDialog.py</Source> <Source>ViewManager/ViewManager.py</Source> <Source>ViewManager/__init__.py</Source> + <Source>WebBrowser/AdBlock/AdBlockDialog.py</Source> + <Source>WebBrowser/AdBlock/AdBlockExceptionsDialog.py</Source> + <Source>WebBrowser/AdBlock/AdBlockIcon.py</Source> <Source>WebBrowser/AdBlock/AdBlockManager.py</Source> <Source>WebBrowser/AdBlock/AdBlockPage.py</Source> + <Source>WebBrowser/AdBlock/AdBlockRule.py</Source> <Source>WebBrowser/AdBlock/AdBlockSubscription.py</Source> + <Source>WebBrowser/AdBlock/AdBlockTreeWidget.py</Source> + <Source>WebBrowser/AdBlock/AdBlockUrlInterceptor.py</Source> <Source>WebBrowser/AdBlock/__init__.py</Source> <Source>WebBrowser/Bookmarks/AddBookmarkDialog.py</Source> <Source>WebBrowser/Bookmarks/BookmarkNode.py</Source> @@ -1346,6 +1352,7 @@ <Source>WebBrowser/History/__init__.py</Source> <Source>WebBrowser/JavaScript/ExternalJsObject.py</Source> <Source>WebBrowser/JavaScript/__init__.py</Source> + <Source>WebBrowser/Network/EricSchemeHandler.py</Source> <Source>WebBrowser/Network/FollowRedirectReply.py</Source> <Source>WebBrowser/Network/LoadRequest.py</Source> <Source>WebBrowser/Network/NetworkManager.py</Source> @@ -1427,6 +1434,8 @@ <Source>WebBrowser/ZoomManager/ZoomValuesModel.py</Source> <Source>WebBrowser/ZoomManager/__init__.py</Source> <Source>WebBrowser/__init__.py</Source> + <Source>WebBrowser/data/html_rc.py</Source> + <Source>WebBrowser/data/icons_rc.py</Source> <Source>WebBrowser/data/javascript_rc.py</Source> <Source>__init__.py</Source> <Source>cleanupSource.py</Source> @@ -1827,6 +1836,8 @@ <Form>VCS/CommandOptionsDialog.ui</Form> <Form>VCS/RepositoryInfoDialog.ui</Form> <Form>ViewManager/BookmarkedFilesDialog.ui</Form> + <Form>WebBrowser/AdBlock/AdBlockDialog.ui</Form> + <Form>WebBrowser/AdBlock/AdBlockExceptionsDialog.ui</Form> <Form>WebBrowser/Bookmarks/AddBookmarkDialog.ui</Form> <Form>WebBrowser/Bookmarks/BookmarkPropertiesDialog.ui</Form> <Form>WebBrowser/Bookmarks/BookmarksDialog.ui</Form> @@ -1904,6 +1915,8 @@ <Resource>IconEditor/cursors/cursors.qrc</Resource> <Resource>WebBrowser/Bookmarks/DefaultBookmarks.qrc</Resource> <Resource>WebBrowser/OpenSearch/DefaultSearchEngines/DefaultSearchEngines.qrc</Resource> + <Resource>WebBrowser/data/html.qrc</Resource> + <Resource>WebBrowser/data/icons.qrc</Resource> <Resource>WebBrowser/data/javascript.qrc</Resource> </Resources> <Interfaces/> @@ -2026,6 +2039,9 @@ <Other>WebBrowser/OpenSearch/DefaultSearchEngines/Wiktionary.xml</Other> <Other>WebBrowser/OpenSearch/DefaultSearchEngines/Yahoo.xml</Other> <Other>WebBrowser/OpenSearch/DefaultSearchEngines/YouTube.xml</Other> + <Other>WebBrowser/data/html/adblockPage.html</Other> + <Other>WebBrowser/data/icons/adBlockPlus16.png</Other> + <Other>WebBrowser/data/icons/adBlockPlus64.png</Other> <Other>WebBrowser/data/javascript/jquery-ui.js</Other> <Other>WebBrowser/data/javascript/jquery.js</Other> <Other>WebBrowser/data/javascript/qwebchannel.js</Other>