From e21400debecad7975e98e5a761e1d75ff504b0b4 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 27 Dec 2021 18:30:08 -0600 Subject: [PATCH 01/39] Fix preview gif Use githubusercontent instead of discord cdn --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cd03fa1..d666350 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ #### SearchifyX in action -![in action](https://media.discordapp.net/attachments/714922631693860956/925164698058502175/ta1Y74Ehy8.gif) +![in action](https://user-images.githubusercontent.com/72637910/147515480-236fe392-6282-44bc-b888-54f15adeb523.gif) +
@@ -88,4 +89,4 @@ Here is a [demo website](https://www.codingwithjesse.com/demo/2007-05-16-detect- #### Settings page -![settings](https://i.imgur.com/iOciyxd.png) \ No newline at end of file +![settings](https://i.imgur.com/iOciyxd.png) From a0abb5e48a4afdb5c89cf600c73af838e559abc8 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 27 Dec 2021 18:52:37 -0600 Subject: [PATCH 02/39] Add disclaimer Add disclaimer and CLI usage --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/README.md b/README.md index d666350..734a3d9 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,35 @@ pyperclip You also need to download [tesseract-ocr](https://cdn.discordapp.com/attachments/714922631693860956/925180968808087572/tesseract-ocr.7z) and extract it to the root directory to use OCR. +
+ +## CLI usage + +An alternative for Linux/Mac OS users is to use [`scraper.py`](https://github.com/daijro/SearchifyX/blob/main/scraper.py) as a CLI tool. + +Usage: +``` +scraper.py [-h] [--query QUERY] [--output OUTPUT] [--sites SITES] +``` + +Required arguments: + +``` +--query QUERY, -q QUERY + query to search for +``` + +Optional arguments: + +``` +-h, --help show this help message and exit + +--output OUTPUT, -o OUTPUT + output file (optional) +--sites SITES, -s SITES + question sources quizlet,quizizz,brainly (comma seperated list) +``` + --- @@ -41,6 +70,7 @@ You also need to download [tesseract-ocr](https://cdn.discordapp.com/attachments - Various different options for input for stealthy use +
### Stealth options @@ -56,8 +86,11 @@ You also need to download [tesseract-ocr](https://cdn.discordapp.com/attachments - Quickly change window opacity hotkey +- Change window opacity (slider in title bar) + - Option to not show in taskbar +
### Window switching safety lock @@ -90,3 +123,10 @@ Here is a [demo website](https://www.codingwithjesse.com/demo/2007-05-16-detect- #### Settings page ![settings](https://i.imgur.com/iOciyxd.png) + + +--- + +### Disclaimer + +The purpose of this program is to provide an example of asynchronous webscraping and data gathering in Python. I am not in any way attempting to promote cheating, and I am not responsible for any misuse of this tool. This tool was created strictly for educational purposes only. From 578d8ac451538265696ea0106fe9e2477e423464 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 27 Dec 2021 18:54:32 -0600 Subject: [PATCH 03/39] Change default transp value Change default transparency value to 95 instead of 97 (looks nicer) --- config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 7a89970..2aa5dac 100644 --- a/config.json +++ b/config.json @@ -10,11 +10,11 @@ "search_ocr": true, "search_paste": true, "save_focus": false, - "save_transp": 97, + "save_transp": 95, "save_pos": null, "rclick_reset": true, "on_top": true, "hide_taskbar": false, "theme": 0, "font_size": 10 -} \ No newline at end of file +} From c4dd7c577b854098a74093ea193be358381ba2bf Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 27 Dec 2021 19:58:59 -0600 Subject: [PATCH 04/39] Error handling --- README.md | 12 +++--------- config.json | 2 +- gui.pyw | 14 ++++++++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 734a3d9..e100186 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,13 @@ Windows binaries are not avaliable yet at this moment. -Here are the [python 3.8](https://www.python.org/downloads/release/python-389/) dependencies: +Install the [Python 3.8](https://www.python.org/downloads/release/python-389/) dependencies: ``` -PyQt5 -pywin32 -keyboard -grequests -beautifulsoup4 -pytesseract -pyperclip +python -m pip install requirements.txt ``` -You also need to download [tesseract-ocr](https://cdn.discordapp.com/attachments/714922631693860956/925180968808087572/tesseract-ocr.7z) and extract it to the root directory to use OCR. +You also need to download [tesseract-ocr](https://cdn.discordapp.com/attachments/714922631693860956/925180968808087572/tesseract-ocr.7z) and extract it to the root directory to use the OCR tool.
diff --git a/config.json b/config.json index 2aa5dac..7a7e025 100644 --- a/config.json +++ b/config.json @@ -17,4 +17,4 @@ "hide_taskbar": false, "theme": 0, "font_size": 10 -} +} \ No newline at end of file diff --git a/gui.pyw b/gui.pyw index 8b3b106..bc92d8b 100644 --- a/gui.pyw +++ b/gui.pyw @@ -314,13 +314,18 @@ class UI(QMainWindow): # calling scraper and adding to ui def run_searcher(self): + query = self.search_bar.text().strip() + + if not query: + self.status_label.setText('Please enter a search query') + return + self.status_label.setText('Searching...') self.search_frame.setEnabled(False) QtWidgets.QApplication.processEvents() sites = [] - query = self.search_bar.text().strip() if self.quizizz_button.isChecked(): sites.append('quizizz') if self.quizlet_button.isChecked(): sites.append('quizlet') if self.brainly_button.isChecked(): sites.append('brainly') @@ -365,12 +370,13 @@ class UI(QMainWindow): # data entry tools def run_ocr_tool(self, force_run_searcher=False): + if not os.path.exists(resource_path('tesseract-ocr')): + self.status_label.setText('Tesseract not found.') + return + self.status_label.setText('OCR in progress...') QtWidgets.QApplication.processEvents() - # # delay - # time.sleep(0.2) - self.setWindowOpacity(0) self.stackedWidget.setCurrentIndex(0) QtWidgets.QApplication.processEvents() From 68a655b736411df822391e166e229c7ba4fbd8d2 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 27 Dec 2021 19:59:11 -0600 Subject: [PATCH 05/39] Create requirements.txt --- requirements.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b49f6b6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,22 @@ +beautifulsoup4==4.10.0 +certifi==2021.10.8 +cffi==1.15.0 +charset-normalizer==2.0.9 +gevent==21.12.0 +greenlet==1.1.2 +grequests==0.6.0 +idna==3.3 +keyboard==0.13.5 +Pillow==8.4.0 +pycparser==2.21 +pyperclip==1.8.2 +PyQt5==5.15.6 +PyQt5-Qt5==5.15.2 +PyQt5-sip==12.9.0 +pytesseract==0.3.8 +pywin32==303 +requests==2.26.0 +soupsieve==2.3.1 +urllib3==1.26.7 +zope.event==4.5.0 +zope.interface==5.4.0 From 4ac502963fab1eff90833ed69338545c42be0b7a Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 27 Dec 2021 21:30:53 -0600 Subject: [PATCH 06/39] Update download link --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e100186..acfcaec 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,15 @@ ![in action](https://user-images.githubusercontent.com/72637910/147515480-236fe392-6282-44bc-b888-54f15adeb523.gif) -
+--- ## Download -Windows binaries are not avaliable yet at this moment. +#### Binaries + +Download Windows binaries [here](https://github.com/daijro/SearchifyX/releases) + +#### Running from source code Install the [Python 3.8](https://www.python.org/downloads/release/python-389/) dependencies: From 2593156c2bb0e47414f559cf47670ec74c6d0b22 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Tue, 28 Dec 2021 14:28:44 -0600 Subject: [PATCH 07/39] Update README.md --- README.md | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index acfcaec..57e387e 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ **SearchifyX**, predecessor to *[Searchify](https://www.reddit.com/user/daijro/comments/jg7wee/searchify_quizletbrainly_searcher/)*, is a ***fast*** Quizlet, Quizizz, and Brainly webscraper with various stealth features. +SearchifyX lets you easily query a quiz question through different answer websites *(similar to Socratic on mobile)*, and sort them based on how similar they are to your query. It also includes a screen OCR scanner, hotkeys, and other features for stealthy use. + +
#### SearchifyX in action @@ -14,11 +17,11 @@ ## Download -#### Binaries +### Binaries Download Windows binaries [here](https://github.com/daijro/SearchifyX/releases) -#### Running from source code +### Running from source code Install the [Python 3.8](https://www.python.org/downloads/release/python-389/) dependencies: @@ -60,14 +63,12 @@ Optional arguments: --- -### What it does +## What it does - Searches Bing for Quizlet, Quizizz, and Brainly results - Sort results by how similar the identified question is to the input question -- Various different options for input for stealthy use -
### Stealth options @@ -90,9 +91,10 @@ Optional arguments:
+ ### Window switching safety lock -Many websites can detect when the window focus is lost. SearchifyX includes features such as hotkeys and a __window switching safety lock__ to prevent websites from knowing your are using a differenty window. +Many websites can detect when the window focus is lost. SearchifyX includes a __window switching safety lock__ to prevent websites from knowing you are using a different window. *Note: The text search bar does not work when the Window switch safety lock is enabled. It is designed to be used with the OCR tool and Paste & Search tool.* @@ -100,6 +102,25 @@ Here is a [demo website](https://www.codingwithjesse.com/demo/2007-05-16-detect- ![window safety lock](https://i.imgur.com/mGBAV1K.gif) +
+ +### Improvements from *Searchify* + +- Completely rewritten from scratch + +- Added stealth features ([listed above](https://github.com/daijro/SearchifyX#stealth-options)) + +- Added screen OCR scanner + +- Added global hotkeys + +- MAJOR changes to UI + +- MAJOR changes web scraper code (averages 1-2 seconds now; uses significantly less CPU) + +- Completely fixed the "Too many requests" error + +- Significantly more stable & returns better results --- From d88428a9f4293f86ee8c71422993a2a1eebd63ed Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Thu, 10 Feb 2022 21:50:58 -0600 Subject: [PATCH 08/39] Use dropbox - Change discord cdn link for tesseract-ocr to dropbox - Remove "quiz" from example (to not promote cheating) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 57e387e..3a00553 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **SearchifyX**, predecessor to *[Searchify](https://www.reddit.com/user/daijro/comments/jg7wee/searchify_quizletbrainly_searcher/)*, is a ***fast*** Quizlet, Quizizz, and Brainly webscraper with various stealth features. -SearchifyX lets you easily query a quiz question through different answer websites *(similar to Socratic on mobile)*, and sort them based on how similar they are to your query. It also includes a screen OCR scanner, hotkeys, and other features for stealthy use. +SearchifyX lets you easily query a question through different answer websites *(similar to Socratic on mobile)*, and sort them based on how similar they are to your query. It also includes a screen OCR scanner, hotkeys, and other features for stealthy use.
@@ -29,7 +29,7 @@ Install the [Python 3.8](https://www.python.org/downloads/release/python-389/) d python -m pip install requirements.txt ``` -You also need to download [tesseract-ocr](https://cdn.discordapp.com/attachments/714922631693860956/925180968808087572/tesseract-ocr.7z) and extract it to the root directory to use the OCR tool. +You also need to download [tesseract-ocr](https://www.dropbox.com/s/abuo044ayx4vlex/tesseract-ocr.7z?dl=1) and extract it to the root directory to use the OCR tool.
From 692e8fbd4bb0d3f877cd7bd5117d75537ff7eb93 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Mon, 11 Apr 2022 02:54:24 -0500 Subject: [PATCH 09/39] Fix #2 - Fix Bing search - Add Google and Startpage scrapers (change in ui settings) - Fix headers + add header randomizer - Completely remove Brainly from the project due to new WAF + slow processing time - Fix delay in cursor restoring after OCR - Manually calculate selection rectangle for OCR - Change minimum value for window transparency slider to 5% - Upgrade Pillow and pytesseract to fix security concerns - Add requests_html, fake_headers, and their dependencies to requirements.txt --- config.json | 2 +- gui.pyw | 23 +++--- img/brainly.png | Bin 6933 -> 0 bytes requirements.txt | 26 ++++++- scraper.py | 186 ++++++++++++++++++++++++----------------------- textshot.py | 9 ++- window.ui | 113 ++++++++++++++++++++-------- 7 files changed, 221 insertions(+), 138 deletions(-) delete mode 100644 img/brainly.png diff --git a/config.json b/config.json index 7a7e025..4139f9f 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "quizlet": true, "quizizz": true, - "brainly": false, + "search_engine": 0, "hide_show_key": "Ctrl+D", "ocr_key": "Ctrl+Shift+X", "paste_key": "Ctrl+Shift+V", diff --git a/gui.pyw b/gui.pyw index bc92d8b..ae81d4a 100644 --- a/gui.pyw +++ b/gui.pyw @@ -19,7 +19,7 @@ import tkinter as tk root = tk.Tk() root.withdraw() -from scraper import Searchify +from scraper import Searchify, SearchEngine from textshot import * from windoweffect import WindowEffect @@ -96,17 +96,13 @@ class UI(QMainWindow): self.status_label = self.findChild(QtWidgets.QLabel, "status_label") self.quizlet_button = self.findChild(QtWidgets.QPushButton, "quizlet_button") self.quizizz_button = self.findChild(QtWidgets.QPushButton, "quizizz_button") - self.brainly_button = self.findChild(QtWidgets.QPushButton, "brainly_button") self.settings_button = self.findChild(QtWidgets.QPushButton, "settings_button") self.quizlet_button.setChecked(self.conf['quizlet']) self.quizizz_button.setChecked(self.conf['quizizz']) - self.brainly_button.setChecked(self.conf['brainly']) self.quizlet_button.toggled.connect(lambda: self.updatejson('quizlet')) self.quizizz_button.toggled.connect(lambda: self.updatejson('quizizz')) - self.brainly_button.toggled.connect(lambda: self.updatejson('brainly')) - self.settings_button.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(1)) @@ -115,7 +111,6 @@ class UI(QMainWindow): self.quizizz_button.setIcon(QtGui.QIcon(resource_path("img\\quizizz.png"))) self.quizlet_button.setIcon(QtGui.QIcon(resource_path("img\\quizlet.png"))) - self.brainly_button.setIcon(QtGui.QIcon(resource_path("img\\brainly.png"))) self.titleIcon.setPixmap(QtGui.QPixmap(resource_path("img\\search.png"))) @@ -203,6 +198,11 @@ class UI(QMainWindow): self.setting_on_top.setChecked(self.conf['on_top']) self.setting_on_top.toggled.connect(lambda: self.set_window_on_top()) + + self.search_engine_combo = self.findChild(QtWidgets.QComboBox, "search_engine_combo") + self.search_engine_combo.setCurrentIndex(self.conf['search_engine']) + self.search_engine = SearchEngine(self.search_engine_combo.currentText().lower()) + self.search_engine_combo.currentIndexChanged.connect(lambda: self.run_search_engine()) # window theme self.themeInput = self.findChild(QtWidgets.QComboBox, "themeInput") @@ -291,7 +291,7 @@ class UI(QMainWindow): font_size = self.font_size.value() # icon sizes - for obj in [self.quizizz_button, self.quizlet_button, self.brainly_button]: + for obj in [self.quizizz_button, self.quizlet_button]: obj.setIconSize(QtCore.QSize(font_size*2, font_size*2)) @@ -313,6 +313,10 @@ class UI(QMainWindow): # calling scraper and adding to ui + def run_search_engine(self): + self.search_engine = SearchEngine(self.search_engine_combo.currentText().lower()) + self.updatejson('search_engine') + def run_searcher(self): query = self.search_bar.text().strip() @@ -328,14 +332,13 @@ class UI(QMainWindow): if self.quizizz_button.isChecked(): sites.append('quizizz') if self.quizlet_button.isChecked(): sites.append('quizlet') - if self.brainly_button.isChecked(): sites.append('brainly') if not sites: self.status_label.setText('Please select at least one site.') self.search_frame.setEnabled(True) return - searchify = Searchify(query, sites) + searchify = Searchify(query, sites, self.search_engine) t = Thread(target=searchify.main) t.daemon = True @@ -530,7 +533,6 @@ class UI(QMainWindow): # keybinds "quizlet": lambda: self.quizlet_button.isChecked(), "quizizz": lambda: self.quizizz_button.isChecked(), - "brainly": lambda: self.brainly_button.isChecked(), "hide_show_key": lambda: self.hide_show_key.keySequence().toString(), "ocr_key": lambda: self.ocr_key.keySequence().toString(), "paste_key": lambda: self.paste_key.keySequence().toString(), @@ -550,6 +552,7 @@ class UI(QMainWindow): "hide_taskbar": lambda: self.setting_hide_taskbar.isChecked(), "theme": lambda: self.themeInput.currentIndex(), "font_size": lambda: self.font_size.value(), + "search_engine": lambda: self.search_engine_combo.currentIndex(), } def updatejson(self, key): diff --git a/img/brainly.png b/img/brainly.png deleted file mode 100644 index 8c1df6900f3c61269080e89372a10cebe0b2aed5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6933 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 D#nc(I diff --git a/requirements.txt b/requirements.txt index b49f6b6..701b68a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,22 +1,44 @@ +appdirs==1.4.4 beautifulsoup4==4.10.0 +bs4==0.0.1 certifi==2021.10.8 cffi==1.15.0 charset-normalizer==2.0.9 +colorama==0.4.4 +cssselect==1.1.0 +fake-headers==1.0.2 +fake-useragent==0.1.11 gevent==21.12.0 greenlet==1.1.2 grequests==0.6.0 +html5lib==1.1 idna==3.3 +importlib-metadata==4.11.3 keyboard==0.13.5 -Pillow==8.4.0 +lxml==4.8.0 +packaging==21.3 +parse==1.19.0 +Pillow==9.1.0 pycparser==2.21 +pyee==8.2.2 +pyparsing==3.0.8 pyperclip==1.8.2 +pyppeteer==1.0.2 PyQt5==5.15.6 PyQt5-Qt5==5.15.2 PyQt5-sip==12.9.0 -pytesseract==0.3.8 +pyquery==1.4.3 +pytesseract==0.3.9 pywin32==303 requests==2.26.0 +requests-html==0.10.0 +six==1.16.0 soupsieve==2.3.1 +tqdm==4.64.0 urllib3==1.26.7 +w3lib==1.22.0 +webencodings==0.5.1 +websockets==10.2 +zipp==3.8.0 zope.event==4.5.0 zope.interface==5.4.0 diff --git a/scraper.py b/scraper.py index f923bfb..659bfed 100644 --- a/scraper.py +++ b/scraper.py @@ -1,71 +1,124 @@ +import grequests import json from bs4 import BeautifulSoup from difflib import SequenceMatcher import json -import grequests +from requests_html import HTMLSession +from fake_headers import Headers import re import sys import time from urllib.parse import urlencode from threading import Thread - headers = { - "Connection": "keep-alive", - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36 Edg/95.0.1020.53', - "Sec-Fetch-Site": "same-origin", + "Sec-Ch-Ua": "\"(Not(A:Brand\";v=\"8\", \"Chromium\";v=\"99\"", + "Sec-Ch-Ua-Mobile": "?0", + "Sec-Ch-Ua-Platform": "\"Windows\"", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Sec-Fetch-Site": "none", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", - "Referer": "https://www.bing.com/", - "Accept-Language": "en-US,en;q=0.9" + "Accept-Encoding": "gzip, deflate", + "Accept-Language": "en-US,en;q=0.9", + "Connection": "close" } - get_text = lambda x: BeautifulSoup(x, features='lxml').get_text().strip() sluggify = lambda a: ' '.join(re.sub(r'[^\\sa-z0-9\\.,\\(\\)]+', ' ', a.lower()).split()) similar = lambda a, b: SequenceMatcher(None, sluggify(a), sluggify(b)).ratio() remove_duplicates = lambda a: list(set(a)) +def _make_headers(): + return {**headers, **Headers(headers=True, browser='chrome', os='windows').generate()} -class SearchBing: +class SearchEngine: + headers = headers.copy() + def __init__(self, engine_name): + self.sess = HTMLSession() + self.engine_name = engine_name + self._web_engines = { # simple scrapers using get requests + 'google': ('https://www.google.com/search?', 'q', {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'}), + 'bing': ('https://www.bing.com/search?', 'q', {'pq': ''}), + } + if engine_name in self._web_engines: + return + elif engine_name == 'startpage': + print('Starting startpage instance...') + self.t = Thread(target=self._init_startpage) + self.t.daemon = True + self.t.start() + + def find_items(self, soup, args): + return {i: soup.find('input', {'type': 'hidden', 'name': i})['value'] for i in args} + + def get_startpage_items(self, r): + soup = BeautifulSoup(r.text, 'lxml') + return {'query': None, 'cat': 'web', **self.find_items(soup, ['lui', 'language', 'sc', 'abp'])} + + def _init_startpage(self): + self._startpage_data = self.get_startpage_items(self.sess.get('https://www.startpage.com/', headers=self.headers)) + self.headers.update({"Sec-Fetch-Site": "same-origin", 'Referer': 'https://www.startpage.com/'}) + + def startpage_get_page(self, query, sites): + self.t.join() + resps = grequests.map([ + grequests.post('https://www.startpage.com/sp/search', + headers=self.headers, + data={**self._startpage_data, **{'query': f'{query} site:{site}.com'}} + ) + for site in sites + ]) + self.t = Thread(target=self.get_startpage_items, args=(resps[-1],)) + self.t.daemon = True + self.t.start() + return dict(zip(sites, resps)) + + def get_page(self, query, sites): + if self.engine_name == 'startpage': + return self.startpage_get_page(query, sites) + return dict(zip( + sites, + grequests.map([ + grequests.get( + (web_engine := self._web_engines[self.engine_name])[0] + + urlencode({web_engine[1]: f'{query} site:{site}.com', **web_engine[2]}), + headers=self.headers, session=self.sess + ) + for site in sites + ], size=len(sites)) + )) + + +class SearchWeb: """ - search bing for query + search web for query """ - def __init__(self, query, sites): + def __init__(self, query, sites, engine): self.query = query self.links = None self.sites = sites + self.engine = engine self._regex_objs = { 'quizlet': re.compile('https?://quizlet.com/\d+/[a-z0-9\\-]+/'), 'quizizz': re.compile('https?://quizizz.com/admin/quiz/[a-f0-9]+/[a-z\\-]+'), - 'brainly': re.compile('https?://brainly.com/question/\d+'), } def search(self): """ - search bing for query + search web for query """ - resps = dict(zip( - self.sites, - grequests.map([ - grequests.get( - 'https://www.bing.com/search?' - + urlencode({'q': self.query + f' site:{site}.com'}), - headers=headers, - ) - for site in self.sites - ], size=len(self.sites)) - )) - + resps = self.engine.get_page(self.query, self.sites) self.links = { site: remove_duplicates(re.findall(self._regex_objs[site], resps[site].text)) for site in self.sites } - class QuizizzScraper: def __init__(self, links, query): self.links = links @@ -74,7 +127,7 @@ def __init__(self, links, query): self.query = query def async_requests(self, links): - reqs = [grequests.get(u, headers=headers) for u in links] + reqs = [grequests.get(u, headers=_make_headers()) for u in links] self.resps = grequests.map(reqs, size=len(reqs)) def parse_links(self): @@ -136,7 +189,7 @@ def __init__(self, links, query): self._regex_obj = re.compile('\\= \\{"alphabeticalIsDifferent.*\\}; QLoad\\(') def async_requests(self, links): - reqs = [grequests.get(u, headers=headers) for u in links] + reqs = [grequests.get(u, headers=_make_headers()) for u in links] self.resps = grequests.map(reqs, size=len(reqs)) def parse_links(self): @@ -170,61 +223,6 @@ def quizlet_parser(self, resp): ) - -class BrainlyScraper: - def __init__(self, links, query): - self.links = links - self.resps = None - self.brainlys = [] - self.query = query - - def async_requests(self, links): - reqs = [grequests.get(u, headers=headers) for u in links] - self.resps = grequests.map(reqs, size=len(reqs)) - - def parse_links(self): - self.async_requests(self.links) - for resp in self.resps: - try: - self.brainlys.append(self.brainly_parser(resp)) - except Exception as e: - print('exception', e, resp.url) - # pass # skip over any errors - return self.brainlys - - - def brainly_parser(self, resp): - data = json.loads(BeautifulSoup(resp.text, features='lxml').find('script', type="application/ld+json").string)[0] - answers = [] - if 'acceptedAnswer' in data['mainEntity']: - answers += data['mainEntity']['acceptedAnswer'] - if 'suggestedAnswer' in data['mainEntity']: - answers += data['mainEntity']['suggestedAnswer'] - - return max( - ( - { - 'question': data['name'].strip(), - 'answer': get_text(i['text']) - .replace('Answer:', 'Answer: ') - .replace('Explanation:', '\nExplanation: ') - + '\nUpvotes: ' - + str(i['upvoteCount']), - 'similarity': ( - similar(data['name'], self.query), - True, - i['upvoteCount'], - ), - 'url': resp.url, - } - for i in answers - ), - key=lambda x: x['similarity'], - ) - - - - class TimeLogger: def __init__(self): self.elapsed_total = time.time() @@ -261,19 +259,17 @@ def print_timers(self): - - class Searchify: - def __init__(self, query, sites): + def __init__(self, query, sites, engine): self.query = query self.sites = sites + self.engine = engine self.timer = TimeLogger() self.flashcards = [] self.links = [] self.site_scrapers = { 'quizlet': QuizletScraper, 'quizizz': QuizizzScraper, - 'brainly': BrainlyScraper, } def main(self): @@ -306,8 +302,8 @@ def _flashcard_thread(self, site_scraper, links, site_name): def get_links(self): - self.timer.start('bing search') - search_bing = SearchBing(self.query, self.sites) + self.timer.start('web search') + search_bing = SearchWeb(self.query, self.sites, self.engine) search_bing.search() self.timer.end() self.links = search_bing.links @@ -328,10 +324,11 @@ def sort_flashcards(self): # sourcery skip: for-index-replacement if __name__ == '__main__' and len(sys.argv) > 1: # argument parsing import argparse - parser = argparse.ArgumentParser(description='Search Bing for flashcards') + parser = argparse.ArgumentParser(description='Search the web for flashcards') parser.add_argument('--query', '-q', help='query to search for', default=None) parser.add_argument('--output', '-o', help='output file', default=None) - parser.add_argument('--sites', '-s', help='question sources quizlet,quizizz,brainly (comma seperated list)', default='quizlet,quizizz,brainly') + parser.add_argument('--sites', '-s', help='question sources quizlet,quizizz (comma seperated list)', default='quizlet,quizizz') + parser.add_argument('--engine', '-e', help='search engine to use (google, bing)', default='bing') args = parser.parse_args() if args.output: @@ -348,15 +345,20 @@ def sort_flashcards(self): # sourcery skip: for-index-replacement flashcards = [] # create flashcard list sites = args.sites.lower().split(',') # get list of sites + engine_name = args.engine.lower().strip() # get search engine + # start search engine + engine = SearchEngine(engine_name) + # run search s = Searchify( query=args.query, sites=sites, + engine=engine, ) s.main() write(json.dumps(s.flashcards, indent=4)) - print(str(len(s.flashcards))+ ' flashcards found') + print(f'{len(s.flashcards)} flashcards found') s.timer.print_timers() \ No newline at end of file diff --git a/textshot.py b/textshot.py index 1c215e0..cae8cc3 100644 --- a/textshot.py +++ b/textshot.py @@ -134,8 +134,15 @@ def mouseReleaseEvent(self, event): return super().mouseReleaseEvent(event) self.hide() + QtWidgets.QApplication.restoreOverrideCursor() QtWidgets.QApplication.processEvents() - shot = self.screen.copy(QtCore.QRect(self.start, self.end)) + + shot = self.screen.copy( + min(self.start.x(), self.end.x()), + min(self.start.y(), self.end.y()), + abs(self.start.x() - self.end.x()), + abs(self.start.y() - self.end.y()), + ) self.processImage(shot) self.quit_app() print('done') diff --git a/window.ui b/window.ui index ae39845..9473920 100644 --- a/window.ui +++ b/window.ui @@ -204,28 +204,6 @@ - - - - - 30 - 30 - - - - Brainly - - - true - - - false - - - true - - - @@ -404,9 +382,9 @@ 0 - 0 - 379 - 631 + -77 + 656 + 465 @@ -775,26 +753,97 @@ true - - + + - Search after running OCR + Search after pasting true - - + + - Search after pasting + Search after running OCR true + + + + + + + 150 + 0 + + + + + Bing + + + + + Google + + + + + Startpage + + + + + + + + + 100 + 0 + + + + Search engine: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 70 + 20 + + + + + + @@ -972,7 +1021,7 @@ Window transparency - 15 + 5 100 From cee78c51529bc566714cd0439a810c2e2451cf63 Mon Sep 17 00:00:00 2001 From: kuro <72637910+daijro@users.noreply.github.com> Date: Wed, 13 Apr 2022 22:22:45 -0500 Subject: [PATCH 10/39] Fix typo Add -r parameter --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a00553..1ab8144 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Download Windows binaries [here](https://github.com/daijro/SearchifyX/releases) Install the [Python 3.8](https://www.python.org/downloads/release/python-389/) dependencies: ``` -python -m pip install requirements.txt +python -m pip install -r requirements.txt ``` You also need to download [tesseract-ocr](https://www.dropbox.com/s/abuo044ayx4vlex/tesseract-ocr.7z?dl=1) and extract it to the root directory to use the OCR tool. From 22fee1ec05a4053b3efb84e72d703dd679c46038 Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Sat, 3 Sep 2022 19:09:34 -0500 Subject: [PATCH 11/39] Add macOS support --- .gitignore | 30 ++ macOS/README.md | 20 + macOS/SearchifyX.xcodeproj/project.pbxproj | 351 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../UserInterfaceState.xcuserstate | Bin 0 -> 44306 bytes .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/1024.png | Bin 0 -> 51753 bytes .../AppIcon.appiconset/Contents.json | 68 ++++ .../Icon-MacOS-128x128@1x.png | Bin 0 -> 6378 bytes .../Icon-MacOS-128x128@2x.png | Bin 0 -> 12874 bytes .../Icon-MacOS-16x16@1x.png | Bin 0 -> 578 bytes .../Icon-MacOS-16x16@2x.png | Bin 0 -> 1261 bytes .../Icon-MacOS-256x256@1x.png | Bin 0 -> 12888 bytes .../Icon-MacOS-256x256@2x.png | Bin 0 -> 29707 bytes .../Icon-MacOS-32x32@1x.png | Bin 0 -> 1279 bytes .../Icon-MacOS-32x32@2x.png | Bin 0 -> 2801 bytes .../Icon-MacOS-512x512@1x.png | Bin 0 -> 29351 bytes .../SearchifyX/Assets.xcassets/Contents.json | 6 + .../QuizizzIcon.imageset/Contents.json | 21 ++ .../QuizizzIcon.imageset/quizizz.png | Bin 0 -> 64690 bytes .../AppLogo-Quizlet copy.png | Bin 0 -> 43220 bytes .../QuizletIcon.imageset/Contents.json | 21 ++ macOS/SearchifyX/ContentView.swift | 119 ++++++ macOS/SearchifyX/Flashcard.swift | 16 + macOS/SearchifyX/Scraper.swift | 40 ++ macOS/SearchifyX/SearchifyXApp.swift | 17 + macOS/build.sh | 16 + macOS/clean.sh | 7 + macOS/requirements.txt | 6 + 30 files changed, 764 insertions(+) create mode 100644 macOS/README.md create mode 100644 macOS/SearchifyX.xcodeproj/project.pbxproj create mode 100644 macOS/SearchifyX.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate create mode 100644 macOS/SearchifyX/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/1024.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-128x128@1x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-128x128@2x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-16x16@1x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-16x16@2x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-256x256@1x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-256x256@2x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-32x32@1x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-32x32@2x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-512x512@1x.png create mode 100644 macOS/SearchifyX/Assets.xcassets/Contents.json create mode 100644 macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/Contents.json create mode 100644 macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/quizizz.png create mode 100644 macOS/SearchifyX/Assets.xcassets/QuizletIcon.imageset/AppLogo-Quizlet copy.png create mode 100644 macOS/SearchifyX/Assets.xcassets/QuizletIcon.imageset/Contents.json create mode 100644 macOS/SearchifyX/ContentView.swift create mode 100644 macOS/SearchifyX/Flashcard.swift create mode 100644 macOS/SearchifyX/Scraper.swift create mode 100644 macOS/SearchifyX/SearchifyXApp.swift create mode 100755 macOS/build.sh create mode 100755 macOS/clean.sh create mode 100644 macOS/requirements.txt diff --git a/.gitignore b/.gitignore index 623bd3a..1afdaae 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,33 @@ tesseract-ocr/ # tesserect-ocr needs to be redownloaded from link provided in README.md __pycache__/ windoweffect/__pycache__/ + +# scraper.app must be rebuilt because of the amount of files +macOS/SearchifyX/scraper.app + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/macOS/README.md b/macOS/README.md new file mode 100644 index 0000000..4f49865 --- /dev/null +++ b/macOS/README.md @@ -0,0 +1,20 @@ +# SearchifyX for macOS + +There now exists a native Swift app for macOS! It still uses Python for the scraping but the front-end/GUI is now native. +The only downsides to this version is that so far the stealth features are not available in this version. + +## Building + +To build this version of SearchifyX, you will need to only install the dependencies required for this version of SearchifyX listed in the [requirements.txt]() file: +``` +$ python3 -m pip install -r requirements.txt +``` + +Then just run the build script from the macOS directory to build the latest version of [scraper.py](): +``` +$ ./build.sh +``` +> You may need to give the build and clean scripts the proper permissions to execute + +That will build and compile the macOS app of scraper.py. +Now you can launch the Xcode project and build from there! \ No newline at end of file diff --git a/macOS/SearchifyX.xcodeproj/project.pbxproj b/macOS/SearchifyX.xcodeproj/project.pbxproj new file mode 100644 index 0000000..66847a2 --- /dev/null +++ b/macOS/SearchifyX.xcodeproj/project.pbxproj @@ -0,0 +1,351 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 4214674528C1C5EF00E9D706 /* SearchifyXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */; }; + 4214674728C1C5EF00E9D706 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214674628C1C5EF00E9D706 /* ContentView.swift */; }; + 4214674928C1C5F200E9D706 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4214674828C1C5F200E9D706 /* Assets.xcassets */; }; + 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214676F28C1CFB500E9D706 /* Flashcard.swift */; }; + 4214677528C1D99300E9D706 /* Scraper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214677428C1D99300E9D706 /* Scraper.swift */; }; + 4214677928C2887F00E9D706 /* scraper.app in Resources */ = {isa = PBXBuildFile; fileRef = 4214677828C2887F00E9D706 /* scraper.app */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 4214674128C1C5EF00E9D706 /* SearchifyX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SearchifyX.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchifyXApp.swift; sourceTree = ""; }; + 4214674628C1C5EF00E9D706 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 4214674828C1C5F200E9D706 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 4214676F28C1CFB500E9D706 /* Flashcard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flashcard.swift; sourceTree = ""; }; + 4214677428C1D99300E9D706 /* Scraper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scraper.swift; sourceTree = ""; }; + 4214677828C2887F00E9D706 /* scraper.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = scraper.app; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 4214673E28C1C5EF00E9D706 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4214673828C1C5EF00E9D706 = { + isa = PBXGroup; + children = ( + 4214674328C1C5EF00E9D706 /* SearchifyX */, + 4214674228C1C5EF00E9D706 /* Products */, + ); + sourceTree = ""; + }; + 4214674228C1C5EF00E9D706 /* Products */ = { + isa = PBXGroup; + children = ( + 4214674128C1C5EF00E9D706 /* SearchifyX.app */, + ); + name = Products; + sourceTree = ""; + }; + 4214674328C1C5EF00E9D706 /* SearchifyX */ = { + isa = PBXGroup; + children = ( + 4214677828C2887F00E9D706 /* scraper.app */, + 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */, + 4214674628C1C5EF00E9D706 /* ContentView.swift */, + 4214674828C1C5F200E9D706 /* Assets.xcassets */, + 4214676F28C1CFB500E9D706 /* Flashcard.swift */, + 4214677428C1D99300E9D706 /* Scraper.swift */, + ); + path = SearchifyX; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 4214674028C1C5EF00E9D706 /* SearchifyX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4214676628C1C5F200E9D706 /* Build configuration list for PBXNativeTarget "SearchifyX" */; + buildPhases = ( + 4214673D28C1C5EF00E9D706 /* Sources */, + 4214673E28C1C5EF00E9D706 /* Frameworks */, + 4214673F28C1C5EF00E9D706 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SearchifyX; + packageProductDependencies = ( + ); + productName = SearchifyX; + productReference = 4214674128C1C5EF00E9D706 /* SearchifyX.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 4214673928C1C5EF00E9D706 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1340; + LastUpgradeCheck = 1340; + TargetAttributes = { + 4214674028C1C5EF00E9D706 = { + CreatedOnToolsVersion = 13.4.1; + }; + }; + }; + buildConfigurationList = 4214673C28C1C5EF00E9D706 /* Build configuration list for PBXProject "SearchifyX" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 4214673828C1C5EF00E9D706; + packageReferences = ( + ); + productRefGroup = 4214674228C1C5EF00E9D706 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 4214674028C1C5EF00E9D706 /* SearchifyX */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 4214673F28C1C5EF00E9D706 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4214677928C2887F00E9D706 /* scraper.app in Resources */, + 4214674928C1C5F200E9D706 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 4214673D28C1C5EF00E9D706 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4214677528C1D99300E9D706 /* Scraper.swift in Sources */, + 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */, + 4214674728C1C5EF00E9D706 /* ContentView.swift in Sources */, + 4214674528C1C5EF00E9D706 /* SearchifyXApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 4214676428C1C5F200E9D706 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 4214676528C1C5F200E9D706 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.3; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 4214676728C1C5F200E9D706 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGN_ENTITLEMENTS = SearchifyX/SearchifyX.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = SearchifyX/scraper.app; + DEVELOPMENT_TEAM = R5T6626VHW; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 12.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.teamaurous.SearchifyX; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 4214676828C1C5F200E9D706 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + CODE_SIGN_ENTITLEMENTS = SearchifyX/SearchifyX.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = SearchifyX/scraper.app; + DEVELOPMENT_TEAM = R5T6626VHW; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 12.0; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.teamaurous.SearchifyX; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 4214673C28C1C5EF00E9D706 /* Build configuration list for PBXProject "SearchifyX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4214676428C1C5F200E9D706 /* Debug */, + 4214676528C1C5F200E9D706 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4214676628C1C5F200E9D706 /* Build configuration list for PBXNativeTarget "SearchifyX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4214676728C1C5F200E9D706 /* Debug */, + 4214676828C1C5F200E9D706 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 4214673928C1C5EF00E9D706 /* Project object */; +} diff --git a/macOS/SearchifyX.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/macOS/SearchifyX.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/macOS/SearchifyX.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000000000000000000000000000000000000..7a188d60987d7b3b01776033c541a56abdd42efb GIT binary patch literal 44306 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 z zr`44dmrt8KwXU|Ls-$RI`Q%A;l_jtQ$_|4ZnqWqGZFyl;$y7+CCpo^1l36tc5Z7ar z;WKa(M`DT{PW?~I%y6IjFMWW{@0C8JBtzA&0gyiC*bOO0KMqQtLs%fWQG)R77)rAG zq%Wi|DaoOvX6Rsks}E*21dII3gE?qdslF~LeJ}k2u`$vQ(h=!L=_l!^^fM(BD9NQH zj}jQZ0!j+ENWV(INxw^fNPkLyQ36p#m6QOeS5q>HlF4jz|HWw0e>KQ;xZ+O|yZYY> zMm@z?TTQyiA~3lO3QX~!xKmk?N07VuHz+Bkqy!Fn`Q)B4GNI++?K$@BzW;5c zmC=PovJU>8i4q4T%@j^MBa0|$*&=tyOU;S0OYV}pDOpSjL|km9 z1XRQ}O4=FavMWZ6$N zQNf*qE*f&5Z5ry(FDWYQ?&@+v9(D=hz~H)6!OFq?*Cv(U>pvnOaL^6e8&$FwPWBHQ z?&e$LqO`uy@cwH1zY_FiqS|w3leq@$Fc9U0n^@T$KVgX2(}7tEv@C|!CjwiTo*^V z>$uyvm$_Hrf|l30{cy|M``qW;7u;9ecieBtgcRffN8*Q|P!x{F!R1vMa8+zB%10%z z!nXun3>U;`fBKK3x9i`H-{`4YI7P%@`*UOn2kw*4mCvK3gObiZ`Fwc|C0&%9F%-it z(J^dkoi)k8FxaLD*p-o9n39xfFR^9XiwbNhnMuXA0=RU|mROXYRG5*Tnp~W29~4d| zU#S-a+;U7oX=%yD_Qc`>TPa-c4Fwez!TrG{CAQ?^%!15Pdr`W*z&LnNzDB;50q$B# zx_jkylq_S|6L3O_qf3b!n3UK+$#S*e4R*S!ypj0Iy>cH~$0f@*%UeJJ&`&GZ?tjv@ z0O4j#_eVeX)r+gP|LjYtM6trx}(oOQ+@;z)H$qC+{bo+{YpA2_C_R9BDvI@@k z0srbr2hkvzM`VZ#=#zKJk5Y0LCA3f8ErXls97?VmN;1#rGp+txp}8mCYAe5}mkS5K z%>S2_{si}7mgAD_?x4p(PmZlqHw)yKIV8VHotYZhEE2K z{Uje9s_^|P!wrwU@^6$}-7Eh=$u(^BJo+yeV58?gm|sC?Mz4Y?S*x~AiC>_1pA8S| zs=IteP~g7DK?=PhE8Z~2iXy+Nj8r@ntKzA6DWfR4UYq0fl-xiGK*x;~P7Ea*w<TTeE}FgO46c~v6O`5WCfw=!P){Lkjb z7&4mzJDmm(S)!5*Q=%kMvZWU;M1-pkkDn265wg8d?3iFpKu&6D)kI)5oMGkYG>Xnt zvW6BtLCFILkCIEtwq6Ac@9l7yJpdp(C|o~cdXQ>v6jGwpaK77=Qe~o2rj#ocN~Kbz zR4bE|$&`Sn=ypoLQ*Vri_x~2u^R}7lxAQ&?2pn@YB!s8!MUp1t(@+Mdd;P9 zT0FZR*Jp5LZ08n$hIXm+;OFJ+mYK#**pxH}PLFlERwO3HC(qD7PS^f}dq|s>bv0?7 zvbDl>d95}$)S#mq)TJ!#>msMCYkGZWTUtsDT$0dO=yWbAXz5I}$0Zum(XO~)6QAN# zI+UeKCnb+jvYQf+6Hjbbx|D8ZnX;UcCn@x@5N%OUUyp?obsj|m6=0%%c*bP@7&PYryO|;vs za2EMU&O@Qxi<^|Qm2(t8`)4V6iIP|Q{Zz{N%0=LBQ`RUKC;QSv+`FKkjSRxVLM zgL;vYJpDOUfYG2GaE zxBfRJ+?b)Y%JsuEo}8)NplksDJ|!Yi%MqKcEi2ljwVObJ|EwaegQ%3Ncbg= z9@ijyqSs$F^#-bDRh%)YwiE>E>!D%cBS()J8v);I;ffEarx~^bEp)+mhBIUHBlQvU z6s;<+3QP*Z@tSa>M~@4n&Gd3sNFf|?y*Da)e9UlWio2q|@v#F|N>sEhe(0s_wpb{@ z4&Gp|K^<$-XRa?PcG%}9Fd!Ddomxx4fLIAP&|k=1%v}oiYTd-$0{3d&%iYiIa2iw|C2zn^VK`Ws zyalI1X;)*g%YIHm%DUm6T;h9;9 z8R0e6I<`Cx1_|d0L~N|PDNieG?SMV&RRB)jRg?9UFT&XoT1vP?oT1Vyn!8;83>SrO zBR2{g@K5A-r8VwTFWXua5asr7Q} zmDa1RYpv_7w^{G7-etYVdY|x0&Zt-Gv`Ss%APY5mUA>RISH!*h}68qZriU-10g zi}xDk73>x2749|0E5gg>mEe`=mF$)3mF_jktHEof*IKVlUYosc_PWLEPOn{FPk6oW z^`+O>Uf+6s?{&oMr%|4x0!O8f${dwF>a$Vbdi#5ad6#+L=6%2S9`AkLA9)}4{=xf4 z@1x$oc>m`8hxcDT$j8ga+sD_(-zU%~*eBE{+-HnWgipH9Y#-HUv(Mu`pZhAlNxs>> zIlj5R6Mbj+&i8frHv2k#JA6BRSNf{Hm-w#pz25f*-y3~5`u6$W=6i?lUB37D-sk&( z?}NUt`u^n?=r`Uk+po;8(y!XD#&4?MG{0s)mtU7(x8HKVbN$ZuyTI>azf1it_uJri zqu)(_y?#6Wp7wjr?*+e?{9f^U&F=%h1Ad?QedhPM-ci z_~-c-_}BPP^`GWH!+)0l9RGR#3;a*>KhOVG|2_Uk0{jAU0=fdO3b-d=cfi{L?*_ad z@L|A#fKLJr1{@0bBH*iluLHgfI2{(*sk!GWQH;elfUBLb5H zD+B8SdjhWxyd&_%z%K)T2^tYJCMYeaI%r1F%%Isp4MB}Tj-d9SuArWvl|gHQt_iv} z=(?cwK^uZ@3hE8IJ?PG$yMyixx<6=V&_h9w1icsZQ?NBSHn=pnHh4ksX~7M_O~K8< zi-KLj-NDO)dxBR6uL?dZ_}buI!G}Yj2rCJj7*-xu88$0yPT0J#1z~4} ztqHp#?2)j?!~PLY!p-4c;X∾bGyU!^eilg~x~6!;`{O!qdX5!|TIO55Fe7FMLz@ z=I|}ykB7e;{#y9H@crR$g})R2WB8w=gGPsp4vS2WERLKQSsqyxIVrLxvNf_N^6bcS zBUeYRiM%lKs>o|1uZ_Gea((26$onJTh&&MaQ`E?)QBiSGX;Jx66;acpPK#=YYKn41 zEsSc3S`u|e)YVZNqWYpXM{SAP8g*CH!%@4Uo{ZWP^+D9ZsBfZ@i6(DKS%H>SCH=nqwBlw8c1Mmd3bZE{eG==AoF^V)n(n5%Xru+cEFPydU#n%z>Cs zVh+X}iup5^i^Z{~SUy&am10N4T4TLpePaD%17qW3=f<|hu83V9dr$1!vERo288_ZH?O&w0&Z?Ck^vd^*4voEl>*q7PQwqI<&)PA}BO8Z;(1NNi# z-xIwOgAyYXqZ4Bi>k}6zE=ydQcz)v5i8mx}P285aBk}gc2NHKBK9TrV;=#n<6aP%& zl1LJtWJywzJd(VUe3JZ=f|8PwQj^k?GLy2Ca+3;@ijyWLl_ymtO-iasYD>B}>CU9R zNk1hACr?aXl6+zEt;x?MzmmK+`Hkc^lRrxSBKaT5-zI;b{A2RbxBWZk^B~3{inPyEJl@^>9mNq6WA}uj3B`qy2BdsW{Ds6V!ytD;r zr={JNc7NK=w1?AC`p9%^x>veSdO~_jdRO|I^jp(+q~D%?SNgr_52QbozAJrq`rGO6 zrGJ=yApMi{gXxFTze_)w{%iUl8C(X=@W}AW@Xqkfh{#CHNX|&jNY5zFn3z$XQJFC# zqcNj7V^PN9j2#&dW;~p+D`R)YOBo+$9L)GU*i2hyLS|LwlFZ98@5+25^S7+9tlX^mS*K^6leIeQf~rTG znVp=Sk)55Ln_ZM$l3kWvkv%(mdG@;O_1PP;H)e0j-jaQ5_Kxg3vY*R-G5h80SF`tK zzn;B6`@`(dvcJgwNA|bbhqM38K{+JHoD-B2ofDH2mlL0pos*lBpHrAqoiitAeokFZ zea@{p_vh@)c_?RB&I>so=6sxUFz54}uX4W0Ih=DO=V;EaIe$#>n&30RZ$iL?pb4Q9 zMo$5S2-l#mEywJSZJbPYp zURqvu-h{mTyu!RGd7XLPc`Ncx&s&wJ=AE5)Uf!C#-n`9uTk^K%ZOhw{cSqjNyr=V? z%X=YjPyXEeMfr>KTl1aym*iiYzcc^g{73V5=RcYMO#XBEFXq3Te<=UU{IB!B%|D#~ zL;g?se-+>YbAeFcUEo&`P!LoQS&&eWQ;=6sP*7Ar3ob3Vyx_`$YYJW|c&FgEfrWIxsW)&6{Ruonj))dwjPA_aIbQCTuY$;q`cy8h9 z!Zn2#7G7I;ec=s-Hx}Mk_(b8;h0hi~Uo@|%rD#b}TTw^Rx}uwl9xB>Zw7clZqGyVp zFWOV|O3~h;H;UdW`nu@5qVJ226#Z26OVRH|e-?Aaq}W_66h{;n6)!Blp!l}peZ@yh zd`nUxSY>X>f|B}@#*)^O?vmvtJtZqkR+XGpa&gIJC0CYQQ?jn)`jQ7qo+^31WKYQ} zC9jw4FL}G<-I6a$zApKxl$464a_Pv@QKdem{-uGX<4b3kE-YPBdQs^mrI(jpRl2tH zy3!j;Zz|nc`f%x^rMpX?D1EB*nbKEE-zt5#^n=m^rJt65R{BHfPo+PX{yI^Z=snSQ zqW{FeiBS{BPmG;to0v6m!o<9Z1rujYbWB_{aq+~~GO^63%&#nK?nae2j+71vZ;Td}2Lf5j)2rb?kws#GdHD!nSb zEBz`1E0ZhJDl;pyD<@RuRTflMR8Fa!RynhBPUXDHmde&jXXVn$b1KiPyt4A@%C(j2 zDsQgbTDh%qN96;RPgOo!`F!PzRUTErRiRbkRb#92suovWRCQ_9V~SD zs`{!Pu6nfU@v0}Qp00Yf>iMd@Rc}|lSM_1l$5o$J9j-c3b+qc2YPotubzpUHb!c^X zwXND-om8DtomX8|J-K>Hb#3*v)tjrgRBx@`UcIyWrRrC!_f_w&e!Kd;>JO{`znaeb zziC6!;vsAn!Uk>neGe9kH9k>Pj1v~_v0QJB#uo2h<{0!_2b_0{ZG%y|P3-$*`gA>3> z;J4sZP!19x2|B=eU?sQ^TnsJ)SAuK6_25RZ8axJ`1b+q3g6F}D;8pNCcniD(J_BEZ z4d5Gj6L}kXcX_frMV==ATs}rVPCijSS)L`IF3*;0dtWm60tXKT3s8$?PoK&1vTvgmvJWxDV)GMAVCn%>WVP&pTuSArX5?2yR zyOL3I%8+uUa-;H;@`Cai)B@@Rb%we?-JrfuKd3)65E=o^fI!FsxuJPbCA1J)3@wG0 zL#v=o&{n7l+5sJcs-YU_IP@EI1-cJCf}TM2(0f%gRZCTCRXbG&RS#89RhlYY)mPPD zHC#1K1*!BZtBO{!Dz}PLm8t}lsEVrQsN$-5svlKnR8Qena2L2coD8SJ>2M$TOZXc& z3!V;V!vLHIo8Vcn8OGs4*a;WG#jqQm4M*UG@N#%1yc%8$Z-%$QRq#*nF8C0968;1J z4}2BA4&Q`t!>`p%)!o#C)kD>p>dES9YL&V`&8oxdsCuq?p1M-KP`y~aOubUQM!j3T zSG`|-P<=#QqduWNtv;*1puVVnsA-|;q#3L+Xedogvt0AD=D6l}&1Frk=9=b)=Ca_VuJ)6UlVwIS^}?Nx1^_J;O$ZZNkZw=#D@?xNhf+()@j za_e)S=auEn$&2UB%d5=0l6ODvVcz4sdffosC|#!RE8W++bGoa#I^7N3ZGEXes-L5e z>nrs4^{@1=^>6j>4dV?n4Tu3Xm<kK~_HW{`UP8lBLx6L1x59Pb_m*(%!zmoq3Nkp0=Es$17MfD zAPvY{}~949B3S39BRxkeqkJCR2m(|O5<+h6;qoU zM)#uo&;#gUv>L5JPoSsJU(pA%TFx3W3;5KUEu6J~)|FZRU|q2^tT)yV8-QhCW3X}9 z1Z)yE1LxajXKHk1fWQVk@v!SQT~vtHzFDC$Y2GdF&!~3A=+m zGdDN4GPg0eH+M95Hg_{8nN!TY%zeyXnZGuVH%~NAGJk8HW}acrHiKq`88TDmx#k__ zOXjzhRLf+G$x>!nW?669XxU=fX4zvoY^k=?SdLpxT25R3v|O>&S#DbHSnlFY@Xzqh zcsD!=Ps7vkzIcCpH2xKyh0nwRT!E|c96S%#|1T^VkK+~ieEfTS3BDX(g|Edo;G6KR zcolvEKaHQk&*2yF-|@?MEq)EZj^D!X;CBm}6r>kq72pNYg6##@tclh%>jbOLidk_h zVYORXYpHd%HDDF25o^r4$hy?J!n)eJ&bq-`WBtu~*;;G8X1!(o%X-iH!1{(rB-#<3 ziEcy^kwWw(1`vaYA;eH(GGQWo#B5?N@g1>%SVSx*RuXH7b;M5M2yvOHC9V-Sh}*=W;-e7-2 zwjlpSb|sU^R5G3HPYxu9kVDCFs3uf%swLHd>Omz_DO4JjPW7QO zsF74AHHI2TO`vpC0Yy>{s)%w^9K};UYA&^eT1l;;)>E6QtyC4YgE~T;qwY}msE5=O z>M8YtYM|ay?;Qz_#*VIz9*$&3iX+X@+tJT4z%j`2xnr0k!vQ$#4#}~@aoO>~+3OSK zIN!-R15UviamJkUoy(moovWQ|o$H-HICnYsI`=ydI*&MyI&V7vcD`^nINv%y(v9dQ zbThgW-HYx=52T0C8T1$QX!=WfDy^aknxq|c5nW7sXfN%f%jqB;rla&~dL6xi-binz zx6#|_o%A01XZjcVAbpswqdye&DwCDY{zpj_JW;d*Ldz3xSo?_3i=h=(wefAOi zgso?vu`k)z>|6F7`?0uDapU6D;_=0%Vt?_5;t`n})uCuO-u1l^zUA3+Ut_IgT*GG4vyScliyS2Nm zJJ~(ZJ;XiCJ;FW8o#~$9&T>z4&vY+vuW@g3Z*^C>e{%10|KdL6u6EbB?|NE!26-lV zW_kdR!UK799=#{uWAivXMV?|0=PC8f_V_)Lr@~X|S?Kx0bKCRO^TN~MdFy#!l2FpP zqV`uE~zTH!nNW?aAUdg+&A20PQ_`sTu#p+Tmi>&B^=L{ zaX~K3MY%cLd~PYXfjh!o(zS^FY3j-mENP?M|>ClTVBT(@*MBwdEUpz_&NMsUg8(=OZgT2Dt-sQ zi{H!d=MVBH_)B~(e~rJv|Ha?uAMsE4H>K@MlS@-e(@Xo74k#T|npyf)>DW(`m)}0Y z#~+v0mp=b=TK?t}f%>DbwXdD8gRhgXtFMQzr!Un9`2xPZzGr1U%chpe%amo_@|yCK z<$si4DX%NPS$?^0*wMq0?h+s1JeSz0et`o6a;JmGEf|d2Nnc=3>*tw4Ez!J zPvB~xE^s68KG-VQF4!U1DcC)j983-N3Jwhp4~__q3c7>Apb!*;vEY;7KcUv4cA*ZT zPNA-$9-*G0v{3KR$WUfzOlVwaVrX(GD>OZn9Rfmls3;T)tqT1Zst#QW-3~nt)rX#k zUJ7l6E<$%9Sx6Bw1&x3Rc7YTM1&6>3WrAM_38D}cmI>>HjlvdTn@}Yj63z%`g>%9M zp-!k5o(r#pH^MvNV>mI~G~6QGEu0ii3HJ*33HJ{V3V$9R9v%_S4(EqGVIjOYyd}IZ zd^B7WJ{~?Fz7W0`ejzpz6UD}2Q?Y~CN$e{25R=6eakvPGd7@6#i}|8WEEJt0Bf3P7 zD2Nr}3UQ~nN8BeK5D$w-#pB{B@r-z0yeQrmABlg9PsQirEAfr^PW%{2j5LWfi?omQ zi)2J*MD&rONI0@AvMX{fQX9D$xfg8{?HK)cG(9>j`ek%%bbR!i=#;1|Dvv@@byOS8 zixx%aMmI*UMQ=wRMjuCCMc>B~VvS?XVl85wVo9--Sg%;0*x=aESVnAQY;-I?7K`nT z9f=){U5Nb|yArF5-HhFjJ&OGudlq{U`)5v*c$;{;cv5^od~kedJR?3bo*5q#pBkSL z&yIs}Wn2|k$8+M|_^SA?@dhbDYAJmtb(fN*zS0mWLz*TjB$cF=awJT`C97nYD9I_6 zNWA2eW=jz%D$S7=NSmc?(st=5X}9#V^ow*zs+NvPC#BQUpHi)KRl5FvwO2x7;(xvM Mt^fM}>%77L1HuDS-2eap literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AccentColor.colorset/Contents.json b/macOS/SearchifyX/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/macOS/SearchifyX/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/1024.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000000000000000000000000000000000000..ce352d1c77278edfb2f801fc03728831f3bdc997 GIT binary patch literal 51753 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 Gz4t%PJb-5a literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Contents.json b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..fcf4b95 --- /dev/null +++ b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "filename" : "Icon-MacOS-16x16@1x.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "filename" : "Icon-MacOS-16x16@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "filename" : "Icon-MacOS-32x32@1x.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "filename" : "Icon-MacOS-32x32@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "filename" : "Icon-MacOS-128x128@1x.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "filename" : "Icon-MacOS-128x128@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "filename" : "Icon-MacOS-256x256@1x.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "filename" : "Icon-MacOS-256x256@2x.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "filename" : "Icon-MacOS-512x512@1x.png", + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "filename" : "1024.png", + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-128x128@1x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-128x128@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..8094661bd668317924cfd3dea9b37cfc7d1aca86 GIT binary patch literal 6378 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 literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-128x128@2x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-128x128@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..22b4a98ba6a920916761d8db250ec1df0624e261 GIT binary patch literal 12874 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 literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-16x16@1x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-16x16@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..a52c13953d1b3f0f017b210a0eed861d18eb366a GIT binary patch literal 578 zcmV-I0=@l-P){sFqS8xa?71dBV-Lcz9+ z5NI%jDy7<55M8v3Hufw1n9K}yX5PClQiarMd*H3^dFR}F-n#~Mm_Q4V0^&f7Xb9i~ zwVe|Hn2AK9BcIPdvu%4pDdo!^&{`|Uah6M^(yL4+(+OArZG}SN`CgayLb+Ui4IBYD zVcYgX6lvK}GB)SS+aJH>QzdAqxvskmbjE;qGMP;89`?(I;>F}Pn}LvOGMHRf42*kt zx?XQ?Za%t`7hSuZS3E6`Ke|$04MhEQ6p^Rzw&cm+=06_L6`A(uUm<7HCKr#HtcOCy z7uEzWUrAD}h7DXZO2AV>vdO>#0u5_{5Q`bKw!}ysKGeXC?BG&IoTboW3r!d|z%=ME zVQ${1x)>ZR;8*7OIbC6JJjVQjj~NKX>21b_Z0_7`+kb@FnQuI}--jC}=zlcC`|lYH ze*+1j|5l3JDeFJOtkyad5&1ejBe(nR$(io+GWuayL_|DaWOYmJekjpeYak2I={U}k zh{*Mxo6>#mf{cue9{3YI&szmfnt(kuH8q^eb{cR5XpF&d%nkFBDdL zd;9TXvG}r9t1T*}!hMXj>$)ow6BBQ;+3ab+GIj(l>g(JJGyz7WZNxhN0n{bM&#~gl QJpcdz07*qoM6N<$g3aFv=>Px# literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-16x16@2x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-16x16@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..74a2a14d44651927476b15e405013eed45ba886b GIT binary patch literal 1261 zcmVA!TJF`36-IjjPB2++a5J*8jgapJ!O-vd;ZXm|Q7!woXg_r&T{sUYaLxO@L zT0|uvr78hJ{fI!*8EytwMd!I)Rik&-U_Be6z9WeX=&N}ki|A{H8(fE z2N*>I8W4^~quU+_9KbZqje!A8r;xR77{;z ztiRKBy#dexAp$3LQp#IG2xC6rX;*Qg-{F=e$+(KBE(nLf_7t9kYD2K0LFbK@*~1AT zmI0H+5fJl*=Oi5I%afdzL?eQiRvSE76T;9S>na8&eEyx1T*fC=}r374euxW226G zU@d$I1LZ2E6fOZ>+*|JEQ&<%ls5do20#aFt2ZXgUa0O;WU}Y6!DUb3k#sUqjZ_=r+ zucCj%WyDo1(FG%Ug|7;5sX%Cg`VjQ>`2HAY&YWlaho3Su5a&?O7;SBFnwt#_ zU68dU1A`8|y*6@Mvgwr=Z5twU#uOBm#d@VwVovzUQye_p!RYWm*j^L6-uVP0wwkGl z4AnInk+8tZO0pSAbxdPNtI4~s$7d}>A;fZEVqPO~>hw<>JlsLfwwcTdl2^}h_{|Wa zF3R~!J~tB%c~?=pB*d0hlbst(Hm;oC;Fdn6DD%%bd+q`U4t_;0n`Lkwui3us z`TK&z&0-ThKS?Qb4;XM=_s&cMpMUucne;R_Zww-(;RQ77Fxz-?43bERjh3+11tcaXcPx1)cz^O0zGXH3|)C zRWLkNflHk^_H%QnxDoXM2gm}M;G8cO;mn{Kg?(E%FjItA);HX5LQ-fM-N1-fVvhd+ X@rav_MZI?A00000NkvXXu0mjfTrF5* literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-256x256@1x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-256x256@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc557bb2da4cffccd3b8fc4ae4c6c024bc5ab714 GIT binary patch literal 12888 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 literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-256x256@2x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-256x256@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6ec897d5cccab10d131ac68459ce92a82f80842 GIT binary patch literal 29707 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 literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-32x32@2x.png b/macOS/SearchifyX/Assets.xcassets/AppIcon.appiconset/Icon-MacOS-32x32@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..05c471589988bbbf725df4d697ff08a3eabc8f84 GIT binary patch literal 2801 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 PC;|0H+A5XGmZAR#_k8y$ literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/Contents.json b/macOS/SearchifyX/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/macOS/SearchifyX/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/Contents.json b/macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/Contents.json new file mode 100644 index 0000000..653d8b4 --- /dev/null +++ b/macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "quizizz.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/quizizz.png b/macOS/SearchifyX/Assets.xcassets/QuizizzIcon.imageset/quizizz.png new file mode 100644 index 0000000000000000000000000000000000000000..f0f1397c03c510adbaee5e186cb6017d49543693 GIT binary patch literal 64690 zcmZU5cOaGR|NlA1IWj7njIu{|A)+`%*(2GTLS$uTpHqYg+1trpp{!7xN+Lw|rmXCh zJF};>!k;u2%x8k|ESIxUea}@`Yd++N8!A-+Yc(Smj%4HHf;C#L)enMlx}V4 zXL&Ja&r)7Yx{y68KUX7{zx6W7OK9%HAb0DHYgtbqFd`Nd_#$C~JUBl?qw3r<_Q*5i zp(nWJ)Y!~i(q#TtwJq}o?_T%b;+*4`#hM30-R*PQmHF+JK{kVxFyo;MoOg!4IxrP( zPM}dD@a|@=6W9)HLD>Y#uhu7z(5Xi$#}l&*;gVVv`%kKoAf=Dt>NZ*WViL?YP7N z4b|W38?(*@UiPp2?l9&x`x$FDzbG@p!UO(yB9?Ijs9Ph}L7Q4H^U%sT|Iq5-b7nJa zqh`FkP_jhBzi-!wRQ6XKH3nkVZ2m}HV=m^P0Aa9{FKzlUKf^|#=i>I9wqr5Z9?ftj zGUxyAHk_*Cetiwx{3ZB@mUMA@^_8lQ#VEo6BY06*P<$MXRDkn90s=--Q>`p50~Zg? zz4^2`7qjY`m-DEFjd)P*b{UdZ16p9g{b%Vul>bl{9>i*N+sSpy%vOQfq`$qS($)mR=i>Hb{(0jMpl((ubz{m}jns=$s>W<`}k@Y0wyW`*%NpW5eAiG(`Zjrf44p4=g+~0)%iMO8tk;q zH%k~b#OTWSl&Ux%XW=J@=BtKVJKXypx~mRed>i8W%8ob6Bgi{}3CUmr9^qDo3?N^Ce? zytCZ?PrTqLJcX#F{>3|{%i%p73nH&Aw(s|z;VH~2i^znGFRTh^yUPxq3DK*vbR!#? zuhrS&NRODa#APO)+cDdWsg#Gw*Ej_z8Z>ufYWvrFVS3}MW0k)!ZE|C0d zWMY(G!S)}%o~r%$g1h^CK@v0uOFjHG1uL0ppvrblSwon zrL)*r@r9yk{WrB9cJ&IXyCqt=+vz5wn-Uj}ZvE#AzaXYr-4?d3V>H#EE-%1P(f8{I zWg0Qihzhd8IXbbTOX|1D0q=$??hEgCJ-)9>cK=faUMXhJu_kU-SZ;%a&2+{2+(Qc` zGErMau=_ZsI4q&t%Ftm-OV8XvV?({RnPINjzeQMDh~kB}()~E3(yjjHokC;QcZc6| zm>QzwU|D;8FDr|4X78H#+^<@L)ai7yS~$_UfA9JUJEmDp^%^_dwL0BKOZ6f06t!8- zez55$0v7@f!)_h8mJAm^-2GzviWoyr# z!9Ch3^3PMmozIvTkfkHO{%@m2u>+%h#Y=e2+bUCynJiVh9Q*QW4M)Ck{N(IA(V(;E z=R%AaHX{~NDsbA-xR1Oa8N!vL0{-oSSQ406cl?W)g6gj_3=O^Q)eGS*bgJpn#v^x9 zf=1vH1XwHf9Iicsl9)g1zS4{46$Snx$${$cj_Jx9x~Lu@@BhGJvl~|+Lcjy>e{k(0 zr2j$b<*1r1-RMK}0wSk^7oWJa{(WvI3@T|~NTZ6}$7!w6@vDUJb@?1QD3>Uuuv&bZ^b89caiM-x)obZ$#Ui5U}eSX8V`5E>wN?%&cx zA*>bF zD?;QAW76$^;UBn32oq9iNE$uQZK;0HvDvIA3cQl*w2IEb(rPW)wux@&zOmiSb@rS{T#9}=MX5!XX|dIW&R9*Oz}nu)p(B0*<%WD3PdI4 z71R6>Onz@Or=rWjl*RG+Nq59VE&ZU|gU4D9+rqKGhiunO2UdxrS&qv;4f&*oV|?vd zEQ6d$?_s(~PD$dDND1Foc`H2xdTu@}ChXZSfo%ojd4B^)QYP^+B|y-!umbXxvVcI- z%U8YENHo52W9cDN>(Q-~-qIUf0@;L zl`&c<5r`76+pymUhRx?|i!I*TBcsdTCZvDKA72ql1@B&jjjd^gy*K~$JfxaSba|WW zA|%Et>Q()3gc^?+vk{JL**`p6O<^*F#CG01Kz2nQ7KK;{dT^OOAG(UYX5GO zoC7MBe{h*s(7mHixqg%?OVEDk3<72GOi<)vS%{!#rkimRZ5bc)zu_C4EdYt^x*x*z zl7P!TrCby~GL)m-3z2Bn*eD(;3r*U`HBI6;6ny?a-^4>qfF3rXjNV23-dVa|8vG;I zA3~@vUAz7;+cd*rbt`c9)-Nv{TUdYC|0H*`KRpG^lcdkaoh+4ybFtpKLggApam0Zz zB&+Pp#Nh+KjnMUiU83}xKK;j+($m5wd`|7-sY82wNz)eLXSmn&$>NDO^+BY&EL(x? zs$+gL&R*VrTHv^epkBbcQv_8PR51(Qb%Ephhda-6=|Z3TgKX7kbg$j>l{jYY#iTib*2f zoe6MIHkq2QQHET8=+?esQ&%DvPa??VsCgWn$U%Z2zm+0o(^VBc67aJ?1meY&P1YfH z@Q@4VuuH?Od+h1s63~sn(o5o^)4^YTfBk0u%#=EEr`eJ#+cax_m)rJk!<}T$&|~(( zGOh-_C+*{x`EIvGcR~Lkh>^(X5izR1Aag#m8}+Q#T%(!d7=$4)4KPH8jsD#$YUhoA zvD?*TPLM(x#c+-J=jVoS3d!LV<|j0rz=N?dNXvP6kW$Bm$^;jG3rCDTQ8Ze2{N;a9 z^u@95NZddQoIZDfHtnkUK@7c`LT)J&lObefZ0N_ko^*xmPn6b-$1M;7lLw($p)4Yt2U;V!>RV$IKQ6N0x^PU#5LgcBgQSIyYX*Ia19#~XM)f15 zoQ%Ldz=74BtY6@)X(~8P?%}*=$ zQ1|SlStsrBl^`%~st(bCSBjH~c!hYqJt*2vTwH>6lql9K*{;bXHP_Slrv?)rvt6f3 z)FnEx>8!@#ZimFdVn}4I_p$2d-0kU+Nz*bt2`34db^gD zO6d4LP!sSZv9Ll9W4lEomGqrJ1{rN{0YyBg96EUbkhQ%+b?HdTk*y6pw^ z#;h}ADgq-fUkwb=B2aaTBX`#u#C21x?ud!1{CR#tMj#s7-oe_x{ADBVK2bHVw%=`F z$X`#0EP3`J!`bbClnd9p`-PR^g!(A%72CGzzo;(kxz2A2Sy^gfELIpYJRh}v93kPu zyqGE(36Bc*!??OMY4-fRdabKd<`1bT&mTW71lCz;ZuHcRZ>wl`q<}Wgn1F?yGxOC_ z8&37(7XzAzcPE}pE}>*rLQDI@%6W5=M&7=x)lk_4CR{$>;j~KYlNFP&Z#b9>bh?Jr3^`*jc8Kpx8|tunH-{7VDX!F_T=Q{)QYN9&~Rrbe~9zWsQ1G00$v z5*21Jo2s4Dr47YKS#u{`CJ{X$&hc|lRnc^%ocT%ByVeF5FDk3P#fK|hzC(ZPR4ufc$R>SA#4^r_2mCzH)mT^uiDL3-TVm@faG!?*JA6UstW!y1Qs6DE>|lxGd9 zS{WdT7iZ(=q&-Vrf0l`#JU|@Hg8`mbhu>&wb%jcA2E^$RVAPcioa=NAi`1fn%U~pz zPPjY^IT5tt0(L1__#o!dK-U#`#)q|X^AKgon(v?!7jBCFcKEGh6qmd-19hoSZ2G-U zu)rh&1y~=yao?UH^y#@1k|!rBM_rl`o32AURFy9V{-H#IKVw$s8<&Z+TUoCYU@+s@GL=JFu|I!K_!T)n^xo3LR`k;zQ}cs> zh0`dL=IdSW>z?EXBEDQXVY~1Y9`b2o_4Ie<-^w*6X`@6SZ#CcYZvS~AF8fm0m+e>* zM#MtS3%w_3*BT=G!(V{}QtNwF*3Fn9fX#eY?zkwBELyNeqy7Y{pbQ+w6xJb??cD+^ zaZFRXa*dj}>p#}TO3On;wqBkZd9e7&tdZi62!zC^j!ydtfbOf`{sbP^yBQ~XMb>2k z(@5P7L$+uAfo3QhXozHqoIF?&7iPNg@TxQU1c?EZrO;C+i_1&F(UV+Gx8~-F-HvC$ z8kq(X_|jc-A%5q|Vc4bfSF1`_Od;~&IVY57CopbGuF)3zG*(W77P_D-^x^gr)VEqt z^P*nJ53-Y1r$eU^y>|W14};7SUG)(Q_o5qD30TB+FIcZRZfbN&AHN(m0uQTxd&&Cj z?ctnsXynV7ULDs(I^#bWYQ`t%+sr5MjR>xUq-x_%8Z}>Qv{{GsSeY-v%{7ZZG)>kE zdsQCiPDCs$b5@>>bkl>OR)z@%kl(RUy~=$X->tZB?45jUzdklWiqYkPh>LIqWPIZr zyA`4O(8-G=Zeizpo+T!R+8|JAin9b-OiDI7I=*kLpn6Qgnwl6RL* zw4!GGbB>%!=6{|Cn6WaWi>*kfNH!!gv6EdH;Zr~l?czEvAqY&3MtHijF=a4pA7%nM zC+V6ezcnk{Mih7DKTFr3F6CaC?nQqW;qN$eyM(A#PMiN3yvBG?_Js1WoUooN`*jXq zo{tpL!7q=Ybf}-XpJyoMr6EIHMh>2|6~HYUhX)hxow~e?N`sQeGW+H4Zu&d15M&9Q zv_K;s4NmW`yRiVrlbG{{3A_mL1b`wB`{2~EhzV-1;-qk|@bjf0AirLs2eqk@YZ8+u z@eYZFcQe)MYDT1?ZH3Gb5aTXKGA)hrr^np`cr2UrDq=y!TYww`5HWZ6y%)AvnMh8h z9DU+S6czlMxj`YIXDz<+C{zj*<6XTuMqIBodBW|@uA`A{)h)h+$n==<$!qCFw8m^j zU*+UZsWD- z#41j0?pK(+K4dnH`riK^DZ#(7U~FnL_`Y->dd>EEe{(9wMS>e6Yps{3R1RB|+8>?V zQH%!CcQvhcro=zaY5ArHpDq+x@!0a!>$fNPHn0g8KgLu$jj+WC(xjj$rP`OR?I}5< zcT%V1Jc+1Fr`n5BM_=9dPJgGHNDBEiF@&SKI&dPEp-`T%xj2-iG$}?U6k;XT{(L01 z%r{!;V((*SR7|EMw|9=_(pP$h6h;I_yLK~d;=m>0Kcfa0y`agVw2!0n! zl~Zw4nYP*G-=K%oL^$G<30mt;3KVXD;dfcrq&cF@tiNhGI?!DgPI@U(%x$bk^T(@R z%@G&1p=OKI+Shx0Pw~aS_uM=gC?IGg={Xmdd*LQY?#kK_@^rr&HVoFL{}H>eA|}S= z52X;SztFsdXUx>o(Cx>B3Q4NfNykTGvS3M-d_@-bUxe^+O~*|}Ql>-4hvL(lC+j(~ z7EXE#k{s@OeKeskzC4$b4$}S0KjqL=Q+x9yNU-q0IMWN`^B}@`OPB{0SY$n>L5=&Q za9A|hp!bR$S_hQhx`dEGl1bls7dBcbce3oABo`=T2i$_JZ6I{9R1N_dnW-)9kL!p2 z$10u(YII)pe&YdcQfe+J9f~hg?b~>Mqy5R*|C}0xu%w*D&~>eRNnY>n!{|l51$v0L zrME5@j+=e*Kf&=Pw^{3ehw}Gj*rP%qxwI*IQrEF8?Cbe@DL4^tC5E?nTtH^=MRV2yd=b1skX37Tr%zeS5T z1@7x^m^{LPlQ;~4u~JGj8`U+zP&tYQ!Jo1XPo99B=P9;%dM&URiYdlLtRKWy$_E&>o62@-zKNA9zdu zF%;P)MO!H{bP^hn*g=@|sv9r=r%$Ain^24}|9|*^nH$uN7Wv9_E?ooC^z9o7m9f;w z95Ds+e>|C*4Kw}cu=?N;bE*cUU+kgoLyGIu?+&*Ai=TF^n6FGJL(Gf|#0W^lw7?%N z^gXf(?*E*(v;b-DvPVS%xn;~}){_-X`X8$gr{S@4FjaseCr+d8jcgxJFM*zFiBsHs zuwSVmyIdQud27;q_SN=}7wGWrwn@?9rnuU^8bPv?07IhVyyxzuuO2Ve}F3I9hS}~zxZEyU&KsrA66f}I$!=-%8JYK%Id7A@>yIf-#=IO z%d@aa-n5vo;JCtS@{5u;zfVcC`Eet&&kNOHZJDo%D%t0VBTmP!IBkRlYqXa>T_$r3 z)f)QrnS-Crh^@QpvDoHDfG3BHxar#ZS~iP}=~}oKZfg_P+|shXtQ%=MJ|^yggARPS zxAoEbyTgFX?*l>Hyx>5sOT^>#51VK%&A;lj;~M|LmaH}?VUthczWuXbOrSpdcaZ-t zntyaz#G-LWb*_+GS7xm!&ge6)&bF=K6!&%z*WM4B3{^7mf}1ht+L1Dwiz72a;Vh{VS*~stV21`hw1uU2}!(K;e zJtpDNJ^xV-smi5mv#UPAN4y9$_RqF$;2uu;O`e8qO!>)@3$N=#s=MSz6J7sTygv{I&)@Mo&;ih2}NiG9p8S#ed9>BRETRoFW}_r)iNbD zPRNl8vw>x0 z%hlm8Z{@DjwHxx+9)2B!y<#BSJxZyG!cerdFD0&eJBQ;=Lq-bwNL9+p|I#be0V0D} zPU$J_i>%q7#PwdUU(wD@{Pcm|Q+;-~-EPYN!gu%e8r8!xg2R2cmpHen44UDZ72&fb zM-Ev@E+IN2qX+5u7xiW=J;Z-*el#1Kgy4}SVv8GED8 zc`)nkx3DGd9h6*lY&6n;pS5d4b07K66;(r-;Vom{lg9G3~c}*75r}Bv2P?CVnEjp?7WO^wDSW z+rlTDSL-R(KZ-zHdm*Jm5J0c+yKP4BHt0mUTUW_EHmKi?lgW4JY$hAO3x{!#n{t}e z6tp11a#w{NZahe#H%nnHHQQWvHe-$_g$E~D9fcw#9{gsR-;*L=|G8E3J2z%U&;2i< z!bZVXLsp${x0hwzUH*RPc(0l>oinJp=LXFrT@$m6KujW)RntO98HcrUc;R)0qY(%e z30TsDP;SSh!C_O#Z+$-BlHdzeDaEshBdkGViM5oA1+6XJ|ETXKr}y6c^hxi%kW)?h z{T$TpmD>Uw?-Z=U(^+Ly5-u8+RV59aw?BgKcLvD4hu?DY-x!Q#)zP?Y)E_!mAexW< z)USkb|Ex9JUmNYZ(4)vuWouE`PfUx>fXB6&@|I~`GRxs5v@@!Bl{eD=ml+@v;Th!# z=U!WDwhv~|74h9AW%}FqK}NzEDr^_hS3Iu;2qU3OKo4k;%0{iSAi1A=CURqwf2_BJG5o+?vZ+iM*Qx10F~ zhi(x+7G1P(BSh|Q*wPH@h7N`-9(g2D0%xR_%z(d_|JJ&lc(`GAdE5I8J@ z<>ZMFR2B^x?Gj2HjfP-pU~@&^7`xd}He?}!vc@kjDIOK50*o*gMq#dtecCmJclVP$ z9$Z*^Oay`E5}m7}FlKd->jiEB)4?p1!pIz@7A!BOZZ$4ZEOfawi^= z<(oy)h;!nDc^+9%0=JpbkpJz7visQa^(^3)({6GtL@XLv*bLLdNFm&MU~8JFvJaw; zZEJ$y2uH0+^W0)(&eHv$yk$&)J#uZ37!fycH7HGg`H;1Yfohhyw;{!prNCnd(bMM* z@>=W-ntIO|-fykVwCwy!b$|K$2g?T`vPU{v5WsLUghIY+^o6-qda%hw-~*f)0xhXJ zr{M3FmCp|M?w_3nsSAwFjGtk9{*UP-pPMIkc($G} zOO@dUJ{pu3qqqj!=L8|M^&!Pol@1AVN4*KNTj;#!cRKevr4IuSY;$_wS_C%$$Kj;b z%l!^NchDQZwwQNu_&O%QY5{+JzZ$a3ug|Mj$+V~!^1!NgocL(gh=l`2!>6s)x49LM z*0omjiQSHDK<0wuhGWxGy(b@5sA1!AJ3{mD1X-0rV01_#M7hk1T1b(GHA;-goZ9uM zH)ckFP6#-6)nf&Tdwv*8$vePeaZ?V0eoL}nF(X93{#|!%Dj64hU1~F?fispGOVjvi_n zc8;^w#XWiC{Ni6@;lYqV1{ygbhQJ(}9tOz;n;J0=ua3Ic)bixj-5}P01T%Ox#zu#Ax`jHHE;b`S=VAMrRPUU?SEIgz0f687BnFHTGoG4=Z+8|xjZVbZbZ4KKnIGXF{$g%BMm zvFuh7>bONl>eM9~bYy~5(0h;SLml61?V4Ufh19Dyh6z)YK1VJc8qwo^>h1iQil`RF z@;<%EgjW;=z{fRhb&SK}3ry`tSTus;z`|cr@ zTgaaybL>!ajcoG&q#JVw1w+#RlsJty!!l&NpLGk(meIwEIgWv=XDmR|E|l1=d6dmj z=8$>E?~eyG~MjS5me@G~H#UmF+eEVmb-vs5hrWpFz*=lWp`1zEjd zsJ}k-Lh&paJ{WTc6k~7P$F0+G;U6TWI62n<7BdpHGHrdpg`rd* zUKwC902T&?r+|r3?9M%vXGARH7U=DU$JKu-{l8s}--s=B>h*S8ErI2;lV3*fzxUbM z9r>}gs?7XtG}T*{_SE?!^Kl}E)Dz&>V@I%Mu-_k#w z`;&K<^Tc3vlq1${=R!!ptxi#3j+pxeS2Z}|Je;A@jze6=w@}ofr@^f{S{N9nyxG8h z_F8AEP}B3kmegqKMEoXc@iW37Z?JNJwJ{QCk~cK>JB)P|#%>&N@`v>tgs%Srg^toX zRNs8;B}aeG4^ScGctd#w)?_@(z{-w7)gmM}X4(4A)S6H})NvDs4}jmX zBPt#Gc}qsO-tLPA-h!RKisb-33RW5ngj~~465k0{64YR?$Qj<=R_$b6{1e68kcL;0 zD#A)N;bO`4l>)o51~&AS^EW>MvnIt)fsSLyDe-zJN4;qp+vzjmi63#V2Hq;U%YKw^ zhSRPHQEpETt!*^@;HUik`z6;^FsT~{rpn9|yYOuX5EYW#Y@1Vs#su1=%6UHjV8Rn- z30bpdNB?hS;xe4`xZ%M;Zl)*lSeGr@#aP-+@=ECVPF1|;4m#=a<|2wWm%-pDuvotd#(4u?y)oe5GCR^<>MO_rL{0=Z7>{4} zi<@!uzU^E&39qp^O5B))zz|e8vjruvbt&R=eEaoR7teFy+!;hIZsC`5{q3FDbVqNI~=EgDn1}pZiX4*nqEXnmj?Y~O@J$n`A84==c0VQHxY%( zyZ9($Cjb_zydeDq$e)|2e6~~Pw$I*`Xn*e0Tvq{@Xdt|dB3VlcD>MyKMlb(!C^KDf zsM7f+3eYa>H(@EbnPv27jC{6)wxUzCZF46QoC@FaN^j@RG{LEi`dejDPtpYNo<2%b z`0v{Txy}qw$;>bX;d)7|8@WXODk=T zFAz*B)@DRK{%5qjLUgaHal8~U9w2pSAM`F!Q`W$G#Mr}zN>{@XL|z2wg``5sEX-UzjF@LME3eq^5_{4+ix$zoLF zE7yMY>tQiaO-p2`4X z-dc%wF?B=`RsLbzPkh(F%oI8?w%%2n&I)QQ-`*$IKmWbi7TAP8U!lX7=b{`xRdkF>-^3$he@OE&E zl%uzRx7~juDkbre&JU?oVz4YetVmk9M_JeV+~Cz!{~zQq2_Qj5?#vNF-XapU8&EL0 z!*{?~a_uOFrwDbt)24C@itoz;tp2-t+-V9VRt(sSkw`ZO7*(*Ok>D%Kye7VTOR-45 zqDa+=>1d@hhyw1uNV>-N{Pyh*)}Mb9{V?jI(y6yBGN2 zZ%VO56%6V!4g{U|zv7(l?>w1WB4D`(Y%&H!68SUS%|M$Ncv$SAg^n5xvuj6 z<84={g_p>kZbyi4N=h1xu$mR05n;Ixq&WWf6&i3B^aLCfg{s%5ygAl0OuqVliU1;k zz#M4t)Fi*_U2$vLHDy=kEn?U8Wmq*kfHjcL|An;#HgbydtYjZHO0!av9hCO|&S;o9 zq6K~1Lc0*sU%IL{3ws(V`$kbCDZgQo7)aBfgr+UA4p48f1U8;wgk= zR;plx&q}~K+}Joimh>y4V5rpFp?W~JqUinrJI!5Co@|63JoB&+m;RnZY`)vsA?iNBh;VWY zWIWiM1C03cyhc8aJ2N#;n8kl9w9*^MKL` zbK%J9HcI7mgU>!568&4x#G0e~xAiBnM&@P}CxHk4(&)5XB%oj1-4ei{cMilxp z>{6`7K90Fy?ET?S)%W=4uu=i`blFQ15TY_fL9W)8(DqkboRxCdQA-Eg4Cm$4(!|Ml zJu`%-oepUSr7s?^uP2{WKobto@ozm;lg;gEu|PvlM#K*Ojz2g(LEQ=STU)p0%s1&I zPJe^%ul zpIb@z>lk}0iurv-bvC{oc=dqoThipE8OhQ>)1rARC|d^MU-3Jzqy?{VSxKG+)TfXb zR2Z8+volBM*eB}?i2gcCjFIEPNX-!rPbK3VT2rx~O;<+o&-w^#kNmXdE->CMd@;Bh z_u^DG-lMi|ojO{KC`Ok>dn9}MO+*^`M5`Dcfsmy@v2f)iKcFyCsOo|8=5qW}oQPMN zr2(_(-`)rkgJ7tz<0q@TuJVcP6Kq6u5x>Vk;2u0NfiHj=a--*&YxO(7t5)4@YWO?K zg)+sA3@lFdS}!Ay1o0fH_f%=)8DTcJB>n&@H(+m4hlCCa{BQC7b*R8w|W!` z0oj}`fRySw{Ja+zF&@;H82m~eU)vY4qP*00WOH!+@m+aG>dbd-_+1Grqv})IqOy&_ zkE$$hbhPO=M>FxEyj=Rh-`A1QW~AqCE!GB&ap$^9aP}MH4fCBGSVfsINtD9rIWnfk zxU=+Sgpx&Dftq5--|#^$!A7pls&wJPPC~a%74akNBhd& z7m0&(yc+{ys?h`&GI2-v?q@aVDm&RepTwsHlt7zok81$i?IbnYz=}CrHR@-}M6w^9 zoxC&=`67m4t;6s$$F-H(o zSAYw~;z7VhG#FG+)yNg>V|dBl??eU!2BoghGydI`(^G8h7TL?q5y^L~+Ri|+(SV91 zoK{%}iH18qNu}RByhlkzXSjJ=g7U~~pvj~Gfq~5*O2$f-PHPNJCz1ol4Zw>lPabth zfy8J))!)ed^i6aO1bueI^5C zE)iZ!oApa0uSS;#*+B)BRPWs#noN#j=l5C#Mv5OA&wJ`9No-5k**?)yFBWWEYy*iT z%|y8s*pY@8x@2_s=IG;iLt=c8`^+7&qRv!AL;r)t>^%B| z?d5v+0fP-A_T)Z$O{#;}hr~D?v7cj=p2-4r^rC|6`327*J=&MBJVf1j#$C81BcWS! zqQ&fww12%OP~#xd(-==QOp9`qNw@geLX zWn#1-ERgivSbvFOG1sngA5-E=iMGs)-Jr=f^z5KPwbzqw8%^~&hV~pc?K{Zp$=$ID zN=CQ^j5$}V^HE92L2|}RzxKZBRfC@zfCnW59#r*0Vu#Jl9L<>aP9GGt+CNcHGQg&Z zC(k!UPm#vAbdDXyaL(<_fToa`ccJI`!SX5FIm#zouagzZ+`&7MFAT24HT_mdwvz1! zlLTf5&o`W9r+b{uOdWO@emwwdyZ~$TofZpWGqXQRTt+@Gm$^sE1tB4bD@CK@>61b` z_96UR8TqBb!Zsc6Ux_{(Qb{Vvz+Rlw7paKjbLLirpGMDS<~CFH zT_?m>NWf$V353(a0`#+m@3K_fDR_T*RV<`f?_;aO14eWt$-;1@tY7j*^8OW<;@0F# zy2e$w`pCwK$?t{TN->qGLyAL!a|6|{wTgAVG|xsc!q&ch5Ndw+(v%$!E7W{QC`OOX z9eAqcX|gke$OtGZ3S!Yo4Td|^FzpyW=ZOjN_$8Lj+gJ-&a<4-SGgpBk zt|9U5cKjFG&~T^cR1bO&sb{-u%W%zu&@VQt)jbHmlxv314(FkTL5e;gmfr+&W^KrQ z2p{I}$kV>(Y2Mm`_h~Ca=c;@xgPUQU{)F{5_dy};Bink_pw)m`QK>b4yk^J)9ME&%!GvjDE>>*Nh>tb%d&Hx9^lQW4I@_e+$foTCHHQK^}5kiAs9 zVO8I{j#A1`-MS1mehzFL{U{5MQi0fth*1`TVu>nh`BFaED+=Mm$V1OL^~;vs_jh)N zt{QbQCz%u3lr-8CsxLpvxeqE6=R4KnOIJ!G8)avRV&t&z+J0ADFOC}at>zp^^#u|1 z7GOI@qWxLVQ8Y&oukN!}{vgRJ&?y*-zKPHgG`I*#BKkSLV%qNZL;Am^?OfB5J{9oU zM}B0uM5r4>pBpoTen`pe*Vl=uFH&h$+O2RfH9SqK0TCWcxBvo8B)-rRw!LYeAJGW)Z}phQ@Ev2Qn1 zhhO|w{Am29`D+McSp3jU(L-Oxs4IHz2N5EP!&f#ZLy>pD(Vs_|O95Nf!rV<4T*D@l zA<9)5WHHxZjW_-7jUFh~-6h?dVr~*rzsnSg0!&L`uzF-_n6EwBt8I?`3Ca>4=B9Gt z-GWI=gDeYBl>t!ItBqU_xDl%cfU@_XBo%Ux(_S~MswX;Sy)EMMTt)k2L^`d(b**1z z`N%@G*HiBczsG~L_oEm0mGiQ>fd~J%uatnm8fbl8CIT#qfC0Q_hn$5!`+!Tpk^SsE z|7Da2u7>P$!@HQzpI(lVcs{Q1iK8hp&PI?_$ue zw@BSd{XqbD00^I`?4Y1=^3wVv8jze`*LD~Zi55WkNT;_liOZ_)%S2Wv_x4{t^`x>M zIbyXj*=Z;gt!DcXxrDO7t(HF|Y@y?iPTm`38TBbKzRThOTo&~Yhr^st!fQ;8JWoG2 z?%JR4!Xd$75!Qou0{dz2HZRea&~8oW_*vO@xj%wQ^}Ob=4m&UzvHazo zuXR;Tld_n-t@xA$wsoFWJoapl$4H!@5F>>t_Y* zXv9Ab8e%1S{C5+UCl9PgV_y`C4@%KzcoZRRGqv1ou$Ip5I0tGNlhn6fl_HjUq{DBw z*F`4pza>E_Y4BzRB9^O#Bodnn)9*9o(H#|UNNtXGQ-ITc*Jp7&>n$61P$$Z9&~*`( zP4l3;;EmBiM@8pa*j;6O;-+DRwp@?j6+*1gY=0XjJO%32zKC~lY~4NiNg_QR%xzoM zYX1gV$_o?@1LufaufpcLGj!U=4#VEBZyUb#U3Z`1xXl$#*EI0fIL8M7gn+?C5SF4O z+&n>Vx0P0*NMCz%ae&+Zu%>^Z_yIF0r}2QQBrOy5&70UIScKp9J68p%ktG}Q`Y#A~ zhapzxYg=h5+YjEasK$Lc6}s}AhA5OMS{k=7W6B?Cm_yt0JHzBH7>7qj>Ra49qG?vI_)c? zD`0h1)wb{pEP9S3cHeAM4nqwSyZf-Y5)h^@pQf@Uo*RSIbqQt!Guxuz@PqSnI4!dG zwV*!E=<~4MeDoX}j+<&?B>TYCCGS5I6VpThJ|iP5HC|Ac?1K(vfsWvh!-W8(4SaKH zkWbg`Ab!%W`C^;-0syirv>M=32=K8q#uW3)09&w(Ih=9~rUkFYU}x5w`?u=iK3bDm ztog@~I*zalFSg`ge%Hd1xV`%Ll7mY#0UAlt(D?P+8TDbNCN3K=k;ad&($X@se3HeU zg(dNFN?%*Mldn^lbp8|P?PQ{&{dwft~D#lfen z)uidRH06#_Ow?0d05!<*q@a>`P-8>e zhT{v7pYZkJpC4I8;R`Gp*|%vtR~CafFY|Vu{YjbmPP zG`)}8zg3^7jO%;U-N95gZCj3KT;yJEF-R~$_Cr+FFMT69bB&GusPrZBPw6Y><~V5f zgscV;kioyPk8gNQP0-22B<~Hg%*VeLI09cjco*HbXW&PtNvcVBgLc8&ZMfD;RZ#ZJ%WvmeX_>9Z|I62Odgbkhyeg6QhBqYu#aFA zKPW&etBA>miBu*|(`=#XlCymTtI@ovlDND4_yhDU860b$YrPVezvS%iw)gUwZWuoN zid_EAzww9(fE= zEuO%wx--lFlE?6X_;stf^gI;)ocbMT7rtFFeJSaq5rZn8UmI9apIiz(6acer{I=qi z>?q__1n9>!rRrC;(6Qf+E#o}vQHTxfGv)8OTTmA21?1N3<*hwa%eJT<(BKliMEiIG zjZ{PcN|1e9>CDdI{4D47fCFHdT(EtFV>Fsg1zyA^ygkYXhN@b5f075Cf#c_>`YeqE zWK?&45dNTKgMFt=5cA6!?%tCGV{w$neBeyHtXYr*zFe1x@T%Z4bS5aB-5#5eGKQR_gb~t9mwNezNvQSGe8885k$U zyR|x2&Vd(rHgy}1K$#!ewBR=doN&RXvTa}6zB>E#(4Ivj(v(GLbSK5<&!?bYd@DzD z0N4Q-2%qPy2>?+Pu&*trQa?8az3SaS5N!+!25#RqmsQpmug^!e$3JCY*et|6`pInv00PmYx-fe*|samqzr;t1G(ALDY%-GKy;N3Z%+bI8^q0nFVKzicz^9-Hx zeXXoy;-(Ko==TJkmlwVT-QWGa{Jj5Z8z?u3qluZreFcwvNB;T*Xh`6O z*TF=JnY*It74oKmBzBL}@3rF&D;tjdl_*AjJmMV5D@5oWzL&s)LxmKGJ=7-KYy?@M04rR1gY0><-y&3(XgAEl4| zeooW6@TAh7!^~&hzc0|Esq)2;9ktjiHv9|ISD1KV4$Y&KO;$E7(=g*bkLbx~74~U} zpX}q(0E3qpT`u3oDBwqj@Y6oG{Jx)BqUe@^SFa>W;VA_b4Fjri z_kp@Ze=@c1M>Dh&;Sk)rkTS^d)!qB{*5Fz07p_~#1G}9$dw~a3$6>>~Z3B0(dfW49 zq05uy{!(WzTw*tiLOr7IFs9o#1mw|NlT7rXIKI-MsQH1THc<6F(K~#?P#BaxNwIB+ zvB-XY*=)tr-*G(kAtKDsf5fACgnxTxa125zk9mOJ;OlK3p&Mx)fj;MQ?%{6KhtRpu zq6!;R?l0mS+lTiQ2#MfwSc#2#&70Y%@>}eiG3c@g49QNnGVYT zDr|_~a0+)p;iFw^oBB7v&nHoK3ZT0GgthedjLc-n`~{klKE|-6-=9Ch=;^GK>~0nX zvU7+6%K-JR@ltpR(K{{VT^z|D>nZ>E@WU~i2mmmN(z~_w|BtKhj;Hc}|3BwAbnIg% z>)3lliL7H}6WLoLl9i0?b4sNM*_(uvO-AOaWJZ#i9kNHt7Qff+{rSB=pU2nV?sLD! zHJ{h>y6#JxP<>VaPl$Be0zM<%pD z>4-Le1(f~s)x=OT*T8LaKTga8J!#mrHs3tGg&N+m)FxK`^6MrwP<$%bA?#)C!2`$$ z@0sq+OnvDr`xZtT+WyCd8IKnca7(Sgppj1jK5dXdF-GHsC%k*`#aB5g&phRnGX(c- zXaS5j`knJohY9`~`5syD*2v&T$BC`#e8nW93{HcS1d{$59XV$nRYsJIF<6f3nWVR9 z0euV~r+WXF4a0Gd;B_qgWbL^0oDhp?vA?}v9$3r^`jJ}aZ25cpArAD+0d+?9(-$q) zbu)@-%AWuTFP(z^Iv3gnZ_Bisv`F?9?~%0QhS}Vj5bwA@`r92X$O%GdHe%_LQJxqZ zDcwfmarVCGS+mKMG55*5-1Z?rBZoM+xzsSz2j9j?6|CX~JN!Tc(}8I74JeVTCiO1!VbX@%49_p6XD5iRNI#aOH~=*>CNdB&Z|zlo zbTsP~W4gJqp77;eaZCfegB>0TqNegi0-6z&?4Z(wrUzh&G#*za>Z@K~3rs`QjVK{qTBv`@^5^9yh&A)*-sX z?_6E8dEH8sxebufL5+w#G%6PB{qeiE_Tf*s>$981ViJCHXV2@un}}Kmcf)^N`_QUQ4PLFdEhPyVVLbkt}m7{camYG`-`^sXCLg>c$Ix!Sv&ma#Vs|j_<3Q zYYOiIp;C_(Y4E{TI|N5sebOxlH>!vSQnocm8KVK z_^e3^KLqMkK9xdq9+6L5h_+I`{AO%()2jwMiI)#JXyb29-|+Rzbp)i(XxhDvm6wjk zt5a-=be;5Kv5MtEGaTihQRu!97LF+#_j!cfB(DFXV3jMZcBbVSa)nK_WOeKd^lvTS-Ey^nZ81u+gXDI`rCU4fBKw&IE8bulJbv+y>%6N2fX#0`X|s z(G6l@*9Q9xEgJYMG60%rO@{5*yeiPJ)gbj^Bp9A;yn;~!f~11HT8l!eLXgj`JAvKy zK36z6X*c(SxB4f$xxDX3EG^t&#^s-hn6~BwH^J~x zH_n4Wg7M_rg`Se72Cj`?98ot0!_1;CXmL%u!Cyw~AFX}SRu08i(fJ1Wb#5EwX^j<# znPEbZDgg7xygmLCjeCtKKK2yy>|prHbX7vkigEr zpAZAIzzy8oO>$5d=cI-3tpQ!9icIvcGx=jQs&?@q4JTyUc0LgI52-pmo2--ongt$w zWe5q^oL)Vi09{}rYE9n&|I+|A?GJ-LCiD3*6h_51`ruYi=C2}Mj=z~N@A3d@p;tEc z7#|$4hBuo?u8Wk6E~6D+YsmbW8>PhnDpTO@hwh;%5pX)0BC}Vx>MN>4v`}zRHu*cQ z`aTyl9|eO&fQ(j1NjHrlXUL`PDZ;tPiXLRb_&)Gz)HAszF8enS;HTxD;tCRB_RIK_ z=sj!c(#f;+utkV*BVl3R`k?HI;p*IsE?z1yqtgl2%W7F!i3cu%g@Tro%fJ%e{8zjr zC1hvno%@+c$5H3H2zofOOQ4)LC^A_3C|;7i=ej9V#FNNG>CEqz3c5d33D2QeLbjM^ z-Va`S;=k@mIP;~6|8RHR-{Za`V11xiX(d40?y&oZk1r5x7DXK|xOFT|nSjo3({L#w zwFM1C-_--??2cfJgTEZA*s4OGFZjYF)e9(w#Tab&upE^}x z|8e}<2WM%9X&v%(D%R^`P#9VAIA)qg#&kL=%NYQMBOoB@+(AH1BHat(RUzy=z(Al9 zOr|H=r)bNDt%g3z_U0l6<8N!eG%dDr{5r!a@)&|V771}la>O!;y#ccxNAC}hr8X{$ zpO=JYDrj?-d+c9MJzC1U#`?b0k7m(FpQ#~SI|ES7!P~hXJ?BBAUjxfx>F-MP@FTJy zCX0{7%+tr*G!JUwPOzPRurL)5k}jx}E+Xo6^NW-y8^?Q2z*8lI>9ZJa-6_E~l(O*v z5UhG%?))9V;mmIQQ$c6M4Jvq8fcVI!*A!X3h!zHj52zPjezu}rJ?A<^6}O1?iUlHe zhLZ1fomGzeLd`mfm;H`ZTc|i-(B8Gb2?a2~_D)v~D<(Et_aX$+vwUM*%bHsuI@EjM zAJDAMfyx9QymaPR>f{+Vf~zB8BbaKhU!ySb_|>J!si*1F=k!IzcA#IiL?9 zHE;;5R|e>6G9q@(8;H%T*DBaio_)`-cm0P5R7mxb%Ll*)mOz34_-=R=%uPZ+pY*Ft zZxtTaox&WA>g2F0AnR+ykJ&G5b3&DvGi*w~4`>itDw zAtZa@aNJ=%em6tvR)SSOCp9vGAqSr0b_+!T-$1H+A1ZC+To@5n;s^M+qS*sYQivdB zpo%krxemNHGxULkD{301ZN-@GYOw>*=d;sB>Kx$ z0R|gjaETmxyv}piyYhh-@iB&ZJx*7X2<}Vl0xPs);ZmJ0M?8pO=K>+mMU%zl)L8%{rI>2tphz z;vQ-KdynkDD|D2(JZeB%u?qO7m1O(tv!lzz>T062XQiV_u#wX;sQ>);Cl6F1ADVqs zJ?;^ufvCujTX@0_<(SjAr_V%X;{NGna>FxcsLZEb`XFHnt1C$2$t{3U!Y;0;7^7HC zbEf)uNJ%MWS3_5GnhC4aEhb8uToAE@o>6lmPG}{WSD2OaMSyT$RoK;A!-BnI6Qe+y z(*&_ZIjQ!m(KsQ5MigtFwm|DwGW_xz*VMyK|B|zK)l&|l8{8CLw-6%Xwkom9qsoU8 z;KLGOEAFGI5R+uAcjzf$o+ZYUp8MlY*J6!wydzp6EAGNs?($Pb@bmnXk?2$36wEs+ z!gbs|X1pm1TrM&DW3K5um@q73V0U7?O3`7zW#a-f$nta<3x&$!-evb(OeI`=cb5$| zoDio*51p&MA&M0Lk@W2fE5A*kkLD!|hPUIeMd`w-i2z&kJ^_yQa5fp%%1iF%9 zD{n@wPS%XMA(stNq7~kiQ{sonz*b8z?cCEi7!%9~Hqmah{=HJChSziZ zS0M$Y(Eu2OEiW(Q`mF5<5%@G`>>jER+z7U(9+;qKWJrsXvV7r5ff#9Vk*o@XbaPVR z)X{xfn7daCitW;h0XJ<~*&ZCDd|^2$eh5;VCQfb)+5m5>^@MgJiF_7GKS3QIa0Ag$e$j4e}A!{k4miw`{Bv_bpo;DOZg&Cxuu| zeTLJAo{T!~?j_ML=zhZyS{Wo>I1(kUX%_f7So0l6dL)96uzv!7xih8~=`6N0HbQYq zwZmMCO%!KIDtoMQ7oRty_0Jah!4{j+&@>1=GK#qx8NGwW%^%cLh$7SRw*-A;lA13zGKm_i$L)D2eMh$6lmy zPGKt4mm2#?N|qA4TdUl^iLZZ!Jwgfag6+NbMpGd4$a$z%C;m`1zIlrcxRqLLRcX3( zmJ~u&yy6L!vN{t9(a+y)HpD!4;=iQ?gk_UkOqF~3Hr|$qHbjAEme>Fj(0TcFX))Dw zlv*a?lBw#MIKP>szGja7r# zuXVcipN<&Bx;u(}%;EN?O`St0;Qx<2KU1Lg)G!?fVYjcAf);I^S0omCLDkl@vc>-qfRrD?|DIfj@|b{$`O>4F4>08S3# zSpr$HW!*JbS676bVAZ}ZM)LBtA3?2$Zt^551RrpP1uaA!b}aDTli>nmb|R?} zs7_7=u89oyxEb-p8fh{0gXWz#*j9otDV%fK0v9=b&+n^~@WRQ;HNhXi3SJ`P5w}@r zdmGjHn#ms_Q82`_90nG2eCZ|$GMI}X2vfZ7;~4uVb15z{YrbP#_muL9sl4?`{dMUN z>EilkraCdnKA~>M*NSYMd+O zVS_s%U0?!6WC-P)JNUiz@spZ6Y}IzJMamM`SZa&dc)mg@EeSx2vqXG-eMuabd+F%{ z`Rb(3SE^tL;1m%Qy*{Y7YM5p@VVLEQf)D4d;%l|_OrDXwKodbm>n&C*^vUXE^Oy@! zX8eW<5q4pVra=XgLLrhDn7$P3f=4Dx(37>NK^^#XF(Xdjn7DjD9pEz_B;T>1QCM8u)dlB(x!S>7CAh3P8|5}#5c+! zs0&;KGMu_S{gicr9ZzbIBtuNxCXiS7U1Uw!6yL>**2!1epN_SV6aVVG(%w%~<$ySv z(meHVl*GBSxx7MrZ)R?0-NwYGRq8wtIE`8)G;(r_Rs1~lr1-BhIh{MlD3n?6t;fTZ zm|)BbbY&VX|BY+91RH#59X4H(=z5r+pZA85_O!dFjeNx4dFI6{m_MSg%0unHn_}f6 zY@MiTz8x*U-7V(szzfKNSOPuV)OpEj3F$#x==m$cni)uKSHgWPdQ+rt^zy>9$61J5 zRu=Fa=lO_p5ablAeb;ns%Wt*caBPH>6>b6!xbPb34{Qz%zIVa}c0uJOs3dh7H>)9m zZ6G1b^A1d^F^O3jxBb8W4%dgfAk}~M?6AQA6eGmWI|B*LPtw(^-LYGh-oI)6mD|?j z{JoSJ^KiH-aQ7M8&VEQL;l5PiN%kSlPi*GLWv8(a61}Hozgu%b-~zqN7cv-Sk$T4) z$Rw9=wLZWS;cM==v$)N?rb39EAAF$=@zV;(@;qkFiC!McBEdzQaNit+_Fzi$LpcWz zqr{P5(&T$I$6jgWg+nb!Dg3d`cVhyy8ZfgvnRO&M@-9s>Dxhp$buir+!VJ>kdj(?J zOI@frD>3V}gLx~IbztmC9nFW~(=W2IV>=bJtX=I)e}yz!g-AC~F#pI48seU8c5ISZ z1-yBH<)ehLb*V*x=L%s(Z~uq{8yLiT@xv5uYYZ%dXvW|bquPA}C&GPy<%E;3-mOD- zs!XS_6}YVX#Pr$8i4gp^rP_t4WvVblWW+}^x?{d_gbjgpHO z3K9vr_>7RzYZivLZf>PH_msdcieqNv#DEL>MT>@k$oTEENcW>FwuYt{|FF^l(_tYN z4m@-*s0hbOGHiFPvUR(kWt(0fs*nqKp+s%;83a4h;fI5~n^XKUBIBei@L>d`jp&&R zFoh}NukJ6mDKZLa4AgKWIIf2n3Zy(~YbAm}7r8Z7DRW}Ce~tzN4lK4o=?oI+f(y*W z{Gy7f7WilFK@21E97?VB1~Hb1Ry6CT#X`~+6da=stT5toSJz-qdS7CV#{^==M!}^{ zf-B$bebR*XQo}L8qRVRo`*R!bo5s9{okk_c3>`h6w>OYc>rD6#mvgXCypzEVaPMc0 zTxkalF^?Evmy`6KZbiP0N-o*XZx+utS9oqE}z#-s$Ywl>;4`i?jSM|pK z{q=F;X$+NU)`0OhSYNKe>GI7HiSvmvE&^y;bvo?FN}5V8$hin2uVbbm+2d!Zt_6qv zpCj_hf%(H_3{F55GR*|!qQ!i1i%uBk^P2t+v=*+x;_v-i z?gU@hTM-szVMtA$tDs2`SxA+4{U!X2`L!l@Xt4P!s$M`c33x>HP>EH*B0rk8%{^|r z=p0Sa|0tHq#}ANVbs;XA97(?R4vB!~m&h38q>&Kttly7VSwCo;b$@y#rwf=C_IYg; zEb0gfHvaF5E?$7W4Q2@kTk5W-d3z4*b)b;Q5HoFv5s>Ma^^<-hjAs3;RJ3gRxC6K? z`~#58u&%!7u8Or^N95>~L>MW+Lyb(J7?z2NVVE^)NHk#d+ zOZy^}R9i6Rs^r+_yoqCg)i*JG`2O~*sN)YP=80lJkzN;k7yYTM^v%$DHwSerDL8iR z1Uv?KDT7WySk`s=$#aaof-tgVK&69r0Q3m#0h!xLw?3Jp^#Wz21wE1UFb6mbU>^>e z=;|aZLN9VVfVja7!;^5>xndpyM5w~GwfKK+=s6g>0sU0#6&Qm!dIqwCXHencm56B= zm3!#iI_39-r&xx6v&R!sFDBfH*5Yr4ga+86kq8%9{4BA{_vL-Y!qT~Out3vj5PASz zS7885Vs)epaSqMdhnH$efgSko%5%rmIsRnuFOv@p3>0$k&~W9H1L1!dsp^9AO0@br zNwnh*`^f!qn>+)=W-vGrG1p6O%FmV?2^Pm?{(mDT1HevuhjA#hi*Zh6W#!l5d&)NW z5vq!15)H>wTc|`1EXlMpxlJfoicWrnkqLO>jp?I0bU6}uxGc{HHEXxP^dH$=Q0)4K z%>AyOnpC;7?;V)8!^;DI46aJX8dji@BM7;0ZH**&>PO0)Cae+`IU&Jk;=c_``vbYD z@j;eGfNQ!!rhFE4k5&M@@2W_bXXFNZS#T5-3IQ^0UzQP2L-GVKGF*}`x6A)}2z|Ir zxLPD703N<_>EDM?6--UGET31@K9BSMw%eZbPD#mE&j$`sXN`oDk>^@@q@_Ieo{e% zc<5T~d&F>0VB7A!Y*j?b@EBy+&GmiO9kaxPV{#GYJpJrgD8pjE)cdko zsk$)a)2+RU4yDQ{S4d@yg!Hm3$p(xEQDzN;l|CPQPcI0xKrth}-uX)VO{^`-(I&~s z)-S7Dl8X(A5XKT=$|pZR!d4O2q3x?W6J&s5o+>qv>KFv6LPOwqulhFeRwb|vcD!81 z7C*UR^OwFmYv;Q|8Y3SLZJP>kG8<(zHiM|9lGtTA`&IX-do$o~_Ywc?w4bgh3EgQz0_PHOkB znRBtW4?8$+vzuecCl34uGpJWY0(j>pS*u?}VqJ7`Uw_5HI2_ylhNj9D=$dg6>KCRD zi@AFVgtI)~<>$q9AwvZY3WK+`etBigb-~**ucn&Y>t7ipyd)eeFtgWI8HV5|Mb4YF zXsQ9BZ6oEOT6DMW_0W=068<9kI`#}A8fcJLRMr!kP5m5!GR-dSu0}wENT3D!d2JqZ z7HlKO7BaBSG?L%miN!S!a(kOVq0niLK#KnxBtw})%I;+M)PqGdv!Px1Kj9@G*&mMY zQ>|}pp5G;Dp?;Se%`;OBWXkz(DjU2EDY;LbWu`B*eqpl%FZAe&F63~YBb0|cn=ior zh=kbKWIBQkWqsmy&4)a*3DtdNLKWe7!ukxMD(b-M44Z=aU(D&a5ec;%jT5ye5l=7h zSo!Ct#y=M|nKxP2e(Hwy!UFLkTGV}ly-QrjV1M`1z-TrJ?s7GT7VOD>Is%Sy5sH1! zp?aZ&^?DJ6PgXxgQ-j!7hL}L~lrJ5CsH zjnCP{?ssUtw2mbfgeX#hWMIOFnZx%_i_G$dIp?|2q@Bw8MMvbUc; zQZ^eS54=w(@l7vCT1kQJxP*WCUZ?o}K#pd3;WO|KckL@V1>~z^iDHTKDHt6t^%n$absqNXOpjf2R1V}`WykSp+9#S z2A{hrbgEAFn}wXT40I146(9yp2ID+R?$3epS2IW&rdc%9l`$B^IGF_Ib7;EbV#;+| zMw*|sznD*ZaieEx7ohg z;Z>0i_^D8ah2WPs*!zl4k4g;|i*36S8{*N0y9sh$iH2jxvQ+HyPn)zWx^`3(?F_GTMX*0* zT+HCkmJu|DGv0rA)|+z!Gt-`y`e$t=R4cLJ^hw2p{-UP*}coXAeB>cd+()&RObjAK>7PX=N63|CMSuYzhYgtbq(Oq zrY30|J>lPEDRcH+S-}OP?(w4;Y4~pFvo1{ZuI3kGwYM0ZZg5K=eW04x?fHl?bNu&Z zODzi>4eQ-YgnOk#IYFdPKpzY}WP5=t6zt!owfFoim6AI2;n7?)D#+=yl z&UJ}OW!ejfI2C{E3Q9nTum)og)s^~q`QbNMnqb>HP+;sVg00>!;U!;`Tksj%uj&}5 zo|~tDm=9#xjH)9T@I*-Ik`XV0ROo<-{hx%2{?fY{r89KUte2bwLc-kwO)rU-NgAD$t(xk#tjhZYKO58~h3}$oE~Yr!kv?oHxVgSgS|=>BMQhOP(~t z2hL=+J(oLHGsnB)L!Nq%rVomGrSrKAkW`E#&DYb7lg!u~pF3NUWdwgU7Mm~?X6 zSX5=u1l(|GBDV*~lFCH`is{4T@&^?8jXjzt1a;ofdr)K z-8-{53#sStz?MIkD5N%M+FvY!SsUv;|6M9KWwIX&O`n<;$J2?+jM}M6l@cL@WlFxn zeG4w=f!Ez);I}g)E4J?Ng^e4JRPaZ~H>)1h3-WqHdKWB)9^*76VN)1cn3c?tLNMPt zU!+l@82H@t=uqe ze`KZT`3@u)=K&XVv#daCkk4$G%yFY9>21mD(w;A^t!>$tl>@1lZ#XQ^L1nvpyb?R% z6}D^b`hlq8los6>>=Rme4>(pATkHpo=`chwVlO*fu6e8oCU(*yJpP=*0=m#p^jXu{nUWKQnb=dNsVaRMpIsYXm3 z?k0@vRFtqinq{CdZxONR(h;VA@<;;hRSS%`|8Vju1+Dq+$8!~Oi}K^#_GO5=KhmHm z{VLZH@VlC6&&oLDls$4_B}STlUN{OP?!uxT0cchtuP<*Y6y9*RIrLWLA>Bohk58QS z<7~B>D7w>pfU4sQh)LLe)xODXzA;4z*THg3x4F!lz&;mklyWtuG59M|Oza@pKOi45 zt80$B4PUg=lmt?cO~ym1v$b@O;%5d{U%h5^yzb*WSPC=zBT)3Sre6KNwFGKA@ud3t z%l`bg?ET_OxR37FwWdT zBSaxzsv<+BiZ#J+IE!7oc;Sa@KB0QoR-E%XX9?@WkC0hxBK{HN^HmO>dtzZfnvs9a z#CH4lUC^ZhKY@x{E$5}6!t-Z^)VNAN9qfW*B?0BLF{TO(S}{SlO$2&>E&|}q49}v< z(}c@YOd@-DZ-gN&MS;^B45xrrcXY<2DQ!zS8-$TH)eEp>OOy3 z4JGFr>4If>Za^TGC2E9&Jz!DPe(Io%r$udpCxRWW2Wg+B%m;PgI$x*zcV?|MP}j1Q z-4^ls_~4S3u60x!Gx{=kabGY#&Gj6t$INI2m2^^MLY;da^3oRDd{!Tk=ET$M_uGA4 z#fK+@ni}GHvVD0H|w8TKcBxU>kCH9)iPCdjEqQGwAOLlVw2_4YnYZqgTcsc{@*$;tZmFu=I zMA93Ke+ht^qd!y!@(<~xf?I5U3Vtn6g#9p&NIpLHUXsOpowtYs%|sYXT>5j$2L*_o z4W7Y7>sG^WTQoH~;D+k*V)O9W8;JZX`IUPsSDrO}_De>+ed5CHujro)Vxu}9?o)Rl zPoBV#tTi+#@OCVc6dHgc)uICGRG(T2Ov?o3SM6Z_rLq=<||N+Pc1aMndd) zRU5z?hR&Lj_*(6%Yu%HDr{tgihRe|j+H!r6g5V3zhhP}#&9FUD6zEtvbEcc^q|u1$ z1{Y;V5X<%NM znY~*QudUJs`)ntPwbns#5dP1IPq49Re zy0g>bjC@BvV{~D$R5q7WVufTuMHi1)Nh+3-xc&E2qs^ZHft$WIl#AKUlN3GpfZ_b-l&Ha={{(IVQ&i!Bp!HK!};2z3eh zLZPyR3T}$*8Mqy;&3Gt65jpZ!WF;Y`V3D&fZCVI?AjxL}aHuQxoy8n^1qE#hKGi+H zi~O7WrTq{ZglCXEo11v6W^Lej6f?8)71YE7g?7MS?HO;Xk>{pDX8ZFzO;7Bq6P z&f5N0)I+f^1{;5x1Jji*FWM;Q`o9DQ?~-X^23jVHz+V;;oT6}V)E!}X-q3sFHnsLW z?-+{*H@G!-=$4Dw&|)l>A)bR7JUSm`;e zcqvbX3RR~MM0G`5TLmOu0QnTDQc7C`iPyXkzOUTi-NxXVyah0@?R5T#eJSCU^_cqW zA6LWnRr7yv0@!Qs3J8P68IQtocM#bpD@GN`OTQ$pVlGRovj;4cLD@qGf(FW+9~0lyKfLBGb(byr!|GD4=ZKh2^WU#-$Vv_Dzq!C>Eum{) zn8*G0o0eDCgC7z{%Z21x2YuNl)6jGQu9h%E41|5Yr`=BJD0+3~68!jJ8x; zU$A;77PTn6nd&PFW4}pmy*U;+_qO}$B^EqrLBj^&EjGf0cVrjk5#q6pj+r9IuGgpe zZ>j@33+NZPn|CUt5bN}N>n|;?CD_gN&UJL%#skM^60P8VfB3KpVt?o463BNI+lf7h ztWyA&Fkq+G86hwH4Ggi;L8=^7ul=^yp_&7i;uV9{^L^&aS?9$Z`Wdy$bA_*m5k*Cn z^vj5U;AGp4V|T!#hT{zI!sigOhn4xN$yAc|t=NkQNzBuwvS5MVN}0E@1$hy;V}OPA zwLEf!oU3BU-y4F0LccoADRRrO=IIgv({^FcU(7yQN=H5i67~yGruZjrRcGRMqbdd_ z`E9rR?W-xOR^!hgrB?*N^fZy$BP@Xu@oE3l);^0hIf1g;&7Eq;HTLn;aS??~TuWB< zP~0rg6K4EYKUu)mP>U9D^iuG%lD7fQDgXP`tNagJKf#X$g7~xVrM}t|EEcI4;9C#s zt0azMe1=vSAwF&Pzh7qigA6#TiFhwVK9~ki**(<#SUj|^qsVRNA>iV-@b657gUAl2 z2yX1pYcM-x+8>|W$hH5Y=gW~IHQgd7dQ8!jJ?w;ZX|m-NJDd)J9Q&}-CH#}IgOR2e zN4kvcKt^W6@2Rj~ApXdK0%S}%;Qn9^QVfX8DBZAmZb4zeZ=A*s6gVt^&*pyZX2psr z)FbVs3r+(~VFN20;h4!k<&LYpn`?weF-h6+;xQ9Pg(J-%ZN!QLZ4MlabfMX7z#4kI z2>#`13g2V1d`bGFp}pHE`&hMpXZ?-gKsdytI^wZE@n3s!dp#L2M>K;m1|}A~Vby6u zI}?o14nv_G7BSOsgB`}$9cy;!SP)P9yFBBI*qFR>eB3G3FZ?=L-H=WQ>~J%l5WPJ% zKeNJ4dlX&pHi$V2DdjT(HJ`hH{>_So@7$AFZiGvDvGc7-eN;Q9ysSt=kPq z{rkQa3zpdiNm<>!@MxS8v0~u7YLdk0S2{Oly( zJ^JSJh;jZTJFJo0&ilnQ<0y!;g-FX0*nC$sIf9JTI3X!AgkkUf%SQtA3@-{XXm%R0 z_~JwuVCw3a1{RQU(m-6R>1u4(clyqnUOSGvAIwRqetKS?BZkkZ136U=#U2+ItWae-E#HKKmt$tD$B!L1D~a_$((UWTBpsyXi~{jg_3V zu?2PAJ7yV{i62=wQVQFxlKh)bojwwo41Sm&-0@`-FwYcKj{Pfyi>{DdTzn7DN?r0n zm$Rt0XUb}=jw!oWALpKqhV0X_|FWY{xzm1edl*@6CjCpsJf||ZzkYCvduu|YiaHeU z3{1nndCs1l{YpK(?B6Y^*5gQVYUDYxk#6VqEE#?P_&hu#@ijmq&_Ie1FFv!PTtw`rXmV;w_0{#| zEoVhg6H@@`rc4gcBCVWj;K(nn>7Dv^9zv$3rSKmz5c?hnB1@BHkN+%xDbbHlE{>NI zZ&vkl|Gp%3g9J2Z{9A&-THs4M1)(sVw}35-&9Fw33_0Yf87BLqP`T1^i29m|MLt$7 z9GorWpe$?!$rZE3iQhf+p4)r5Y<4lgKQCyf^2=^**`Jd?Yge^zU4Ifp%S{Imbxq)z zlv(9LlywzRJy;!=oXOvwsrdCabfKUdcz_Hkd>=M zD)dRu0?T>Jd17ZE;c}M>n_BB2+NZWa%N7j&#Q|GFBmsT0+2gUpl;P|G1b`$)QqQY@Bh)=|yw*86D%DYC;?8oJKB7cG&$oelVX=+9FVQhdU9-O-F}q&78h zH}#g}+EQ(?5yCo^OAGWgC?i0BgH!)#yiu60dYoq#Ijgvu>t zJwdAVyK67hv1%_eAs|IQU~I~9`-92%Px=H9#bAvPh815W_ZHtvI{qG#&iVL6f>^ zKjLbe16qn0(Cz2G4J##GVh_r+v+W5ckG+UcM@*w`>A$bYyFNs-naS~*wgNH_gmX`)=g6pwUnUE5#k$# zUUxD;ex|8AdG^@xXn^!5k8VLI%}8~?EBVlFJEw&+>6EgQMRlKXrqY>j3FL^pQ9H>49u%c_>7mBCBSb;KP?MUtX z#<$k$SD9y5UNC==z{kd-Wdr*Kpn%E(z-Ui@M^e&Zz&KdQr-Q<03pkgfmF`8 zzp5zN>lr?}i;il|JWFpr#PGJqz|!i(Z;914?o(1Zv}%AdgApdv zbGi|@AmR@%Kg@3vduoIJg>}8S&#ZLip7`w_Az!*dJj@!2fAa6iW-E9CCe?q#x zadq@uwoMK0rT@gm&3Xyd>gU4Gf3(cAB$t=%X8TTS_0aM6KSuD<=*79Dz zIw2du*5DU6{Ii7<;9h@aDQ|FN0ERm^*wQF6^~E|0nx*;A*$}P+B81mjjIBBh{}VzK zv@Nt!eQy&gdX!SQ(Jqg$x(zjwOU0er{uJe9G_i?UqfswM|NjRDp`pM306d@vBev3` zD(Z4*l+W^aS;$K0_m7W(^WCpnX)R!7+b|L&~gKcDLY7xN!Ng)|tBBuu=l zCM}|q6fd47w4*Q)fB|38%G%k6m&zMm_FWON8h)i|amNBv;6(NRB?3zhB*HQQa4h?b zawKXEo{~p8t&-0E(Zv;3(?gMb-VD)Pv0b+4oy;GO?LXNrAl?@9C_@-1BoJl9b*P-O zE6jk8N=0+e@w=VVANtZWUMLC{1ebw@q2N@boRQ+a8HLWtbhcR8R3zLJOjY{G+w6Sb zXX)z|2ZxuuUG?`|0mT$pgjj&Jf=-FJ<>hm)-xS6jWyp8-d`@g!4elIG7o5*$nAHCm z`p;<(01G$$3@jm($%TW1zpOVzb@j0BHZ=l&+JDlnO!S`(&5sB{C5-G#>`1QX* zT?85;r|IWJD`u~K^j7)Ue#pHw=eg~f1WM#_1ELL%?FDSxuWZ)Fs>?pj-oc#i?GV6q zbuDd<5ja}J?A3J4Zp(2jZ3Q}f6mfCL&S)X*{8h!!dG67y#vV6{%H1NY+hcR)ivdx- z=LXD~0fydM6SKV%yfZy|Sm`(s=UaL6m#c;3${E3qnfocB8qNrC0a&PXevTp1fTqu8 zdME5iOTXFW4Kz+K5;+vyQr}EdzS@v4*7ejlgT6d@uPl@7VZf>O&_je*O->XMoDK=lqxpH+GM)Rr&BD}3V_L}9 zXE$E9`57vyA=D*PW|{wek+ysDhDOJLj(#HPD?R$d#?V3bovviws<7Cy$>VDvqknCA zul4k6!)OdxH2nTe&=w6?;fo{Jx8~Zf${m=UcZI+<-XR;|=EHk6pUV|_@;$WN-N4K) z1M$9^kgCakx7a1OL$f2k4J#& zm!Dl3OI5s1J&bobDZVtS4o6GwuL^os`g(+cf?%EY$L8wk^q3a0s>zcflhbjuAWeS( z%rVtP=u-+vY!1LL0)C|@S0Arfz*16F&f_P>{JL3J=;4RLpyA8mD@}A6_^{Cjr=wf# zoumud05&e1nZsM8{G&c9^06alZDiwj*n)Kdc zcW`h4e4MBGB(Q?sap86r&CJPF&}mtG{PFnLg6?xrCDu_ho;$IX{L%1tGD~(%IAH!o za$ar%xx+a_pEy95cnM7TSrd=AE1;<{$gasQx~li(JRVnysIIQAyuKf3A%DX#L<%FE znFy~RlpH_MIZ2^w>kK#I??|C**D}^k@DSXSw>?zBU!6RtbF*%Kzi>n9AHBH?4kV+> z8Ttwma@C4R@zQVJlF}T#8BqMhIIS^SxJ~$nfZ{{t-Pz~@zxj)2h`+bDcP@6`m>+pf zH@B$uQiiQlRdn^|&|~pNaVYZz+?2qP2YRRCQ4jDdh^-unBPXUk!`G$c+-N_3&59{0 zF5w(%&e5^^>ArArnNy|fj5a{8J<88qB|2q=JkX$g4u~2Z0xLu|2LLPA%7#VR}nR=FbBB7K# z-PG-^M^l^Z&~bT9I|Uizl2l*9Msm2HT#dr!$7zv z>9Z=qEbUjf{XQ(E^=;&@cH_2a3tLk$YP-Xn;*{EPb0S)ZN8tks8#$oijswm_I?_T= z+Ww`qoV-*oAbL%iAPheYUI8<3I!ss2Ap~z56_<%thWwQ_CB4^Iby7d|GAx&Z^*lCC zogx7~bmj!af;!;)WRIIh=XBr=ceYzMIN||-yE|VV1$DAv{>KmirrM2R{jDFh;yTu^ zb|%>fwx~LDf}*?q?$CwNv__L_Mt)k$j4Q&tCOfa3>SR_P7~KYCQQCM~P(k!ux`_FD zkTZ4lfLbrE!==jOi+}mksxPZI2k-hT2un@vca36GplUHTXB0?QnqC_mL|UGB8oKC& z_Q@a>@OPxZFw32jk87eI^Pm{%!Tre$;`!)`a?D$c2l%^AZ?oH)_tWUer0^`8e4Q`I zm7x1RI;*B9*Ok5=5UxrYOn57X9L8_01x*#QV4g#%HHsB*6sOT(oDmL3hG3fTuCNZ- z^%V*SUl?@Zh5TBoDR)jYv;D+Fs83?6a*Jo`psS~=vlMDK>ce?t~NQl`SQ^ph2{r7OOyG>s!9vXhb0uDY$LWWATjCgAJsX!O#R^0weCSk z>4pf@Pa7<?|+4u1s!R z9P(f34z#@yLQP7V6kFbRFev+C=%U=J$>p8j<%Kuzv+E zgg;Wr?oazcgJqqJ-f1Pr8W33s7xTebsBwNY1B9=UC&OA7xp^R#6%2lOAx7i)cU^1i zov|yEltA15%aXFMBb4gN&3|P%=Gu8z@DHb9fPS(6W#rM!MwqdbOfJadfy1%D<0*|)2KQDT`tbG-|)?oF=(5SdK>!OQ+|=JP3C$?y_KCpUeMHf z|M?g3YU&!=U_hSQ$W%#LVTvXxxhMC|74~lJuDtPs%9i9rOS?}_aZTby$BcPPa{W$U zdVN-;^Md{cn$c|YJVC+#A6r)$7UkBpX9iG8q!feh20)d zLAsHU8kBAUDJco*?woHwoC4qP&$+mcGkbQdz4nTG-OCe7O6!WyOQ8jQXy=nt_6^*X z>l2^GJwERIMw{f19PCvuGo1_U^=**VzvE&W_ul4?DJUuiIpCGO+!3sO>C~KfMpo9w z>D}JmURjW_8Yp{Q4oXrLL$Y&i=1X*3Nz*rX^#}n5F&h9sI)wq9A; zjrnwout49>--I>Lw%DzQPB|ti-HcXxZ#0QlD#61)8p}ryUTA5f$=Z)o!InWX(iYMv zGZTp01y~xmLyvzg7Pzd&{HFX`rGQIFeM^hGVwd!?>)JIhp~z~#^ux6fPyf-EhTQMY z8+sVJWQ{IG3S9z~+(aNBW1n{x;N_6~K59H73byWRE^Qx}L7D(yrhVdLT^a*f^vop- zyjmTyHhnN(V|hZ}KYX?O_@cS5!8LC;(97&qaG|r2%QnGZ5zp;Z8K`yQeIJ`9-FY5| z>%eI)`6LaZH7Hau0@5Mbz17{bKesJnpNIM=iMhTRI$W!CSh_JSX6d6kK50Zqj80qoieJ6Ymz>mZR!22o6K9niz);$=p`tL zesm?24!GY3g7faP;+!&1Hx?fNR}{EixHI%dqxq(QQy?TXI9smqZQVfe-K?P%bfCjL znK$o|qQKT0R5!QyU0|P@hB}MX%w=3@nEP6LB4d1sQ(04&#lPBs5qiL180epipmhdY z3v8Asmus68?rJ=IH|X*4FA7aG^H2GBA4b@oEu>QGHBHBZP3K#Wy=JODAQKgZR%sqVTIeT>5kbfZ7G|I^>uJ6QVcF# z-z_)YxyB$`(fkPu$LnD0?Cw5I!n+R@AFu@0`GN0s7dt zx80HnhB|#El_902U&{;cKWQsm@!WZ+bcKbd!z=te*neur=KQs;g+7xRt?iL>HFEea zca!Q6afnXi;}$y_I3N;Yvf3(PJbE)--`6GMl?-4uL!nd<`H%DY90v(MI@od!bl!aL zFnlP`*mfS%{v}l5-ox_z;pa%FpB6%^&q9;i_eS?j=WF+%*lr9R8Xsk5ln=P< zsnNO`Y_K$eDomx$dr*MCREySf2R1txYhBcTro&@3F3xp$mpiA}Tdhzt>|jqx^GD)Z z-+Q^U7{&S-P>>Furxtu!VGzytM}qgYY~ri9>{eBl;mx(bnxj2LkadWTv9Sq(n_?vWUWN?t!~oMkivzy&?jX)X4X^Pk zP*Td0W2OAe>|}CDSeG5gwdQ$xm1Mzdid0&h+ZA@5=fvzRXkQk6`Z{wRkUV(+EH_#+ zBmg)m&G-u=5zMao4!-0R zmml@p=OSCY=-Fm`v zXwG(}2bd|$vsi8?F=8x+(xs}aQ!%(=M&f>(3qHAjs?nm zzHst)L7;&iic3#=NJuH?mJDw%Iv(X#?F(=E{~E`&b02rP?A|3vVJ>ZjTO^Mj#_Sch zzW4~V9?U1(T5a+zfo;Uijkq)14Sl-rVnpB@D-eEiG$EyaC02er%ZxZQHf?H z;*Unwn-BF?I+Uu~sCsR09!_OTftYmeZ|deFD8PCKWi2OX3>FrM^7Kdl>?l{*S{_(# zTUt1FV~+!$Uv`biKfjvkP1Qa0Rj}Pmy{~Wlv!VIp@{z)z^BXk|-Ve9YbU<|y)$jw3 zu{4G}kjO4O9Qw%!5Ff&~NuUc3Dg;WhVYoJA?5@>LiTyM;-O^ZyM{gM%9SrG1Br&*x z5MCPY^a;3Jo7e?i{Mp@b+fabno5PX12i@luY!I!S%LvFRn--S2B8JuwD&va&$PySr z;O(COvx^>JiXnK_fC(j#VcQFh!->{6;73ZuIdYG!k2^BqveI=HKX*S;wKcRns+e!r z{2ERhb8)9FF*kzYEp^X^V#OO&3lz$zKqmvovW<+jkuA*-FVFaB?Kf59$g$otAb275 z!o4!LS;S>wQ08bSNJO0|xSxnPZ<)}(&wpE1{m}+ocb5cS2u>$T!>$0-5%6FGc;93d z$8y8~jn{nL$infZ=+uJ?T!%f&8vU^Bab)Ya*qKu{TUh=4IKh5i>2a*&SvhnM5fq?? zin}305qNjaY9+Vmmc>LA+F-{`ayzw>6z*LO{D@)O=*|^Xdqu;4XJ1ra9?}I(`Kb!L z*PIj1^sV^PG-I3Gbqn<&kaW(J3FeH8P;Lj zJ{e=i^T$==WdC{_{V#a|utB=B`jcj|-5UnTAKLJ9d16{pln)WgcJ{R-Sn^L5ZjfS98 z*3+VVZF#`g&=z!{`0V-ag+ZQDIQ4a)U2LDsd^&~%3UZ*U4chnkK|2u(<~;YGw!4S3 z)#2w_1S|lLG~{s3;f9gVmLZJR%G696XXxgTq%xT}kl7g!Wp9$%@BoJG1ciz~ks=u! zJB)<2u{~0Rd*`{w{*gd)?LAsZL=_QCI8Sq6rIWoaPR7jld2qNZHywDkO$4wvAZOG2 zToafrC2?9#RzxahCAs2Y%zuau4flp*z7hxDf#9>8(Lz&$^f+o{uucK(OCjiRpu#uS z=;J#Ye2dr~f>ThC2a^NcA>^ZEc&N2hK5om_yOFEi-gFH-u~D3P=KHpbUDY!s6xI~{ zaCaX2Uu_g_)%@=CN%`Qrf&Nl6;H7;9p(!Sd`Rz!kyx(iwea8yMyAI+nT}85PD>F5{ zWth94-$Wb5vhW@iO(g4%F13lgt|aLM2yfIY2?o%iQdueKXdGpJbpJlL)_Vi{dl1h6 zD|3=A*4WqBGQ$dEJGw;Qhob|(o?YeH*exY|4e<7V7lJ{y8PhJ4!}0~!CYD@ zWD+ViAG7grY;Ud{$AK((-o=DuXb?e`EVs)sj#Z zS`6T8kO?1Es8spwc~i5S5EpuVS1QplH23$tl*I$1fcgG(V}3UE`{nx*KJOp;%B0%H zLjZW<6+dtSiM)J(k&SjtJE@}R4t4deirZ3-c``^GuPZ)+N{$Fg@-S3Gz>l~&pjaG% zS?85Qiw#fg6tcvIUmv&vz1wLHp`3uzjcMhFt|7PwN0q>LcVx$gh-|PaDf%m{LO~6^ z5VfxW99z4Z35tZ;xtP*K;>nBo)(5r7$_k$aPz^!Ya~kO8dgDW|EZc;q&kuGM&mYCT z%7^~1DGp%NNq_X{9M)C7K^^>&&yL^PL&8!a^YV^bnZD z2%3sHF}KBEktv_P)aMIEK@~stcZ_N%*5jj!B^;@Rex+TcYPh{bEa>o6+LiInMcnHE zebNbgkqT}Nk{0_@^+xc)s8DqzAf@q%dMgCEnhiKmtk2zbX5DTClzdSMFu4iaA5WESxg$)j58^Z z5)h`sC*9R0)uA#FQd3&M3C^pL^!1Azn%~<)hq`pmpsAxtAl#<{;9aH=TWm_};)$sW z5m+F|0}7J<8lu0?TUvTyZr|rJ$$!PiVCO+!_|YTQKBY3rh&FBf<0BUKnR1Mj1<1IY zZutkgv8uZ_I)63TUwLilb9smaEZ}V(KN}DQ`!wY3`&C1(b;D~z`W@14+Pm*XAo_pe zPW7>mkzzgU4j}0e-eOlnM0FPnZC6UT02O#O%tS+byux`b23)B_tZddLPey#QAuS|{ z031}2n{uHy-e@Inqs4UU2}-gC(tc+*7vUxPm3J1ut)_w+RVtOMt-r>6%6Kq_%S zzG*T(btGg|u~MZtYaq*&?;g0PlAtwO(cOr4gAW=@fQl+KDTy}Qm{|*hd#|Bhy8P|p z0l(l!`V;R1tH8@SCd<(wPiy0QC|!H*Ilou$zdcS8V% zuWmLomBvD6Jq-m0hXp%?-$|_C)3=Rs$Ob4#oo-I(X3CRlmD#^M;C0M*VRK#XzFQuJ z*YAxOej>heJ~EgJXoE3akx)qYbCESl53_hztpu$Byn@W*+mBn${9*<21vmz_KFb+= z*~Ss?7*G7Q>!0hb=S=n4-3~Bp=!lGOae^yZ2)GD=z^33-c`jR*E$w7Z?&nglQL)s3 z=|>|HD{kt$*vWPC?Y_m+gDJOs-DR^FIq&t%RI35l2!fIwwa^`y#|FeR&4xK{%G6a$ zx0~cU9t|5&1_HghBTegW7;(_><+)!@5NLy^f0xBp9CyWQ1&jTzFl2eFcrimNREH<; zNj-g;OPAdwl&H^W&gebghzku(fMaECJq2Jx+#of?MOm}^js7F}VM82e`qu%!4wDpb zyso8yUfB1Im!PBnhPcqn^V3dji>J)1`9^`qlB(~=2T!5PGB#}fscCSz&m!K-L_Vx{ zm8`-Jq#eg}l_VXZ9OC*7S}0coV0Z4W$t{(Uqg?0p0I!#eZx+w2}%OH_>52Wk?sEQ_Jp>iN+441%e;*F^ER{_K?k_s9Rh9=ewi03AS zv=*v++kyD!%npYUOQmBjGTP;JN`<^Y|3#$fi;l%mGf~P;f7*INlXaLZiC1gcn69n zl~aP)rm+&cHu0S70WyfI-Qx(vTgL1j)I+jCPM(&Y5!`{_($Y%Zn_SY^x{PZ~V`DWRE)z*HqBxX{t_;eSjMs=)$1ZtlCLMY3d_;KVuz! zyx=hX?QJHlpb*$Z2~|z{lH_&ldjCq8o&<0_(bj~$D!u#7A$Fdb)BBB7 z7_T<1+pKWe?Bu-Z;`j|o-sI(>hxZZ~XXDW$@v|d~jRv?DAoh(6y+Z<;XVH$m0IJk- zt(GgO$+`CpYJjHg1IgGuk|;8`FE#|jfG(v7cd7nD_X~Nq|1z zSTI!8wduWaduzpqhuH3#&2J-#*HFtko4qlTx;hHpQ?^S5*=?5==gO zKV1gsd--%w-U9*L;!V&&g6eDlg6A3Duh6?WXY4kS-^awlP;QF#7}VjhGC*M3p(kCN zYq?Se{9E6u^#d~2*qa7hUc$oN9tvN=ZNX60np;)lz1XucIRn+H5!+WHAA99{tPHuY zt#Z&bLAg0Y?M%cT(bDu@g$yxV01v>4^dWFD0O`Ju?XuF~77?(G1SrlTD?*}PL!;?W zRC_G9&zv+ZfD=an8QaTZaT=H#4&&d~GOzNyQ)vjYJwifdt#Cjs_cU~~1|weJ)Efkk zRg3iN)y|}=kN3#p{zaOah~0Zw+N;FC&xvS<;Na~E(U77CHEe+SZy~pq;c1IoUp!A} zb~yZ3@UNWK@MJ)aiLNTBKE!m)@_4gmUd#f`^iXxyi9|J6@coNXqEJIr3b>Q5L=(iO zs4Pz_%&ns+i~-2NH~h%}B?j`ILpLKN zwhJHa)7laHs@u(WZ_Dl+R|p0HxaLaZSAbgv^E1Q?n~ZEU&-GTt+;AG=1rfhOldqPb z{aY-rp+b!y^z5S!BNsrr`p(4;J;tqcVbKZzEb%OTTz5v%bnR_RxO+Z+ZMZ2D8^Bt? z?68hS2!)qr7{a-w33B&B17BW_Sw_aw4evXh?>~@#fx?3zU~9u0+I$m>JWMv$F?ekI zOj7#?b~&cw6gpgI0Q=!ZQ~Jh>xc2x+f=)qfNGj2;2nY%vPi_AxKxFpPeVm=Q;lYID zpx~m?V|_$kdu3M?RIyxFMwhUi7j#Gx6OGBtX0x zlw4bo1x&nB28C^FkKXwC2m6^*^8grH2;t>hJ=5#Fv4|~fKG(RP%M*yy ztO5Ehw=sRP^4%vUuhjI7Cf)>k>}Xa>*Y+6$4b1gv0wQ? z^h=Ya8E-nCb$EYkW$JpsOVk$PrQ6GbG5_67ngaoC8uceTN=75*j#Hp352}W%cUTux;o*Zd=G`9!GS6jH^(&!fUPjkene1b!1Rq_1;OLFov}eR#Ir)i|B(R! zfQCTBRCWiKMUw-C1I~;#EE)tx!JG2~kU!mk?#ia23;$Re9)oEG2uD9u61qPw{Ml}E zhY-pFUNF5-V0^?kkA*ST=G&KI|%Ja2l3l`|KWte@nOfXyt{6Uk{9&+KX^8Zu^5WRJ%k!OBXUVnhrpq?i-=Q&M~#pC-WWjyzyI7+4VS$OY z8^%HVnq3)GGMN(ng+IIM?tYV8p@FlxgNX)@5ypF?uR)J_z`c;6d4PSl|I52Ei_13p@_E4d!o$bk8*TBBLQf+um-AZSiC9wG>+Myb17=j4Yt@kUwO}L)n<&0i= z_{wn+<~#rE)vW)TzsX^jiT3)TmA2(!iuZQ$u&uN|noyhEfohH2SdYOdhZUa%|gNZDjdH0T^Tj#=QZR~JBg~z=33JZ@mOOsq* ze%7e2VBq%tbSs4k$hBF3_T=uQS^)FoHYTv`_SDbjL;(ym-zs7Yz~XF$O}Jl1*J*BV zh(}axD}?^01t?s$^LV1!ohm9>^F7Z<{hn>kD5ZP#JzohL*61zZeJ6B9pBX2;Y~8o z5Nz`c%dusGQCk|D3J6dnA@DXMfN%b}-Q+T6I~g>!I}6ZNz`$`eW`<;q*gg~GN#&D_ zxrr6>N;eQbpQ+Z@ZmZDu*)5zr9N-D=9`)YnJ$q;Zt_Q%nOAk*EddOrsBerI5^K`iB z15}}|0I`$^H;@iY2A-xYa1JN(0UM$ZC{ZM4wfqf*nu&Su0KTU<#&a~Repv2u#;V4L z+X;v6GA2&RB)ge$$)2&fP-5R%E(3tJ3aV610cMMHO0&%3O}$H7WnU8ru4P#`y_m{I zx16tHO|06>FDWmiLF7OcA#eCXAPNO2zD6j zuxB!Q`flDH-9sf7L!F0rXTKd8%zyI+ys0j`#CcC4dW*IC@e)u~#IpH}fj$>|fq5*D z#efB1z6};T6md&Ii4sbeUFNTBk`8`9#~IS6&Y=L5*;ThEJ7em(xuAn_^w@q9aoIgB z!}EL2(4kNW;5Ojv+R`@c-5wVA9JM=)3lFa2*`yxopVakXn~taT_ByhK-Uv9^&bowm z*bV>tXCH|%-$7o0D;lW&ZP3#iB_j>Ys`?E9E=80PLp%QoYwHHi+*Pdmj!6$A-;(x~ zRTeD|)qpg$u3`M39K@MPPVUsWDs0Qj#T{OeB|6Wsox0qcy|q@5J>9$Ax*^|GlvA6S z&vF-Jp`7G{qVySgw?l>aR$C{gqSW3xtK2tB21zJQj~#)JJtnia0h*awx&N4%6N(pt zl4Il1;=H@5M4RWH3C@qd*hEd?;Fpzo}i|vUv33Tt@nIEM;!W$92uyZcw&}2#65XF7hjMAHr3?O_BXGp z&B_m11$Ec#X%RjbEq+#IS6tt}F*_9K?|o*lDrJ2j75nh0D0ZjhQwoYQ70LrI%1J|V z068#khFxQQKPsuGUd%cF(MA^x7@xgGzfNPVo* zJhdrixhzRf?hx^K=%8b|sSgu<`E_~}7Vygf4U<0gF%K5>m;<{@A1#LS8}i-?w#?G0 zGlEwKO0Yb)-lhh&#wU|lup+UN-s6ID4Cu4R|FQUV+@yKFOI%LHONBqk#MK+WUm?0Y z`%9P(1wGU|i2g4y6xgl5rUjBF!))menB3+39A3j;&%a;#@EPI4|2v`Oh*NtutJNZ# zsi9m7+yQs1UCiPzUYwpr{LCt*?DJ+7OMG&nbFZSg1o1m2L@?KRY2gqQ(cTb0H{K3q z!|u#X(Z_c82hzfH{L7xTIOgOv*FVk((z7?x<4dEQTEFH=eTzx%j#tdp*sgHA`bCDN zQe9&-<4eh$W}=dc#&&{xJI2Eyu`)ScVPhV8M0_dOd#|UD@uI(}V91c| zh|E{Prb}iA9gEBGN^uPoHaea8(SP4S(pvgRE$u!po33D+oe;A3Kq#)&9e)MfXkk_cb#LbjksTcle@>*B-XefzSpa@1*rxwD%>_w1 z04bK@P#7OEVv z-?|7()b#}In#P=6IoekTiA2{!JY0U9G28E0U4{<_8KSU}2lvAu{-u9bW$A;}LHVvj z??`4~7d;`Ew+z`t^Di@V|E z(o%_8y*j(N6rM88`OpE)s2tyPbTsAvbFvq6NHsgZDEHwE(QR4*oTBJ}9(-(v!u1V6 zo&5I%U_SDA3p;%xlitz$y@rSDnbG()k&9J38~z0krdXzyetP|C*}=Qw6M!#>he{gf zMg=5bUx5M&e|^7E#^+FEyD63X@P+7xV{cZ_G{K7h&m*~;G5(my1TVIP@i4$a6N>HB zN&4CBH`AAoEKj?*#UK~=pEV%AV7F_#C1hcIm70?+L%V(?+YP$SRvU(4_NTmqQ>mYJ z30xy%MHrC3p1Sb*%cm{X;lZ{_ego0lwSOs4Xry-{h~R^~tiztq1?{2?yTL=VJGi%Q zc`cNBc&}GCDOK;2<$v75P3Z?^Z>#wII1(R5#P?M_(?YS46&7K~*4E!L7LNF#mT7vZ zDb6-+;N`_0yZUHYXQVgn4h$wLEpzX-y7jKYdhVp|XsN{Dh~V6SARZyS8n5<^+&xeG zt*N~q?bOwEiWUE?49v{rGrDU%qG><3S}`KtUFZI`W0GV0OU%b=w|ictn`hTHLif+! zTnC5(ZoGRf?DssMj7;r~T_c5YN2`K1f&ZRz4t}fd&C#KY_JMKbYk*boChs6cIOu$6 zV0q*%Zv0GKvsy^~6&RZVGD6qd)25PPFn77jZ?SDh8ykY6~89Hy+yiKd`&grf8-jue|NxJ{9ID_$|{ZWqoDEeshKxJz#xT z&un>Y*8d~ms&p%B>u2lSj>bVRmt3!|fTn^;eL0iw(Q?Tyx3hbCdZi!81kWp!&{&2( z=b;Rv*t#YDa>IsWT_zB3WV zihB)#=3xl{o$pTlBeAq3+Qk;mYDR=ISr7yj@~6K%ireqT3@66Z`g#vlC1j2bA!`1W zb?_JR4nmlRUicDei%F4%*X zkS^YJ*v=dwDTpbb+yxloA#VRJj`7)%gYVUti?CD==LaK~eDfh^`Sf-lFcNcRQxdxJ z!g*6@`AUNY{ul>DCcS;C3LcQb0$?kc^pvxI{(A)%7~skQuOPyRj{$Z@<;jWH@OVwg zo46a{nuIP7!B3>qDskQ@jsJgs7A3 zy|2nHOnm7;R1kq4;7fmpjZPx8`(shWEBR=@ZH&n9r4U%!wG#Ns=`};2#t>|TSKK-n zooxdn^nCTeY`>#Ey@Oz(sM=;0LKQGbl!`pU=rz&bZr^{St)wHBrjqG`&&$Bbv9VgQ zcwhLQ|8s+OlxTJC)44pE5%s=H3R8@<@+Ua# z>m~|LY4GRWSow%lG8M&xNy2tkhe$!n{`8ceBPuo2&WxU~5HiI^Y8Xh%eyj00tT_2% z9-jy*2z%iG;ddcCj&zj`50+Zn8uCmHzW~a7o}3V%3gqb&X+6X!_IzW8S^3Mro?yaA zAr|*jf}V#hkP0ipJPTug;LmS!c%HtI4pQ z8VHOVz}cy3z~v$+YV1QI1rwCAzlwfsyKs7!KrB)XaZ62-`e+$j_$dPA2fO9Whxe!E z@(IR%Y6X3UlHUqpWTjFS_DY+`o>8y(PyIB812^BTuIlpp_=?X8ffjPGG@VVmkOx2q zf1C~7YRunuS9+qY-guZrx?bMEfr6AAXyj4mRF`IwL3^NNSm$78LZYDwg=j>rV z8w9oZZ<2GZ)}qb@MZ@f^1hWfFTHmn#IUEczOEHshlO;!TLKeoEO%ErIWPbU_q==;p zk$vhEWH5ezg5TF{;JyzpbSxXW4+Hd87I6TFe2uTO1PchaW&`!yiPck1nJFf8w4h9`|* zg^%^@wd19b64o1vGyQo%0VNEaicq>Q;7ch-Z#x%kwHYKLsoq znN)68+#g)AW8FJGgdoP?!cu=bX0(jkp+f%rEbZ7AWM3BcD~w2X?01YJf_6y=7WeRX z#6=m6+l_85$062#2<&?%)JJH8Lv=AqH5h_qYzuSZz#4jMn3EsgXYg4~2}u z7B=US{lsJrT#ZZ^VUhjsTE6_ae5}991WukItqo#O&)>B@zl$#sN9%k)`Vw+tbYG`bjIaS@}pUY5Z^#IPs6(q0N`Zb9oxds(d*lFh%m0H84kbz`m0*RIh&O^54Y~{>?=uB6`%cy%>UiVBO3W z82_PX^}Pb)(d;ue4OQYRqwikS>P`Vn%)e_n{;NO@IV~|+Dgz7He&2cn(_YUZa<+c4 z`uYg|IwC?(OYO#pmEeCa_dmiLfNZF6eNFVT!REchUhXb1!(=xICUU;3+gC*sB)wLF z*($4^ir@fMM?}!?w(BtT(j7C(=&>GyX(NH@RL;DzuI1!>@?BjLUiv_W>W@{GadfJf zdmWyCr3dHr->#fd-{{4KO*MlX_;sCGL)KDorsBA-^Xa|7!v~htIOpN?;N5DsHq38a z*nHa~)YWibd8=O^EXjt_-U$D(3B-*;J`Xp|UlWyXfBPc#7#nqeDG+1>Tg!e-@x3=X zXd#~*(*E@AkI4xEyNWG5N85ksM&9$ok4O7bF!G;Et#DrA2S_&UTZK=@7;^vk3aAtV zB_aju60y6RLmuQAo&JiRho2R#ZH0|{aUQuA`s}S4r*rT)6w1z>a__*Q(OTm?{Ujfm z(8RC5lxT&y+ifZpCp)UhVX^%ie(AM~^CIJ8p~u&hZ~V_sngpV5YECc8btv8T-tfl? zuZo8$uMMFkOAIpC8GzWn)cv7y{!ekzX6wA=?sreFd3gCJUf-S_3#{m%=`i9Rcf6Pi z{#_q+b%pppm$qX71S#3`yLS4luj=!@z2|r^x!DNyqWi>zji%kqpFUX4{b|Odw-F5& z6PR2CZ*a`A>7Fx~KhF#+x^QJ^rg%i?_f1sHc#l*4qE)yO0#A$*$wfjHvijEXf)EW-$GK-ee4(V9O!Zt#$hE>^CS{J`Lu) z3VCII*5nKsEF=H>#q4du1^azxoyS$2iK??MpL>qWPfuJl6c3K@G*@s{LC-K>uEe6{ zBlRsX6Y1d21ljndKY7Le@p(S|yV z%W=vPZ!-ROogD;DKYC^CHaB`2EYDZg(}cj3Yu<~fU1*ydv|_`@QPsG$`KQ%6CIc7Y zF&vCch>YmJ8gB%6`yQmWvIjL{y#e`jSr_lM2D5`o;eY^i%YnIg(s zn1eQSv90RTo2WhnX1V>%*gMtU?yhqq@%J^@Qd`GwSTu|6Y3Ui}_hESBHnGjIg=Miqw1Q z6D$<+Kc=o^|5F}Oi+jT^c#H^*FEslRt6Mm zI@CgCM(pB-H=RGo^E4@$lJ!6suam1q4&ppzQEyp&X`WI(EEUt2-rp3M0CoyLstM8M zauwB`aQPe^O_YcNz0ZShkKe4ElziwSpfwS~A z_V!*lc-`BwWGp4#|Ig#D$~4BgOTob|qp``*Yu&WsxPLAdhI?j;#IXZ)%h-l(@bT|j z2chyW^b()d0OaoEoPk|QG86MzS=gE)IW?b5SH*ZbT=G?Aws$`^dgy0yiS_q#r7Q;h z5JjK|l zU+)e&+|=qO5yvz=Czmir0JkwK6@R)lWlTYC&S_wZBUuqaa}7=$Vc6tN+s>BS;u)Xt*V>U1> zc(u1;pgem3;s0ZJC_y2_$(d*hb1`O{K*57iJlh^@r1Y$z*_X4yD5gX$-n+n;l=r=} z|L5cZ;&`24a%ETZ4biJtk2-37?JYK}cT~t=j^0IwLXPKa_@i+TYHzkM(Cu0bJK^C- zo!hRx`vl-SPYr~W#c|?gm5MM7{w{+#BW&@z)7xxXTtHM{#jUjOT5ekSjEXNYp{6B! zu>wbXqVVl#EP-RU;)lz->{?1%bv|hY{{@X0S&5 zC}ckWzsvUtz%7ce()(g%#ox8H68N^_U=+D~jSTjZ^a=W4!OLR|C11^*s7}{n&CXAC zX7LZZc`^;X>L!=s*iPE9VGwP-btifStpyK^hDG%b^_bdX?d)n@NO8o>MTeTmFtuQP z>W(Wu_1*wL;nPp;AzR(;>la@}Bx2sr#^vNcyTT72Q%}l5zs+Zto%S-nf|~!W5I$gv zGy5pw&#yaZCAp51Ti)6yWf;qDnpHh=a!zGrmp<_IqH{O&UF4xNw zMR%hv*y*O6?jM5)fiO~TNbhv2-oZA;k?49_W0k+|U$3dc9@M+mT`rKb z;8)^TN(QsLKhyRTc1Bp21g|CaVml)qFYGHQ^*cEN@++df4nyL&O2f6WwYDB{0kh(L zmhL?^`dPut>YE>7I%K_a6L7LN8`xEfj!75P^_Xq|dOI<~J1#_f9)^J;JJ{lJbV+&g zq_ojdk0A@G$sIhHbIYEX%G_DM>+k#u+NDu}{!y2B$+n74--I0vbo9z{p5yBBs^QVT zXZRPJ={^2E(tJf$AXSvOX?84K$WP6}jtGx>Mz|I|ubMf^<+Lk{!4;G{q$*3R`MG_N zh`wBq^&+>eEyTx9e9NG6m4s_At2Rg;LlXZz%ENI~&LOFi<1nxr)cu}V1PV0`JwI%Z#^~=DtT{pEFM^a%&C33xYk#tbf6O?xAGJ2LzA_j|{I*t=#Ls3(m34-Td)~ z?NCeCDf0LYrM9iv{&}f!*2Qr8rodJucDQm1`x0*`+~rBi{KGmDJgow+8hLHi*~QD0 z4RdGrPp=1ih-@ZWxJB>4kV$wZb81qAy;*iyT9Pgu8(sUmo+xE%%j8OH&oyvUeCIwj zt;ICUzeN72si{c>#q824g|;2O`y@%xzu_TF$@;l$SHYW3GZ`ui6MTS!=q(v1=nzSX z!#jV)3=pdggti%<8S(R%{^Q1Xv2?oZIarD>dUPjYxCyy9cCA+*Z@P30o>TIRNSPH; zSo*w?%Fr-5nz-w~Az|}Z$o#t*aAhK5PS@%PrdqR9XTG_-BDP z7ca{;8i=@*r=_mKd9`&CmGZ#*-1eo{iJB*j6)-EG9UKq~6sj-|^yWE=&zYO_K6E9b z(L^N4Y97SOU{N}=uT4Az7OP&hNrXK6M)#v2uP|o7IC5e#w2p}H1^8|gx2#ig9~u9C zcFDZOY_|GixM|AoE26s%rKGUKP`HkR+*+IYQRAAlw5^t?T!ec59pvwhGbASk26Xhn zcT$RF^1YvRp**R7_)WK7?ESsiCdDHG;yEykA`_gdbf7i1Q$YDWjbXegLR{24M()f{1_B8^5*sx;|N@O?7V^G1;OTBXqd6 zZQq%SW&QG1O`UmvDZc^D@(;xkB8lGG)Shi6j+A@Nu|}ul*k={rsVyV2*tJ5}i8fQx z8S`|z_eNwuU%k*sI5>2P<}LxD+<`URm?l_Gyc)xDtcXOM(Er#gPt=gUce-4D;|uMz z`xh*ZkG86%>XrAp*kA(?et)^kUH{&K{#Zl5$&XJzmTTJXFF#-F%5R_K_$7Vn;9>AS zoTnU_Q!@jR(phOen_u|#->X`=%Bg)LEg84pPPMTqi-@+*d~VyrPshV~mEuQpT{m-{ zEb3}f&*|L>P)qWTz`QhX48EXgK2_%}9^_wrB(hl+1JlY&JMcA=L7O+YQQvYa)xLe_ zzG5P4qJbXAlpCE=y|nTvjf3RI1%b?|m6zwb@@F1>H`D%-<-xl7NJ3`z{P05Tyy|}L z$cpB*V4Bj)$$fKkZ|f%8rwxMR?TXyEu8*HUCV-)-DqmP_=RBZMQtmmYPXiyrE}fp6?|aiPGDOttzv;XsF_lAM5Gr0( zF2~wW|}BANGFouE%DZA)9i!W;Aua(KoNR27tQrpZ~f>l$g%tAlvdYzP~DmZ zOOj#>?cwgTgWG?wNBn^A%Bqs=ZY1rRO02y!Eu4B5BYPizWmbss(Mg$Dd4=NthFSe$ z>M&EVJv~@gU6vG)n>;=~DpbgJ8P2;BKH$FjN<1d4?lM-Q5;sS&}>p!&-6Bw_{_1nn?agFJv!X8(ym??7eWHVs+mL5rb@yIH{749RC(Bb zr_|hP zPRjf`^ETxZeXs37lKe$I@}!Pa(uHnB3?6U}gUCe@kFeZ=y$jExK*1eM_Qv^WcT8l^ zeY1-FXA{{*trJ*2SHo;D-{lFTy1t)zSReczdf~3O#&Ax{=kR9YRIu;sitv%+wVi(E zMo4F(`G#AUysJQ9r1FB+myasO{zN11=FHT@5a?O-NTz^SLl*8zu)1sg`ORgUTgOTo$yNQs zEY=F7NrFG9)}9`2PSuTPU0PYO&UP409DP?jlGb;ZS?uJ=BGDJ%BGt&ZKN9Km3orWd zcZ;8ANb1Rd<}vR-n-znDR`fE>{ zD2$9o(^GO%!y?JY0nDNUqIhMGXs)a(Bd^2iYgE^gx!_5CH(zZx2UmXBTySz~RkGQL z8i3P0-OW4b6%~=e-kI$oIc0bS(2un)j9y#5E+pofURHPOx@?o)a7scZN37=PP-&h3 z6~a;uCKx|ZzVzzH;M+q+DysE|SBLYXL|4{G$}m%RyQoZ?VB!gPjZdZKNT`TfR^3`! z9n<^Y55*67XD#2MO}dgWIAq_aH8nJt*o%!K+er9)b?E{ZMcEIZM_JRQ+QOY>H_+O` zc^`d+5CyB0-7F_IvOtA4LbFr66|EMYy;B|&X_qh9YZ*NJ0aJ>*`s~C@4D(ULF*dtg z{dPB1rY~UkH#G*Gj?>R~56O1n#|PD_h0%ACZN5c8FndIQx$OkA&3yGOp-W;xoO#oY z*UFZ|@2(wuZx1HOhiVJ{8&&!vvI9icr}TD|(iI+N9@#Y)^aPd{U-zIJzSY#2yHY3I z*`M>lx-}c-*fsp1y0|3ogI3&hVvuw6J@f-hp&@3oCFEZ)&3|qaQU|9(+o zV+qCVvu(^J9?IU*P0GB=|2;Aw0A?@z#e4A_MV-^ah`f{V)xk&0{>=|_X~Lxp#p!*8 z_Y2<3ZJbJ1iXLY=+6Q0$E<-+Y%oPus#16yOEP7NqS2g*TdQ{~yIQa+AJNr{-KIm;O z0p+2*uJ6Io=Z|Zty*K^%%xMizg|6*okg>Z>U#!jK`m&zRMhpH((Qz!f;<$`))rq+x z7QyBdFofXk9QdkSGcB_B7IWT_1D)(+Q^Cy5TT&z)XKp^q$Zu&BE4rqWS<#&A<9FBL z7!&)C*R??ayzS)jVuQCGX=EZ_A06d*aD`Q5Fud<5SJey&2PC2>vh}0SS99K4S}O8+ z5na7K1{9^JbK0=z&*aa(y4aFN#;0<>6--d1YH8Ln*?N$2HZ!fh&J@nnI~b9jx$IOn z_#&g_2?Fisvi#%fa@Pk zm09y}_Z5A-6Lrueb7q6@0m{9(=Re353Lr3m(K#DqExMk+n5DB2Gr zw)m3!i7_?`E8l#0voG3tv1%D7OwaFE2i0%^X6D*J-yj`Nv4cm*NFjA2 z0MGzrXf6Y-_sUJ2&Q*BXCqXA-51qqxPJ9K)Iv$OUdY->McTW6zU()hALO!Ri^TOw; z>YpR>XBNZTMK8nL1-E~C1g{h8WbAF`G z?k&Bqw%wUblz=RtNK|kV7rw_&M=_!Uz*c;cq7}Dj>T2#fO6?x6nHXM^|M}RhCV=os zdS&QOoG!;J7Eq1u-Q?Q0Fi9j z*wj#nNN8?4q&Uo{|D-1Oj`wq2c)wXMhCnCgzIfQ+E7HtiM?4tIL8Y~T*DxcjDojh0 zHD1xD-J-SiYA2Jo& zz!L>Y6=@hDV(p$*`kf4!GZl{#a-FuK`l#LNhGgvnew;b;`pI#H&R=_GbPsNR$-Ahh ztTQ*v!p|+6H&-J31C|d-&;#FX?A8$PAdRqyn@@T8R(lyyEQnj>TZN8K8TXQ95ajWt z@!LmaGoNjQjBV)zhlV+%p0;&Yh<7~{+uo42c2yVNH$IvtCpi)1d6$H0_m?)j?brXZ zj+BElIL)oT)!clis<4gd1!-3BI5qhUZaUgh>3a6l-skyl0`M`TMP2uAzK^KNfB4(i zP9`8-TO)`o+yBFo>(`MJYoGanRR8n_K0 zK5x-spQ|6I(pv#5codIwd8c66m>Fan?PZKg%8*bJEQf$qu4=fzw5>rux4#bmmUy>U znvQq92^+O*euw&hvhY_R1>nVGZyE6OFY_;HM8(92Cc>i1J>8Y=X)oU(W22Nk2mgH9 z_5rZLIFw`d6{54F?%Va@35FcQ>v*tf@>bgs7v$MVos`z>(LX&r;uX-2Ih&fFe_p@b z5x8Tb#O+aZJM{3e4dY)_0;ASO)z{5}{s+T=yn@}z7;I=Y&}DCTCB`8IZyfRZIVD8eNGloX9|>8cA};Ifg%+J*hlz~T!+t|UW*Ftn9@S53 zLW@HZ@egFD9tQwp!hjAcE5XCDnzv@E8%G2BOQ4(nMWkf(Q|(@X;i}&surM?WLe_IP zJv-BOU8d;UtJ!&MRQJa{krGdRPUrc&%KruLOk7ZQm|yzzDmSPkMxJJQA82na!(#hN z?PoOt);wl=$=y&3ffF${qz6Ja-Tj+$cVC0%;Lnr-dU%qp_9%tQ?y?5GdqtZ9)Pe1v z*An{6i$qy=>%~`z<>9iU0I}*?QJpyLU|=K&mbQ4w_1(Ol?kzu5=QC+)&CiTjF zlL>$3Oi~z;g#LPQDi+Dn$bA0ZDuHzEOc`E#KFToi|F!qn( zs%$3KnwHjDR71hyi|;i5YW?Fc`;gy*|YsN+~2v?WQUMmzG zyI`h>$_c>l7CgN&5L#=^!*J(kak$*LA^LmQD3p-b8YF0>4&U0GkHJPhXZ;bIeBSqu z2&qXqD#XB4`&_v|?o-~_@|YiBg0)=z`HR#kS=RT|ug5Aedj0{Fkk&&VSWuqRnv2l~ zR&?mj_akBYc`{i0Y}#o4CO6X>JOp;M=RkToq4Q1_K0R(&yN6bby}Bf8Dq@f>!UDF> zLC9V0Vt>^woKH8_vHlT3})$*PS84cS%AgwjDgzA9Y4O)|EI@a*U19 zMP3aSP}B4OOw*Mx6#uV8Q*F(uW*!XIj!-xdiN#htBT0DPy)m=^>U6A&_W!!N&VZ(} zC43W!kD>wrL`5Jh5m0Fol%haZ0Vz_&AcznIqz46oMT|*U6#+q%B0Vb7dkMW{m%g+W z1f&`igLIbA3CX*>A8(2Il|T2MGjqN(Gk4B6XWnpiSrSHg?c%|PBjiW6eu@wppq_Vt z%ZjG;{==HHfc8G4zXw0(9HM0b{g+LxVeL`2fvb|N5OAcGNzZJ9{yGO`tot*jIMW!2 z=oaYR&+NH(ME^euGoQ7URwbtgD7b>_Vl=)mY770#7Dwk&SI>oCU(jMY!3DZeMKcunX;(FA6K3kStDgHb=#4j#880CA^4ZJ>apVH7&e+X)1XTrQ{b1XHv@DlCeckO(T1bIu= zJAjc{0Tba<5;Y#5ZDJU-|1_Q~uUz$cE477{)MQ26#ruAWjr?@qX|u)J8W%iyc>PuV z+=Yg>-n%blm!^NVKpQZ53x{(tyZG*%SD9*;^?^g*Za03T7r}H3g)$z74tIl;;(yl_ z{HMe#H*?s4R&)DS^`_+FYBX@nw8bm0)^Eo<{)e%y;T*T#9wUGM1Zg7R{_7UlFisn( znY~c-WQwA00KD+kKdS0OKp+Nduf5t$7j_cmc!r3UfyK^SOU>OjyHF5>h;jU_-Wv`$ zrAWCZQqhL2#Jh=9$(I(fP$+Ij?%R3Ms4} zn<&kgocIS5=h+qm7<_%PXZH}QHa#ettR>`q^-xYL%Z-$x+5K)(5SdcB=TKj(Uz+B3 zJVHb^Lj5Xzmd=Gf_F@l+Nk*NO}fEUQ|q+`RPtG)Hs_l2#gtTLbKpXx|?4l-=sMt2Sl@JHH4r}FS9gPiTc5~Vy>1%FbhbiLfT)Bv1;j#ngK&O;Eyvov= zD`Y?I+jgJ~o{|-r{E6{O6@U!jY*uD&-#YPF*%>8iCxqo9dd6m9%I~#RNOB>~ePpq_Kpn9o$6K)W)ZQI8Q}hk-_90n}*~}8FxvUMT0=rQeIPKZ7b~k$^QxI z$PqXOi6-^m9;#bwfb+;>;%h#REqs-iZ0F=HwtGPQ$b?TSLukF+hv!7ui5dehfc6)) z*F15vDkcQSFC)DyYWxojN{y;_ocHNnj;%t9<&`_N;clT;4p!`5%s6bZl?_D#`ri$A zdtlurJvu~@;GywiThARC9G^kGhQfaQgT+Lj{76J*_y4?>bwoL;6sQDVc*P8AtzE2` zxS=G{gCsd9_d2YcGpGkUyx%Gvjv=OSLR z`g4aYhXl^cN`plL9oZS12{x5Jeyn$o9xR<#W9EgoRCv5%TpvRYaQdxpaOD`L7E<%K zE1iR9$;YhqPNt|p;K1p0aYDTnlaYh+DyyaZbS;?w4 zonI-3j>2gvZMrUQ>_Hj?Isl3Wgmb%#Uv;03?0a109`ynfO)HvD$|7Dg@E zkxh?sk$5bK4bf;!$pMdTStNzA`;4gVry>!}rP^2--baJ3w-I~S|NcJ=TTUlh_U?V} z2X|tWMg~3={~keLr|M!L%U?9a;3YV(LyJ4t=XUgl3F#DhiP9K;?iW(jGk_CNB1V!w ziWMQsYga!wOez6ezhdR3*2ze$;%Z=orP__ySk^MDl`ma(fu8=7%K+H?;T$P4+u%Rs z;DHm|ObN2Tgt1wdrh!_b1ryPWywO1WxSv_CAoe)A;Q$XebA)*iW4#FM#DjA5GD% zA)-s6W6-^WiMMiXHD-Zka0KKYoLf?`T?#~`#)HzCGf-K+Xh7WtDXJ4F z=Q3WXOBn57{^n52#ZTyvIx$@*(@;~Hbj>Yl z)>yX9dv;02p1nqdrSZKczJ`M^u=G0l1dZVaoyJ*H=~OgA0|FK|P1FBKkIgnkRd4hv z7_+nMs+gkm1{RM0nW2FM_z*GF^qKXQoL&2LM(9*q52M#pC;1C*hA;o-yo$oCZ;U{~ z+(1My+SpEf@Mej!zx4DJw?pz%J&7eO;Wp^ zsqC@klp;-ZaT=&%T2BAu5;i61z_vXlena*^Y(qP<#MVm&Ud|lPn~zH4LI;o?9)?og z_B=tqqa@Tu5e=n|%HB-0snQKdW`{MH*^p{M&XrdCE^|WL<#Biv7m?f(-+Kp7FS-z` zyOSU2ev9l`8b2MLU3Sg)?cc8B?X&j`0q3=u3_tD{XV6frl|;ZV(c|FzFZn<2ZpOED ze;9q~ks(phg(^~KhF%r3t_VJ35Yll1LI>KDuFup*b=7;qRvL_gU5G6X5=zcj#(iEpW17)qy18$uhCVPg<(}2gy$WiW zs04*-$b)vGJmpcwht6wB^=(WVWz=rI^0~Mh56r5wr`uY>$QV!!p(^hUaPXhi-cXi1|=yrNBH2aYUjrv5z750gs98Xk9w_l5( zvu}`5I?lU>!}L2k`2j_zt7a2h^}mnx_8x%rg21GrvO>^b1(iDmFb@p!2buR%-6IOm z6D(bmbSfzHfRIG`=JBp`0x!Rgx*UTnSHPA8+RuX^o*Frx)ySQK0EH1!ZhbsAmhQuH zV4S+XqGvoKTJBvh7aw$E<<6^A_MehTiWgM^6k^d-u{~(D1|h=LVVUREGzi$#>7L0W zL0dwRu+)WxIITYGjCpLv=aMreANr8Ixn2wpeYjQ9A@7VnODxOnYFG0U$LlYH;);h| z?I~ONf8K4!u!GCW9kEpbpZ~3#q?tg#!WA8XwQ!8q`|_YTdz5fvo9?LRdZPDTG9xzw z%shIr$jilBgqEhvE-AkfANw^a)bTHl44u%>`PbCR)JW@qhh2v$GYW_6R2_6_LI7N*P(lK2*f9S0oP7vG*Rw z;dei$-{F{J*wy7jBi z|Q&LX54V_=0Lw&AuqR5Z|E{&;l1-YXJ*DaO4$8jjf{xk zqvJ`3Y9a^{BHA`ouVRnPdkZK#of-X7J+=-)QHpE0^UdOzdOw&AMYqbgtIpl!pa zWafTbxv}1~5bEheQPDk?nuL)XSvSQtf6iD)ZazUe`iUsol)j5EupMjq0~loPHeZn; zN3vLvDMzzdktN4wgG;~6kbIjhw`w$9*AN~dg_u+?z6 z$`YLo_{voEHob0!?oN_!LC08NAZN&jXR0Q5*G4XERJkoWmK2SrbL#{rrc=W7WcPmg z?8TmJ`#1pk)7E&bcQk~0)8MU^lh9f?Y3W;J;LX!uLC#>grA6r#DgKGwEeY0;qvY&z z%7fjfg^m*m*LCKE6u?T5cfYN904>V3_|dygX`bbf59qKGuR9OgwpW^~NrLA>7q$)kd;8D5wYn<9ijCwcoR76+ znQ0fdSpb~Vyl)3_MWJ>;cz zEkr~6#^?I(^!L5|WEFu#@Z)t`5xQ5M3+@NndOsDx+i$_=qt5$B7n?c4i_6GiR8^}b zkr*yA*1sP*B|12K?pN+mP=H5>vO(KJmSdAU54qU;2Kt7)r*hm6ge{-c>`;)yk2i99 z_gMns1P{Ah>b-#kaPCq3#uf)*;&|@t3Npfrb4JK*v8>DD<}O!>eA0X)&(WseC4ow^ zz+VT#4w-K{0mU$^ExzQb;P~1CK8Gnf@Nd45fB!ChFhrgdVuf*u>PAtetWe3oOP(k{ znsFJ@u3FX4b4eegRtv>itS1yS6VFcQW#t=j)2; z8suloj#=R+Q;ffF${h(u_IoHWbB#FbcZ8{5FA8#nNxGHb6|uw`2Z&&ft1RL)tmNrA zB)tqCApGq}`volOsV+>@+1oShH@Tov?C~#QJ~TI0#@I=eVIs-O;xoQ|vYO3yU1EXt z1?qElV{3TV?=f8xtLuqgOmj?uKi_;}r{CXWQ7>^p_|L(SLY79__r+y+`cZ-x?TP>r zN5e`JExngaI0&k%@DrJm(+n1h_2DaWitRNseTDwR@&@p@kX~p&+7GYN>)5x^NrTq~ z1;Z+jpTLKX;1cuKjkRkl!&H#bdunEMRv#0D0kN^$uYVBhaq$X|z*=l;%HN_OJ9r`U zY`eMsRm=LI3!4c*H+Xm}f!0EF zW`H=WtSOzvmfbscP{Hb9M-ad zhsivC7gt)2uKKb=G3h_~fMyuUzl9IJnWxgyexw|;rvlCRspM&pmj`VU7&&M+GSFjP zzZV6ylbT@-<)08{FI4)Et_HP4R{VWXw-a*-UV7YO(myHIV-xp9TN?iT>+9Jy?8wm2 z-jCD85y(Jo!fHm{hBW*?JsU@nIM%Yn@=pT3zJ|FwF&796Xx1AVTGQ!FU=o9)DUlE1 z6M*EinfOaTrbVyj!+J0`8)_(j0FOgW1t$C=1+Su4U$fhac5F{QSmI)W$EW%$D>(8c z9t@7)fF z5(3)MdVT>{pqe+KHVnonaqSHoh49=B5 zChYsxE3by4aXmG^Yl@u*?i9b~2$mpq*4J!=mwO>ImsH_hhZOf5yzG>@AphIUT%13! zSu={0EFHUO0s)Bzj|X^}J#+@}H@l1R6~K*^2S&p$K%8yMy8Qz~15GVnEF3}Y6_j(nE(VEbx;lGaJ5h3FRFE zYKK<2#oxD@+=uTOo#gyuvd))M5oDGB@rYND=X3Ej^|IqOSm&YrYJQv!y<$dt>H)Iv zkcA!|qrOsk_xEa9goc_;%#OSOJap{~`=ottZlo=2%WMVCRv(ALE(|(FyAmDu6BE0= z(UE=s+3?9nco5NC>Eq6LIzYy4en@sHNCO_bZSFt!(m!^a3munodHCcFJOaibW+ zE{yJ;nE!impvSi<^L_NOR#LUx@F5HAE1)UI-?C17W=%bBdsmH4*a*BHza#x|g?Twa zwf8CVxQ#GWqy8JisdmV+wfK&EDTpA0i24Sk@VnsSF-F-mCwwG90$jOPa*_UJX6(|X zKMz?5luS7TPZ7I)n!%uoAn4{J-|jzK6___O5kMX*69~I)uUv(RDbB5F(8)g?YH&h$ z56a9Z4efaOJN?F3fbT$sn}7C>nH*tyQeIf$=+L;)ErFl)0;iRXYVJ}xn zSLc>u;;is==iq70e+{aoN0Uy=-YDxi6r_WP5dD1u4)t1*{lQ7hr&+tTdSN#yS{6Pfk3jG4gl8Omtjx(^uClDqf@%ZEqVQcGLd6!LM%m%bz7y9y_AZk_eYWdv>vbPV}VIeRK3KDiO#A0c;Ln_ZK z$%_(}I#!Y1%DueJ6gp6R(o7iH&uMHE<}ApR5Zz(=g8xpC^QqGO9`dMN&E69YpF1au zZe=?xw1mk)UK@U+Es@!97<>Hk-`w8WlCY#-!Rc{hPw}CI!@Ndq7n=ShIB>cGHym`E z@FMXGuX%Fb`BJ{f%3~73d(>p6CKtqRo|fhRj6S3y9L()&{Q|P9r_&Y)eiaJu3DI!3 z^&^;XC`V*G31JAj^}=iUCf)YSHCw|I!qSjya85x*n`s}xBL36rsZ+r0MiytnXC?1Lcro=} z{q9GK!`3D1VXA-U!qs0QyBLh}4f?c0LZG-=wbCK7E>kOm;VHhEu(oTo?d+?Fl1$qf zdocX_%g;yp{3b zPG3Fe&pR&(hu(a?^5u#3ou&(V)_CaOmq=Eof(-i%uMr$G0=-d9(OL|fpa1nZBaQCq ze@0#=g?(c&>04sJX^zVMGjZd&RRL2cM}?UM)?$Y8LIi@x@73>Toc+g9f+d3_`UQ>) zf&ce^1GfOK`y>{;k2bf^DMR2I^GA z@=w;BbJJ2~`v}bVq9HBmpGhFZd~|JBp*rB-UTTtf=89KHPTF=~5EhxT`Q4o{aK7J( zg^cjqSxJM~4eEh$D7xc~; z{bzw?pbeWtu(A8kH@vnzkTO+p&`3fcwz<19MZSt4pa0{xmwxpBdQM>N|9I}IlltH1 z8h5BnLEwCwK%uJ$lT5+?-8)RIsUfrde;=*PYIPf5a{iyc?^97${daRb^GGU!!GNj< zzq+55BCHsQ2>vHjESdk-og(F)Cp_6F`v08L%y&iS!zlmEtM(yDR^j`nL)*7& zvo^z%>2CBMTLdP`?6LF;`c%?Wu&k6GuLT|KEi~a0P9lyacAARYGTXA-a@+FTKDK>o zbHwePfez23e(Ystz$oB8(%Rm^^tK!@b6LtynKHdA`ftWWLL{mu!95{trkvGnrO7hR_VJxElx3ul{L7U|HVAUQeTNh>kG0`Ds&y^Jq*-Ny(iA|)z44Dk1Gz> z`hpUUrFSNaPtN0Ac6RYclf#yMmi?9kmV=fe)NpWxcim*x+pQ_{{y;@CyKt6XV2vTGEs9^1-)BcjDz*wGW-BG?w&y_uyo^{%0{npi({yR-Np zI;>MV?^C|=)#Ssj_VNfRhlidD3+W%{*M2PFm=?GjBifhf=%}9hcO}r*Dy~HPHYr{l zWWaiPRHZgOzQOW5ipvGRRO0vxw?)=~qH)0;fhdU<=t6UuN3K^-vYk$gH&ZR!T0k_L ztspHr&gk+*W_>oa_tozD-_~&^`6`PZE=)U|G$~P0p|hQoX$oc!F;4IN7crb$5l4|( zahp4Pt!|rJ#-n?t`K2`l`|tdVe2bfR4^BbN_j14ni6=mmlvK-YOzZe2&a*zodN1mv zf$rETE6JvKuvoPl~)F78_!z4K(xy?ZksjqD`8+OW`Bgj3t+zJ)59spvR- z+gkFgU0Roj7{ku%T^(DDiJ}+mZmztwr$?=3FpZUI9|5J$()AF z`CyaLl)o0{u#mjQi{(Xfb;RQf^FIXn7eAWTUdk)_)XCSOG@kU8wRA{q_fXBhVl;mh zJ8C>yNHMUY5v`aqjjf7%Xmhg1Q^ZFFkwKR{AjD)}|Ay_{!P$cWGICP}wocQ?gq6^N znZd2ofZYyCKRh>XGTrCEKJ4GYc{tQA)|pmZNehf}pK39wpnTC&=i{ju+huU&$HXe2 z>>kiYgS@p!I4n?-G&5x88KcZkDz2?G{wcBZ);q+05sS_-`ffdg?C_S4LmQ#K$pzgl zl4-iu#mD|pXL_`r37VpU_vlc0t#~ZP>a6cTnv%WaDh|UuEv4NPZ(}91*=f4^@};Q= zMNYBhZMU%B*nvpvS*Bfmy?Y(8*Kir+5TYJdrI=YsGgh;DX+t@g1Q$KM5q{+3G19JG z8)ma-*&kxi@6v7WerFpPli*`YW8Rv1@K`VAxqIF{FGkJ1%e&l58FUZ=2irs%rGoQI z_1LKVF*Y1i`+@(vYH~Yoe zuj*+dxGSqHg00eh=s0r*N~8uS)J)U=(9MM2f61sYKh~^Km$lG41s2Wi9V(r6)n?`1 zCnof!wt-f2)oKQg?^E$T`oodd?ZNNMHoL|jEM?q<5F+qaa`N+@?|$MQ1v1rudx$iy z(R)hk`?+xG=2|q(G}i9PNEMC8RiHPzZik)EegCFOmxD0h@bbj&91TQW18=2GnEzIb zen*ZqKHW<4`C>ZH%!1*4o5e#RutI`TXWgpIg9igoCIGPFTjCfbZ9?nxF2;856?!mm zee^VRiV~>yl;DCtvLaqFG3qN5YGC8wm4YhTF}fuEPJRi^X6U@Fg6)S(ah@Gi61-L? z8};Q+m9vwaHu>0=z{g=re-xoM)rwkKsc03lEb@?O1V`(Q&J#1^<1)Je_D-OVx$pf}G=WXNNn9zef%XL>hQ%Xg*_o#F_ z$djhR=j#_y*%PB;+`vA<{&dvunl6AtDgsRa;-v`on&4}#nA>n*nmdvd^+<1Q7BEY>4WHDrFD_y6z3$fNc%LNUl!Y~DN(l&z>x;rW)z&k+_qL856du2f zJ?KD`w3Ot`gixQTn4Nq9NSd0GW|;9|p|KYeT8KjYH!2VSLR7$DF{({Eq*d_^ETfNp z?zLXb_p`X9jc(DG=1L7DOA%2-Qan1w(8Q@$YrRx1^5fZ_xX-K z_W-Ib{|M{$5&2jZV22l$Z6@6mi1`nbn69j=0cg^=-h^ijR08xIwLnc{y+jJSbs7Hb zwB+Pn+(7Zh<}R8~WKr+Yu>I~6&X8Mdp6>%LCOzO?%RtBN_(#vo%tQ^BN&~zc@CN}E z@X8DRzQl!#wC&J(qN_dmtFwM4etyADL#C@@u zV{oB}XI5%OY(w+q_BJJX#V_(_T4!XwN1F`@*a}?gc;`gE*|DiIp##3441Xp&$7=B9 zU8~(sc9PF;r~^6a4%QB#-cu?i+PUB8cC1!-FtA#C@I?641y6`f1+bs&+T*U1ozVc0 z@g;yzV#~Z|+9jk$+V6bd$YYt8rof!VfU=g=!tg1jL85CAuvXU~zF${(%}j5^A5D9~ z@krJarEYT8pa|L>5Rw!YE=7SPy!?sQI}HjDW}YX3WSD_G@0T4gSajp^yjR84bsU<` zQI>~FvSKrGDjcMwWNpHbpQ~?J{Y~Ks|44Eh0x>5dBkAfTiwU-$7A5|P65_ab2h^>p z)WU~8jZ}F#4i7-l4I3Jikdoc=4v0|`kozevfc><8d;iQP@-K+;3Z3SyS=<%cYwjrz zjY-Kwr;f72ZuvJxb+gMjA4P&_$^sv;mRb?@aSC6S57ZAlR~*~1=v-lP)uHKv!Vl?* zsL+8`-o=Nio^D5jxN;AN2E!f9t|v9LE&_IAkUgm3sk>{Uyw;wV(UF_mFvz!lkBl`Y zDnCAu{C#0O8_Prt!0x+gBao$G(3BTo^p~kut$)g&+GaoZLp?aFF74BnN^QX}w$nJP z{;il)dnWGk!{sbWh!$|z{GzP1;3JUsNA1a>qmH7z=-1DU1&VWpP*)@x>)wwX?RnOU zJhjD*fky0KPm%)k4;cS+B^yts`wnTvcv_| zki%~zmh_+;je?J^=y70V?+VMvT&FT5ilCkj?RSWY$lu#Nuj;2);rKh@+tW2j=q=!| z&gsIR zdF9b)pMtM4Q;W{lO-C_)Yw0&__@rF9zcXw!^)HfhG`Fnd$bYx)}M1`@SXp)!H`TdcX z!kfPXgVOB2iYsobZe>N7ILDFzWN8yL#SZxILwxA^iA}XWay-hRnm4a7&+K(lk0#kO zS0yE8HFt-mkhYPIEFHtm%}teEO+bwTAn7Iy1{VEFzXsAf)xc-cYe_T;#+TD}O-Fv& zDh*1k-X}owO#&phGeL~j%)O943yLwZCZNjK{gHHFP{Il)nMAEngiUZ7y*PN)s<-T% zuaj=9M#^`Xsd|8_E3bgh>6qr<*c?4jDEzd5#5-z`u?EKE4--iS<=q=@h+^**G#6!p zeguO}N7^5bKNxM0*PR}`YLJ#jt-yRCKwcK)s}s*924g*Fqeu|_K(3oDeFC4<7-lsB zqx<@`vOyMMW~2C`Leio0A@Dea(n#qfM6CkObzLI=)T{P73_3cn)bO{oY*C*k8EfQ) zwf4IUt4z@#RT{-P=kGX3LZ{9G$v=8UN2}c4W=5w1Eadk2b18)>A%G4+AOj=ve62HS zZhsyZc0Hy=$9hBiq+o~pBqn6ezz5gT8}jem56Djx$pPg2pv452gUklRf!4UOh1shP zI4LUV_#N0}(*^*ECHICxa$`T)av$T*jV=)D%Ow>8OD`VP zUN+>v&yPoDn2@u!Y%I)gs`xyA->}icwB=m4f&;ic1=y;-zproZvcI5?_L_KEwIpkZ zhQ;epW$Y@RR&w_tvH=;r@(a2R)U{?HcC>mXFYm(UpIRAU|EynmDUg-L*1a~B^ez~_?*yF!0F)}|NOQBv33A!3yX2L90m|Wjxecl z0HErqlU3C=p5REoQ)+0KNUiV&Ghby;ioX04Q+`nVh&GaB>M`JON!B3OqZUSn?IQr1zF3)E}{<0imRu%eOqtpq9oq$*D03ygNEIAeES#f)Vk)e-U5|eNap(aaYDxt_l(F9O=qLb0 z)35tD$y;7jAfvZD6WS1+HhE($D4n-LU(u+k38X#1PrJqz*iOdRE?Ho^UIF!3xf%BL zf&v-&a(K8*EGf$2aE>m_sz3kM(%w}lksGigB5N&0aDtI*(wHZzWc7}oJ+PUfigc0n z+d8#;<5z4^AF2W-i4YsW-b|4V2H$;7BDx(_ZoOjy!K z>yP)~fB~D1p6AstU3(L&@7XzvFWg*~QImpffqx@207Xc&e+E{i^`$d?b}BfFCE;b> zg*Y+HW)CR{%v%2puc<@pxj;dQ2Rb|1W-7K$gHnF0^c+}qdVaakZL)D{yH*B{yLNCi zkPJ8p1cIhgO0CD3`@_3M=lm)f1+s%)k3E5d?G)mQpZP1eOHeonU~bRRvcAFHCcanC%)6?&PS?%1cYzwstf-33=|X^Oxe5!YKQ_G_UA#2 z{5voo>|*-EHq|-xM;677zfv6Wa->kuD=@9p(U(_uT8AOG-n)Ibf{~RVVi95Cr6BC% zUVx5ZHJ|)dDX9DH@6)`&JxCEyq;U^eRyW>FA~rDLBA8(IYngZMrs~c>zoH}%QsFZD zrS(Mb0nbL7u|0WcpC9PeXOFQIUFnM)pnRkO+LNdiIN6F?Gs}4DBaSPj%H`8S3Eon1qKdSELKZ3+mXzBoI@Sa{2Rk-#ZYP_`0V)o zG@9#M!)>r2o;&xTha5<*7m$-p{ChWFxX9qo2iXF{eMMiZ7sU_vj(ui%*NyXs8A&rR zAa|{xsl&Ga7DNNi*xb1LF)a^EU=r8&i3__@K%}M<=VgoQy&rfnYbMyvRp758-U1aA za!xn9!ihVH<8cC5!nM11;F+=WviJ8?N?jIXs_LWZRly#B0r=5cIYm9{eN+OBR|@GB zu!$D?gS^~HK}Qh|6S{j<0Vk)Y_<;KTwHQP_sxVug>U*;?#|5TYDdZT1zHTckmqu)W zLtAgrb5#G}z#2F3Q^XFJ^p;wIEGZVGgxF4XMVpa}V|!1a9zfXoyw~@Wx@hyCX>IzVF|c>u$Fj zWM`x}PTD%I)zfcw$7zj$-De;3gIWaN(7`3MKE9#vtk>TCh7<-VpYiPEPfd2Z#C}#5h&6>Hy!Xzj zxi2B$eBItU0ekSyr*3WQ!UZ#4eP`WvLo@nei-r;XXo-Eb-Ea5Hgx#Ojn8|i&QBcMu zBq(>3kNmX;QJJKVaOZQwOfyCpM5r0^LwD?4-W#A4`DQlxi_3|Lkad_1+$7c-PX*3> zOL3&Zvmugl3Jt=*@ZVb$-@4i}n|W3drWCkC!84X2Suik=Z5{CS zhk?$pr^Fjj%IOw=25QD#J*-45vZ0<7-+NI!LS~wy$6Z8ZuoXI)kDG~do9+s*cVhU0 zAHUn4m`&B?#6)5vxUuG#u3Vwue04nvi5YPS47^U=O14@Ko9Zo(470zn3sVm5+A#oLak*G`N6t zu48TnWkoEgYdjyxma6c{5SVWJEY41yEq!Iahsu3e$>>Cei0m9-N092Iw0uxiEWYQh znR1iN)3tRtUxRbpf;kFMoq8m4u~SdEC#!+)YmUwhS%o!$$e`x4k^6)88*X^oOtJ+IL~Br8^{UtxGef^X-2fLqg-`*2t6@n3I% zVnhwgOD8hIz&uq`S4<+-&pqv_(_SL|rI3BgZHhe588Lc+xEU_m_^@O4BsnTnuOwbS zzQ{k5pSVY*u0DnUtx&Nsw(iz{@^2}1m}u-7Paf(e8`nK_)|(yi{^|MnX3kqYXX2WWOR`2f4mPfM-V4CWn=MmYNCW#)p-wa+KnMk=v;gyCfVpOV`qs?KwcPbXmHWS=l@F;)J^e|Kbm-w zkD{>6jf=z59?6K_q@7jO&`r>^lp zwmJZ_w!@&h**|jNCQ;p5WO@6|`}wX)V7?A!)yPF&Kr(RHnU!H%+?Tu0Pp;6mt>kn(h{lxYE3iU9z?cbgppWh$4rW1@FbNk{X)$?EvApgX)c zNC4Vr0Rd_fGvf`=h^_X-KGe`Y{sX8}xV-PiU%aTpzZQ_)D)TTst&LbM@z&!ZTmJVS zU`d{%qu^jGXuY&^VR-ynOd@~_-)eq}(bq2*V@FJaK<9&`L-q`Smn*K&0W9sw+8fd8 z-4yRG`GdOV@I(;|O^j;TAw?LQ)kxI2T9DC=cRGmiHdWl>ObVa(%^zt7kwV3>Apr+R zbb_L{fU=gYx_<99s(h<&Idh4c)=e=OJ~QJR!mX*VCe2fv{j2`=F&*5j)PC0~<)fUY zp$5Q`-0V7|c<1{<^;Ex(8KHHmOCHUw`G?G89`XzIdq$4(1=Mu+l(|5gBKqf8Tsi0@ z^R4=}YYXic)5V8$Mp3P)YWuzP-Ld$fJBdDJ>uPte>n`piKiWYctpY022NrK%iJQCH? z?)jDoojWTvrLFT)0o(kRuh3z+0{>ir@k+q_qq==P5a}{XdGpYf z-Ya-6Myx)XU9RdyuqG#8o$KuA+Pkht-eYsJP(AlNfU&54PPqn%E_8t3zKN;6j`>VB<&YW-WGcg{0m&d6s_8>2qdK+nWvK?aDBv))NOlMYBo^LPyNV+*&Pe0385s*$oWBso5qu}U8 zL9U*032F2BaDegh)(M2C8}*i%Gr}-Rv!chTdAvw1NV2VQ^dYy{r6}&wNgOUef5C^j zDmXYNEJm}MnX@3pbP$?y8H9x2>ldtyvqy%o;Y#owfE{;61QWcYyFV9)EO(GbM1Lu+;tek>`tp?2hlK1uMpZi9b<-f|omstc~@F zB!FcUxCtD(@0%hQ3nQ^js|`QpToBSaE9!RE5%B8?vC#U)FSitSPnJs9twli~8Rinr z6^W871Gi3g+!>m&Fl)2MK4CztZd6Mx93L+8+-{<}TX5k6Ra1KmJ;mq<<9;jX#V9wo zEHZA?uy$E3o8uqDN#Q+JKT^aB;&7xDQggNw-&#-t~h>H`f(*du)N+@ zC0h8Z_15vDr8&{5()1J-PGwD7b}Vu8DNNEw~g`kV}F zMII&_jb3~c&JRk6_M2()`Y!q%oxE4NiJ056yUU`ZN4YVwFCFbwe_Xc z36vvA1PDX(9}iKk>!|oBM&VhIi=aV6HoB|zPdFBeRF&r~Eq)ix;vBDT)P`7zyh+|X zFI!($YXJ3W~d4EqMOiEzjjzgW6Suj_HCvG_ZiS%8@%UgnIDBp~AM!r8Gu; zX;P15Mq)|F<^-oa4p09ARu7xP%K=oy2|0Kj`wYIKl+^g{^k0Yzh$m&v;3VNThWln@ zzkST1fTNOEg<*5YZY@PkH$Z_TcYI4OC3q(n3y~ib42f@}kuU9q-wWyxwE_L0tN;xu z>=X8t_;YuTWa?ZqBT~5zdg4}G3XJ4kh$Q^yzB{6MofE!hU3hX|Yf}rp_H(NE9Wro& zIPnUQr#l|4E0L&<1XQ3>FWOAG^I+>P-czoefc4jmb_>)j{7A+=MK!$_5WjR)hmE(It6W=pipv8Znie|Py~<$x4Lzw? z`Ui9yl07C2^fO@zp8MPOh;ze#8k}X(-K| zj0zD&*>MDAd@H9M_2>J3C`n;{1R%&z7*5g_PSGG@!$$Up24H#?+P>TXpxd4FtW=Uf zRrSO8YHbeA+K45|gU)%>e1dbVdf(FtMbcEDz_*$~amc2g8KaZ%L0+lz0AXtoc((M= zm&&9=a%v=fFV4fH;ilBvXw73O(D+i0)A|*ul9WzQH=1Fkj2}r#tfcC|8lF1J&fj8)`JB{qsh5iCe z?o`d_=Nt~aX~ntoH~lmNGf>A*RD0}1muP;;X%U6LFQF^LKS;)2s(d(r&KUT;8U<>V zUEvgCb2kthz}*s$lbX${2Iyq0*q)lU?RN{DGp!iq9odyUJB416jAuRIV4B`|Fo0fj z-wO-_7@q~6@wAW}_xx>WFe(lPsHa}MKjM6Om(8u$+mvyC#AIoX8?mu90q$fO52O9q zu-^7h7ZTP=640^NhOZE%g08t!9}C?TtmgiB*soblx^GVUC^M@81foGvl9X{_pKCAg z=#Iqa`WUku3NqT*O7-=+D@$`+2rdv{6UU-l@{QJoz&2Al7MUeIHq$kzY%|<_O7sGlgHxGsjyJyTb32^Z`X2VZfO5i` zizbrTt9E3=(`mLI%reo#bv*dmqhU%j;J5kof^EP~&pq<@#ZUTgS%6*^_A;KG;okd@ z7Ld?Wi2&e9-0P}Lb&zCR1t{HDW0v;eWi{baxnFYfL>kN(v}LDJVf2TIYvYt}IM1#aM(<3#iWTSjEHF?*}lum0OEKEohF)6((jN`kt4 z{04NU+2@&Rh@nhn&LA6Gm$$dmwpJ-fJzBY?V2J%TqEFX&NzjEN&i7{RB0% zo2s6hn{G%Ql68?rWjj`Nv|}t$uaHA*jZ8nvzXiSr(yI>Tzyi}!1Zqw*dDqAGo?A!) zzY2_29N{ih40O~RUA!?H;GyT`?d_qs2WMTQBxJXNu-pc6ew`=jK634##clg54x{Ck z_?vPnD!&WGuPop31R2+vBf{Nd#vcbXuQ($HQi9bGN~_y1S$pxh3S)^&*Wy!}ls;L+ zS!|UQuDD+W#tWogu-=2{A1P?mVgdRNtTC%rOLJ_5dL)rKxK9d_umKGh&ed?|v>b|4 z0@ySKDDuu4gT%Mbxdf>SGw49H!I?<>99{W&F1R##8~O!+G*IhzoLqX_YBk|^r+ckl1;1WRB zVUL$2z`DxTerMrwmUhEi0ycaa+*XAh5}+3$!Ib;8AW!X;_iIb@5Q(BuS?^5)U7 zhk9SKostX`&Vb1;`%*dhoV>k`b5#vo(*fam_n{=&R0i-n@_DTqlMGwu{G297(Ch^j z{tqVb?8^DQ=c@vliCrVW#WeH_8gHI?0Syz&3{Zh>{_l%b0HXxWQR~z*<)Dj59rO}3 z)P(Hy5QPhx2s!sG+JVFmnJVTIpYT?d5=?T47|$6Nwx;38SkWQ-$zoMe3j5Sjr;jR1N6;#VJ*9kjGw zb5+Fs+wK8rv#brslRwNq1$FoG0DAVA*xBJgJ$KS0&`q(O~tcx% z@mK)ET^%sV8FQ)ByG7&Xb6-htX=!=TyMGdYOZl<13{o)CDmdpQB=ru3cda8_?fcK$ z2B3iev?PL3d5kIyXB3U4wSb#YO=aNTSPT2eC`u+;wH=rQ6s}AIl%Skpy8Qv&RP$b3 z(v$`2-c+CGrDUbtvK-FM%T-py-}Iww4(c-am@_{*(BE1=uNevI#o&&)H9=oNc@XCB z?E=XlAA#Ooe6ohZHbx#ZZL_j!l_V7ku3a5l&qUm-KwNp|wcTlf8Sn(ieiCz+sCRP) ztj%A*&4BTU5@bLVCkx;OM{_uS?5;@5z=iKxw}n z`jWz3QV5p5xCYNp^v}FJwi}RH`tgo$W9-2Vu5}%__KF$T8%xj-CV%^;H10IR-=Yja zM_4eWfw&m=y@-HVr~Kp#w#xe5jeegM(yf0QLxGOq&a>~_cYjCRLhwAVzQcq{d0-C_ zjCz@m0+bzl^b=Hf?1ag|&FK$7#jMZbdWhHE>*~BsEK7M7T59_R&375Q&GqP}lmTtl z4qhCp#*bgF_=_e@0i;`1Lpx38z9cC%v?#)Rb~b~D^xKx`TBGf0arld z8$s7$to%GOAd-_Nm9$FMZT(*S&enN|IW#coN~P3q<9ZJVmFaPCjA+obH{2@;$ph}w zF5u=sQ+M0bTFS_h@$}SwJ3VD&Ko3##-+_^5C74fem;G46L*W;2LmRlnS)Abl1%kE# zK0hbxSmVR8a77=+^yEX+gXQO0@Yj?aK!Bn>($^W#@fCIw^H%XPA_=E8h=M>(kneGm z^k_qZMk+(v)nsso9kiu@_?W2KuG`>}vkkN$aH*yCV7mS~NRRgV{=FduYBrbRy?&tt zW5_l93zXrS%^-aeM4dSyALB5g$klV-=Q;maF;O6B3^K^3SWj&IJ!|0?Xnw~S z@LvrW$WKD%MR3FTQ2l*j(XMz0&HHzrg^oIR@7A6Hv8ut=w`|wi3#P4$HI#6f=SX_` zMMHzkz~R9eNNakDMJ=~1Z*tcaeOL@i zHP27l*+CeZQED0(pT}j9z}HR;+;;1)17xczK%SH4QotKo@7lzEGAQC1!1gPg*q_;y zyBS%xjV%oKiZrhPvEit`&ho|S{YxE?qLNPb3WpK>mKy<$8$gBGRq5X&1xu}hv&~S1 zTc$GqXcuxY3^BZrP#D~E|DHlI=d`NGv(6A?~fa6w8VFaTdur*@x;~Jn~K%PwfYos2>X0Zz3}Sl>M&;TyStz6?!;X8 z1nZqTe@}hPo+tkJ)`-7VMt5>aVBM!-Z8O)W45S`rVd%R*#m}|(td-YL5H))Yk+Wyr zJYOeogTC9EFWOn|r22b=-rV}!JmQQui@u8O-pAD?A>WU54|mG#Xr%uT3$g4Z;%ZYA zWoDfRHr4B_Ptc4jOXt1_pYgc;^36V{_!|*>&AFPg!Huq0QD7y==UYTh(hsFXE7aAL zQ0(-I#fk%Ac5`Qb*ZG8zS80yawgXaiN>(fBkCadZQj27oznLx z`?bTB%nKw^Q`Qs`oGOO8rK=8rp#34*q$UAVoD>P9^-znf@V(GM*68y_-z}x=iz!x% z4X!X%H_mu8ckZUQ$JcQ(pBHtob)iKkg#99-L)1E*i0d4ZF4xJsp-BoY&FLJiST5hD zgQq*oaL4TST)>Q&xw$WveE;>UhHoO3JEMp4C#nZ(j)`|xjmC!SVOScmFNSV@S!BP6 z0UIKG=-Xe0yr2*Dls4*4l={XKY?FNNhfzPE=D{IbOq@SQoxC5KCmX$@2GtkqEL@+0da%sS5N$Us6OGp`xzO6#$+uU|8{%{_bd{KwxFi0@vS!G&_UiC-`8rdi#YEkr)M zjb!TS1AO8oQ0ev{vEj|9gsA?Tm=O~^2tT)vb%D1TE&tZZzeB&T zLQ-`ue17$Ngw9+M=Hy4go06x~EWFn_erUXJ@@4CG`VQ1FcUSBTG_h;=AW`OgY0RGs zfzQQt7DMMU0*i+LV+fzTw=y*`@Pl&I#=&ZcC&@PrtO(6#?&?c!-YwbQ9rFxgjA77` zuerx5YHwzSxD4}Oh;=Hi%aoq&>mSxW~ zH1F!bf4+0ui5Y3*eKrzG{_=YEj-i(WGem&iOtB5z~6GAgv<$ zCob>DLs6^rAvT1eZ<_F{tzII7@jPjc0gS^SzD&cpD9_0N$@J$xtMA*`SC(}aW4})JO?{)3qP}HyD%7qbS2O+X8;7C)eB-uL`M{uU%(GR##82C)UWS!#&wD_(eQ6)s z8ZWgozW<&2BT}Gla z0^MVoBrM6TfjcBF3I^{9d7e28`*;R3V&LY^W9S5$&Z7xm!+u@U1!=}799#1LVd}jD zsr=vn@gtR215L6+NZET!c2*&>D=RyDJ4%u4o!u}aviB(2A{>sbLUM3y$M(B!ulMKm z`~KlC=YHPLam~l|xSsb|>`u|lx42`8ViBbGh#cTlB~(+N(Wj5R-=$Wu=VGeASFcC? z36TSCQFPt|95sn6S}rEJcsSK*U#7}OO8WNh$bT>Ma+Ar%+i+Czx~_L|bK8W{?YI_l zqn25A)u)vnSw-L@temvmg8C~bzCSpZ>uX1(^93x*P&B8qrt$Y8ev6OjA6ymm@iry~ zsGl}EOX^Xjv_h}>Rlapw+SS5DTUl-v%GT@CX8!l4q;YmWo+nt}Fc#sgv{xct;mm_T_E#ehjs%C+ zLNzjdD4Oa3oh1>Hx+re2KN7Z02Le!<`zOPUHGfoG8)rhYSa1| zxXB-Ujs9KBk8h24hqsL=+%Kr=JXXldpG?R)+Pdof9K(}Abk))y+evemxS7j&6YG!z zq5x3}Ks;YSw#j^beRT4f5Sv&Qg9~NIw#if4Q>rLpU*RLHon)ALsMehQA!u$VJ3 z@V^Xpl|EylS=^7^gs>4emLlfF`qVuC=yd-My_CqcyYgfIo|?VwT>Q0d7q^_vvJ(%8 zz-h{uaD_)Z3x~Lv=(c|!_cUbemlbh3i8|<*m>LFRaNh2Rq_Lsuy4=;_6dpv@k0BF0 z7T?-dwwqa9m^a;m`QVp;kAKQWgqnEV{|sR5CCt7fyl1x}k{`v1EK-TJVC5i{14?b z@HOnzg;Y%b?o`s)n-LAmKgWz0kJUbd&3pTj=HiT=Ssi}9F*M@tc|$|GiUbf+#4f&NF^CRju4wg*pTbTl79ULI|~y*N_M?-)?x&=@P1Le9q1h&j-&yD6_(GJ>2&nE4;q zwjE!qqZt(&kasrE(PHn z;f|Tdw|BeD$zzz3S6-*|FK7SvM4+!#v@RxdxB8B~>LUAR#0->y(OKC0^muNuV(y@g zRroUX=v8MdNY%vAJF)`iG_?mmAWv{G)hkmts3QisF(I|i_*&}thid8Kb~Sl6A?0O# z5D*$D7j70({hT-X~-n^QZq6ta94! z$l{MuM?%8=VV=c|*hCZcb19|P@G7TW)6q+EFIvIqOGihMXLGAC=g}=;tsbWNYj3#O zQOgzKCLIYa@r*~KNAu~km`P%#{x=`DYg!+zcaP??PjAe&=0Ohq0E0zmJT)f;a*%D( zcCtvexi!1N^}h!W?6NQz^1t;3(KNdo_dgx~WO0kczrlIkCk-R?be~_vYIw2uAu%Ws zDYzPv#iyiyePnobBhqzMes(-K5{%&}2B*xA;cRVPnqFk^L(ZcgN+hwkhDrRk%<}Wo z;VjYp_V2!srTTGR9$5JDIG)d0T;$8~WyGxnxY2%(g)P<<%$GS3es6dwB10+tJ5Rhd+m2 z`s6x1z9p=3%IXteIzu*5;nB%;zH?#EHG`9TR}{8jb_Ra9)$C(sOVx)6_zkX1#K|44 zUx-dA;e9dv(V*v7)SwCT{lB96ZRVJjJgpbr=+|Q5;8c1zSbpLe$rDo3W9XTiyvqxHphTWMAj_l3G+``@M z73EBPgpHGF0-7VLFya3cJ5r2$S5GeW$V3fpJ`(j|{num)g6-bhE4@Q#6|5@a$DWx9 zk-rC<^6&&A!6ypC5)^xEjy5dUC^*8Xtshyt?svm0><#t5M=Z1I#nW%{Q^>)5|L2+9 zBmv4=P!Ovy2x3fPIHJ=OdFN-1&Z{qfYba zAg%j9z+sdXa-x>+GtN%|V_o@ZW}kxk%{#`P{^vC64KJ}+7Er?e9Sj zt8n=ft@o<`{DYkDkqc0gBy;{xN+o^iRntwWV? zUqC++SRNgJ>WP|trL6g5*}E51@Elxa@`DTNNO;^xNhgxXY#vwlZ!|zuS25Y5W$I4} znFM|LBa@_|MRg=#GfniQYoTKrM|@x}fpRUg!0|3YQLu`!jMrLr?JYzdpZ+iE7y{vJ z86GxEgP3||IT3p#&F@1hLZGuz`{4DUf-Klsg~1{}Au&XT z{giSYoe-fi^iOAD=*0-=y!biB|C^+cgIdZrR^fS=WU@Eacq1kFYHnvEZ0+A`1)dh| zf2e=-Oman8eL0Uv>ScH;=tRM*xXC8mQJl<@QFf=ztNS*I|Dnx5!6oJI_Wk?k)$FZZ zTvW+Yx}(~ioBo@imU#Mvr{TM!h&TJKme7I*7CESd1*v!z&*t%J>G$nwq!FR*5E%WR z7@Yuv`Uph6W0>Y;bz#x;pN_oU=^s|%`o#W+^O%`q&|8E>UUz4)McTnG#YaqB`~L#v z&+N`kGmW{lM`1bmIj3K4MVlKh$%TivMtwMEjSj;p@r^ey4TSCwiF~f~5er^l7Zqpv z26^8j@%oQsVFw@(GHL}h4PUyv%mg;D2~*fjL&&b;a(R5!S%BwB!fwNTNKUt&THl&< z=Tki0SshlgNMjKAkcjkqKy=bL*RIA)n;iah^?1oEG1DC8!yeHCg%Pnps%|1~QzWgM z8@xtUCK_h)p`A7?EUYu{&B=+*HB+3*>@4H?)n(5zmyOU45p;Td`=1?&?vABc&;&l8 z%3e#EM^I6{0e}x4{TM=45(1cV#I{kxB+p><{w}66^GS819%g~7Hs5^x0Fpljwuhdf zE2b)k{;3ST9GD-Un}+OsR{qE>+Wg?a%sz7S%f_SiowRWKYn2#^|97nBnYyw2JbIq; zOSD07gfY`Fn@S}&(mC9UWwE-olCEr9 zzB#W1{vaycs4HP4kZAlc1B5nD+S*ip{Qp^`v~=G2npExsi#xuao_n?WyF1T!ZN;Mj zOOSYP(~P;wCwWbCmwMe&S~6F_c$Uc-Gs4TXt1rx~IGUv`kY!)9EQgbP z%HWFonzmFD78cc}Pf9L6{kO_+YE7RYwyq0)w#B>CEF6(uxJrDq$;3>Sh}kdwoTKelIz$1;lu=rY z6-f%|x~JCUUnCuXhrEFlME%4?V%e|{gOw!@>p#wunDxs*VwUU>uh2;@{5m77)s=JL zjkDqE>l(AssI%dBeKfwz{|;ji5jpjRHdoE=j7m*d_G={QwFdvoeV2yZx9r*-uN_+- zPhP!Gi~lNs;7Nj3YoQVPuEpMXw5z72G@E&OyAC!|iqZeqw9%qy8mArI-dpo{%tf># z`}YyZ`2WRuS}pQ$JEGR#&2mdhnjX`X7IIfkzVO%ObFizG@X@jJ(VJ-%oEPAkj$GbS z&?^zYzbm#*DZItoslBl|IVUgXaHcKyq^*4qk>V#m*}?KQKWRI>WUxPD$J^%9Qx-jK`da_cULwoR+lhm>^9xp z(mJW6vimuIEU_!{z=W0LrLx)Wi%aRr*K3;C+Y{{&6OKTjl(~vT^GPSexV-_l8V~%! z7{oCg{X~NOopw?03U+>_~=PV#C8|lM(2$ zQQ9^Cl?$%w?H&4MLJ-5K?caUp_eMKg@3ZH7PfeO{M%7yHkxgudO&pF%5bSI6{+p#z z7egC0be*4awL9%T;HPok4cebY3sb`bh1_HpOQF9LstbaRi~1os4M8v!QApkx46bR zqX4P0F$tQ;5(*l1XHra=vL&<3!USeVr0Lqgg5walGz(vuX;DD~q)VU6@vfbHoXSuc zsGTo)%cECzQ*ZTk^_4!(crO#eR_3uzx{{nU+R8(NIQ-#G`*%SBaw?jKIOBf@qDC;> zXEH%ZMdEF5FYoY*U6$(Ev;FnmKaFDkyl96!SraSraKTz_P)YKF;oUw?NPr&TLf7w$ zYhA1OtU^HVPybmpvhkD#j8GqDMxD}dpM%r(lI4i~fnkd&o+7J$Y!E|!MbRlrP}9<4f0sBQ-&hS0=JoCI+i8xF4XO((G+XF%`F+eLC4LZ1k!W4-gh40D=1OcuJ zBhrDK?a8@PF&$${H(WhgOpvA`51mv@r=tx;mQZ-j{^t}nbB@>%_lE!#Ug*5nW4W2GTiP|0_xI#c`R9LAGwXbJ zb_#3FXNkLqH8B~u0|tE2hSV#U!3sjVm^T@$MdB&d39Oz)zgLY#UH+7*lJmAw&Ec+p z>2z1gs7c6f=!*AZ`n~z#^tMmE=-`c?J#egQ7}MvFk+!tlHtWWC7VnB^P;kWrd^P)E zqomPeHQW2}Os3RC$r&;8)?U>_F>b?MvAqX4{0%Ip^WeB;%v8ea@YtngBCv3*IND*7 z23@L}tZ32s#ftV+#hDf(w()t=om?V20zpqxf57If$XU_BwmBc>d% z)t&0nDPT<#1G!7_6Rqcy6YsP&o{b%T(hO7_Quz`J)q}`PgBUnF6wFQshsAYCOvnm5 zmyr^;m(zMrP{Pk~qZ^5>o>w;ndZ4zj zn%OQSaD4AFvDn*Qh{#sIZoCZZN;b6}+sLeykvg+_NYMCYY%R+gu3xHyo7|nXyzl2( z-4wQK-qO8pR=?nuy|67c>X42{bp^uOo^;ectvYxcs%WH^Qq6zw!637E{nWVB-Y|rk ztAF*%9Ir9xeQ?Ci%Gm6F9`n}B_1&+F@So|8KB!K$iBrB=h=Ya$tuj~{8hpHfW`j$cGUo?Fd#mF@l|}5p(|3 zxYg5DANYrZqu}13!r49NMqP*-lkCJIxvJ!istbFjzhEd=_kP=-(o28qTlb|RhhYxx z_=*3UVKGH#Uaa8OS{bXo-T|O}OU$Ke?61j031LG`zELxe7Z(+~MqZ9KuQq>G0tszo z073iy9NW@~ppjV1)u(o;%uXAvnv3(K^|SrM?^@0q@)j@}EpDm}w&9;r7dF_ArE{fk zFW(Eb=I_rMWDGwcU=`3rHtcq-X^Xb6ZVC~sdgX$26f<3IkUdbn9XGgkx|jH>w4OBxaEcg)??v8}H}B3Zo7gAkZPk;B&1~xNUZ9-LkKl zmv%tSnAS3&LBLri!)Knl&xZQsP-N$A(l8Mua5BdyiKK7az5!KBQyg5wS1IojF4B@{ zG{pDJu9;E(RDrEz028Y2w^OD`*hrE{+2Ir5F-sub?Kdlqa5#Iy7Xc4u?Jq04b0glc zfIhiM538&4zO3*|aEYw>ua@IfS6rSF#xj7fG4h7bO!m3z@;f$R6db*j%wlxSp;>sS zs3!rlklU(f8l7z3eS@C;+o*4yfPTT=gB!9L#3$(oxtf%;H|0K3p)1M=$0lECGdfc{ z9(p2bwX;*-v@X*1WByzMSd+3(;v4v?YWfY*A=g7)8Tu{@=MIQMTNKKwrRPz5RIr`Q zn3|xdV72PP;ptxo`xEJ6`rMIWp3B0Rnl^q)Ipy2>d5&zU`B6>0T#(};;5O&HJsv{c zt^7d6QMI%YgNI)Nj|*|0@Huxh*m!XX7U~8i?JBNr5gmVI$K+e3wWKFlEJ~@DLZSsV z-G%#2Dmq8%a*d5_aFq?j*-oK7Y}+ERDraA1R$9{FLo|_kEdx*>Do<*3ZfxX zl<+cUhGe0vP;yJimCg6ld|b?NIw;X~^jGI2O>Az7zU)uB<(xL8lEcEJ-hg9l!}L zqz^JlG@9cv_{Eo*k_!`LTRd>YK{?{N^P5@9hi_9`$2c{$<|BR3ye3&)GhAW^!(At$ zoN(69;FiTsk@WNNN~CkX`$F5lETXy$ugoR7&g?Yk?u(3lA9wE0?k-1D+$-EKIomi2 zaf_4%R1afyH>et%V5aU53JMmEKC} zP;sqk=!pkcGJa@sjTca21&Zty_#%^ZsQK$* z>8#V-@jbmWqawZJ<0oxkUo1G1_QQVE*l~V0KF{3q0q0rPaV$5R7emhb?51fcI*`ai z92VZ1^ZhM2d|@HnFJAZg*p+HoxQ(R0{@|xHCem+7IWzQgNlhly*w_uoGCMOGBMxOW z=t^7{vo)s*ZX`-??2L6j0Xm2e9h`RnMz3^3Er8b5^xX~#-Ks#Xx)kY8L;czse{b@m^-Y?f*JKbK%;}!hk6%&R8$&+eXY3_B+cLud;TN#l6~6m}B@UW*Vni zJYojsXEEIXIG-@351T&efbrWNGtYz^Ls``(u8=~}#st00VEyB?Ui#JM8Od5j+bGPu zM%}&;Qo62{Jz$*wvp#U!bV@W0Q>-BAD^vwR?h17(zJ~*ajsQ6P9xk+RVNV_ZTJQQs zW(`#8xh6RWV8cvUyS!K+kX2GPFC3!k*W5}Sn^#KsHq@6Knh@w$o&eV@y5ycc`;AknkFmSk_y1sRsZ?XaPpTlChHLd zwMzFq$y){Vugz}Jm^MVulXsY{il-b~X$QiHU4*i|5Pgg#gQiVJTJ+sQIY2xI4n$A< zOh?4f7F)z&szq6>gL_p6{FJuRpHSXAcOd^M5#Ys)>VkB|1kUK{GsZ^JS0~dt1vjs4 z)ok!eUc22rej}O@Yk79QNerAa!U{^f)Hb!~FAYxHXDHviwW23pM&iR{% zndfVo9`QiI9IPn>>Rga6(+)g|!o&#UqBg=v`ogqs9atOX^jz4GF3g$h-)BguHMGB% zU@MvOZolMIV+|yQK4TFYHvk=#BW$GBrg+JT0;CTm_s3ccwH1wVMNYf-s#avl^_a^D zw*cYIA5Fdyb6}&So6ZP#j?&bW$CPPeqZNDd%m-J=M^(@H6Oh&0gCq4c!ZfGygk&C6 z#nDJ7v}09<2k4d@4t6}Y1xs~+Q&FA3?^!f7O`%uG`(@}Xe$wVqxs6E8Zsl{eUmS0C zo*hEv*7T5QJY5+zfuJr^796i4vwxKVyQ&w{D}u9ip?7T!dQi-woTiAOQQV4h)%1SA zF%8`YxI!aGS&X{gQtgYaqJbYn-!rsX5t|_*aJ$a^b;+KW8YU zx-_woX|cT@y{Td-oy8{G7K3J5!WT)@|0r3>7vc|r?Dto+6IL|rMe3PSA)JY>Erf1w@Tj zGMx?3oU%gYEw-{>KYKLtLiwWyl9-sBGyGg^>=@!-CSREDA2wu0p#iJeI`4{I@7lQS zC^EF(+9BG~lKHmO05X{Vde&bJe?Eo9WdCxNh?6yYzfiD55|MVlGxQujjria-s5w7? zfhwk*k@zK4hG-elT_>Gna0N-sF3VqZ7L7~RdR~l;i7{HP{!84tm+j?l@mVF1JhM`4?MA_*cNHCSH-D);_E}m_4oAF1WSv5)UAV27c3zE$DNHv)p+Z^% z?&<)7F?d_quGx3h1e8>tx%&#ouFap@&>-@wDNm0L-UwCVVbQ->L8U+>C# zsf>Qco2$t!>3Pq-GORXuzwdm!u@zB}NUzDQsRVCP|_0>!LO2XkZo@L0M$8H%m@W1Vc`t~) zatr2Xja+s#aH{i=BDOy#9aH`ibT6ILgyVH=EBD9D>;&;Sx%!ly^PG@C4=ySX91IgR zN+QQb@P6>g5zpS+VDp4Nb~K{H9H?1~^A`_n@JSCqytDr_K5>*0 zT+frkeAG`VWZ7CY&m|-B6P__n$Y)Dq|5Ep%EA_rn&23#rf*cTzP$%o-Q5u30e5?e& z+{ih`s1a$nE|Q#B?BOv3a!X)ua!0)DOV{jt2P__SW6sE)=OTWj4E9)ey_Qt5pn!d@ zS3Zocbv>L5d*5wy44vP~J+hRJs1AT$ zRFYoF(S6!fz)SqWi#}9!2O4lSsUPtvrt?ht@L?k?>m zrJEJBtS%-MD#i@o1G;UsL_JWKAIy;~roV`b$h19n`pqSn^aY&mdXuG7W@W7+!JTCF z3no$uuX%rTiMnqsR7Qo6^z!gtIzM1~ZOt_-wyMe*>}9iEEyPx}<;Ra6XCmq}oj!25 zKPI1Dk#%wd;HB+f3g_KTmSr&Q=dG0*c2!;$EuBc#y5PyZA%H1MzcZ7^ve$O{4dmeu znJ!w?MN3Xvs(1?0i1v%JMZYf>(ZzH;5+{H(1-fm4G6(!+rd| zrfim-IV`nse{EKak9_wi-1FM1Hts>$>m)zuELp1Vb|%pBAPLfo=Q_>QOF`j|l&KT% zy7Bk6w+T0Z8Pgdhxpft%_+{)pS5e8~iKtO6_nrarhn5ADj@qmb5y<6KE~Cvr_oZA1 zYRrD!^Sx_j%nZ3V6^A1+<64$miUwnL3I%YC({HDGpYQfxJTxXbLgGQmGl8w(EqZa= z7Z)5mK51!lSab5HB&;_$x8(IepyNw(N!l8PrMUj>*2sgYm^(-C1ZNXEC)=IERw)v( zFhBkgues>^WS`jWRD_LypDlLZowU&#W)PEn<;o3+(&8qhk{#V+{~Bp^%1eISyHPEJ zkam=vJ*MfF6c!(ShFZCV-#tz;5{>0^bq-SnJuRItK*Bqc@UC#BC_sPjf(4+2nxrP6y0 zkBUYiB0%l}^5GCqxYYIJ@9Yp!JFVWSFY2tpZ=5|`PP9=nY2dyO1*kAA>nqrD#mg<3 zrEN(@>?4PefdIJh@H`YuXUts!947>OgEIWatmdyoAt7AzrdeVa*OCW`wbG==RU;_l zhOVUq|6Q_qLKO{pwmDO)(Xn`N#t+&6zkx%%sg8f&ub2^-pI=LcFudvwY0YgD$%K@a5xf0+LH zf8oA1>)PPA_KaKjtf}X+poZE3b40PR5&fjfuR(Q(q$)rjuV#lDoDgN| zZU62xZClXw;9NU%@)iS9000u(h2%b4iDxoq%^2_5%Ru3CvMhGI_72~m^6yAl-NoVR zwn7uktWNIMe-UT}QHsGPDk#$4-c1T}NaW)l6DinOe%qa}h=!`k)<7BxR!Z$9d}yOu zRkGiX>U%Q#Pn`dD+2lIV^Wkq?NR%v7wsDk?$RAF9zrRH8k8pQ6?177ckfvhqZ%{9h zUG%Ij?>-L+CtEUkR;O;rhfuXMu7`BDqy;n5tB#0#E#6gf7Ha!fCME=#g#Ebs58O!_ z2_USIz^ZTp(#zSiqLm@)#>$^c%EKR35mYjP!p$$F`1`!Zb=;PqtHO>*y1ZE*#zs0< z&u+E({q;q(1Ih;^6%`=nEy$52qoCO8f_7&-V{RLbaR3t0N3(962tG@e^>}S`_OFeW zsvmL|91R%;U{rn_RGe%ShV$jgsYw8hP*#(bR-})@YP$CgL`sP)ME)s%6N9(^y4|J$H0A0Sq-VjLOt$Z^0(5@jw_33QV=`G*XEsr7 z2k{Y>vKIlNBuhn3r^v}bC0$%W_0GGT%G%bg-oHR%9xmIaqP)+3b`(Yh!f8ko@`FK|h_C$7ihcKpUCtzLx!Vh%i>JF1!`fbcTW zY-V=?R=BWdPlSs-1@$>&N6Ku~NRuq%@v8mLhTuP~55155+y!yl%Y;OCb<0ywoIR#z zU|v5)8Eo>leei-r68jmUYn6c_6ZeJrH#}YDA0?iRc-nD%TUULS1}TvXHB6Jpqn3a$ z*l6%+IF$)%6pu^9UD2(KJLwoJVsKO!pvK6?HQPBNncH$zICwltO{Om30JK)Go>LD& zhq*t9c!lj1t|mzhdx-=XjS|&@e@8iFb~8_)nG`?bc05aCeX61BgFO!yC*GjlmPKrJ z0kB*Pu22DE?2mo-7X*G+~yZJDMYDzqGf&q!55RsGkH^px2~T3i<$_oUdyS!n?SoQ-8OQ{@C}0enuS-8x*??lr3yd?P_S2q1nDfP_%~o6 z*9p8Di`U2EuDA6(AG$==7z9>kSsjy#a&281+1I3^qnqNQga9On)fHP_W;%4`3cr*1 zw4PaNiaTi(%!)?*tA^Rb!>d|<0#(`qJ*E`vpxGw&+qw?>jd?&N8KO9=^r7ZOI8UKYHo{oswc(zbmsqAO*m zh+DKo4XC622ZVnb8^Gvza9gu22-aw3RK5>d>uty6KI_9@NeC~vXL|T@I$vmtY!_lx zC)}N93zBJe3*XN{&(f8>M|_5lZUl;S!ghwsY}rgd+i}V}xO?l93rt?Yg}!n@mWUnOeD~sfh9MvQ)+P4j-Y- z(RS=*T7}Sr2i8bZtPro7$3HqSIr!}sfqcD1Z>r#n!G6QLz$LxT$8a}Y{>t&j;!nyg z{V1Gtdi5C(&`-nNTy6S>ocK4>7VI~cc)M9M9hEp|a@s@7w}qk3d6?bSh5R1`0CBerZA^!rMld`J%x zE7eh5XH~#WSd_r2PyfNhu;Uze4rFRv2;q0Uv9F-hUPX2-5+iU{NnWiXR(q40rs#4U zf!ZCPH&2o=u_3K{xQn54aILQt>#z-dm)!O#7c16hQbD7U{bnn*+k6)P*kry+xCre8`1NVFcrOzNKK0bFm3B-Sg+qdvZ*Pw8+#fh{dx& z1oEWe09rO-Ap3VhZTFT+H=%ljMl&%nIeA-)=w?$O)d-6hay#GK&!YCufE%y48?l`m z=H%z6&*DZh`{CmGs4CFZ&Yqr+Ga)a}&Y~m$`SBlBO}c2YAn~a?P^U)6d58M^`9#Jt zy(yp#PF*@Nj@3u~fef(m6L5ao{{+lICjuvwrPbx+{EQF%$G3iYZkL-aVjrOX05IRU zm~}!C3|(Pnb$vQx>Z@0KLL1$l`ffD~B1yUXBc~gw!F73j%V^{g^)0&#)isfTMEDU` z@;LD8=!%!*gqBi>mw|7HqF;k3Qevy_j=p%HxlamZU+}9oX-y4uoGzg~s-%jKmq&GX z(-^L~0yMC3l3^R=3{S_F3z(Q8nPc0Jp)V2{4_^8fkh6%rNSm?D zr+{moKfnC|cRwEzYlH*>)UrxJ)C9m)w`exhcc46uH2JkS%E?VT15H%L*fC*2G>ru! zZ!35$k2JhiU+whS7zX=G%FgqVEAp>k5edcODJ_xpPKw0{#oBND_(OXTTc776ycL;t zZ^p;rlxB;EQ=%b?BD(pw)P$Sp4a7aDbVsNKSy|Kd?MsHfdi57g?FziiN!SckkVWBBId>5jS! zfiB3&L1H>H9d`_&(i{zeoL-3qcSMvkup>W~n-B=d!5rq67VD}TavgD_P56o4Kraa@ zeG@3EqTY2sDr4}|{|Lco?=a$Xg(1~uOTo5@)LnQyN(xF$sB~d-`%2n|SZ-)U`hA54 zKon#jqydYJj_>D!UV)D3w>*njRn$QktkUESWbZ*e_3;oU0@tO*=nM#}iIPzQG#kMu z1}-I@JNI!v=~N>c?EmsjpaX+RN)HVSm)%o*LQC`(~=teGt8ytY$ZwGkCS%;eOws z==-B#d(j{5u0+P@o}Nbf8443nd&r(QWQUiYGQ50~aw%5HZr@*ISR(w@E1wJiy{6v$ zNIc^?M%O3}G2TOJM7NM5%y^&h{YV2f*`8<3mUpI24KLuyelj4*N*qEKD4bV`6brO_ zGW11nPEIaEazowgj$5*=R4gMJbsn^#wMeFq$i2kj%}4 zjfrU=7!lXFGWD{8nMSekv}(-Tdf+Dn ztJ+3y7Myo`!RBxsz~&LQ|EYR5}AAm~165S1WDeG;JV!6xwAPMw9rou0wO7(##sq_PK#So#0`5aN|yCqP%$*GFB@8X%=- zveKr#==InDx$pB+JO0xMHhS3v(q6vsn&HpVYEGxCMP7%!dR3bw=JyHOG}3B6#S z3y>l0#VC&uNJEfTCLlF2j@JoIow*3p6xNg`6D}j`gwPPo-U9&eQG28t#$M1tB5v*+GPy+?wB}|OxxT7FRui`n?wDIZ zgSZfnF}lwvrx-p*I_*D%h4%9p-m_|=RXSy+UN}} zJX}b88j|CcYeRjB%^i9Dnar8engVGmzL(;2{#I}}jU-7WH*^rE^m~<_3aU!NDal|* z=v9p@m@dL?`r&4Y$dv`I=lpk(Un|}^K3aau;M&n(C!lymB(b@L*N-}bst;M6M(2!CF%vR>~twuo@73S(s1N}-Y?&w?u zNEn}-1ZVUummy&3P=_6wV*C6S;Q}K#q@N17vGut%X0!fh0>R4m(a&UR@JmnS9|6DuTNE{63`s0n$`_5rO=EIe0qrLY#Jtrkcubj zZ96z2AfIUgSw_jO$sck^7jy+PleC@BUf4Rh7<|3epdNe}*li)>LP*eBw-|qXQHYDb zAy9rV-a*4+N~Dn-1OVt|V0n#Ni?2cB7ZhI2Fn=)ncl3wc6NfWbP%e6Ca&_Te$gf<>QNdb(LA#^60z{G3sin zC82AKOw^6BN2J)XV~jAGxjU&SSs!ZuQ&IZN%pSJ;VAh_3O8NlW=7_eu5z!&Rye)8> zmV_cFwCH9;l!OIy-1l@%H>}rX%5%^3!KB_Td-MRzd9a$5g;K>`Tx%*gOC)O9dZ$1T zBt2pw`7_)L*ujnGI<2S&f6FdY(n$aA@gnL~SAv&GZLaIkP?$I5E)XKcjt1s!03eqA zHimKhcJ9U72&DFb;9}B=s)brEYU^F@+E?@Da5Ln-0j7&d8TD3o7s!OrOnkCrraTPM z|6nIKp&yO~qTtabuaEA11o|GKZl&2Lit`xh!U)_3^g)N1{!!E>K9u>#kL1KheLSXTouo`33mg&>QK0uU$~ z_~mBL6DBUEQP46X9R|>@w~`)^ALYfie_u7=MSes=@UydX{@f60qGGlm-^*Cox^OU0k0_>trunyGx$ALK(j zuo=SB3n%tL9KxH}o%an;lmW+KRonBC-j~7jE?eJ71Bo+KO~8|EOXd%5iKhxEF0JSy zWUh#Up3^i-9}I3}uZ4~IJ>Y^mW2o;b7n2Hv=jhLpqc%f!7b|R+s~Xf7j_|j1)^;**@@3(uz((=gkpizwtfhyd5<2Q7<*%#iKY0 zY1(jGdPQh>_)3~sui{{z6i4BEnrR^CAoykdgG)2QOIsha?T}_==mQHkDY;9AZE$_0 z7h&`LkIiuYxg#DgijSQKGjz=wZboqWrBn2xMd*sSigT7&Z%w8jMib2~UqCdQKq2l&R+ND08{|c#swU}H#uZq2;9PC4=Wkr{FKcbp-nBXHN6^DD><$*)hSAUWSxf}*n8)Nn5 z7XlO+HkjOi-uafm+fbWoscOd=S~Brx2d>`3>N_l6iGqk=iX<-}+qiS#a#0rg(u2B# zRf&(r&>ptOWBCp)4Z1)v`Xq_%HVO@yC(6SCxd{nUm@1z_IpE=Cz#Tx<)r#h3W}%N# zRb!|X?A)?>-wXQsRHh@}TI;ul>haBV zz6@exWazEyxbBXxVZklDn$V@yH!S#g;rP3bwFW#|Z1pj2Np4ZpY2kKS*FU_I7O(y_L>?IM-P;y=rF#vV_!l)FS0@-e zjKBJxBCxEpjNSh|<&VoMOZD}w&%9u~^(LF= zJi zr!2|ox3J|bH;KWuPaYgd=UOeztxuyJ?o85%N$>jp6L&|3*uDgo;!Aotb@++%84LllRl8Pwf!jLSlk&wl`a$dc}AR2Wh3< zqZN!Io}hrfs6kb`)wwu_nTv2XF`jGkS)H5gFHc>ZYoAN@O*~Nt-y6G{oac~Y(4`;l z_fXzzI+1kFvd~V&;qYD6kb&6d8!1oR)Z;H)QTS;G^lpQ1M?$_t?1T?m!)r5+bFMzu z<~4Uvy>QpUWL&lN50lsFpKDj_wTkvr(hIaTetWfQ+@|-jt`nqwO9>y>iB*7>(GRQ~ z8W9pT?>uPzbQB+%JV5gZ+S;fv&`TtDk9Mfl#}1vwd5kuf`s#XroWDN3)IDs#@nqvk ztE9{9x0z-wn%8nYAx2)tJMKo6{ zgcoX%OV+)+Zp6!zZ{T>{Zp@8Ia7jESJhd{C%TRkHkC9iI1}o}!+VO8&RcXn#w*KhT z{Of0n&iyjw7Rb1FczwERY25mP^u;Sq*l3rvaqXCAA1EkoLZ|Bw-}b>`*2Sf%t9ZuO z+CHu?bQ<(IpeIvsI`rxW)T4cA;a~lJE>~d&{fgdLMYK*ydX1tlhG;e?aIa_uRTk73 zbYIfY#BfQz@!Qxe5SV!x)|?#1CNiuyZ~sAnfpy4avGnF+*`#fCE&bBHyCdam zW+N4cA6)+a-FDfVZho9xaos0<$H?32g2~&xI@$buzs)f=c`9kAJ)fQBAH$`lJ-MYW z8^6|*32yF&ShczEQ=M^+s2j-sG{1hCe=KJLkhxIY7QN(Rd_^0JGoSw zY3dSXPp7wDmRflmtR%0P)Q!ioN>?zBdoA^?8;uGQ-GV#I-`;38U74hksCe*lYv)(l zTu=q4(&6Ezyw#7?kbcgo_$-wl)aimP*^&&I)&~5*zoyM*kjbDfe_l{8_a9XGtZkP6KEL;1i>t%QRLgs$ zXjgk=z~{!|nDfV}C5_96J~pil5tkQ*UH1~h3^XpG{p^}nN}ZZ|e|HAF+z5Kjec|B2 zXp$dcHeSHS&Drb!Ywy}0q1^VqPRZ#ayDJq=8;KW}|VNF54xHYiKZ3ZZjE!h|JSt&i8S8_q%_4|AF_n_5G~1zH6=T zeLXz$3b5yx>OH<>+IPTgf4xLb#dD>C*Wqh1| z(SB0#MHs=;x$)=PMtPF;?#PaofvA7KA4u51Nbf&*^%uP!)a`x#$!CkU!lx@06clW* zuh%PtuYup1RZw6pfzL@PDC}JH|6Tu=G|uO5Jfw>p25FfaMg@71(1~t|(m#Og*i#nD zSKg-TNB9n?hkmX63riVZsi-+ntQ1SUD<^Ze zoAm=Mb8qto&Hl@2;D-VS!?jz8%)fXQB+HH*ommVF!_RLJR`_*C=Y8WLnC{x_%x|Qm z6yg2}JY6_$9Huirb?$%q-N;iZmJKSt|GUXf1N8>lRv7EVXEVDl_IIRzTV^cCDDC_i zl~mI-#2mU=DaFOaucz#{&t3=0-0-ou@$;(-9NbEvTrx$28LHDU1EU-qw&!p3%?z&$ zG#qHwCQB`O1t zr#tNXUDx!uD%hEF|HV)A(Z%dl8gK?-I*BlInb;W3st$zVfuO5utaGo03F-Q zzPK)zJrVE)D%d`At;v%G>!uBrYm0DdK)c)*eIRO!0>@N&@yK%kzHumxH34EeZSygm zuOB7c_+HpEEBFqxLdIMn`(vX!2e%daT_Qy9`cJovGzRl&;Xpenvm@v}hlAgCCZGz~ zj7=cTdA_3Qr?KmEDr;cGE;sTx-K}Zcw%RU#f)fA_&$U+Sy0z?G2fnCKIZD*|t}8k8 z62igl1lpxY)R(wNl&92`-W0|H!0GiWoT>c7julr2A!F3ho?_VTAT{np8)qafdEyJ0 zB6iGp(fgb(N+qlLT8=idXfeopM~Y!NcT}F5Am4m#!%5{~cq{9GNd1`?U(nmzl*_+^|{WS>B^)8nR&i zD%j|)#_%h`Q+01tHx==KR(QCiwNSU5)%>_8162gte8;W3VFE?8ZgPcl$hQ%-4j#`w zLwR#<@QX~Mi+PcZBkFW@Y1-CK3~ro10sxCZ{hXKP>eUihifPn!xTw?>3Bd}_8CBSr z0@?~bH)ChSuwxb)A}fGL`20@eON{l?Hv$6%M9dnety&*ZpRlYB4P(a=wr4U*Dex*e zv|CI~Wml;Fm{~N=Kir=;qyY`oPD{BYyNkK%I`YCQ~a@DZ`*1fBK7W z2=av0RbUj0Dq?cpXz4HI{JLf1zL)7D=%278R0JOGPnfC$zvl3M259GfQGJ+K3#Bx* zY5pa)x?PHU^K{r@MzlIH1Fc?Q63whIb~Iw_IYZltEQ2}W`)}P%&0|?Dy?Z7V-41}c z!(yww_3lmEIDUA4!fHV7Igfgu)c1~g&0<~`= z2a}0QE=})mZT-L6DKx{swef$oBWXs|zT~m;Zcc_d%oi=YV?TzLvaGVJTJE9SVcqBP zw}P1EMB*=Z)lCRPDKDmqGVEaBGxgR0hB|NG4hl~iQz7eYl4xPN)v+RX_g0o!>HqlW zONrKcK+3k2U6h&$2a@%9hRAI&_HgMf9cH=XtW8iQ#ck&P3K-+LTH^qPAuWCqa4-Q~ zf@#Us;wE31N&RnR-ww!g-lvK7(cR^#R#54c&Y47v_z?s!b>dP!T%j}$UJDA4&i861 z8R1**Wl zs*I3o09eMBT6|%YZ9EimMMO*-xefLjo(2@0j%UgEdB^@ON%9ZaL=AStfdj?6Ma0C@ zdb+cUAZ3=Z3z|EYSbq!o$RT1zxT^>1l(;F|EbeE!GU@P~Kz9S6@!G~Czh{p0*9qx} zhBG<2)i`=)rc&@)4qjgwxZV>?^aBQO#A3tw3%oCR zyW`{^Dz zsk7%6ayJ{c-NNgA+q#1^D~N2!A9faZe?L`3^uXrc6y3Au=d7RZtE(tO1-knHLywZ{ zdQD5%`hhi_5>@b`@Q^5JQaSIG|6oVyWj`L~!*xExCieBA$@}NH%7WnK*seRB+wr?cd>cJg@)~I* zKw9uMX3tI->5>*~l?mB6yl=fwmm-g|9fTX}qN6pPzVPqT;5Qnrb8KWtn$h-~x^al~ z4z9m&Ct?rlV#z@@O_wqr7xZB06{BtTMpH9w3S+HLyE6LgI!|3ne_X@yS0yE6zWr2D zzXf!8B#SPaT+TSrgpf|<6H@Xw8Q>8hx_aS`nyXRTeK4Y!#LuQYQtN&D-VUpo6pCX$| zu8pl8s@SwfRhIJN6a_qICsTC3J~ZCs3Kt*z|GL(-_&?|Uf4Iiokb z{CHT<%k?C4L_cw<>~nTgRr+G9Z5u$e7=DsmB=X}TzsGIei=)Ne=q=uk*h8#!3cL}W zXN%0xAEY+Ov(V{U`Q?#6*9(FjU@PZ;Y2NmD9cgaZE|lgo!vybPwVBE!ONTsk(h|Lb z8)+P{H7^5A3$Lhy z>bmU5MNV95s>{y_PmEKm@MPM|W(Xs!Cv1I7O1-fE!SW(`3zxqTBeEAHw|cfCM`XvP zGF{wgvadA~JOS9aSyW29Z%ABokzNQI6NbOW%bSUVo$xqPkx}6fOiiq1^qh#uJoNqDtq%Z&)z6; zKE|IYh($4@YiUmp4UO{FL3MX`Y1k7s74Abe{}bHYMp+~}03vd3%90NcK4QpG%(vNyhx28CF#Gv*di3#7&{l)5TDBaX9xU@wPm;bP03BZI$G5D~ zfh+x38t7{}SENol)TGl^{PhFgq|Gp5#Fst*MiM^&aj31Jzb`8(ij2R>NT*LuW*DBM zW2qM=pW=Nw*@9IyoA$aNuK7cJpZZ^N5l zlYxS`5q$RJr9<+2F!HKn^c=lgZwBw9bK;Y_(Pdh_t^Vfr*_$1H@^@IbL-Zu^YNcLv z5`i-QT};q0g?`>T!b-Pk{xBTMqe`uvr|(}N2#K+&i;ch84tHrk`H!HvvY_6S~V%Ye?`6DvNi8WL0){@TCNI0NmcS`ZTJ_6U2B+(#r|Aj^liXWSQa^{{s)ODrNqA zh$|g?Y6evZm1cRTDQ_-vj~k9)rV$238axBpAs|5LXQiyHq*}|y#%CX>-5-%EYMv;< z9IATTL`3ZyU-{F2U`4afm>OyPZCL$9?k)1(dJxw1$}A6yt9!5}nQ=l#voc+{H^=#_ zpJ~apXR>1}8W$;;--4fLv2tC{(+=*Yp3zo~sdAJw9E1d6aAo>~1Q!Xmm*~Ax-RCSd zKI*vm)B6{kym6Gf!~U9gpiFu%R6y9bNP(s0Noub!ct2Szu2ea5V)QyEhs5AnT9l>o zdwSZKq$$e1&|6mdhTSZ=3plDPDx=aLv2M((!QD- zddH#*y`wkc@#%J0sx+KEc*^3z$2E-Yf!%!x2?eHYlh?29Lw})NxQeLo#a+SUHgIRy z<2R6Vh*x;}sg7C2fcqP`kS;t7;y|m-~~ZWQ1-2PPD7$jNWi$p=!rQiqx3ZYI|$W7w&V97J9E#_2H_uSHIP%xuVw@rALfL4<+ct$H^6a@5L^EcD+Um Q%vr(O(!nDC$dAAN2mF+6CjbBd literal 0 HcmV?d00001 diff --git a/macOS/SearchifyX/Assets.xcassets/QuizletIcon.imageset/Contents.json b/macOS/SearchifyX/Assets.xcassets/QuizletIcon.imageset/Contents.json new file mode 100644 index 0000000..7b14d60 --- /dev/null +++ b/macOS/SearchifyX/Assets.xcassets/QuizletIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "AppLogo-Quizlet copy.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift new file mode 100644 index 0000000..96e6c5d --- /dev/null +++ b/macOS/SearchifyX/ContentView.swift @@ -0,0 +1,119 @@ +// +// ContentView.swift +// SearchifyX +// +// Created by Jose Molina on 9/2/22. +// + +import SwiftUI + +let scraper = Scraper() + +struct ContentView: View { + @State var question: String = "" + @State var enableQuizizz: Bool = true + @State var enableQuizlet: Bool = true + @State var cards: [Flashcard] = [] + @State var selected: Flashcard.ID? + @State var searching: Bool = false + @State var engine: String = "google" + + var body: some View { + VStack { + HStack { + TextField("Search a question here", text: $question) + Button( + action: { + searching = true + print(engine) + + var sites: [String] = [] + + if enableQuizizz { + sites.append("quizizz") + } + if enableQuizlet { + sites.append("quizlet") + } + + cards = scraper.search(query: question, sites: sites.joined(separator: ","), engine: engine) + searching = false + }, + label: { + Image(systemName: "magnifyingglass") + Text("Search") + } + ) + Button( + action: { + var clipboardItems: [String] = [] + for element in NSPasteboard.general.pasteboardItems! { + if let str = element.string(forType: NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text")) { + clipboardItems.append(str) + } + } + + question = clipboardItems[0] + }, + label: { + Image(systemName: "doc.on.clipboard") + } + ) + } + .disabled(searching != false) + .padding() + + Table(cards, selection: $selected) { + TableColumn("Question", value: \.question) + TableColumn("Answer", value: \.answer) + TableColumn("Similarity", value: \.similarity) + TableColumn("URL", value: \.url) + } + + HStack { + Spacer() + Picker("Search Engine", selection: $engine) { + Text("Google").tag("google") + Text("Bing").tag("bing") + Text("Startpage").tag("startpage") + } + Button(action: { + var original: Flashcard? + + for item in cards { + if (item.id == selected) { + original = item + break + } + } + + let url = URL(string: original!.url)! + NSWorkspace.shared.open(url) + + }, label: { + Text("Open question") + }) + .disabled(selected == nil) + Toggle(isOn: $enableQuizizz) { + Image("QuizizzIcon") + .resizable() + .frame(width: 16, height: 16) + Text("Quizizz") + } + Toggle(isOn: $enableQuizlet) { + Image("QuizletIcon") + .resizable() + .frame(width: 16, height: 16) + Text("Quizlet") + } + } + .padding() + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/macOS/SearchifyX/Flashcard.swift b/macOS/SearchifyX/Flashcard.swift new file mode 100644 index 0000000..14a68b4 --- /dev/null +++ b/macOS/SearchifyX/Flashcard.swift @@ -0,0 +1,16 @@ +// +// Flashcard.swift +// SearchifyX +// +// Created by Jose Molina on 9/2/22. +// + +import Foundation + +struct Flashcard: Identifiable, Codable { + let question: String + let answer: String + let url: String + let similarity: String + var id = UUID() +} diff --git a/macOS/SearchifyX/Scraper.swift b/macOS/SearchifyX/Scraper.swift new file mode 100644 index 0000000..aeb7d39 --- /dev/null +++ b/macOS/SearchifyX/Scraper.swift @@ -0,0 +1,40 @@ +// +// Scraper.swift +// SearchifyX +// +// Created by Jose Molina on 9/2/22. +// + +import Foundation +import PythonKit + +class Scraper { + func search(query: String, sites: String, engine: String) -> [Flashcard] { + let proc = Process() + let exec = Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/scraper.app/Contents/MacOS/scraper") + proc.executableURL = exec + + let tempDir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) + let tempFile = ProcessInfo().globallyUniqueString + + let tempPath = tempDir.appendingPathComponent(tempFile) + var json: String = "" + + do { + try "".write(to: tempPath, atomically: true, encoding: .utf8) + print(tempPath.path) + proc.arguments = ["-q", query, "-s", sites, "-e", engine, "-o", tempPath.path] + print("Launching python process now") + try proc.run() + proc.waitUntilExit() + + json = try String(contentsOf: tempPath, encoding: .utf8) + } + catch { + print("Error occurred trying to run the scraper") + } + + let result = try? JSONDecoder().decode([Flashcard].self, from: json.data(using: .utf8)!) + return result! + } +} diff --git a/macOS/SearchifyX/SearchifyXApp.swift b/macOS/SearchifyX/SearchifyXApp.swift new file mode 100644 index 0000000..9939bf7 --- /dev/null +++ b/macOS/SearchifyX/SearchifyXApp.swift @@ -0,0 +1,17 @@ +// +// SearchifyXApp.swift +// SearchifyX +// +// Created by Jose Molina on 9/2/22. +// + +import SwiftUI + +@main +struct SearchifyXApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} diff --git a/macOS/build.sh b/macOS/build.sh new file mode 100755 index 0000000..953807a --- /dev/null +++ b/macOS/build.sh @@ -0,0 +1,16 @@ +#!/bin/zsh + +# Get package requirements +pip3 install -r requirements.txt + +# Create setup.py file +py2applet --make-setup ../scraper.py + +# Generate app +python3 setup.py py2app + +# Delete old scraper.app +rm -r ./SearchifyX/scraper.app + +# Copy newest scraper.app +cp -R ./dist/scraper.app ./SearchifyX/ \ No newline at end of file diff --git a/macOS/clean.sh b/macOS/clean.sh new file mode 100755 index 0000000..7a8f27c --- /dev/null +++ b/macOS/clean.sh @@ -0,0 +1,7 @@ +#!/bin/zsh + +# Remove build directories +rm -r ./build/ +rm -r ./dist/ + +rm setup.py \ No newline at end of file diff --git a/macOS/requirements.txt b/macOS/requirements.txt new file mode 100644 index 0000000..3d0c76a --- /dev/null +++ b/macOS/requirements.txt @@ -0,0 +1,6 @@ +beautifulsoup4==4.11.1 +fake_headers==1.0.2 +grequests==0.6.0 +requests_html==0.10.0 +setuptools==63.2.0 +py2app==0.28.2 From 9e566c54dbe3c1d49243b1731cea92fa802e50b9 Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Sat, 3 Sep 2022 21:09:46 -0500 Subject: [PATCH 12/39] Update Scraper.swift --- macOS/SearchifyX/Scraper.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/macOS/SearchifyX/Scraper.swift b/macOS/SearchifyX/Scraper.swift index aeb7d39..4192363 100644 --- a/macOS/SearchifyX/Scraper.swift +++ b/macOS/SearchifyX/Scraper.swift @@ -6,7 +6,6 @@ // import Foundation -import PythonKit class Scraper { func search(query: String, sites: String, engine: String) -> [Flashcard] { From aa1850c3a083b8cfa86b952fecb0b2981b00ac14 Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Mon, 5 Sep 2022 01:53:23 -0500 Subject: [PATCH 13/39] Made code async and do catches --- macOS/SearchifyX.xcodeproj/project.pbxproj | 2 -- macOS/SearchifyX/ContentView.swift | 6 ++++-- macOS/SearchifyX/Flashcard.swift | 2 +- macOS/SearchifyX/Scraper.swift | 11 +++++++++-- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/macOS/SearchifyX.xcodeproj/project.pbxproj b/macOS/SearchifyX.xcodeproj/project.pbxproj index 66847a2..b31f989 100644 --- a/macOS/SearchifyX.xcodeproj/project.pbxproj +++ b/macOS/SearchifyX.xcodeproj/project.pbxproj @@ -270,7 +270,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; - CODE_SIGN_ENTITLEMENTS = SearchifyX/SearchifyX.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; @@ -300,7 +299,6 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; - CODE_SIGN_ENTITLEMENTS = SearchifyX/SearchifyX.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift index 96e6c5d..311456c 100644 --- a/macOS/SearchifyX/ContentView.swift +++ b/macOS/SearchifyX/ContentView.swift @@ -36,8 +36,10 @@ struct ContentView: View { sites.append("quizlet") } - cards = scraper.search(query: question, sites: sites.joined(separator: ","), engine: engine) - searching = false + DispatchQueue.global(qos: .userInitiated).async { + cards = scraper.search(query: question, sites: sites.joined(separator: ","), engine: engine) + searching = false + } }, label: { Image(systemName: "magnifyingglass") diff --git a/macOS/SearchifyX/Flashcard.swift b/macOS/SearchifyX/Flashcard.swift index 14a68b4..ce7cdf6 100644 --- a/macOS/SearchifyX/Flashcard.swift +++ b/macOS/SearchifyX/Flashcard.swift @@ -12,5 +12,5 @@ struct Flashcard: Identifiable, Codable { let answer: String let url: String let similarity: String - var id = UUID() + let id = UUID() } diff --git a/macOS/SearchifyX/Scraper.swift b/macOS/SearchifyX/Scraper.swift index 4192363..700a9b8 100644 --- a/macOS/SearchifyX/Scraper.swift +++ b/macOS/SearchifyX/Scraper.swift @@ -31,9 +31,16 @@ class Scraper { } catch { print("Error occurred trying to run the scraper") + return [] } - let result = try? JSONDecoder().decode([Flashcard].self, from: json.data(using: .utf8)!) - return result! + do { + let result = try JSONDecoder().decode([Flashcard].self, from: json.data(using: .utf8)!) + return result + } + catch { + print("An unexpected error occurred: \(error)") + return [] + } } } From ab6d3a1d3ed32f4f18e49a1f2954b9fccb176690 Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Mon, 5 Sep 2022 16:19:33 -0500 Subject: [PATCH 14/39] Added loading indicator --- macOS/SearchifyX/ContentView.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift index 311456c..3b1fc19 100644 --- a/macOS/SearchifyX/ContentView.swift +++ b/macOS/SearchifyX/ContentView.swift @@ -65,11 +65,16 @@ struct ContentView: View { .disabled(searching != false) .padding() - Table(cards, selection: $selected) { - TableColumn("Question", value: \.question) - TableColumn("Answer", value: \.answer) - TableColumn("Similarity", value: \.similarity) - TableColumn("URL", value: \.url) + ZStack { + Table(cards, selection: $selected) { + TableColumn("Question", value: \.question) + TableColumn("Answer", value: \.answer) + TableColumn("Similarity", value: \.similarity) + TableColumn("URL", value: \.url) + } + if searching { + ProgressView() + } } HStack { From 8966263ec7627c6cc40c4896d1e48a8afd76e304 Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Tue, 6 Sep 2022 22:07:21 -0500 Subject: [PATCH 15/39] Window detection, OCR, and refactor --- .gitignore | 3 + macOS/SearchifyX.xcodeproj/project.pbxproj | 4 + .../UserInterfaceState.xcuserstate | Bin 44306 -> 62841 bytes macOS/SearchifyX/AppDelegate.swift | 46 +++++++++++ macOS/SearchifyX/ContentView.swift | 31 ++++++- macOS/SearchifyX/FlashcardRow.swift | 28 +++++++ macOS/SearchifyX/FloatingPanel.swift | 27 ++++++ macOS/SearchifyX/ModEx.swift | 53 ++++++++++++ macOS/SearchifyX/Scraper.swift | 77 +++++++++++++++--- macOS/SearchifyX/SearchifyXApp.swift | 2 +- 10 files changed, 259 insertions(+), 12 deletions(-) create mode 100644 macOS/SearchifyX/AppDelegate.swift create mode 100644 macOS/SearchifyX/FlashcardRow.swift create mode 100644 macOS/SearchifyX/FloatingPanel.swift create mode 100644 macOS/SearchifyX/ModEx.swift diff --git a/.gitignore b/.gitignore index 1afdaae..95ed708 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ windoweffect/__pycache__/ # scraper.app must be rebuilt because of the amount of files macOS/SearchifyX/scraper.app +# Xcode +xcuserdata/ + # General .DS_Store .AppleDouble diff --git a/macOS/SearchifyX.xcodeproj/project.pbxproj b/macOS/SearchifyX.xcodeproj/project.pbxproj index b31f989..dde7791 100644 --- a/macOS/SearchifyX.xcodeproj/project.pbxproj +++ b/macOS/SearchifyX.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214676F28C1CFB500E9D706 /* Flashcard.swift */; }; 4214677528C1D99300E9D706 /* Scraper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214677428C1D99300E9D706 /* Scraper.swift */; }; 4214677928C2887F00E9D706 /* scraper.app in Resources */ = {isa = PBXBuildFile; fileRef = 4214677828C2887F00E9D706 /* scraper.app */; }; + 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -23,6 +24,7 @@ 4214676F28C1CFB500E9D706 /* Flashcard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flashcard.swift; sourceTree = ""; }; 4214677428C1D99300E9D706 /* Scraper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scraper.swift; sourceTree = ""; }; 4214677828C2887F00E9D706 /* scraper.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = scraper.app; sourceTree = ""; }; + 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -61,6 +63,7 @@ 4214674828C1C5F200E9D706 /* Assets.xcassets */, 4214676F28C1CFB500E9D706 /* Flashcard.swift */, 4214677428C1D99300E9D706 /* Scraper.swift */, + 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */, ); path = SearchifyX; sourceTree = ""; @@ -143,6 +146,7 @@ 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */, 4214674728C1C5EF00E9D706 /* ContentView.swift in Sources */, 4214674528C1C5EF00E9D706 /* SearchifyXApp.swift in Sources */, + 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate index 7a188d60987d7b3b01776033c541a56abdd42efb..e4314f9010e840e052a2a7815858fdee63427b4a 100644 GIT binary patch literal 62841 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 z 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 OYQH=N_vPc9@&5wAQBM2- delta 23111 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: ViewModifier { + @Binding var isPresented: Bool + + var contentRect: CGRect = CGRect(x: 0, y: 0, width: 624, height: 512) + + @ViewBuilder let view: () -> PanelContent + + @State var panel: FloatingPanel? + + func body(content: Content) -> some View { + content + .onAppear { + panel = FloatingPanel(view: view, contentRect: contentRect, isPresented: $isPresented) + panel?.center() + if isPresented { + present() + } + }.onDisappear { + panel?.close() + panel = nil + }.onChange(of: isPresented) { value in + if value { + present() + } else { + panel?.close() + } + } + } + + func present() { + panel?.orderFront(nil) + panel?.makeKey() + } +} + +extension View { + func floatingPanel(isPresented: Binding, + contentRect: CGRect = CGRect(x: 0, y: 0, width: 624, height: 512), + @ViewBuilder content: @escaping () -> Content) -> some View { + self.modifier(FloatingPanelModifier(isPresented: isPresented, contentRect: contentRect, view: content)) + } +} diff --git a/macOS/SearchifyX/Scraper.swift b/macOS/SearchifyX/Scraper.swift index 700a9b8..29d2008 100644 --- a/macOS/SearchifyX/Scraper.swift +++ b/macOS/SearchifyX/Scraper.swift @@ -6,41 +6,98 @@ // import Foundation +import AppKit +import Vision class Scraper { func search(query: String, sites: String, engine: String) -> [Flashcard] { let proc = Process() - let exec = Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/scraper.app/Contents/MacOS/scraper") - proc.executableURL = exec + proc.executableURL = + Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/scraper.app/Contents/MacOS/scraper") let tempDir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let tempFile = ProcessInfo().globallyUniqueString let tempPath = tempDir.appendingPathComponent(tempFile) + proc.arguments = ["-q", query, "-s", sites, "-e", engine, "-o", tempPath.path] + var json: String = "" do { try "".write(to: tempPath, atomically: true, encoding: .utf8) - print(tempPath.path) - proc.arguments = ["-q", query, "-s", sites, "-e", engine, "-o", tempPath.path] - print("Launching python process now") try proc.run() proc.waitUntilExit() json = try String(contentsOf: tempPath, encoding: .utf8) + let result = try JSONDecoder().decode([Flashcard].self, from: json.data(using: .utf8)!) + return result } catch { - print("Error occurred trying to run the scraper") + print("Error occurred trying to run the scraper: \(error)") return [] } + } + + func ocr() -> String { + let proc = Process() + let exec = URL(fileURLWithPath: "/usr/sbin/screencapture") + proc.executableURL = exec + proc.arguments = ["-i", "-c"] do { - let result = try JSONDecoder().decode([Flashcard].self, from: json.data(using: .utf8)!) - return result + try proc.run() + proc.waitUntilExit() + + var data: Data? + + for element in NSPasteboard.general.pasteboardItems! { + if let img = element.data(forType: NSPasteboard.PasteboardType(rawValue: "public.png")) { + data = img + } + } + + let requestHandler = VNImageRequestHandler(data: data!) + let req = VNRecognizeTextRequest(completionHandler: nil) + + try requestHandler.perform([req]) + + let observations = req.results + + let recognizedStrings = observations!.compactMap { observation in + // Return the string of the top VNRecognizedText instance. + return observation.topCandidates(1).first?.string + } + + if recognizedStrings.isEmpty { + alert(caption: "Unable to run the OCR", msg: "No text was detected") + return "" + } + + return recognizedStrings.joined() } catch { - print("An unexpected error occurred: \(error)") - return [] + print("An error occurred trying to run the OCR: \(error)") + alert(caption: "Unable to run the OCR", msg: "An error occurred while trying to run or process the OCR") + return "" + } + } + + func alert(caption: String, msg: String) { + DispatchQueue.main.async { + let alert = NSAlert() + alert.messageText = caption + alert.informativeText = msg + alert.addButton(withTitle: "OK") + alert.alertStyle = .warning + alert.runModal() + } + } + + static func convertPercent(from input: String) -> Float { + if let res = Float(input.replacingOccurrences(of: "%", with: "")) { + return res / 100 + } else { + return 0 } } } diff --git a/macOS/SearchifyX/SearchifyXApp.swift b/macOS/SearchifyX/SearchifyXApp.swift index 9939bf7..8f07034 100644 --- a/macOS/SearchifyX/SearchifyXApp.swift +++ b/macOS/SearchifyX/SearchifyXApp.swift @@ -11,7 +11,7 @@ import SwiftUI struct SearchifyXApp: App { var body: some Scene { WindowGroup { - ContentView() + ContentView(isPanel: false) } } } From 7b2a24873cf95ac26ad438f8923058db60f039ac Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Tue, 6 Sep 2022 23:12:31 -0500 Subject: [PATCH 16/39] Add settings, and shortcuts --- macOS/SearchifyX.xcodeproj/project.pbxproj | 31 +++++++++++++ .../xcshareddata/swiftpm/Package.resolved | 14 ++++++ macOS/SearchifyX/Constants.swift | 13 ++++++ macOS/SearchifyX/ContentView.swift | 46 ++++++++++++------- macOS/SearchifyX/SearchifyXApp.swift | 22 +++++++++ macOS/SearchifyX/SettingsView.swift | 33 +++++++++++++ 6 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 macOS/SearchifyX/Constants.swift create mode 100644 macOS/SearchifyX/SettingsView.swift diff --git a/macOS/SearchifyX.xcodeproj/project.pbxproj b/macOS/SearchifyX.xcodeproj/project.pbxproj index dde7791..34a6117 100644 --- a/macOS/SearchifyX.xcodeproj/project.pbxproj +++ b/macOS/SearchifyX.xcodeproj/project.pbxproj @@ -14,6 +14,9 @@ 4214677528C1D99300E9D706 /* Scraper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214677428C1D99300E9D706 /* Scraper.swift */; }; 4214677928C2887F00E9D706 /* scraper.app in Resources */ = {isa = PBXBuildFile; fileRef = 4214677828C2887F00E9D706 /* scraper.app */; }; 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */; }; + 42E9579B28C84C0E00BF7B3B /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 42E9579A28C84C0E00BF7B3B /* KeyboardShortcuts */; }; + 42E9579D28C84C6900BF7B3B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9579C28C84C6900BF7B3B /* SettingsView.swift */; }; + 42E9579F28C84DAC00BF7B3B /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9579E28C84DAC00BF7B3B /* Constants.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -25,6 +28,8 @@ 4214677428C1D99300E9D706 /* Scraper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scraper.swift; sourceTree = ""; }; 4214677828C2887F00E9D706 /* scraper.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = scraper.app; sourceTree = ""; }; 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanel.swift; sourceTree = ""; }; + 42E9579C28C84C6900BF7B3B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + 42E9579E28C84DAC00BF7B3B /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -32,6 +37,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 42E9579B28C84C0E00BF7B3B /* KeyboardShortcuts in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -64,6 +70,8 @@ 4214676F28C1CFB500E9D706 /* Flashcard.swift */, 4214677428C1D99300E9D706 /* Scraper.swift */, 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */, + 42E9579C28C84C6900BF7B3B /* SettingsView.swift */, + 42E9579E28C84DAC00BF7B3B /* Constants.swift */, ); path = SearchifyX; sourceTree = ""; @@ -85,6 +93,7 @@ ); name = SearchifyX; packageProductDependencies = ( + 42E9579A28C84C0E00BF7B3B /* KeyboardShortcuts */, ); productName = SearchifyX; productReference = 4214674128C1C5EF00E9D706 /* SearchifyX.app */; @@ -115,6 +124,7 @@ ); mainGroup = 4214673828C1C5EF00E9D706; packageReferences = ( + 42E9579928C84C0E00BF7B3B /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */, ); productRefGroup = 4214674228C1C5EF00E9D706 /* Products */; projectDirPath = ""; @@ -145,6 +155,8 @@ 4214677528C1D99300E9D706 /* Scraper.swift in Sources */, 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */, 4214674728C1C5EF00E9D706 /* ContentView.swift in Sources */, + 42E9579D28C84C6900BF7B3B /* SettingsView.swift in Sources */, + 42E9579F28C84DAC00BF7B3B /* Constants.swift in Sources */, 4214674528C1C5EF00E9D706 /* SearchifyXApp.swift in Sources */, 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */, ); @@ -348,6 +360,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 42E9579928C84C0E00BF7B3B /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/sindresorhus/KeyboardShortcuts"; + requirement = { + branch = main; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 42E9579A28C84C0E00BF7B3B /* KeyboardShortcuts */ = { + isa = XCSwiftPackageProductDependency; + package = 42E9579928C84C0E00BF7B3B /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */; + productName = KeyboardShortcuts; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 4214673928C1C5EF00E9D706 /* Project object */; } diff --git a/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..bc354a9 --- /dev/null +++ b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "keyboardshortcuts", + "kind" : "remoteSourceControl", + "location" : "https://github.com/sindresorhus/KeyboardShortcuts", + "state" : { + "branch" : "main", + "revision" : "5e674337c13f9d0f8ff72d9d39ded08ce9bb7e34" + } + } + ], + "version" : 2 +} diff --git a/macOS/SearchifyX/Constants.swift b/macOS/SearchifyX/Constants.swift new file mode 100644 index 0000000..9da3b11 --- /dev/null +++ b/macOS/SearchifyX/Constants.swift @@ -0,0 +1,13 @@ +// +// Constants.swift +// SearchifyX +// +// Created by Jose Molina on 9/6/22. +// + +import Foundation +import KeyboardShortcuts + +extension KeyboardShortcuts.Name { + static let openSearchify = Self("openSearchify") +} diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift index 1135d4d..9e912c3 100644 --- a/macOS/SearchifyX/ContentView.swift +++ b/macOS/SearchifyX/ContentView.swift @@ -19,6 +19,9 @@ struct ContentView: View { @State var engine: String = "google" @State var showingPanel: Bool = false + @AppStorage("runAfterOcr") var runAfterOcr: Bool = false + @AppStorage("runAfterPaste") var runAfterPaste: Bool = false + var isPanel: Bool var body: some View { @@ -42,22 +45,7 @@ struct ContentView: View { .lineLimit(nil) Button( action: { - searching = true - print(engine) - - var sites: [String] = [] - - if enableQuizizz { - sites.append("quizizz") - } - if enableQuizlet { - sites.append("quizlet") - } - - DispatchQueue.global(qos: .userInitiated).async { - cards = scraper.search(query: question, sites: sites.joined(separator: ","), engine: engine) - searching = false - } + searchQuestion() }, label: { Image(systemName: "magnifyingglass") @@ -74,6 +62,10 @@ struct ContentView: View { } question = clipboardItems[0] + + if runAfterPaste { + searchQuestion() + } }, label: { Image(systemName: "doc.on.clipboard") @@ -83,6 +75,10 @@ struct ContentView: View { action: { DispatchQueue.global(qos: .userInitiated).async { question = scraper.ocr() + + if runAfterOcr { + searchQuestion() + } } }, label: { @@ -146,6 +142,24 @@ struct ContentView: View { .padding() } } + + func searchQuestion() { + searching = true + + var sites: [String] = [] + + if enableQuizizz { + sites.append("quizizz") + } + if enableQuizlet { + sites.append("quizlet") + } + + DispatchQueue.global(qos: .userInitiated).async { + cards = scraper.search(query: question, sites: sites.joined(separator: ","), engine: engine) + searching = false + } + } } struct ContentView_Previews: PreviewProvider { diff --git a/macOS/SearchifyX/SearchifyXApp.swift b/macOS/SearchifyX/SearchifyXApp.swift index 8f07034..acec8ac 100644 --- a/macOS/SearchifyX/SearchifyXApp.swift +++ b/macOS/SearchifyX/SearchifyXApp.swift @@ -6,12 +6,34 @@ // import SwiftUI +import KeyboardShortcuts @main struct SearchifyXApp: App { + @StateObject private var appState = AppState() + var body: some Scene { WindowGroup { ContentView(isPanel: false) } + Settings { + SettingsView() + } + } +} + +@MainActor +final class AppState: ObservableObject { + init() { + KeyboardShortcuts.onKeyUp(for: .openSearchify) { [self] in + let ep = FloatingPanel(contentRect: NSRect(x: 0, y: 0, width: 900, height: 450), backing: .buffered, defer: false) + + ep.title = "Hidden SearchifyX" + ep.contentView = NSHostingView(rootView: ContentView(isPanel: true)) + + ep.center() + ep.orderFront(nil) + ep.makeKey() + } } } diff --git a/macOS/SearchifyX/SettingsView.swift b/macOS/SearchifyX/SettingsView.swift new file mode 100644 index 0000000..dfe01f8 --- /dev/null +++ b/macOS/SearchifyX/SettingsView.swift @@ -0,0 +1,33 @@ +// +// SettingsView.swift +// SearchifyX +// +// Created by Jose Molina on 9/6/22. +// + +import SwiftUI +import KeyboardShortcuts + +struct SettingsView: View { + @AppStorage("runAfterOcr") var runAfterOcr: Bool = false + @AppStorage("runAfterPaste") var runAfterPaste: Bool = false + + var body: some View { + VStack { + Toggle(isOn: $runAfterOcr) { + Text("Search after OCR text is pasted") + } + Toggle(isOn: $runAfterPaste) { + Text("Search after text is pasted") + } + KeyboardShortcuts.Recorder("Open Hidden SearchifyX", name: .openSearchify) + } + .padding() + } +} + +struct SettingsView_Previews: PreviewProvider { + static var previews: some View { + SettingsView() + } +} From 1d1f16302955ece1dc11f8e89a392e02862aebf4 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Wed, 7 Sep 2022 11:28:38 -0500 Subject: [PATCH 17/39] Remove unused files --- macOS/SearchifyX/AppDelegate.swift | 46 ------------------------- macOS/SearchifyX/FlashcardRow.swift | 28 --------------- macOS/SearchifyX/ModEx.swift | 53 ----------------------------- 3 files changed, 127 deletions(-) delete mode 100644 macOS/SearchifyX/AppDelegate.swift delete mode 100644 macOS/SearchifyX/FlashcardRow.swift delete mode 100644 macOS/SearchifyX/ModEx.swift diff --git a/macOS/SearchifyX/AppDelegate.swift b/macOS/SearchifyX/AppDelegate.swift deleted file mode 100644 index 1630191..0000000 --- a/macOS/SearchifyX/AppDelegate.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// AppDelegate.swift -// SearchifyX -// -// Created by Jose Molina on 9/6/22. -// - -import Foundation -import AppKit -import SwiftUI - -class AppDelegate: NSObject, NSApplicationDelegate { - var newEntryPanel: FloatingPanel! - - func applicationDidFinishLaunching(_ aNotification: Notification) { - if let window = NSApplication.shared.windows.first { - window.close() - } - - createFloatingPanel() - - // Center doesn't place it in the absolute center, see the documentation for more details - newEntryPanel.center() - - // Shows the panel and makes it active - newEntryPanel.orderFront(nil) - newEntryPanel.makeKey() - } - - func applicationWillTerminate(_ aNotification: Notification) { - // Insert code here to tear down your application - } - - private func createFloatingPanel() { - // Create the SwiftUI view that provides the window contents. - // I've opted to ignore top safe area as well, since we're hiding the traffic icons - let contentView = ContentView(isPanel: true) - .edgesIgnoringSafeArea(.top) - - // Create the window and set the content view. - newEntryPanel = FloatingPanel(contentRect: NSRect(x: 0, y: 0, width: 512, height: 80), backing: .buffered, defer: false) - - newEntryPanel.title = "Hidden SearchifyX" - newEntryPanel.contentView = NSHostingView(rootView: contentView) - } -} diff --git a/macOS/SearchifyX/FlashcardRow.swift b/macOS/SearchifyX/FlashcardRow.swift deleted file mode 100644 index 0030c47..0000000 --- a/macOS/SearchifyX/FlashcardRow.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// FlashcardRow.swift -// SearchifyX -// -// Created by Jose Molina on 9/6/22. -// - -import SwiftUI - -struct FlashcardRow: View { - let card: Flashcard - - var body: some View { - HStack { - ProgressView(value: Scraper.convertPercent(from: card.similarity)) - Text(card.question) - .fixedSize(horizontal: true, vertical: false) - Text(card.answer) - - } - } -} - -struct FlashcardRow_Previews: PreviewProvider { - static var previews: some View { - FlashcardRow(card: Flashcard(question: "What is biology?", answer: "Biology is the study of life", url: "https://google.com", similarity: "100%")) - } -} diff --git a/macOS/SearchifyX/ModEx.swift b/macOS/SearchifyX/ModEx.swift deleted file mode 100644 index c04bd1c..0000000 --- a/macOS/SearchifyX/ModEx.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// ModEx.swift -// SearchifyX -// -// Created by Jose Molina on 9/6/22. -// - -import Foundation - -import SwiftUI - -fileprivate struct FloatingPanelModifier: ViewModifier { - @Binding var isPresented: Bool - - var contentRect: CGRect = CGRect(x: 0, y: 0, width: 624, height: 512) - - @ViewBuilder let view: () -> PanelContent - - @State var panel: FloatingPanel? - - func body(content: Content) -> some View { - content - .onAppear { - panel = FloatingPanel(view: view, contentRect: contentRect, isPresented: $isPresented) - panel?.center() - if isPresented { - present() - } - }.onDisappear { - panel?.close() - panel = nil - }.onChange(of: isPresented) { value in - if value { - present() - } else { - panel?.close() - } - } - } - - func present() { - panel?.orderFront(nil) - panel?.makeKey() - } -} - -extension View { - func floatingPanel(isPresented: Binding, - contentRect: CGRect = CGRect(x: 0, y: 0, width: 624, height: 512), - @ViewBuilder content: @escaping () -> Content) -> some View { - self.modifier(FloatingPanelModifier(isPresented: isPresented, contentRect: contentRect, view: content)) - } -} From d00d329c53316b9e627be7a2e4080a69e5d6ec5f Mon Sep 17 00:00:00 2001 From: OmegaLol21 <48543854+LavamasterYT@users.noreply.github.com> Date: Wed, 19 Oct 2022 14:19:40 -0500 Subject: [PATCH 18/39] Stability, and it now works --- .gitignore | 7 +- macOS/SearchifyX.xcodeproj/project.pbxproj | 10 +- .../UserInterfaceState.xcuserstate | Bin 62841 -> 0 bytes macOS/SearchifyX/Constants.swift | 15 +-- macOS/SearchifyX/ContentView.swift | 60 ++++++------ macOS/SearchifyX/Flashcard.swift | 7 -- macOS/SearchifyX/Scraper.swift | 90 ++++++++++++++---- macOS/SearchifyX/SearchifyXApp.swift | 47 +++++---- macOS/SearchifyX/SettingsView.swift | 13 ++- macOS/build.sh | 9 +- macOS/clean.sh | 4 +- macOS/requirements.txt | 3 +- 12 files changed, 158 insertions(+), 107 deletions(-) delete mode 100644 macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/.gitignore b/.gitignore index 95ed708..f66ed3f 100644 --- a/.gitignore +++ b/.gitignore @@ -4,10 +4,13 @@ __pycache__/ windoweffect/__pycache__/ # scraper.app must be rebuilt because of the amount of files -macOS/SearchifyX/scraper.app +macOS/SearchifyX/scraper/ +macOS/build/ +macOS/dist/ +macOS/scraper.spec # Xcode -xcuserdata/ +xcuserdata # General .DS_Store diff --git a/macOS/SearchifyX.xcodeproj/project.pbxproj b/macOS/SearchifyX.xcodeproj/project.pbxproj index 34a6117..e11455f 100644 --- a/macOS/SearchifyX.xcodeproj/project.pbxproj +++ b/macOS/SearchifyX.xcodeproj/project.pbxproj @@ -12,7 +12,7 @@ 4214674928C1C5F200E9D706 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4214674828C1C5F200E9D706 /* Assets.xcassets */; }; 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214676F28C1CFB500E9D706 /* Flashcard.swift */; }; 4214677528C1D99300E9D706 /* Scraper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214677428C1D99300E9D706 /* Scraper.swift */; }; - 4214677928C2887F00E9D706 /* scraper.app in Resources */ = {isa = PBXBuildFile; fileRef = 4214677828C2887F00E9D706 /* scraper.app */; }; + 42C95D932900657A008936E3 /* scraper in Resources */ = {isa = PBXBuildFile; fileRef = 42C95D922900657A008936E3 /* scraper */; }; 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */; }; 42E9579B28C84C0E00BF7B3B /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 42E9579A28C84C0E00BF7B3B /* KeyboardShortcuts */; }; 42E9579D28C84C6900BF7B3B /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9579C28C84C6900BF7B3B /* SettingsView.swift */; }; @@ -26,7 +26,7 @@ 4214674828C1C5F200E9D706 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4214676F28C1CFB500E9D706 /* Flashcard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flashcard.swift; sourceTree = ""; }; 4214677428C1D99300E9D706 /* Scraper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scraper.swift; sourceTree = ""; }; - 4214677828C2887F00E9D706 /* scraper.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = scraper.app; sourceTree = ""; }; + 42C95D922900657A008936E3 /* scraper */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scraper; sourceTree = ""; }; 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanel.swift; sourceTree = ""; }; 42E9579C28C84C6900BF7B3B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 42E9579E28C84DAC00BF7B3B /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; @@ -63,7 +63,7 @@ 4214674328C1C5EF00E9D706 /* SearchifyX */ = { isa = PBXGroup; children = ( - 4214677828C2887F00E9D706 /* scraper.app */, + 42C95D922900657A008936E3 /* scraper */, 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */, 4214674628C1C5EF00E9D706 /* ContentView.swift */, 4214674828C1C5F200E9D706 /* Assets.xcassets */, @@ -140,8 +140,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4214677928C2887F00E9D706 /* scraper.app in Resources */, 4214674928C1C5F200E9D706 /* Assets.xcassets in Resources */, + 42C95D932900657A008936E3 /* scraper in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -289,7 +289,6 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = SearchifyX/scraper.app; DEVELOPMENT_TEAM = R5T6626VHW; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; @@ -318,7 +317,6 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = SearchifyX/scraper.app; DEVELOPMENT_TEAM = R5T6626VHW; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; diff --git a/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate b/macOS/SearchifyX.xcodeproj/project.xcworkspace/xcuserdata/josem.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index e4314f9010e840e052a2a7815858fdee63427b4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62841 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 z zt&-u%9?6JgpJY_>&SYxx-ehJnD>*wkH+g?@Q*wK9S8`8sZ?ZIbF8OrwndHUf^Ndvt z6^1%PgQ3STWEeB78Fmauh6@AEaA!m?Vi+_=JR^~@pK*Xuz$j#tFnEk3j3x%3Az-vK zIvFPzgN$LuSc+nbMhYxNKgB3zbBcM2Wr|ITeTrjBXbLN(F-4ftnIcLNr<_a~Oc_eK znDS%F{gg*3Pg7o`{Fd@M()OgKr)8#PrRAjMrtME_P8&=6DSc)7mUO@L)bxt< zW9f_OSJJPg-%P)q{wV!r`m6Le>F?4%GG&-@OnD}lslrreYBD!5b(qdfA0~$B&%`r> znW4-GW+XF_$zY~3+01-q0kfESkXga3X4Wu|GLJLom}i)a%=64k%qz@m%$v*~nLjZf zFyAvjWyof%$N*)m&QQo$m$4xOlA)5JmSL5F%h;PylQEQWCv#<{VWwv$DU+5NpP7`& z$jr>#pLrm&AhS5LG?SNkB(o`#pDD;}&+N>c&AgO(HSO-+KFfU10hC7UImwJK|E*19aEEJ&74 zmTs0omT?vJs^nT9%_Wg_df8{_p z790#Gh!esI=MXuuoMcWaCykTA$>L;l*ql5LhjV~a$vMP1%sIko;-{7yefGy6}&}PepP?@vMjPI zawu{x+EKK#D5NN{h*7ksD7`4NXkQV#Xn)axqQat*qL!kzqN7FaMV&>WqTZt8Mg2u5 zi%t~{7hNrSTfC{*wK%%Cpt!sEO!1SF)g|B(l@j$5jS{_*ttF-<7A4jtb|nrah!UR? zbP2WuSAs7|F4c{R3a`JE}1BqE}1PkTXL@CLdm6)pGsbo zt}IRXB~#g_V)29ze1mX%6M zFO|M6(<$>Piz;K6HIyAK>nQ6k>nS@?HeNPWHd8iVcD8J>?0VU)vO8t>${v5s%6(tqCii(Pwin@x1il&O5ilK_{ zDlS%BuDDupqvCeO-HQ7ak1C#4Jg=0mTvfTIQlWBPrBbDGrD~;mrDi3xQoGWrGNf`} zWmDx;<>RXLRoko3Rn#g*)t;*Ks*I|Ri>0 zsykKpsvcH7t9oAbvg)_$71c`Bs?{5-wW?v&dew&2#?`jf9@Qb$;nk7V(bc=FsnzuA z#A-(Mp6c}K%4Y?+!hE@|_lT^c~DXXckX|8FlIa_R@+*8w6>$RyH;E)sqL>lSvyoaT02pDx%O)9_1c@Yw`=d#-miUB`=s{g z+Fxp49^P=+^f2yl>fxHhBZu$Q$=1Q@TYK6U6iOkGf2WLy-_o-g4epUV2`gQdi z>b2{)*2C*P>Jjxm_2_zRJ+3~meph{HeMEgq{oeZY`iy#3eRh3r{r>v=`hxnR`jYyN z`nmdNM>ZU>Iud*&>qz~PQ%9~G`SHk4M;;t`bmZlccSk-p$TX~I05z;?P-#$a&}`V$ z0Bg`|aBV<0_&4Aif*Qgahz(H<W12ex`vL1frc{;iw)-+ zE;U?fxYls9;m3xb8Xhz}ZurzF*C^k(vT=2zLgV^IaHDdgTI0q>%|^RMLSsf_edAc; z{id}|o12hLl%|BH2cHZrWZ}WHT~WUYF^z8Zq{zrZ#HV)+-%xx-fY!u)9l&o-@Ln-+DvawY-Tj? zX-;p>Y~I(*Zr08YVK+7ZI(2jYkuCM++x!b+>+hGZ<%QM zvE?Iw6@M*%9e)FVBVU(qz&GM==5OV1=R5LU_;9`lAHhfRDSQS$ji15K;^*@B^AGR~ z_%-}Ceh0ssFXs302l#{hA^vIp75+2+FZ^Hmzw_Vn-}67U%C&-8SGOv(!dmrP4O@*{ zH@9wUHEXqKwQ99(wQqH74Qk!ndbo9{^>*9Jwk>TwZLw{fw$iqPZIx}+ZH;Zhw$8Th zHgVgrw&QK%ZBuPCZS!qs+ZNlNw!LlpD3BG%3)Tn}1seol0Zg!6U@5Q>*b7_)aDj)w zOMn-U1bYQc0ZWiA$Q5t|TtShbRB%vGDQFjT2}A<1;FzFKa6&LB7!r&M#s!mt+k#I= z^^bZTr5-IiDmi-o=nLU`p}J60xJjrZG!a?|t%Np0JE4QnNr)7pgczZ}5HBPMQ-nD} zj*u%X67q!Q!Ybh*p+ML!>=&LAjtIwvQsJ!dwD7F(y6{oEO#6!VmF;WV727woL)ul_ zH@0iFYq#sR+qXNlyR^HuyS00^d$;?xquVj<{_O$nf$fa;gYA9om)qZU=yrH@kUR1^ znmXD$x;lC~dOHR?COf1Za~)?o7CXM{xX^K_<4(uDj)xsjI)3i>rE^`UW~WZ4UZ-K_ zmd@>+=AD+EZk?W;{++uzLpvinNu9Bsv`%_wVrOz^S*NITvh!T$rOqpz*E(-^-tD~K z`LOeKmwcB-7qm;KORvkY%cN^-muZ(pmvxt27rG1E<=++171*__E3_-Ti`W&_Mef?& zmDknMCGC3Ht=MhZP3Yd!UD@5+J=i_mJ=Q(ZeY*Q%_xIgby03O$@4ngnr2FUY7u~;g zzwUl3QWNQmOhj8nrXnkmt;k;FDDn}ZMZuy75lKWAQAKg01W}SGTU0D+7PX3wiaJEy zBC$v!>KC094T(lY7e$vvKZvf0ZisG+?uzb-9*7=`o{E0%QRvyygXu}?sq7i-x!LnU z3>75xqXW=w4DUxp#MO zY%i@hzBj3t(VN^mMloVliZg)l01<-lRTHal)RF>mb{g`mwY@f zb9~cr=i`ybbB_y-pE>?Z--bTZK2#sRFQ_l1FRYK!m(Z8g$LLG#+uN7k$LZtt74?<& z9qg;<6ZZ}GP4rFo&Gwz`JJ)x0=YuZ?Uk$!KC4Xw=sWqn*Px+k+KSewh zb&7Io`qcST7f)S2b#-X_kmC?)2s7kAgdYkT3KWVCU#Yjk*YY;8seL4DS^v&qI(T`&?W13?|V-92Zv8b^0d9yT5^9ycC8 zo;02^J~n=Kd~y8z_@xQu3E0He3DXIS3F`^F3C9Vq3FHK70yE)1fuA5uvS9M?Wb5S7$&ShHN%7>#N$KS2$%V=9CcmHjVee1BGspnHKr(R9V zOs|+;IlX3DaeBivc-n0`Y5LIg#Pkd4YN?jgM7mkJMY>JuAa#^FNnNA}sgD#b#Yl~N)`kB6& z*_m52zs;_h)tz;m^_oS`;%3ukvu5|rmdqZW<7q2-XedoYq4jscTuu9wm7*sy*Rsg zdhzVy_lrL)UR%7ecz^N1;-kfv=T@Ctdv4u1rE|*X)Xr&~gPzklr+3b9`2jGwFHglm OYQH=N_vPc9@&5wAQBM2- diff --git a/macOS/SearchifyX/Constants.swift b/macOS/SearchifyX/Constants.swift index 9da3b11..98db160 100644 --- a/macOS/SearchifyX/Constants.swift +++ b/macOS/SearchifyX/Constants.swift @@ -1,13 +1,14 @@ -// -// Constants.swift -// SearchifyX -// -// Created by Jose Molina on 9/6/22. -// - import Foundation import KeyboardShortcuts +import AppKit +import SwiftUI extension KeyboardShortcuts.Name { static let openSearchify = Self("openSearchify") + static let ocrAndSearch = Self("ocrAndSearch") + static let pasteAndSearch = Self("pasteAndSearch") +} + +class Variables { + static var hiddenWindow: NSWindow? } diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift index 9e912c3..2175ca0 100644 --- a/macOS/SearchifyX/ContentView.swift +++ b/macOS/SearchifyX/ContentView.swift @@ -1,14 +1,5 @@ -// -// ContentView.swift -// SearchifyX -// -// Created by Jose Molina on 9/2/22. -// - import SwiftUI -let scraper = Scraper() - struct ContentView: View { @State var question: String = "" @State var enableQuizizz: Bool = true @@ -23,20 +14,26 @@ struct ContentView: View { @AppStorage("runAfterPaste") var runAfterPaste: Bool = false var isPanel: Bool + var hasShown: Bool? + var skQuery: String? + + init(isPanel: Bool, question q: String?) { + self.isPanel = isPanel + if q != nil { + skQuery = q! + hasShown = true + } + else { + hasShown = false + } + } var body: some View { VStack { HStack { if isPanel == false { Button(action: { - let ep = FloatingPanel(contentRect: NSRect(x: 0, y: 0, width: 900, height: 450), backing: .buffered, defer: false) - - ep.title = "Hidden SearchifyX" - ep.contentView = NSHostingView(rootView: ContentView(isPanel: true)) - - ep.center() - ep.orderFront(nil) - ep.makeKey() + Scraper.makeHiddenWindow(question: nil) }, label: { Image(systemName: "eye.slash") }) @@ -45,7 +42,7 @@ struct ContentView: View { .lineLimit(nil) Button( action: { - searchQuestion() + searchQuestion(query: self.question) }, label: { Image(systemName: "magnifyingglass") @@ -54,17 +51,10 @@ struct ContentView: View { ) Button( action: { - var clipboardItems: [String] = [] - for element in NSPasteboard.general.pasteboardItems! { - if let str = element.string(forType: NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text")) { - clipboardItems.append(str) - } - } - - question = clipboardItems[0] + question = Scraper.getClipboard() if runAfterPaste { - searchQuestion() + searchQuestion(query: self.question) } }, label: { @@ -74,10 +64,10 @@ struct ContentView: View { Button( action: { DispatchQueue.global(qos: .userInitiated).async { - question = scraper.ocr() + question = Scraper.ocr() if runAfterOcr { - searchQuestion() + searchQuestion(query: self.question) } } }, @@ -141,9 +131,15 @@ struct ContentView: View { } .padding() } + .onAppear { + if hasShown! { + self.question = skQuery! + searchQuestion(query: skQuery!) + } + } } - func searchQuestion() { + func searchQuestion(query: String) { searching = true var sites: [String] = [] @@ -156,7 +152,7 @@ struct ContentView: View { } DispatchQueue.global(qos: .userInitiated).async { - cards = scraper.search(query: question, sites: sites.joined(separator: ","), engine: engine) + cards = Scraper.search(query: query, sites: sites.joined(separator: ","), engine: engine) searching = false } } @@ -164,6 +160,6 @@ struct ContentView: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView(isPanel: false) + ContentView(isPanel: false, question: nil) } } diff --git a/macOS/SearchifyX/Flashcard.swift b/macOS/SearchifyX/Flashcard.swift index ce7cdf6..e6e180f 100644 --- a/macOS/SearchifyX/Flashcard.swift +++ b/macOS/SearchifyX/Flashcard.swift @@ -1,10 +1,3 @@ -// -// Flashcard.swift -// SearchifyX -// -// Created by Jose Molina on 9/2/22. -// - import Foundation struct Flashcard: Identifiable, Codable { diff --git a/macOS/SearchifyX/Scraper.swift b/macOS/SearchifyX/Scraper.swift index 29d2008..aa4ed37 100644 --- a/macOS/SearchifyX/Scraper.swift +++ b/macOS/SearchifyX/Scraper.swift @@ -1,19 +1,18 @@ -// -// Scraper.swift -// SearchifyX -// -// Created by Jose Molina on 9/2/22. -// - import Foundation import AppKit import Vision +import SwiftUI +import UserNotifications class Scraper { - func search(query: String, sites: String, engine: String) -> [Flashcard] { + static func search(query: String, sites: String, engine: String) -> [Flashcard] { + if query.isEmpty { + return [] + } + let proc = Process() proc.executableURL = - Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/scraper.app/Contents/MacOS/scraper") + Bundle.main.bundleURL.appendingPathComponent("Contents/Resources/scraper/scraper") let tempDir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let tempFile = ProcessInfo().globallyUniqueString @@ -34,11 +33,23 @@ class Scraper { } catch { print("Error occurred trying to run the scraper: \(error)") + Scraper.alert(caption: "Unable to search", msg: "An error occurred while trying to scrape results") return [] } } - func ocr() -> String { + static func ocr() -> String { + var window: NSWindow? + + if Variables.hiddenWindow != nil { + DispatchQueue.main.async { + if Variables.hiddenWindow!.isKeyWindow { + window = NSApp.keyWindow + window?.orderOut(nil) + } + } + } + let proc = Process() let exec = URL(fileURLWithPath: "/usr/sbin/screencapture") proc.executableURL = exec @@ -48,6 +59,12 @@ class Scraper { try proc.run() proc.waitUntilExit() + if Variables.hiddenWindow != nil { + DispatchQueue.main.async { + window?.orderFront(nil) + } + } + var data: Data? for element in NSPasteboard.general.pasteboardItems! { @@ -69,7 +86,7 @@ class Scraper { } if recognizedStrings.isEmpty { - alert(caption: "Unable to run the OCR", msg: "No text was detected") + Scraper.alert(caption: "Unable to run the OCR", msg: "No text was detected") return "" } @@ -77,20 +94,37 @@ class Scraper { } catch { print("An error occurred trying to run the OCR: \(error)") - alert(caption: "Unable to run the OCR", msg: "An error occurred while trying to run or process the OCR") + Scraper.alert(caption: "Unable to run the OCR", msg: "An error occurred while trying to run or process the OCR") return "" } } - func alert(caption: String, msg: String) { - DispatchQueue.main.async { - let alert = NSAlert() - alert.messageText = caption - alert.informativeText = msg - alert.addButton(withTitle: "OK") - alert.alertStyle = .warning - alert.runModal() + static func alert(caption: String, msg: String) { + let content = UNMutableNotificationContent() + content.title = caption + content.body = msg + + let uuid = UUID().uuidString + let request = UNNotificationRequest(identifier: uuid, content: content, trigger: nil) + + let center = UNUserNotificationCenter.current() + center.requestAuthorization(options: [.alert, .sound]) { _, _ in} + center.add(request) + } + + static func getClipboard() -> String { + var clipboardItems: [String] = [] + for element in NSPasteboard.general.pasteboardItems! { + if let str = element.string(forType: NSPasteboard.PasteboardType(rawValue: "public.utf8-plain-text")) { + clipboardItems.append(str) + } } + + if (clipboardItems.isEmpty) { + return "" + } + + return clipboardItems[0] } static func convertPercent(from input: String) -> Float { @@ -100,4 +134,20 @@ class Scraper { return 0 } } + + static func makeHiddenWindow(question: String?) { + if Variables.hiddenWindow != nil { + Variables.hiddenWindow?.isReleasedWhenClosed = true + Variables.hiddenWindow?.close() + } + + Variables.hiddenWindow = FloatingPanel(contentRect: NSRect(x: 0, y: 0, width: 900, height: 450), backing: .buffered, defer: false) + + Variables.hiddenWindow?.title = "Hidden SearchifyX" + Variables.hiddenWindow?.contentView = NSHostingView(rootView: ContentView(isPanel: true, question: question)) + + Variables.hiddenWindow?.center() + Variables.hiddenWindow?.orderFront(nil) + Variables.hiddenWindow?.makeKey() + } } diff --git a/macOS/SearchifyX/SearchifyXApp.swift b/macOS/SearchifyX/SearchifyXApp.swift index acec8ac..8802728 100644 --- a/macOS/SearchifyX/SearchifyXApp.swift +++ b/macOS/SearchifyX/SearchifyXApp.swift @@ -1,10 +1,3 @@ -// -// SearchifyXApp.swift -// SearchifyX -// -// Created by Jose Molina on 9/2/22. -// - import SwiftUI import KeyboardShortcuts @@ -14,7 +7,7 @@ struct SearchifyXApp: App { var body: some Scene { WindowGroup { - ContentView(isPanel: false) + ContentView(isPanel: false, question: nil) } Settings { SettingsView() @@ -26,14 +19,36 @@ struct SearchifyXApp: App { final class AppState: ObservableObject { init() { KeyboardShortcuts.onKeyUp(for: .openSearchify) { [self] in - let ep = FloatingPanel(contentRect: NSRect(x: 0, y: 0, width: 900, height: 450), backing: .buffered, defer: false) - - ep.title = "Hidden SearchifyX" - ep.contentView = NSHostingView(rootView: ContentView(isPanel: true)) - - ep.center() - ep.orderFront(nil) - ep.makeKey() + Scraper.makeHiddenWindow(question: nil) + } + + KeyboardShortcuts.onKeyUp(for: .ocrAndSearch) { [self] in + if UserDefaults.standard.bool(forKey: "showOnNotificationCenter") { + searchAndSend(question: Scraper.ocr()) + } + else { + Scraper.makeHiddenWindow(question: Scraper.ocr()) + } + } + + KeyboardShortcuts.onKeyUp(for: .pasteAndSearch) { [self] in + if UserDefaults.standard.bool(forKey: "showOnNotificationCenter") { + searchAndSend(question: Scraper.getClipboard()) + } + else { + Scraper.makeHiddenWindow(question: Scraper.getClipboard()) + } + } + } + + func searchAndSend(question: String?) { + if (question == nil) { + return + } + + var card = Scraper.search(query: question!, sites: "quizlet,quizizz", engine: "google").first + if (card != nil) { + Scraper.alert(caption: card!.question, msg: card!.answer) } } } diff --git a/macOS/SearchifyX/SettingsView.swift b/macOS/SearchifyX/SettingsView.swift index dfe01f8..585d0da 100644 --- a/macOS/SearchifyX/SettingsView.swift +++ b/macOS/SearchifyX/SettingsView.swift @@ -1,16 +1,10 @@ -// -// SettingsView.swift -// SearchifyX -// -// Created by Jose Molina on 9/6/22. -// - import SwiftUI import KeyboardShortcuts struct SettingsView: View { @AppStorage("runAfterOcr") var runAfterOcr: Bool = false @AppStorage("runAfterPaste") var runAfterPaste: Bool = false + @AppStorage("showOnNotificationCenter") var showOnNotificationCenter: Bool = false var body: some View { VStack { @@ -20,7 +14,12 @@ struct SettingsView: View { Toggle(isOn: $runAfterPaste) { Text("Search after text is pasted") } + Toggle(isOn: $showOnNotificationCenter) { + Text("Send answer as notification instead of showing window") + } KeyboardShortcuts.Recorder("Open Hidden SearchifyX", name: .openSearchify) + KeyboardShortcuts.Recorder("OCR and search", name: .ocrAndSearch) + KeyboardShortcuts.Recorder("Paste and search", name: .pasteAndSearch) } .padding() } diff --git a/macOS/build.sh b/macOS/build.sh index 953807a..cec70df 100755 --- a/macOS/build.sh +++ b/macOS/build.sh @@ -3,14 +3,11 @@ # Get package requirements pip3 install -r requirements.txt -# Create setup.py file -py2applet --make-setup ../scraper.py - # Generate app -python3 setup.py py2app +pyinstaller ../scraper.py # Delete old scraper.app -rm -r ./SearchifyX/scraper.app +rm -r ./SearchifyX/scraper # Copy newest scraper.app -cp -R ./dist/scraper.app ./SearchifyX/ \ No newline at end of file +cp -R ./dist/scraper ./SearchifyX/ diff --git a/macOS/clean.sh b/macOS/clean.sh index 7a8f27c..3b248ad 100755 --- a/macOS/clean.sh +++ b/macOS/clean.sh @@ -3,5 +3,5 @@ # Remove build directories rm -r ./build/ rm -r ./dist/ - -rm setup.py \ No newline at end of file +rm scraper.spec +rm ./SearchifyX/scraper diff --git a/macOS/requirements.txt b/macOS/requirements.txt index 3d0c76a..94c6923 100644 --- a/macOS/requirements.txt +++ b/macOS/requirements.txt @@ -2,5 +2,4 @@ beautifulsoup4==4.11.1 fake_headers==1.0.2 grequests==0.6.0 requests_html==0.10.0 -setuptools==63.2.0 -py2app==0.28.2 +pyinstaller==5.3 From 96c125daf3c99c2af4de1ca0cebcb1b17b03533f Mon Sep 17 00:00:00 2001 From: daijro Date: Mon, 19 Dec 2022 21:52:04 -0600 Subject: [PATCH 19/39] Fix scraper (Patch #5) - Google scraper is much fasterm and randomizes domains to avoid CAPTCHA blocks. - Bing block has been bypassed by creating cookies before sending search requests - Google is now the default search engine Works as of December 2022. --- config.json | 2 +- scraper.py | 93 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/config.json b/config.json index 4139f9f..4ce82b3 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "quizlet": true, "quizizz": true, - "search_engine": 0, + "search_engine": 1, "hide_show_key": "Ctrl+D", "ocr_key": "Ctrl+Shift+X", "paste_key": "Ctrl+Shift+V", diff --git a/scraper.py b/scraper.py index 659bfed..5e7598e 100644 --- a/scraper.py +++ b/scraper.py @@ -8,6 +8,7 @@ import re import sys import time +from random import choice from urllib.parse import urlencode from threading import Thread @@ -27,6 +28,32 @@ "Connection": "close" } +google_domains = ( + 'com', 'ad', 'ae', 'com.af', 'com.ag', 'com.ai', 'al', 'am', + 'co.ao', 'com.ar', 'as', 'at', 'com.au', 'az', 'ba', 'com.bd', + 'be', 'bf', 'bg', 'com.bh', 'bi', 'bj', 'com.bn', 'com.bo', + 'com.br', 'bs', 'bt', 'co.bw', 'by', 'com.bz', 'ca', 'cd', 'cf', + 'cg', 'ch', 'ci', 'co.ck', 'cl', 'cm', 'cn', 'com.co', 'co.cr', + 'com.cu', 'cv', 'com.cy', 'cz', 'de', 'dj', 'dk', 'dm', 'com.do', + 'dz', 'com.ec', 'ee', 'com.eg', 'es', 'com.et', 'fi', 'com.fj', + 'fm', 'fr', 'ga', 'ge', 'gg', 'com.gh', 'com.gi', 'gl', 'gm', + 'gr', 'com.gt', 'gy', 'com.hk', 'hn', 'hr', 'ht', 'hu', 'co.id', + 'ie', 'co.il', 'im', 'co.in', 'iq', 'is', 'it', 'je', 'com.jm', + 'jo', 'co.jp', 'co.ke', 'com.kh', 'ki', 'kg', 'co.kr', 'com.kw', + 'kz', 'la', 'com.lb', 'li', 'lk', 'co.ls', 'lt', 'lu', 'lv', + 'com.ly', 'co.ma', 'md', 'me', 'mg', 'mk', 'ml', 'com.mm', 'mn', + 'ms', 'com.mt', 'mu', 'mv', 'mw', 'com.mx', 'com.my', 'co.mz', + 'com.na', 'com.ng', 'com.ni', 'ne', 'nl', 'no', 'com.np', 'nr', + 'nu', 'co.nz', 'com.om', 'com.pa', 'com.pe', 'com.pg', 'com.ph', + 'com.pk', 'pl', 'pn', 'com.pr', 'ps', 'pt', 'com.py', 'com.qa', + 'ro', 'ru', 'rw', 'com.sa', 'com.sb', 'sc', 'se', 'com.sg', 'sh', + 'si', 'sk', 'com.sl', 'sn', 'so', 'sm', 'sr', 'st', 'com.sv', + 'td', 'tg', 'co.th', 'com.tj', 'tl', 'tm', 'tn', 'to', 'com.tr', + 'tt', 'com.tw', 'co.tz', 'com.ua', 'co.ug', 'co.uk', 'com.uy', + 'co.uz', 'com.vc', 'co.ve', 'vg', 'co.vi', 'com.vn', 'vu', 'ws', + 'rs', 'co.za', 'co.zm', 'co.zw', 'cat' +) + get_text = lambda x: BeautifulSoup(x, features='lxml').get_text().strip() sluggify = lambda a: ' '.join(re.sub(r'[^\\sa-z0-9\\.,\\(\\)]+', ' ', a.lower()).split()) similar = lambda a, b: SequenceMatcher(None, sluggify(a), sluggify(b)).ratio() @@ -37,39 +64,42 @@ def _make_headers(): class SearchEngine: - headers = headers.copy() def __init__(self, engine_name): self.sess = HTMLSession() self.engine_name = engine_name self._web_engines = { # simple scrapers using get requests - 'google': ('https://www.google.com/search?', 'q', {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'}), - 'bing': ('https://www.bing.com/search?', 'q', {'pq': ''}), + 'google': { + 'domain': 'https://www.google.com/', + 'query': 'q', + 'args': {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'} + }, + 'bing': { + 'domain': 'https://www.bing.com/', + 'query': 'q', + 'args': {'ghsh': '0', 'ghacc': '0', 'ghpl': ''} + }, + 'startpage': { + 'domain': 'https://www.startpage.com/', + } } - if engine_name in self._web_engines: - return - elif engine_name == 'startpage': - print('Starting startpage instance...') - self.t = Thread(target=self._init_startpage) - self.t.daemon = True - self.t.start() + self.sess.headers.update({**headers, "Sec-Fetch-Site": "same-origin", 'Referer': self._web_engines[self.engine_name]['domain']}) + print('Starting instance...') + self.t = Thread(target=self._init_search) + self.t.daemon = True + self.t.start() - def find_items(self, soup, args): - return {i: soup.find('input', {'type': 'hidden', 'name': i})['value'] for i in args} - - def get_startpage_items(self, r): - soup = BeautifulSoup(r.text, 'lxml') - return {'query': None, 'cat': 'web', **self.find_items(soup, ['lui', 'language', 'sc', 'abp'])} + def _init_search(self): + if self.engine_name == 'google': + return + r = self.sess.get(self._web_engines[self.engine_name]['domain']) + if self.engine_name == 'startpage': + self._startpage_data = self.get_startpage_items(r) - def _init_startpage(self): - self._startpage_data = self.get_startpage_items(self.sess.get('https://www.startpage.com/', headers=self.headers)) - self.headers.update({"Sec-Fetch-Site": "same-origin", 'Referer': 'https://www.startpage.com/'}) - def startpage_get_page(self, query, sites): - self.t.join() resps = grequests.map([ grequests.post('https://www.startpage.com/sp/search', - headers=self.headers, - data={**self._startpage_data, **{'query': f'{query} site:{site}.com'}} + data={**self._startpage_data, **{'query': f'{query} site:{site}.com'}}, + session=self.sess ) for site in sites ]) @@ -78,22 +108,31 @@ def startpage_get_page(self, query, sites): self.t.start() return dict(zip(sites, resps)) + def find_items(self, soup, args): + return {i: soup.find('input', {'type': 'hidden', 'name': i})['value'] for i in args} + + def get_startpage_items(self, r): + soup = BeautifulSoup(r.text, 'lxml') + return {'query': None, 'cat': 'web', **self.find_items(soup, ['lui', 'language', 'sc', 'abp'])} + def get_page(self, query, sites): + self.t.join() if self.engine_name == 'startpage': return self.startpage_get_page(query, sites) + if self.engine_name == 'google': + self.sess.headers['Referer'] = self._web_engines[self.engine_name]['domain'] = f'https://www.google.{choice(google_domains)}/' return dict(zip( sites, grequests.map([ grequests.get( - (web_engine := self._web_engines[self.engine_name])[0] - + urlencode({web_engine[1]: f'{query} site:{site}.com', **web_engine[2]}), - headers=self.headers, session=self.sess + (web_engine := self._web_engines[self.engine_name])['domain'] + 'search?' + + urlencode({web_engine['query']: f'{query} site:{site}.com', **web_engine['args']}), + session=self.sess ) for site in sites ], size=len(sites)) )) - class SearchWeb: """ search web for query From 6448fd6689e36d4bb4faab4469bd6c5c21ff9fec Mon Sep 17 00:00:00 2001 From: daijro Date: Mon, 19 Dec 2022 21:55:15 -0600 Subject: [PATCH 20/39] Fix GUI scrolling - Change item view scrolling to ScrollPerPixel - Much smoother scrolling experience --- window.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/window.ui b/window.ui index 9473920..8ae405e 100644 --- a/window.ui +++ b/window.ui @@ -87,6 +87,9 @@ QFrame::NoFrame + + QAbstractItemView::ScrollPerPixel + false From aa5f747ff5051db980c2c40c19411841df87375f Mon Sep 17 00:00:00 2001 From: daijro Date: Tue, 20 Dec 2022 08:15:35 -0600 Subject: [PATCH 21/39] Add character limit for long queries Fix scraper returning poor results on longer queries --- scraper.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scraper.py b/scraper.py index 5e7598e..c8b7a22 100644 --- a/scraper.py +++ b/scraper.py @@ -71,15 +71,18 @@ def __init__(self, engine_name): 'google': { 'domain': 'https://www.google.com/', 'query': 'q', - 'args': {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'} + 'args': {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'}, + 'limit': 2038 }, 'bing': { 'domain': 'https://www.bing.com/', 'query': 'q', - 'args': {'ghsh': '0', 'ghacc': '0', 'ghpl': ''} + 'args': {'ghsh': '0', 'ghacc': '0', 'ghpl': ''}, + 'limit': 990 }, 'startpage': { 'domain': 'https://www.startpage.com/', + 'limit': 2038 } } self.sess.headers.update({**headers, "Sec-Fetch-Site": "same-origin", 'Referer': self._web_engines[self.engine_name]['domain']}) @@ -119,14 +122,17 @@ def get_page(self, query, sites): self.t.join() if self.engine_name == 'startpage': return self.startpage_get_page(query, sites) - if self.engine_name == 'google': + elif self.engine_name == 'google': self.sess.headers['Referer'] = self._web_engines[self.engine_name]['domain'] = f'https://www.google.{choice(google_domains)}/' return dict(zip( sites, grequests.map([ grequests.get( (web_engine := self._web_engines[self.engine_name])['domain'] + 'search?' - + urlencode({web_engine['query']: f'{query} site:{site}.com', **web_engine['args']}), + + urlencode({ + web_engine['query']: f"{query[:self._web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com", + **web_engine['args'] + }), session=self.sess ) for site in sites From 3a7b3857008e373bab090595949817e32fe684a0 Mon Sep 17 00:00:00 2001 From: daijro Date: Tue, 20 Dec 2022 08:38:50 -0600 Subject: [PATCH 22/39] Escape search query - Escape search query - Repeat last update for startpage - Change default engine back to Bing --- config.json | 2 +- scraper.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/config.json b/config.json index 4ce82b3..4139f9f 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "quizlet": true, "quizizz": true, - "search_engine": 1, + "search_engine": 0, "hide_show_key": "Ctrl+D", "ocr_key": "Ctrl+Shift+X", "paste_key": "Ctrl+Shift+V", diff --git a/scraper.py b/scraper.py index c8b7a22..31ee4dc 100644 --- a/scraper.py +++ b/scraper.py @@ -101,7 +101,10 @@ def _init_search(self): def startpage_get_page(self, query, sites): resps = grequests.map([ grequests.post('https://www.startpage.com/sp/search', - data={**self._startpage_data, **{'query': f'{query} site:{site}.com'}}, + data={ + **self._startpage_data, + 'query': f"{query[:self._web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com" + }, session=self.sess ) for site in sites @@ -120,6 +123,8 @@ def get_startpage_items(self, r): def get_page(self, query, sites): self.t.join() + # escape query sequence + query = re.escape(query) if self.engine_name == 'startpage': return self.startpage_get_page(query, sites) elif self.engine_name == 'google': From dfe83f0528754f7f08136e48e4a46a739e442dc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Dec 2022 14:51:16 +0000 Subject: [PATCH 23/39] Bump certifi from 2021.10.8 to 2022.12.7 Bumps [certifi](https://github.com/certifi/python-certifi) from 2021.10.8 to 2022.12.7. - [Release notes](https://github.com/certifi/python-certifi/releases) - [Commits](https://github.com/certifi/python-certifi/compare/2021.10.08...2022.12.07) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 701b68a..0c00c92 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ appdirs==1.4.4 beautifulsoup4==4.10.0 bs4==0.0.1 -certifi==2021.10.8 +certifi==2022.12.7 cffi==1.15.0 charset-normalizer==2.0.9 colorama==0.4.4 From e7a3893247de6aa323c9c3384dc008eb231b692e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Dec 2022 14:52:49 +0000 Subject: [PATCH 24/39] Bump lxml from 4.8.0 to 4.9.1 Bumps [lxml](https://github.com/lxml/lxml) from 4.8.0 to 4.9.1. - [Release notes](https://github.com/lxml/lxml/releases) - [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt) - [Commits](https://github.com/lxml/lxml/compare/lxml-4.8.0...lxml-4.9.1) --- updated-dependencies: - dependency-name: lxml dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 701b68a..6a12dbe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,7 +15,7 @@ html5lib==1.1 idna==3.3 importlib-metadata==4.11.3 keyboard==0.13.5 -lxml==4.8.0 +lxml==4.9.1 packaging==21.3 parse==1.19.0 Pillow==9.1.0 From efc81fc944cf9e1f90ac2e3b81cdc9bcfe32d051 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Dec 2022 14:53:02 +0000 Subject: [PATCH 25/39] Bump pillow from 9.1.0 to 9.3.0 Bumps [pillow](https://github.com/python-pillow/Pillow) from 9.1.0 to 9.3.0. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/9.1.0...9.3.0) --- updated-dependencies: - dependency-name: pillow dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 701b68a..9f1783c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ keyboard==0.13.5 lxml==4.8.0 packaging==21.3 parse==1.19.0 -Pillow==9.1.0 +Pillow==9.3.0 pycparser==2.21 pyee==8.2.2 pyparsing==3.0.8 From 27ecf23cae47d43be31a2b96df0db540e424508d Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Tue, 20 Dec 2022 09:33:33 -0600 Subject: [PATCH 26/39] Update macOS --- macOS/SearchifyX.xcodeproj/project.pbxproj | 90 +++++++- macOS/SearchifyX/Constants.swift | 2 + macOS/SearchifyX/ContentView.swift | 182 ++++------------ .../{ => Helpers}/FloatingPanel.swift | 4 +- macOS/SearchifyX/Helpers/ViewLoadExt.swift | 37 ++++ macOS/SearchifyX/{ => Models}/Flashcard.swift | 0 macOS/SearchifyX/SearchifyXApp.swift | 5 +- .../SearchifyX/Toolbars/BrowserToolbar.swift | 39 ++++ .../SearchifyX/Toolbars/ScraperToolbar.swift | 64 ++++++ macOS/SearchifyX/Views/BrowserView.swift | 44 ++++ macOS/SearchifyX/Views/ContentView.swift | 206 ++++++++++++++++++ macOS/SearchifyX/Views/NotesView.swift | 20 ++ macOS/SearchifyX/Views/ScraperView.swift | 127 +++++++++++ .../SearchifyX/{ => Views}/SettingsView.swift | 0 macOS/SearchifyX/WebView/NSWebView.swift | 21 ++ macOS/SearchifyX/WebView/WebView.swift | 22 ++ macOS/SearchifyX/WebView/WebViewModel.swift | 27 +++ macOS/clean.sh | 0 18 files changed, 737 insertions(+), 153 deletions(-) rename macOS/SearchifyX/{ => Helpers}/FloatingPanel.swift (90%) create mode 100644 macOS/SearchifyX/Helpers/ViewLoadExt.swift rename macOS/SearchifyX/{ => Models}/Flashcard.swift (100%) create mode 100644 macOS/SearchifyX/Toolbars/BrowserToolbar.swift create mode 100644 macOS/SearchifyX/Toolbars/ScraperToolbar.swift create mode 100644 macOS/SearchifyX/Views/BrowserView.swift create mode 100644 macOS/SearchifyX/Views/ContentView.swift create mode 100644 macOS/SearchifyX/Views/NotesView.swift create mode 100644 macOS/SearchifyX/Views/ScraperView.swift rename macOS/SearchifyX/{ => Views}/SettingsView.swift (100%) create mode 100644 macOS/SearchifyX/WebView/NSWebView.swift create mode 100644 macOS/SearchifyX/WebView/WebView.swift create mode 100644 macOS/SearchifyX/WebView/WebViewModel.swift mode change 100755 => 100644 macOS/clean.sh diff --git a/macOS/SearchifyX.xcodeproj/project.pbxproj b/macOS/SearchifyX.xcodeproj/project.pbxproj index e11455f..663033f 100644 --- a/macOS/SearchifyX.xcodeproj/project.pbxproj +++ b/macOS/SearchifyX.xcodeproj/project.pbxproj @@ -8,10 +8,18 @@ /* Begin PBXBuildFile section */ 4214674528C1C5EF00E9D706 /* SearchifyXApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */; }; - 4214674728C1C5EF00E9D706 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214674628C1C5EF00E9D706 /* ContentView.swift */; }; 4214674928C1C5F200E9D706 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4214674828C1C5F200E9D706 /* Assets.xcassets */; }; 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214676F28C1CFB500E9D706 /* Flashcard.swift */; }; 4214677528C1D99300E9D706 /* Scraper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4214677428C1D99300E9D706 /* Scraper.swift */; }; + 423A30E82926193900071A8A /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30E72926193900071A8A /* WebViewModel.swift */; }; + 423A30EE29268E6100071A8A /* NotesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30ED29268E6100071A8A /* NotesView.swift */; }; + 423A30F029268E7700071A8A /* BrowserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30EF29268E7700071A8A /* BrowserView.swift */; }; + 423A30F229268FB000071A8A /* ScraperView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30F129268FB000071A8A /* ScraperView.swift */; }; + 423A30F429268FED00071A8A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30F329268FED00071A8A /* ContentView.swift */; }; + 423A30F62926A9C400071A8A /* ViewLoadExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30F52926A9C400071A8A /* ViewLoadExt.swift */; }; + 423A30F92926B65100071A8A /* BrowserToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30F82926B65100071A8A /* BrowserToolbar.swift */; }; + 423A30FB2926B70F00071A8A /* ScraperToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423A30FA2926B70F00071A8A /* ScraperToolbar.swift */; }; + 423AC30D290116FA00319B15 /* NSWebView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 423AC30C290116FA00319B15 /* NSWebView.swift */; }; 42C95D932900657A008936E3 /* scraper in Resources */ = {isa = PBXBuildFile; fileRef = 42C95D922900657A008936E3 /* scraper */; }; 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */; }; 42E9579B28C84C0E00BF7B3B /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 42E9579A28C84C0E00BF7B3B /* KeyboardShortcuts */; }; @@ -22,10 +30,18 @@ /* Begin PBXFileReference section */ 4214674128C1C5EF00E9D706 /* SearchifyX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SearchifyX.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchifyXApp.swift; sourceTree = ""; }; - 4214674628C1C5EF00E9D706 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 4214674828C1C5F200E9D706 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 4214676F28C1CFB500E9D706 /* Flashcard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flashcard.swift; sourceTree = ""; }; 4214677428C1D99300E9D706 /* Scraper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scraper.swift; sourceTree = ""; }; + 423A30E72926193900071A8A /* WebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewModel.swift; sourceTree = ""; }; + 423A30ED29268E6100071A8A /* NotesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotesView.swift; sourceTree = ""; }; + 423A30EF29268E7700071A8A /* BrowserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserView.swift; sourceTree = ""; }; + 423A30F129268FB000071A8A /* ScraperView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScraperView.swift; sourceTree = ""; }; + 423A30F329268FED00071A8A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 423A30F52926A9C400071A8A /* ViewLoadExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewLoadExt.swift; sourceTree = ""; }; + 423A30F82926B65100071A8A /* BrowserToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserToolbar.swift; sourceTree = ""; }; + 423A30FA2926B70F00071A8A /* ScraperToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScraperToolbar.swift; sourceTree = ""; }; + 423AC30C290116FA00319B15 /* NSWebView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSWebView.swift; sourceTree = ""; }; 42C95D922900657A008936E3 /* scraper */ = {isa = PBXFileReference; lastKnownFileType = folder; path = scraper; sourceTree = ""; }; 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FloatingPanel.swift; sourceTree = ""; }; 42E9579C28C84C6900BF7B3B /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; @@ -63,19 +79,67 @@ 4214674328C1C5EF00E9D706 /* SearchifyX */ = { isa = PBXGroup; children = ( + 423A30F72926B57F00071A8A /* Toolbars */, + 423A30EC2926198300071A8A /* Helpers */, + 423A30EB2926197000071A8A /* Models */, + 423A30EA2926195700071A8A /* Views */, + 423A30E92926193F00071A8A /* WebView */, 42C95D922900657A008936E3 /* scraper */, 4214674428C1C5EF00E9D706 /* SearchifyXApp.swift */, - 4214674628C1C5EF00E9D706 /* ContentView.swift */, 4214674828C1C5F200E9D706 /* Assets.xcassets */, - 4214676F28C1CFB500E9D706 /* Flashcard.swift */, 4214677428C1D99300E9D706 /* Scraper.swift */, - 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */, - 42E9579C28C84C6900BF7B3B /* SettingsView.swift */, 42E9579E28C84DAC00BF7B3B /* Constants.swift */, + 423A30F329268FED00071A8A /* ContentView.swift */, ); path = SearchifyX; sourceTree = ""; }; + 423A30E92926193F00071A8A /* WebView */ = { + isa = PBXGroup; + children = ( + 423A30E72926193900071A8A /* WebViewModel.swift */, + 423AC30C290116FA00319B15 /* NSWebView.swift */, + ); + path = WebView; + sourceTree = ""; + }; + 423A30EA2926195700071A8A /* Views */ = { + isa = PBXGroup; + children = ( + 42E9579C28C84C6900BF7B3B /* SettingsView.swift */, + 423A30ED29268E6100071A8A /* NotesView.swift */, + 423A30EF29268E7700071A8A /* BrowserView.swift */, + 423A30F129268FB000071A8A /* ScraperView.swift */, + ); + path = Views; + sourceTree = ""; + }; + 423A30EB2926197000071A8A /* Models */ = { + isa = PBXGroup; + children = ( + 4214676F28C1CFB500E9D706 /* Flashcard.swift */, + ); + path = Models; + sourceTree = ""; + }; + 423A30EC2926198300071A8A /* Helpers */ = { + isa = PBXGroup; + children = ( + 42E9576E28C80FA300BF7B3B /* FloatingPanel.swift */, + 423A30F52926A9C400071A8A /* ViewLoadExt.swift */, + ); + path = Helpers; + sourceTree = ""; + }; + 423A30F72926B57F00071A8A /* Toolbars */ = { + isa = PBXGroup; + children = ( + 423A30F82926B65100071A8A /* BrowserToolbar.swift */, + 423A30FA2926B70F00071A8A /* ScraperToolbar.swift */, + ); + path = Toolbars; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -153,11 +217,19 @@ buildActionMask = 2147483647; files = ( 4214677528C1D99300E9D706 /* Scraper.swift in Sources */, + 423A30F62926A9C400071A8A /* ViewLoadExt.swift in Sources */, + 423AC30D290116FA00319B15 /* NSWebView.swift in Sources */, + 423A30EE29268E6100071A8A /* NotesView.swift in Sources */, + 423A30F229268FB000071A8A /* ScraperView.swift in Sources */, 4214677028C1CFB600E9D706 /* Flashcard.swift in Sources */, - 4214674728C1C5EF00E9D706 /* ContentView.swift in Sources */, + 423A30F029268E7700071A8A /* BrowserView.swift in Sources */, + 423A30E82926193900071A8A /* WebViewModel.swift in Sources */, 42E9579D28C84C6900BF7B3B /* SettingsView.swift in Sources */, 42E9579F28C84DAC00BF7B3B /* Constants.swift in Sources */, + 423A30F429268FED00071A8A /* ContentView.swift in Sources */, + 423A30FB2926B70F00071A8A /* ScraperToolbar.swift in Sources */, 4214674528C1C5EF00E9D706 /* SearchifyXApp.swift in Sources */, + 423A30F92926B65100071A8A /* BrowserToolbar.swift in Sources */, 42E9576F28C80FA300BF7B3B /* FloatingPanel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -299,7 +371,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 12.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.teamaurous.SearchifyX; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -327,7 +399,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 12.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.teamaurous.SearchifyX; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/macOS/SearchifyX/Constants.swift b/macOS/SearchifyX/Constants.swift index 98db160..9f484de 100644 --- a/macOS/SearchifyX/Constants.swift +++ b/macOS/SearchifyX/Constants.swift @@ -11,4 +11,6 @@ extension KeyboardShortcuts.Name { class Variables { static var hiddenWindow: NSWindow? + + static var wkModel = WebViewModel() } diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift index 2175ca0..00bee22 100644 --- a/macOS/SearchifyX/ContentView.swift +++ b/macOS/SearchifyX/ContentView.swift @@ -1,165 +1,67 @@ +// +// ContentView.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + import SwiftUI struct ContentView: View { - @State var question: String = "" - @State var enableQuizizz: Bool = true - @State var enableQuizlet: Bool = true - @State var cards: [Flashcard] = [] - @State var selected: Flashcard.ID? - @State var searching: Bool = false - @State var engine: String = "google" - @State var showingPanel: Bool = false - - @AppStorage("runAfterOcr") var runAfterOcr: Bool = false - @AppStorage("runAfterPaste") var runAfterPaste: Bool = false - var isPanel: Bool - var hasShown: Bool? - var skQuery: String? - - init(isPanel: Bool, question q: String?) { - self.isPanel = isPanel - if q != nil { - skQuery = q! - hasShown = true - } - else { - hasShown = false - } - } + var question: String? var body: some View { - VStack { - HStack { - if isPanel == false { - Button(action: { - Scraper.makeHiddenWindow(question: nil) - }, label: { - Image(systemName: "eye.slash") - }) - } - TextField("Search a question here", text: $question) - .lineLimit(nil) - Button( - action: { - searchQuestion(query: self.question) - }, - label: { + NavigationView() { + List() { + NavigationLink(destination: ScraperView(isPanel: isPanel, question: question)) { + HStack { Image(systemName: "magnifyingglass") Text("Search") } - ) - Button( - action: { - question = Scraper.getClipboard() - - if runAfterPaste { - searchQuestion(query: self.question) - } - }, - label: { - Image(systemName: "doc.on.clipboard") + } + .navigationTitle("Search") + NavigationLink(destination: BrowserView(isPanel: isPanel)) { + HStack { + Image(systemName: "globe.americas") + Text("Browser") } - ) - Button( - action: { - DispatchQueue.global(qos: .userInitiated).async { - question = Scraper.ocr() - - if runAfterOcr { - searchQuestion(query: self.question) - } - } - }, - label: { - Image(systemName: "eye") + } + .navigationTitle("Browser") + NavigationLink(destination: NotesView()) { + HStack { + Image(systemName: "note.text") + Text("Notes") } - ) - } - .disabled(searching != false) - .padding() - - ZStack { - Table(cards, selection: $selected) { - TableColumn("Question", value: \.question) - TableColumn("Answer", value: \.answer) - TableColumn("Similarity", value: \.similarity) - TableColumn("URL", value: \.url) } - - if searching { - ProgressView() + .navigationTitle("Notes") + NavigationLink(destination: SettingsView()) { + HStack { + Image(systemName: "gear") + Text("Settings") + } } + .navigationTitle("Settings") } - - HStack { - Spacer() - Picker("Search Engine", selection: $engine) { - Text("Google").tag("google") - Text("Bing").tag("bing") - Text("Startpage").tag("startpage") - } - Button(action: { - var original: Flashcard? - - for item in cards { - if (item.id == selected) { - original = item - break - } + .toolbar { + ToolbarItemGroup(placement: .navigation) { + if !isPanel { + Button(action: { + Scraper.makeHiddenWindow(question: nil) + }, label: { + Image(systemName: "eye.slash.fill") + }) } - - let url = URL(string: original!.url)! - NSWorkspace.shared.open(url) - - }, label: { - Text("Open question") - }) - .disabled(selected == nil) - Toggle(isOn: $enableQuizizz) { - Image("QuizizzIcon") - .resizable() - .frame(width: 16, height: 16) - Text("Quizizz") - } - Toggle(isOn: $enableQuizlet) { - Image("QuizletIcon") - .resizable() - .frame(width: 16, height: 16) - Text("Quizlet") } } - .padding() - } - .onAppear { - if hasShown! { - self.question = skQuery! - searchQuestion(query: skQuery!) - } - } - } - - func searchQuestion(query: String) { - searching = true - - var sites: [String] = [] - - if enableQuizizz { - sites.append("quizizz") - } - if enableQuizlet { - sites.append("quizlet") - } - - DispatchQueue.global(qos: .userInitiated).async { - cards = Scraper.search(query: query, sites: sites.joined(separator: ","), engine: engine) - searching = false + .frame() + .listStyle(.sidebar) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView(isPanel: false, question: nil) + ContentView(isPanel: false) } } diff --git a/macOS/SearchifyX/FloatingPanel.swift b/macOS/SearchifyX/Helpers/FloatingPanel.swift similarity index 90% rename from macOS/SearchifyX/FloatingPanel.swift rename to macOS/SearchifyX/Helpers/FloatingPanel.swift index fffc2ea..47a6c11 100644 --- a/macOS/SearchifyX/FloatingPanel.swift +++ b/macOS/SearchifyX/Helpers/FloatingPanel.swift @@ -7,8 +7,8 @@ class FloatingPanel: NSPanel { self.isFloatingPanel = true self.level = .floating self.collectionBehavior.insert(.fullScreenAuxiliary) - self.titleVisibility = .visible - self.titlebarAppearsTransparent = false + self.titleVisibility = .hidden + self.titlebarAppearsTransparent = true self.isMovableByWindowBackground = true self.isReleasedWhenClosed = false diff --git a/macOS/SearchifyX/Helpers/ViewLoadExt.swift b/macOS/SearchifyX/Helpers/ViewLoadExt.swift new file mode 100644 index 0000000..2b5697e --- /dev/null +++ b/macOS/SearchifyX/Helpers/ViewLoadExt.swift @@ -0,0 +1,37 @@ +// +// ViewLoadExt.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + +import Foundation +import SwiftUI + +struct ViewDidLoadModifier: ViewModifier { + + @State private var didLoad = false + private let action: (() -> Void)? + + init(perform action: (() -> Void)? = nil) { + self.action = action + } + + func body(content: Content) -> some View { + content.onAppear { + if didLoad == false { + didLoad = true + action?() + } + } + } + +} + +extension View { + + func onLoad(perform action: (() -> Void)? = nil) -> some View { + modifier(ViewDidLoadModifier(perform: action)) + } + +} diff --git a/macOS/SearchifyX/Flashcard.swift b/macOS/SearchifyX/Models/Flashcard.swift similarity index 100% rename from macOS/SearchifyX/Flashcard.swift rename to macOS/SearchifyX/Models/Flashcard.swift diff --git a/macOS/SearchifyX/SearchifyXApp.swift b/macOS/SearchifyX/SearchifyXApp.swift index 8802728..c8c1b6b 100644 --- a/macOS/SearchifyX/SearchifyXApp.swift +++ b/macOS/SearchifyX/SearchifyXApp.swift @@ -7,8 +7,9 @@ struct SearchifyXApp: App { var body: some Scene { WindowGroup { - ContentView(isPanel: false, question: nil) + ContentView(isPanel: false) } + .windowStyle(HiddenTitleBarWindowStyle()) Settings { SettingsView() } @@ -46,7 +47,7 @@ final class AppState: ObservableObject { return } - var card = Scraper.search(query: question!, sites: "quizlet,quizizz", engine: "google").first + let card = Scraper.search(query: question!, sites: "quizlet,quizizz", engine: "google").first if (card != nil) { Scraper.alert(caption: card!.question, msg: card!.answer) } diff --git a/macOS/SearchifyX/Toolbars/BrowserToolbar.swift b/macOS/SearchifyX/Toolbars/BrowserToolbar.swift new file mode 100644 index 0000000..70aa7d3 --- /dev/null +++ b/macOS/SearchifyX/Toolbars/BrowserToolbar.swift @@ -0,0 +1,39 @@ +// +// BrowserToolbar.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + +import SwiftUI + +struct BrowserToolbar: View { + var url: Binding + + var body: some View { + HStack { + Button(action: { + Variables.wkModel.instance.goBack() + }, label: { + Image(systemName: "chevron.left") + }) + .buttonStyle(.borderless) + Button(action: { + Variables.wkModel.instance.goBack() + }, label: { + Image(systemName: "chevron.right") + }) + .buttonStyle(.borderless) + TextField("Enter URL", text: url) + .frame(minWidth: 400) + .textFieldStyle(.roundedBorder) + Button(action: { + Variables.wkModel.loadUrl() + }, label: { + Text("Go") + }) + .buttonStyle(.borderless) + Spacer() + } + } +} diff --git a/macOS/SearchifyX/Toolbars/ScraperToolbar.swift b/macOS/SearchifyX/Toolbars/ScraperToolbar.swift new file mode 100644 index 0000000..4cc83e0 --- /dev/null +++ b/macOS/SearchifyX/Toolbars/ScraperToolbar.swift @@ -0,0 +1,64 @@ +// +// ScraperToolbar.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + +import SwiftUI + +struct ScraperToolbar: View { + var question: Binding + var runAfterPaste: Binding + var searchQuestion: (String) -> Void + var runAfterOcr: Binding + var searching: Binding + + var body: some View { + HStack { + TextField("Search a question here", text: question) + .lineLimit(nil) + .frame(minWidth: 400) + .textFieldStyle(.roundedBorder) + Button( + action: { + searchQuestion(self.question.wrappedValue) + }, + label: { + Image(systemName: "magnifyingglass") + Text("Search") + } + ) + .buttonStyle(.borderless) + Button( + action: { + self.question.wrappedValue = Scraper.getClipboard() + + if runAfterPaste.wrappedValue { + searchQuestion(self.question.wrappedValue) + } + }, + label: { + Image(systemName: "doc.on.clipboard") + } + ) + .buttonStyle(.borderless) + Button( + action: { + DispatchQueue.global(qos: .userInitiated).async { + question.wrappedValue = Scraper.ocr() + + if runAfterOcr.wrappedValue { + searchQuestion(self.question.wrappedValue) + } + } + }, + label: { + Image(systemName: "eye") + } + ) + .buttonStyle(.borderless) + } + .disabled(searching.wrappedValue != false) + } +} diff --git a/macOS/SearchifyX/Views/BrowserView.swift b/macOS/SearchifyX/Views/BrowserView.swift new file mode 100644 index 0000000..06e8bff --- /dev/null +++ b/macOS/SearchifyX/Views/BrowserView.swift @@ -0,0 +1,44 @@ +// +// BrowserView.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + +import SwiftUI + +struct BrowserView: View { + var urlStr: Binding { Binding( + get: { return Variables.wkModel.urlString }, set: {str in + Variables.wkModel.urlString = str + } + )} + + var isPanel: Bool + + var body: some View { + VStack { + if (isPanel) { + BrowserToolbar(url: urlStr) + .padding(.leading) + .padding(.trailing) + } + + NSWebView(webkit: Variables.wkModel.instance) + } + .toolbar { + ToolbarItemGroup(placement: .principal) { + BrowserToolbar(url: urlStr) + } + } + .onLoad { + Variables.wkModel.loadUrl() + } + } +} + +struct BrowserView_Previews: PreviewProvider { + static var previews: some View { + BrowserView(isPanel: false) + } +} diff --git a/macOS/SearchifyX/Views/ContentView.swift b/macOS/SearchifyX/Views/ContentView.swift new file mode 100644 index 0000000..d35aec3 --- /dev/null +++ b/macOS/SearchifyX/Views/ContentView.swift @@ -0,0 +1,206 @@ +import SwiftUI + +struct ContentView: View { + @State var question: String = "" + @State var enableQuizizz: Bool = true + @State var enableQuizlet: Bool = true + @State var cards: [Flashcard] = [] + @State var selected: Flashcard.ID? + @State var searching: Bool = false + @State var engine: String = "google" + @State var showingPanel: Bool = false + @State var showBrowser: Bool = false + + @StateObject var wkmodel = WebViewModel() + + @AppStorage("runAfterOcr") var runAfterOcr: Bool = false + @AppStorage("runAfterPaste") var runAfterPaste: Bool = false + + var isPanel: Bool + var hasShown: Bool? + var skQuery: String? + + init(isPanel: Bool, question q: String?) { + self.isPanel = isPanel + if q != nil { + skQuery = q! + hasShown = true + } + else { + hasShown = false + } + } + + var body: some View { + VStack { + HStack { + if isPanel == false { + Button(action: { + Scraper.makeHiddenWindow(question: nil) + }, label: { + Image(systemName: "eye.slash") + }) + } + TextField("Search a question here", text: $question) + .lineLimit(nil) + Button( + action: { + searchQuestion(query: self.question) + }, + label: { + Image(systemName: "magnifyingglass") + Text("Search") + } + ) + Button( + action: { + question = Scraper.getClipboard() + + if runAfterPaste { + searchQuestion(query: self.question) + } + }, + label: { + Image(systemName: "doc.on.clipboard") + } + ) + Button( + action: { + showBrowser = !showBrowser + }, + label: { + Image(systemName: "globe.americas.fill") + } + ) + Button( + action: { + DispatchQueue.global(qos: .userInitiated).async { + question = Scraper.ocr() + + if runAfterOcr { + searchQuestion(query: self.question) + } + } + }, + label: { + Image(systemName: "eye") + } + ) + } + .disabled(searching != false) + .padding() + + ZStack { + if showBrowser { + VStack { + HStack { + Button(action: { + wkmodel.instance.goBack() + }, label: { + Image(systemName: "chevron.left") + }) + Button(action: { + wkmodel.instance.goBack() + }, label: { + Image(systemName: "chevron.right") + }) + TextField("Enter URL", text: $wkmodel.urlString) + Button(action: { + wkmodel.loadUrl() + }, label: { + Text("Go") + }) + Spacer() + } + .padding(.trailing) + .padding(.leading) + NSWebView(webkit: wkmodel.instance) + } + } + else { + Table(cards, selection: $selected) { + TableColumn("Question", value: \.question) + TableColumn("Answer", value: \.answer) + TableColumn("Similarity", value: \.similarity) + TableColumn("URL", value: \.url) + } + + if searching { + ProgressView() + } + } + } + + HStack { + Spacer() + Picker("Search Engine", selection: $engine) { + Text("Google").tag("google") + Text("Bing").tag("bing") + Text("Startpage").tag("startpage") + } + Button(action: { + var original: Flashcard? + + for item in cards { + if (item.id == selected) { + original = item + break + } + } + + let url = URL(string: original!.url)! + wkmodel.urlString = url.absoluteString + showBrowser = true + wkmodel.loadUrl() + + }, label: { + Text("Open question") + }) + .disabled(selected == nil) + Toggle(isOn: $enableQuizizz) { + Image("QuizizzIcon") + .resizable() + .frame(width: 16, height: 16) + Text("Quizizz") + } + Toggle(isOn: $enableQuizlet) { + Image("QuizletIcon") + .resizable() + .frame(width: 16, height: 16) + Text("Quizlet") + } + } + .padding() + } + .onAppear { + if hasShown! { + self.question = skQuery! + searchQuestion(query: skQuery!) + } + } + } + + func searchQuestion(query: String) { + searching = true + + var sites: [String] = [] + + if enableQuizizz { + sites.append("quizizz") + } + if enableQuizlet { + sites.append("quizlet") + } + + DispatchQueue.global(qos: .userInitiated).async { + cards = Scraper.search(query: query, sites: sites.joined(separator: ","), engine: engine) + searching = false + } + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView(isPanel: false, question: nil) + } +} diff --git a/macOS/SearchifyX/Views/NotesView.swift b/macOS/SearchifyX/Views/NotesView.swift new file mode 100644 index 0000000..09ffe1d --- /dev/null +++ b/macOS/SearchifyX/Views/NotesView.swift @@ -0,0 +1,20 @@ +// +// NotesView.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + +import SwiftUI + +struct NotesView: View { + var body: some View { + Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) + } +} + +struct NotesView_Previews: PreviewProvider { + static var previews: some View { + NotesView() + } +} diff --git a/macOS/SearchifyX/Views/ScraperView.swift b/macOS/SearchifyX/Views/ScraperView.swift new file mode 100644 index 0000000..be27729 --- /dev/null +++ b/macOS/SearchifyX/Views/ScraperView.swift @@ -0,0 +1,127 @@ +import SwiftUI + +struct ScraperView: View { + @State var question: String = "" + @State var enableQuizizz: Bool = true + @State var enableQuizlet: Bool = true + @State var cards: [Flashcard] = [] + @State var selected: Flashcard.ID? + @State var searching: Bool = false + @State var engine: String = "google" + + @AppStorage("runAfterOcr") var runAfterOcr: Bool = false + @AppStorage("runAfterPaste") var runAfterPaste: Bool = false + + var hasShown: Bool? + var skQuery: String? + + var isPanel: Bool + + init(isPanel: Bool, question q: String?) { + self.isPanel = isPanel + if q != nil { + skQuery = q! + hasShown = true + } + else { + hasShown = false + } + } + + var body: some View { + VStack { + if isPanel { + ScraperToolbar(question: $question, runAfterPaste: $runAfterPaste, searchQuestion: searchQuestion(query:), runAfterOcr: $runAfterOcr, searching: $searching) + .padding(.leading) + .padding(.trailing) + } + + ZStack { + Table(cards, selection: $selected) { + TableColumn("Question", value: \.question) + TableColumn("Answer", value: \.answer) + TableColumn("Similarity", value: \.similarity) + TableColumn("URL", value: \.url) + } + + if searching { + ProgressView() + } + } + + HStack { + Spacer() + Picker("Search Engine", selection: $engine) { + Text("Google").tag("google") + Text("Bing").tag("bing") + Text("Startpage").tag("startpage") + } + Button(action: { + var original: Flashcard? + + for item in cards { + if (item.id == selected) { + original = item + break + } + } + + let url = URL(string: original!.url)! + Variables.wkModel.urlString = url.absoluteString + + }, label: { + Text("Open question") + }) + .disabled(selected == nil) + Toggle(isOn: $enableQuizizz) { + Image("QuizizzIcon") + .resizable() + .frame(width: 16, height: 16) + Text("Quizizz") + } + Toggle(isOn: $enableQuizlet) { + Image("QuizletIcon") + .resizable() + .frame(width: 16, height: 16) + Text("Quizlet") + } + } + .padding() + } + .onAppear { + if hasShown! { + self.question = skQuery! + searchQuestion(query: skQuery!) + } + } + .toolbar { + ToolbarItemGroup(placement: .principal) { + ScraperToolbar(question: $question, runAfterPaste: $runAfterPaste, searchQuestion: searchQuestion(query:), runAfterOcr: $runAfterOcr, searching: $searching) + } + } + } + + func searchQuestion(query: String) { + searching = true + + var sites: [String] = [] + + if enableQuizizz { + sites.append("quizizz") + } + if enableQuizlet { + sites.append("quizlet") + } + + DispatchQueue.global(qos: .userInitiated).async { + cards = Scraper.search(query: query, sites: sites.joined(separator: ","), engine: engine) + searching = false + } + } +} + +struct ScraperView_Previews: PreviewProvider { + static var previews: some View { + ScraperView(isPanel: false, question: nil) + } +} diff --git a/macOS/SearchifyX/SettingsView.swift b/macOS/SearchifyX/Views/SettingsView.swift similarity index 100% rename from macOS/SearchifyX/SettingsView.swift rename to macOS/SearchifyX/Views/SettingsView.swift diff --git a/macOS/SearchifyX/WebView/NSWebView.swift b/macOS/SearchifyX/WebView/NSWebView.swift new file mode 100644 index 0000000..20decdd --- /dev/null +++ b/macOS/SearchifyX/WebView/NSWebView.swift @@ -0,0 +1,21 @@ +// +// WebView.swift +// SearchifyX +// +// Created by Jose Molina on 10/20/22. +// + +import Foundation +import WebKit +import SwiftUI + +struct NSWebView: NSViewRepresentable { + let webkit: WKWebView + + func makeNSView(context: Context) -> WKWebView { + webkit + } + + func updateNSView(_ nsView: WKWebView, context: Context) { + } +} diff --git a/macOS/SearchifyX/WebView/WebView.swift b/macOS/SearchifyX/WebView/WebView.swift new file mode 100644 index 0000000..ca13cda --- /dev/null +++ b/macOS/SearchifyX/WebView/WebView.swift @@ -0,0 +1,22 @@ +// +// WebView.swift +// SearchifyX +// +// Created by Jose Molina on 10/24/22. +// + +import SwiftUI + +struct WebView: View { + @StateObject var model = WebViewModel() + + var body: some View { + + } +} + +struct WebView_Previews: PreviewProvider { + static var previews: some View { + WebView() + } +} diff --git a/macOS/SearchifyX/WebView/WebViewModel.swift b/macOS/SearchifyX/WebView/WebViewModel.swift new file mode 100644 index 0000000..31c43e4 --- /dev/null +++ b/macOS/SearchifyX/WebView/WebViewModel.swift @@ -0,0 +1,27 @@ +// +// WebViewModel.swift +// SearchifyX +// +// Created by Jose Molina on 11/17/22. +// + +import Foundation +import WebKit + +class WebViewModel: ObservableObject { + @Published var urlString: String = "https://google.com/" + + let instance: WKWebView + + init() { + instance = WKWebView(frame: .zero); + } + + func loadUrl() { + guard let url = URL(string: urlString) else { + return + } + + instance.load(URLRequest(url: url)) + } +} diff --git a/macOS/clean.sh b/macOS/clean.sh old mode 100755 new mode 100644 From 2ea635ec422607390b35800b4e388b8e32718d6d Mon Sep 17 00:00:00 2001 From: kuro <72637910+daijro@users.noreply.github.com> Date: Tue, 27 Dec 2022 12:09:01 -0600 Subject: [PATCH 27/39] Clean code, add Singleton, etc - Only allow once instance to be ran at a time - Search C:\Program Files\ for tesseract path - Remove redundant findChild lines --- gui.pyw | 64 +++++------------------------------------------------ textshot.py | 9 +++++++- window.ui | 12 +++++----- 3 files changed, 19 insertions(+), 66 deletions(-) diff --git a/gui.pyw b/gui.pyw index ae81d4a..b588fcc 100644 --- a/gui.pyw +++ b/gui.pyw @@ -1,3 +1,6 @@ +from tendo.singleton import SingleInstance +me = SingleInstance() + import ctypes import os import sys @@ -66,38 +69,6 @@ class UI(QMainWindow): self.conf = self.loadjson() # get old config self.set_conf_keys() - - ''' - find the widgets in the xml file and set slots - ''' - - # title bar - self.transp_slider = self.findChild(QtWidgets.QSlider, "transparency_slider") - self.toggle_noactive = self.findChild(QtWidgets.QPushButton, "toggle_noactive_style") - self.minimize_button = self.findChild(QtWidgets.QPushButton, "minimize_button") - self.close_button = self.findChild(QtWidgets.QPushButton, "close_button") - self.copy_button = self.findChild(QtWidgets.QPushButton, "copy_button") - self.titleIcon = self.findChild(QtWidgets.QLabel, "titleIcon") - self.titleBar = self.findChild(QtWidgets.QFrame, "titleBar") - - # search bar area - self.search_bar = self.findChild(QtWidgets.QLineEdit, "search_bar") - self.search_button = self.findChild(QtWidgets.QPushButton, "search_button") - self.ocr_button = self.findChild(QtWidgets.QPushButton, "ocr_button") - self.paste_button = self.findChild(QtWidgets.QPushButton, "paste_button") - self.search_frame = self.findChild(QtWidgets.QFrame, "search_frame") - - # body - self.treeWidget = self.findChild(QtWidgets.QTreeWidget, "treeWidget") - self.stackedWidget = self.findChild(QtWidgets.QStackedWidget, "stackedWidget") - - # bottom row - self.copy_button = self.findChild(QtWidgets.QPushButton, "copy_button") - self.status_label = self.findChild(QtWidgets.QLabel, "status_label") - self.quizlet_button = self.findChild(QtWidgets.QPushButton, "quizlet_button") - self.quizizz_button = self.findChild(QtWidgets.QPushButton, "quizizz_button") - self.settings_button = self.findChild(QtWidgets.QPushButton, "settings_button") - self.quizlet_button.setChecked(self.conf['quizlet']) self.quizizz_button.setChecked(self.conf['quizizz']) @@ -120,12 +91,6 @@ class UI(QMainWindow): self.hotkeys = KeyboardManager() self.window_shown = True - self.hide_show_key = self.findChild(QtWidgets.QKeySequenceEdit, "hide_show_key") - self.ocr_key = self.findChild(QtWidgets.QKeySequenceEdit, "ocr_key") - self.paste_key = self.findChild(QtWidgets.QKeySequenceEdit, "paste_key") - self.win_transp_key = self.findChild(QtWidgets.QKeySequenceEdit, "win_transp_key") - self.win_trasp_value = self.findChild(QtWidgets.QSpinBox, "win_trasp_value") - self.hide_show_key.setKeySequence(QtGui.QKeySequence.fromString(self.conf['hide_show_key'])) self.ocr_key.setKeySequence(QtGui.QKeySequence.fromString(self.conf['ocr_key'])) self.paste_key.setKeySequence(QtGui.QKeySequence.fromString(self.conf['paste_key'])) @@ -150,21 +115,12 @@ class UI(QMainWindow): win_trasp_cmd() # clear hotkey - self.hide_show_key_clear = self.findChild(QtWidgets.QPushButton, "hide_show_key_clear") - self.ocr_key_clear = self.findChild(QtWidgets.QPushButton, "ocr_key_clear") - self.paste_key_clear = self.findChild(QtWidgets.QPushButton, "paste_key_clear") - self.win_transp_key_clear = self.findChild(QtWidgets.QPushButton, "win_transp_key_clear") - self.hide_show_key_clear.clicked.connect(lambda: [x() for x in [self.hide_show_key.clear, hide_show_cmd]]) self.ocr_key_clear.clicked.connect(lambda: [x() for x in [self.ocr_key.clear, ocr_cmd]]) self.paste_key_clear.clicked.connect(lambda: [x() for x in [self.paste_key.clear, paste_cmd]]) self.win_transp_key_clear.clicked.connect(lambda: [x() for x in [self.win_transp_key.clear, win_trasp_cmd]]) # checks - self.setting_search_ocr = self.findChild(QtWidgets.QCheckBox, "setting_search_ocr") - self.setting_search_paste = self.findChild(QtWidgets.QCheckBox, "setting_search_paste") - self.setting_hide_taskbar = self.findChild(QtWidgets.QCheckBox, "setting_hide_taskbar") - self.setting_search_ocr.setChecked(self.conf['search_ocr']) self.setting_search_ocr.toggled.connect(lambda: self.updatejson('search_ocr')) @@ -174,12 +130,6 @@ class UI(QMainWindow): self.setting_hide_taskbar.setChecked(self.conf['hide_taskbar']) self.setting_hide_taskbar.toggled.connect(lambda: self.set_hide_taskbar()) - self.setting_save_focus = self.findChild(QtWidgets.QCheckBox, "setting_save_focus") - self.setting_save_transp = self.findChild(QtWidgets.QCheckBox, "setting_save_transp") - self.setting_save_pos = self.findChild(QtWidgets.QCheckBox, "setting_save_pos") - self.setting_rightclick_reset = self.findChild(QtWidgets.QCheckBox, "setting_rightclick_reset") - self.setting_on_top = self.findChild(QtWidgets.QCheckBox, "setting_on_top") - if self.conf['save_focus'] != None: self.setting_save_focus.setChecked(True) self.toggle_noactive.setChecked(self.conf['save_focus']) @@ -205,8 +155,6 @@ class UI(QMainWindow): self.search_engine_combo.currentIndexChanged.connect(lambda: self.run_search_engine()) # window theme - self.themeInput = self.findChild(QtWidgets.QComboBox, "themeInput") - self.font_size = self.findChild(QtWidgets.QSpinBox, "font_size") self.themeInput.setCurrentIndex(self.conf['theme']) self.font_size.setValue(self.conf['font_size']) @@ -215,8 +163,6 @@ class UI(QMainWindow): self.font_size.valueChanged.connect(self.set_window_theme) # exit settings - self.back_button = self.findChild(QtWidgets.QPushButton, "back_button") - self.back_label = self.findChild(QtWidgets.QLabel, "back_label") self.back_label.mousePressEvent = lambda x: self.stackedWidget.setCurrentIndex(0) if x.button() == Qt.LeftButton else None self.back_button.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(0)) @@ -275,7 +221,7 @@ class UI(QMainWindow): cursor = QtGui.QCursor.pos() area = GetMonitorInfo(MonitorFromPoint((cursor.x(), cursor.y()))) - work = area.get('Work') + work = area.get('Work') if not work: screen = QtWidgets.QApplication.screenAt(cursor).geometry() # get screen work = (screen.width(), screen.height()) @@ -373,7 +319,7 @@ class UI(QMainWindow): # data entry tools def run_ocr_tool(self, force_run_searcher=False): - if not os.path.exists(resource_path('tesseract-ocr')): + if not check_tesseract_paths(): self.status_label.setText('Tesseract not found.') return diff --git a/textshot.py b/textshot.py index cae8cc3..34f67ab 100644 --- a/textshot.py +++ b/textshot.py @@ -32,7 +32,14 @@ def resource_path(relative_path): base_path = os.path.dirname(__file__) return os.path.join(base_path, relative_path) -pytesseract.pytesseract.tesseract_cmd = resource_path(r"tesseract-ocr\tesseract.exe") + +def check_tesseract_paths(): + for path in (resource_path(r"tesseract-ocr\tesseract.exe"), r'C:\Program Files\Tesseract-OCR\tesseract.exe'): + if os.path.exists(path): + return path + + +pytesseract.pytesseract.tesseract_cmd = check_tesseract_paths() user32 = ctypes.windll.user32 diff --git a/window.ui b/window.ui index 8ae405e..175cb81 100644 --- a/window.ui +++ b/window.ui @@ -385,9 +385,9 @@ 0 - -77 - 656 - 465 + 0 + 395 + 668 @@ -1013,7 +1013,7 @@ - + 100 @@ -1041,7 +1041,7 @@ - + 30 @@ -1061,7 +1061,7 @@ - Unlock window (allow focus) + Toggle window safety lock From 163b75f53cf8b205f99d67b60c71de337f53f53f Mon Sep 17 00:00:00 2001 From: kuro <72637910+daijro@users.noreply.github.com> Date: Tue, 27 Dec 2022 12:19:24 -0600 Subject: [PATCH 28/39] Bump dependencies --- macOS/requirements.txt | 2 +- requirements.txt | 53 +++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/macOS/requirements.txt b/macOS/requirements.txt index 3d0c76a..3e9ed5e 100644 --- a/macOS/requirements.txt +++ b/macOS/requirements.txt @@ -2,5 +2,5 @@ beautifulsoup4==4.11.1 fake_headers==1.0.2 grequests==0.6.0 requests_html==0.10.0 -setuptools==63.2.0 +setuptools py2app==0.28.2 diff --git a/requirements.txt b/requirements.txt index 413d27f..6019a50 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,44 +1,45 @@ appdirs==1.4.4 -beautifulsoup4==4.10.0 +beautifulsoup4==4.11.1 bs4==0.0.1 certifi==2022.12.7 -cffi==1.15.0 -charset-normalizer==2.0.9 -colorama==0.4.4 -cssselect==1.1.0 +cffi==1.15.1 +charset-normalizer==2.1.1 +colorama==0.4.6 +cssselect==1.2.0 fake-headers==1.0.2 -fake-useragent==0.1.11 -gevent==21.12.0 -greenlet==1.1.2 +fake-useragent==1.1.1 +gevent==22.10.2 +greenlet==2.0.1 grequests==0.6.0 html5lib==1.1 -idna==3.3 -importlib-metadata==4.11.3 +idna==3.4 +importlib-metadata==5.2.0 +importlib-resources==5.10.1 keyboard==0.13.5 -lxml==4.9.1 -packaging==21.3 +lxml==4.9.2 +packaging==22.0 parse==1.19.0 Pillow==9.3.0 pycparser==2.21 pyee==8.2.2 -pyparsing==3.0.8 pyperclip==1.8.2 pyppeteer==1.0.2 -PyQt5==5.15.6 +PyQt5==5.15.7 PyQt5-Qt5==5.15.2 -PyQt5-sip==12.9.0 +PyQt5-sip==12.11.0 pyquery==1.4.3 -pytesseract==0.3.9 -pywin32==303 -requests==2.26.0 +pytesseract==0.3.10 +pywin32==305 +requests==2.28.1 requests-html==0.10.0 six==1.16.0 -soupsieve==2.3.1 -tqdm==4.64.0 -urllib3==1.26.7 -w3lib==1.22.0 +soupsieve==2.3.2.post1 +tendo==0.3.0 +tqdm==4.64.1 +urllib3==1.26.13 +w3lib==2.1.1 webencodings==0.5.1 -websockets==10.2 -zipp==3.8.0 -zope.event==4.5.0 -zope.interface==5.4.0 +websockets==10.4 +zipp==3.11.0 +zope.event==4.6 +zope.interface==5.5.2 \ No newline at end of file From 22de499864c8c523f946e80577945ab429edc871 Mon Sep 17 00:00:00 2001 From: daijro Date: Sat, 31 Dec 2022 05:33:51 -0600 Subject: [PATCH 29/39] Add support for typing with window safety lock - Added experimental support for typing while the window focus safety lock is enabled. Works by listening for global key inputs, and forwards them to the search bar - Requires mouse dependency to detect when user clicks off window --- gui.pyw | 92 +++++++++++++++++++++++++++++++++++++++++++----- requirements.txt | 1 + 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/gui.pyw b/gui.pyw index b588fcc..2ab64bf 100644 --- a/gui.pyw +++ b/gui.pyw @@ -6,9 +6,10 @@ import os import sys import time from ctypes.wintypes import MSG -from threading import Thread +from threading import Thread, Event import json import keyboard +import mouse import win32api import win32con from pyperclip import paste @@ -84,7 +85,6 @@ class UI(QMainWindow): self.quizlet_button.setIcon(QtGui.QIcon(resource_path("img\\quizlet.png"))) self.titleIcon.setPixmap(QtGui.QPixmap(resource_path("img\\search.png"))) - # SETTINGS PAGE # hotkeys @@ -155,7 +155,6 @@ class UI(QMainWindow): self.search_engine_combo.currentIndexChanged.connect(lambda: self.run_search_engine()) # window theme - self.themeInput.setCurrentIndex(self.conf['theme']) self.font_size.setValue(self.conf['font_size']) @@ -163,10 +162,14 @@ class UI(QMainWindow): self.font_size.valueChanged.connect(self.set_window_theme) # exit settings - self.back_label.mousePressEvent = lambda x: self.stackedWidget.setCurrentIndex(0) if x.button() == Qt.LeftButton else None self.back_button.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(0)) + # search bar events + self.search_bar.focusInEvent = self.search_bar_focus_in + self.search_bar.focusOutEvent = self.search_bar_focus_out + self._modifiers = QtCore.Qt.KeyboardModifiers() + self._bar_thread_end = None # set connections self.search_bar.returnPressed.connect(self.run_searcher) @@ -178,7 +181,6 @@ class UI(QMainWindow): self.paste_button.clicked.connect(self.paste_text) self.search_button.clicked.connect(self.run_searcher) - # set column width self.treeWidget.setColumnWidth(1, 250) @@ -212,6 +214,80 @@ class UI(QMainWindow): # show ui self.show() + # search bar keyboard listener + + def search_bar_focus_in(self, event): + # create thread to listen for keyboard events + if self.toggle_noactive.isChecked(): + self._bar_thread_end = Event() + self._bar_thread = Thread(target=self.search_bar_listener, daemon=True) + self._bar_thread.start() + Thread(target=self.listen_mouse_out, daemon=True).start() + super(QtWidgets.QLineEdit, self.search_bar).focusInEvent(event) + + def search_bar_listener(self): + # hacky method to activate cursor + for key, mod in ((QtCore.Qt.Key_Left, QtCore.Qt.ShiftModifier), (QtCore.Qt.Key_Right, QtCore.Qt.NoModifier)): + QtWidgets.QApplication.postEvent(self.search_bar, + QtGui.QKeyEvent(QtGui.QKeyEvent.KeyPress, key, mod, text='')) + # listen for keyboard events, and forward them to the search bar + hook = keyboard.hook(self.search_bar_keypress, suppress=True) + self._bar_thread_end.wait() + keyboard.unhook(hook) + + def listen_mouse_out(self): + # if mouse is out, deactivate cursor + mouse_hook = mouse.on_click( + lambda: None + if self.geometry().contains(QtGui.QCursor.pos()) + else self.search_bar.clearFocus() + ) + self._bar_thread_end.wait() + mouse.unhook(mouse_hook) + + scan_code_map = { + 75: QtCore.Qt.Key_Left, + 77: QtCore.Qt.Key_Right, + 14: QtCore.Qt.Key_Backspace, + 57: QtCore.Qt.Key_Space, + 71: QtCore.Qt.Key_Home, + 79: QtCore.Qt.Key_End, + 83: QtCore.Qt.Key_Delete, + 28: QtCore.Qt.Key_Return, + } + modifier_map = { + 29: QtCore.Qt.ControlModifier, + 42: QtCore.Qt.ShiftModifier, + 56: QtCore.Qt.AltModifier, + } + + def search_bar_keypress(self, key: keyboard.KeyboardEvent): + # send the keypress to the self.search_bar + if key.scan_code in self.modifier_map: + if key.event_type == 'down': + self._modifiers = self._modifiers | self.modifier_map[key.scan_code] + else: + self._modifiers = self._modifiers & ~self.modifier_map[key.scan_code] + return + + scan_code = self.scan_code_map.get(key.scan_code, key.scan_code) + keypress = QtGui.QKeyEvent( + {'up': QtGui.QKeyEvent.KeyRelease, 'down': QtGui.QKeyEvent.KeyPress}[key.event_type], + scan_code, + self._modifiers, + text=key.name if len(key.name) == 1 else ' ' if key.name == 'space' else '', + ) + # print(keypress.key(), key.scan_code, key.event_type, key.is_keypad, self._modifiers) + # send the keypress to the search bar + QtWidgets.QApplication.postEvent(self.search_bar, keypress) + + + def search_bar_focus_out(self, event): + # kill thread + self._bar_thread_end.set() + self._bar_thread.join() + super(QtWidgets.QLineEdit, self.search_bar).focusOutEvent(event) + # setting window attributes def set_window_opacity(self): @@ -437,7 +513,8 @@ class UI(QMainWindow): else: self.remove_noactive_style() # set placeholder text om lineEdit - self.search_bar.setPlaceholderText('Window focus safety lock on' if x else 'Type a question here') + self.search_bar.setPlaceholderText('Type a question here (Window focus safety ON)' if x else 'Type a question here') + self._bar_thread_end and self._bar_thread_end.set() # end safety lock typing thread # hide minimize button self.minimize_button.setVisible(not (x or self.setting_hide_taskbar.isChecked())) self.updatejson('save_focus') @@ -566,9 +643,6 @@ dark_titleBar_palette = QtGui.QPalette() dark_titleBar_palette.setColor(QtGui.QPalette.Window, (QtGui.QColor(28, 38, 48))) - - - MainWindow = QtWidgets.QMainWindow() try: diff --git a/requirements.txt b/requirements.txt index 6019a50..3eeb4a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,6 +17,7 @@ importlib-metadata==5.2.0 importlib-resources==5.10.1 keyboard==0.13.5 lxml==4.9.2 +mouse==0.7.1 packaging==22.0 parse==1.19.0 Pillow==9.3.0 From 7f8018f2a471358434450a6492592877d8d17907 Mon Sep 17 00:00:00 2001 From: daijro Date: Sat, 31 Dec 2022 05:39:21 -0600 Subject: [PATCH 30/39] Added support for Num Lock and Caps Lock Added support for Num Lock and Caps Lock when window focus safety lock is enabled --- gui.pyw | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gui.pyw b/gui.pyw index 2ab64bf..225ca85 100644 --- a/gui.pyw +++ b/gui.pyw @@ -260,7 +260,8 @@ class UI(QMainWindow): 42: QtCore.Qt.ShiftModifier, 56: QtCore.Qt.AltModifier, } - + key_exceptions = {58, 69} + def search_bar_keypress(self, key: keyboard.KeyboardEvent): # send the keypress to the self.search_bar if key.scan_code in self.modifier_map: @@ -269,7 +270,12 @@ class UI(QMainWindow): else: self._modifiers = self._modifiers & ~self.modifier_map[key.scan_code] return - + if key.scan_code in self.key_exceptions: + if key.event_type == 'down': + keyboard.press(key.scan_code) + else: + keyboard.release(key.scan_code) + return scan_code = self.scan_code_map.get(key.scan_code, key.scan_code) keypress = QtGui.QKeyEvent( {'up': QtGui.QKeyEvent.KeyRelease, 'down': QtGui.QKeyEvent.KeyPress}[key.event_type], From 2c3de9031395594405cb7b282ecc390c113b3230 Mon Sep 17 00:00:00 2001 From: daijro Date: Sat, 31 Dec 2022 05:59:46 -0600 Subject: [PATCH 31/39] Merge threads/code cleanup - Merge keyboard and mouse hook threads - Lose focus on windows key - Add comments - Fix error when losing focus on search bar without window safety lock on --- gui.pyw | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/gui.pyw b/gui.pyw index 225ca85..7adc055 100644 --- a/gui.pyw +++ b/gui.pyw @@ -169,7 +169,7 @@ class UI(QMainWindow): self.search_bar.focusInEvent = self.search_bar_focus_in self.search_bar.focusOutEvent = self.search_bar_focus_out self._modifiers = QtCore.Qt.KeyboardModifiers() - self._bar_thread_end = None + self._bar_thread = self._bar_thread_end = None # set connections self.search_bar.returnPressed.connect(self.run_searcher) @@ -222,7 +222,6 @@ class UI(QMainWindow): self._bar_thread_end = Event() self._bar_thread = Thread(target=self.search_bar_listener, daemon=True) self._bar_thread.start() - Thread(target=self.listen_mouse_out, daemon=True).start() super(QtWidgets.QLineEdit, self.search_bar).focusInEvent(event) def search_bar_listener(self): @@ -231,20 +230,16 @@ class UI(QMainWindow): QtWidgets.QApplication.postEvent(self.search_bar, QtGui.QKeyEvent(QtGui.QKeyEvent.KeyPress, key, mod, text='')) # listen for keyboard events, and forward them to the search bar - hook = keyboard.hook(self.search_bar_keypress, suppress=True) - self._bar_thread_end.wait() - keyboard.unhook(hook) - - def listen_mouse_out(self): - # if mouse is out, deactivate cursor mouse_hook = mouse.on_click( lambda: None if self.geometry().contains(QtGui.QCursor.pos()) else self.search_bar.clearFocus() ) + hook = keyboard.hook(self.search_bar_keypress, suppress=True) self._bar_thread_end.wait() + keyboard.unhook(hook) mouse.unhook(mouse_hook) - + scan_code_map = { 75: QtCore.Qt.Key_Left, 77: QtCore.Qt.Key_Right, @@ -270,12 +265,18 @@ class UI(QMainWindow): else: self._modifiers = self._modifiers & ~self.modifier_map[key.scan_code] return + # exempt select keys if key.scan_code in self.key_exceptions: if key.event_type == 'down': keyboard.press(key.scan_code) else: keyboard.release(key.scan_code) return + # exit on meta key + elif key.scan_code == 91: + self.search_bar.clearFocus() + return + scan_code = self.scan_code_map.get(key.scan_code, key.scan_code) keypress = QtGui.QKeyEvent( {'up': QtGui.QKeyEvent.KeyRelease, 'down': QtGui.QKeyEvent.KeyPress}[key.event_type], @@ -287,11 +288,11 @@ class UI(QMainWindow): # send the keypress to the search bar QtWidgets.QApplication.postEvent(self.search_bar, keypress) - def search_bar_focus_out(self, event): # kill thread - self._bar_thread_end.set() - self._bar_thread.join() + if self._bar_thread and self._bar_thread.is_alive(): + self._bar_thread_end.set() + self._bar_thread.join() super(QtWidgets.QLineEdit, self.search_bar).focusOutEvent(event) # setting window attributes @@ -322,7 +323,6 @@ class UI(QMainWindow): for obj in [self.quizizz_button, self.quizlet_button]: obj.setIconSize(QtCore.QSize(font_size*2, font_size*2)) - if theme == 2 or (DARK_MODE and not theme): # dark app.setPalette(dark_palette) self.titleBar.setPalette(dark_titleBar_palette) From d7933a4f504489f4e9f8d2060235c5543d03cbe0 Mon Sep 17 00:00:00 2001 From: daijro Date: Sat, 31 Dec 2022 16:33:44 -0600 Subject: [PATCH 32/39] Fixes for typing with window safety lock - Ignore key events with None name - Add Ctrl+A to select all --- gui.pyw | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gui.pyw b/gui.pyw index 7adc055..d1781d0 100644 --- a/gui.pyw +++ b/gui.pyw @@ -276,6 +276,13 @@ class UI(QMainWindow): elif key.scan_code == 91: self.search_bar.clearFocus() return + # ignore None events + elif not key.name: + return + # handle ctrl+a + elif key.scan_code == 30 and self._modifiers & QtCore.Qt.ControlModifier: + self.search_bar.selectAll() + return scan_code = self.scan_code_map.get(key.scan_code, key.scan_code) keypress = QtGui.QKeyEvent( From c1585cc2f7926520ecf454eff19e9795319625cc Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Tue, 3 Jan 2023 20:02:40 -0600 Subject: [PATCH 33/39] Add DuckDuckGo scraper --- scraper.py | 63 ++++++++++++++++++++++++++++++++---------------------- window.ui | 5 +++++ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/scraper.py b/scraper.py index 31ee4dc..e4a08d3 100644 --- a/scraper.py +++ b/scraper.py @@ -63,38 +63,49 @@ def _make_headers(): return {**headers, **Headers(headers=True, browser='chrome', os='windows').generate()} +_web_engines = { + 'google': { + 'domain': 'https://www.google.com/', + 'query': 'q', + 'args': {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'}, + 'limit': 2038, + 'start_sess': False, + }, + 'bing': { + 'domain': 'https://www.bing.com/', + 'query': 'q', + 'args': {'ghsh': '0', 'ghacc': '0', 'ghpl': ''}, + 'limit': 990, + 'start_sess': True, + }, + 'startpage': { + 'domain': 'https://www.startpage.com/', + 'limit': 2038, + 'start_sess': True, + }, + 'duckduckgo': { + 'domain': 'https://ddg-webapp-aagd.vercel.app/', + 'query': 'q', + 'args': {'max_results': '10'}, + 'limit': 490, + 'start_sess': False, + } +} + class SearchEngine: def __init__(self, engine_name): self.sess = HTMLSession() self.engine_name = engine_name - self._web_engines = { # simple scrapers using get requests - 'google': { - 'domain': 'https://www.google.com/', - 'query': 'q', - 'args': {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'}, - 'limit': 2038 - }, - 'bing': { - 'domain': 'https://www.bing.com/', - 'query': 'q', - 'args': {'ghsh': '0', 'ghacc': '0', 'ghpl': ''}, - 'limit': 990 - }, - 'startpage': { - 'domain': 'https://www.startpage.com/', - 'limit': 2038 - } - } - self.sess.headers.update({**headers, "Sec-Fetch-Site": "same-origin", 'Referer': self._web_engines[self.engine_name]['domain']}) + self.sess.headers.update({**headers, "Sec-Fetch-Site": "same-origin", 'Referer': _web_engines[self.engine_name]['domain']}) print('Starting instance...') self.t = Thread(target=self._init_search) self.t.daemon = True self.t.start() def _init_search(self): - if self.engine_name == 'google': + if not _web_engines[self.engine_name]['start_sess']: return - r = self.sess.get(self._web_engines[self.engine_name]['domain']) + r = self.sess.get(_web_engines[self.engine_name]['domain']) if self.engine_name == 'startpage': self._startpage_data = self.get_startpage_items(r) @@ -103,7 +114,7 @@ def startpage_get_page(self, query, sites): grequests.post('https://www.startpage.com/sp/search', data={ **self._startpage_data, - 'query': f"{query[:self._web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com" + 'query': f"{query[:_web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com" }, session=self.sess ) @@ -128,14 +139,14 @@ def get_page(self, query, sites): if self.engine_name == 'startpage': return self.startpage_get_page(query, sites) elif self.engine_name == 'google': - self.sess.headers['Referer'] = self._web_engines[self.engine_name]['domain'] = f'https://www.google.{choice(google_domains)}/' + self.sess.headers['Referer'] = _web_engines[self.engine_name]['domain'] = f'https://www.google.{choice(google_domains)}/' return dict(zip( sites, grequests.map([ grequests.get( - (web_engine := self._web_engines[self.engine_name])['domain'] + 'search?' + (web_engine := _web_engines[self.engine_name])['domain'] + 'search?' + urlencode({ - web_engine['query']: f"{query[:self._web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com", + web_engine['query']: f"{query[:_web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com", **web_engine['args'] }), session=self.sess @@ -378,7 +389,7 @@ def sort_flashcards(self): # sourcery skip: for-index-replacement parser.add_argument('--query', '-q', help='query to search for', default=None) parser.add_argument('--output', '-o', help='output file', default=None) parser.add_argument('--sites', '-s', help='question sources quizlet,quizizz (comma seperated list)', default='quizlet,quizizz') - parser.add_argument('--engine', '-e', help='search engine to use (google, bing)', default='bing') + parser.add_argument('--engine', '-e', help='search engine to use', default='bing', choices=_web_engines.keys()) args = parser.parse_args() if args.output: diff --git a/window.ui b/window.ui index 175cb81..c460e9d 100644 --- a/window.ui +++ b/window.ui @@ -791,6 +791,11 @@ Bing + + + DuckDuckGo + + Google From f8f76e5b51e4e5ae22d0ccfd1f6a149884309a99 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Wed, 4 Jan 2023 05:39:13 -0600 Subject: [PATCH 34/39] Update README.md --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1ab8144..9e1d095 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Install the [Python 3.8](https://www.python.org/downloads/release/python-389/) d python -m pip install -r requirements.txt ``` -You also need to download [tesseract-ocr](https://www.dropbox.com/s/abuo044ayx4vlex/tesseract-ocr.7z?dl=1) and extract it to the root directory to use the OCR tool. +You also need to [install](https://www.dropbox.com/s/abuo044ayx4vlex/tesseract-ocr.7z?dl=1) Tesseract to use the OCR tool, or *download and extract* the [portable archive](https://www.dropbox.com/s/abuo044ayx4vlex/tesseract-ocr.7z?dl=1) to the root directory.


@@ -39,7 +39,7 @@ An alternative for Linux/Mac OS users is to use [`scraper.py`](https://github.co Usage: ``` -scraper.py [-h] [--query QUERY] [--output OUTPUT] [--sites SITES] +scraper.py [-h] [--query QUERY] [--output OUTPUT] [--sites SITES] [--engine {google,bing,startpage,duckduckgo}] ``` Required arguments: @@ -57,7 +57,9 @@ Optional arguments: --output OUTPUT, -o OUTPUT output file (optional) --sites SITES, -s SITES - question sources quizlet,quizizz,brainly (comma seperated list) + question sources quizlet,quizizz (comma seperated list) +--engine ENGINE, -e ENGINE + search engine to use ``` --- @@ -65,7 +67,7 @@ Optional arguments: ## What it does -- Searches Bing for Quizlet, Quizizz, and Brainly results +- Searches online for Quizlet and Quizizz results - Sort results by how similar the identified question is to the input question @@ -96,7 +98,6 @@ Optional arguments: Many websites can detect when the window focus is lost. SearchifyX includes a __window switching safety lock__ to prevent websites from knowing you are using a different window. -*Note: The text search bar does not work when the Window switch safety lock is enabled. It is designed to be used with the OCR tool and Paste & Search tool.* Here is a [demo website](https://www.codingwithjesse.com/demo/2007-05-16-detect-browser-window-focus/) that turns black when the window is out of focus: @@ -114,9 +115,9 @@ Here is a [demo website](https://www.codingwithjesse.com/demo/2007-05-16-detect- - Added global hotkeys -- MAJOR changes to UI +- *Major* changes to UI -- MAJOR changes web scraper code (averages 1-2 seconds now; uses significantly less CPU) +- *Major* changes web scraper code (averages 1-2 seconds now; uses significantly less CPU) - Completely fixed the "Too many requests" error From bfbf2a07102baca2af9c79fac714e61e3aaf4184 Mon Sep 17 00:00:00 2001 From: daijro <72637910+daijro@users.noreply.github.com> Date: Sat, 7 Jan 2023 00:25:11 -0600 Subject: [PATCH 35/39] Replace regex findall with search --- scraper.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scraper.py b/scraper.py index e4a08d3..5f94e95 100644 --- a/scraper.py +++ b/scraper.py @@ -247,7 +247,7 @@ def __init__(self, links, query): self.resps = None self.quizlets = [] self.query = query - self._regex_obj = re.compile('\\= \\{"alphabeticalIsDifferent.*\\}; QLoad\\(') + self._regex_obj = re.compile('\\= (\\{"alphabeticalIsDifferent.*\\}); QLoad\\(') def async_requests(self, links): reqs = [grequests.get(u, headers=_make_headers()) for u in links] @@ -265,7 +265,7 @@ def parse_links(self): def quizlet_parser(self, resp): - data = json.loads(re.findall(self._regex_obj, resp.text)[0][2:-8]) # get quizlet headerData + data = json.loads(re.search(self._regex_obj, resp.text)[1]) # get quizlet headerData return max( ( { From 821be9ba0b135217f21dbcd126277d9e8f2161a4 Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Wed, 18 Jan 2023 09:51:04 -0600 Subject: [PATCH 36/39] Changed browser, solving merge conflicts --- config.json | 20 - fonts/OFL.txt | 93 -- fonts/Poppins Medium.ttf | Bin 156480 -> 0 bytes gui.pyw | 634 --------- img/quizizz.png | Bin 6581 -> 0 bytes img/quizlet.png | Bin 7017 -> 0 bytes img/search.png | Bin 19761 -> 0 bytes .../xcschemes/SearchifyX.xcscheme | 78 ++ macOS/SearchifyX/ContentView.swift | 16 +- macOS/SearchifyX/SearchifyXApp.swift | 1 + .../SearchifyX/Toolbars/BrowserToolbar.swift | 2 +- macOS/SearchifyX/Views/BrowserView.swift | 12 +- macOS/SearchifyX/WebView/WebViewModel.swift | 37 +- macOS/build.sh | 3 +- macOS/requirements.txt | 5 - requirements.txt | 44 - scraper.py | 414 ------ textshot.py | 188 --- window.ui | 1183 ----------------- windoweffect/LICENSE | 21 - windoweffect/__init__.py | 2 - windoweffect/c_structures.py | 135 -- windoweffect/window_effect.py | 114 -- 23 files changed, 131 insertions(+), 2871 deletions(-) delete mode 100644 config.json delete mode 100644 fonts/OFL.txt delete mode 100644 fonts/Poppins Medium.ttf delete mode 100644 gui.pyw delete mode 100644 img/quizizz.png delete mode 100644 img/quizlet.png delete mode 100644 img/search.png create mode 100644 macOS/SearchifyX.xcodeproj/xcshareddata/xcschemes/SearchifyX.xcscheme delete mode 100644 macOS/requirements.txt delete mode 100644 requirements.txt delete mode 100644 scraper.py delete mode 100644 textshot.py delete mode 100644 window.ui delete mode 100644 windoweffect/LICENSE delete mode 100644 windoweffect/__init__.py delete mode 100644 windoweffect/c_structures.py delete mode 100644 windoweffect/window_effect.py diff --git a/config.json b/config.json deleted file mode 100644 index 4139f9f..0000000 --- a/config.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "quizlet": true, - "quizizz": true, - "search_engine": 0, - "hide_show_key": "Ctrl+D", - "ocr_key": "Ctrl+Shift+X", - "paste_key": "Ctrl+Shift+V", - "win_transp_key": "", - "win_transp_value": 5, - "search_ocr": true, - "search_paste": true, - "save_focus": false, - "save_transp": 95, - "save_pos": null, - "rclick_reset": true, - "on_top": true, - "hide_taskbar": false, - "theme": 0, - "font_size": 10 -} \ No newline at end of file diff --git a/fonts/OFL.txt b/fonts/OFL.txt deleted file mode 100644 index 76df3b5..0000000 --- a/fonts/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2020 The Poppins Project Authors (https://github.com/itfoundry/Poppins) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/fonts/Poppins Medium.ttf b/fonts/Poppins Medium.ttf deleted file mode 100644 index e90e87ed69a7ebb8d965ec248fb86286423f103f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156480 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 w - self.BORDER_WIDTH - ty = yPos < self.BORDER_WIDTH - by = yPos > h - self.BORDER_WIDTH - if lx and ty: - return True, win32con.HTTOPLEFT - elif rx and by: - return True, win32con.HTBOTTOMRIGHT - elif rx and ty: - return True, win32con.HTTOPRIGHT - elif lx and by: - return True, win32con.HTBOTTOMLEFT - elif ty: - return True, win32con.HTTOP - elif by: - return True, win32con.HTBOTTOM - elif lx: - return True, win32con.HTLEFT - elif rx: - return True, win32con.HTRIGHT - elif msg.message == win32con.WM_NCCALCSIZE: - return True, 0 - - return QMainWindow.nativeEvent(self, eventType, message) - - def mousePressEvent(self, event): - if event.button() == Qt.LeftButton: - self.oldPos = event.globalPos() - self._pressed = True - # QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ClosedHandCursor)) - elif event.button() == Qt.RightButton and self.setting_rightclick_reset.isChecked(): - self.set_window_geometry() - self._pressed = False - self.updatejson('save_pos') - return super().mousePressEvent(event) - - def mouseMoveEvent(self, event): - if self._pressed: - delta = QtCore.QPoint(event.globalPos() - self.oldPos) - self.move(self.x() + delta.x(), self.y() + delta.y()) - self.oldPos = event.globalPos() - return super().mouseMoveEvent(event) - - def mouseReleaseEvent(self, event): - self._pressed = False - # QtWidgets.QApplication.restoreOverrideCursor() - return super().mouseReleaseEvent(event) - - # window switch safety lock - - def active_button_toggle(self, x): - if x: - self.set_noactive_style() - else: - self.remove_noactive_style() - # set placeholder text om lineEdit - self.search_bar.setPlaceholderText('Window focus safety lock on' if x else 'Type a question here') - # hide minimize button - self.minimize_button.setVisible(not (x or self.setting_hide_taskbar.isChecked())) - self.updatejson('save_focus') - self.set_window_on_top() - self.setFocus(x) - - def set_noactive_style(self): - user32.SetWindowLongW(self.dc, win32con.GWL_EXSTYLE, user32.GetWindowLongW(self.dc, win32con.GWL_EXSTYLE) | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_APPWINDOW) - - def remove_noactive_style(self): - # removes win32con.WS_EX_NOACTIVATE - user32.SetWindowLongW(self.dc, win32con.GWL_EXSTYLE, user32.GetWindowLongW(self.dc, win32con.GWL_EXSTYLE) & ~win32con.WS_EX_NOACTIVATE) - - # toggle always on top - - def set_window_on_top(self): - if self.setting_on_top.isChecked() or self.toggle_noactive.isChecked(): - self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint) - else: - self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint) - self.updatejson('on_top') - self.windowEffect.addWindowAnimation(self.winId()) # add back animation - self.show() - - def set_hide_taskbar(self): - if self.setting_hide_taskbar.isChecked(): - self.setWindowFlags(self.windowFlags() | Qt.Tool) - self.minimize_button.setVisible(False) - else: - self.setWindowFlags(self.windowFlags() & ~Qt.Tool) - self.minimize_button.setVisible(not self.toggle_noactive.isChecked()) - self.updatejson('hide_taskbar') - self.show() - - # saving/opening config - - def set_conf_keys(self): - self.conf_keys = { - # keybinds - "quizlet": lambda: self.quizlet_button.isChecked(), - "quizizz": lambda: self.quizizz_button.isChecked(), - "hide_show_key": lambda: self.hide_show_key.keySequence().toString(), - "ocr_key": lambda: self.ocr_key.keySequence().toString(), - "paste_key": lambda: self.paste_key.keySequence().toString(), - "win_transp_key": lambda: self.win_transp_key.keySequence().toString(), - "win_transp_value": lambda: self.win_trasp_value.value(), - "search_ocr": lambda: self.setting_search_ocr.isChecked(), - "search_paste": lambda: self.setting_search_paste.isChecked(), - "save_focus": lambda: self.toggle_noactive.isChecked() if self.setting_save_focus.isChecked() else None, - "save_transp": lambda: self.transp_slider.value() if self.setting_save_transp.isChecked() else None, - "save_pos": lambda: (self.geometry().left(), - self.geometry().top(), - self.geometry().width(), - self.geometry().height() - ) if self.setting_save_pos.isChecked() else None, - "rclick_reset": lambda: self.setting_rightclick_reset.isChecked(), - "on_top": lambda: self.setting_on_top.isChecked(), - "hide_taskbar": lambda: self.setting_hide_taskbar.isChecked(), - "theme": lambda: self.themeInput.currentIndex(), - "font_size": lambda: self.font_size.value(), - "search_engine": lambda: self.search_engine_combo.currentIndex(), - } - - def updatejson(self, key): - data = self.loadjson() - with open(resource_path('config.json'), 'w') as f: - data[key] = self.conf_keys[key]() - json.dump(data, f, ensure_ascii=False, indent=4) - - def loadjson(self): - with open(resource_path('config.json'), 'r') as f: - return json.load(f) - - -def detect_darkmode_in_windows() -> bool: # automatically detect dark mode - try: - import winreg - except ImportError: - return False - registry = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) - reg_keypath = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize' - try: - reg_key = winreg.OpenKey(registry, reg_keypath) - except FileNotFoundError: - return False - - for i in range(1024): - try: - value_name, value, _ = winreg.EnumValue(reg_key, i) - if value_name == 'AppsUseLightTheme': - return value == 0 - except OSError: - break - return False - - - -# initialize app -QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling) -app = QApplication(sys.argv) -QtGui.QFontDatabase.addApplicationFont(resource_path('fonts\\Poppins Medium.ttf')) - -# color palettes -DARK_MODE = detect_darkmode_in_windows() - -light_palette = QtGui.QPalette() - -light_titleBar_palette = QtGui.QPalette() -light_titleBar_palette.setColor(QtGui.QPalette.Window, QtCore.Qt.white) - -dark_palette = QtGui.QPalette() -dark_palette.setColor(QtGui.QPalette.Window, QtGui.QColor(25,35,45)) -dark_palette.setColor(QtGui.QPalette.WindowText, QtCore.Qt.white) -dark_palette.setColor(QtGui.QPalette.Base, QtGui.QColor(39, 49, 58)) -dark_palette.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(25,35,45)) -dark_palette.setColor(QtGui.QPalette.ToolTipBase, QtCore.Qt.white) -dark_palette.setColor(QtGui.QPalette.ToolTipText, QtCore.Qt.white) -dark_palette.setColor(QtGui.QPalette.Text, QtCore.Qt.white) -dark_palette.setColor(QtGui.QPalette.Button, QtGui.QColor(25,35,45)) -dark_palette.setColor(QtGui.QPalette.ButtonText, QtCore.Qt.white) -dark_palette.setColor(QtGui.QPalette.BrightText, QtCore.Qt.blue) -dark_palette.setColor(QtGui.QPalette.Highlight, QtGui.QColor(20, 129, 216)) -dark_palette.setColor(QtGui.QPalette.HighlightedText, QtCore.Qt.black) - -dark_titleBar_palette = QtGui.QPalette() -dark_titleBar_palette.setColor(QtGui.QPalette.Window, (QtGui.QColor(28, 38, 48))) - - - - - -MainWindow = QtWidgets.QMainWindow() - -try: - window = UI() - app.exec_() -except Exception as e: - messagebox.showerror('SearchifyX - Error', str(e)) - -sys.exit() \ No newline at end of file diff --git a/img/quizizz.png b/img/quizizz.png deleted file mode 100644 index beb8c381f05d9f85bf22a0a6d6ae994f3009d0b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6581 zcmaKR1yEegv+u#3KnQM&!v}myYJn4Gd11kbpLv)XKJczraN9kO_2bX3KswX0;rOl7Ltek9oVQys$v4qMKW|d z8C4ko`1TeLVS$1C2U#g;sRBR%D-st40Jnefy8z$~27rBY01(Xt0CKn7R!woF0@G4i zQ4V;O{a>m_gCrDfp@ za`SMtb$D$9^741H0SQ|=I0LwUDK6+=jUS8)5$5OP7vZ-C^CSEJ(f(V`C-C25Ua&Pk zueGq1wTQ4S7;MQ0=C=_M27^UJgmG=GY>`t5+2DTG?n_3xP!XW>zqnxI=U@u}6d#5w<+%#quXbB}}Z?IBvco z8^`jgw^Jp1y6a+W^Of>LpU0)Z!Q8C5^j_W4O~WYHc#R#Vx{#` zhWIx8kLfp5l+gKJq-I6=jPrytpN<7>TuJV%<(=nUomQmGyr&2jQjtZ+0iFWP3aDY| zK>T|Egd%Opj65FiDE`0V!$q{0X6<6F=^D{sN2%`6{C}+wE+$1}p$pN64^%{^gc5zM&QlyH^48EuQ1l;-Av+DOqHgF}}T-e0w2)${+(`z^2xB_PgBk5B1+0 zgQvsM0ma&f;pd|*yRFI-chffSqQA z3N=(qTI=W#mL#hIHA*Sl{cBR!N_(+MOQP8PTpS4N{q=`@d^*GB z9Xk8NU%XQHGZV@5kkvT%MtS7q5yXkVvNuPS)!QE9@22bc@Rv%@*q{`@$;rhLTTE7V ziF!dcPxVQdnV1FzMDNZ#UHo^A2X>;k)i%tD;AaePPp)#Z@};a`%a>wO>rk+yI;kBS zR|JG7*Z<&g)fN%+YpUH&QKR_SwBF5LsgJ2Oay&sAc0HQ71X-vs>F_;x{sU#rppVGT z@;jx3^Jo)YXObiwTaG9K9opSP--DaJF0lTjtSGHOs{e6q@R)~IVAMMz?Ogo>*0Xf7 z``7F0kn`I9qGTWDI8?bF%!VSzLHKaxosYhdfFM?+OxH$!)(1lkE#czVN>c@l*X`f+ zVo>puZ(kj+R|dL@pTrE@6MUNwyGGe$z6lY&Qrw1($n+Jd*D}u?e=$AV-y(H=ZgzFm zkd&l~d03Ev@$Owk^w{tOoshptKPBmm-Gs`7>W&nV?r`ho-J6XzSi(wDV4_nPz|`_x z-?eMMmYV17?Tb@(&F+%s+qH&?$Fmz7SHu{OtY+j+@vUu8$nTPcQIU|@KiHZ93B&ui z1r-;I!BU}n8KLiJdXtDvi9G@FfzF`bIQou@vOkI;{&<<-6)vYHz2obf4k_c7Yg05J zIa*p-9Qc9(kwU?~SD#Hm7)GcU=)|gC7QLy4x(DU2f^9?eUisYE z4U1alVGq?R_5KliF%rX_*%k(76~r+*L?IeSY#n+&-kb2XrYS$0Yp(uNRqhfBTZ*ow ztv6w>h+i%q!OKX*H(wKMyGZhFbY9nVH;RT`$>-s&V^~gYqU7u79T}LFEDFO6q6={; zO+>zQa(4Q&5VVG(P#cw{{5t-+>^VbTWp+RA7?GDsP^!FcX*kQ_V$Z!;XYcW={eF1M zn5U)WTO*xbqgW)JEgFud{(1l@Vo--pS_Whe$`i2jdFXCGO%&yWGNVaP9v{s$nRs|! zrg!jeSqoM!yN%=;Q|%LiMITZ(-TRVrynpWTTJBmFp``5uZV$37jG~aD0Ju@n&Q&<8 zHy>8^n-*FVbuq1boShmsJm-#%oHbF+&G~m)M_#{1)gsBsi24Q`{xT#*i^Wfz)}5S- z+(4`+4}VMtV-LI(v*>|)j|fQyTrp|xQOIZZu;Eh%4mVp3qKAKK0NYK7tT5d&wJOV; z=Vdn`COG}x?Z*>yt8|C?{G7o{9}OHC4yaJ@UBClPbRtY-KIv93f64?lbuX=d73<|1 z5r0&9y>^^ENbe_}H_G3y*mbVt87!?Mbfv3=!+(^xH$=%%|2uOMK=~?M*;_2E$q3J( zN3>RU3XE5HS$V^>-%8>fyboCW{(|{k?t72viXnVx;yo20UDcCjSSlw{boIJC%!vf$NNOLb(;D_R$Ef$nZ% z@^-MP|1)*yG*S|C_9VxB2fC6P2 zp<)U*MiE^@^R+;yUG9a!H7ue6nyGvH8^zP+!ee?_+s#uL&B}&=v|gj12DEtT$vd|O zn?Bo%B_a@0Nc#hf2r_#V#h@u(_8smR9+>!)R|vw>cDMA)ruFjfAe%a8G8S8dD0`o9 z_P9FfcfZG(r)l%O#1l|f)<;VJGZcZjJJM?0TqeKp$+4@GHQ&>3$>Mx}~U*^bv_oCengJG}zAjyL!&4S}8$plYx5ddU$*Ta+hQC@HYf6&{qpa zc7N-gxKPJy(uKj{jrQwe94v+;PIlOuuSqc3=aLT{5h-7nmdUyhtSOA}A z9aDOnlB0_YTrls_m%zTlxtQF->q_(o=Rc=xH@CQGG7%^;*}Yr6aV(suR8G_^8TaD2 z9`^8~ug9IYlXy}o+6ei`H@CCbkz_Y$p3{&S(jlspuWM}^lNW(}gsUyy`d9G;5_xeH zBJMgH@%aT929hq!aX;2|7d0DFcgHUG4RqyoboJ!(SWye&wb?EUsZZ0H2Gw(jwl7zN zT#rl(`yD0BN0wEI7}*6-YPJ%!6DP2rIj;(I<0^QSew37W=^otf1G$wVMRA{L9fnJb zF&^;Op4YOCWp5d9@cAzs%xnlx?+z7V;nNY#UCOkDjA4EfT1d7eiP3VYYjc@vjYGYJ z|1fduCpUq?r(SuFJ#4jTCj3mjG|qNJJGCr*zz<_d$|Y4!_hp(He}p&;6c@r2h&tL= zsgf=#zmeLhBu!&=v{`4VOJ05*NwCoUKE069>tp6jL>Ae1;Lm zHcYbHDed((d-)kgm>hi};~1JX-x~??gKEG1^EH-ea3WLqd^PJ2W|-jarFJ~H)S)m~ z?CV0Mk=^8oKq_xVvQI_bX7mEHyoy`9=o$6NU3JCQ=yf&-lPag&SGW95)--(j!1FN? zw5Qu~b=L~gsQs10^V}Y76a3tuodAs-uoENRm5R{K-R7JYT5#Q6P#@Wc}_XXtKM3u8pJEru3utpTl^F zIu*FAtfR#Fe1BLz)a2qpjFZ-h3%Y2)y#HsZtn$3NbNBYKGyMXkYE$lpZY*i6D`4}R zetvdo0m0?^xz9=zo~?hJv{)9QYoAk@n5KPXKD!a!s91@VsFN++i>7}_~hs-ETZ`(l6X&evt>cZ;Lz4h@uUx*@U#za=mr#JC16 z0Z&1dPQcIl3lGbes?RZe^G;db=m0iV_O+4}9o1$-7JoX%wtQFSqo0;St>?2!HZkTy zm$hcAbx1YW4QwlWt$~o;)sEgml!dZTu&w5u>cn`aXyENqMn1%GI(`7}6_=yWT>I&@ zXEnn1`N}5TLPWtt^&Pg6^5Bp0_S0F{$6YniI6lVxX+MRhWd(x4^*`@z$^}E3Edsaa zgWImKvQg&~tY135Tn}4?#XR|kT3fQy5>W7>I{P4phT`Dp;(+Bo-s!~t#ohJ&TLLcbEWtn{ zKcA~^BEOG#DZy&BCuNd0VNi&g=w(EfYe#*vrydtB%!(9r_O9=e74F@6p}ILeL^{Avw-;_bIGzs7~$6 zm+ESS`HO0Ce-q>MEDb4VlGiS6JHsbjSxwkl`m9>+nGaFeFm(?t$h4>k=r+Y~LHz_e z@=_3MX;_zVa_!l>oP0Y3Ve+Rp9C*sOG)~F71iSm>+?9sn zSC!S{?OR{yA6i=q4GY@|b`4nfC=V#rhFO-757d*EeYHk!hhFRLX|W@=m)Q2slknVv zV{(APNjkx0CA?eviPYV;Lx#kkO)G&mM;0d=h68V_BSXUHaajA=c{f84Av3q&vGoAn z#hV0V_-g#!SQLjEwPx&FJ{U`LkxIg^WEeBP@%~S`WQt0^16%0vhNRH;EXPBAao(Y_ z`$_~o*W)Jg2Gk`H3N_YtYL4za+9x~gP!A0~`$DP-=XZ8?%!2&c>JCq*Q%eeQPb4jI z<7w6~mIUnUM#$Rh4jX(^Ald_=KGVPUNCxy&D8z$m{?u7*YtVW*u@}Od(NW(u1U4Ss z*xz7rKHjbm_n$1x&t^v^sS#EJB;ERpW^_rnPAYzf}>SqY_*ac;D^AU$1n) zQk{(#^ylVgi96Y^%yGdr8=>&W0af}5H&-)S52f_*21{+{nK`@Q1`E3m`N z%&-Uo@7&XX+aYbTo)wO-&j*{mqxRNsXxv`J?lKHd#)Q>kT1%X574^SRmR6>V_{jW8 zf~fs&Urf^ABD~Cv;`S|?xf0wMs6b&r!~4-25tg{As!sco)K5Xy3nc?Ao=w|9C$>`4 zv`3w>di}HZiotU+q6K-TnnJhdb>D0>)km<<1F=6n)qDc9qUs~?qwvW(ox(n zAube)I>=EP1RFYeeJ$obSGL@UV4&e976JyZAN>a3yzM%j6rx|$ZW)AmQ!@JbUwkHA z|5_0w`AYKe@SeLeF0eZ9K?2{JdoArEEu2L@d7`O0!0f&=fJus@Ct(*FtvC2m2Mk%! ze|NaDF|EMP@Gu_EX^|Mjt?Ht??V~P2b0fb{g0X90rq1<5rknI5JdsN~GkvQiFo!6R zjo>t(FDnvZUS?79e&WZT1&RJYqsi8`IWm+E3N`ht?#-U$OzxSdUzjfTEuz^`dKgp! zj{yjmSf7#trW;AbTWv4Ju=%GwDE+KL{rV~InJGr1thdP4hOm#8qK_O5WAtEnbsQo% z=v(%iCb!GVv4#{c9891VRHh?xG|!}t%g0WfsI^#oiAGV_$adg;=i84C!C^8h?=&kN z_6DZoo_X(Yrr^)y5vc|#Iz$z|-Aa~>%q7^4+%Xm{@y>19G4XX*`IUh0ug7oF25>tr9BxLf*TM&P`^ zY=udHFGtf6;f)83^7`6LXpV9U)1)NBb-{w8UV*Cn_U}&#rxpXOC>h^8b0OYHNuN4f zg5+Qkrbq^Z%=7_!j6vdIEiIR9x2+nLu99dPCe-?4$9TgNh8n^5UlUT9w0WcibuC1mO+yalTj`m z%cl}{cRVjnMH||a_t&0xxB9;K@D`m?>|A|^Tg;qv2p=e<~tkzDDF z=FdVNF|E7Msd5$J`k=y6nP`xv0;u-z~_=C+SDm7hyqp^XnIGh z=4ME+iQUOkQ;^#R6fi|R_A}dR$bs7H;U7PW3(L}IH{B2jq*KS!Ar*@E(SF_dA%4A` z&2*+Q@3&haR$qIBk`*O?6$|hp?vs=CFUEw-e)2WBI($kJl+HdlCsZrH{RF&rC1_7av$0oPf_`Ib$Nq#1RuP-`4jNNVT^dSDDz7-Pmd)@q zo->uOS4`T-6za#Ue zsA1ocsaXKT`xHPpB|l>2C{r=7Yq@#tkXIEcZ10I`@hu$;=hUQzxj937p|{eJ+$2{ ztZV?@CpoB4q>|#ll=4Uf)Y-z$M#aX(&dVMU;N{zQPpm;=$p2rAzJv9@Lwt{MJ|Q7b z{|7|f*4ER;3*Zyfrv7Au)VlpG3H-|gT~8a27p~6EHZESs=SG%*+6n={fNk85a(z0B zdfc`6;TZ|kf3}g3y2aUVF|IQE~ehnnMV@~UMb^G uZ7P!remjTw5`2?pw`b{{cgR&&cSt{;$Ydc8J4e=A001hlCRZhE9`SGUsAgaQ diff --git a/img/quizlet.png b/img/quizlet.png deleted file mode 100644 index 28e16d0972ab7b034c7e0e6f8e222136580747e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7017 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 diff --git a/img/search.png b/img/search.png deleted file mode 100644 index 40159a19c100d04c7d8ba6faeb32f670a6058b52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19761 zcmYH_2RxPU_wThMGbLLSnU%dRA+k4-6-8uUGu#`=D5=QEOc@a(d)=$D%gElVYtL(5 zu6zHF@9+2j{(L?@xbJiJdCqg5bIvQ;Ku?37mV*|8Ao@F+YDN%527V=jXsE!Coq+yB z@PoqV)*TZX@D)ts7zO@5<*9ks2Z9)Wo_xdJ2{CYj57`mw76@aHhX{Xr?+1{-zrW}s zcUK<=d(Q`=9^Ou=>k1qY#0T9`Q!xohTb&3*Sw9F-+FUrw@EIC$Dx)sD#Y9eVi^7pP zjPEiN6U7(bp=+iuP`8v_SIUVdek}JZDn>0`2d?( zH2kVGgZ714=O&S>3) zay-Vl_fPHz4Z$ou@?D4pg5D%HZtR~y^>2h$%0YLaI_LmWh(fG~rgNc!r%HNHsTivI z3*uDl6%TFT?JH0sN zV(5RZ8^5;eT}wyO&N@s<5d)w1n;a=}?V zJv!_H=9}f*!mB;x;cwZ`3%Uy*Jb?tP4r_(JWmVJZ^lP?cZGpleVJ%wBgkL@#q$hn} zeii1{-F-8n}J0DMc(IZ6dOMYdfhO(2ZSFfaN`9E0@ zEP@w3^$*|h;HXb$!lyWs#)i7}lpe{QrVQt#$&RwBuJ@Et3t`1fq0DDKzOiB`La)?C zlWHC%?j$p)R{VgW1j3XWboecQK0%)gVMopBEPSvSrEEhAS=$6plrAOdMt)eH1AJeg z;wh0Tp*Il^a zDl+tXY}rp1?w%?1pwHgf5iE)rt|*LYJy0s9_)8Am>kEuJY%8=RG+SP2Y@MUXenAcy z(pWcSBd($RV0t&xBb?!tu6ACHi=vj^VTkt(s;Va}tDO@S%Yd#R8Do8Poi1>Mt@T*E z6{@N7WQt;7fYdH{{x19e#$cIO!jt)+@zdfc)pV}WWW(CvnJZ3mr`LF;CDf>_zZHm| zX*|64BJ=)3Ayn$Oy7A^UpDP}6r|DmEa$O`Zwn>4TWD$AG?@=hHbg7zf2Bn`1c3abq zCK2#gW>fT3Jz4-8%D|Q(9*x0gDTc^2!7|p@3*{|r?g~;~nM-^-Y`~CYJ;fEvcb7sm zvpgX2K?KjmOBDW}%lz@a8=588xg&r&2F5FdwDa&BRb(=wh;!LY0%Qk6_j-@1Gp^g6 z19s-Xf1f+F8xjfOe$DuFLo&O;?b+a3N#olCr8q|MaLy~)*Xn>HbojkPe|Z`K{mI>C zib$c#@Jwjjsr?u)r0Y~l50G4|efVHW&6!X~HR&!#XZS1u7Ch!ZF1G#WdlPVO6Uwzt zM5XyV5;MjW;sOS_c*ileWH+aN#ZDYB7~3--)VZyGG&Qpp7+r9S{7^$r&J_)%{lxRJ{*Nvyco;}?;aoW5@0I8gn1UUn93UsM$ zYUfO7qh+ls-*>S{106k|E^9?NT*Xe%6v5r(=-#MTMz!%5!&@505U*tbe-fJJB0@YR z35U#CjMvj6+HP@NBxUTT35_jimMn>TVPL35Xf(;Cs_HXA9kL~VEuJ3P_K-|rQ!h^-v^L@}&N-$Y+-IL11LRN=zIT@>5Zpi! zM%8yW%2|28=G4B!l#G#7Dg%r92?p;GZMk<#xJJrFG~gqO!C8oP68WPyIwv<=?L^I? zhwjtHjocWo6Z~24V8PhuBhf3m)X^-!DeKl6-8M*MU^CM((?=4cH!dqRADue=>IOHe zO{VCUQm&%i%_ZSa{?l}Tz(?}@Y^6y7! zt~p`{B2gS{&OytQU7i(ss>vRZHXOin9OQAvd7-J8-Q;x6dqI3c)(vHdx6TAwi~tZV zKi6FhI}tY?l>JwS`V=PvIHA_vPn13z1< zktl?b7gOu|!uJ=G%&<<$3@lgg!T5yAO9tCBZY@nw;+O&Iwq%APucp}6t3*dR&GVj6 z)^OdP;KXcF2O4EpydN-^XOScz`Qw7LJMXvO~Ph9m{ zpNh^LEz~^toqs#B$!DF~^EH5FRkHN_0W4a4J^cqO1H`I5^yS*G{>DRY)YggA$?fQe zab8MJb8Zo`kiqJ`y83`GVmMC7?c^ba^D%s+>u2leg4PHkfzJ!dvZx6PTw=XatxX<# zvfx=1aYRpS>%&IZo3~2>D!}bZOFc~=i3X3uvL+GdF2;O%q7}G*(W;oE4Ticuvy8?1 zsPA+)(Gi$>+Z3W~{F~_cwUd_kDq8v=LEO1w0o%*j$Ww`M=GgJiIT_#Qh6sAnDGWxg z_h4C?bwQ>}ihrtBGj9MV$}aiZt7>n}?*3v_qCoU!L&(#e_gyAJU|n0SU*HmAYs>X3 zAv&M-8kP~lauciF6l>Vvdj+r7Ixd<+0&o9`gKwsuQWNe9en6Fz1O2v88qsRj{n?kK zem!ATnJ~6bcSZUB{!lqpOx*^<23~n&<4Cui+MDOK5P3w|?MZ6f1HOevto4nloyNht zVk9DqTUV#s$G*tcEmjqvW!a%G0$qPz=RlS^P9H`M$Rw^({ua!-aKTw;=eY3#OycrU zjFM&}RjoEhx_VaOr{23{axXZn)$KG?E^SbzMi#i*Vr}1?|CsT(PW-04I~yH{2ye=c zaE**)=UwIKOf@=SmVIH@AE{^;Yz%$uBa^-*FF?ohwIQoiGOx6uXMaURmR`)vmsy|s z8Y$-I`Gwvq8=YzAl|NyCZ?#qX1rnKT)8JuA`?11TlzoiE8}-DMgwAKK9Xax9G*Zdo zI5?k3O6@s6UL0s^c4w9yrLrQP{p{7X!Djn9(4YPi<+Y3rg_!h0-l4glB8s$atUnB$ zX%ZlZn_=NAN3_VtX0M}q_>Wx1?yhpuNFiLmtjsIh8QF(Nem}fGWMtx#Y{K`>Zr|W7 z)-A9DF4a?qV@|*GsS{1@8MY*huw!RSPCl#i$Rv53i9kFQ7_sTG82en>sNtX*H~;iG zjD4A(MEvAIb8wiweZ%&%_ZJMnVc50cUMGY2hCR zn<(E2j*?Z}mSxrLlvc+6pPC)WxMz#~6#L{a7V?Nya-V-qA0^y!1L5R8lqsDaK3Q-9 zrsHaoJlS7WuRmbC_jGrHL(KosqVKcethm8hQ$f;%iB|oNj4VD8Khj!&dq%Zst^L7w zw__HY{ou_K*A5#yTY%NK?=K%VTIqg4Qmxg3*sFr$?q^As4mXk z)!kCwyF!3On|H@eTd!RwW|o@*ZcHeJ~U{om$-XC5B3vHD_t(GN{S zA&elP?HrtL=a>5Z?`@uDUUhZGfY7|ScUB>Y?L)Gs!MF{5iZ-rMQ#oo2CAM$MGHme0Bu{ zp){%iYw0UDXP(FBbXr8Ic#nhIHJS(!|X^#O7@^zlUT#8HyJ* zHTlQ~3y-motjTjbd7*kyv{F^+{&nbPEEPM2JFG3=HS>>1l$Eh!ijWJOi1%0EzhaOd6?rjqr<{Zw1BUykNH zb4SIU`X-yGvtz+uM(11SC&}%FkPzyUCif?$+JMmc$lQ;sbX7Etza)jUNS~e}CDJby z8!>o}pO3g?c~*bnW7Y88{(yk^xQg`N46-nV0grr>+Z~_7(|))sUTSDTBtG^0rhNO} zw=ak?vjg&g9CU#(8CP$?=Bw*5{<9y+gNn50KEx{d-QHAgG6=;@X=j@j*?Ql3XmnnT zMrJvV>ux%CzaLAbt-CVcTakTxRdXv41&%|e_Sh(@W5RRt0^O4%}8B7YbY_dUX zl?Y|`_EQb%qkw`R8n0i#?3KEa)#GNn%T<$^l1daHxp657`Ro^BOQZ+%Qbzd>Fc(BS zGhcf7@%ni0U8ZhF6^j`TpGV`UQ8)(VGS+{-@xB~2HB|69BNtb}#N{BTVRGtFulv2U zY;~+?FHy&p^`63nidC!!FL&w#(o^TGa#Q5)a_g>4{B;?~;CJvN)6nM-(gT3ya8Hl7 zGfc`RYT%8lCHN^fQrD+nw~P`TTWSgZ+jNboND=?I_S0NY{?*Y6vy6>kM&(gNq5#Lc z^`ivIXz9%lueAiGzuaNaOEs8yqC0FrJe$KnO77g~vUOSB1sRC$U$aC}^{6iY*te=2 z0Q-E_8$gNT*JD$eJgvI?$JdZhNFA9RK|RyDU`4lH0SHwaA+$q5kAJ?zWhhaoJEIuS zRUPbP^h~EV*A!jM>OIiug#``Q!T)_H9 zp0kVYDbe@y_jknC)$LvJ<_VR7PWJ-!Lsfc8I$@}SR~#$;;F?sjv66>?)9E1pJrgJ2wQz&;NDxhO!FU&vw{Cp80^*8(nBY-%Gq> z`ifb!i^?g_Wr~Q88f$g;AKUKnYS#Qf6MXhpDzj|j$RX3_q|8AFSa3VyRlc((#HQ!l zV>$QYGgHb%NRK0Lv#Zpjh&_>nsSn$blYfHb=wAWnW`RIbgNI92FXEMev)(DuwDs)h zJp3EVhjC^B=IC&%yTl{&@ekbxv&V`XG_w^lP*0R~T|vOfblqF3L!r-6%^!X#GHUAzpoT)dU(d6-JgBk%0fV^fGkG zUV0#Epmty#di>19-cZCgoE)OJ%Kf$@coNE(AF{K_coc*`r(hdvQ+kqwY|cL=+V#Hk z!nCrMe7$x_u$q(0E`bYjwir!XE|0qBDyNbBV7##~TXNeOS=Q6ofxb^@64jHx&VDb8 z2InI;&FBMb8I^uL0aCFvlMwVSB4Mt@$Y1lYj_GD+#MTx)4Ou~6c zDaR_yD`$zzzW+7UrO@_tw&jJeaV)OH;89bJQ%>Qwu=0LC>5WqRKhTspq z*IA%R?O-O={}da^eUG*6RcLA2`W6^;Vh2Lt5b;ix$qF90VAj38w|cOHF91DaIUu5! zJ#>e^u0NX~!~nne^v;>UhnPviTeF5ST$R~>)_a7pS^F#(r?|S@Ae8HgOYG_%#ffSo73o~xn5>fN}?29))pbgjv z=3)FQEw;cPxBLs4!_nPb#KzqtSy+$f2&eW>sfq@JL9F@ogLzaN^A3dpZ2HfA0gVx1cnyui+9$nZnF5 zxT&HCU&1djE~Jz1_ds&HQF^ET0=$0@vHE1w^6pi4KeArMSz;Zd#oxhuhWvfzFTc^- zRd#n5rh5;_NctR=GGU~M8`xew(JRRgS~4Xgw3i0TwjndiV|=D?sIw^ zts?Zzwk93CP&s-10%9Fh)}598kABEqc})&AsMnYf&j)PsLeqb}>N|OxZ45)K4=u-(v;2U^&%%#`_!Gmso+j z<=mSoR6SN=fOf9ZWeR6fO&j#d>YRc2|tX`XnbB zU`{D)#@!bd1vgtun2-M7Vjxt^!O@3cI%;V2V_v(w2DqC0BuhOhzs1c+_?R4Hj5p^} z7*ID>T=})qJpMr;gLJ<$~eL+lpZ5d&T{68fUF?oplIT;_PC4e&D;b$LFX*sv`@cD>Ia(QBMgy z59WE4*3XanQ3LyMKIRFYJVcsKZr8Dx>|lcUIXpzT%8vqK>Kzm#@k-xrnt4iMy(yJ| zR9AiR-J;WfCa^(n+uz?eQ!=@A^jJ(CLhTLI@?aEzB3-m-8C>Vbp3XMs;;0YJV3WQq z=CDsg?EUVL`xZ@2wm%Q*3 zU$zW!V@&@+d35B%07(fYF$5$yr*V%w+)8|U|0x!YY=pkO(oBA3|8i&r?S@2l!7%r; z|32X26?xSzapnGc`~Yu^ zC?!yfy^r7?*VGWFM^F z=D0ZIn7t}2ktMb!_hz!UbNsE2b)g6&wNgT)(|7=NWidXmp|g^(XJQ$uvtgqv%SOc#RT%=`E-ue+eyA|gzB zlNwmvyg)eDL7u_T2E*Lyb4qyiNBJXQjO))YT%NN%-dv;7=E9?ui^|L!=NDJFAmP7H z_C!hB#YomG!ldOb7?)yS*C|XV{tVTj95uvwx0ZyKz2dA5vLt6ay!q75lHWR2&lRvO zJJQSchh(AQ_70dG75vy(?JL3cl6Bte%AGyP=%?+*u_ObOSmXUJgQl$s>_iL}8AFzc zTsweXDShv9B|A{B#|A-we*8{Dl`#28mgE)Z85}%0TpC6{TLAOB?R35%U z!Els$D+=pzTRS!42!al-a1D_50h`&r_ONF!hBT4YG1#u>u(z$X=26aO(pD@~pZpiT#Y5oCO_@7<%0%hwqg+!zbx76>( z38?l9V)g!&G+I>-^pPwkg{jf$WbC{`jXrioE^TA z4Z>4?;ux!_=){=UlL$K4Auj041>@7yG~?ATLp%1 zs*V&lpXMn_iObbw%1z*5cfQ$C7sY1hp&NKA6#OWHhaQwsU-89iZ9~em=Q`olPUlIqGbANi``m|2E(ym(tm#ypZ;| z%$*8sFcl%U0U{D|o}okuK*FSeWSPmbYr=chX9vsB6*-70?>JqK_}nuFwD^R*^G=17=|p{Zh%%fJVImFNZf+Bl~A_%<$}I=G&zd0{DBap3vP>4 z;A5;sb*F)X;v2yKsvK3;1$#MIGkqs~G8o1+Hrlh_Icv#8 zV2Nn!WfA!^%12)x|Ne2SxWrP|iN-%`Swab|@Z)U(S4-S6^$BMG$3zD}0K zY=<8cbRB^pfh2O}@xc27>Ryz}F?Eo0vITKZYs^ms>Ry1D{K+gNq03x0l&_yhVm+!7 z9!N9wp=Kc_AIrn_Lr1z-pn+#H7>yAf7>)mB{IQ;Vv#O-X80^|lBnR85E4i^S?5Io{=TvDi1S3^>>C z@&B^`Z%tF>-Q=K%bDf!co!?`rsZq&iRGNT61IICakOdLJH(Ci(j-CgSaMXe<_O-&; z_(&@Wz1PX*nUJ50tqcADEfS_dd!Ow z*ph{Qrv2$CJ`0J$m@J4Ah{gwSF-sZfXGV#z6-=BP_0j>~=Q%6|MWKMA1&4i4D>r?^ zJ?0sW#p?esEpyR6r7S^>8veG)hha&Aeff#Yd(*}ye6+|nItRGRt}v|wLUmt)75xBD zIOy$8N2r^pQ&dh?G zyw+lvast8|JbTV6r{hG!VGgZg0MzJ!+Yn>COj$V4d_{MHI~3R_8&tiH-f+3#Xri96qq@K=ofLUypJH|8f>K_f#5GHk)+WznGMIoC#= z@>%}SpB!4#->qEbRC{C~HMY)7GAu0P0o-F&lNtlV&`$V%9)c`(FHPDHR4~qk1Kgcf zelR}hHH8f|klVifgAtP*IFVJBgEeBpGB*Ig^`s9TaM$EQ#f{^CwY*z$W`vX<7 ztv+$kINO=2Gg9B&s86f4r>!vX$iQ;&J+NSr z0t4R;xc|O&wmZ`64239ru6^U0hV1C+8wL^2v)oo^XqA&o3GL-!5lN8Q9aGC2wzPoo z6M?%9Abk6=O5pa2*44>6Gr!x7NgYWsy;U{bL;-~Iw*6VmWl?)LO$!NP0kdB~2rH=yH$ zi@y*P2e8VSlKh#GDhTr0jO-|pg)DwXhLB_C)1G&;V`RXA|67l41EPV7;~VpEt{}Bz zE?t*Fm35m!eSrFHv650xJiI7ITI{uARU|m*&ukT0!64L7tqhb5{9D`zvI%Z(gkkR7 z*CtK*KwmW*mA1H0Z-M%)T45L(K)|%o+{&L?8G8M!e)yl0zU;4oAQZ5LVtkqMD(rTZ zuS48jz~(o4&efwGMrd}=nyfmE9OYa7t`0Wn`z1rvE--+6am8ssxvklg92mw8H}u*nb}zmg%SKD za?cyXhdytlkFh`#xmAdH zl-gzgy|ZrEpaSg8d?rSVs-~{9kmJt86C^lWBFcwrIPKh$Zbz$|f_hNQ+oDtv5hUg1 zm78#$=}t$^-uqa{VDIQTRKSo3SN~n$w0e(d&c4(bxNchvRWGbu{r>tcXmo`&)?qCp z>tF@IqYW?de6^2H7lQOGGkE_=A`#nMBUElvlusc$>#EyLU2e()UkQRSQf}q@u_gBw zp2E;P2qs!;<|qE-_2uzvlJ@{37h#*jxa_6#^D+UQL?ntFRZ+gjE4TS^_R%hb(0=I4 z^FZ2y63J0T<3Bg-mb{=b9EX*+8F3&I#6!cqRUbbd0yT84 z&}Miclal?}_qpeH%Xl~nbr-}R?D{c4;mx=_fiv_9ZcEKb2yo&12`G7^&o}HUz6da zG`WG&gVQ7RC2-(+rHIiG8V+la>z28sR&Mh}sepLI^|vnM@wd$`ezI z0p5mnm({ajo4yM!azQSfRv_GYUF7-t=MN{zB%dNQ1k*~v{Op$AoO$l0nTqw3Vha0nIuF7x!f7Z=#qe3))s zC-L?n%o(fIN2-A8n*+?pM4$JUv3=jo$FrU`HjcSmlCOdSGtrngygaB!wEfl}mUE&fiD&8wp zVz?DlNfagQcAHSprdD3dV6qJxP@LCZzp?saK%+0U?!Dg78-d$)yxpr4}@>FbWZrI9E9|eH3y_NpkA2A3-H-jEwh_=f1|c`?pvMvFomY$0GwfW43rP84rr%tre8SSp|rW# zvM3@_Mrfxpq9Sfa?Y?*iL3uWQ<3a9+#Q)TNUT`|qpvnK91y!nPtX{07bua!|6ONyg z1_f74h-}UDg;2&x2Q!|Hp#0wOE^4p`F3x>Pm?!v$>IE`7VEMAh7&r;zGt!kZLY1=f=KE2`8wgRQD)(V0H*l#9u{?_L5#tjBm%nrJFE|(@ zoy~#C9%oBep0JqAcoo(%(;d^Xg;nhO<;4kz|cTYr%h5{D#1OL*^ zPd%~!@YcxvkzU9nwQj>AaaR4i=?9DuH>kozP;DO3^90cs-vU~eN*zqv`eVtnJC!-M zN~jGfe(8MY89B6Oe#EsDF>MQ!5r2<8V4A+Wjhp-~(UH@-|6t9?W-||dCrYm(m+1bf z8hq+YuihO9*Re z*!L-!v!cne6wkgyIs#)x;kgp-;NJ97YR^T%GJJ*nE1~_i7CE|BzV(<$?#VGQ*zDwl zG%Q*;S?V`Y8a+iG(1Um-9^{=Gm*j8i@uC?xoFJr4daYqDJ%;3qez-sCq6Dgv94uQ~ zXTes|BoD9)kNj;aBk&rlUuk)4a>~_q0Z%0NN*%~m-;Tdji<_DRe*gL&oPX;zv=7X9 z`vGtDlk`aI<{8ElOAc_ByxTgsHi>nzWudPw8|`ifjR+kzB)hmbcUn*9yQg)w+lJ>` zBF_WW6*xu4O)0j$I9}DxzEgzW9beTiJgx_Y<+ft^t9Xil!s(Dv!=7sYbZQTpODw>j zuvm%EK>sep%S{%HThoH;R{u#WrM!d$yGJ>kN3Y0%92T$cr1S?#nOR25n*ZPFtp#Kz zi*DK8VBm=D;B1X7)bn**hQEf40}br>D`V>OR!_^Z$4ISW)(cK}*=yWW+o@)G!de^+ z-|vB%sNd+iE(-Ww!iY3fj7>B{U9@{ljtav^HhGL-F`u|5w_RrW+pZvB^IJz zl#vN+Kc@T5sM~pw7o=}~`j59t@2{jvBY+j9om-mV1i9>p7Bo&$=1Hx@(R=c(3pg!h2S#hS;yHl8YK>l>9uIOz zg9zovfytcQ+#;A|V)f08ARdA$PYJq-?wBh|D>|t_pJe*mHg8Z&c`IoR;X$=y2||x3 zy7x!PdfNvdA!(E&Th7xQ?dI4|Xh}Q`f0I(Gtx7{GoKO=Iv1SInbzi7!k`u zyVB7Eg$8=?aC6pNxGXO~PuQypw3+pPofec==%!MzY<|p11G=X%VB`(SFe%`y{0_IV zQ9Ok$4Gan7ol;?C)FStvivRKaw=k(mt9*8Q?c&o_0nimN{itpWLv8GYQi0i`qflGS zifhMf)J7PB$8KOPbJY~w*Y^WBCFlF<${R&viuaa9w9cx=pm zo{2km@bHs`z}~?@yI4@~zz-ZRt$%{g&|7@_JC(+(Rk9|g(!bw|$Y+Euwt_?0WO(s| z_|M~`LR;avD)evFt%7`3duwi`&_kqbLV)?y1+V4H3$Ju350`kMv@F}#vumq9qSc-Y z%dI7asfgrw7j9QMy=kg%t7tK6FhEo+GUwK3jhRt`#W29WuD@eh4?$J!aNnT()FRJo ziwL@}-XjK@cm?w(Sb8D}tjgI=6Wh*;dkBG6Np2zWOM)cDZbQf>p!At)UbSaD7nuNo z0>tu|gY6hFKKCZU*@vfLtszB7r(Vh*W?;G_hJ*yxhhu(gdq}5UlNk^o#RM}SERnD$ zw7Z$I4B~HiZcNB39CLLdWlSu!LbZdQejZw&g<^*%LH}&~u+us1I%jmtIo0+s!{4|K zkF^yZ+6GJ$wQNrsg@7Y2UCEu~E9U3Bjd^F!%y(UM3+wUQXG8kzQ*tP_4Kz06Zg;PU zeOMdzS2a;!OLZ|No*k<^3J6J$WbX^O2StQK7UkpW+)G&NZo z$8zUWyPD2I9EnY!C$Le=*0ZxWH$5mx^;-CR1U(OJ3AMkV?G$y!lh3D1Xmrvr)?}>p z!Fh3G8*TQTQW;b5i)5EuWv46@#J1`B3{L_ceGUPpe56!6r1WCYVd0j^4)QN8XSfK7 zSowInbl#LPQpa!RvJ9ocnjj>mWc57+Etd6b%>1Rr{e*8p?GY(2bQVquCeNMo!6@ET z84o9NzmFq_R?nc5c+@w7oolVypB-QeNQ4F~?#yM>c?USMm#iAo>)notFkI@>S;&tf zwqB?G<=KhO_CM}y(@T40GInr{pYHbg4m5g5Dqy&Fq_sbsn}(6;(=`@|(?(>@eE)B6 z`kWzgfREOb(OZeQcJoYJ3K(gDp{O2w0tT&^e^kyDLYwATtJNOHT!|}LTpkQqPGMO# z4m1474g(rx=wwutXQ1_l_EmZu_nJFKFf$C;vPPjh471 z!68;TsU|mP6~EbX7sUs^)qslmKz=@7bHnK3dHLr~v^~=_hp#r#bL$E=_s+y-?rPq- zmB(n5cih?DKBTKL!U>vGd6vMw`|k&w-v=s;KUS^CtaS-f8Yr=pdW_o~-@fwlk*~oN zW&j#x)Sv5)JG(V~Nu4!j{HcjA+2xj6X_1U1{L>`?@);)z4g--+^hHG%vWJAVp$|qQ zmJL6@sxQTph~<((X`}ghsgE*;l2iucu zkiw97RyUG2@-y$jt^8NiQQG)@|APysxcq~|lFn47L5stGXZ(?Em%6QwC9zUkPC+Jq z-*uht#4QOQeYXbbtV$x#Nu?V~%gNAx^Ch3nI%?K}s63@enGsY=VNUL#Azx1x^?*Wo zLzEYNY|T?>mSiw5NpRJ=GQ;1}ai=OR{hpItClMSeieaLpn03kStk8}b&B~VyxCc`g zi?LHvoT(uSc%4&%SI#Sr&TwQ=;wF@M0{G%u%@cZ37lM$#1;IRJ!{c7UDtGQjE}AJK z1?C>!yn0txX4L~7t!A7Wom7=g*q;}e{xlb#?57##bo%E@sLl5*s^V;q=R?2V>yg(tXAd^aLO2Fv5Gygk_7Go*44yN=orp{%VWYw~6r zJ4EVi?DLDaA7wdwi#!Uo!gSXxVV5rQi<|HhFfcq(R|}4sKpBx>?D^@X?r z6eJh&CAjQak`1=|tJf<&Nt=+Mt*~F{)K@o5f;FrJ`myL#t%shAdBjsGUh##*abeO- zO7QFOk#BFE-HoU1A5aBg4u?7e{%(8hZcAQbBV{aN{D?t*TQ7r80FHo z&cb<7pp$4LFkIKl^HP;GpE>hMBecdY5xILM9@BgCOtO^7Qv`P$TRv4UrpqlPhcp_L z7;15)Ri=B~&;Bq!pKA-w1R7IO_wnWuT{2Y0@Bm3QdQ!3}XiYu%6ZUa31M}$)!!ieJ ziHNu+8AipSt%CJ#x5?&O0f%$-9hL@B)ZH%OvYZq zVD6HJL21L-IdyyeSm`B}S5XVK<-pCQU}(Q1Kph)P8~q8=lc6Thft7rDvobK;IMLej zn`f|izh{iIrCfsLnqcVtG#}!u&mVsf!a+&!zCb0`_5y9Z7*W2QEAS5r`3o19c^DMo z_3`YeMbxZcvf*2E&7O2326 z>KG47a4m{6=dImM`xU3_^jV4lx_;&eH>Jx(ZLGAZF0tlYp`3`GU=e+NM@XXIJakH0 z019yu6rg0K<#@n|YRSmK-#XQ{fN~cdFowTnN@p)o^6HdL;Z5!`q65tSOvIHiwKkVC z+QdFrjiUldO7=Bx)Q-yfyBG6$Y$>mdgzDK1bcW4{5VYnn^i4m@9XFQcQv_Z|D4;b| z_73Z7JQ)AAoBOSw#T>ei>A-F9o9}Gyp%2Y9OPdg^7h_}$!~O>BcE9NE3?4uvT7tU0 zS7j1%s5pJN<|Db@wHN-O^Ld^fZn>A34NYp4UGB|lzhL`Re3SbM4HtCrC3ec3c=p*`NN?kwK!kCVHY#+JaJ zjgh4<6OwI_J)Hk`Q$MxqJ_|L9#tzR|LJ*R(2|C^QSYzz3|E(j1)rhu-(dR1sOnmmf zuFPMNdf#=QgBtbP0U!4TtQ>;J6}#y>tp2(Q(>J}q&a56QuXP;Qe-_V7NJ|`o{ zz3b{#8S#e|OTzX)9iUs!v9?DzYREa3z7rX-I()9bio5G3Mb!Nkw}iEIm9EkkU0U$R za@rPN5Djx8QW-ndUCG9)Uc7SlrP8Vd50@tEnds{-`26c5mx|$vr6VVA^N6Be+u^Bg ziN`sqt+U*`Bp#E`0~S;lIX-|Xf0>2E=7rpn8{AiDWuRwJ=hS0hZg0V7G|v`;~Re<67#1;p&y{fEC7PQ;PAoU5CdPH_xxOR2f5_Ty>`_iE~*pB ztIX03{H4FZXzL7Q$J7Z|16+1h=x2YM6MUH(NHx7Ba*Ne08}-*>zpL`apH}2C(~?9w zze_b8h6(hhJJE3dl%~}<;oDL-?b}-jT+%SJXgY_ z>G=9`ma#*B)w%SfS#NI{j>PkrQGOqc^qVmsykRR{d)Ot>&4ZK39&E*Bk~) zI{7qZfdtq5Fo|HzKG2NPtCaI!xn#^HB5OjMJNNS}HHzatzO{}Zq$bGKIPLN>BZ$X9 zD*d^@==klC3}-{ONjdm-7GSj%mIb=pet>xF8OG)}Y*Q3f3LOAt+ZzhR{g>O}gOp3? zM{F~`GUOOo7HBf>0S|>_4#S6voO$+(?}n;u^I2u9c%}{n4J`kvTl>;~6TH6gY#&~9 z14K`(t@+SFIxjMCvNWZAWGULvCCBsU)lq)aJY0M9`oPqo@*X&UH>(2+E+)b|NztvO zoe`ofdUo>9BW!vONpNF_|9s4CR=Kw*z4BUr`8lJcf8HKjCotp!n-bPUq>Bct^7;ddmPz|{Sr z+MoM8Bh7BF)7`%vwW}}W61x%SmVd8 zqR;K8zUb1gNbR}>UdObfIKlh@nA&_iUVdVw1)b;@5E;g=X!t8XA;3NLQ2j>!;cW}Um;)93}A zrvi#WTY@}xVMFBJw0|PoyQ-Bt1EKEOmhqQ^t48o5H3jH|NSWvDvBZVPBy0rVMl%)|rX5T>*uQZGS9$ z%^zmz3(EXn-h258{v(9Y+Y;N(_Z4U{7qHSjo|!qn{)aTXwmCVM6u|C5`x_o0U{_DE z*s`AQ2%S4;;OhkqgEns`{4r2XGrX_snIrMNcM0h(+F1XudPKgZiRHUADttq#q4`vh z-ZH?EFC_!5lAn;6$4!la*CZHK8KwmM0vDET(k0R(vo$C{E%9Mh6W)E};O|hQyoOfp zO+!%VJ^v3|Ik=4yYuAeH^*=e-V%$5dUZ(l^PvjtnGVxuGyOz^febC5Go&-Us6Hopx z0HNPFciX@d5R3r&igUqltbr-ZzBjG(p-KLgLxtbK)2Pd8b-p<7?8ye~pwAgnOZegH zPgoZ3iAVC> z*U+_&Bb-yhlO48Wo{)l}IVbQwHHQ((ia*uV%zdBZrtNXk&7WP;vh?5$d*H9gCml$S zO!UWv;J*WG9SuaU&{uh^El;bn)4x3Sys^9xDz~d^la#sFdP%*c<3YlRzZ00%qLUB<*hGsa%cfbezuT*-XBq$aoXif129f_#?`VX2(7a?-aikH z?Zx<8gBolUH#C?op6YcstIWU5gW%eqw-VD-a+hOKkEt+kb5@Pznb{%JJbH1Lrb9d$PK=@k&xMewC&3A-o47`vEG`UV3DNP8O zdo#3hQxq-i>UVXw#poIVw@|CTZZzI{u3|34s=|-*Dg@L>#3XWxQewC;R@6< zBK|1gKf)9xX?7vhvT23>p9}iT08MEL1gl<8V@CLmhb~3@M;YaqA>Glw-BAq=9+q0x z&8+DdGlmXN1EvTYuTR>76=$-gUtAK4`j~mmX~1DhPG~n6^*QSH<-Py17MCYBHKkZt zCojousUK;}!wB`9AKJHVhw`Z*-rBq6GCi8g2#(jHU=-CF#j4&kWa+;XlDb2KU{l+5 z#uoX!tIJ)zYC8`LVAUw)`H!06%)OZV^3X|006A`U$O|ll0Y37L5FNEA=J#K^{1@fE zTF`^O!HIgKoIUT~{1>3mUFWc(K(;Nt%%%)I#fFTm}q-v0xr(fpS} zzTCzCQCN=t`7c0$(9XXA1&s#(QplIO^*;)ur~W5{ixA>}01XEJQV=-*f&Kp#VCZ@4 z`oHqnvGe}>`Q}T8{}-X{w8Ou6ZnU=j%g`^{V8{+=>n>4EZJtu@Uo@UHkN^FAhWUT% zzvs;Vi-$Jz{lEAH(p;qe1>P)Z|Chk`qUHYqp#QIkYmbLA>*HsdS0uMdUP4Aws##PT zll!Ih3~w$wq^#Gi8MFwI+io*%sm&~JY++ls2E)5jgbcY8BKNRj+}?G0hs~Ib*7St& zKEwN|KhNi!@9%ui_xC%`bI#|S-zoV5P%ZfaSS;@T3@EtT{uz+;2=iscS$EAo_pqos z`UMc&g>K2@dVRS5Mugm;Bz7s%#E!-|smlZaLwf6v{P!`N8kRBl1b0-C$wh_^D)&>c zKaAc~#ul(+fu)`7+8yKsU0iYEwkqg1emCo)J8cDyj~bGZBv;Y+-B%&H8*5Avl6#56 zm1qzdos6gkKKj>-b2|CHbolM>#8|&^pSZf-o%%Ag9N=fhwJIqz7%9C)gYI6q}QGS&@pcJ2cx@ipaW(M6e^OeW?30!5Hxnz95 z7ym4HzNhzqv`*Zq4Mog2rNtBQ&G`)#DO_{;Jfr`ZT8ozy5LB%aD$%l<^R87;V||q= zj`A*zkbj~K=W>J&&V#2xsO-Gn%XIvyc(QsA5^86L_FU?A>2y~q`EZwpavmJ;k z>}%h*tAy_pgHmAF6fWT^s_2YC8ddoL|B#Sx2L;qLYJxW%UNc1ual#3CzSRpdjOc#f zUp31&YnRCowDmno%H02qji&f_fW!TH6uj?GKHabXftHQZSLt^qR6n$M#uGQhgW`cD z#a2P8*2>xmT*0lAz>#C|d&JLfR5*N`$zV*|BFA0keW58?;t2hT;ZLcgZ*R*1{4ljd zyj(yqG0yjDhwfA0&b`Qp8GEf@PA1hDBJOGuL6LqhPdr@Uw#!6Sy(r#QW@kcRFtU$^ zaLx{iD)@;WrolSA&6{%Y_qeR`YE_s+=bF5Z*BrZkXRnp}B?Zo_e;+G6b>|}qAC+I` zp+tf(!n#Fk52^D9ArHK5>o3yQBQJx8hYEwQwR-DoRqW4?r37Y0oh1n8UZ`Fe4#>{z z%_YojZM$T?4jp(-?{DCSNrJ(Xy4Fe6R!?n)dYFlu0A%HN{3Dg8&{wc|XafzhSfohq z(Rh3uk{>Z>s*97DIHH>ILBQ?Bf^si62!|B!?-mE8-Jr4wxeAwb3!gY(8R$Q(r3Sj0 z$ljzX#RX?qZ8a&oK!(x4%`Ul1Y2wJrv89CpS!C;E=!0HUsXR?wx`m$z#7Di6 zl-H0UJyxu~?I`-!77FlKB&Z$g47!`QiAPw`127n$DnD(oLxn?5W-N172aPar=~S|_ zxQiA!8>oHFbl9RilEsi=2U2%NFvbduQ&EiNl#zCXpuCM!i|03)M|(kAD#CzR+^!)edP z`uBjAYc=)&f+qdp!&;SP%zfX`U}fnTY>t^3T*A`0;of>FozQgbfjK z7S9E8kUNLUzPXfVj2w437Kt?i;*Oe&_o9CY3YuxWFGp6nkNUrPViigOb4YDsI4&|^ zHL>H#x3oE_5m_27iJzNkE~?|H1E3%1U<0%r?A0I1vuWLto)#&Vx%POi#*Wzuv3L_i zQ&jQzIsFe5_B?qbmN?UGnQI#uT>0Z{55ajlvHCecqSqk=k?(F|qJf9@GU#qf z#fr6MYQAfYWTw$VjE~8F07?hnV_Iy}($XH@b`XYiDM@#ZveOnROF`?x=!)_TB)T`5 zRZnYbc|1sD*^4gDdtTI;;#JgNuQWoa2SlJJsWu&@% z)uZNqb1KTN=wc5XBC`pwB=|6@tLZB&)NYz|EO;nIjs=}84$de-R-CtEy=EeAyuvrCLq uM9wBFT3VkHhQf|B-&_&sVnO^Tk;F!aLGq#IS}EjtGjM_Q4OI3uCE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macOS/SearchifyX/ContentView.swift b/macOS/SearchifyX/ContentView.swift index 00bee22..b41b793 100644 --- a/macOS/SearchifyX/ContentView.swift +++ b/macOS/SearchifyX/ContentView.swift @@ -11,31 +11,34 @@ struct ContentView: View { var isPanel: Bool var question: String? - var body: some View { + @State var selection: Int? + @EnvironmentObject var wkvm: WebViewModel + + var body: some View { NavigationView() { List() { - NavigationLink(destination: ScraperView(isPanel: isPanel, question: question)) { + NavigationLink(destination: ScraperView(isPanel: isPanel, question: question), tag: 0, selection: $selection) { HStack { Image(systemName: "magnifyingglass") Text("Search") } } .navigationTitle("Search") - NavigationLink(destination: BrowserView(isPanel: isPanel)) { + NavigationLink(destination: BrowserView(isPanel: isPanel).environmentObject(wkvm), tag: 1, selection: $selection) { HStack { Image(systemName: "globe.americas") Text("Browser") } } .navigationTitle("Browser") - NavigationLink(destination: NotesView()) { + NavigationLink(destination: NotesView(), tag: 2, selection: $selection) { HStack { Image(systemName: "note.text") Text("Notes") } } .navigationTitle("Notes") - NavigationLink(destination: SettingsView()) { + NavigationLink(destination: SettingsView(), tag: 3, selection: $selection) { HStack { Image(systemName: "gear") Text("Settings") @@ -43,6 +46,9 @@ struct ContentView: View { } .navigationTitle("Settings") } + .onAppear() { + self.selection = 0 + } .toolbar { ToolbarItemGroup(placement: .navigation) { if !isPanel { diff --git a/macOS/SearchifyX/SearchifyXApp.swift b/macOS/SearchifyX/SearchifyXApp.swift index c8c1b6b..7d5d143 100644 --- a/macOS/SearchifyX/SearchifyXApp.swift +++ b/macOS/SearchifyX/SearchifyXApp.swift @@ -8,6 +8,7 @@ struct SearchifyXApp: App { var body: some Scene { WindowGroup { ContentView(isPanel: false) + .environmentObject(Variables.wkModel) } .windowStyle(HiddenTitleBarWindowStyle()) Settings { diff --git a/macOS/SearchifyX/Toolbars/BrowserToolbar.swift b/macOS/SearchifyX/Toolbars/BrowserToolbar.swift index 70aa7d3..7e98b0f 100644 --- a/macOS/SearchifyX/Toolbars/BrowserToolbar.swift +++ b/macOS/SearchifyX/Toolbars/BrowserToolbar.swift @@ -25,7 +25,7 @@ struct BrowserToolbar: View { }) .buttonStyle(.borderless) TextField("Enter URL", text: url) - .frame(minWidth: 400) + .frame(minWidth: 400, maxWidth: 400) .textFieldStyle(.roundedBorder) Button(action: { Variables.wkModel.loadUrl() diff --git a/macOS/SearchifyX/Views/BrowserView.swift b/macOS/SearchifyX/Views/BrowserView.swift index 06e8bff..f3371d4 100644 --- a/macOS/SearchifyX/Views/BrowserView.swift +++ b/macOS/SearchifyX/Views/BrowserView.swift @@ -8,18 +8,14 @@ import SwiftUI struct BrowserView: View { - var urlStr: Binding { Binding( - get: { return Variables.wkModel.urlString }, set: {str in - Variables.wkModel.urlString = str - } - )} - var isPanel: Bool + @EnvironmentObject var wkvm: WebViewModel + var body: some View { VStack { if (isPanel) { - BrowserToolbar(url: urlStr) + BrowserToolbar(url: $wkvm.urlString) .padding(.leading) .padding(.trailing) } @@ -28,7 +24,7 @@ struct BrowserView: View { } .toolbar { ToolbarItemGroup(placement: .principal) { - BrowserToolbar(url: urlStr) + BrowserToolbar(url: $wkvm.urlString) } } .onLoad { diff --git a/macOS/SearchifyX/WebView/WebViewModel.swift b/macOS/SearchifyX/WebView/WebViewModel.swift index 31c43e4..db12488 100644 --- a/macOS/SearchifyX/WebView/WebViewModel.swift +++ b/macOS/SearchifyX/WebView/WebViewModel.swift @@ -9,19 +9,50 @@ import Foundation import WebKit class WebViewModel: ObservableObject { - @Published var urlString: String = "https://google.com/" + @Published var urlString: String = "https://google.com" let instance: WKWebView + var cord: Coordinator? + var bindingsInit: Bool init() { instance = WKWebView(frame: .zero); + bindingsInit = false + cord = nil } func loadUrl() { - guard let url = URL(string: urlString) else { + createBindings() + + if !urlString.starts(with: "http") { + urlString = "https://" + urlString + } + + var req = URLRequest(url: URL(string: urlString)!) + instance.load(req) + } + + func createBindings() { + if bindingsInit == true { return } + cord = Coordinator(self) + instance.navigationDelegate = cord + bindingsInit = true + } + + class Coordinator: NSObject, WKNavigationDelegate { + let parent: WebViewModel + + init(_ parent: WebViewModel) { + self.parent = parent + } + + func webView(_ webView: WKWebView, + didStartProvisionalNavigation navigation: WKNavigation!) { + print(webView.url!.absoluteString) + parent.urlString = webView.url!.absoluteString + } - instance.load(URLRequest(url: url)) } } diff --git a/macOS/build.sh b/macOS/build.sh index cec70df..3457b4b 100755 --- a/macOS/build.sh +++ b/macOS/build.sh @@ -4,7 +4,8 @@ pip3 install -r requirements.txt # Generate app -pyinstaller ../scraper.py +mkdir ./SearchifyX/scraper +python3 -m PyInstaller --noconfirm ../scraper.py # Delete old scraper.app rm -r ./SearchifyX/scraper diff --git a/macOS/requirements.txt b/macOS/requirements.txt deleted file mode 100644 index 94c6923..0000000 --- a/macOS/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -beautifulsoup4==4.11.1 -fake_headers==1.0.2 -grequests==0.6.0 -requests_html==0.10.0 -pyinstaller==5.3 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 413d27f..0000000 --- a/requirements.txt +++ /dev/null @@ -1,44 +0,0 @@ -appdirs==1.4.4 -beautifulsoup4==4.10.0 -bs4==0.0.1 -certifi==2022.12.7 -cffi==1.15.0 -charset-normalizer==2.0.9 -colorama==0.4.4 -cssselect==1.1.0 -fake-headers==1.0.2 -fake-useragent==0.1.11 -gevent==21.12.0 -greenlet==1.1.2 -grequests==0.6.0 -html5lib==1.1 -idna==3.3 -importlib-metadata==4.11.3 -keyboard==0.13.5 -lxml==4.9.1 -packaging==21.3 -parse==1.19.0 -Pillow==9.3.0 -pycparser==2.21 -pyee==8.2.2 -pyparsing==3.0.8 -pyperclip==1.8.2 -pyppeteer==1.0.2 -PyQt5==5.15.6 -PyQt5-Qt5==5.15.2 -PyQt5-sip==12.9.0 -pyquery==1.4.3 -pytesseract==0.3.9 -pywin32==303 -requests==2.26.0 -requests-html==0.10.0 -six==1.16.0 -soupsieve==2.3.1 -tqdm==4.64.0 -urllib3==1.26.7 -w3lib==1.22.0 -webencodings==0.5.1 -websockets==10.2 -zipp==3.8.0 -zope.event==4.5.0 -zope.interface==5.4.0 diff --git a/scraper.py b/scraper.py deleted file mode 100644 index 31ee4dc..0000000 --- a/scraper.py +++ /dev/null @@ -1,414 +0,0 @@ -import grequests -import json -from bs4 import BeautifulSoup -from difflib import SequenceMatcher -import json -from requests_html import HTMLSession -from fake_headers import Headers -import re -import sys -import time -from random import choice -from urllib.parse import urlencode -from threading import Thread - -headers = { - "Sec-Ch-Ua": "\"(Not(A:Brand\";v=\"8\", \"Chromium\";v=\"99\"", - "Sec-Ch-Ua-Mobile": "?0", - "Sec-Ch-Ua-Platform": "\"Windows\"", - "Upgrade-Insecure-Requests": "1", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36", - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", - "Sec-Fetch-Site": "none", - "Sec-Fetch-Mode": "navigate", - "Sec-Fetch-User": "?1", - "Sec-Fetch-Dest": "document", - "Accept-Encoding": "gzip, deflate", - "Accept-Language": "en-US,en;q=0.9", - "Connection": "close" -} - -google_domains = ( - 'com', 'ad', 'ae', 'com.af', 'com.ag', 'com.ai', 'al', 'am', - 'co.ao', 'com.ar', 'as', 'at', 'com.au', 'az', 'ba', 'com.bd', - 'be', 'bf', 'bg', 'com.bh', 'bi', 'bj', 'com.bn', 'com.bo', - 'com.br', 'bs', 'bt', 'co.bw', 'by', 'com.bz', 'ca', 'cd', 'cf', - 'cg', 'ch', 'ci', 'co.ck', 'cl', 'cm', 'cn', 'com.co', 'co.cr', - 'com.cu', 'cv', 'com.cy', 'cz', 'de', 'dj', 'dk', 'dm', 'com.do', - 'dz', 'com.ec', 'ee', 'com.eg', 'es', 'com.et', 'fi', 'com.fj', - 'fm', 'fr', 'ga', 'ge', 'gg', 'com.gh', 'com.gi', 'gl', 'gm', - 'gr', 'com.gt', 'gy', 'com.hk', 'hn', 'hr', 'ht', 'hu', 'co.id', - 'ie', 'co.il', 'im', 'co.in', 'iq', 'is', 'it', 'je', 'com.jm', - 'jo', 'co.jp', 'co.ke', 'com.kh', 'ki', 'kg', 'co.kr', 'com.kw', - 'kz', 'la', 'com.lb', 'li', 'lk', 'co.ls', 'lt', 'lu', 'lv', - 'com.ly', 'co.ma', 'md', 'me', 'mg', 'mk', 'ml', 'com.mm', 'mn', - 'ms', 'com.mt', 'mu', 'mv', 'mw', 'com.mx', 'com.my', 'co.mz', - 'com.na', 'com.ng', 'com.ni', 'ne', 'nl', 'no', 'com.np', 'nr', - 'nu', 'co.nz', 'com.om', 'com.pa', 'com.pe', 'com.pg', 'com.ph', - 'com.pk', 'pl', 'pn', 'com.pr', 'ps', 'pt', 'com.py', 'com.qa', - 'ro', 'ru', 'rw', 'com.sa', 'com.sb', 'sc', 'se', 'com.sg', 'sh', - 'si', 'sk', 'com.sl', 'sn', 'so', 'sm', 'sr', 'st', 'com.sv', - 'td', 'tg', 'co.th', 'com.tj', 'tl', 'tm', 'tn', 'to', 'com.tr', - 'tt', 'com.tw', 'co.tz', 'com.ua', 'co.ug', 'co.uk', 'com.uy', - 'co.uz', 'com.vc', 'co.ve', 'vg', 'co.vi', 'com.vn', 'vu', 'ws', - 'rs', 'co.za', 'co.zm', 'co.zw', 'cat' -) - -get_text = lambda x: BeautifulSoup(x, features='lxml').get_text().strip() -sluggify = lambda a: ' '.join(re.sub(r'[^\\sa-z0-9\\.,\\(\\)]+', ' ', a.lower()).split()) -similar = lambda a, b: SequenceMatcher(None, sluggify(a), sluggify(b)).ratio() -remove_duplicates = lambda a: list(set(a)) - -def _make_headers(): - return {**headers, **Headers(headers=True, browser='chrome', os='windows').generate()} - - -class SearchEngine: - def __init__(self, engine_name): - self.sess = HTMLSession() - self.engine_name = engine_name - self._web_engines = { # simple scrapers using get requests - 'google': { - 'domain': 'https://www.google.com/', - 'query': 'q', - 'args': {'aqs': 'chrome..69i57.888j0j1', 'sourceid': 'chrome', 'ie': 'UTF-8'}, - 'limit': 2038 - }, - 'bing': { - 'domain': 'https://www.bing.com/', - 'query': 'q', - 'args': {'ghsh': '0', 'ghacc': '0', 'ghpl': ''}, - 'limit': 990 - }, - 'startpage': { - 'domain': 'https://www.startpage.com/', - 'limit': 2038 - } - } - self.sess.headers.update({**headers, "Sec-Fetch-Site": "same-origin", 'Referer': self._web_engines[self.engine_name]['domain']}) - print('Starting instance...') - self.t = Thread(target=self._init_search) - self.t.daemon = True - self.t.start() - - def _init_search(self): - if self.engine_name == 'google': - return - r = self.sess.get(self._web_engines[self.engine_name]['domain']) - if self.engine_name == 'startpage': - self._startpage_data = self.get_startpage_items(r) - - def startpage_get_page(self, query, sites): - resps = grequests.map([ - grequests.post('https://www.startpage.com/sp/search', - data={ - **self._startpage_data, - 'query': f"{query[:self._web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com" - }, - session=self.sess - ) - for site in sites - ]) - self.t = Thread(target=self.get_startpage_items, args=(resps[-1],)) - self.t.daemon = True - self.t.start() - return dict(zip(sites, resps)) - - def find_items(self, soup, args): - return {i: soup.find('input', {'type': 'hidden', 'name': i})['value'] for i in args} - - def get_startpage_items(self, r): - soup = BeautifulSoup(r.text, 'lxml') - return {'query': None, 'cat': 'web', **self.find_items(soup, ['lui', 'language', 'sc', 'abp'])} - - def get_page(self, query, sites): - self.t.join() - # escape query sequence - query = re.escape(query) - if self.engine_name == 'startpage': - return self.startpage_get_page(query, sites) - elif self.engine_name == 'google': - self.sess.headers['Referer'] = self._web_engines[self.engine_name]['domain'] = f'https://www.google.{choice(google_domains)}/' - return dict(zip( - sites, - grequests.map([ - grequests.get( - (web_engine := self._web_engines[self.engine_name])['domain'] + 'search?' - + urlencode({ - web_engine['query']: f"{query[:self._web_engines[self.engine_name]['limit']-len(site)]} site:{site}.com", - **web_engine['args'] - }), - session=self.sess - ) - for site in sites - ], size=len(sites)) - )) - -class SearchWeb: - """ - search web for query - """ - def __init__(self, query, sites, engine): - self.query = query - self.links = None - self.sites = sites - self.engine = engine - self._regex_objs = { - 'quizlet': re.compile('https?://quizlet.com/\d+/[a-z0-9\\-]+/'), - 'quizizz': re.compile('https?://quizizz.com/admin/quiz/[a-f0-9]+/[a-z\\-]+'), - } - - def search(self): - """ - search web for query - """ - resps = self.engine.get_page(self.query, self.sites) - self.links = { - site: remove_duplicates(re.findall(self._regex_objs[site], resps[site].text)) - for site in self.sites - } - - -class QuizizzScraper: - def __init__(self, links, query): - self.links = links - self.resps = None - self.quizizzs = [] - self.query = query - - def async_requests(self, links): - reqs = [grequests.get(u, headers=_make_headers()) for u in links] - self.resps = grequests.map(reqs, size=len(reqs)) - - def parse_links(self): - links = ['https://quizizz.com/quiz/' + u.split('/')[-2] for u in self.links] - self.async_requests(links) - for resp in self.resps: - try: - self.quizizzs.append(self.quizizz_parser(resp)) - except Exception as e: - print('exception', e, resp.url) - return self.quizizzs - - - def quizizz_parser(self, resp): - data = resp.json()['data']['quiz']['info'] - return max( - ( - { - 'question': questr, - 'answer': get_text( - question["structure"]["options"][ - int(question["structure"]["answer"]) - ]["text"] - ) - or question["structure"]["options"][ - int(question["structure"]["answer"]) - ]["media"][0]["url"] - if question["type"] == "MCQ" - else ', '.join( - [ - get_text( - question["structure"]["options"][int(answerC)]["text"] - ) - or question["structure"]["options"][int(answerC)]["media"][0]["url"] - for answerC in question["structure"]["answer"] - ] - ) - if question["type"] == "MSQ" - else None, - 'similarity': (similar(questr, self.query), True), - 'url': resp.url, - } - for questr, question in [ - (get_text(x["structure"]["query"]["text"]), x) - for x in data["questions"] - ] - ), - key=lambda x: x['similarity'], - ) - - - -class QuizletScraper: - def __init__(self, links, query): - self.links = links - self.resps = None - self.quizlets = [] - self.query = query - self._regex_obj = re.compile('\\= \\{"alphabeticalIsDifferent.*\\}; QLoad\\(') - - def async_requests(self, links): - reqs = [grequests.get(u, headers=_make_headers()) for u in links] - self.resps = grequests.map(reqs, size=len(reqs)) - - def parse_links(self): - self.async_requests(self.links) - for resp in self.resps: - try: - self.quizlets.append(self.quizlet_parser(resp)) - except Exception as e: - print('exception', e, resp.url) - # pass # skip over any errors - return self.quizlets - - - def quizlet_parser(self, resp): - data = json.loads(re.findall(self._regex_obj, resp.text)[0][2:-8]) # get quizlet headerData - return max( - ( - { - 'question': i['word'].strip(), - 'answer': i['definition'].strip(), - 'similarity': max( - (similar(i[x], self.query), x == 'word') - # (similarity: float, is_term: bool) - for x in ['word', 'definition'] - ), - 'url': resp.url, - } - for i in data['termIdToTermsMap'].values() - ), - key=lambda x: x['similarity'], - ) - - -class TimeLogger: - def __init__(self): - self.elapsed_total = time.time() - self.ongoing = {} - self.finished = {} - self.finished_threads = {} - - def start(self, item): - self.ongoing[item] = time.time() - - def end(self, item=-1, _thread_flag=False): - if type(item) == int: - item = list(self.ongoing)[item] - if _thread_flag: - self.finished_threads[item] = time.time() - self.ongoing.pop(item) - else: - self.finished[item] = time.time() - self.ongoing.pop(item) - - def print_timers(self): - print('ELAPSED RUN TIMES:') - longest_len = len(max(list(self.finished), key=lambda x: len(x))) - for k, v in self.finished.items(): - print(f'> {k.title().ljust(longest_len, " ")} \t= {round(v, 5)}') - if self.finished_threads: - print( - '> Threads'.ljust(longest_len, " ") + - ' \t= ' + - (',\n'+longest_len*' ' + ' \t ').join([ - ': '.join([name.title(), str(round(time, 5))]) - for name, time in self.finished_threads.items() - ]) - ) - print('TOTAL ELAPSED'.ljust(longest_len, " ") + ' \t= ' + str(round(time.time() - self.elapsed_total, 5))) - - - -class Searchify: - def __init__(self, query, sites, engine): - self.query = query - self.sites = sites - self.engine = engine - self.timer = TimeLogger() - self.flashcards = [] - self.links = [] - self.site_scrapers = { - 'quizlet': QuizletScraper, - 'quizizz': QuizizzScraper, - } - - def main(self): - self.get_links() - threads = [] - for site in self.sites: - threads.append(Thread( - target=self._flashcard_thread, - args=( - self.site_scrapers[site], - self.links[site], - site, - ) - )) - threads[-1].daemon = True - self.timer.start(site) - threads[-1].start() - - for n, T in enumerate(threads): - T.join() - print(f'Thread {n} finished') - - self.sort_flashcards() - self.stop_time = time.time() - self.timer.elapsed_total - - - def _flashcard_thread(self, site_scraper, links, site_name): - self.flashcards += site_scraper(links, self.query).parse_links() - self.timer.end(site_name, _thread_flag=True) - - - def get_links(self): - self.timer.start('web search') - search_bing = SearchWeb(self.query, self.sites, self.engine) - search_bing.search() - self.timer.end() - self.links = search_bing.links - - - def sort_flashcards(self): # sourcery skip: for-index-replacement - self.flashcards.sort(key=lambda x: x['similarity'], reverse=True) - - for card in range(len(self.flashcards)): - if not self.flashcards[card]['similarity'][1]: # if cards and terms are swapped - self.flashcards[card]['question'], self.flashcards[card]['answer'] = ( - self.flashcards[card]['answer'], self.flashcards[card]['question'] ) - - self.flashcards[card]['similarity'] = str(round(self.flashcards[card]['similarity'][0] * 100, 2)) + '%' - - - -if __name__ == '__main__' and len(sys.argv) > 1: - # argument parsing - import argparse - parser = argparse.ArgumentParser(description='Search the web for flashcards') - parser.add_argument('--query', '-q', help='query to search for', default=None) - parser.add_argument('--output', '-o', help='output file', default=None) - parser.add_argument('--sites', '-s', help='question sources quizlet,quizizz (comma seperated list)', default='quizlet,quizizz') - parser.add_argument('--engine', '-e', help='search engine to use (google, bing)', default='bing') - args = parser.parse_args() - - if args.output: - f = open(args.output, 'w') - write = f.write - else: - write = print - - if not args.query: - print('No input specified') - exit() - - # main program - flashcards = [] # create flashcard list - - sites = args.sites.lower().split(',') # get list of sites - engine_name = args.engine.lower().strip() # get search engine - - # start search engine - engine = SearchEngine(engine_name) - - # run search - s = Searchify( - query=args.query, - sites=sites, - engine=engine, - ) - s.main() - - write(json.dumps(s.flashcards, indent=4)) - print(f'{len(s.flashcards)} flashcards found') - - s.timer.print_timers() \ No newline at end of file diff --git a/textshot.py b/textshot.py deleted file mode 100644 index cae8cc3..0000000 --- a/textshot.py +++ /dev/null @@ -1,188 +0,0 @@ -""" - -HEAVILY ADAPTED FROM https://github.com/ianzhao05/textshot -USE PERMITTED UNDER MIT LICENSE - -Copyright (c) 2020 Ian Zhao - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -""" - -import io -import os -import sys -import ctypes, win32con - -import pytesseract -from PIL import Image -from PyQt5 import QtCore, QtGui, QtWidgets -from PyQt5.QtCore import Qt - - -def resource_path(relative_path): - try: - base_path = sys._MEIPASS - except Exception: - base_path = os.path.dirname(__file__) - return os.path.join(base_path, relative_path) - -pytesseract.pytesseract.tesseract_cmd = resource_path(r"tesseract-ocr\tesseract.exe") -user32 = ctypes.windll.user32 - - -class Snipper(QtWidgets.QWidget): - def __init__(self, parent=None, flags=Qt.WindowFlags()): - super().__init__(parent=parent, flags=flags) - self.setWindowTitle("TextShot") - self.set_window_flags() - self._pressed = False - - - def set_window_flags(self): - self.setAttribute(Qt.WA_ShowWithoutActivating) - - self.setWindowFlags( - Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Dialog - ) - self.setWindowState(self.windowState() | Qt.WindowFullScreen) - - dc = int(self.winId()) - user32.SetWindowLongW(dc, win32con.GWL_EXSTYLE, user32.GetWindowLongW(dc, win32con.GWL_EXSTYLE) | win32con.WS_EX_NOACTIVATE | win32con.WS_EX_APPWINDOW) - - screen = QtWidgets.QApplication.screenAt(QtGui.QCursor.pos()) # get screen - self.screen = screen.grabWindow(0) # screenshot - geom = screen.geometry() # get position of screen - self.setGeometry(geom.left(), geom.top(), geom.width(), geom.height()) # move window to monitor - - - def run(self): - self._running = True - self.set_window_flags() # reset all window flags - QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor)) - - palette = QtGui.QPalette() - palette.setBrush(self.backgroundRole(), QtGui.QBrush(self.screen)) - self.setPalette(palette) - self.start = self.end = QtCore.QPoint() - self._pressed = self.result = None - self.show() - - - def quit_app(self, canceled=False): - self._running = False if canceled else None - QtWidgets.QApplication.restoreOverrideCursor() - QtWidgets.QApplication.processEvents() - self.hide() - # QtWidgets.QApplication.quit() - - - def keyPressEvent(self, event): - if event.key() == Qt.Key_Escape: - self.quit_app(canceled=True) - - return super().keyPressEvent(event) - - def paintEvent(self, event): - painter = QtGui.QPainter(self) - painter.setPen(Qt.NoPen) - painter.setBrush(QtGui.QColor(0, 0, 0, 100)) - painter.drawRect(0, 0, self.width(), self.height()) - - if self.start == self.end: - return super().paintEvent(event) - - painter.setPen(QtGui.QPen(QtGui.QColor(255, 255, 255), 3)) - painter.setBrush(painter.background()) - painter.drawRect(QtCore.QRect(self.start, self.end)) - return super().paintEvent(event) - - - def mousePressEvent(self, event): - if event.button() == Qt.LeftButton: - self.start = self.end = event.pos() - self._pressed = True - self.update() - elif event.button() == Qt.RightButton: - if self._pressed: - self.start = self.end = QtCore.QPoint() - self.update() - self._pressed = False - else: - self.hide() - self.quit_app(canceled=True) - return super().mousePressEvent(event) - - - def mouseMoveEvent(self, event): - if self._pressed: - self.end = event.pos() - self.update() - return super().mousePressEvent(event) - - - def mouseReleaseEvent(self, event): - if event.button() == Qt.LeftButton: - self._pressed = False - - if self.start == self.end or event.button() != Qt.LeftButton: - return super().mouseReleaseEvent(event) - - self.hide() - QtWidgets.QApplication.restoreOverrideCursor() - QtWidgets.QApplication.processEvents() - - shot = self.screen.copy( - min(self.start.x(), self.end.x()), - min(self.start.y(), self.end.y()), - abs(self.start.x() - self.end.x()), - abs(self.start.y() - self.end.y()), - ) - self.processImage(shot) - self.quit_app() - print('done') - - - def processImage(self, img): - buffer = QtCore.QBuffer() - buffer.open(QtCore.QBuffer.ReadWrite) - img.save(buffer, "PNG") - pil_img = Image.open(io.BytesIO(buffer.data())) - buffer.close() - - try: - self.result = pytesseract.image_to_string( - pil_img, lang=(sys.argv[1] if len(sys.argv) > 1 else None) - ).strip() - except RuntimeError as error: - self.result = None - print(f"ERROR: An error occurred when trying to process the image: {error}") - - if self.result: - print(f'INFO: returned "{self.result}"') - else: - print("INFO: Unable to read text from image, did not copy") - - - - -if __name__ == "__main__": - QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling) - app = QtWidgets.QApplication(sys.argv) - try: - pytesseract.get_tesseract_version() - except EnvironmentError: - raise ( - "ERROR: Tesseract is either not installed or cannot be reached.\n" - "Have you installed it and added the install directory to your system path?" - ) - - window = QtWidgets.QMainWindow() - snipper = Snipper(window) - snipper.run() - sys.exit(app.exec_()) diff --git a/window.ui b/window.ui deleted file mode 100644 index 8ae405e..0000000 --- a/window.ui +++ /dev/null @@ -1,1183 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 700 - 450 - - - - - Poppins Medium - 10 - - - - SearchifyX - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 6 - - - 4 - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 6 - - - 4 - - - - - - 6 - - - 0 - - - 6 - - - 3 - - - 3 - - - - - QFrame::NoFrame - - - QAbstractItemView::ScrollPerPixel - - - false - - - - Confidence - - - - - Identified Question - - - - - Answer - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - Settings - - - - - - true - - - - - - - - 30 - 30 - - - - Quizlet - - - true - - - false - - - true - - - - - - - - 30 - 30 - - - - Quizizz - - - true - - - false - - - true - - - - - - - - - - 6 - - - 0 - - - 5 - - - 0 - - - 0 - - - - - false - - - Type a question here - - - true - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - Search text using OCR - - - - - - true - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - 0 - 27 - - - - - Segoe MDL2 Assets - 14 - - - - Search text in clipboard - - - - - - true - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - Search - - - - - - false - - - false - - - true - - - - - - - - - - - - - - - 5 - - - 0 - - - 5 - - - 0 - - - 6 - - - 4 - - - - - QFrame::NoFrame - - - true - - - - - 0 - -77 - 656 - 465 - - - - - - - Window - - - true - - - - - - - - - 150 - 0 - - - - - Auto - - - - - Light - - - - - Dark - - - - - Classic - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Font Size: - - - - - - - - 100 - 0 - - - - Theme: - - - - - - - 20 - - - 10 - - - Qt::Horizontal - - - - - - - - 70 - 0 - - - - px - - - 5 - - - 10 - - - - - - - - - Remember window transparency - - - false - - - - - - - Always on top - - - true - - - - - - - Right-click title bar to reset window position - - - true - - - - - - - Remember window position - - - false - - - - - - - Remember state for window focus safety lock - - - false - - - - - - - Don't show in taskbar - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Global Hotkeys - - - true - - - - - - Clear - - - - - - - - 150 - 0 - - - - Hide/show window: - - - - - - - Clear - - - - - - - Clear - - - - - - - - 150 - 16777215 - - - - Alt+Shift+O - - - - - - - OCR & search: - - - - - - - - 150 - 16777215 - - - - Alt+Shift+V - - - - - - - Paste & search: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 150 - 16777215 - - - - Ctrl+D - - - - - - - - 150 - 16777215 - - - - - - - - - - Window opacity to: - - - - - - - false - - - QAbstractSpinBox::NoButtons - - - % - - - 5 - - - 100 - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - - Clear - - - - - - - - - - Search - - - true - - - - - - Search after pasting - - - true - - - - - - - Search after running OCR - - - true - - - - - - - - - - 150 - 0 - - - - - Bing - - - - - Google - - - - - Startpage - - - - - - - - - 100 - 0 - - - - Search engine: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 70 - 20 - - - - - - - - - - - - - - - - - 6 - - - 6 - - - 4 - - - 6 - - - 4 - - - - - Qt::Horizontal - - - - 591 - 27 - - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - - - - true - - - - - - - Go Back - - - - - - - - - - - - - true - - - - 6 - - - 6 - - - 2 - - - 6 - - - 2 - - - - - - 0 - 0 - - - - - 181 - 0 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 20 - 20 - - - - true - - - - - - - SearchifyX - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 100 - 16777215 - - - - Window transparency - - - 5 - - - 100 - - - 95 - - - Qt::Horizontal - - - QSlider::NoTicks - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - Unlock window (allow focus) - - - - - - true - - - false - - - true - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - - - - false - - - true - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - Segoe MDL2 Assets - 14 - - - - - - - false - - - true - - - - - - - - - - - - - font_size_slider - valueChanged(int) - font_size - setValue(int) - - - 242 - 315 - - - 150 - 311 - - - - - font_size - valueChanged(int) - font_size_slider - setValue(int) - - - 172 - 324 - - - 285 - 315 - - - - - diff --git a/windoweffect/LICENSE b/windoweffect/LICENSE deleted file mode 100644 index c446912..0000000 --- a/windoweffect/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021 Zhengzhi Huang - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/windoweffect/__init__.py b/windoweffect/__init__.py deleted file mode 100644 index a3fb4ed..0000000 --- a/windoweffect/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .window_effect import WindowEffect -from .c_structures import * \ No newline at end of file diff --git a/windoweffect/c_structures.py b/windoweffect/c_structures.py deleted file mode 100644 index 1553383..0000000 --- a/windoweffect/c_structures.py +++ /dev/null @@ -1,135 +0,0 @@ -# coding:utf-8 - -from ctypes import POINTER, Structure, c_int -from ctypes.wintypes import DWORD, HWND, ULONG, POINT, RECT, UINT -from enum import Enum - - -class WINDOWCOMPOSITIONATTRIB(Enum): - WCA_UNDEFINED = 0 - WCA_NCRENDERING_ENABLED = 1 - WCA_NCRENDERING_POLICY = 2 - WCA_TRANSITIONS_FORCEDISABLED = 3 - WCA_ALLOW_NCPAINT = 4 - WCA_CAPTION_BUTTON_BOUNDS = 5 - WCA_NONCLIENT_RTL_LAYOUT = 6 - WCA_FORCE_ICONIC_REPRESENTATION = 7 - WCA_EXTENDED_FRAME_BOUNDS = 8 - WCA_HAS_ICONIC_BITMAP = 9 - WCA_THEME_ATTRIBUTES = 10 - WCA_NCRENDERING_EXILED = 11 - WCA_NCADORNMENTINFO = 12 - WCA_EXCLUDED_FROM_LIVEPREVIEW = 13 - WCA_VIDEO_OVERLAY_ACTIVE = 14 - WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15 - WCA_DISALLOW_PEEK = 16 - WCA_CLOAK = 17 - WCA_CLOAKED = 18 - WCA_ACCENT_POLICY = 19 - WCA_FREEZE_REPRESENTATION = 20 - WCA_EVER_UNCLOAKED = 21 - WCA_VISUAL_OWNER = 22 - WCA_LAST = 23 - - -class ACCENT_STATE(Enum): - """ Client area status enumeration class """ - ACCENT_DISABLED = 0 - ACCENT_ENABLE_GRADIENT = 1 - ACCENT_ENABLE_TRANSPARENTGRADIENT = 2 - ACCENT_ENABLE_BLURBEHIND = 3 # Aero effect - ACCENT_ENABLE_ACRYLICBLURBEHIND = 4 # Acrylic effect - ACCENT_ENABLE_HOSTBACKDROP = 5 # Mica effect - ACCENT_INVALID_STATE = 6 - - -class ACCENT_POLICY(Structure): - """ Specific attributes of client area """ - - _fields_ = [ - ("AccentState", DWORD), - ("AccentFlags", DWORD), - ("GradientColor", DWORD), - ("AnimationId", DWORD), - ] - - -class WINDOWCOMPOSITIONATTRIBDATA(Structure): - _fields_ = [ - ("Attribute", DWORD), - # Pointer() receives any ctypes type and returns a pointer type - ("Data", POINTER(ACCENT_POLICY)), - ("SizeOfData", ULONG), - ] - - -class DWMNCRENDERINGPOLICY(Enum): - DWMNCRP_USEWINDOWSTYLE = 0 - DWMNCRP_DISABLED = 1 - DWMNCRP_ENABLED = 2 - DWMNCRP_LAS = 3 - - -class DWMWINDOWATTRIBUTE(Enum): - DWMWA_NCRENDERING_ENABLED = 1 - DWMWA_NCRENDERING_POLICY = 2 - DWMWA_TRANSITIONS_FORCEDISABLED = 3 - DWMWA_ALLOW_NCPAINT = 4 - DWMWA_CAPTION_BUTTON_BOUNDS = 5 - DWMWA_NONCLIENT_RTL_LAYOUT = 6 - DWMWA_FORCE_ICONIC_REPRESENTATION = 7 - DWMWA_FLIP3D_POLICY = 8 - DWMWA_EXTENDED_FRAME_BOUNDS = 9 - DWMWA_HAS_ICONIC_BITMAP = 10 - DWMWA_DISALLOW_PEEK = 11 - DWMWA_EXCLUDED_FROM_PEEK = 12 - DWMWA_CLOAK = 13 - DWMWA_CLOAKED = 14 - DWMWA_FREEZE_REPRESENTATION = 15 - DWMWA_PASSIVE_UPDATE_MODE = 16 - DWMWA_USE_HOSTBACKDROPBRUSH = 17 - DWMWA_USE_IMMERSIVE_DARK_MODE = 18 - DWMWA_WINDOW_CORNER_PREFERENCE = 19 - DWMWA_BORDER_COLOR = 20 - DWMWA_CAPTION_COLOR = 21 - DWMWA_TEXT_COLOR = 22 - DWMWA_VISIBLE_FRAME_BORDER_THICKNESS = 23 - DWMWA_LAST = 24 - - -class MARGINS(Structure): - _fields_ = [ - ("cxLeftWidth", c_int), - ("cxRightWidth", c_int), - ("cyTopHeight", c_int), - ("cyBottomHeight", c_int), - ] - - -class MINMAXINFO(Structure): - _fields_ = [ - ("ptReserved", POINT), - ("ptMaxSize", POINT), - ("ptMaxPosition", POINT), - ("ptMinTrackSize", POINT), - ("ptMaxTrackSize", POINT), - ] - - -class PWINDOWPOS(Structure): - _fields_ = [ - ('hWnd', HWND), - ('hwndInsertAfter', HWND), - ('x', c_int), - ('y', c_int), - ('cx', c_int), - ('cy', c_int), - ('flags', UINT) - ] - - -class NCCALCSIZE_PARAMS(Structure): - _fields_ = [ - ('rgrc', RECT*3), - ('lppos', POINTER(PWINDOWPOS)) - ] diff --git a/windoweffect/window_effect.py b/windoweffect/window_effect.py deleted file mode 100644 index e53946c..0000000 --- a/windoweffect/window_effect.py +++ /dev/null @@ -1,114 +0,0 @@ -# coding:utf-8 -import sys - -from ctypes import POINTER, c_bool, c_int, pointer, sizeof, WinDLL, byref -from ctypes.wintypes import DWORD, LONG, LPCVOID - -from win32 import win32api, win32gui -from win32.lib import win32con - -from .c_structures import ( - ACCENT_POLICY, - ACCENT_STATE, - MARGINS, - DWMNCRENDERINGPOLICY, - DWMWINDOWATTRIBUTE, - WINDOWCOMPOSITIONATTRIB, - WINDOWCOMPOSITIONATTRIBDATA, -) - - -class WindowEffect: - """ A class that calls Windows API to realize window effect """ - - def __init__(self): - # Declare the function signature of the API - self.user32 = WinDLL("user32") - self.dwmapi = WinDLL("dwmapi") - self.SetWindowCompositionAttribute = self.user32.SetWindowCompositionAttribute - self.DwmExtendFrameIntoClientArea = self.dwmapi.DwmExtendFrameIntoClientArea - self.DwmSetWindowAttribute = self.dwmapi.DwmSetWindowAttribute - self.SetWindowCompositionAttribute.restype = c_bool - self.DwmExtendFrameIntoClientArea.restype = LONG - self.DwmSetWindowAttribute.restype = LONG - self.SetWindowCompositionAttribute.argtypes = [ - c_int, - POINTER(WINDOWCOMPOSITIONATTRIBDATA), - ] - self.DwmSetWindowAttribute.argtypes = [c_int, DWORD, LPCVOID, DWORD] - self.DwmExtendFrameIntoClientArea.argtypes = [c_int, POINTER(MARGINS)] - - # Initialize structure - self.accentPolicy = ACCENT_POLICY() - self.winCompAttrData = WINDOWCOMPOSITIONATTRIBDATA() - self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value - self.winCompAttrData.SizeOfData = sizeof(self.accentPolicy) - self.winCompAttrData.Data = pointer(self.accentPolicy) - - - def addShadowEffect(self, hWnd): - """ Add DWM shadow to the window - - Parameters - ---------- - hWnd: int or `sip.voidptr` - Window handle - """ - hWnd = int(hWnd) - self.DwmSetWindowAttribute( - hWnd, - DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value, - byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_ENABLED.value)), - 4, - ) - margins = MARGINS(-1, -1, -1, -1) - self.DwmExtendFrameIntoClientArea(hWnd, byref(margins)) - - def removeShadowEffect(self, hWnd): - """ Remove DWM shadow from the window - - Parameters - ---------- - hWnd: int or `sip.voidptr` - Window handle - """ - hWnd = int(hWnd) - self.DwmSetWindowAttribute( - hWnd, - DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value, - byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_DISABLED.value)), - 4, - ) - - @staticmethod - def removeMenuShadowEffect(hWnd): - """ Remove shadow from pop-up menu - - Parameters - ---------- - hWnd: int or `sip.voidptr` - Window handle - """ - style = win32gui.GetClassLong(hWnd, win32con.GCL_STYLE) - style &= ~0x00020000 # CS_DROPSHADOW - win32api.SetClassLong(hWnd, win32con.GCL_STYLE, style) - - @staticmethod - def addWindowAnimation(hWnd): - """ Enables the maximize and minimize animation of the window - - Parameters - ---------- - hWnd : int or `sip.voidptr` - Window handle - """ - style = win32gui.GetWindowLong(hWnd, win32con.GWL_STYLE) - win32gui.SetWindowLong( - hWnd, - win32con.GWL_STYLE, - style - | win32con.WS_MAXIMIZEBOX - | win32con.WS_CAPTION - | win32con.CS_DBLCLKS - | win32con.WS_THICKFRAME, - ) From 6f73686be8abb90df84df26f5163bebff83774d6 Mon Sep 17 00:00:00 2001 From: daijro Date: Fri, 27 Jan 2023 16:22:36 -0600 Subject: [PATCH 37/39] Bug fixes - Fix dark mode not working on all devices - Don't omit non-alphanumeric characters for checking levenshtein distance. This change will add support for searching code and programming questions --- gui.pyw | 26 ++------------------------ requirements.txt | 1 + scraper.py | 2 +- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/gui.pyw b/gui.pyw index d1781d0..9f27305 100644 --- a/gui.pyw +++ b/gui.pyw @@ -17,6 +17,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets, uic from PyQt5.QtCore import QObject, Qt, pyqtSignal from PyQt5.QtWidgets import QApplication, QMainWindow from win32api import GetMonitorInfo, MonitorFromPoint +import darkdetect from tkinter import messagebox import tkinter as tk @@ -602,36 +603,13 @@ class UI(QMainWindow): return json.load(f) -def detect_darkmode_in_windows() -> bool: # automatically detect dark mode - try: - import winreg - except ImportError: - return False - registry = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER) - reg_keypath = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize' - try: - reg_key = winreg.OpenKey(registry, reg_keypath) - except FileNotFoundError: - return False - - for i in range(1024): - try: - value_name, value, _ = winreg.EnumValue(reg_key, i) - if value_name == 'AppsUseLightTheme': - return value == 0 - except OSError: - break - return False - - - # initialize app QtCore.QCoreApplication.setAttribute(Qt.AA_DisableHighDpiScaling) app = QApplication(sys.argv) QtGui.QFontDatabase.addApplicationFont(resource_path('fonts\\Poppins Medium.ttf')) # color palettes -DARK_MODE = detect_darkmode_in_windows() +DARK_MODE = darkdetect.isDark() light_palette = QtGui.QPalette() diff --git a/requirements.txt b/requirements.txt index 3eeb4a3..b06c6b9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ cffi==1.15.1 charset-normalizer==2.1.1 colorama==0.4.6 cssselect==1.2.0 +darkdetect==0.5.1 fake-headers==1.0.2 fake-useragent==1.1.1 gevent==22.10.2 diff --git a/scraper.py b/scraper.py index 5f94e95..43d47b3 100644 --- a/scraper.py +++ b/scraper.py @@ -55,7 +55,7 @@ ) get_text = lambda x: BeautifulSoup(x, features='lxml').get_text().strip() -sluggify = lambda a: ' '.join(re.sub(r'[^\\sa-z0-9\\.,\\(\\)]+', ' ', a.lower()).split()) +sluggify = lambda a: ' '.join(a.lower().split()) similar = lambda a, b: SequenceMatcher(None, sluggify(a), sluggify(b)).ratio() remove_duplicates = lambda a: list(set(a)) From dc5eb0fe0cfbcf46e0405dc3a06402053fd7deb3 Mon Sep 17 00:00:00 2001 From: daijro Date: Fri, 27 Jan 2023 21:30:46 -0600 Subject: [PATCH 38/39] Add ChatGPT scraper, fix Quizlet Scraper - Use logging library - Fix Quizlet scraper - Add an experimental scraper for ChatGPT through Merlin. - New --chatgpt flag will retrieve the best answer from the flashcard results and an explanation with ChatGPT. No login required! --- merlin.py | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++ scraper.py | 55 ++++++++++++++++++++++------ 2 files changed, 149 insertions(+), 10 deletions(-) create mode 100644 merlin.py diff --git a/merlin.py b/merlin.py new file mode 100644 index 0000000..db60f58 --- /dev/null +++ b/merlin.py @@ -0,0 +1,104 @@ +import requests +import re +import json +import os +from random import randint +import logging +from queue import Queue + +# logging +logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s', datefmt='%H:%M:%S') + +# headers +class MerlinScraper: + headers = { + 'authority': 'openai-api-yak3s7dv3a-ue.a.run.app', + 'accept': 'text/event-stream', + 'accept-language': 'en-US,en;q=0.9', + 'cache-control': 'no-cache', + 'dnt': '1', + 'origin': 'https://www.google.com', + 'referer': 'https://www.google.com/', + 'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108"', + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': '"Windows"', + 'sec-fetch-dest': 'empty', + 'sec-fetch-mode': 'cors', + 'sec-fetch-site': 'cross-site', + 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36', + } + + def __init__(self): + self.setAccount() + + def setAccount(self): + # make account + if os.path.exists('merlin_id.bin'): + with open('merlin_id.bin', 'r') as f: + self.userid = f.read().strip() + logging.debug(f'Account loaded from merin_id.bin: {self.userid}') + else: + self.userid = self.generateAccount() + + def generateAccount(self): # sourcery skip: raise-specific-error + logging.info('Generating Merlin account...') + url = "https://us-central1-foyer-work.cloudfunctions.net:443/createMerlinFreeUser" + acc_headers = { + **self.headers, + "content-type": "text/plain;charset=UTF-8", + "accept": "*/*", + "origin": "chrome-extension://camppjleccjaphfdbohjdohecfnoikec", + "connection": "close" + } + userid = ''.join([hex(randint(0, 16))[-1] for _ in range(60)]) + payload = {"segmentation": "OPENAI_CHATGPT_VERSION", "userid": userid} + r = requests.post(url, headers=acc_headers, json=payload) + if r.status_code != 200: + logging.critical('Error making account.') + raise Exception(r.text) + else: + logging.info(f'Account created: {userid}') + with open('merlin_id.bin', 'w') as f: + f.write(userid) + return userid + + def prompt(self, prompt, queue: Queue=None): + assert self.userid is not None + r = requests.get( + "https://openai-api-yak3s7dv3a-ue.a.run.app/", + headers=self.headers, + params={ + 'q': prompt.strip(), + 'userid': self.userid, + 'segmentation': 'OPENAI_CHATGPT_VERSION' + }, + stream=True + ) + all_text = '' + for chunk in r.iter_content(chunk_size=1024): + resp = re.search('{.*}', chunk.decode()) + if not resp: + continue + try: + data = json.loads(resp[0]) + except json.decoder.JSONDecodeError: + logging.critical(f'Error decoding JSON:\n{resp[0]}') + continue + if 'choices' not in data: + continue + if 'text' not in data['choices'][0]: + continue + text = data['choices'][0]['text'] + if not all_text: + text = text.lstrip() + queue and queue.put(text) + print(text, end='') + all_text += text + queue and queue.put(None) + print('') + return all_text + + +if __name__ == "__main__": + chatgpt = MerlinScraper() + chatgpt.prompt('Hello, how are you?') \ No newline at end of file diff --git a/scraper.py b/scraper.py index 43d47b3..c23be00 100644 --- a/scraper.py +++ b/scraper.py @@ -11,6 +11,10 @@ from random import choice from urllib.parse import urlencode from threading import Thread +from merlin import MerlinScraper +import logging + +logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s', datefmt='%H:%M:%S') headers = { "Sec-Ch-Ua": "\"(Not(A:Brand\";v=\"8\", \"Chromium\";v=\"99\"", @@ -97,7 +101,7 @@ def __init__(self, engine_name): self.sess = HTMLSession() self.engine_name = engine_name self.sess.headers.update({**headers, "Sec-Fetch-Site": "same-origin", 'Referer': _web_engines[self.engine_name]['domain']}) - print('Starting instance...') + logging.info('Starting instance...') self.t = Thread(target=self._init_search) self.t.daemon = True self.t.start() @@ -165,7 +169,7 @@ def __init__(self, query, sites, engine): self.sites = sites self.engine = engine self._regex_objs = { - 'quizlet': re.compile('https?://quizlet.com/\d+/[a-z0-9\\-]+/'), + 'quizlet': re.compile('https?://quizlet.com/\d+/[a-z\d\\-]+/'), 'quizizz': re.compile('https?://quizizz.com/admin/quiz/[a-f0-9]+/[a-z\\-]+'), } @@ -198,7 +202,7 @@ def parse_links(self): try: self.quizizzs.append(self.quizizz_parser(resp)) except Exception as e: - print('exception', e, resp.url) + logging.info(f'Quizizz exception: {e} {resp.url}') return self.quizizzs @@ -247,7 +251,7 @@ def __init__(self, links, query): self.resps = None self.quizlets = [] self.query = query - self._regex_obj = re.compile('\\= (\\{"alphabeticalIsDifferent.*\\}); QLoad\\(') + self._regex_obj = re.compile(r'(\\?)"termIdToTermsMap\\?":({.*}),\\?"termSort\\?"') def async_requests(self, links): reqs = [grequests.get(u, headers=_make_headers()) for u in links] @@ -259,13 +263,16 @@ def parse_links(self): try: self.quizlets.append(self.quizlet_parser(resp)) except Exception as e: - print('exception', e, resp.url) - # pass # skip over any errors + logging.info(f'Quizlet exception: {e} {resp.url}') return self.quizlets def quizlet_parser(self, resp): - data = json.loads(re.search(self._regex_obj, resp.text)[1]) # get quizlet headerData + terms_match = re.search(self._regex_obj, resp.text) + if terms_match[1]: # needs to be unescaped + data = json.loads(terms_match[2].encode('utf-8').decode('unicode_escape')) + else: + data = json.loads(terms_match[2]) return max( ( { @@ -278,7 +285,7 @@ def quizlet_parser(self, resp): ), 'url': resp.url, } - for i in data['termIdToTermsMap'].values() + for i in data.values() ), key=lambda x: x['similarity'], ) @@ -351,7 +358,7 @@ def main(self): for n, T in enumerate(threads): T.join() - print(f'Thread {n} finished') + logging.info(f'Thread {n} finished') self.sort_flashcards() self.stop_time = time.time() - self.timer.elapsed_total @@ -390,6 +397,7 @@ def sort_flashcards(self): # sourcery skip: for-index-replacement parser.add_argument('--output', '-o', help='output file', default=None) parser.add_argument('--sites', '-s', help='question sources quizlet,quizizz (comma seperated list)', default='quizlet,quizizz') parser.add_argument('--engine', '-e', help='search engine to use', default='bing', choices=_web_engines.keys()) + parser.add_argument('--chatgpt', '-gpt', help='summarize the results in ChatGPT (expiremental)', action='store_true') args = parser.parse_args() if args.output: @@ -422,4 +430,31 @@ def sort_flashcards(self): # sourcery skip: for-index-replacement write(json.dumps(s.flashcards, indent=4)) print(f'{len(s.flashcards)} flashcards found') - s.timer.print_timers() \ No newline at end of file + s.timer.print_timers() + + # get best answer with chatgpt + if args.chatgpt: + print('\n--------------------\nCHATGPT SUMMARIZATION:') + chatgpt = MerlinScraper() + print('') # newline + chatgpt.prompt(f""" +Instuctions: You are now FlashcardGPT. A student queries a quiz question into the web search. Using the provided data from FlashcardSearch, which flashcard most likely answers to the student's query? Return the most frequent and similar answer. + +Start with "Best Answer:", and explain the question and how the answer is correct. Example: +Best Answer: X +Explanation: ... + +Query: "{args.query}" + +Data collected from FlashcardSearch, a web scraper that searches the internet for flashcards: +{ + json.dumps([ + { + 'question': card['question'], + 'answer': card['answer'], + 'similarity': card['similarity'], + } + for card in s.flashcards + ], indent=4) +} +""") \ No newline at end of file From 778b6e0e59bd9f067bc506226e3f8b1ed28f612d Mon Sep 17 00:00:00 2001 From: Jose <48543854+LavamasterYT@users.noreply.github.com> Date: Fri, 17 Nov 2023 12:51:08 -0600 Subject: [PATCH 39/39] Removed obsolete jaro_distance function --- scraper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scraper.py b/scraper.py index ef2fe4a..3cf0629 100644 --- a/scraper.py +++ b/scraper.py @@ -15,7 +15,7 @@ import orjson import regex from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning -from jellyfish import jaro_distance as similar +from jellyfish import jaro_similarity as similar # set logger logger = logging.getLogger(__name__)