From 3082faaadc8196ef9b5a3dc2a33a13f96db738af Mon Sep 17 00:00:00 2001 From: putyy Date: Mon, 19 Feb 2024 15:27:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BB=A3=E7=90=86=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E3=80=81=E6=9B=B4=E6=8D=A2=E8=AF=81=E4=B9=A6=E3=80=81?= =?UTF-8?q?mac=E4=B8=8B=E5=A2=9E=E5=8A=A0http=E7=9A=84=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E3=80=81=E5=AE=8C=E5=96=84image=20content-ty?= =?UTF-8?q?pe=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + README.md | 16 +- components.d.ts | 1 + electron/main/const.ts | 3 +- electron/main/index.ts | 5 - electron/main/ipc.ts | 69 +--- electron/main/proxyServer.ts | 295 ++++++++-------- electron/main/setProxy.ts | 16 +- electron/main/utils.ts | 30 +- electron/res/keys/private.key | 55 +-- electron/res/keys/private.pem | 55 +-- electron/res/keys/public.crt | 40 ++- electron/res/keys/public.pem | 40 ++- override/hoxy/lib/cycle.js | 616 ++++++++++++++++++++++++++++++++++ package.json | 5 +- public/show.jpg | Bin 31192 -> 0 bytes public/show.webp | Bin 0 -> 23586 bytes src/views/About.vue | 4 + src/views/Index.vue | 77 ++--- src/views/Setting.vue | 18 +- 20 files changed, 1000 insertions(+), 347 deletions(-) create mode 100644 override/hoxy/lib/cycle.js delete mode 100644 public/show.jpg create mode 100644 public/show.webp diff --git a/.gitignore b/.gitignore index 7166e88..6e5ada7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ lerna-debug.log* node_modules dist temp +test dist-ssr dist-electron release @@ -28,4 +29,5 @@ release # lockfile package-lock.json +yarn.lock pnpm-lock.yaml \ No newline at end of file diff --git a/README.md b/README.md index 8f9ba9e..cd67baa 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,9 @@ 🎯 基于 [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue.git) 📦 操作简单、可获取不同类型的资源 -💪 支持获取视频、音频、图片、m3u8 -🖥 支持获取视频号、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源 +💪 支持获取视频、音频、图片、m3u8 +🖥 支持获取视频号、抖音、快手、小红书、酷狗音乐、qq音乐、微信小程序等网络资源 +🍊 支持设置代理以获取特殊网络下的资源 ## 软件下载 🆕 [github下载](https://github.com/putyy/res-downloader/releases) @@ -28,9 +29,6 @@ yarn run build --mac yarn run build --win ``` -## 软件截图 -![](public/show.jpg) - ## 使用方法 > 1. 打开本软件 > 2. 软件首页选择要获取的资源类型(默认选中的视频) @@ -42,6 +40,13 @@ yarn run build --win > > 手动检测系统代理是否设置正确 本软件代理地址: 127.0.0.1:8899 > 2. 关闭软件后无法正常上网 > > 手动关闭系统代理设置 +> 3. 视频号抓取流程 +> > 将需要下载的视频发给好友或者文件助手 再打开即可拦截,通常会出现解密下载按钮 +> > +> > 大视频可以复制链接通过其他工具加速下载,然后再通过对应的视频操作项进行"视频解密" + +## 软件截图 +![](public/show.webp) ## 实现原理 > 通过代理网络抓包拦截响应,筛选出有用的资源,同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的,只不过这些软件需要手动进行筛选,对于小白用户上手还是有点难度,所以就有了本项目这样的软件。 @@ -49,3 +54,4 @@ yarn run build --win ## 参考项目 - [WeChatVideoDownloader](https://github.com/lecepin/WeChatVideoDownloader) 原项目是react写的,本项目参考原项目用vue3重写了一下,核心逻辑没什么变化,主要是增加了一些新的功能,再次感谢! + diff --git a/components.d.ts b/components.d.ts index e62d0ea..13d3cfb 100755 --- a/components.d.ts +++ b/components.d.ts @@ -14,6 +14,7 @@ declare module 'vue' { ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElHeader: typeof import('element-plus/es')['ElHeader'] ElIcon: typeof import('element-plus/es')['ElIcon'] + ElInput: typeof import('element-plus/es')['ElInput'] ElMain: typeof import('element-plus/es')['ElMain'] ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] diff --git a/electron/main/const.ts b/electron/main/const.ts index ecb586d..c79ec21 100755 --- a/electron/main/const.ts +++ b/electron/main/const.ts @@ -13,14 +13,13 @@ const EXECUTABLE_PATH = path.join( ) const HOME_PATH = path.join(os.homedir(), '.res-downloader@putyy') - export default { IS_DEV: isDev, EXECUTABLE_PATH, HOME_PATH, CERT_PRIVATE_PATH: path.join(EXECUTABLE_PATH, './keys/private.pem'), CERT_PUBLIC_PATH: path.join(EXECUTABLE_PATH, './keys/public.pem'), - INSTALL_CERT_FLAG: path.join(HOME_PATH, './installed.lock'), + INSTALL_CERT_FLAG: path.join(HOME_PATH, './res-downloader-installed.lock'), WIN_CERT_INSTALL_HELPER: path.join(EXECUTABLE_PATH, './w_c.exe'), APP_CN_NAME: '爱享素材下载器', APP_EN_NAME: 'ResDownloader', diff --git a/electron/main/index.ts b/electron/main/index.ts index 6a3dbac..89191b0 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -156,11 +156,6 @@ function createPreviewWindow(parent: BrowserWindow) { // previewWin.hide() previewWin.setTitle("预览") - previewWin.webContents.session.on('will-download', (event, item, webContents) => { - // console.log("取消下载") - item.cancel() - }) - previewWin.on("page-title-updated", (event) => { // 阻止该事件 event.preventDefault() diff --git a/electron/main/ipc.ts b/electron/main/ipc.ts index 84c8d3b..53a422a 100755 --- a/electron/main/ipc.ts +++ b/electron/main/ipc.ts @@ -1,42 +1,20 @@ import {ipcMain, dialog, BrowserWindow, app, shell} from 'electron' import {startServer} from './proxyServer' import {installCert, checkCertInstalled} from './cert' -import {downloadFile, decodeWxFile} from './utils' +import {downloadFile, decodeWxFile, suffix} from './utils' // @ts-ignore import {hexMD5} from '../../src/common/md5' import fs from "fs" import CryptoJS from 'crypto-js' -import {closeProxy, setProxy} from "./setProxy" -import log from "electron-log" -import {floor} from "lodash"; +import {floor} from "lodash" let getMac = require("getmac").default let win: BrowserWindow let previewWin: BrowserWindow let isStartProxy = false -let isOpenProxy = false let aesKey = "as5d45as4d6qe6wqfar6gt4749q6y7w6h34v64tv7t37ty5qwtv6t6qv" -const suffix = (type: string) => { - switch (type) { - case "video/mp4": - return ".mp4"; - case "image/png": - return ".png"; - case "image/webp": - return ".webp"; - case "image/svg+xml": - return ".svg"; - case "image/gif": - return ".gif"; - case "audio/mpeg": - return ".mp3"; - case "application/vnd.apple.mpegurl": - return ".m3u8"; - } -} - export default function initIPC() { ipcMain.handle('invoke_app_is_init', async (event, arg) => { @@ -44,47 +22,26 @@ export default function initIPC() { return checkCertInstalled() }) - ipcMain.handle('invoke_init_app', (event, arg) => { + ipcMain.handle('invoke_init_app', (event, arg) => { // 开始 初始化应用 安装证书相关 - // console.log('invoke_init_app') - return installCert(false) + installCert(false).then(r => {}) }) - ipcMain.handle('invoke_start_proxy', async (event, arg) => { + ipcMain.handle('invoke_start_proxy', (event, arg) => { // 启动代理服务 if (isStartProxy) { - if (isOpenProxy === false) { - isOpenProxy = true - setProxy('127.0.0.1', 8899) - .then(() => { - }) - .catch((err) => { - }) - } return } isStartProxy = true - isOpenProxy = true return startServer({ win: win, + upstreamProxy: arg.upstream_proxy ? arg.upstream_proxy : "", setProxyErrorCallback: err => { - isStartProxy = false - isOpenProxy = false + }, }) }) - ipcMain.handle('invoke_close_proxy', (event, arg) => { - // 关闭代理 - try { - isOpenProxy = false - return closeProxy() - } catch (error) { - log.log("--------------closeProxy error--------------", error) - } - - }) - ipcMain.handle('invoke_select_down_dir', async (event, arg) => { // 选择下载位置 const result = dialog.showOpenDialogSync({title: '保存', properties: ['openDirectory']}) @@ -123,6 +80,10 @@ export default function initIPC() { let url_sign = hexMD5(down_url) let save_path_file = `${save_path}/${url_sign}` + suffix(data.type) + if (process.platform === 'win32'){ + save_path_file = `${save_path}\\${url_sign}` + suffix(data.type) + } + if (fs.existsSync(save_path_file)) { return {fullFileName: save_path_file, totalLen: ""} } @@ -135,7 +96,6 @@ export default function initIPC() { win?.webContents.send('on_down_file_schedule', {schedule: floor(res * 100)}) } ).catch(err => { - // console.log('invoke_down_file:err', err) return false }) }) @@ -156,6 +116,8 @@ export default function initIPC() { return } + console.log('url', url) + previewWin.loadURL(url).then(r => { return }).catch(res => { @@ -171,6 +133,11 @@ export default function initIPC() { ipcMain.handle('invoke_open_file_dir', (event, {save_path}) => { shell.showItemInFolder(save_path) }) + + ipcMain.handle('invoke_window_restart', (event) => { + app.relaunch() + app.exit() + }) } export function setWin(w, p) { diff --git a/electron/main/proxyServer.ts b/electron/main/proxyServer.ts index b8c090f..31e1882 100755 --- a/electron/main/proxyServer.ts +++ b/electron/main/proxyServer.ts @@ -76,106 +76,128 @@ setTimeout(() => { export async function startServer({ win, + upstreamProxy, setProxyErrorCallback = f => f, }) { return new Promise(async (resolve: any, reject) => { - const proxy = hoXy.createServer({ + try { + const proxy = hoXy.createServer({ + upstreamProxy: upstreamProxy, certAuthority: { key: fs.readFileSync(CONFIG.CERT_PRIVATE_PATH), cert: fs.readFileSync(CONFIG.CERT_PUBLIC_PATH), }, }) - .listen(port, () => { - setProxy('127.0.0.1', port) - .then(() => { - // log.log("--------------setProxy success--------------") - resolve() - }) - .catch((err) => { - // log.log("--------------setProxy error--------------") - // setProxyErrorCallback(data); - setProxyErrorCallback({}); - reject('设置代理失败'); - }); - }) - .on('error', err => { - log.log("--------------proxy err--------------", err) - }); - - - proxy.intercept( - { - phase: 'request', - hostname: 'res-downloader.666666.com', - as: 'json', - }, - (req, res) => { - // console.log('req.json: ', req.json) - res.string = 'ok' - res.statusCode = 200 - let url_sign: string = hexMD5(req.json.url) - let urlInfo = urlTool.parse(req.json.url, true) - win?.webContents?.send?.('on_get_queue', { - url_sign: url_sign, - url: req.json.url, - down_url: req.json.url, - high_url: '', - platform: urlInfo.hostname, - size: toSize(req.json.size ?? 0), - type: "video/mp4", - type_str: 'video', - progress_bar: '', - save_path: '', - downing: false, - decode_key: req.json.decode_key, - description: req.json.description, - uploader: '', + .listen(port, () => { + setProxy('127.0.0.1', port) + .then((res) => { + resolve() + }) + .catch((err) => { + setProxyErrorCallback(err); + reject('setting proxy err: '+ err.toString()); + }); }) - }, - ); + .on('error', err => { + setProxyErrorCallback(err); + reject('proxy service err: ' + err.toString()); + }); - proxy.intercept( - { - phase: 'response', - hostname: 'channels.weixin.qq.com', - as: 'string', - }, - async (req, res) => { - // console.log('inject[channels.weixin.qq.com] req.url:', req.url); - if (req.url.includes('/web/pages/feed') || req.url.includes('/web/pages/home')) { - res.string = res.string.replace('', '\n\n'); - res.statusCode = 200; - // console.log('inject[channels.weixin.qq.com]:', req.url, res.string.length); - } - }, - ); - proxy.intercept( - { - phase: 'response', - }, - async (req, res) => { - // 拦截响应 - let ctype = res?._data?.headers?.['content-type'] - let url_sign: string = hexMD5(req.fullUrl()) - let res_url = req.fullUrl() - let urlInfo = urlTool.parse(res_url, true) - switch (ctype) { - case "video/mp4": - if (videoList.hasOwnProperty(url_sign) === false) { - videoList[url_sign] = req.fullUrl() - let high_url = '' - let down_url = res_url - // console.log('down_url', down_url) + proxy.intercept( + { + phase: 'request', + hostname: 'res-downloader.666666.com', + as: 'json', + }, + (req, res) => { + res.string = 'ok' + res.statusCode = 200 + let url_sign: string = hexMD5(req.json.url) + let urlInfo = urlTool.parse(req.json.url, true) + win?.webContents?.send?.('on_get_queue', { + url_sign: url_sign, + url: req.json.url, + down_url: req.json.url, + high_url: '', + platform: urlInfo.hostname, + size: toSize(req.json.size ?? 0), + type: "video/mp4", + type_str: 'video', + progress_bar: '', + save_path: '', + downing: false, + decode_key: req.json.decode_key, + description: req.json.description, + uploader: '', + }) + }, + ); + + proxy.intercept( + { + phase: 'response', + hostname: 'channels.weixin.qq.com', + as: 'string', + }, + async (req, res) => { + if (req.url.includes('/web/pages/feed') || req.url.includes('/web/pages/home')) { + res.string = res.string.replace('', '\n\n'); + res.statusCode = 200; + } + }, + ); + + proxy.intercept( + { + phase: 'response', + }, + async (req, res) => { + // 拦截响应 + let ctype = res?._data?.headers?.['content-type'] + let url_sign: string = hexMD5(req.fullUrl()) + let res_url = req.fullUrl() + let urlInfo = urlTool.parse(res_url, true) + switch (ctype) { + case "video/mp4": + if (videoList.hasOwnProperty(url_sign) === false) { + videoList[url_sign] = req.fullUrl() + let high_url = '' + let down_url = res_url + win?.webContents?.send?.('on_get_queue', { + url_sign: url_sign, + url: down_url, + down_url: down_url, + high_url: high_url, + platform: urlInfo.hostname, + size: toSize(res?._data?.headers?.['content-length'] ?? 0), + type: ctype, + type_str: 'video', + progress_bar: '', + save_path: '', + downing: false, + decode_key: '', + description: '', + uploader: '', + }) + } + break; + case "image/png": + case "image/webp": + case "image/jpeg": + case "image/jpg": + case "image/svg+xml": + case "image/gif": + case "image/avif": win?.webContents?.send?.('on_get_queue', { url_sign: url_sign, - url: down_url, - down_url: down_url, - high_url: high_url, + url: res_url, + down_url: res_url, + high_url: '', platform: urlInfo.hostname, size: toSize(res?._data?.headers?.['content-length'] ?? 0), type: ctype, - type_str: 'video', + type_str: 'image', progress_bar: '', save_path: '', downing: false, @@ -183,70 +205,51 @@ export async function startServer({ description: '', uploader: '', }) - } - break; - case "image/png": - case "image/webp": - case "image/svg+xml": - case "image/gif": - win?.webContents?.send?.('on_get_queue', { - url_sign: url_sign, - url: res_url, - down_url: res_url, - high_url: '', - platform: urlInfo.hostname, - size: toSize(res?._data?.headers?.['content-length'] ?? 0), - type: ctype, - type_str: 'image', - progress_bar: '', - save_path: '', - downing: false, - decode_key: '', - description: '', - uploader: '', - }) - break; - case "audio/mpeg": - win?.webContents?.send?.('on_get_queue', { - url_sign: url_sign, - url: res_url, - down_url: res_url, - high_url: '', - platform: urlInfo.hostname, - size: toSize(res?._data?.headers?.['content-length'] ?? 0), - type: ctype, - type_str: 'audio', - progress_bar: '', - save_path: '', - downing: false, - decode_key: '', - description: '', - uploader: '', - }) - break; - case "application/vnd.apple.mpegurl": - win.webContents?.send?.('on_get_queue', { - url_sign: url_sign, - url: res_url, - down_url: res_url, - high_url: '', - platform: urlInfo.hostname, - size: toSize(res?._data?.headers?.['content-length'] ?? 0), - type: ctype, - type_str: 'm3u8', - progress_bar: '', - save_path: '', - downing: false, - decode_key: '', - description: '', - uploader: '', - }) - break; + break; + case "audio/mpeg": + win?.webContents?.send?.('on_get_queue', { + url_sign: url_sign, + url: res_url, + down_url: res_url, + high_url: '', + platform: urlInfo.hostname, + size: toSize(res?._data?.headers?.['content-length'] ?? 0), + type: ctype, + type_str: 'audio', + progress_bar: '', + save_path: '', + downing: false, + decode_key: '', + description: '', + uploader: '', + }) + break; + case "application/vnd.apple.mpegurl": + win.webContents?.send?.('on_get_queue', { + url_sign: url_sign, + url: res_url, + down_url: res_url, + high_url: '', + platform: urlInfo.hostname, + size: toSize(res?._data?.headers?.['content-length'] ?? 0), + type: ctype, + type_str: 'm3u8', + progress_bar: '', + save_path: '', + downing: false, + decode_key: '', + description: '', + uploader: '', + }) + break; - } + } - }, - ) + }, + ) + } catch (e) { + log.log("--------------proxy catch err--------------", e) + } }) } diff --git a/electron/main/setProxy.ts b/electron/main/setProxy.ts index a5d6903..dbc9503 100755 --- a/electron/main/setProxy.ts +++ b/electron/main/setProxy.ts @@ -22,7 +22,13 @@ export async function setProxy(host, port) { if (error) { reject(null) } else { - resolve(network) + exec(`networksetup -setwebproxy "${network}" ${host} ${port}`, error => { + if (error) { + reject(null) + } else { + resolve(network) + } + }); } }); }); @@ -63,7 +69,13 @@ export async function closeProxy() { if (error) { reject(null) } else { - resolve(network) + exec(`networksetup -setwebproxystate "${network}" off`, error => { + if (error) { + reject(null) + } else { + resolve(network) + } + }); } }); }); diff --git a/electron/main/utils.ts b/electron/main/utils.ts index f80938c..9e0dfbc 100755 --- a/electron/main/utils.ts +++ b/electron/main/utils.ts @@ -1,6 +1,6 @@ import fs from 'fs' import {Transform } from 'stream' -import {getDecryptionArray} from '../wxjs/decrypt' +import {getDecryptionArray} from '../wxjs/decrypt.js' const axios = require('axios') function xorTransform(decryptionArray) { @@ -92,4 +92,30 @@ function toSize(size: number) { return size + 'b' } -export {downloadFile, toSize, decodeWxFile} +function suffix(type: string) { + switch (type) { + case "video/mp4": + return ".mp4"; + case "image/png": + return ".png"; + case "image/webp": + return ".webp"; + case "image/svg+xml": + return ".svg"; + case "image/gif": + return ".gif"; + case "audio/mpeg": + return ".mp3"; + case "application/vnd.apple.mpegurl": + return ".m3u8"; + case "image/jpeg": + return ".jpeg"; + case "image/jpg": + return ".jpg"; + case "image/avif": + return ".avif"; + } + return "" +} + +export {downloadFile, toSize, decodeWxFile, suffix} diff --git a/electron/res/keys/private.key b/electron/res/keys/private.key index 8b994f1..25be5e3 100755 --- a/electron/res/keys/private.key +++ b/electron/res/keys/private.key @@ -1,27 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAsmAqn3hYd/YZcrfgqM1Q6xgHI50EBckbOkfCqTWS1yVFZjLF -bMehWb9xGFZJD21A5sxl4xelIWblhety+YTVa/mn2CEJh3je069oeULfXdzhhHyf -/ci0IloJhvX+2RJ+176uTKKcWhuOtNVs5VeFoHDoUcISnTqkaVyWeeLfafgrOW7w -N8ip128nuBx19ylIygb/DELmjKRRCSpx2vOw2JErTM8L5r0f4eWdqiwBOwu0NHWy -Svh9YG8B31UPga4I8FbFhybOP9cQNQPafOSfjwuZoi5CAtyJbwT7KyII9iMD74bZ -1mTx2xokmQ2TeiCSKSF8Mx9/8Gq+95mzvvIbRwIDAQABAoIBAHNt++caj9WBclJk -X4Oc6eJYuDX5o+LCk1YRngy12IJVYiWScWPFg8p6MouXOsw63Sb92mksofWNirYw -+UQzC5FGC7G3H12FgFzoQ+lEtxscluuPYlFukfMw5L1rbzG14FNo145MJHXDI4Qu -ILwA+T4sEorl1fndOwvbmJzjjcQaeRNz7/R9e6QTOlZ2+IEMKnHSBXXGJbDj6mPN -+f1/ec6nVENdxazgRCi0xfinyft4Ipst93Eb+wGcpk+J43aF+0leWQCdl6Y9U1Lz -zpv5H5XOQdwpX+dpuioRp73zwPwIialq+hTUN28Bn9U1jW2tjxUl/vgIpjy1s94a -UipRwSECgYEA57vYB+wGnxQxY9IPpr9H/y3HciIwCnuOEsWBzjYe8sIqBif2tEpO -OgDZZMQY7+JJrDQbDRs442TuRjKhJ5hiW+MyoiFWaYkBBoNVM8RBTkIjHfrh+uB2 -XT15FbEyyxo3n9QY610ZJFRnW4Uf5V0osjOqqUgQRrVXvamk6NQH6FkCgYEAxQ3v -jFYPL3EkZe1br6X0RM42ykGv5Di5Q6NnjpSPcyn9a2obA1cZuCd5S1lhrkuZGsdI -iFapeL+7vpts9gu9/ii9y+CgEKplOMmm0ZrChBKAcXMZvdDKV3y5SmTMZPas4X5i -hqNqatx9/J93sMYWc0CuoosDEJYKtSz8GE+1rJ8CgYAmp5rdl21zU7b5Y6zgr7+e -vVArpbBFz15fmzqP309CR0kjRb9NS6fI3SNmP5+5RBHt+7MXeJcAt3FXnFJtfGnL -0hY8HTuA1y2onHe17uLF3xpkgdj4NEEKRJrSF4DViEYHDyYo/JqZCMtE5OvxIp0L -PLsXCcJNSSqdpJKxk8zN4QKBgEuoxSAh7uStUWddUkXHt1kvwDO6MtmyuddxhxJk -kguKxMWYUNTgfXyKk3TN1caBOkDg4UWP2LQHEgPmU1jJO2K5q9362hpsAj9ilY2H -GUZygCSPKAQMhZQ/zDj3KM9fMxPFXfkKB5MOI8V6SQ9zjy0jWaoJK90TbvsPUZ/Y -Aw5LAoGADifZwCHPiXhTfJjOom2uBgXmL03yTXcCw4EDIX3ZR0sP6ACPQq4T4jxZ -UJLXLjOb2pzCq0c5+k0cG6ahYINq4tGOo+vQ9fDvhKg0nlf1FrzxSd7S12o+un2q -+U+dBllYIDlRMgMhXu9CxFDjUsCwPRmsBvmVZiH4XSs6QVnfn90= ------END RSA PRIVATE KEY----- \ No newline at end of file +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcDt23t6ioBoHG +/Y2mOjxntWQa9dP3eNl+mAC6425DlEtyc6czNAIKuuM9wt+wAwDQAgrd5RaxdcpJ +H1JlMkEtBFkIkdn0Ag98D7nwlVA9ON3xQi5Bkl+sN/oWOE8lOwvNyNNT6ZPu3qUS +KY8SXZVY315daqz2eRWsm2otqjqbWGhh9c7FGHr3r9aAG08dyaO6OvK14GJIhNV+ +UOPH5hDMMaxurDt8znaSUw93b7D++aEninGro/s2LY4G91dgM8i4t88UWobXpqs5 +GMGTI0InLX2I66HkteH4RRfXXC9svA2CxN3yP294FIP7gdRQ1CGJeJcluzsjtx0V +i2G9vrT1AgMBAAECggEAF0obfQ4a82183qqHC0iui+tOpOvPeyl3G0bLDPx09wIC +2iITV//xF2GgGzE8q0wmEd2leMZ+GFn3BrYh6kPfUfxbz+RfxMtTCDZB34xt6YzT +MG1op9ft+DQUa7WZ6r7NCQJwGzllRqqZncp4MeFlpPo+6nQXyh4WhSYNnredbENE +uPZ63Kme4RZfMvtVso+XgAQM3oDih0onv1YitmNQpL9rRzlthTfybAT4737DBINq +zsmBNE6QIsXnSKpzo11OtDgof2QM9ac6eAXf73oTpDxfodwCotILytKn+8WYvlR+ +T15uuknb4M3XI1FPVolkF4qtK5SLAAbVzV4DsCmuIQKBgQD6bTKKbL2huvU6dEKx +bgS079LfQUxxOTClgwkhVsMxRtvcPBnHYMAsPK4mnMhEh9x+TF6wxMx0pmhQluPI +ZULNBj/qdoiBL0RwVLA+9jgE0NeWB3XXFDsEavQBr9Q8CC0uzrsgsxFcvHpqqs2Q +RtngxRWtJP06D6mKC23s4YjDHwKBgQDg9KUCFqOmWcRXyeg9gYMC4jFFQw4lUQBd +sYpqSMHDw1b+T1W/dCPbwbxZL/+d8y930BYy9QYDtQwHdLyXCH0pHM7S6rfgr5xk +2Szd8xBUIqmeV/zcR00mTeQHJ1M50VHfclAVgZgkpWSoLwbX+bXyx/mfqLAtynZ5 +yU9RfrT5awKBgQC0uJ8TlFvZXjFgyMvkfY/5/2R/ZwFCaFI573FkVNeyNP+vVNQJ +tUGZ6wSGqvg/tIgjwPtIuA0QVZLMLcgeMy1dBhiUHIxwJetO4V77YPaWSxx5kdKx +r1DT5FdI7FnOJNxufhQ/CdsKwJ3bYn3Mk8TiV3hIJnx0LR9dltfybeQjYwKBgDOY +6aApATBOtrJMJXC2HA61QwfX8Y6tnZ/f8RefyJHWZEXAfLKFORRWw5TRZZgdB247 +1Furx81h4Xh0Vi1uTQb5DJdkLvjiTsTy60+dSMmDidQ/6ke8Mv3uL7dUVcqVMGpI +FgZYy0TcitHot3EiXZFqPN9aGc7m+XXFruPKZEgxAoGBAMA96jsow7CzulU+GRW8 +Njg4zWuAEVErgPoNBcOXAVWLCTU/qGIEMNpZL6Ok34kf13pJDMjQ8eDuQHu5CSqf +0ul5Zy85fwfVq2IvNAyYT8eflQprTejFw22CHhfPBfADVW9ro8dK/Jw+J/31Vh7V +ILKEQKmPPzKs7kp/7Nz+2cT3 +-----END PRIVATE KEY----- diff --git a/electron/res/keys/private.pem b/electron/res/keys/private.pem index 8b994f1..25be5e3 100755 --- a/electron/res/keys/private.pem +++ b/electron/res/keys/private.pem @@ -1,27 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAsmAqn3hYd/YZcrfgqM1Q6xgHI50EBckbOkfCqTWS1yVFZjLF -bMehWb9xGFZJD21A5sxl4xelIWblhety+YTVa/mn2CEJh3je069oeULfXdzhhHyf -/ci0IloJhvX+2RJ+176uTKKcWhuOtNVs5VeFoHDoUcISnTqkaVyWeeLfafgrOW7w -N8ip128nuBx19ylIygb/DELmjKRRCSpx2vOw2JErTM8L5r0f4eWdqiwBOwu0NHWy -Svh9YG8B31UPga4I8FbFhybOP9cQNQPafOSfjwuZoi5CAtyJbwT7KyII9iMD74bZ -1mTx2xokmQ2TeiCSKSF8Mx9/8Gq+95mzvvIbRwIDAQABAoIBAHNt++caj9WBclJk -X4Oc6eJYuDX5o+LCk1YRngy12IJVYiWScWPFg8p6MouXOsw63Sb92mksofWNirYw -+UQzC5FGC7G3H12FgFzoQ+lEtxscluuPYlFukfMw5L1rbzG14FNo145MJHXDI4Qu -ILwA+T4sEorl1fndOwvbmJzjjcQaeRNz7/R9e6QTOlZ2+IEMKnHSBXXGJbDj6mPN -+f1/ec6nVENdxazgRCi0xfinyft4Ipst93Eb+wGcpk+J43aF+0leWQCdl6Y9U1Lz -zpv5H5XOQdwpX+dpuioRp73zwPwIialq+hTUN28Bn9U1jW2tjxUl/vgIpjy1s94a -UipRwSECgYEA57vYB+wGnxQxY9IPpr9H/y3HciIwCnuOEsWBzjYe8sIqBif2tEpO -OgDZZMQY7+JJrDQbDRs442TuRjKhJ5hiW+MyoiFWaYkBBoNVM8RBTkIjHfrh+uB2 -XT15FbEyyxo3n9QY610ZJFRnW4Uf5V0osjOqqUgQRrVXvamk6NQH6FkCgYEAxQ3v -jFYPL3EkZe1br6X0RM42ykGv5Di5Q6NnjpSPcyn9a2obA1cZuCd5S1lhrkuZGsdI -iFapeL+7vpts9gu9/ii9y+CgEKplOMmm0ZrChBKAcXMZvdDKV3y5SmTMZPas4X5i -hqNqatx9/J93sMYWc0CuoosDEJYKtSz8GE+1rJ8CgYAmp5rdl21zU7b5Y6zgr7+e -vVArpbBFz15fmzqP309CR0kjRb9NS6fI3SNmP5+5RBHt+7MXeJcAt3FXnFJtfGnL -0hY8HTuA1y2onHe17uLF3xpkgdj4NEEKRJrSF4DViEYHDyYo/JqZCMtE5OvxIp0L -PLsXCcJNSSqdpJKxk8zN4QKBgEuoxSAh7uStUWddUkXHt1kvwDO6MtmyuddxhxJk -kguKxMWYUNTgfXyKk3TN1caBOkDg4UWP2LQHEgPmU1jJO2K5q9362hpsAj9ilY2H -GUZygCSPKAQMhZQ/zDj3KM9fMxPFXfkKB5MOI8V6SQ9zjy0jWaoJK90TbvsPUZ/Y -Aw5LAoGADifZwCHPiXhTfJjOom2uBgXmL03yTXcCw4EDIX3ZR0sP6ACPQq4T4jxZ -UJLXLjOb2pzCq0c5+k0cG6ahYINq4tGOo+vQ9fDvhKg0nlf1FrzxSd7S12o+un2q -+U+dBllYIDlRMgMhXu9CxFDjUsCwPRmsBvmVZiH4XSs6QVnfn90= ------END RSA PRIVATE KEY----- \ No newline at end of file +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcDt23t6ioBoHG +/Y2mOjxntWQa9dP3eNl+mAC6425DlEtyc6czNAIKuuM9wt+wAwDQAgrd5RaxdcpJ +H1JlMkEtBFkIkdn0Ag98D7nwlVA9ON3xQi5Bkl+sN/oWOE8lOwvNyNNT6ZPu3qUS +KY8SXZVY315daqz2eRWsm2otqjqbWGhh9c7FGHr3r9aAG08dyaO6OvK14GJIhNV+ +UOPH5hDMMaxurDt8znaSUw93b7D++aEninGro/s2LY4G91dgM8i4t88UWobXpqs5 +GMGTI0InLX2I66HkteH4RRfXXC9svA2CxN3yP294FIP7gdRQ1CGJeJcluzsjtx0V +i2G9vrT1AgMBAAECggEAF0obfQ4a82183qqHC0iui+tOpOvPeyl3G0bLDPx09wIC +2iITV//xF2GgGzE8q0wmEd2leMZ+GFn3BrYh6kPfUfxbz+RfxMtTCDZB34xt6YzT +MG1op9ft+DQUa7WZ6r7NCQJwGzllRqqZncp4MeFlpPo+6nQXyh4WhSYNnredbENE +uPZ63Kme4RZfMvtVso+XgAQM3oDih0onv1YitmNQpL9rRzlthTfybAT4737DBINq +zsmBNE6QIsXnSKpzo11OtDgof2QM9ac6eAXf73oTpDxfodwCotILytKn+8WYvlR+ +T15uuknb4M3XI1FPVolkF4qtK5SLAAbVzV4DsCmuIQKBgQD6bTKKbL2huvU6dEKx +bgS079LfQUxxOTClgwkhVsMxRtvcPBnHYMAsPK4mnMhEh9x+TF6wxMx0pmhQluPI +ZULNBj/qdoiBL0RwVLA+9jgE0NeWB3XXFDsEavQBr9Q8CC0uzrsgsxFcvHpqqs2Q +RtngxRWtJP06D6mKC23s4YjDHwKBgQDg9KUCFqOmWcRXyeg9gYMC4jFFQw4lUQBd +sYpqSMHDw1b+T1W/dCPbwbxZL/+d8y930BYy9QYDtQwHdLyXCH0pHM7S6rfgr5xk +2Szd8xBUIqmeV/zcR00mTeQHJ1M50VHfclAVgZgkpWSoLwbX+bXyx/mfqLAtynZ5 +yU9RfrT5awKBgQC0uJ8TlFvZXjFgyMvkfY/5/2R/ZwFCaFI573FkVNeyNP+vVNQJ +tUGZ6wSGqvg/tIgjwPtIuA0QVZLMLcgeMy1dBhiUHIxwJetO4V77YPaWSxx5kdKx +r1DT5FdI7FnOJNxufhQ/CdsKwJ3bYn3Mk8TiV3hIJnx0LR9dltfybeQjYwKBgDOY +6aApATBOtrJMJXC2HA61QwfX8Y6tnZ/f8RefyJHWZEXAfLKFORRWw5TRZZgdB247 +1Furx81h4Xh0Vi1uTQb5DJdkLvjiTsTy60+dSMmDidQ/6ke8Mv3uL7dUVcqVMGpI +FgZYy0TcitHot3EiXZFqPN9aGc7m+XXFruPKZEgxAoGBAMA96jsow7CzulU+GRW8 +Njg4zWuAEVErgPoNBcOXAVWLCTU/qGIEMNpZL6Ok34kf13pJDMjQ8eDuQHu5CSqf +0ul5Zy85fwfVq2IvNAyYT8eflQprTejFw22CHhfPBfADVW9ro8dK/Jw+J/31Vh7V +ILKEQKmPPzKs7kp/7Nz+2cT3 +-----END PRIVATE KEY----- diff --git a/electron/res/keys/public.crt b/electron/res/keys/public.crt index 0735da0..7446031 100755 --- a/electron/res/keys/public.crt +++ b/electron/res/keys/public.crt @@ -1,17 +1,23 @@ ------BEGIN CERTIFICATE----- -MIICuDCCAaACCQC7PQmrxgWOlTANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJs -ZWNlcGluLTIwMjItMDUtMTkwIBcNMjIwNTE5MTI1NjA0WhgPMzAyMTA5MTkxMjU2 -MDRaMB0xGzAZBgNVBAMMEmxlY2VwaW4tMjAyMi0wNS0xOTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALJgKp94WHf2GXK34KjNUOsYByOdBAXJGzpHwqk1 -ktclRWYyxWzHoVm/cRhWSQ9tQObMZeMXpSFm5YXrcvmE1Wv5p9ghCYd43tOvaHlC -313c4YR8n/3ItCJaCYb1/tkSfte+rkyinFobjrTVbOVXhaBw6FHCEp06pGlclnni -32n4Kzlu8DfIqddvJ7gcdfcpSMoG/wxC5oykUQkqcdrzsNiRK0zPC+a9H+Hlnaos -ATsLtDR1skr4fWBvAd9VD4GuCPBWxYcmzj/XEDUD2nzkn48LmaIuQgLciW8E+ysi -CPYjA++G2dZk8dsaJJkNk3ogkikhfDMff/BqvveZs77yG0cCAwEAATANBgkqhkiG -9w0BAQsFAAOCAQEADymHk+wLJAdv3p+4hHo57VLaBtwVYXc5oRUbUzgMYTTtPWIs -xuILEqXftMspt6PzdEt0V1WeCWNyypsAbur/CKpAOoVjBDPIo09TiYnYIn9xt5wQ -AmR5kVEZheuazcvzW3C9NAY1T6QDmxNvFCiCXRbtklOg2HqFDZX+pkj8CylQ9TDk -rroUg17b/FD1ds1uyPXzucEWfxqkOaujvsCnzrbFs9luB5VfM+QzLU+l9QRN9Tmj -z7CpGuP6vKvhXJLUjXkZ0q5JyL5wEAe6Ttbu+c/8HhPFKQsW6q/lQSDo0v0LGDrd -ikjWXhSrVjd8+qTTVgia/UNqv/wi+bkWnVdRzQ== ------END CERTIFICATE----- \ No newline at end of file +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIUFAnC6268dp/z1DR9E1UepiWgWzkwDQYJKoZIhvcNAQEL +BQAwcDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25ncWluZzESMBAGA1UEBwwJ +Q2hvbmdxaW5nMQ4wDAYDVQQKDAVnb3dhczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVu +dDERMA8GA1UEAwwIZ293YXMuY24wIBcNMjQwMjE4MDIwOTI2WhgPMjEyNDAxMjUw +MjA5MjZaMHAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlDaG9uZ3FpbmcxEjAQBgNV +BAcMCUNob25ncWluZzEOMAwGA1UECgwFZ293YXMxFjAUBgNVBAsMDUlUIERlcGFy +dG1lbnQxETAPBgNVBAMMCGdvd2FzLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA3A7dt7eoqAaBxv2Npjo8Z7VkGvXT93jZfpgAuuNuQ5RLcnOnMzQC +CrrjPcLfsAMA0AIK3eUWsXXKSR9SZTJBLQRZCJHZ9AIPfA+58JVQPTjd8UIuQZJf +rDf6FjhPJTsLzcjTU+mT7t6lEimPEl2VWN9eXWqs9nkVrJtqLao6m1hoYfXOxRh6 +96/WgBtPHcmjujryteBiSITVflDjx+YQzDGsbqw7fM52klMPd2+w/vmhJ4pxq6P7 +Ni2OBvdXYDPIuLfPFFqG16arORjBkyNCJy19iOuh5LXh+EUX11wvbLwNgsTd8j9v +eBSD+4HUUNQhiXiXJbs7I7cdFYthvb609QIDAQABo1MwUTAdBgNVHQ4EFgQUdI8p +aY1A47rWCRvQKSTRCCk6FoMwHwYDVR0jBBgwFoAUdI8paY1A47rWCRvQKSTRCCk6 +FoMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArMCAfqidgXL7 +cW5TAZTCqnUeKzbbqMJgk6iFsma8scMRsUXz9ZhF0UVf98376KvoJpy4vd81afbi +TehQ8wVBuKTtkHeh/MkXMWC/FU4HqSjtvxpic2+Or5dMjIrfa5VYPgzfqNaBIUh4 +InD5lo8b/n5V+jdwX7RX9VYAKug6QZlCg5YSKIvgNRChb36JmrGcvsp5R0Vejnii +e3oowvgwikqm6XR6BEcRpPkztqcKST7jPFGHiXWsAqiibc+/plMW9qebhfMXEGhQ +5yVNeSxX2zqasZvP/fRy+3I5iVilxtKvJuVpPZ0UZzGS0CJ/lF67ntibktiPa3sR +D8HixYbEDg== +-----END CERTIFICATE----- diff --git a/electron/res/keys/public.pem b/electron/res/keys/public.pem index 0735da0..7446031 100755 --- a/electron/res/keys/public.pem +++ b/electron/res/keys/public.pem @@ -1,17 +1,23 @@ ------BEGIN CERTIFICATE----- -MIICuDCCAaACCQC7PQmrxgWOlTANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJs -ZWNlcGluLTIwMjItMDUtMTkwIBcNMjIwNTE5MTI1NjA0WhgPMzAyMTA5MTkxMjU2 -MDRaMB0xGzAZBgNVBAMMEmxlY2VwaW4tMjAyMi0wNS0xOTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALJgKp94WHf2GXK34KjNUOsYByOdBAXJGzpHwqk1 -ktclRWYyxWzHoVm/cRhWSQ9tQObMZeMXpSFm5YXrcvmE1Wv5p9ghCYd43tOvaHlC -313c4YR8n/3ItCJaCYb1/tkSfte+rkyinFobjrTVbOVXhaBw6FHCEp06pGlclnni -32n4Kzlu8DfIqddvJ7gcdfcpSMoG/wxC5oykUQkqcdrzsNiRK0zPC+a9H+Hlnaos -ATsLtDR1skr4fWBvAd9VD4GuCPBWxYcmzj/XEDUD2nzkn48LmaIuQgLciW8E+ysi -CPYjA++G2dZk8dsaJJkNk3ogkikhfDMff/BqvveZs77yG0cCAwEAATANBgkqhkiG -9w0BAQsFAAOCAQEADymHk+wLJAdv3p+4hHo57VLaBtwVYXc5oRUbUzgMYTTtPWIs -xuILEqXftMspt6PzdEt0V1WeCWNyypsAbur/CKpAOoVjBDPIo09TiYnYIn9xt5wQ -AmR5kVEZheuazcvzW3C9NAY1T6QDmxNvFCiCXRbtklOg2HqFDZX+pkj8CylQ9TDk -rroUg17b/FD1ds1uyPXzucEWfxqkOaujvsCnzrbFs9luB5VfM+QzLU+l9QRN9Tmj -z7CpGuP6vKvhXJLUjXkZ0q5JyL5wEAe6Ttbu+c/8HhPFKQsW6q/lQSDo0v0LGDrd -ikjWXhSrVjd8+qTTVgia/UNqv/wi+bkWnVdRzQ== ------END CERTIFICATE----- \ No newline at end of file +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIUFAnC6268dp/z1DR9E1UepiWgWzkwDQYJKoZIhvcNAQEL +BQAwcDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25ncWluZzESMBAGA1UEBwwJ +Q2hvbmdxaW5nMQ4wDAYDVQQKDAVnb3dhczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVu +dDERMA8GA1UEAwwIZ293YXMuY24wIBcNMjQwMjE4MDIwOTI2WhgPMjEyNDAxMjUw +MjA5MjZaMHAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlDaG9uZ3FpbmcxEjAQBgNV +BAcMCUNob25ncWluZzEOMAwGA1UECgwFZ293YXMxFjAUBgNVBAsMDUlUIERlcGFy +dG1lbnQxETAPBgNVBAMMCGdvd2FzLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA3A7dt7eoqAaBxv2Npjo8Z7VkGvXT93jZfpgAuuNuQ5RLcnOnMzQC +CrrjPcLfsAMA0AIK3eUWsXXKSR9SZTJBLQRZCJHZ9AIPfA+58JVQPTjd8UIuQZJf +rDf6FjhPJTsLzcjTU+mT7t6lEimPEl2VWN9eXWqs9nkVrJtqLao6m1hoYfXOxRh6 +96/WgBtPHcmjujryteBiSITVflDjx+YQzDGsbqw7fM52klMPd2+w/vmhJ4pxq6P7 +Ni2OBvdXYDPIuLfPFFqG16arORjBkyNCJy19iOuh5LXh+EUX11wvbLwNgsTd8j9v +eBSD+4HUUNQhiXiXJbs7I7cdFYthvb609QIDAQABo1MwUTAdBgNVHQ4EFgQUdI8p +aY1A47rWCRvQKSTRCCk6FoMwHwYDVR0jBBgwFoAUdI8paY1A47rWCRvQKSTRCCk6 +FoMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArMCAfqidgXL7 +cW5TAZTCqnUeKzbbqMJgk6iFsma8scMRsUXz9ZhF0UVf98376KvoJpy4vd81afbi +TehQ8wVBuKTtkHeh/MkXMWC/FU4HqSjtvxpic2+Or5dMjIrfa5VYPgzfqNaBIUh4 +InD5lo8b/n5V+jdwX7RX9VYAKug6QZlCg5YSKIvgNRChb36JmrGcvsp5R0Vejnii +e3oowvgwikqm6XR6BEcRpPkztqcKST7jPFGHiXWsAqiibc+/plMW9qebhfMXEGhQ +5yVNeSxX2zqasZvP/fRy+3I5iVilxtKvJuVpPZ0UZzGS0CJ/lF67ntibktiPa3sR +D8HixYbEDg== +-----END CERTIFICATE----- diff --git a/override/hoxy/lib/cycle.js b/override/hoxy/lib/cycle.js new file mode 100644 index 0000000..3a555c5 --- /dev/null +++ b/override/hoxy/lib/cycle.js @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2015 by Greg Reimer + * MIT License. See mit-license.txt for more info. + */ + +'use strict'; + +var _createClass = require('babel-runtime/helpers/create-class')['default']; + +var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; + +var _get = require('babel-runtime/helpers/get')['default']; + +var _inherits = require('babel-runtime/helpers/inherits')['default']; + +var _Promise = require('babel-runtime/core-js/promise')['default']; + +var _regeneratorRuntime = require('babel-runtime/regenerator')['default']; + +var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default']; + +Object.defineProperty(exports, '__esModule', { + value: true +}); + +var _request = require('./request'); + +var _request2 = _interopRequireDefault(_request); + +var _response = require('./response'); + +var _response2 = _interopRequireDefault(_response); + +var _streams = require('./streams'); + +var _streams2 = _interopRequireDefault(_streams); + +var _await = require('await'); + +var _await2 = _interopRequireDefault(_await); + +var _mkdirp = require('mkdirp'); + +var _mkdirp2 = _interopRequireDefault(_mkdirp); + +var _lodash = require('lodash'); + +var _lodash2 = _interopRequireDefault(_lodash); + +var _nodeStatic = require('node-static'); + +var _http = require('http'); + +var _http2 = _interopRequireDefault(_http); + +var _https = require('https'); + +var _https2 = _interopRequireDefault(_https); + +var _url = require('url'); + +var _url2 = _interopRequireDefault(_url); + +var _fs = require('fs'); + +var _fs2 = _interopRequireDefault(_fs); + +var _util = require('util'); + +var _util2 = _interopRequireDefault(_util); + +var _path = require('path'); + +var _path2 = _interopRequireDefault(_path); + +var _zlib = require('zlib'); + +var _zlib2 = _interopRequireDefault(_zlib); + +var _events = require('events'); + +var _co = require('co'); + +var _co2 = _interopRequireDefault(_co); + +var _uglyAdapter = require('ugly-adapter'); + +var _uglyAdapter2 = _interopRequireDefault(_uglyAdapter); + +var _wait = require('./wait'); + +var _wait2 = _interopRequireDefault(_wait); + +var _task = require('./task'); + +var _task2 = _interopRequireDefault(_task); + +var _urlPath = require('./url-path'); +const url = require("url"); + +var _urlPath2 = _interopRequireDefault(_urlPath); + +var staticServer = (function () { + + var getStatic = (function () { + var statics = {}; + return function (docroot) { + var stat = statics[docroot]; + if (!stat) { + stat = statics[docroot] = new _nodeStatic.Server(docroot); + } + return stat; + }; + })(); + + // Start up the server and serve out of various docroots. + var server = _http2['default'].createServer(function (req, resp) { + var docroot = req.headers['x-hoxy-static-docroot']; + var pDocroot = new _urlPath2['default'](docroot); + var stat = getStatic(pDocroot.toSystemPath()); + stat.serve(req, resp); + }).listen(0, 'localhost'); + + return server; +})(); + +var httpsOverHttpAgent, httpsOverHttpsAgent, httpOverHttpsAgent; +var tunnelAgent = require('tunnel-agent'); +var ptGetTunnelAgent = function (requestIsSSL, externalProxyUrl) { + var urlObject = url.parse(externalProxyUrl); + var protocol = urlObject.protocol || 'http:'; + var port = urlObject.port; + if (!port) { + port = protocol === 'http:' ? 80 : 443; + } + var hostname = urlObject.hostname || 'localhost'; + + if (requestIsSSL) { + if (protocol === 'http:') { + if (!httpsOverHttpAgent) { + httpsOverHttpAgent = tunnelAgent.httpsOverHttp({ + proxy: { + host: hostname, + port: port + } + }); + } + return httpsOverHttpAgent; + } else { + if (!httpsOverHttpsAgent) { + httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({ + proxy: { + host: hostname, + port: port + } + }); + } + return httpsOverHttpsAgent; + } + } else { + if (protocol === 'http:') { + // if (!httpOverHttpAgent) { + // httpOverHttpAgent = tunnelAgent.httpOverHttp({ + // proxy: { + // host: hostname, + // port: port + // } + // }); + // } + return false; + } else { + if (!httpOverHttpsAgent) { + httpOverHttpsAgent = tunnelAgent.httpOverHttps({ + proxy: { + host: hostname, + port: port + } + }); + } + return httpOverHttpsAgent; + } + } +} + +var ProvisionableRequest = (function () { + function ProvisionableRequest(opts) { + _classCallCheck(this, ProvisionableRequest); + + this._respProm = (0, _task2['default'])(); + var h = /https/i.test(opts.protocol) ? _https2['default'] : _http2['default']; + if (opts.proxy) { + // var proxyInfo = _url2['default'].parse(opts.proxy), + // proxyPort = proxyInfo.port, + // proxyHostname = proxyInfo.hostname, + // proxyPath = 'http://' + opts.hostname + (opts.port ? ':' + opts.port : '') + opts.path; + // opts.hostname = proxyHostname; + // opts.port = proxyPort; + // opts.path = proxyPath; + opts.agent = ptGetTunnelAgent(/https/i.test(opts.protocol), opts.proxy); + // console.log('opts.agent', opts.proxy) + opts.proxy = '' + } + + this._writable = h.request(opts, this._respProm.resolve); + this._writable.on('error', this._respProm.reject); + } + + /* + * This check() function made me scratch my head when I came back to + * it months later. It simply does too many things. It still isn't perfect, + * but hopefully now this beast is slightly easier to follow. It returns + * a promise on a boolean indicating whether or not the passed file was + * created. IF the strategy is NOT 'mirror' it resolves false since 'mirror' + * is the only strategy that creates files. Otherwise if the file exists + * it resolves false. Otherwise it has a side effect of creating the file + * by requesting out to the remote server and writing the result to the + * file, then resolves true. + */ + + _createClass(ProvisionableRequest, [{ + key: 'send', + value: function send(readable) { + var _this = this; + + return new _Promise(function (resolve, reject) { + if (!readable || typeof readable === 'string') { + _this._writable.end(readable || '', resolve); + } else { + readable.on('error', reject); + readable.on('end', resolve); + readable.pipe(_this._writable); + } + }); + } + }, { + key: 'receive', + value: function receive() { + return this._respProm; + } + }]); + + return ProvisionableRequest; +})(); + +function check(strategy, file, req, upstreamProxy) { + var parsed = _url2['default'].parse(file); + file = parsed.pathname; // stripped of query string. + + return (0, _co2['default'])(_regeneratorRuntime.mark(function callee$1$0() { + var provReq, mirrResp, writeToFile, gunzip; + return _regeneratorRuntime.wrap(function callee$1$0$(context$2$0) { + while (1) switch (context$2$0.prev = context$2$0.next) { + case 0: + if (!(strategy !== 'mirror')) { + context$2$0.next = 2; + break; + } + + return context$2$0.abrupt('return', false); + + case 2: + context$2$0.prev = 2; + context$2$0.next = 5; + return (0, _uglyAdapter2['default'])(_fs2['default'].stat, file); + + case 5: + return context$2$0.abrupt('return', false); + + case 8: + context$2$0.prev = 8; + context$2$0.t0 = context$2$0['catch'](2); + + case 10: + context$2$0.next = 12; + return (0, _uglyAdapter2['default'])(_mkdirp2['default'], _path2['default'].dirname(file)); + + case 12: + provReq = new ProvisionableRequest({ + protocol: req.protocol, + proxy: upstreamProxy, + method: 'GET', + hostname: req.hostname, + port: req.port, + path: req.url + }); + + provReq.send(); + context$2$0.next = 16; + return provReq.receive(); + + case 16: + mirrResp = context$2$0.sent; + + if (!(mirrResp.statusCode !== 200)) { + context$2$0.next = 19; + break; + } + + throw new Error('mirroring failed: ' + req.fullUrl() + ' => ' + mirrResp.statusCode); + + case 19: + writeToFile = _fs2['default'].createWriteStream(file); + + if (mirrResp.headers['content-encoding'] === 'gzip') { + gunzip = _zlib2['default'].createGunzip(); + + mirrResp = mirrResp.pipe(gunzip); + } + context$2$0.next = 23; + return new _Promise(function (resolve, reject) { + mirrResp.pipe(writeToFile); + mirrResp.on('end', resolve); + writeToFile.on('error', reject); + }); + + case 23: + case 'end': + return context$2$0.stop(); + } + }, callee$1$0, this, [[2, 8]]); + })); +} + +// --------------------------- + +var Cycle = (function (_EventEmitter) { + _inherits(Cycle, _EventEmitter); + + function Cycle(proxy) { + var _this2 = this; + + _classCallCheck(this, Cycle); + + _get(Object.getPrototypeOf(Cycle.prototype), 'constructor', this).call(this); + this._proxy = proxy; + this._request = new _request2['default'](); + this._response = new _response2['default'](); + this._request.on('log', function (log) { + return _this2.emit('log', log); + }); + this._response.on('log', function (log) { + return _this2.emit('log', log); + }); + } + + _createClass(Cycle, [{ + key: 'data', + value: function data(name, val) { + if (!this._userData) { + this._userData = {}; + } + if (arguments.length === 2) { + this._userData[name] = val; + } + return this._userData[name]; + } + }, { + key: 'serve', + value: function serve(opts) { + + return _co2['default'].call(this, _regeneratorRuntime.mark(function callee$2$0() { + var req, resp, _opts, docroot, path, strategy, headers, pDocroot, pPath, pFullPath, fullSysPath, + created, staticResp, code, useResponse, isError, message; + + return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { + while (1) switch (context$3$0.prev = context$3$0.next) { + case 0: + req = this._request; + resp = this._response; + + if (typeof opts === 'string') { + opts = {path: opts}; + } + opts = _lodash2['default'].extend({ + docroot: _path2['default'].sep, + path: _url2['default'].parse(req.url).pathname, + strategy: 'replace' + }, opts); + _opts = opts; + docroot = _opts.docroot; + path = _opts.path; + strategy = _opts.strategy; + headers = _lodash2['default'].extend({ + 'x-hoxy-static-docroot': docroot + }, req.headers); + + delete headers['if-none-match']; + delete headers['if-modified-since']; + + // Now call the static file service. + pDocroot = new _urlPath2['default'](docroot), pPath = new _urlPath2['default'](path), pFullPath = pPath.rootTo(pDocroot), fullSysPath = pFullPath.toSystemPath(); + context$3$0.next = 14; + return check(strategy, fullSysPath, req, this._proxy._upstreamProxy); + + case 14: + created = context$3$0.sent; + + if (created) { + this.emit('log', { + level: 'info', + message: 'copied ' + req.fullUrl() + ' to ' + fullSysPath + }); + } + context$3$0.next = 18; + return new _Promise(function (resolve, reject) { + var addr = staticServer.address(); + _http2['default'].get({ + hostname: addr.address, + port: addr.port, + headers: headers, + path: pPath.toUrlPath() + }, resolve).on('error', reject); + }); + + case 18: + staticResp = context$3$0.sent; + code = staticResp.statusCode, useResponse = undefined, isError = undefined; + + if (/^2\d\d$/.test(code)) { + useResponse = true; + } else if (/^4\d\d$/.test(code)) { + if (strategy === 'replace') { + useResponse = true; + } else if (strategy === 'mirror') { + isError = true; + } + } else { + isError = true; // nope + } + + if (!isError) { + context$3$0.next = 26; + break; + } + + message = _util2['default'].format('Failed to serve static file: %s => %s. Static server returned %d. Strategy: %s', req.fullUrl(), fullSysPath, staticResp.statusCode, strategy); + throw new Error(message); + + case 26: + if (useResponse) { + resp._setHttpSource(staticResp); + } + + case 27: + case 'end': + return context$3$0.stop(); + } + }, callee$2$0, this); + })); + } + }, { + key: '_setPhase', + value: function _setPhase(phase) { + this._phase = this._request.phase = this._response.phase = phase; + } + + /* + * This returns a promise on a partially fulfilled request + * (an instance of class ProvisionableRequest). At the time + * the promise is fulfilled, the request is in a state where + * it's been fully piped out, but nothing received. It's up + * to the caller of this function to call receive() on it, thus + * getting a promise on the serverResponse object. That enables + * hoxy to implement the 'request-sent' phase. + */ + }, { + key: '_sendToServer', + value: function _sendToServer() { + var req = this._request._finalize(), + resp = this._response, + upstreamProxy = this._proxy._upstreamProxy, + source = req._source, + pSlow = this._proxy._slow || {}, + rSlow = req.slow() || {}, + latency = rSlow.latency || 0; + if (resp._populated) { + return _Promise.resolve(undefined); + } + return _co2['default'].call(this, _regeneratorRuntime.mark(function callee$2$0() { + var provisionableReq, brake, groupedBrake; + return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { + while (1) switch (context$3$0.prev = context$3$0.next) { + case 0: + provisionableReq = new ProvisionableRequest({ + protocol: req.protocol, + proxy: upstreamProxy, + hostname: req.hostname, + port: req.port || req._getDefaultPort(), + method: req.method, + path: req.url, + headers: req.headers + }); + + if (!(latency > 0)) { + context$3$0.next = 4; + break; + } + + context$3$0.next = 4; + return (0, _wait2['default'])(latency); + + case 4: + if (rSlow.rate > 0) { + brake = _streams2['default'].brake(rSlow.rate); + + source = source.pipe(brake); + } + if (pSlow.rate) { + groupedBrake = pSlow.rate.throttle(); + + source = source.pipe(groupedBrake); + } + if (pSlow.up) { + groupedBrake = pSlow.up.throttle(); + + source = source.pipe(groupedBrake); + } + req._tees().forEach(function (writable) { + return source.pipe(writable); + }); + context$3$0.next = 10; + return provisionableReq.send(source); + + case 10: + return context$3$0.abrupt('return', provisionableReq); + + case 11: + case 'end': + return context$3$0.stop(); + } + }, callee$2$0, this); + })); + } + }, { + key: '_sendToClient', + value: function _sendToClient(outResp) { + var resp = this._response._finalize(), + source = resp._source, + rSlow = resp.slow() || {}, + pSlow = this._proxy._slow || {}, + rLatency = rSlow.latency || 0, + pLatency = pSlow.latency || 0, + latency = Math.max(pLatency, rLatency); + return _co2['default'].call(this, _regeneratorRuntime.mark(function callee$2$0() { + var brake, groupedBrake, tees; + return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) { + while (1) switch (context$3$0.prev = context$3$0.next) { + case 0: + if (!(latency > 0)) { + context$3$0.next = 3; + break; + } + + context$3$0.next = 3; + return (0, _wait2['default'])(latency); + + case 3: + outResp.writeHead(resp.statusCode, resp.headers); + if (rSlow.rate > 0) { + brake = _streams2['default'].brake(rSlow.rate); + + source = source.pipe(brake); + } + if (pSlow.rate) { + groupedBrake = pSlow.rate.throttle(); + + source = source.pipe(groupedBrake); + } + if (pSlow.down) { + groupedBrake = pSlow.down.throttle(); + + source = source.pipe(groupedBrake); + } + tees = resp._tees(); + + tees.forEach(function (writable) { + return source.pipe(writable); + }); + context$3$0.next = 11; + return new _Promise(function (resolve, reject) { + source.on('error', reject); + source.on('end', resolve); + source.pipe(outResp); + }); + + case 11: + case 'end': + return context$3$0.stop(); + } + }, callee$2$0, this); + })); + } + }, { + key: '_start', + value: function _start() { + // for now, an immediately-kept promise + return (0, _await2['default'])('started').keep('started'); + } + }]); + + return Cycle; +})(_events.EventEmitter); + +exports['default'] = Cycle; +module.exports = exports['default']; + +// file does not exist, so continue + +// TODO: test coverage for mkdirp + +// TODO: test coverage + +// First, get all our ducks in a row WRT to +// options, setting variables, etc. +// return the outer promise +// wait for it all to pipe out \ No newline at end of file diff --git a/package.json b/package.json index b0b3a8f..b795c26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "res-downloader", - "version": "1.0.4", + "version": "1.0.5", "main": "dist-electron/main/index.js", "description": "Electron + Vue + Vite 实现的资源下载软件,支持微信视频号下载、抖音视频下载、快手视频下载、酷狗音乐下载等", "author": "putyy@qq.com", @@ -56,6 +56,7 @@ "axios": "^1.5.0", "electron-store": "^8.1.0", "getmac": "^5.20.0", - "hoxy": "^3.3.1" + "hoxy": "^3.3.1", + "tunnel-agent": "^0.6.0" } } diff --git a/public/show.jpg b/public/show.jpg deleted file mode 100644 index 1ba74e2a3cbd4d644e0e5d8337449fabf2d09a59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31192 zcmeEu1z254vhc+T4ncww+zB2a1b27W;O;J$0KtMwaCdhJuEE{iU4jIH=D%cSGP1L~ zv-|D)-!HFEpVL*<)zy8ftE=mt=HuJ!w^aa&xUiTo01ONO00UisZwp|MC;;@IFHBI0 z1;7DaSO6jb34joE69E_iv;a!bMGJyN0n7mQpKnosB|s1$1G;~DS^{(d4gej1D(H3q z!6kq|fD7mf1VO!kd_WrL?gg9yWaRA29AaL-#vhD9RO5Vh;XQQ2ryy* zI4T$fD%iI!024?-;1G|h`jJ2=Bos6Z*iY#P8Kg{b2uP@J^8f@0P#Y8o6j0UXq1h$l z-nO{AS{I9_PWVpB{KrI`>zn=5aIHfB|I}5xe;gnCA(1IelI>ly79E;D|I~l{>Jkw; zj{2(dk$`~U(8c7o(nX|^!Oy*74TOm_5}+P`0wJsR#}=rO#8Z;ovA6b z`ZF6-kSX@QeyMl4=Y59FuM1#hyBo<0Q0lCj**@f;avK&>c1y98HV&Ctuw~eq$lvVU z=fFrU6UP%es{fED*Ng9r;#Pw1rM6%TW7&LZY9p< zpK1X-WNr!zXifyG1XHR}2f#pxxQiTk4Cgju4}av0ox!R}8qo-^D5IIU4wo6o>D;-k zIq5xLxPLx0{2*hN(80nR#bzS&YQd>!!tbwtUTVFVA_UsKT=Q7#zvmo7)TQX*Hx7}==K0X`qBHzBz zR=VxlQJQ9evCn?Fgde{+pkR%&(cW5?>Q%;7H=}uNRVO(Uedvg`ci^bLwZ)m@us2** zSbx5x)#V!YL2)K!|2R5mcCZw}%jQqt8_JoDG4@3jHGLJWz8Y0M!Y+Wiwul#yrIL9t zki1)zyc=ep$uS(b;~=@qaR`zCox9+=!%4UCy@F}lB-Thc+8K%C>e+m2k3t$s)w0055XTRk?zIXhlH zH$qry0IHv0$J@mh;WRoAnr8x`0YpbEg`B(~=+^{SQaJjEJ?rgu0{%*VgbWChJ zXT6;y2!XvI2sNUI^hIwEFUSVpzi0Xh0wD0Wqx;!MfN1YP6+flPg)xTK$Qjn!myJ24 zR#FR1JGu+4A0`2SU;2Y{G*92L%WY=vQcWG&pyhTS9BrxTw|CS$4of%tMasWgVrVF( zKejR5Ju%sDx=KG+a8sThOtVfHPg-36!V#c;?DY+h;B4)`bTG*EsGz@;o(-t=l+Iw) z5zHqwIA%T|3$)@N%Jyu%woLpaB(>-c&GtjeFVl$Q#x>7be&*#nB)&3s_{KiAmR*LX zAv=0`YVK@(`3k0a25k99qkjg3M(Ja!whf??GpB!Ng-97gRQphU^@x053ZQb+uGZxt zSs}}lz^h^Z?6RVzhPlOIYIJVAe&5>eV~d5>@~ZQV0ax2&o1YSOyIqDEXdM9nP=@aj zYL3WD+muxS036}{!l78jBulCCpBaBHz=n70Lh%Wdw#+#38Pc`dERF0*TfwXosc z{2+sX@BR@~!oc`0tZ~oBSjfE^x<@=bU!I&VX>nupT|)oB(8pz*qmpLWRq@b-WvsixWDM5glGD{7VDH?96L zXlA+L@-B_9$;|xX)DS0y)~B=ndxMF^^`wPl?Xf_!QHhM5Tk=s5^_S`Y#}fZp?RP1G z|BUNz>T#wm@~5ZW;4Fr-$LrK)&9MygSmxxs9AXS9fAD@+kRS+!w2=a1fgF9x`)7p! zY5b#e`G<-1lF`tkbei*xf{}%}f5X@(ZFQ+>_JI###rsxoUfqyk8}t5XuVkqV1Ved- z4S*FVDlUg|g5n>CoHD4;90WeHz#2p#a<@}%M*PA*J;52K8RpmE{;tQ>mNROsy=7Z> zpS70vm-=5zoP}4z$yd*X%e1w~bBx75){q?`^P~gN-UEN|d{<@|^IIbX0PMOPA@>c2 zp*vVk-c;nUb+Bd3u)*agW_x`j(|WVocSR=O9||^9^>$ZueMI&jIo*MML;&bgvp!rB zrh$UTi3g{Gn}$1Q#FG@jgu?>);L@Z*RtlG}mfm-lwSQDv;k+YRd^D}Pas{P0;E6Er zk3s!14d72vjDHY80F%BX@Mj#lm|cVkU$1v*{1SUBvwA>VI(!VB0TY#?m+lg*`SsvCktfjE6=3ebn~~_@n2)1Uwojh!Je_)lSwQ z{0~^eg>~}%v%e(f2h%T`>Z^d{i$8`@?5{)5)3ScB{w3fSEx|;br-l#zz6tcsSd0CI z?(d0z#2^ip88b#VzHH45IoTa#)D0}2d@^g2z|D1=m}a+EYWlNHlR#kDjfc(9Ck|Q_ zTleo5xUIt1pT^pL>Jb_ti|CJi|Aa$v4)rP-bwt|ZZ1?uG{f6fkpLzOVJ$7A1i%`zg zHURPWi=`Wpp_V8Bf3#tSZRMjFoCOl$BcGCzalE0Fj2!&a41zEOAXu?QQU09Sv^B>< z4)8affk3?FXqTP+%cM_iVg1#t?vzN}zh(F_nili1>nM{a>Eysf@V{TI+~^FpB!ayY zvit76K;714S{4=0nhiER_WGM8|A+zr5ZIfJJJTjIs*58OC7}VYf#0b=KYp>o^`=ib zXIme}E(CT&S7*bfdWy251AjY=;nIX0?Vb!4$Q`L%J?fxziiV7FmQ0_~8}EUZ%->4< z6PVFRxDw4TgYq|3zeGs{gadBj)MBWlf{|!~zbgizA_Jp{)qttQq=B*X>n?%2o-$iH zO23iuXP~)7-MhF0wW%V{g0j3xu+H+|F#YHgtN$jA+G1q{ALf+<-s!0QC%(S~TJ5b` z-)n3Us{BUgUjV_2%&H&Rke_V5E*p7mbMx}Lb9ZA0IV(K*b=bd+B7O;D|J9}ag<M7&~@I`1H@hT?mKK*5I;WCZ$=C@|`L-rqm zWbz-B?~V-;gt{CfyTAQG{tn>k2wl&N@&2CpM-0kI^&R}PUIEhB?Y^SHDq((`f!oxT$+45kC!|vmhr9@7_ zbatLwQpMOynbfu)t-f!$AncVhOmq7W>URLKEc5PQH~sg-KVlHE6KP5#l|!F+w1+!W ze6wF(0wC93{NVa&h9Iy35IvvW7yp5W{Mmah+^`S74*RJ&7{Y;h%FA;zE_&&)x-d@> zt=@!5`!B{l!yt;(xGx_aG=BdFvkE0N%sV!hB$C`i9TZe;d?3!6pL5x8$&(Fc&fN z9kJCt^EQw4&l0Ay(m|goeu(=W05-JDDTO!pap!^z!2$q~e)?LlNzZlCv8aeoFOdGj@y zj941;q>DeB1pxkZx$v;>-p$2z_k_5Z)V=#_kJ^i&l|qlA{q#TU^H&<8Wy{k!KKUV=(;zg>-KiaIn*Rgw*oTU~0+QHw4o^%+Ux^JY%;7a&DUGZQ zK&P(G>^NzdE3|}qzE1ZWR5xZ#RM9RK?zxrH%1S7yEOqo$o|jt@a`S|QrsVx~48Mhb zjy!)$`WIlZlJ9}|<9D9&U;XpHAmArf=zP%m6$QwnLqUK;gN~$rPLHQlr~ot!sHZ6C zm_#pRp>=I|L5EhbpffHoZ~)kIB!dE@#%#&$rT=7-4&xOSr;5l!tV(kJ&nE}Lb%9rG zQI0Z#%oCoh1&hfspCz66xBW%}_WhokWMr+`>UAYfX6qJOSh++g|CQ^(6B|A(KZZN})uLd_D$Fhj+8(3B<`!kJX=j zk}&o~>WB~r=qpFI?cmEQOWhQ)dN_7}<$9gHwtf>LWcr3s-sOHdcW=*;&r3_qd4GR^ z2T{#ZFfqQRA3kb7zzwIfZs?1$gnM^&HcKmq36~>1g1K+G zJ~#YPo8w;*IafnDa8o{yea(<~--t6-A9L_z&^8wjJQhRL4khIC_)9Zg`+5r60v|-l zY^{D8c13BY5an`sb~_{=d6eK>A8lgY$=zUjPi|s#@mQ%@!^qfka2d&hwZqRM4J|xlx2E-<~nom`4KONa7 zs=RH+>5>ylqcL!Jie zbpAxLW6h>slO7A+zhh0*&t=V%;t{f`SGGXTS}UKmV8cZi%ee4h!$o}8sh7lv|Gfm! znb`>SN!Hv&?2?u}DKy7R+rI%^O?aML9JTMRCw7&*>?i;7f(JxlqJ!BMNv1Ei%l zeW8jYA7H+Q_EsH8DnhgfSuD0XX)1(HO?4wb>I^FjqaOrMQVpG&esqbLM;s8z4?%{D zA2g2NJYVL~=9Xwr-X?QYoh0L zn^gM&lLf=sB5w+yv$a%j!g-d}k!Az`Q|WW%BmtF7ua8rpjnq7(KvOk=N*G7G%Z@U> zL*lY6x8jKGbi=VLMVh~mpa$x)Ix>Amo9Q|bOm;NtYal_yZSb*zsw3M$^5WN5T-{5t z*URiWp!Kyi`4W*%fihDdL8RZbC;RpKO|TD*6jKwdaoAF3;44g+hmKKKMnl{aFh)69Fpx7i+s7j;wL%oJ!H_+X95roSRPspb(!oAmNf_n1AWJ`~ zhpAGrAK}z=VSVW{NmS~ToBIu5>n+Kf!+}nmBbnC0*~~RL>XlkNH4|8k-*YmvCr>5N zmicxYs}vOyI_U=DBh31)PMX|lexdb3qtXf|gV32Yx?R>N!4wdmSxYE+=4E5t&KKfE z)CI`*Kq6Rg@Ecc0GbdjF*qaSH7#n|pllesnE>ISLp^%J|T&;wA1Hr;9={mmYVI@by zl1M%KKE@;w%FJo8K%hn*o|u)3E{kz1LSiyuOp|gI&zmS32nBEn;oF)4ZgM}9;03^k zBvNMEr9?ig)-%GaM|wUtdG&F%(9pyLIJ=->WdijaPS?5~I{`OXgCL@sK+EktjqDgD zEOmsWF61s%_@dyd=Vyg@CO?hQINyP?(eWk#x|TqJNJb_=0l7X%PQpUG01y7n4H`)2 zP7qmXLhZVp!t^no=<_Hhf@3d^SX%4B#fSwFeCF^Qu)QGydU;T2;W!vB2+%N;5>E~B!o4k{@sD>vP(?g&v}Z9 zq6q%d0D3(7DBbnMB#`Cpr13F-@p-f(Il@_WWCOx+VsM4P7!#>ubO#YgCwl2!6&P*5 zYWyp}B{CXayHEjZZ!@_aeP*6&?)j5mFZkE1gu|O#vTtKa`6>C~1B|42Wdkf;k1er+ z$8^aSqWgi2?=xYwOLJ}$fEOu?h@Q)X9wMOWsy91F);%SDg)TffMogT7`jp5) zT!%4`-$pGQaH5njpFepNC2=!Jg^G^OC!A*{=qZ55!HnLPugzVJkRk8L38hg@g%BOJ{BEuSAy@WEP0}k zXdiY(B#kxycMUI~{-+Y*q&hM~Z;AmEHo`lB=MlYs0nooa0WJBvv`N!%08cuY51S8J zGPipsuUaX-;CQb{@NHf50o%jJ2KRBC6^DLDBgCZOTlfak)I`*7!`I}ytVQo}&r zqk?vfm9sRtJSXbIBHzjuKAmm!TTEghj8L%&6+3;d?JG9@SczoxWGxFPbkmPl zUC`mMQWy*+KA!hoxTUy2sTn`hVi=S@h~;}C!yjWA?CU2>NEqi6PhsBAEWkT&Th&gH ze+gO(XLpT2*zhL>X)m9I&$*;kzz~~Fye`srfMiq_8e+W=dSsY1O;du57A(Miu1o3r zXl@JxUx`wC{%L9-D`7av0ZHhbH1&Qoi*14|iAS^e80R~7Pxx=>Lf`$HqG1lf>)nTVcGOt_9y zMlyTopzSK&P(^N#m>{<1KWc#e+) zov)34N=JTkXgKi`XE0@k(&P5J$k_NA#O{O-X4!AIN4CLOC&a7Ln<;1lo4~||`F4)9 zS-h7xNF5x;vQl~3ubMz7O7U+@dvLJ)L4=4%(TA||QAg?#IZqR$NWdb{$&J1zgLHk# z!5{>&gg8qCw9fs)20mxFNN9e4ioEQub6-l9JZNVvbdo znt4?2)+Jug6SAL|y%^=PU49|^@A zKKz@R?dzu%c)sgM6E4fzh5wCtW&eBZ{PT)<{Ap(JeMbO|nrFp3%%e&E`Y(9(U^dDKyg^?gWKjU%pl=Tlu+UI&kdROiP>-J* zAW$LEqP}7JV%% zJfC?(2Xp2+kAiXb|GED~9hAw>nGvwnng-=Qp|_xG;{G})$2QV6YyY)>t@14M^1dMu zvsr1GlaCRD*|4DF8(<@LOaLdKn~|%fYG}??4KY-p<2LbeBL3(8&*=asd4?TEZN$2% ztsiy`%n%|lkXlip%f}>UuaO7d4T3m!%_L_OiOBkX7+cM5yAhu9a@kV@9C@LfE;qA{ zKcoqu5n893Br&OQIDjIbUitwW>9jt~)^E&);b?k1BfYNG3J5`qLInwrCh@ZN;21bv z&tBhJccqfr>XM|sJlPQ!{z-V0IQu7>|FN*(*>@ zl?>F?DwDJ?(~x)mkVArvG!sZkvt)rG+l zP~{s&(8@%3wUF~WHnCJ1+)cbU+=dTo7c&L=)$^ZxYWLJrswNB@K!YpgsI9MW0Ouw# zs=0-I9exvj%gtI%@EjjN3Xc!Vcph8(xuJD_=HjN7XX_r?-cVk~fZBo&8j}bh7WQs1 zn_xwxxOL#QUv5LnlyLT}$ksvO>t~sfF*UrE_32@h#`fKE0iJ_BHEw&?xOfe&byynx zyMYP_nvqV}zyZc7Q>?r9^+p_`j<~rrbQI{Z(pH{qdhSlBi~^Wc?`dWgDCqZ;OK>pq z3+KW)p3Tm`5i+d7=$#6b6@~O+WGRr#ua+O?kI?a9#+EMNrHX<@fMU0(D3TR_ueic1 zl38iM(m~+NAyz^B+ji7rSwjBggNF=OE>BVUbIL@aCDN%SJU@AqiHG6Lafm?H_|G_e z(kx@{;JMwheb=cdq1C5hKpMpb7QfMVFF#lHIeTR-cH)U}I)8UByW*0*{`giqjSVpU z^4(~s3?g6TUYz5GQN=N|K9k&F@3ZB*o>)XUyileov)z}58$DzD$^zn{B9b3;0rlia z{Qd@xyeAf6^wPIh)!k&m3ccQ!CfPwc(MvB#3&QRt8aiwg(dv_9N@BQ5^QPE1HUs0(M_Z2tmP8;+5!_a zbb39HLpBXNUTu9tHT9R6lzwLXtLBV`Rzi`2HSfV?pp8q?h0N2lvALoTC0FJ5w8hWy8|WShLsl0qesXH>y(XBrcs7 z(CTT(wRHrm7Zt6A{4n7xlc`Xr_?ysxI$zfoGg1|uTLAeN65v$chV4JZuiwM!(h-ys4j_hE^DeoZ*R2Y<;`Nd@G5vU)%%+^nCTp&isrYZ zd46qcu12+Q^epdWGJ%<4m&5pW3Bq*@f#R5wz33XQRa%K$tDmm{SrTy&WOerieagKb zDhl4Xk;Z)k9Q*0+!l_`VkxNU`^?d`dbTQ&}4%2qaWe{-$H_47rfcXs=w~!N9LHaYah-#>AiMe%L=glz&M){`zfKQEW`jiTfh_Nvu7M zrY1aMM+X-rf)yA=>-QCqo0-mM4lex}!MV@f-o*;7RDZ56(!58vj=jA6!h6ztZm-bW zxPwd~Zqr`l#Ucp|vghiuX7o=6-!SAve&=q;JLg-@R&zoPGmKwl?s=BeX>1+_eY%g^ zh{+l4{gcb5FI6-G03Dh#{o&HFB`^+$dh~{#OO9*$l$rYMS2r;w0Gf8s4N-(7yaCg$yebUfLnkNQM?5_oxCBY_cR>#hU7APcJD?3-r z4u6B1pqfuxS22DLkQ&A&N4ImzZ0dA84BV1{k7dVyN3u1@5DPlSCdZDU%BE%5-gq&E zfx1VfcuOqX7ab{?sH(14B5EgL<~~uW8$`Oc_tl7yNLq}^*M{!nIkNj1l{;#i4O1{A zTriUkgW(oV%r$#%4okdQVBkeep=Tr|j($RR0!w*y=a$lDTz`&;E|ZUgy_7vwJu}jl z#JE6A6g_KjzfufpMm(FK03Te*Avr`5skkUAI(4}2{iLRlf~;b{4E{_S>gGSlA<|I_ z3Jq_}xU&9P&S>rnQ7-y8H4wiTqU|9P^@mK4kx;d*PlsMXquwbY6L|KAEYwj1n4t&? zR*fyu%gO63sYX1?iL^ul}gTA5q z6>nZ~f4cT34Uq8tj`--P&Gc`KNTS%P&4L{BoW?I9#TWA^dJ*QVEl&4xhUlH{XPWf; z5xJ}y2>Xk1hZElbh97i!XoOqK=`zIccGwWslDv%wY|ZRbJ8WFi3EM%u2@0QK8Et&#+!vJSi#_< zwcv(>g*MJ(=+Q!vU0?n;WZs3_OIJ4c+L@PO3x@<-8% zM{b&z-HYxbBa`i(?vba9dD+B^T?NlT(3{5^4)KQaEm(fzt$rOi@~)ClUwMpNWsMLF zzkW%nrM(_T_vE5`o%3zD$jkfA-4=CM(F$FS~(ldXz$O0taw|} zW^|R8w>gOF35AAmxzmGU^?~?+B98&k&W|8eAla--f8=Gu7PsY48Mbz#kvB^>i1@14coqy7?An|yB+|)Pj+gX6j!~i}q~N8T_H3*FEDUqRejyQ+4_%QIht-M! zPhN8*$)@(e>)j-FsRf-4iH`y|_knKDdK*h`Av_g%N{Puz40*%VWk~AmrMj5X0LLw9 zh$?S2hrN16Wl|ApeZPM>bVeiIPLr^qgT0dowal*O=pwJi`_Z$~232VCjU+U(HF5%b7Du+bY2D-DwbC#QcmS+0oMxu{u9ynku&?{JBGCYV zmA&>tCOz*HiYTo5RrmKoof-1ddN+hBwaQ$dV5NkI6kNHwFJccSJGIky6xfcJ4OvV3 z+?+5hz$n-otw_wcG8#zl31l;9d6k=Un3Lo5KlzN)i9js{hrwe;7hpUCTETo&T48QP zJ=D?lA!OpBWd9h3Lcl8HZ%pFlN^}W!BfknbY~6}8(hDrHH%|)0Bch+tIJry;5tpQb zkBm^4qf`=>mpVscv~~*{rWFbWu24odq(B8$&LW;iV-62pJp{x^Hk3THbq(mr9Xm(6 zFVl%AJCg!oY@4!kufq;&4=b7!o$MqSFH=|oshLCP0$#c!+^oqq;%W~ZV)D;^?f_z>4Iq)qPp(sH$Pj?%yP@!bdl$DYe+o!Daz&qVnNQ!kv_HWxv%qOB_DJJhCVEG^X~*1)7|x&6$i(F8DT-hUnlW68sVPnj9$=iGYYVlyh)sSKl~wEPISFzhOIe91Zv{UK3Nd}%^{TdG@wkWKs8+h zimWVIQzA1`(5L|tv!>+8$L4}Mh9o8*bDF}*od0+~M2x?tOz!LfZqK}Q*yPmc@!neLR4P#U=IAT6aNlJxJdx5{%8?P_fQmf${i8PuxAP`EDDR#xQbPI4I>8-MW ztna$Uv_!i$Q#mW{c1Q!pmqveniZ*3hP*7hFWAh*svNFozD_Tq3(E|aqzoOZ?d11vg zEl2O-2Gy28g}5-d#H6HxhcF^0lXb9r*L{ClCdh^NlCov-tVp$n2yJGN;Pjzt-vx0Z zPMNLdeee5e@{Y?`u_fO5`4itr44i2A7Fp;sBO%&Zw>G49oLIwLDqpV!5o7q?kf-L` zJa;0><=HOvM;w->@&$%&YT~CW$E~G0XKw7z2xIgaOh4LyyNiJ!& z6M|xQbT9pfuQxer(n(x&Z6t1CC?w^&7Ame)?#5G`N!!pzuM55b`VDDvDpjeMr@sMK zf&%NsVP+ZG&&8476&ChvdiBMat(!8iFe0dX>JxrG3x;qOaNRXQrySXRK^ zE2)cG?^#85ytn%Xh;XBmYT0<=L|E+!x4r%RQs;hK;)E^SK4!t8nCg7tMH30~RmFu{ zH(`8h3(*bCD2^M{$u2n9_g6vY&6A*fwUfM8ACDOi?9%G;K>_L~bKqyH2ZxIk%Uy@u zZV1O}OLxs$SLZ0O`ohCU8A8OX`2)GScx#XphWe})&!VU}bOIr4SEzhNb&is(m#97r z^i9?rA~v_|>&&AN!0evAjM4ni%!n-XwNpKVtp@ZrLA?FwJ?n9;7WsTgK~FRrXjz*E zryKfnwRm5t*#10Fwoh$o6%1b`bN!FXZg z?;Kc6t3Mbg$kn^T42}Qc*iTV=WA{ri52I(BsZud`RjLvS{C;Igd@W8p9!c_5#f$Oc z{7L^1KbRLS5523#=nSHhu(<4&nI*#5(7e}A1{s!aq@@bL*|`i`lFB#~`KucS59vIi zPB@$@GcdKi-I|UanN?8o0ZBAFBYwH3OB)=FQ0xq^?1MbiP$QX6Uj;&q z6-Jxnn39h0Y2IxoojebG{x!eG~M5?=dW8;S^Ki)JLHvOh7q z7!u-leX6{E8zRY1#@45LZk8D!o6ahY88k2h+a60LClRXr4N#ydJnGzOCo}eC-kVf7 zuc7+FmT4Px*FoYPdy}5*ife+Z&`6{Idcxz9y!B;O_P8_4nqR4;W03x6Tt}tIgM?Xa zr2_hC?W(76XkWiP6I&+-p3kTH0?HXI@oEURuv?3td50*SZskT=J5q8^svR){h3t(I z!HP<(P(8k(I7b8L!V*VU$kI1}nexpi@k@Fj58GAwI=LImd4<9?H%qO*^CyGiDa}cH z8A@2D{`%ljv%~}`@DGN4G&`&W_4Fu(c(pZK9)}kPTlDGN(|6pNR$U0+0Ozs{Yo@V^ zCUh4mlLj8|5!=Jovzq1ltBSy(SLIcp3ULPdQP5EufzYS3lXA+Fg{(`KubZaGFEtBU zrb)W|V%oeIb`!;J&b=h?*dQ8`eq1MWo!IXG^7^TRKfq zo*+8O(rHatm|?Retk<^Sa^bTJ@g>T(`e-!p$&ljmayz}Xxd}HLoTr}~GfLG#>k(QT z|MP^RF_3py-$9$UZ7HZdp7K-4@ML#^gh2mrAG=ig7101QFJ`N}QGI9GsXMQqkbfJ& zU$Xw);q;;^<%eRgfD+k9-y)R68hUl>7&8{@e_f=@P%mgqE7YgidPG@ZIn!K!Qq#P1 z5c44V;i=7qwZHT+6xgx9iO&&N26Y|rfITzE>(GaAjn2Et`%_s9RqdHTDc`qV*8({* zC^7wUNVRxU+l0A!>u8ApwKkY}$;|COIk8bf7q>0Yiv9+W{@P$#j>iX0W|WD30$8S& z!@ce@gs6lcm>qsr)~cB)@$B43_e6jzqUUSS^Ji}QHr59z9b_p`%DluM+Xt0%+W8cnpR2N=ZwMTdB+}1m zKTUMWI%VlnQ@vWd-7qVYZ6GZP&`m((*R0|$)z2a4mEpXi2qK5h=v`c()M)D;7?@tB zYtF3Kh#t~FWGKmDRor27B;A4j^aUr!DosfwrjEYbk{YV<-jYCm@ndXFBku(nMLv>z z{)c+K`dvYLHB*(`m=JQuo#j*cRWg$1k}r{r#2MQN?-r+r?n%7E#V6Es3 znYmS(8=SjI&cvVa>6t&>&5^+}f>PR5OSY{oiIH~e4zX7PZwX+3{Xl#&CUh;;u`&8f#B`v%z z_Vs8x&zow!mdtagm4MRt{1|rxznBa!SH5Ewm*P){Tnt6Xk#BxsY4?OV`J*v_y?izr zwQ%yeKm?3siJd+|Z?-Kht+n1=KFsKA;0653C?v#HHb88ZhzPZ<%Y94N!oo0J7nU7T z(+$HC6zd~{dW=rCfKBKTHC_S#5o*_!=S zuwW(vvVt-K?Chs*c}nc`sI~jchHu06G!guwc1vWxIwPG^Z?T)d%j{Y@*Qu63pewAh z3o^nw40~|_&d5$HzEi>Dpwbz_$Sz>9=q!T%x!tUJU%oDGeY^;KEf6U=F_hqi`m6Zi zjuK#NZI6BVrx<-g?vrAAIVpM6!l`A%vN!eG%z)%74Awb&9Z%pQ1M&>Lemg;1np>nI zN;VSYXSDSy+z6qJp?0fw3()tqS8+tDTKu+$YPPcQxRhK;l}asmnn+G{>=kKR(R8o6 z>v2OgmR`L+-Q7v6_wvR52Egm`5=)C6VSM%0OCdV8_AV93ICXyU#C*@*Wyc7w)O#ED?pJY<};DxCq zUAeETG(3o{?a8Q?!CYZm9Z zG=Bq#7Q^boj&=_vc3jqMkqyNqzF)L>*)J+V#|n8$Brchuo*0Vh2g5k1{#=){2i{78|@&39GsCErL+49MDE;s7nz{i5Ft_ zwXXr2$HxeI%Q^Vq z1+=wdXvsJ{uopE((sBuQI;jm(w*epbFlpt)CWA!Tbc2y<0}(qy`pt6q0m!ISFDi1I z$0KSYo#CH|f{elP%Dte~z`0{k>>i5L*pL@{X!cenH&nweX6&f*MU!NE<@+{OTx0v&fdEW^S2CImgt?{=pDy=Hx7oyJ0WjPQRX4;(vO53{$R#VGtU5|44U%$w zrp0Bh;QSi9905BJsFmV77ZL!y2#e_tU&UsmPj9K$_~nx>(`$LeEg>U&StBFt;>Kd` z$hn3otAsLh>*<+TLe8^RM1NvcvPzG(z!ZTT^K)c>>fK; zFWLJ$?^?25)q5}R;+fi0xV72PBehPa(A#vS!mPJbx-hMHGi!f}_kwsI zSA-s85T(Tgsbc!+mAmq6sYC15g<>H?;=3`uRzLafzy_K)1xV0Q?j27Y9AXew&H7W_ zwtjA6=Rki67!4%yvjFkb=coYMHbk+QId))K)@?J%(uvVaxU^pV3HyU( zC?pOn3yKNRC||lSAM{(q|3O&@_PXVICeVwf_K%M;^}SG$vK1h$n6btzV{8_e8w=d=izf4uG4;ZO*n#SoX~$Sgd|7*I6smx%Bur3V zKdw*^nCXWL=q@JX?cKtqpsZyZUFKGw3MD0-wI;bFzmk2|^`SWs{9(lL=AI#fd+gvV zPnyhaYvk_+G6f()qj%x0h0B>uQZr-}WfLCM%$2dygZFi_@FRexJF<1xCf`W5#=`v? zBxX{hq`T(89(dKeKfUqBRXSpa(^sFjIVh%5!N^f_73E2_Mx?C`y*}=oPkF-%L=~7h zyy_zE%5qbRl@!$?Sc~z<7v=ssu2ucHg86=g{xG}HZt%-(tOU%v$aT6V$r6$HHjWkB zCk0lLs!2#TS5oOm$1e!84lY`FuSCjLA3S-E?`0G9CbbIcZ6HemI_L@-ij+cdsVs6b zah}-~DCTfx*Ha7NhHi6UTw}T^h9G>vzl2s95PfULF(g^j98QDYl`ddr9?QjN(KEIj zMipsRGbU7N(EJ{}p-9@dkPPjaLCqlcsp~FRVm=2K-FEtP7nkRvd4b64plRBtL^iHK%^NMO@ zD!l0wlxCaIU34Yx{b6P~ybWVOwpA;Jn~%mAaOc39hcJibEnaqWT&q|eWYrQ8al@dz zQVkKQIBH+#XExRgCbPylkxRZ4c5P8sirS|I2pHN*14=~PL+u}z6(vam^hb2%9~RHb z$b1pZ6&t4!V-MB4J`q+2l2gZ{Te(AF4dKuAEsk}p9F3V<=})_?gUZ&B)}{I zO4_maIEMPQpnHPvo<}a3Akw>iZ(f>-Uac6-rzT2jQY!8TmP>7da6t*daB57qut8E) zSkBMwO3kfMsW|H>x8$$U=LaaM(p_hA+y!f1)R<8T+ridcpPCv!Pe=%zi(gE0lov7R zy@DQ35fPGg?QC>hm$UI#jRISmx1>x=aA5#Eba?Ju_k4ftjkn(ba-emmXl%jle>R2S z{=URRpb(+s<7D1~E@a6&7HT+;4D?gvt|h4I)f0c&s5J!-4|BayJ}ME zrg(f*2Q-kR4hL*kpH4^Y276Sl zOTDfrbmS|>Jq{5}ViiI9ep)))cr=Fm*zQ+bLM4fF@664uC$T$G+u#!n5fDF(QKv_- zhs>j7l)^UGc@hpVf`?Pb96xE4EFQ425UpSJBuuu^*{1?|=i?GIF_!7Gs9IehuKKCH zQSGg|f_xVxq0hZ-98I1nH2`;=gV_(~F2%WS&`CWxbOsy$_#;^_~@e%|s?L;Xpp*7;p1R?Gm>ZFO`{lfu6tI zQTY1&LKBL@g_;gepZNAW#?VC7*!3rfhs?Aqul)&SYN_Ie z9Ju!w)Zj)~*=GrY6J|aQSwR)?dfg*FnZ)ndD@LDEDSG&_9(nGIH1TlAeFI2xL*fRC zHQcKP4wbGti$M$N#SyBM+joo^uEyv4QabKerw*;T;TFjapKJg3|>X7HlX3H;-(};n4M-90zSEibx}^%<$T$RNFOuR-{pqLU|GJw8A-k zxLY;3=x;fAy84Y~a64uRO=9?|V_Ot#WN>dg&tnNMI>&_C=`Y!*C*UVs{W>m|^rHkR1SlZo{tp`O_m;Z3wrb^_iG1XChCh$KQjTC_MImfacw^{D zQQpsgcUrI6t!Kjr6nBQ;TJwd2z!5Ny{QV!f-EcvKw~GzYQ`HKx&}VvHlHkf)$|+ zZw%%mYbCrZ(5RW59oT@_M#_LI0x!N_oWs{#EJzqr&fzkveb)W;+_mN4@k9X>R@=04 z@Hh$y8j#OiD9}n9ufjYW}WOTYb*GeL72W_SM5XC7}ELK|D&Z@4&l1!BZDkP2B~PfwKQLkvzSe5|PZp zR_(RgscQLxpPS$2RN2e%SxG9-xoUi)zT-j=y_H(SGTX#g(uWny)m!bfPm zz2Yv^##+zbn$8|u5~&Nf;#+M;APhv@VJ8@rHaH%&sRJ( zgjfs*kSV+9jSxPZN@#3{Z4+JBGutJyr4fTYjI93Em<;>q_F?sU7SDt5RtEwpVRQ>hvfhHk3eQo}d+4 zGXd^#nTW`=9hmsGGNDiFW=VBw=6RmL`-FHeLX62UAAlZZFVTKgDJb$K=w!-`zD zpF}#&bV3VJl;qBi1NH%KD?sO;=C-RDW{N@WfCoNsL#V^4q4naFA@h$q30(|NFO-bw ztJ!#;kI&nME!sMVCU&^Gmy_NX~3Jy}kj}*)2wL*u&nJJay3d)}MYcmeLd%(z0f=Bd_1G}MZ2j(S0 zf(UyJXhQYX&*gqrVK#47n75mV1$a`v&0TNM?REm;@KlzL?3e7{Nyv*Rh~|o6DAi=+ zOm7zdYSjD%4puqngzrgo%!U$f`gzF-GwdrqX`reqbDSx0wSU9z^%s${8$G-1bjXyy zHgI}AJ<#Svn(lIBYP0Cr4a@gGm}qCjA0C)X8XoeTxyR62Y_x6Vx2U4Nb(R@*V6(^M zJ2w&)wZ-oS^Lp|&$w&DsWX?w5>~qwiyI&t>hCS&IU}Ny?ibZY((SOh= zJXp~?`%iwLsZQH?@=gt%%+en~#O6_Xp__YiKpdp(3t8}glP@ zvBt%loAx8fIsOd$M^V$iT+ScBfA<$3g_ND^XmV&;wVds4Jd3@4|9?K{JiV)eS^3bn zuyb=531_$^14pnsQ|s3uy7e=P8{rxO7A*nP&gik%4_bG$~+m(LN`(;JTI3 zr(@P^@|e#C>H%ilu9ze(d#!;`cpsSRFhXaaV|ac*PvRD5wx&@eKMH1Q;GhM{gRm?q zWGY+O58Wj=8^Pz}pndp9#e?!FH9(^_26bGC{^BzcEbzT3OuD(w#t-><@pCxC2Xj~# zNz}8+j#I1$C^;46g>Qw|dH(5IU!K4xxBjv<@dG~=x>5{X@D1yiLDU$y=*`Z2oDdjO zynL~K(*dzfsQ0Lys1#m*I3W|H2S!lktrb}we_CBrAbnD~Y{n zsPN!aElmw0HtQfs`pb6th_aQ0WFno(h^&+%j4XvBMoKEg*udi=UzF@W*x z_Zg~WLQnpWL2eWBkVp-sw2&y1F-|D4UM$Vki#i>b84+LvI;6ne-Q10=BcJ8*?uxjG zGX|l)hkQ;HaPaB8!ns#pSK#6D%A`?}J*m;_%byCV?jTqD!x&UM8wP~olRM~E?pSzs zzrH^;%s25eW<8vs@hjHUBioy(Urk@XT@l@Vlt{)QbO_iZhJNkg z`ZnST#Kh+b-k_OM@xPSJXb{df%Ay5P1QRHleQJgFAx(l`}rI`Cq}NXWlDD(;s3H z3)Mvhp9Y&JrU9{nFDB>-tQ(o0o(n&?d4_QGvFueNhR8eF^l}5{f?8gFp-G+W>;=m# zuJ>`HYsA-e;I?}YdY)&HTr9+_4mT)EqIf;9pb8uUXly7JFqVg%g6S{iv0qIB3SR_~ zom9tKl_+MIsO0~;73?y&UZG?$Nn-6efI;Pz=&h&u!vSWV@JPcTNI@ux0P|cdBDN4# zEXgtO#m9L1&h1>vvm{*t7#aDY&xD~x8+Vt!gG^8pm2*zAm$BeTo+%edoL2c9S|ALW z&VRD^I5G-cT+M0pB*FcQ*pvmc7&Aw!V4|G4D$#CK!8UxlaX|7F-lX;Yhipg1a2UZf zso_Dn=imq7UL)5VQMAa*W;)yD1ud50x?5eXJc>t$)`RV9$%9OrL#eZ9SH>Y$r(16t z%-X7d+(-Zw_|?JPEW{w${N+w+lm@!W(IQZra-mR_S9tw--H_6qaQ@^`g*)5*0@s?M zWopq!{lA5p5fUYF`K#h=`V@zuep-;o4aPQxE zUQ9tH_Deikt(*Dyxw)|eG=oO^{I5c=IW!_%vAMzaPImF>e0wG)lgKq;ga%mCa7h6yqJ5I)JbJF^m03SXgFkqNWN ztZB%1Je7P%Ff~S5z?7KGfv$`D1HiPB`7yGp4^i5%_X{8mt&+ZR_JPH3ge)ZQ0`TyF z_;~oY2yYSK|3g*tM#$nWKGltig`R?04gn=6#GHmhOkPn}RNOTn!NSEYF#gBhU%d)E zAW#m_*CUTUXLR|1@4{QX>RUV&epjqU=I%od@`dhbXTY1Pi`{im<@m4RwQU1p&;%s-FCyZR1y~ka1bN|xRhmA~`Cb?QZgN)wr zt&QsB1;ycG*>4m6C{Z(MiWfT!36!+7ZF48ScH17LIpk#c$;TP&HrsLo45DoGW7f)A zA>?w=49sW-wmngq)f{llyqUI7-8(t;Qs<+3VA|A?T?;brX)o(8kx-Gew0aP=Z& zb&FUcbBZ@<%=^-q+Cw!CPkVif0e577q^})O?=XJ$SNJa` zyI@0s{l)rr7!G%#;+*yUS*`W?6~SLq#oE$p^6Koa(p|<XL}9yI zTz}nb$J%=Oxa9aV{8&TxpINqFT`?_;e) zMqw=acVXw|WU`mxi{iI$pN2xdm`lk10T55w`oABfn7DpLD^V6R;M{F~y39_~(Q&oJ zOkgiw3ba&3iUSFCf$XW{`E<=X=BG%-i0O!T`np$3Oth|Wlx*;AW@CGu%M~RA(WIcQ`y~NA`%>b0M7)=D@Oc}`F~+TDxV~QCEZtiohTE{vEa?$(7uJfl7r5&x$pAt z)aTm0J0hsR#VAD6@?4e^Q|kpzxLDWkUR4(^(n*Q4g^gB51Nu}$zbO4&VCf+dz#*~P z#w6%P)Q$-hCS*%I^7dr$^;|8(^qzD@%n^8WsDAtPA)(z~FqmArBJwG$u3!?OW5t&HNHdN;sY4+V#4?>-1otkm~SR2J7axh0i=%-n`nIn=B5uhSE(b7tP5f z0f~>&m|kbq!f@?6am;Bv4dFxtcZ|~(Spc+5zm^uii~QoWBNP#AJqx~5Lpt9PHW6d2 z`cg=Fnjzh9&(d=0^&FmTMsXY z#6?>}HtUk=_o}1^tp+w4BFJ=xlxSTbkSZifOfzqTQqRR%a7*(s|@*WdDcVuZG0CSBgw2O4|lJu^T&;s-!8)+nt#2}VthFfCd;1n zq#BqvRBxKT^Pi#qw*_=U0a=TIu9Zz2P4uu92c0}T1J^^Mi5J>bE#ocsI_L51;>K7Q zfqFB$t_^XaKk%7y0X6!2=fZ?z)6Q}fNsV88B4!5@?6AAclhyosbxAidpVnDq%=RQS zKvi_UPoUd@k**vQvwcnzVD}aMHl6QAB><5`y43pgcypkIDSDvyYum!|>D)#1m_%S3 zWm9t5FTxqWgbAji?b-9|xo=B7VjwvGM=yCnUv+hFo*~f-G z-@1cG>P{^$AXSQV=yTPR?4cM{%h#S!sk8~jeZPsWana7|%U3-*O)1q~A<54`#%Zaw=x`m_#z{`FE6`D4cJ45K+J6RVLj%mT7r>zy6}5JqpOCm&V`+O3*CR zi3z297)~s@cs~wTz&U2e`U#~?#JQvb--MwrExD5M3iWEKpQfRvDLX(hfh^-1_WT1;qHd>CGB_ZOTa)b`*A|l} zNc~aAKDzYcG>$T57ImiiRysYxQRVu*HHlCvP8+l8K|RD0Atn3a^;n(9<0pKd?{)c! zF4la@KLF_p*gF!OP51T$wrMf#7nLxul;VQBHQ6kOw=sq5)w=ZB*nR1R2;jr7@d+}{ZQyyMk{4pi;#6%zEn>>MohKb%f=TRAaq&}wv>mlV=W z;qIqeiFnnYmMuyALByD9<;ER^EP(edxHXa|A9MW0H7`^q@bq2K>+{tpP>;r2Z+iGtP6ynHg!O|rn0r3DA^MDnl#ef z?sN9=iX59UD{P=^I5qj=x4WKk_C^8-X3xnC!VdT4i_s^-sp$fHm;c+6$6fdKYL_U#-KX&9?-6_R zW0)f(U;kg8oug&%{&1fYpC^w9A4R8V+r5A6-#%(Sul;?vt%CmOk-ZV)Xj0aT4n5UV z?+s+Z==>@1o505Z>37C1soQ|wwuXoQa_Cm%9h(eTk8KB6?5tcYE*l2hC%HGe@*B#;i`9Vk%u=4 zFh)d(fRNlpG*gIL={`S^p|%$JbyR^@5{{2i#FFYz??r#OYxRq)1~yv>n(z<-9mi<; zy#_tLwN?D|NFjWf8W2jZ1|e`0;7nRDx|zmmR2oBd+B#ba&+&-@tCRBjz~JuD@+HMg z7*S6|*F`;)-@T5>$a*`fM%=%qC{9hvtAp-M`x62qgihS3)}-b4r(ykFi6XXh|DipK zZn2}2aH59sd#s*#cLM>64$yJ%?~a6?eglCHmWE@dzHRuJFbSw@%5tz8ogZ;;pzttc z4MXAa(?&n2632#S@_H@EgpZ+LlwP4LV0yXRO72|L0<5ZTqoD-a=2?rYjwF3CnTx0h zXPVBt`@MtyfL+3DVzf~)8d%`^jY49|Ooe3W`QJl>=jRmKc72owriftK4fgbQYR=3@ z9{rqJJejnbVX775-Y)(@j>Q2l2s~nmm>76?(PH>PnHBhGS5ychrM-)Yz+*J|=c{9S z`?Zc4*|I%h;dli@^D$nwejTl!LyL_gG`+t6dw6;W0}!#-pto2v(S+*=h+Ia~*GpJ{ z#R2-NfP%m~U;`ATz*udhPDDBN2n(e3+z3@P%zFcj#ReSBvFdhSr7qkP^V}pH>k{>q)h(`|MNjKWGA_ z#$}Ejqv^LD^e#3^R}y5kJPsPJ4X3kw6?tyHPFvi5YP#+Bjdg4>9`+T&^t_bv&4ncx zt%=v#N(+D81>6{7_I9y3a|7EhiJ@0q$&-r z1EVL*Yz_Tuh0#$Lk&}*o5xKLI2Tcv7VV|Y+7L9cGRP%Te(_mWu$e{4_igb~1`LE*w zm9BFsX9kb0pE8qbpKFc(hP_EfSY989c*a-|_uh?Zq%Wr1z@I`3kmq5Nj{!}}NRcNIwqn_j*p|Ls9{gqo8=1u~&70Sb- zOIE`Y5HOLHl>iZee^B6{T>`5&!4#UL~O3bRkDoSbMT}cQ)2u+{?Vi|xzXna=vRw*0-dD@1Y zHkK-G{xn?|ntz>pa?#>qm#^$bdA3%-_i)$|+XxwG;ksP|7nJM*(8Q96`4tmFwc- z_`JapTB{Sio!bYg`_ybWc+@K2hP&qZXemjAop#zUlx86rk&d9Hh-BJp326zbC@wBSV=-gKGr zA-DX35&?48p~x(V(!c8uqg;bTIn}?9-t0o}p!YYTU+lAU6#3`dPfYPt_)Rk@wrMbY zml;I*b>2EU?j8@EXr)Y56T;s<;A5l9*VH6ncU5|NM0vkIiO;02N}=*#B?%9OCFZ%h z!Y=dO^Ew;#xskJ{@EEPth3!E8VT!b?Hb!8SqiOK1EtzN{GNQD)1eByEJE4_h`@xZn z6@%%?FsS$(c3;a5;nDHRr@H5@x=p90n+Fl@iCJEY_&%h;W(N(LQ3sBm35%dI%n&*s zfb^M2u#@|H-BFUO$b1^{|iI=pFk*;F+{5e8bN{By_<{ z`6hfV+0A&cYmFTCq}Wb?$$Q`VV609n!OkO24AOoM!y)HO6D` zkhzp{HehMi?6wh)DE~V%@szW#In32NQ*aEtxC%H(LUW$>I)nWGeHsV7eRJ|N-9KR0 zrVS0Ibj9U2 zBb>KG>cr~x7SKDtG+|umKfU=E06r*MogEqIA~KSj_Bcxnm~V=|uilvZRy?jvS?L)q zxeG0YN-$-l$B#t4imMzu2cojBj#qmPx%73S&%>0r3Xp0(_7q95M58XXOwaKCiU!Or zYsOy^`;v*Yt0s@vYqkvrW8x37Mxt?pLDUvU0h6Vb_#1|-86jM4>BLn|HL3nJlX;=n z?jNf2B7TnD(t3hcO}(`?DD=PlbHjV(lLPJ#QbgTOLrQ>&v&+{NI9vV^sQ&l=tzA?F za0~3Din+z!eHV>_;#4POf{hnhQ_uA5R4wfaq`X;O^oDy))B)AkCc<%^N zrQVcZsF49wviz-mLF;eIfPH~mU(@NOFbxuzQ2*bsMMEy8qxClf9Y26tJ{-YR5{XjQ(T_B>L?7`q`bp-iJr0 z9p{nd8IOkV?is+iLFGzY7fM~&y3akSxD8*#GTu1@Q4oi}f6aSNl#3J)68#xr=CBX) z+gvmvEiF)?p>K+Z4y=b7R7Yla9x=#`m>iO^8#rdhslsvZdkV7SP@ULy;wwUTo4u=M zkIO6#0n5dHb%zyv$bZzS2f2s)`C7@s3F@lXF*hf+kMkccA35CnA8%JNa;n$K_Ix_* z80eOrF1k6}hru_Ps_t&D=tsertoI0d8AY>nc7)Z8rUQ7bAcI4YY`W(tUfi>2l$j4C ze{|T>4F3j(0o4IZxTBH+`)})IYl$3X_(7FuJcW;$oll`*2TF+H zVGrN$byQnzMzp-C{5*Z~FN+i2uGR%cL{%m>?#Xi&Zqj;-@$qB`aIvBJPP0r5i2g<4 z-wDi7)Lhi+$tao`lSLFk8AJRvI^X-lD2=kA$zH;is8^=P>aygfkJ)e+q_3+tv>Nfp zhsZQIn2OWN69kSC!^4LerbfUFYxw<8C8jNcsw=a;MRl7hJh-IW3?SQ-T3YcYW0ttQ z{l5gDx3d-6EShpl>7nWOhGp|3L%;0l92~K7;*U#Dje*US%_nSg@h+-re5=B?;MSB- zl*4=a=oM7ytdb;H@@|#(lZ8m}*rExGsEW79L=yq(`~L*vFGq!~`Jm7rp!zOy2u#r; z{V1Mey6b%}IzXw%#;mKWXvDF!oDToY7BwWVLQR6htYxAJ4-o`r_&<8^6Kjk+&7E(c ziAYbb6hZ^bTE%bjH%!a@vQY&G=-^ z|9ITzFU6W}_?q88SpWM-YztqFzdkE&vih1NNi6Pi1_+Orz9wKp4 zJ&>^9g&zf4z4_}(e`3u+4S2>9ykkIcq@ zs$E-f0{Wv69ppK!{8}-{@9#)oS^=zdc!R8-so(Yd<@(Zuf0tisS6d9UlFBl=`RRw? z(VqBCE_U28i3g53L3zxy$hVhr?L{KYuE$hCj|6-apljjP1Sh^8%tL3vNJI}_X8cQd zj&%cI5o1{6DgxorWJ_ZWOlAf*iIq@QIdhXZEapAat`!6JJG~hw`so0pN*l%qdx)b9 znEm{8#O&3ydN!s;qS$80swEyvjk>+u&_&_;k!l5zb>cFJZR+kp@xviB~g%ci_?1avwOZ%}t073t*>{*I!aI_B@cEZK=zS^LsiG zI~df0pwfH0F!->pmC5X}o`>VI&B*ZhbO--=j=zEY;_Mto>u1k9wa))s$d{FMcEL4l zzT^-hBoT5OzKAA57A5*Ff+FsT5wP8}(_>n=Ag0&N&;Z{!0bku;(lRMCL!X{#yO4zs`TG)TVMmj&I_h zWN8Y*^gq@9*BN~=gc$Hw;#oKIs$Zn=Z$W@GE!({0zv2LC+W%E3$m4G+ep!~eIL*C| zlruxX!mj1IZU+Aw|CAFe3FuiB&Hu^^g{`+Rmj6eoVI9F+0%PK^Kk_1JqSfQ{EBk^y z0{@0Lczc3%r_CwURSUC&Z-rD&xMTfqt}%VCFr`=6NtoRlUBN?+xz&&`H&2(#S11NU zAjoV|N)bJmiciI*;F3O%<%K+WC@uw`gbn^<2b3Gy&fo;HnbaX;(og#C!gTX5NoEt6 zCe$yQh}6pC?-2^!3Dw*6NJqSBIvWY3ll(#{g9O9zj=c9vB1W*YNMX(N-r1Oq*xrb$ z`m=Y_S!aLBpfzcwZnMNG(qu-Ou%jsAVB~r!A_&&uJ1QPz2+iu(xD5C`(JUy%TYA3`E8Xi=+$7Otx#*A*F9dE|z zzgbr@`_#)=oo1Pu?K1txuzxT3zfIg%v(T6f zXg#~(V-Vepcad#kdiIJ8E$47S(~H`l?b~PFS7PIc>?AcitMe~w{FCqfjr=i|vkM>0 zKSK0{J^`LPQXJD~;`?0Of9CQ3HB7&E@IUqi<_o(xPCDTS@;pXUbDjU=r2p@kb-FTr zac`7~fxQk!+xG*G{$c8+`3U2uTj(hD#;Y<8m-B;H+%|)Y7y=Bkz~@ZVDWnQKYVp%! zn`lQJP)da?lu6k;I43f7S4@4?tXc?DdM9kuWO+Il1j?7$n(&Q$=(0J?o0K&gPxdX|EDtIU_>~*J3)CJs6n!L z>M4r1pHQ`>7%`bWuc04b?zP0oUqr@wUf_xHI&<_eRSMr2+$!t=3=f+GmW{|sy=E(x z&QHZDp`RAA@D>R}zMO8z5R=ZVW7gb006gZwO+s)8=`TI&d#EWNIXC+TXNeacd0bZP zj6$RMPc7>oenQhgR?MaF5CH}Jo8$fiy+{1EM77h6C?Wm6Vq1wU*-oGS>ZQc&I z(b@Hb^Y;8Z8ACGEgML=yL}2zRE4PW4%Z8NaA#z)M>%bv9^l;mOhf=^-wuu9XP{?#r z#<9$E!y8P()5-wAngt=aXVvHrA*!VEuq{h3eKqNXh=3%6oQH zI4@L&@Y6%*{ZC8eC>7Mp@7l&GF$HuNsE4=v(-{`GIrXvYRmV#Z#ru`v{d#hDcbcIO zF}wj{T-=-bt-)qa3Sfti-M;x}mmfuq_|5_DIbi3KRGfhbI}}AReeN3&29VQ<$p8_} z%wF1Gvnod2;BZ%>XgOB-O(!HG6Ayy2n*f&mjQ~Orn;O6Zw8Crr#BW59lV!nD-BFz( zkMvRDvADh~)vE8AX17c5j{?S~OHk6zv<=u7Sc!wWJ>|X-#vEDwjg57n5^MZeytwVr zSXyr1g^(Ky@zp<_F&vESw4pa~zNND*SE=K>qdL^Jg2h@(Sp>OM{YECCns|hLg_}=B zHbRypu1wj?fV+Bj0078+$kg0RGd%0Rdqg7quG7{eW0{s)(n%L%1X>@RSWI7ZlGBS{ zBH`SWC7|NAPnH&4uHHV5n=|nssThC7OSAEoD~hMT^G@zh&M-eux5|PMViW@%(3@#A zBUrYCQ@H!YEBnJu>?>@zs~-kr;n1;gtUr0mU^-7MbzHZXrPuxjSGjPg+D zE1?~|-)qLXMqsL^M4F;5r`x0e$`qJE0%B?u%6qsPj@1mB$DpXG0${9*2=@f0-&@HT z;U5~80Ru*OhFF^>3gvF3a|Kw9BXAegjeg4^2HumRf3p-J22CFWu^b-8wmwj)uKI{8 zpQzENo3w5((0c#tP7$$r4BOjs2wiQ2hoJCbm26#yZCiB>EmwqhysayU$Yxz>SBcMm z-B`PtOy`-mo+unL3!v{@NNhITD3W$YTnE0 z#toZhQ5g#|{R_4^6mK*TF|%F#Ch-{GegfJ3s0!2&;NQt)mO+Xmu0IhGC$zdHb<7$3 zZy8Jes6egfr5A=Y`7HC5TJ`$a&~W?-sR}*h%7#LGt?=9z#M`da6aWTJu`riL(i##D zg>r~0Z$HGC#RGVJ61t)=JH61MNrxaAA`6()h*~oZ7HVdebdv7z?~Oi^3D@wTyI?pn z!Bs@wn;zZrUjey+C(oIGln$btZnDfqoUwxO)XlpXTL`Os+gtm&{1EPeURt6&S5zjk zzgKf*n{S3>&%|TFf9MZ_>gDY!r1-;0)Vwd+(kvEwC<^BmUKu4U&^&he%+{3NmLBfv zbn;}&s~Lj2j1hzne$B0y=J~@%lthD`m#qO(PqvvVqfJ3b09-T(J!x`%cxbpbb%1Lx zdYvQ;z7y@yi}HH(7eak*7o*344$q-qjatK$7=ec|e(}-Jw}2^H`LdnHvKsUl8AUi; zx(=aHK%d3qgNvs;Twhh}q1W^w5;?f!>E61+72+fBONqo3+_=SE_HZ9P6Mfwg!JPVx zUQHb*`)&?+WXR1bL3ni;P1%S%S9sINE6W^!R`^}SaM9GG*UQAbWqP4>Dem`VTi&^Z z@TwG*@#M6KAy!*+G=@WI2<>y|WMVD_n}7%D&20`W0UB9u11g>alPPr75a+2W5CX^i zjbTl%upGW^_#r#}^Bwm(oQOPv6Os)vM5U53NpW|1%}0*A7$KS3fcqIB^dg z_!Zh1cjZ+r8s2jp(vbN`VmYKD3pD%3?}v(!^9=+p3@B4=r==w~nziV3G{MKzjkyyM zXqz1>BWb)E(q6AR4nJtY`K4pltw5q0o>YgnLaQ$RXOY%UtF@+?*aZ?ty=9 zq3?tVp>yQQ@N-u!;_cqz(?ub~gHS^}$Y9}ye&aR>477;mRZ#Y;3JtA~hC7O#1;t2W z={EH&5JN(gh1-D8X&15!d)J#$6yMOTbXgRwFc&szj?X)x04F@G^)c%wSi#v3u2%3k zt)>jiyHYHhE8WEtX(+@5#n!0893T0JvnJk#d~EwhWZkkM*pBY1OBBpfm#OT6GZ-GE zjX1{BPoo+X+_a=Gtk8GqlE-L(wS9&+R%}24%n>PZE+6#;Qi6tk&AETz+yAE>5@s>dB-iLMw}6$A@U7c^oST{&0NuW2-U-`8gWvMi7uLDlQnj}ZeXgL zKk2oF3QV%AgWp~_Syd7=U_F0K^fC-BhmvHpV2I6>^Qgw*&{_fKK7)K|WX7NEwyPoC zQ-gP+vrLYbsRB(#v${-(!@H?7SqLd{FDcn?hr5K%iaMr&PxM`%1oLAg|Lu-%@XPd1 zry3V>%~5L}Z*kqjm>tJne6RDh<+`eAxZF?B!r{Qs-B&XWmZ1CO4hiWCnE=aJ;=|$> zA$_;akAp#sI7xq19S&T2gQ+Hl|oyL^$%hL`pY`l;vrA=i^DfaCt;8j<@v_KgeJbpxV+p@cgTbD zUyVa1sc(|3)EYFi$1t1MCg7~~)3z!b30V(*PVwrMZCY@(1xfU_&iAu{`g~7lV+Q&i z==mbvhUy)4w1h?KLrnu~)tQ<9BA|YgiAFvw`a6Y(;4xP2>f42gYu>v-KwxdMEj1wk zAG!ksAZn1{vS+)fMo}K7j~rti!{IIOV&|~lhZ}YL>)XKWZoy~FjBGtJ(7=!Lk!Y}C zx5g+9<1x|P?f%rCzI{Wjf$S~RtV!`y4zE*K$2B5_!_X<9s9bPBG5itk+ZyQ}p7mI8 zW5Bll6wI1rdL`3waNZa*1+{s%FmI1Xe0UsV_A&utw>n@Y&``Uh5hUCjQ(E-98>PgJ zFXlMeJST-$S+F*Hdn}A|7#2Xo{XEE992rRcB(l!<)x^5No=AXWhzm$__LN_M zoYKS;QGMo$s&>okAiWDldxns}7I}J1v_Fk#br=mxW z&Gh)neE5^6bJp0U=|S&Gz%z%mimhyG*yp z!*$P0-($h65h>I&JoW*32K50`9IZz|1QehENC_*KX0&KYZIHZ>dInOQess*b){TTF zsOc2`%yCGSj0QYN6a=$iw_@##k1+k1X@;vKF`U|(>m(1+OHY9wC$D5-LLBaCO6Y4$ z*?|MpoVSE4)ci^70|5AJJ}N+kvy^_0@dB+LM+bA9XL_n2wfzPG#`in6K8u--=paTb zWsnhozWW(E5}wH};+&r)$*ilu$$S0e4R$Ch!HOX|HJPwSb`S?ABC@{2q{(mFr#M~# zt1*wjy2>yMy2!$;<-@0C9D5k$T-Is_z!@}mG!&CD;;gaGLXZgEGf`@W76GGwHpu6G#(^{QPUv<7nIcBI zU?a4}EO|_Oz0R>53VJmsijdzKTOJhWd}+LRKLd?26tSEXUJf8;@h5EVPJvi!JB`%G z233g6$g1cCO1yZ6SQ3O_gl*D4v7bbDR^%})w5^*t;}>`&Z5zFwy~I=}(QNKz;<&la z8B_gac_+3^sL{0rPvQei!L6+!S0$G@-DlJwAEa>B;d+)}C)cMNZH=zox;}Qjmvyqrs?P z#zcd&wVJunz>=fbrL#-9mt7aIR@!uteDS`pqIoBxQ4RICX<~4dGpt){;M%F?e4e+R z^lsNxCUixd5S+iYs5G3^i$80m3LfTm%k3=f?u4$~H1kgW;qOMf*K>WpxlRWTqvIj! zJo>qhv9)kAWYHzcE=1Kn@ENPCTc|AdhUS)Z*)yxq&rNsW*@t7VxvIu>ESz_@Fv@Tr zX+U`83eX9ExjrUCKB|wIVX|hI{-YhJFwUJ2j!Uh2Z@< zC6+Jlk%T4$lZ*FLGj171ywEQ93DJOgIdj((ULfCPLnd~PG?Mx4E<&Z{u?J*4B$($H zJNLWkgqc)IKTP`!r_)({?k^IaRQNPJblKQUKnQdFnR#cZ3t_*M#*dtqQE!zueRXRU zu^3my3F8PiY2ca6|>5Vb1Q!&7(kA?fex0!2gx(iB3OC1^pI}|UyT6~;70ts*VpVPt)P8>rG9ou1b<@(b#i69Cpnb!sl=^f5RuFy zoS7|J^7|pGsS+xuMoB~UF-Gc7vk@b=^c0%ii7>$aJ!@uu%?>shC(!3^ua!a_$U>`1 zhaT$$nwTId$-~+?lWq#&jVBNJYBzp?frzVwqRXybRZ|zt@iT_#7!reXiS#TD83sN- z-Rd6tZQFf@rSL2wHp8?Bp&tdFh%(rWC^ zy2hJy1aaU5IBtBKVSJrlO(Oo782A{038Qp+Xl#k=xJ}P!qS3)TcI5aMYwP(<=s;#oNPnem4}t#)cs6 zppOIXb-#CKyQoa3<+s3vT1}nAX_j!)A6#MUJRe&;;wl{CLX?`Z5WPj0;mVb3wvhPM zg?*3t^8$W+^TtY5M z{+nSnjCD6ZyVFv4T#KJz(d&!J%t}$mRjh6h^#Y*SwG_Cs+6Njts0!c`n zzNf%jqSX6aBY;1sr7T_Gb<8{&VOry;KRmv>rno*Z42Hc{T&$eBUoe(J71H!ZHnD|( za})b^LgM(kmgRoF3}-ubt7un zyC(L3uf@F5vdck*1uC6f%uN+Hf`25B=_%~75bY5mLX8{_Wbh}6>wpVfYBn^q@P(`6 zLZ8X-IhF4)O5)!kiky4?u;`0)p0RKOd91ylZGdB_lp@Qs#aymj4=d*!y&x_Ld~5R; zk|r*m^Xz%K`t>bYLL@pX;)$1bQ91TmLh^3+Tbz&`l-W^D-Usi9u9PHt@g7&-S4JX$ z=oK)6m)4urNKTQu4xYsADp@mM(d@v~b zn`k|^bo+}{QYd>&hHGJR;6>2IMVXkKdj$QsHT0OGTCp|s%-M+7KQn+`ge5P$&J>wk zVaD1Eul}=k5q(X@E>KV{=e$Hnb|Q5I%w$s6LQIx-*x`_-+=c5q+oTsK0kwc5&I>Eaq{2u;j)@}$F{fxK1SteMgi6mo8;dvHgFzXtoj<{ZQ=wDn zhBf;cD*LD#{kJrGRUqz}2lAuj-s4J~r-s;PbE)dy*kEs=kl!wg`Y$12#9XSjxBkib zS?3SL$4;}qYd+7y*>4%>m4ovBV7yLVpx^EV0`NRxndV}jWKq&S$Bup0bk#Fq(JWBEA40aafb{%4TjQ%P0KWY}AxMUXifPJ^s)O@b zR6{cY?>u(7Kg~?3;{)jvp<{EMP68aUPn^$57QJ#`$onv>3~jf2S0mnH2rsE+S90OQ zho0czEE1TWf;T)sR~E+keTgx4F~sfnt#+w!a%~tP!rm3h}Kb1V1=oJl|TE{s=CmWTMnS?qyY)Etl?j1Ci#)Q_u5wUK~XcUJR1h!bbk2B?Z`jX z=r)42U-qO0f4dUep<}Q>a3a7jvbZdvg>VrAn`R zWp?D6ox8DQT;%uXX)u7!5QrR0nSCt2ubfRp=Tyi(k>wNmmRPbF=QT6=-DBrKbY z6QD_ppe;>A!8|b@V4pMI9#<%EXARp(K}`1{+OX7F{wc21@;U5TjG3%6 zZ2C0k>O38qT7Jm{oe|Lm->XT_dP1i8wvYHe{j&CxmO&g|^f%8Puu>^3TcMg&=Aj_U zSG_~ob{DaViq2`obDU^+j$Z;t(5Ds_DbXy)g9A-`A?J67uU1w|r{GApstHsOYp&tQ zdWMC@M}v}m6}18VY(jH2dFXrauU4TxQ^80C$?7q$x(eER`3jvHj}G(?+?yS|#P$(` zcMG)w`Wj8HbB@a}8=bPHrmH zZJE&OnwV{(16LKCB5ZYX0hN$nwh@{4K93x36jsfk8Hw^0z^Y=1Km*#DM<$Sq(7Do* z4vi_Ddd^W^p3rusZ@pI1i`e+ffxKfE_%uMT9VgAO^jQUrMSWhJNb1rK?SbceO^pv- z&+<$N+Gv=)$#+g9K54d%AUXyCqO?)krUtf);H$E@eWc;MoW52Pm{55U+W~-YCFGvn z>}t7#ie#e^Xh^G4daOZ3(qO|R&;G zLT=xbUO1XHK0CDsW|avk-6t@5v>s&WdRRwl=F$?2qQHRjXq8nr@wvmZqJSgGfJ&PsU1#8ZcjgIBu-@0!UDjH&mL(EVVA%Jh!k-f>O0(u; zmV{|KAmudT4a(2E`;J>vYp^&h_#!s8idqj9lM<)bPrld}AB%*OFu8CKN>G}t$2QBh z#ZGYuz?O8IE9Uhw!anwl(xV$pBvB`jRtt+TdI3eSCr$;p80G_Ng;I*xQJbnuSz3##$tWviM!112h?aDIbbF z{Q8yeR6-;OoQm&@l$Hn49a?LIUmnP|jqE-HaG%MU940Zm> zzn{^jxpkDu3qKUuIcB|&i`;a4ZiT3N;B1S;q%MSG4rymv<(iJ(3u3*LQ@uqB4xPV^ zfrJ*-{sWXJoDq!7^YC(6V*7Faw)LQ&3mirV)DWPVD~UOq#ami6%*P{1Q4dW%J^jEdFwNmw z2&8;-s{BOcGS9m$%l8ILh{rD^k`#HbT3qpB=AGepVPDt#eg%|C&LpdAev#vNxA48*3=8V_-onu?fBLn93v@fQ` zsLyD~Oauilby;suSNYh+F&2(=;p2LJ`15BlD)C+}dD*+iA1FSfQ#Y&YI!I{^;tNkoNX14wxl z30{hEkaV-e9%@xO2^g$JZ0j*|_#Kexi@>?lvGPAj~CDWT-&)o7};0;T_Fc1#(o7_^quk z+niTjFq6y*#UVa(f>Qo{fe!+284atpdFEgTX6!aynHsvLv0&Km#Btr=DK*!C;b3Nb zSH!6#%rjzbr39q1%;-yPt3NZwT%#)<8`J*RC67t)Sl+*R=2gx>qdDxtaxi}>(p6~d zQ_sZLjQ{jhn+8!NA(sn~t3ku-DIg8m29&Q#Z%MCbwJqi5-sK zr-$UK`BeHN?T3yS0%V}}B;w<|&E?lCUL;_70RZw)z7lr518yI9G;^I(L-#@K z%zOiK((^_gDeMLC#5+kt(DxS0(DTz_Oi2$gf(c;r2ZlQSY*j80ZIcy440^=Aq{!-!N?Wk$C27FixMYSY|G@Lf z4;VRG-3gSC{Q00@ix-5~b%Ro@T~SujrUYIllSmPclc}>Wg&n1tQ|FgHmVy*Vx7~e8 zf~C0^M<^=lCMja$C_WjkXr_TBB4+%1!HYDm%BH9oiyHmCf{nPnloD#K5dXNKbDVId z=ur))?1g&0c;!TAwR2$%CO8gG7$yLDNe{fNi7!$rKAu3gs@000sG7}11}cO%wSL}M zKKI)dGWLA6;i;jKEw^VvG)vK4cW)U#zUZIdYI%sYt~~X|t+c7R^>MtX`>z8F7zb=O zlSk@r=-u{JbTCUbWh;rpDVcR?WwL3GB@b+#%@TLTvbjw{yNJ<}kd@W`;B4zE2i@R4 zLH20;8VsdH?S~5dnO3`Ip4G)>njELw|$YKtYx&ELz zG4uF2VW0FTU1q!K>Mz711A_%Z$M?;h%{LH=){h7#@ozFKQHTA<6Rk5LIVbFx@g$vy zUgG%$yB-u?-^YiM7l5$3?-%Xdrl5rx_2|U_QrUSI)+nJwD0o{ z*2PuXWc?0y)8~L|RwvhRk^O7M8hor!CTC(3<7|kfY58`BinK1Sdi<;PL8&CSc;H|596nz3%uZvU=+%YNc|-z!R2Sd5@xDES!*Kt? zNhV~N&ua}LB5qucgT!eVp~J~Sc@Vq^(?voZBHO7PLFzki`JEV(jbtx9zfPl-_FA`_ z1pVXD)r&}A8oIVQUAS1KixDX^$1o+}kg=W%9AtF6MpR4s5_^x+q2mX)f&{avZ~kpT zJSI`l7+`^oF8DsZ`|`;9CaDLC_RgS}%qTdfEL9O2i%L8e{W$iOn@=Y!_0HpU)C-P% z`P99rLTz6ioT=2ivD&tT-iPO&z9aJ<*nO3_e42Mzj)P6Iuf6Tb1abrlJKbwe=Lkld z5HULaO+5&fmoKd?Z_=~330dLUOwTKyfTt@OIO~Sn5F+_X>V~SPw^Pjvl=+BV3+k}IHb{E{vbEU=Ltz@OARW-WwTvFANvoDcgxe7 zU=I7$q|dp*!d`~VtajrpNc!~yT}^%>h0iJlY#Qr>A(3KHl*k;HtDK4QVvV>+6eU@4 zYJ7a{72S%++h{Zcp!C(*>S46Hc(ev`)&$~ofIN7c6*G_O3>oEErrr^Ayvk4votC_n zJ-W6JeCP?0%iD%qaUagRMBLP4c1&=YaR?3KJ0sisc5zvDvnrl87unb|cqTocPy>u) z(9=e2V?AYFf>=H0U0pTshuc+HT^vj0#{)N6j?FN6Bw2~#3jl2+Fgfjz^zkW<2}i|C zIo)lg77Zm{Xqm_D(+|Hi69it5RQE6&{A{Lkj!>EXg!$ z;X)h1_tr82SJE`YHX~6Ak9~PxO!ER#mqfwJo${V<(*CRRR3Km93zPNGj11>h3FlfP z7xN4UWi4q(a71#9gvlX9qVKP;0@E4keOC>C2cRsTXmd(vCut`GEy=|z{niPjaY z3C^}^>Meas9qFTG+~UIf24qpU6fPwJA?+Z$^m2a(Szma+Npag-S(zBIr6-&E9D$x4 zA4&k3XS;iR4^!Snq#-Wn{ljIPD|Z2&2AileM+?Q@$mk#y;c zoytD0{Q?*MtGK7pg9+t+hYZx<&T7IP01Awr8+;iCm{(<)`m6i%M!ZVTuN2QC}T2OhZ3bJm}qSuyoiTlHn&lh6WK0KsR2CfsFcQ9W)k#Qsx+c_Er5D7-Y)i+ zyP(U_M6HkwAy!d~vh5R`o}Fu8PTol1S~D|#&Cb4$k#EofEe?S=k*>S$YD%){73^L80Al^ZoCyJ*b!xU)oUAQXBtQ# z<-|-$I5QeeAL<>JxVhH&hz!TtTU3QoY7c(b`NxdIhrYo{aHvOIqc{pvjs-AD`T*}W z2JLXqZ+h2jPfVuxeCL62dsUM{f)EXSR4)f5RCdmy8>ru9G$laq$j?olO+VY7AK;r1 zd0vcZ=rLZt?ZK>&KU1=E$qysv-6PBzirdbpSue`UioT#J<;nvF$Uo5+mZguhuV@9Y z!_-qxzwfUJ8B)}bbI8KXVP$*ac5623^POa9{c&Z1x%Te~uSnD6l5EP#HNrr3B?H-P zUnF)2mDj(Pd)~$<;0X50P?eh(xnQIq%EK}qBCs*e;d$lMBS&0;P}`^N0J0)x-bnt~ zM($YIyg|!i-vmyZps=qQ6-G?Ns4jzS?av`tW9%2LR@}Ai^lu388o+!g({RXDpNN!C zxdDyHZea^p`(_wUWs?*l99F^lgkzvCEv$!m4kAY8pyKmzYKj1As3WbWR7LL#54+p} z%fKg*S$GNK`&@U#?9Of}GDokP1A;gjOmQAbsb$n+36TiOX7)p(TFABumoac8b8oE3 zWCmPjLYmlnSHv}2^A9P+56<&cY48+GEYp$(5D@knmMqUWS2Xo(?ZDjcX=Iu2jFb3e zn^;uOJDW>JW)@D9CXTmZP0t~r1${f`;K(p>V{{_^bx9( z2d9#{5P;_|yywx`0Yhd38MI2MzyvslgP==Uvgepaw0>jtQMNWSQ>}sEXA*0}=;!?l z?e8xtoJ7vTs{y}=C^XEO)$rCX4g6XO?*jAe`ckUzKkNu6v&EO>hO%?(jjLcuM8%_J zW9OEh(xv1i{6Ybn-{fqGS63@i_4Nk44E-}vbfb6t5p)*I3u8`BPYlJh zwfbUM+hfL$9X9aQHwJbAl}$?YT}eWWTU~k{x{fC=(!~4SDla6FJN}GQgS~8?zpn{w zqs&HDUJ55b+}&nGG@GfV7CYEd`J;34u($ELIEq>oiTZwbZXAXl;l+3PDu*NK`+N|u zfI`l9_ZrvXq|j;4i5bF+o%JTP%es)rH)ePwz#(*7G8iW~S3(u<#_F+Rup%Vnu#&YX zY9%>3;UV$9mOe2HFuWa^tmUQZ*B>d&q}iywQn_|SuQ07?#U^p=V?MCe!nbRHMMMAY zq35ItE~!1nj04-H0DZrEdh5bQIeQ}?mQDiIUbM0qFgm>`)pa;gYDysdq$YM~pY^0Y z$5|EbINn?9{Z{AfyNpOfdT$!6xJ%xGoGL$R3b%{v7(ezdE<&YxpIcVQX^-ncSy1(Y z!n`m{L+R;dpUW*Xksts70fhHLzM%z9!5Os@f27{t^y(Go1HaChhY*M0Y)&+Nw}MoP z?R}PesRhMrOc*ph0N8@!n%%Ij{b21Qupq>Itl@1_<|V(>(VkNLPw)LQl!EN|uh((P zV9?EJ!L%!Q1bWb?7k%)3Ns5z10l~z~fUX9KS(|)M z>Cwliq7GJ5d#p0D-h5WC93TJyIy8PsA@~=Qfa9Ar90n^iVhm}1dZH!|?p58(V{y+w z{@*?YVoWM@9p`PW2gg72w~|vyQ3E1rcaj*>O29b*(Rv$vSM`ixm!0mMQK*6KoL(5N z+1LsB)p+?N!5Cg$Zu$WKFf*N6V&A2j0cKrg$*(g81Mdw(c@RfqkPC+|49!Bx^*b@N zi!J~FJ~Vljy*Zd{b~o;Matyqr)r+3)qy#B643zs)X!efSyv@sx%iy8_ktyy5yGen% zRp0c4PeKbTtHNuJ5EL!x`{q((I}k2{C#+xq00``1;kJIy)_b9P*a0jvQNRMBK3uX? z_UUDDCj2(fumP_90kchHsCEQ=4FCWD0q_L?000NRwVWpXQ1}E7`rQ&deStKX zB7MS%f`US5_JiF4dbpPXhn9o!A&oYr)DO7$*zQOtoE7ja6ka1 z^j>|3n7W1|A_L-S)Mly9wIDCvnUTTzMl5Ys-MN$z;P0sdoaF(tA1JhTP(F?*I6{F%IA=+y+q@W*5Q8A&#CMbvEuVXrH?GZnu#d=P!5x;flz2ui_- z;?|s_xctwV5d@S`|3qP47^Un=esvL}Y8?5a+6>9dPv+DtAiHr1-vtJV?yN}*Bu0k+ z16q}gLlWiT+<6|(1P7I8VYyvrM$?j;Z@Y-pvP4D-QqC;4uBsTD3mi=ynP9e&kpN0F zbETcnLExBs?N<=aMKqv04A(T-LbP(cdog;n=0;Rg^Y&LAhQ(5P^&800cs2J2%D} zBKmezNG(4TOS(%ONsFS>paE&tiUtloJeMjJ@s3gL=KbT{4;pDKo7KzcFcM^U)m8jV zQDev@QiclD>;gAd&ebIE*va{1gV)AxL_c=~GFTL9$b9huYANjdl;G<@%m1C&<)103@f2fBLr{m=(%pf7HmxBBR)DYhJXMA zoP6#zmwuI`jMmcQTQw!gSqgdKDEVPH^Q$1%*_BJr*H&^3AnHvKOe)Oy_=HlHj>W}k zRua|C*h8M0Rgx?;6;H5MUsg9 z!qBx8zHrQi=Zn$v*x}fr`z$DuX}<*ufy3T}w3TcI<(XP?meY9S3QX_Ry|d9dCsq2z zIK`}1Qt8^`5$QVE!A;3zyjg-gzHG!B*vY(h{-@TX9jyOoIww#i(eu{U=aLT25fW^0 z2ty8|tpUdnDa2Off~5Lzmu0LknMBT|AqIGyR7h;wQ_^LHetMBD;Y&^~YRP#4*&3Ep zN-BpI%<$WJDn#y!kS?IVR|swd$;zAa{*Yiu283=9ZeQY-Ib@lFZ0Ynhe@c&t_S@NR zCGMn!lulwvM@yH@Ed{NB=Z~P+LGP~c3V0Ggf@)WP(N&+EaQZ6U&fG+HdlT^u;1hh1 zh1w8O4d0WDxNXV^LL17=ZhmanbR)JT{iK#*87x)~1&+f ze1aRm6@#$#YI-ja*XGNyj~-0pCs#dTrsxm^>M9jqZOWGDe2E8caizf&QMKSJa^3a7j`#aDS{~YFX8qr-c@@ghi3cek-<3gglz(cs8wV=>@fzAme!6C;000=3e@~CbrfB*ml2e&`~4d2`&s$Xly zL9bXx7La(I^Cf64IwmzcW8I^Ab+y zMe6@eAwIrR4$MnhIn8QHR1fE0clgrbG3ON{E*o|`^U+(5nN_9FuH)h`q8bX;qZ}LQ zXov7BL92%UFt(Mev)rT0Av0Y z&?Nvk1Gnd1zl3yR#%!mq_3C}5EtVQ&r|KukiP524B?XKvHFx%5KlJ{u;f4SJ00000 zA;SrT8JG9YC@zTL_9-+WCY(v-oIDuEtnF&o*Lp3ehVHhYlu7Zh5sOfuB2ZL~H5vLK zBf?1bo~ALhU?0kg5wzI{dQ0m`7Va~(CUH=?{C3bl-hYaPWqcFfk zX|rv4c*c;!rqY|`)of|F?>Jus%1Y8e84&2_CIgk3OBccP-GYW8wRnzClXDx0V2w(j z1-@L>Ej-}U3#uz93WV?P$K&cLBd`i|=^X3fg~9917$E=$5iL&>+`@xPG$ELtQ~}bB zRHzsmA9q*y<+!z5m$$vrGD%R*;dxWu(z|V2nlM&=ZzE1kfx+(11x)ViRB-T8Ci*+vo65+l`rlf~fy+N-kM1Ji`R4jot$^miKIq4ik3j&{ zz)EAi$-J|ccw(|_L-+j|y|xvvg@asl&BVq9_3V7sN0p0EOa2Y%d;s#mnWkR7a@EZx zPU?SXlf7SS)d#VELa<96!GnDJUF!r5nnb>r6(2Xx(PHrQmpfF;b=$^Kc!eZV^T>iI zn$DAgWdfNbtbxXJ}wF0U7Z`4@!2aHk9CK&;N{9VjI?3Wcobf5 z0Fe(8F~nSF6|3hP;0VQ+cbMflo`BhS*?p*s z)$|=!4C(qRq4PBLfj4Lp02$wcn@t|#VQaEAUy`v)U~d+*m?^U{`6?G=G#9O}oQI~8 zOVsPvWUQzGiUmzM50ZcPB~-Ga_veaMLlUhe+~7|IOB`&YA5*Wm(?x_BF=(C%&RY%B zx}tpd;9s~ONvNX4)JH~ACM62n*Ml`^e2YpwNYA%Wq%<0kE|*=@OV)U}PGGuuwcs$A z7981b35%>GSrCJrq!ctVxi{p4g8h6jc5_(WjGPZu0XiIdTA(+D z>330F6r5huEfz~Y*R1=R18!)q)-8@f2xkTx{7RzK>ZGq!Y4vg7inqD-`Wmb0I|4C| zLS)ouLe&VM%%a^AIxWaLYe*C0T($O5f9^!Ld8S;mf*z;V>D3<*g*t%iu5EQ?T92wF z08}rCX$@E}slbYmcCLSyypp+rtUiDQ{AEqv@ysP`Ewz@Rg zd%nBSQBpu6-^jlrcJlZxLse{m-8vzEKyyV_tddb&c(Z74qMRkjXgxTz4EygH#ZZ~|o`^Iba&Hd8LvS3Gp&YSfIWEM9K~ z|2IvAm#wB^WyWICoEc?g!^tPXxe^yc$eA1gBwf8rFj^F%y= z6CGk3fPX^dVr}1gF58~9ee)%tsGo9ka;5{K*j2dFw%y}Sgb8uj%Hpd`(rSqgaBXXT zHWgdoxiM}5=->ctI4eYjl%uV%H);@P!w)89hz$3A&@=#DxQIWF{(t~WpS=J806E+M z000$F#Rg8Bw>Q5WuCioTat_t3j-sJtqh8$jE$Xe@ZVw{1?t{{lM3?8*dJHS~+Wyx) zxbEmZoHNrG6M1P44d|^ml~jVr5J?xuN7fB0zBVcnckVy}X!0{)j^pP`5>$z}M>!7z z@8j?zToKpm@$Lh&D$Qq?bC~Zh{?S}*uJ|U?ys&Jkh`|(dZ5ruS=6qop>8wn4Mu^Xd z1y?Fuhn{@H94UE0Eilca(+G+wthI9Mf$FBmse}UCpRGyIeNVv8$6)$`z7=LqB~Ye) ze{4d^<2{j}cYaErwp>=76{YjwHSf%Q@?08Zp#G^n{jQgjGmK?}61RVc;8*+(f*ZWn zkD<)gO@M=HzS&GqIhbACdFDJNnu=+&2 zpnG~NaR>;uDqTs_bkC2NNVnn=BbSAgJIDJP+gU&c?i&E<$l&oSHU~p~Ux{K;lx@C} z7-D2i>-TzZx5@>bp_=VNE0my-G<##@h#T+an)CV14WZ6`~ebX2$wo&Npxgv%NT=foaagZ9{3E_|nJUomAe$z77$PK)XS zKT}4~5Kb<7!lYA7b|F6Kl&NdX4mhjJ=NwBGs%q}mG&!y!{Fr*}Q=fco?RN^;%F7js z?4;cLwjJ#2;~!&amPBFP?sfm6^@kf|5gzDBSV*LVzZ@rZS3V}yV$uNBtl2~MMU6;A zWdL5%o$!lb1U(h z`hTQKhsAQK!c260I}AeUAs)eDZ9B}(wb!z)+J%8rM`XUY^ky!b1In^6c|e`kU3|NX z*{&puQKD#H@^!xBo(HbN0-L*)Elb#YawJY{!9?Q$B@rpc0k$qDy&iXzDnoXfN2bkm zx7Zz8M+48WESyG-X`&#mg)+}D7d%#{5nr%_dmtrH32NMtH`cBv{ad?1sYdV4;*x;_ zdkk^eGOpXb$oDldX@2w;MODo4|LbG)YMvMoXQp>FavGojIT{>5W0+puD{uPVN}9C; zgD5oLD8(RkczpP69;g73PZ&v_dz{t{j0v}M;c@7UEox{AB7RRyOV-f@!rDS)K4qO8 zwjelw42dlpP74HP*GSp3H)@uOJ9z)-5>4C0TFCd#O{E{rIc(Ef!7vL|gorhD1brSL zkXDJXn{CJ0sYcFpg-axMIbIU=HCA>kLNyTatfYVRQjieob2-yY0U!k(*&)T7fzWZr zU=lTnm_OCOk1@)LWlUi;mwih!iID8;$(j`iBNiStT??N>OS1WOrhSR6n#CLxffc-SIf)!At2N&=O)6}IKsUuVtt zP%rqhQGkEup9bXdlL)xxMPlGsgn6r3}tPT=|l@2H7jweA$gE&Vho zMQFY`uW`Vy!V~w&(MD@T|2p*AEWc8KD#VU)5%z<(z%Aw>6c1NS20vSJ4kYQuR)^#E zho6m>JL#lc)P{o}FaQE|XR!~xk0rPhnXPXZ?|=sll&l13?b3kIu{GFmi%mv7T?d}$ z{g{gi0}%a`mSwq1#8;%8Wrg(|M!oU0yh_({(lbI$mr>C9q7!HG_YD~oK{gjNBm$4D zQBmF_G@nm1aFtn|9}iq}Mv-}w?ohLkAu2t52?_#omURZ0gEnQ#R2ai&mYlsA<+8lIrW82hn-lp zMl>$$j4#LrS7YB($5rzY=AhRd*HOM%+TU2+KA_jHfVolPxV|y*6Kj>xuDlbv*BWI3 zD{nnu(_CG0a6S;0twq6U<1MtIe-dtB zTasJ?X>TC(4ZH5>yK*M&EDyss#_Zdns<9ht5HPpesewW$#lVJEE{qir!zCY2JXYk&24wz1y)W9;OZ88DLLoj0?&0 zu$ptsnivI^BV_#lx(Ob}Z|%?BKH%Lr8uZ#~2LdBQo}gd95V~U=I^J^0Six@BxS|>1 zqmeoxD38rJpa3?R0g;%+fKEm~KmZvI=w7d60a7Rm_OTQ_0N05hybX7_N#2Q*ITPfg H^#A|>pF(q{ literal 0 HcmV?d00001 diff --git a/src/views/About.vue b/src/views/About.vue index 0bd7eb5..a7e230e 100644 --- a/src/views/About.vue +++ b/src/views/About.vue @@ -35,6 +35,10 @@ const str = "使用方法\n" + " 手动检测系统代理是否设置正确 本软件代理地址: 127.0.0.1:8899\n" + " 2. 关闭软件后无法正常上网\n" + " 手动关闭系统代理设置\n" + + " 3. 视频号抓取流程\n" + + " 将需要下载的视频发给好友或者文件助手 再打开该视频即可拦截到,通常软件界面对应视频会出现标题描述、对应操作会出现解密下载按钮\n" + + " 大视频可以复制链接通过其他工具加速下载,然后再通过对应的视频操作项进行\"视频解密\"\n" + + "实现原理\n" + " 通过代理网络抓包拦截响应,筛选出有用的资源,\n" + " 同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的,\n" + diff --git a/src/views/Index.vue b/src/views/Index.vue index d1aa179..6306c82 100755 --- a/src/views/Index.vue +++ b/src/views/Index.vue @@ -1,7 +1,6 @@