From aaa0df5f171a8e142d5e8a7a2cb99506388874a9 Mon Sep 17 00:00:00 2001 From: mesmerize Date: Fri, 30 Oct 2026 19:01:30 -0700 Subject: [PATCH] fixed an extreme ammount of issues --- DOCUEMENTATION/FORDEV.md | 12 ++--- build-pipeline.js | 2 +- file-updater.js | 98 +++++++++++++++++++++++++++++++++++++- main.js | 17 ++++--- package-lock.json | 3 +- sign-ui.js | 45 ----------------- source.png | Bin 27557 -> 0 bytes src-tauri/tauri.conf.json | 2 +- 8 files changed, 117 insertions(+), 62 deletions(-) delete mode 100644 sign-ui.js delete mode 100644 source.png diff --git a/DOCUEMENTATION/FORDEV.md b/DOCUEMENTATION/FORDEV.md index 41031aa..0246897 100644 --- a/DOCUEMENTATION/FORDEV.md +++ b/DOCUEMENTATION/FORDEV.md @@ -24,14 +24,14 @@ Fixing os error 32 Stop-Process -Name "vyla-home", "node", "cargo" -Force -ErrorAction SilentlyContinue ``` -Fake a test? - -```powershell -$env:VYLA_TEST_UI="1"; npm run dev -``` - Fake an old local version: ```powershell '{"version":"0.0.1","sha256":null}' | Set-Content "$env:APPDATA\vyla-home\vyla-home-files\version.json" ``` + +Fake a test? + +```powershell +$env:VYLA_TEST_UI="1"; npm run dev +``` diff --git a/build-pipeline.js b/build-pipeline.js index f93e710..7042a28 100644 --- a/build-pipeline.js +++ b/build-pipeline.js @@ -174,7 +174,7 @@ function validatePayload(zipPath) { const requiredFiles = [ 'frontend/index.html' ]; - + const validationResults = { valid: true, errors: [], diff --git a/file-updater.js b/file-updater.js index 0dc2783..2c542dd 100644 --- a/file-updater.js +++ b/file-updater.js @@ -9,6 +9,9 @@ const SDK_NAME = '@vyla-entertainment/sdk'; const SDK_LATEST_URL = 'https://registry.npmjs.org/@vyla-entertainment%2Fsdk/latest'; const ALLOWED_ROOTS = ['frontend', 'player']; const MAX_TARBALL = 100 * 1024 * 1024; +const MAX_FILE = 50 * 1024 * 1024; +const LIVE_HOSTS = ['gitlab.com']; +const REPO_API = 'https://gitlab.com/api/v4/projects/vyla-entertainment%2F'; const verParts = (v) => String(v || '').replace(/^v/, '').split(/[.\-+]/).map((n) => parseInt(n, 10) || 0); const cmpVer = (a, b) => { @@ -22,6 +25,7 @@ const cmpVer = (a, b) => { const sha256Buf = (buf) => crypto.createHash('sha256').update(buf).digest('hex'); const sha256File = (p) => sha256Buf(fs.readFileSync(p)); +const gitBlobSha = (buf) => crypto.createHash('sha1').update(Buffer.concat([Buffer.from(`blob ${buf.length}\0`), buf])).digest('hex'); function fetchBuffer(url, { headers = {}, maxBytes, hosts, redirects = 0 }) { return new Promise((resolve, reject) => { @@ -114,7 +118,6 @@ class FileUpdater { this.appDataPath = appDataPath; this.updateClient = updateClient; this.onProgress = null; - this.pending = null; this.statePath = path.join(appDataPath, 'file-state.json'); } @@ -296,6 +299,99 @@ class FileUpdater { return changed ? Buffer.from(text, 'utf8') : buf; } + async repoTree(root) { + const out = []; + for (let page = 1; page <= 50; page++) { + const url = `${REPO_API}${root}/repository/tree?recursive=true&per_page=100&ref=main&page=${page}`; + const raw = await fetchBuffer(url, { headers: { Accept: 'application/json' }, maxBytes: 5 * 1024 * 1024, hosts: LIVE_HOSTS }); + const items = JSON.parse(raw.toString('utf8')); + if (!Array.isArray(items) || items.length === 0) break; + out.push(...items); + if (items.length < 100) break; + } + return out; + } + + fetchRepoFile(rel) { + const parts = rel.split('/'); + const root = parts.shift(); + const file = encodeURIComponent(parts.join('/')); + return fetchBuffer(`${REPO_API}${root}/repository/files/${file}/raw?ref=main`, { maxBytes: MAX_FILE, hosts: LIVE_HOSTS }); + } + + async checkRepos() { + const state = this.readState(); + const changes = []; + for (const root of ALLOWED_ROOTS) { + const tree = await this.repoTree(root); + for (const item of tree) { + if (item.type !== 'blob') continue; + const rel = safeRel(`${root}/${item.path}`); + if (!rel || !/^[0-9a-f]{40}$/.test(item.id)) continue; + const full = this.target(rel); + if (fs.existsSync(full) && (state.base[rel] === item.id || gitBlobSha(fs.readFileSync(full)) === item.id)) continue; + changes.push({ path: rel, sha256: item.id, size: 0 }); + } + } + return { seq: state.seq === null ? 0 : state.seq, changes, removed: [] }; + } + + async applyLive(info, replacements, onFile) { + const staged = []; + const total = info.changes.length; + let next = 0; + let finished = 0; + let failure = null; + const worker = async () => { + while (next < total && !failure) { + const c = info.changes[next++]; + try { + const data = await this.fetchRepoFile(c.path); + if (gitBlobSha(data) !== c.sha256) throw new Error(`Checksum mismatch: ${c.path}`); + staged.push({ c, data: this.applyReplacements(c.path, data, replacements) }); + finished++; + if (onFile) onFile(c.path, finished, total); + } catch (e) { + failure = e; + } + } + }; + await Promise.all(Array.from({ length: Math.min(8, total) }, worker)); + if (failure) throw failure; + + const done = []; + try { + for (const s of staged) { + const full = this.target(s.c.path); + const prev = fs.existsSync(full) ? fs.readFileSync(full) : null; + fs.mkdirSync(path.dirname(full), { recursive: true }); + fs.writeFileSync(`${full}.vyla-tmp`, s.data); + fs.renameSync(`${full}.vyla-tmp`, full); + done.push({ full, prev }); + } + for (const rel of info.removed) { + const full = this.target(rel); + if (!fs.existsSync(full)) continue; + const prev = fs.readFileSync(full); + fs.rmSync(full, { force: true }); + done.push({ full, prev }); + } + } catch (e) { + for (const d of done.reverse()) { + try { + if (d.prev === null) fs.rmSync(d.full, { force: true }); + else fs.writeFileSync(d.full, d.prev); + } catch (x) { } + } + throw e; + } + + const state = this.readState(); + for (const s of staged) state.base[s.c.path] = s.c.sha256; + for (const rel of info.removed) delete state.base[rel]; + this.writeState({ seq: info.seq, base: state.base }); + } + installedSdk() { const roots = [this.appDataPath, path.join(this.appDataPath, 'frontend'), path.join(this.appDataPath, 'player')]; const found = []; diff --git a/main.js b/main.js index 2493d97..7fa151e 100644 --- a/main.js +++ b/main.js @@ -242,7 +242,7 @@ async function start() { const versionNewer = isNewer(release.version, localVersion); const sameVerNewBuild = normalizeVer(release.version) === normalizeVer(localVersion) && !!release.sha256 && !!localSha && release.sha256 !== localSha; - const hasUpdate = versionNewer; + const hasUpdate = versionNewer || sameVerNewBuild; if (isFirstRun) { debugLog("First run with no local payload. Installing remote build..."); @@ -269,12 +269,14 @@ async function start() { patcher.bridgeCredentials(serviceManager.credentialManager); let ver = "1.0.0"; + let manSha = null; try { const man = JSON.parse(fs.readFileSync(path.join(__dirname, 'manifest.json'), 'utf8')); ver = man.version || ver; + manSha = man.sha256 || null; } catch (e) { } - patcher.saveCurrentVersion(ver); + patcher.saveCurrentVersion(ver, manSha); serviceManager.envConfig = getEnvConfig(); debugLog("Local payload extracted successfully."); } else { @@ -289,20 +291,21 @@ async function start() { sendToTauri('status', { message: 'Checking UI files and SDK...' }); const [filesCheck, sdkCheck] = await Promise.all([ - withTimeout(fileUpdater.checkFiles().catch((e) => { - debugLog(`File check failed: ${e.message}`); + withTimeout(fileUpdater.checkRepos().catch((e) => { + debugLog(`Live file check failed: ${e.message}`); return null; - }), 180000), + }), 60000), withTimeout(fileUpdater.checkSdk().catch((e) => { debugLog(`SDK check failed: ${e.message}`); return null; }), 12000) ]); + debugLog(`Repo check result: ${filesCheck ? `${filesCheck.changes.length} change(s)` : 'failed or timed out'}`); - if (filesCheck && filesCheck.changes.length > 0) { + if (filesCheck && (filesCheck.changes.length > 0 || filesCheck.removed.length > 0)) { sendToTauri('status', { message: `Updating ${filesCheck.changes.length} file(s)...` }); try { - await fileUpdater.applyFiles(filesCheck.changes, filesCheck.seq, getReplacementsConfig(), (file, done, total) => { + await fileUpdater.applyLive(filesCheck, getReplacementsConfig(), (file, done, total) => { sendToTauri('extract-progress', { file, done, total, percent: Math.round((done / total) * 100) }); }); sendToTauri('status', { message: `Updated ${filesCheck.changes.length} file(s).` }); diff --git a/package-lock.json b/package-lock.json index 4a8d8b0..10d4ebf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@tauri-apps/api": "2.12.1", "@tauri-apps/plugin-opener": "2.7.0", "@tauri-apps/plugin-process": "2.4.0", + "@tauri-apps/plugin-updater": "^2", "@tauri-apps/plugin-shell": "2.5.0", "@vyla-entertainment/sdk": "^1.20.0", "adm-zip": "^0.6.1", @@ -1535,4 +1536,4 @@ } } } -} +} \ No newline at end of file diff --git a/sign-ui.js b/sign-ui.js deleted file mode 100644 index bbbd011..0000000 --- a/sign-ui.js +++ /dev/null @@ -1,45 +0,0 @@ -const fs = require('fs'); -const path = require('path'); -const crypto = require('crypto'); - -const roots = { frontend: process.argv[2], player: process.argv[3] }; -const outDir = path.join(__dirname, 'ui-updates'); -const filesDir = path.join(outDir, 'files'); -const keyPath = process.env.VYLA_UI_KEY || path.join(__dirname, 'ui-private.pem'); - -fs.rmSync(outDir, { recursive: true, force: true }); -fs.mkdirSync(filesDir, { recursive: true }); -fs.writeFileSync(path.join(outDir, '.gitattributes'), '* -text\n'); - -const files = []; -const walk = (src, rel) => { - for (const name of fs.readdirSync(src)) { - if (name === 'node_modules' || name === '.git') continue; - const full = path.join(src, name); - const r = `${rel}/${name}`; - const st = fs.lstatSync(full); - if (st.isDirectory()) { - walk(full, r); - } else if (st.isFile()) { - const data = fs.readFileSync(full); - const dest = path.join(filesDir, ...r.split('/')); - fs.mkdirSync(path.dirname(dest), { recursive: true }); - fs.writeFileSync(dest, data); - files.push({ path: r, sha256: crypto.createHash('sha256').update(data).digest('hex'), size: data.length }); - } - } -}; - -for (const [root, src] of Object.entries(roots)) { - if (!src || !fs.existsSync(src)) { - console.error(`Missing source dir for ${root}`); - process.exit(1); - } - walk(path.resolve(src), root); -} - -const raw = Buffer.from(JSON.stringify({ seq: Math.floor(Date.now() / 1000), files })); -const sig = crypto.sign(null, raw, crypto.createPrivateKey(fs.readFileSync(keyPath))); -fs.writeFileSync(path.join(outDir, 'files-manifest.json'), raw); -fs.writeFileSync(path.join(outDir, 'files-manifest.sig'), sig.toString('base64')); -console.log(`${files.length} files signed`); \ No newline at end of file diff --git a/source.png b/source.png deleted file mode 100644 index 9fdbb8205965d3c4c4dd0726794419698d82462b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27557 zcmXt9V|ZNA)^5^ZVylg9+g78A%|>l(+mi;38#T6*#_*6aEjS zRKsmqO0gtDPyh%H=0-lw17nzPpR#s`7KDg@KI=VB8x#=0Yyx)r-jq*e$(9?Wg^dwc zzJq*v_v~%C<}QAxu+O>wGVj@1)Os|>r>v1Zi{l+sCnE840Hl!4ZHqd+m5U>(2N7oB zmv*T$bG|XSH8BJ{*${bSr=u2J5IYraPESP*dqMxsgFYVP!^5kz8mj#r!E*j z?rfUhkW!p@#|w&2Y6$XYD3zN0rs4njJLit2ToSJi zvUck<{h!+=xi^wm2Y&w53}K>ypwt9fbequ;K7tM^DFH|f<|?(9T$3Pki|)0-baJkg z)bgC7j>UyMF8c-Awho#}ct^d$FK|?zjw!;m01y2YwFN z26T_#tz4%CTvmg~;*g;CDA@z&Qv(8`=i!0Fy=Y(47$WPs>PZ zcEX551&W=;(q+Gws^@-H@{I5!|Ea(rH;zKz>>f1zqWF-y(5f`~M>Ju(_c0acjS}eNJ55&7N zB=HFIo+RK*H8B`M(>$-E^erLuMrvYR2_k%q??DLE4{kOQ{m_^u5lP)gl~2!xP7Eat);FAf+T@`k~3wyqw#X zIq~7^#*-zh*x%@Wp_NWNpOwuP)+_-Bj>d$R$mpXLo3=5yiJPSQt<}ekenNMRV?8!v zK~#$xx&FBhx9{FO_}wvc2Y;Ef&Bq@4hjxuv2l8bH9_A!z;M4^Wnsx`TRDuADAM|CJ z%9w*mQhebGYoDEyr#lgLA%MzVHtH>l<1B8rqX5h z&jPG%z=$>N=FP0vnP zv|x%YMKn>%JMUwTNY!j^X2r44S!t#NROcjy=?|Rq5%p~9FbM0^uV;IP$W%@p&{rD$ z!KoZ>j>$*6wfv1L&M;$g*x&%Zog8?Fpa|atJ1lQav8(Bi9eO{raiwtsztn%wNo-6Q z+2AS7vw^P-jhT;A5Z8$a2lnLQkwmPA_HiPx0ogy96BSx=2t+qwx~z4&L_@ z;rZ3SQhSUr(wRYgkv|e~(Ne4gBA;Y1%5o3k7fN6yenNwgd0u=N5B23nlK1KZ!i!XP zFoVrk|9KHo1U<2C>4$&B`!QH)z?;xB67`V> ziAVhgGjuzn)@bG8KJv zifqgn3UaRGMK?`d!Ut~;XIJu28ytCjFN}UcD99G~#oOe)o)u35>}QiNi8+pew_$Q@hsPRQxP#qivJub zZ8ag*3n4TB1`Ks*smyCXpn|9kP zjJ`K1&?a={gf$HbkMfJFYoK0k@awXI`j2I=<;f z*q>7@I=g3KI5uWuXfw%4mM`Wo2x{>}7A$+7nC&!--wh^Fp`0<7O_m4cl2YwuN%BA5 zLAY^Y;ac(E2L^_DM+AO!YE_P+y?`H?9h_$V9R6++t0L;fW1`mVYlau#4bu===}rwt z5pqp;h##ftuP{_xRSNWehoT8exZu)ZEQxD4$xJo=4B8fn$(3-|`ndN%7&^Vvz`1oc z9d-M_aA4Jq&I-eiK9qCOPvhxdw13(aW8)-DM05+}f5xvGGq6%>{g?RhOfZ(3 zr%OD>-q{)|()Ccn9(@HW;YW@#J%blSe@N+%p1BAYY|M?a%cVnL_%J5dM~kn)DoiwD zDamlL+<%f?5dhB%C!7@h;oW!t5;cuCajF6mlpOw1a-(mab`Lg3;g{ouI)BFHBpH?Y zB5bjf8qgre_+&fwo>AVv$cy#nX`x7O431h=G|Z#o$}T)NNFA_wqX!t$Lxc7x!+z54 zv*sPZNVSSyqk{X4lWE9RaL3VUKR~r)FwZ;tMn_Z@=U!E5`0Y``VW-ef1-1CL9=ro< z4RvNtB^iA4$5-WIZYzXLOn@32v#tt{e`t$1W0FmkY@Np^tRLP+<#wPqW=>hsKQRLc zp+n`$Oh5liWo4uh4~$30^33+OD^?q==eQgUDHD86B=b7;h>hNvu-dY_ShEf*a1HF} z8+@H=lP{0vpAByW$K|dQf?V;&L)(D?v=ta^g2BWZrY z%QtVRrJI#Y3=2Wb;6i8oUdN)Hq=}eZL#9Fu&8A1WgwT>@rISeGBF7h-0X$k;QG1<{ z{`I{W+ti@8o?_4Q_UsonqsSns**VDSP@E<8dzk_;p`dWMZh`Pqn|00tcw63 zO;`X~91IlqLtCl2^7s5IgCFq@nDkSb8tixw3rwA2I_L|2@K%2%9VN9JAIMmSIoV+O zSH=lsyx{_Pc5^%FOLK8fi+mjh!hhD;;fCyyBGD?J413nH2;jzPmFWDmDuLcfYesZH zx)AxqIf5&3q=(N0BVEywvWE@zxL?bm$J6Y`_0Ni@pPTDBnvzJswp6rWs^<%a zV|@9vZY|n*G3V&)C^AD3Pt@o`Mx}1&=>m=a_Ew`tqi0yfkF+-Qs)} zY|EPKp_-*LKb}LsSf>#{lYxxwE0bSz$aef}S$Ia|iUYJUJlo~-@>f5~EUP5{-qDIL zLY7O2b&99yFK<5Fi~F)Tg6gY2I1n-bm`(Fcv`>k)5jG&{ITZ_tTYHmE{9;+# zWlC};p|(S#o`bEIw(3%ssW|J74vce9_glC3Ktnlg47*Gx*KD! zaGR`F>uJ|elFwY_6Af9Hwa|0*#{~T~=$5)_Bj8GmL6j03Fv}IL2~yvewpM z7@_VXTj!xOs9saCFVCYay{wv_Qk!8?|O{Be`-FGz#Y z(EEhTooTM+>ctskud&YS7~srfFjOUTwM3^Ww2tVOB`P9Xlp(4?3Vy1q9!nC|IrfP;1g=Jz% z+paALA386xtLf{3hds;3D90QxDn5f-r{pz=)C=>toNV_SjjqDyZuDXn=uI>?U)K*% z!wfqg2BuN*j(Vf6&B1gz*feBS_h9Q$I6wZ7aL!31-bJ`|I)ZATG87s2lAJj0)aa*2 zb)}f|IO2vLYc(arY6&(1oXBkJF_RnW}obsXk z2y{b<%-rV;y2_(frJ%&O4fALPwQtr$NTu=S7rx8W;wi}3N0ir`?E5Low}+fcR-a7< zp-4^idzr`_=)TWSrxvO-&d7b#!Cjg>!$a^kQ4(LXr=t7SPAdkir0F8F`##syKR&hf z5t0kE;5L*G!P=vC=wATgLo>mIwe_WZ;tH2sizY|2?^$)@ z6FE{?7l>j?W&Y#l9s9WpLA5McLOb$Xree3L!;F4rNbPIoK_;;1Uk-wBP4!E1!W;#OHZQp1%g-lQetK;G zY%j9pO4Uo!%!e?1&jikT?iY4EkkigPnxbfa8N&~xZfD_?ONoXwo19eFos?!mbXg}e zYTAB(H*E<9Y^A~iLx0r~7Z_R<&3sb|T_BfUIpm(aI$ppP4@p2DdZQTO$$!sjw2ZhZ zeEAMps(B5R7JA08QD`KqwX<|twGV|6&9Td1FU?@us*nc9_6gn!eej3DN6&X*$th%< z*yNBYMi{rmm+>~P_~r!ky>;w=Q0|}oX>p-W9^Nc6sT4T2=~#f@ACKWD_Z6?LVoL>C zcoG0vq#u3B(CwZ=XC$#CA@Hr_L+;ehkni_A%`T;);v~159?(b-e`DCj`rh25ZINyZZHi<98AKWbccR5Ea%w~CQyhPC}jOs{Q&Gq0VY?( zNnnVX1wFyr_*x+&gqMW!Xb)$6n@;CO{F_u2aVqt+0}NvrS)33wN7SyRREb2RiE@|H z+7Xfbuk2z0$vcnLL;1(~L;Np*;ufLv>mOXAgU*zu{W$P6EPN%Dt^P+<0AaTy-3k?4 zA<;l6aobR^5Ng)*5jrnG^j6x6xcim>TpBkbH}olI0Z&yyxXqx<<|M>tn*EjT!{wbE#N(>13a!JRFqxQZr_f=Tn>L{Dwn^TW zGCj5;PxnRMngx!_>;9x!W-ZI;hc^w@Bs9Ur6K@fcqYjcHwhVGb+$Yc|yU}Dg1U+q{ z`5*Y52YdOV+~p@IIc2|I7x^}K-(Jrull0=gcp><%%yqZ}8+$UJe$CtgODba9m5rWUds;f(L(JWf&R+9|+7?$oAI}ImAJ5RETdemKt0*C2{UP1C5{2UP!_)fPsa@NJwEIy>Q42+^U@dEO zLI;ad8hiiWhDF2ErtKK#6hp6)r<*GOzpodu{!RWb$3|vL?bkD(4DLIy19%+yORyL! z-Cs`y_YGOTt&>cquzNgT3=%QP>Iw`Q;5QLid@dKqkToyD5#plP8ZYwlq~C3w_-BR74v%H?l;&9_fpG(;VX9LW z{|88~_8VYp0(yJZaLz=>5KvXeV=2q=%iTH&*)ORQ4Cs$X%W`cOMy51m0k@bsR_M@G zZI@BrSK~as@Hz4tKP-BqFIVh4{}TJ%o7{zqJm+u{z?(w!QJZ-dz8mg=GOgtP?Gydg1Qy-ZTLO-i8Qcayros^GDPR9E7eAUXgm)h&O#>zny zndyv>hvE$qnsjFAe6D>0cA3T+{`{To-g|(+vMJrZWBIIdw(h%;1%cD8;3Ui4vPJs% zI0ssSDf?&QbPa73P%E)OusTAUdI<&fg#5gtFqQ@$jpSH6gKnpQ98))OjdLvwj=1sjO|Dk) zIM4bY-^+w-7v~ASqBo0W?@q+d8|j^c9?z$W#xl|vmiMSZ1ll~SE(uR}oo|0f_t%Gx zjXW@@N8)k&=*!Btey#g?Hx7LGO1WhcNgvyFia~h-!Ca9$fbxxPvZ0MaXRjQ_a2n%~ zcdjS!Z$Ie&I;+UzD)6^H;pyz{)t+Zj-+6bNwx{k4$MXEF{2qD2{J>zrE(6%h>lniT z>2)-+qFNFtYrlEfGJCb6x(D%M_4T3r8WgjjIca8NAc>;GHd6xMYKN6^mQUugG>yn{ao3oF{iz`V$>- zF4_)JO$(AVomx*@%FZa+CvrcWuve-Q)G=UEoN(U?Xl7AHC5gsk#eQe7b;}u`N+JS1 zIQD>j_BgT$oUt?cc9C90(PrqR5BJM`Qw2S1Tlao^{ga?9oTi7TW*Ef|Cx(Z`0>c~G zc4;lR{-~}KMQ%isQ#kTrWY;$rS)v_%Ld7v#BdK8!Y%Hj0;Htp`Y%CVVLQBVjWUlQE z;oSf!etyTzg5FE0qZjw(1Q*9^7Ee2D%~lixcPnf>fvE)k?$ZJ%<<(MSin@UTmr`jH zQ>5~s2{DshJ95$1yw0tiAN4%wCpNnB}UC_-2`*xnv|srjP8Jsm;DL^C3oS^c#B z{C)Dt6U<9gznk;63tX5O{}cl^xuMSH;W=5GN~i4~wnbha_2mY(qcf%4Fy*^(3D0Jx zdstz5zUVI9m^@>yS@yF$!TD}~TtB}<>#3&ty!-3-7Y2V;?{TihYdk$q!yW!)&e4&A z*2@uw7gzL+5q^-SA3TDNFnc%7H|uc)`!(OY)fWOAv09mCw^63X`*bMPD!=PIlIG*e zR%ZFybKdT)u))a-r3dpA>EpUYvIC#4`~w`YYPL`;YSw3>Rh4e`#{_~HYksi*ulKfca?Dc)DK7h@eyy8JZT z-v<{rNaEj?$J}s?)45#0ZQbtFFNhb}U#8rnEh_zMKRzSm2X%o97i<}!PlGUQT5NuM zSY%0B+eNK2y?{?`8AE5eEo>ULv<8G6IT%E!bcpkE-@t-MhxlmvL}avC&4)X$`N6 zRGkVM47od>loRHRr)|6|7eYvBn3CG~o>S+;xIN(fLi-Q~nlqB+fvwZlGdEs@z1t@| zthNE$=H2Aij7MePBei*ZunRPY!REo69%`69;|A@4=@&DCOgT?Bp~)*eNp=C-t-i<( zXJvX6f#2dbG?Q-I=hkN3sEszkev1a~j?2ZwAjwmws3Xb`O~`e`RB4hUMcID8*FOXa zU)=_eVf28{MXxj?E6zVAl1(CwmYL5du%gI1?SaqF2Y|GK2%W#D~@KP1i zrRsI@c|^mX>yayBZkKaTF2cUQ<;Mp-;~@TY(m`PdZ_w#g*KF?3Dxq(A#;oZ)8gO-K z#K)e~(aPLE+#H5k^(@#LikgKlhbS6!<^FnRnbmb9X&Em6{k3Ap?1OB2?+gPs7Yl4= zaQ#Q7*KDB2`eF5xF9N1MKC|n)S^UVLJPYk+=st!E)qLh6I~oi|+y6eD=m1`8J_eMQ z@ry|6H!k2@HklCyEV;SsZ_Eb%-ZK`d39JCGc}c2 zbhw8Tk%|7A>AIkU3g3+{iGfP0zi=TCTtFPV=!#1LjxILPnY$mHVlJXpGOhdYUPWyh zQda6BG@ZLq!KMg-mZ`a0^A;eKA}~~Ci^+C;-Z)lS^`fN%>~oTTU)xce@$1@`U`H9r*joKExlPMLm(UC;|3e5+^+uD ziiSTE0%s=+I+jF(TBlArX{(ze@j@l#?T6a%-EQmu%GFyp>En|3w)%DBRomgLz7EDD zK8Cj)Rnkq{)r7NUDeT3l(QB=nw<^`VXWwkQ-sH3lyb0@+9POr8?wGi%qGR~(u)>NL zTdtJYBJ?cbVA0^fqDi~!;#F(bg1!<0e)Rve0B1#>b)PHq^_zV8e0d_HYA8D9))V&d z30}lo(+}tkPK|>0Ey2cdKX74`_)Fqk>S|E8CIn8;E!p~aw>@tO`}@nuFW`Sah-Zdq zO$io>S(F2UCrd;u%sh~MNekR10ERQmU*_--{fsaoH%Djkhb(X1tX>;aeSTob$v?8M9j3O66}ml#uUo&VJi$Am z_^P^$pI_L}r-@mfU%7%0gS4wHH*Vo;t&7epX9#zyf;WrA(uNL{K5YL_TI|rPD1;|I zR)B>Q@RwldbfiZ8-a&T{)U|3N%btD&j)dR#Im_pROwDP_G5?y=@-f|Ux6LGE@7~MR zJcrPJf{?`fgiWi+x>5noSO}2`q}dj1TjdA#H}cpFeXaau(-6NP=3!V{8$ti|^+K94 z{B;Yl;Vw9%?~wvdFK-UT4SQN6gE~7X&$xgIE(vPD)k-SjB#c^Sc2zV z*h;eQ`b&;rC$F9>xV7bks$r+me6!^{@B3K@4I+JXScXYmNqQGxCm~wI6`#`x$%`}P zgi$Om9fi=&P-j>G?>DuYmAGR}j1Wy6R0+*23HgVs&7y;NCasW8g9<)JL%$z1RIaBz z;3ptG=+f)v3!yPVhNcM*F4jYW&Nwj5h3#f6Jg?x+e?vD;?eEh@Hc-&{MG7QOqDD$u zDvyGl-%SdOpc&dRxpGYG<;ri&(B*BmjkLLZQO4!>Jw!1<6%gn6jk zS5VX~V@s#4F|+#Co}1b_@bMOLKl+1sf^ztijV;o;5u+7A=x6*8b)rB{pnpeLF zR%{W`K+z|GztoJ(c6rA$s}nV-f;)BZLtFY+PP(-Iki2L?IE=bS6=D@mYer2LXtvE$ z#jN?W`C$ATJ_MZW@~C?@FhjIn{sOE(;y2Mqt|(mCe-YG@4JXd_^Js(i_K&l2^$efsn}*EmH}xWMyzTIOzeJe|Y$?5``jr`ZgR=z1tw=mJJ|GL9KKFKB>t z#%5tLt3UAuUoyPuwPfG3AV%(9eCJ|vG}zkQvv$k1-|#RfL(;fY-M**IFIF>+QnKcA z9BUIVV&ULrSQML5aip0SqwilEMA>z3LSY~6!$5fAa}m_~N#UoaGyk`z(^Rt<$LzP~ z{nbdCtb+sZDm^@`$8A#lIyr&yB-}m%%ZyF?hWK4lE_S&1{Um+1;1GF7rWQTrc)6SJ zukKZ{VoF;H?eQn>?da!iCnO7oF}5;dK#>tEBd3%9iwkQ%fiF9GJkFHC!BKVEerFgi zCI}E)9~!aaFed8MHG-^KFL%HZ8-Hs%_T#)LV$L!qer+UmNVLWq(LgIPrHnE}QX5he zQm+3}#l1)Ag;BE}2!fg4{gr1N9n@_S?QFaS!UO7x+Bz#cBpkS1W{mF-WxeZO$4vfe zEixp&a~D*6x@h)o7h(P^h_Up2|40S2%*%#i${ql_=zQ9OW4 zY`qA^hIW!p^T^tFh<0I{z8Mg8f5elyo93#ZLRFC)QP|0XhOk8hDOP=A{0U11`4<0B37M8>gn*v3EzH3U0QGs z5m1}5M8=bn=8#p<^l2C4?H;Y~up)xrdBc?en21kn$HnOA9j5{FlL&fX$S-n}+Q8h9 zKl(XWUR4PPsgJ)2m>xU>qp0xMA&IM#UvUYsuFl(>LQH%DVBHmB`*kQaj3G?F9L5g1 z!PPN6S0mFjCC{0MVR93kT7)na;kLh)3puRIom&8m*SPAI{wCF|9mx?99UQ=Jtf7dj zBhOW?8nT1KqC-ErvJ3B(**8LVN!3B9T+_GANp4bVTJa7VALu0Fb7lc#tW!iqwdTO< z2d`tUnZOA^5K55XL~Eo)k!9gx@b~T@=Mg zlXn09fLl4Hd@Z9xFIb>BIaC_w%@8X!MX}U7AVS6tF8HgXTu=WUQFIY2xaluYSiVAw zPq=&V3d5Bg>gM5WV!j%@M3fi~9c9U{dMC4;O=%Kr? zZKmEJ)0pFMWa43VhVYc3%bhsU!>r}Ca5|^=rY1~|=VlmaT7dD3tpLk|L z^r$CZ!$?(vLWw5Xr{r9&CB6+3=1T4VJ-vb^ZaYQ(tMw6TZL27>KI@*E(3SITX2`jBcJZExHjB^rJcO=e|6%tdhsNu)#>K#|b7Lrc`$21`m*0yW zd%}0klMnXC5XRbwbkDuC%>5j1M`f(b1PYm!&ZY23`_Cth>wc&A+p+E$&MXL-{;v-) zVqbL8f2lAd1fhJIt+aY53$@n{vEkip!hbtb%(^G1h(d;RAf)rY7HqVE~?$2+RSX9w)!zu_!Pcx_3`)q$a zosvMiStMa>{Nwa$2_~pIZ*vp`Vkm3BA)$}oD{C<&Ir%;0S@=2!t@#_z+R`Q=wc?K* zd}DVpf5WN%*RMV#!O06m?teC`cnA(i$uCbPskV|pu>`zz5by+fJK8?QDyH9r!uOZ0$DHWfTXRMMwnMUk1L>2@46(B{)y#aM7 zaBxC7sRqOUVtR}nlIIOcMq&zokILKic0S$lbh?7WGmIwO?)7+B#HXpsAuE(9Gt3R7 zC7ypeCz{X3dkLuu%aBdC!YnV8q~CW)Sh~~6Hbj4?-ofDa6&&|om1;G6Q*EI%17S`I zh|ZG}`7ldPPfKR8t}=vA)> znW%LGI|Sm&(06%nnFt*yPu9d6RiD`h{ml9W4qBnHZ=+_U5&c{4a#CRK1}*+rAsVqn zWH({z&ut6iTcW#_BA=q5?j3vIV?ETO?ztI2qMtE2K@)j)SdZLz_xrkl#dp~Erp(9{ z5ZKZ>XX#h9_0xGBP1DUS1_23st)_FHsqxR&y)n8+pNSGAA{j%?e*GfGy~#wfjT;5> z(ItD~Jp?ArZ;U$H`)`95p(B%>5V|%x8%;5Lt+c6^ zR$^;UoFqfnX(O5L5gUtJ)-oFTHS4wZ1(i>x|4O&bUAGsU)!nN5oxig$&_swK7eC^y zR{#+6pcsHn+(T=Aq6^_OS{g{Jk_&M%3OS~N!_16xyYK)mGWYl~Se~3UB}>jeNK#K0 zn=jv!G?-&}J)|g^&mSW=N6s;+662OP7p>hpUI(!dmQtg@1$kl3WBc2yr~{Nvau#ew zQdwooh|tv-2hf)loP4vwFoVLPQF6gQ0+i!H`){njIHIi@>Pv_k@7$lf&f-1l`>f)p zZSi!hAlf`I=V(ah_G_k;XrojO2xw**t2ZAa@beitd>7QS1v!+Dc4(JwABSnOT^0?! zEAk*TvWcsgQU^(&fR90$HLpi+2m9=#=W<{8^tJtyI`Zv{5yB|tNlx2kc%yE@=_ zb?C>@Y7%*Sn5-d$(PpLY(nYthyI3hEg!%ILiVt7@;DAXIosi4!2=RUkT$A)TvD8ic07&lWE}%lx)D`Q5!7{wAwa<6E#31OFR-pJ>(UE zV`_o({z_T!A|%hdBC|K{^IxmiYqiO;TM2ZH6t)6HK?0e|5mj7JL@lD&Ry%Jbtn0dX zFUHT~NF9N4l;T-@Sh(xWa1ytF%8Z$pjct_mA4J%wXyLnc|IUAXoA+mEt+L0#r%fgo zBW)ruLF`h;L#@QBZlH`6YY-;VCZ)|cNxSO(E?(GAZWODIgG5A-UR-^L?%&biw#TEg zQ$YHxFnfx@KGLG5TMsjCbt!D6#zCYJ(<0=E{eD^O(-Nn(GBUc#2vx?~TA~x7sg-`H zOz2Heqest#q>JsUEhFYHRF}ybHQ&$E^11xI=Xp208Jed1UYA0#$jhN}%=}?F-C^5e z>J{)m0|0ZAdJa5xpO?@~U?+m!RwhIZ!i60??LN8SJ-i$d=BkM7eBNbYo{&E|DUh9v zw^y4T@6(Or{Ns?}V-y7Ip^(=ORHT{ey7~ul^x&uKlxBQ{%NTyNRmHm9OvptQF?6&d zt5CAo-wRx+UHSujhiFB?>nVwtivB_7g>x8qF$VHOZON(;8+WOJ9KK?D9c!2)E ztMn4TU(ddM_x1Izv$gZ}riu>HrX^Cbo78cJp{i|W)qUOf^;O+5%|$pgbN@W&IP#RC zrS`z9<@s{7*+!ikdRL=?k?StAFFKfyTVl4GUvt~;tk)<}{U4WPKaRwe(!l#;f_xb6 z5A-Xef~aSG92{Z=FC#jcd#-AIE4#v$RRIaYYa~w!tobrlj~=a~4`Y!})y-Uufu+k8 z2~y9sTK@6PgS;H*=hzixx?SGAGga#<{Y9%CI<8RU@mqs}dsRG|>@%IBWo9?{`Pk^q ziRX_)@MtgCWiP1!b)akpG=@Gax1+5{|83R^B=gC1Qs~a5o)Ld6i#6~F%(Uu=>1r!y z+_mnpjp8o|9h?PQ+g@dRUeF)~3Ch$x7XHYH6df%?597mNoGgM9hJbY^yo#{=IWu}$ z>2LQ5{V&>7oW6Irb0unZnnLb=ygWOT0u+Q&t;g1vJHyPel|^l?tglI8#&Cu>IhRzW z#nWRbsfeu>gs=>r%O)-t{dn#^xieR#WUO_b_oqGEu_9S|(>vX%Jl+|7U#r@a;h#ja z>S>n<x%9fQ_iTzeel5+QXsXTaQ>ikU+C*!VGltu^j^U_uuLEbXOoW`d- z+qj!(){G!8RXEka?qMb=sKy-DEoEUhYMx4d3azlX18Cj6dPq*av{eRbSuSF=PVOb8 zT-Z`V`+Xue8|NQa7%2a?ssd9R6A-)vkT4>nW-~R>Nrp~9stU|InBh{ZslDSJ($hSK zmkCVB zoV4%x8g={YkD+^*S!YjWtdy*Wct<_0UCUvie&OIP1SdwrkpFhnSgTg_XO2>?@I31? zcqG@OZoB5Fw2a>^cGYE8(O{W``BHF_r%A^O56z#&F&XH;umiaK3N*@d(vnSk*?H)B zEj2X+s=<2=yaS+|?^_LE8*v5FeHa39hav7L08~ zJof8{=N?(>uq1XF?Q^{Q071Bo9Xfcg+G@K6xiXbEYD*W}Wajrx3u!E zotT`o`B~lp)+#J#Oi!{EmkwSKH|);P^-``b_6`To*=z;Se~~8o)uA?_)S7|PwAjV- zH#kRZ#_L|NJ|N6YCulKR*ecldJ3vS${J$)JFJ9M^2+181lD{nm8dBMp@O3=PpA&lE z>Ih=H#LDX?_?sz`UE!R^xl-0OlDXDDKNl{-w`47;0Rmjv$?*y8_f6xHFwzZy$T#Fj z^~jY>@g+S8nh)T~E3t1l%L&wqPBy5i_7KyS=YL??jFGZ*K_hC=SmgZ@U{8+BQu2=m z$|vEjKxq}Q5K7A{mLFCZkMZJZA=gaQ&bzA6`+2* zH%sB_PzKS@wyKd!GBS<;NNW%O;7+jW{4ZZFy&NRy44mP1WKDo`>7cvb&^uVW6B@7M4*mHj79Aab8n2Xo@dJ;pxT1dFFX9DOc9#e?A zfMR0cTG#_8AqEN3Q7#{|U~O$iI-OarS1?d0919xd>Yh(=z?`I(wUR>)3*N`9kW7GeP3uW5M9*_KX%+CU55$f`M1;t}^FVv~Ph9Fv6ACee zrNd*BVLsuf1Y~R3U*y=X{YG<;d)vHxta1;@4U-eAkd9}0mN$}SG^yLko*mjnsG@#G zK1N4Q?)qAAavTuYVybqCJT?O5v?-Mn5?oDjmuN&DhWk<}wPAsaWCVyHI3;N4cMqC7GiVu5q!I`L2L^^&fIpmCzt*ecE;%z8&B-tv(=6a;= zA8qOYA@5MSP|Ih5-)6-Q40puzKaSNL-1-1JxL~B}+H?t!WWHa8F$@f42?XKBHWYTh z`THy#{6ldx9gs&B#SA~&G}3CPjTZ)tXAwgND3sB*C_k`MWAxUfiO`kr)saHZaL;qn zdDCXb`_#c5A%k}f+xZor^nbA}1607k0Ip`GX(spFQfSp7SR~ap2Kw`duj*Oda)QB8 zTtyyRgXc6C_=DdJ2BUCDox7;w?t!_claKNL#DUXqJh?0 zAS|c_M$cP#fp<-)um!s)><9c8j!OQoSJ|s&RUIEZIRxgV1{YTjiU1wEf{5hkFoqY*iYnYlb^^=2yeh5P(EKd( zrOWMSfVucT9@BdDe|T(#!ss#nrb@}B^5!X&@S1WMcSHATE`btA^O03oKWcCX=)zuE z{;aO($%_>}>KyL`fI`RgfCKzA0Acpvz$!m}em(a%u4wex55TYvWW8oxv8m&;c%J%_ zL&eT1#vrcl;+QD%yot6NFGG9?U|FG|RDaC%9T6M0x*5@@oCU0SCX zXErq78$Vxs8K8{gGXB7r^6e<wIrX#V`TtV62DyrBy|YADFCf%_R2RnNC#IzKkL}N87O$h=jj4nL~#0 zn0kd1LTzrUd11mglq zI&VZI7ERay#4Fe_X;PJ_hjfb8yaltlp9k2hOP)vYK9?Rf*q|MFov z)^A7nX?c==z^uh=@U7niIVM*~8e<)d>@<3@8~Huxw13gaUr1gZqDBJa7h7ygW5R?m zWd*vZt{rLC%OpgR5no_T-hM*oh5v(9?V5o*%9wmVh7Yr@_VcETSJHT)9q+xQiSK*8@a%tTY?>@f`}KE`jX!Ceq&oY5 z1NW_GlxAspFQ;~;78kR;PY);aKcsF3q}!}_Uuzc*Yr0B^67IaiInjJUH~t3m^+3Os zDiG1{4U0zlMw&Dop1V?wAUe%ZQr{bQwzBo~s7DXI_saZ;zAh!zr0+vqb!EY3Mvu8t zmfN59a|^|?AZ7oVQeMC*dpQW5!hvF+1=x&h@OlY>!$r770u#?gAl)k^xOy0g1K#9I zuanL8;=~U(ciTQ5v0w}leb(S`(EH>sz5$gJ#1rQBJb}9^=~AubJJ?3~-tdh?RVX z*D8@@lp&o?6*+Lh?6j`jqR7=bHj&-_znacF9Iozr`^sQ+Mi<>E(OYz)%;-^q=+Q-s zPW0Ye^yp>u(V_$)M6Ze7ONicuAPDgu&-eHK=WPYh^%hq2j1@EG&5j2L>8OL(k+)2crDoxyx|vxU#|kH+CT`4iH3g~wjvFk#0l+J z%)S?CK6iLkW;+cD;9kFFUoY_({_)99yFp?&1G+@WPm63$qqo0yMnz#Sg@AN<4Jno^ zE?QVlnqJm^(i6o;f@W$>4>vDmq?Zz7)$5yYHV}6iUvbBlq+FJ$YJKn(wZ3jlk?Wu5 zHGMWfjSq-jgqNc!ZWo>0jHTRG?`7ICx>24vcPP7?x!lGJj=5Aj+AL$WWu}~~r1SLZ z83`NS&DI5Ox3B`)eGZC5i_?xjUcm0qJlY9Q)(Ag?}TmGGaM%H_+zT|Hk!l01)TGoqw zPslshdRrXdq}Yri<(qwO27gbd@`#wKi=^wVQHEy(762E=1JE&k3};gDk5KSh1yS$P zhX8yIb;^}J`M6NBCA@)Y!-HwwExEd-oVU$cUj-hqM~~{_3decvXlXAoMNkjN`Z`zp zoeUtUo->5qEUY4#f|I+`=zAe@u!4!L)VSL*^0cHpIn_%h!%Aos`2;C`Ag>a+6qT`Ve~Z z6OqhFgoTO+A+P|{E_c!BK1(8B+hqdaw&Afy3MF!Fy7oKXDO!(Dynj5;eDm%xfRbgL zYW><@(0yglPhY%l&G@tqxJ#d5gE<7M}#^bnV zC`0O_KB3U+ytzxCahy}6(6+#0G~oSw0r`pn(6W|9rT8yZGnmk~FMDu#MF-e3fjJ1D zx-(Fe*-$MV1_QoHOX^azf-GLBTs z_EYN*Cc-ATaw!@B?_NOeyO|(z+uk}iEF0YWO>q2ZZ^r;YeO8&`xHbyLg{IYhTFOs- z7WueN0MG?YfG~c@o=KOp7TW%L`1qY6h-0SWbEO`IJES8TcAHnGG+lB`UhDX7I)7&* zhqETyX+Ja&L)9PP*>4C!U;Nd_(h|Yyej<@WZjnhSeQkzSFAUmM7NJouAxZe?Zb*9U zNooKb5A|Ju^W`6`#@_RzwtSP>BMXP;_7Ppj9aETMF%rJai>LNXnsb5)lfBpcm?7p? zoQJmHOI3dW{g?QWn{_hshZ1pCslau6XHd}fTE!p#^ihn7qV>xB+e6X0o+xo5I{4;A z);`>UGqF!J7U1Gnf3h!Z3#%`UwZ?1lDTMncmknb6{iUAa^}`=@dlZzEYW8ahsrs8! zo(X@M0Butdm+3oYADN!<&lU#0=u)0E)nJh5I)i=zpX&x}@YRnFM|~xw`ElU1N?x@b z^9a7+*)%Sk0EFqWHSLYaA-fCd@qYaft(Yr1Q#NCqZnQJ!)heQPVi&3t^IA84G8>08 zLJ*&2UM=0c?4T*D`$L4=DDT%Var2?J?v&480|CtmP&D!G=wO85S)}Wo)2H#S5N^di ziykcjeHzxYe}7L;rGJGG0!0X!j9e;vo|uh`QslY%I+WC|L-=Kb8^8dLisNk2rVyt^im3ydG$rvVvR;)Ug21NpMekG27Sx+Cnm@NA|p(*_>ZZc%I#jrgJ=%8TuJ z&!QsFR@Fhu=jV}@t++!*X!P+$_YYDJJ-K~(QfJiX?%rCYRkl9oeKl@P3`@A%z;eD4 z2ix$^)?;+D!T6iZJ_13LB9e#Fiv8tQuu{C%$MwYeC%FzXX-XfO7c6io7PZp!o-yxl zGFVN$uve zCeDj6V5-sN>eQcotrf<8I2ha|YU?!)IfwfgQrfT;4s9^jqF9dmUqoJXVf9_To zoZWg)4hoz35;FBYO~=uOpC2V>UrvmEw*+!ohWn;$x7)P)8`?9P?N>(5vpL@D&QtQ} z%=n*UPzSUg0c8R<;&<9z>Q`?S>#vp^+JPFM=c#W8lIsNDbB*VmL9Jtyc)kRdi&M8I ziBBjqgyQT_Cn}r~{d$qm754$@Td!+Qa|jGz7oWgxU}l>6A3Iq!pt{E7-KuAzf!aN0 z=~6HNQmpgYCW)&BeZ*_0_#@t!zvsKr3%46!Z(j8>Y5@eGo8@@H%seZz4s9=waPhj! zyuXBsYqK^c6?KV4SJE@e6zb4 zA}SQ1O_%sXZvW22lve)uo`KD^(IZG+XsW2wI=_0sdt(0)w`&@nAcuj>C`)YGoeha7 zoBxr+1gPSaFbEtQyDw%-xT7VvOMuj#S_-` zfl7j2y!hFS@*bm)$*?P_xIQHrXen$a{yEH4dG$R3L1^c1FWime7K8F>`Z}cEo`s?3 ztS&9($FV|tw+$Bq#gJmr&3M7P1me^YCEOT_&_{jsC;P?Gpbeaw-K(buqSN@vF!MG{ zFdNx`8z3W}2aDVNRAc!Ri*wHEqovG7nGTC<6T^ain8+xg9Z2!S)n5aUnkaZq7MlDf z-k_W9i}G}6m#mp6Ac_7`gASpidkbWKkM%Sp{pPR2!IhXajBRH~I#X0~gH<*6tVeZDr}pAv>_a`0qL%KxS{|4?7tj%7-x7U=%mj+=u}Jj z@!EJq8I|CuABMXjSg_cCW@C~FJ#)v{{a_ln2(XH;fpgC~wSStPnDVyt}46Ely6m&Amz(yy2n=I>$BHR-1LW#l0C*#6Sj;y^6zZ9Ua6NJsi z7^JT;yHqqWyfUyR3!0Y0vnoF_$PL3v!>E&$9181pyy`<7?gP6y4Qar-R9pT=Gy6~w zgLbQte>H!8{&thHOG*lLPAYQnH#f6@HeeHwzXQM5Hd1`0Q zpGo*yYufOOA;T|33C)Uj30OWaoCA|!!>yl|$llQ|)iCq55C;gg;JX#EeqHqO+FPvd z9HxQ#0I8E?9#%{hJ7vk6tyBU_$`6XCR`a6nV}rY_ksq81;zVYYn<(+9ut!Ixn%$~4i1 z$8eJ6kw*}a%M{Mw2=y^eMgX}<&Ku{Ep%Hn!`dLi+k#4>+;5&iz=Ra0=5B~nV9dVdP z-}m&ckXjN<>+X=wKgNQN{DZbF>e}=O3#EKuUCd8!4X3UG1zLHc&Mq7MK)P%lE0GAV zQg4*2G2W8XCr~5;v0_$!l`@93Yx4u8 zAy(W?9m~-nSf7hz!Ay4M3IeE) zOWMA+!`dAEtEbv!*J~v^?L?kN>>}npc$VDYc&bPqej;p$&1#AgLudg=5jcGtk^=e4 z|)}fHbV|t zH6h<^$;)a;^ew}jm-R<{6f05*G;0JXNsSViCi^y{eo1Xi_E@n%UcUS23V>1D^3eos zO}|~Bz7_mr83{J7-L=@OF7paZ&VzAwj~fl{(BM=~TwcON!DU(vnu)Rp;$&awK!ep! ze)wmdj&tP+Y!&dC%bjr6ZtnFrAFGM4_rkeC<5TB0gwaCuz5M0W()ZnbC2gqVPH@g( zS)1SFK0hAWfK6L>UpNNAP7q4AU0sr2!5_VK$S@^wt;v>LVF;THbfFm`R_rFH`+`zJ zRZN+ix?014rlC|8^5k|uP%nBLda-`5SgAoWD^wD+?tt`mtf%tp^8RQ*&kb(lun>Iu zG~}Q%2dK57#oeY1TL99pFO^b$q%dm~qOj;GHd761{bEY8(e9F2_2t>AvhQ5+)2Un- zUub)PUGl#|=&K_l#-Oy8)`)8|Y&*K^Y-BEqk0DWczArLI+!JYu2e9-YM-^2$+|X5H zD&t2oNhP&d&{8Th?>VPy;^v?hp#0aCuMDu4yv=6Q7>)|}|4cY6d3Nl`rNXs3e7@C+ zHs}RG9zAHXibS8|R;1AX3D1?sWoGiYMM!^Jw=a*iZ% z1Blu@zp(4bRK&(=9=0V9Ik9;{)EWY%wVv+SmKJ}k^(1CPlk{b3&amm$oy)o0P7otN zNMUxzu5WQi@9Fo)42wwEWSU2cDyzh(&QEvz`EmFUC}+(`2`b7;d~NfPGV&qTA_@j1 z5?I_FHQwhv!FFq+6l+j8&(qpHSP3+>XhS`Ag=(fXL1r_iW52&y@8!VDTEN9nfeh_r|3j4Q4cWb*mC@B{NpZ)Yz9d9%eKtCRK0QT z;8-)Cj9PoYeHq#4FbJgJGIjyZDs$PT7oQfG+zGNxV!Q6Jfk&J$;BJ%t-BD&Xc5^a3 z;dNC~!ui9HqBJC{9bS!rrdK&8m83J(r;bSf$zM}U>jq6iGG37mbSm6k;BJUnow74@s=l$*zIN{vMJ%r%%yaih^2IvJLb>C{15Vuk zDZ~vW2=27w?M+vj{-xpat^7^5TXM`&E5ADb<`34z=Yb9e3&|)RelPqVk9ZD2O`Y39 zggEoBUZI|HH^{mAJO^;#72l#tkv!9wthF>akVsh3@8Ew#UY#P znQY05yvg+QNny-kQ`G^sr;m(eQYregd+E>{3Rvm%c0y7Tj&IoouB7 zrTuvxDM4Glf2kF>ZsuA#w=*|JWIT)DR5nx=8N^jx`~#07Lmjj4C+q-57wPRZZDTf9 z+6}rvVRbW%vnSFWe_DU|6o__sthf$}(VPG?OPjsK^E;PK@`sw8chfjY5viiua(6~n zMYth+Ra0b@XwMIr-e78$YJIZFU_@_Hu}Us0R3UBmHF(aF{Bc|yN?4f}o-I(v`F9ge z-bPdrr&}49YqHMzmmdeoDqm(%SzRc=kwjuuK=Q)x_}lYOskZzQ%8I!_1n{4c1s^Dd zG0A}Q0Dn6ul-+ZvPkG2l>Z$S=`G1~eMPMr%aO92^@rWYBYr8jdvDrX2%8`8O%?8vk z)Za+488YA9BZ}tr$^^6_)w#HzoW(e#4&6+9g2s|2>~-yD@H8zeHEI5~DqLL8icuRh zB4BlvUh%%YrQskW~FvJ<`eX}PSzWCHLE z0-)c^tQ1mI86%84L%d2)gVt02b<~7EaE@?U9YD7_Y+vN2W_b(@5mnHl>GHXJLa$L= zmy^`e$WOS*vg1V45%7fYkp`Gp)nJF1nUfOpp?@%_%=wyt%Tg2lKp`^u@j6Qa+u;RX z*vbi;To=STO2#C!5@?!(;esV7(bDC+;+?l+q39uQc5ntg z9(BZQcEw3sOxqV_EjfinMn0TvX&iAIJ?8Ab{WlHmSuIQ`>=CI9H!`>Mt2H|d;T_7A zwhDY!#wY1bgH(s2p`S_;Ii_RHZ0vX%c6Xp#vzhxI_B=12Ob>x|rjpGazD z6_nZvhJNf!#iI1Cv)Net6XPEAVInMS0)G+IO|4UHQSUcgB_-w*p#Y4kw zQZ*)})38fb5HhM%?xetOXjOS=wBsqfli>h((YEn(j$*&kkjo;Xzb2wi5w^4UG-*lJ zEhy=Co|>bbI~>L*>S+6=LlNRXSQ;k6WL!PJw&wck(CimPET76v@W@s{8n{3sTUjei z?Y;o%G^tGv%%hE?H2~v957{^fbQSZgcvBuJLqg1M#P;L*ic=-J2e4oI;aoaH^?znF zlxW06T~9zT3EiuU&fvq(#vI?2n@S$OB#y^$P{`pFySZh{0H!2-;$TqIL&1kDQ&KW= z9Kg^h@FB$}DvpB!4S0z_w#-j({1mNU5mo8b$@HZ=x5Uyr<~m%!{UO4pslJ6VvXw$~2Ey|YzT0fOH+4Y+hk4)C#?sw#dZ z6{J!Y#u}15lrIB*FT7h<)Oz^Z$vM84ocq@hHZHkdN$HsqC9sI{q0(B?s(%Gux2h|I z8}14bjhh?SdY)NX5rF@ZiK_{$2tL6A9le8>hED<4zi~K~>BL6MwH477-SKuC!xFFa zXLQtBOtKS=o+STBIy%Tr8fyCMP+-F*j7@5b{h}(qp*4ImT!q>I11H&t3G}}^>K3KU9jmZ^Z zW+=TRr$Hv?8LZosPfz1ftWd!&aIp(RpgP<@lIL)0=CO^6t@_|O+D8G$sL0f@M zM;qL^X)n@UAlyWqC7blHS@3KH`)n5i@=`xU2SFK2il}DNSangypQ7*o$%#-29}&g& zc|jiM$f+ZGki=6`Yr3tM=7A!_d^ zXFwSxBG`Nt#)|$-{(xeUDuDnlP32PF1yEg@$7rDg#5ItzxzW zavOXg0okt18H|ufVM3;!=ek#?;nA+Raj(SKCa3%rX$#2yd-!R|6&8ID1H+>`dQafd zhK^|};@CdZgBZO8h{?b@B9s>d#m240)qbgm9&)P{1k1xGQmK3awZnirRΝY@TCG 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 F{y*cuqg?<1 diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 455f5e0..f7efbb1 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -45,4 +45,4 @@ "../node_modules/**/*" ] } -} +} \ No newline at end of file