From ece4b8256f622aa2dad87ccba3842dec0480bf1c Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 2 Mar 2026 16:34:44 +0000 Subject: [PATCH] feat(app): enhance theme support and improve PWA integration - Updated the app to support light and dark themes with appropriate CSS classes. - Enhanced PWA configuration with manifest details and caching strategies. - Improved the chat UI with dynamic theme adjustments for various components. - Added new meta tags for better mobile web app experience. - Refactored environment variables to include new Anthropic token. - Updated package dependencies for better compatibility and performance. Made-with: Cursor --- .env.example | 6 +- packages/app/dev-dist/registerSW.js | 1 + packages/app/dev-dist/sw.js | 94 + packages/app/dev-dist/workbox-cf23aef7.js | 3503 +++++++++++++++++ packages/app/index.html | 11 +- packages/app/package.json | 20 +- .../app/public/apple-touch-icon-180x180.png | Bin 0 -> 22652 bytes packages/app/public/favicon.svg | 7 + packages/app/public/icon.svg | 23 + packages/app/public/pwa-192x192.png | Bin 0 -> 24746 bytes packages/app/public/pwa-512x512.png | Bin 0 -> 140280 bytes packages/app/server/claude-proxy.ts | 139 + packages/app/src/App.vue | 10 +- .../app/src/components/chat/ChatHeader.vue | 45 +- .../app/src/components/chat/ChatInput.vue | 14 +- .../app/src/components/chat/ChatMessage.vue | 11 +- .../app/src/components/chat/ChatWindow.vue | 13 +- .../app/src/components/chat/StreamingDots.vue | 8 +- .../app/src/components/widget/AIUIWidget.vue | 5 +- .../app/src/components/widget/WidgetModal.vue | 9 +- packages/app/src/composables/useAI.ts | 240 +- packages/app/src/composables/useTheme.ts | 3 + packages/app/src/env.d.ts | 1 + packages/app/src/pages/ChatPage.vue | 86 +- packages/app/src/stores/chat.ts | 10 +- packages/app/src/styles/main.css | 100 +- packages/app/vite.config.ts | 67 +- pnpm-lock.yaml | 3101 ++++++++++++++- 28 files changed, 7315 insertions(+), 212 deletions(-) create mode 100644 packages/app/dev-dist/registerSW.js create mode 100644 packages/app/dev-dist/sw.js create mode 100644 packages/app/dev-dist/workbox-cf23aef7.js create mode 100644 packages/app/public/apple-touch-icon-180x180.png create mode 100644 packages/app/public/favicon.svg create mode 100644 packages/app/public/icon.svg create mode 100644 packages/app/public/pwa-192x192.png create mode 100644 packages/app/public/pwa-512x512.png create mode 100644 packages/app/server/claude-proxy.ts diff --git a/.env.example b/.env.example index cdae9449..d20628be 100644 --- a/.env.example +++ b/.env.example @@ -5,8 +5,10 @@ # Get your key at: https://openrouter.ai/keys VITE_OPENROUTER_API_KEY=sk-or-your-key-here -# Anthropic Claude (direct API access) -# Get your key at: https://console.anthropic.com/settings/keys +# Anthropic Claude — use ONE of these: +# Option 1: OAuth token from Claude Code CLI (run: claude auth login) +VITE_ANTHROPIC_TOKEN=sk-ant-oat01-your-token-here +# Option 2: API key from console (https://console.anthropic.com/settings/keys) VITE_ANTHROPIC_API_KEY=sk-ant-your-key-here # TMDB API (free, for real film poster images) diff --git a/packages/app/dev-dist/registerSW.js b/packages/app/dev-dist/registerSW.js new file mode 100644 index 00000000..1d5625f4 --- /dev/null +++ b/packages/app/dev-dist/registerSW.js @@ -0,0 +1 @@ +if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' }) \ No newline at end of file diff --git a/packages/app/dev-dist/sw.js b/packages/app/dev-dist/sw.js new file mode 100644 index 00000000..6b593536 --- /dev/null +++ b/packages/app/dev-dist/sw.js @@ -0,0 +1,94 @@ +/** + * Copyright 2018 Google Inc. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// If the loader is already loaded, just stop. +if (!self.define) { + let registry = {}; + + // Used for `eval` and `importScripts` where we can't get script URL by other means. + // In both cases, it's safe to use a global var because those functions are synchronous. + let nextDefineUri; + + const singleRequire = (uri, parentUri) => { + uri = new URL(uri + ".js", parentUri).href; + return registry[uri] || ( + + new Promise(resolve => { + if ("document" in self) { + const script = document.createElement("script"); + script.src = uri; + script.onload = resolve; + document.head.appendChild(script); + } else { + nextDefineUri = uri; + importScripts(uri); + resolve(); + } + }) + + .then(() => { + let promise = registry[uri]; + if (!promise) { + throw new Error(`Module ${uri} didn’t register its module`); + } + return promise; + }) + ); + }; + + self.define = (depsNames, factory) => { + const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href; + if (registry[uri]) { + // Module is already loading or loaded. + return; + } + let exports = {}; + const require = depUri => singleRequire(depUri, uri); + const specialDeps = { + module: { uri }, + exports, + require + }; + registry[uri] = Promise.all(depsNames.map( + depName => specialDeps[depName] || require(depName) + )).then(deps => { + factory(...deps); + return exports; + }); + }; +} +define(['./workbox-cf23aef7'], (function (workbox) { 'use strict'; + + self.skipWaiting(); + workbox.clientsClaim(); + + /** + * The precacheAndRoute() method efficiently caches and responds to + * requests for URLs in the manifest. + * See https://goo.gl/S9QRab + */ + workbox.precacheAndRoute([{ + "url": "registerSW.js", + "revision": "3ca0b8505b4bec776b69afdba2768812" + }, { + "url": "index.html", + "revision": "0.htc1d8sapcc" + }], {}); + workbox.cleanupOutdatedCaches(); + workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { + allowlist: [/^\/$/] + })); + workbox.registerRoute(/^https:\/\/api\.anthropic\.com\/.*/i, new workbox.NetworkOnly(), 'GET'); + workbox.registerRoute(/^https:\/\/openrouter\.ai\/.*/i, new workbox.NetworkOnly(), 'GET'); + +})); diff --git a/packages/app/dev-dist/workbox-cf23aef7.js b/packages/app/dev-dist/workbox-cf23aef7.js new file mode 100644 index 00000000..0e7fbaee --- /dev/null +++ b/packages/app/dev-dist/workbox-cf23aef7.js @@ -0,0 +1,3503 @@ +define(['exports'], (function (exports) { 'use strict'; + + // @ts-ignore + try { + self['workbox:core:7.3.0'] && _(); + } catch (e) {} + + /* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const logger = (() => { + // Don't overwrite this value if it's already set. + // See https://github.com/GoogleChrome/workbox/pull/2284#issuecomment-560470923 + if (!('__WB_DISABLE_DEV_LOGS' in globalThis)) { + self.__WB_DISABLE_DEV_LOGS = false; + } + let inGroup = false; + const methodToColorMap = { + debug: `#7f8c8d`, + log: `#2ecc71`, + warn: `#f39c12`, + error: `#c0392b`, + groupCollapsed: `#3498db`, + groupEnd: null // No colored prefix on groupEnd + }; + const print = function (method, args) { + if (self.__WB_DISABLE_DEV_LOGS) { + return; + } + if (method === 'groupCollapsed') { + // Safari doesn't print all console.groupCollapsed() arguments: + // https://bugs.webkit.org/show_bug.cgi?id=182754 + if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + console[method](...args); + return; + } + } + const styles = [`background: ${methodToColorMap[method]}`, `border-radius: 0.5em`, `color: white`, `font-weight: bold`, `padding: 2px 0.5em`]; + // When in a group, the workbox prefix is not displayed. + const logPrefix = inGroup ? [] : ['%cworkbox', styles.join(';')]; + console[method](...logPrefix, ...args); + if (method === 'groupCollapsed') { + inGroup = true; + } + if (method === 'groupEnd') { + inGroup = false; + } + }; + // eslint-disable-next-line @typescript-eslint/ban-types + const api = {}; + const loggerMethods = Object.keys(methodToColorMap); + for (const key of loggerMethods) { + const method = key; + api[method] = (...args) => { + print(method, args); + }; + } + return api; + })(); + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const messages$1 = { + 'invalid-value': ({ + paramName, + validValueDescription, + value + }) => { + if (!paramName || !validValueDescription) { + throw new Error(`Unexpected input to 'invalid-value' error.`); + } + return `The '${paramName}' parameter was given a value with an ` + `unexpected value. ${validValueDescription} Received a value of ` + `${JSON.stringify(value)}.`; + }, + 'not-an-array': ({ + moduleName, + className, + funcName, + paramName + }) => { + if (!moduleName || !className || !funcName || !paramName) { + throw new Error(`Unexpected input to 'not-an-array' error.`); + } + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${className}.${funcName}()' must be an array.`; + }, + 'incorrect-type': ({ + expectedType, + paramName, + moduleName, + className, + funcName + }) => { + if (!expectedType || !paramName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'incorrect-type' error.`); + } + const classNameStr = className ? `${className}.` : ''; + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}` + `${funcName}()' must be of type ${expectedType}.`; + }, + 'incorrect-class': ({ + expectedClassName, + paramName, + moduleName, + className, + funcName, + isReturnValueProblem + }) => { + if (!expectedClassName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'incorrect-class' error.`); + } + const classNameStr = className ? `${className}.` : ''; + if (isReturnValueProblem) { + return `The return value from ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; + } + return `The parameter '${paramName}' passed into ` + `'${moduleName}.${classNameStr}${funcName}()' ` + `must be an instance of class ${expectedClassName}.`; + }, + 'missing-a-method': ({ + expectedMethod, + paramName, + moduleName, + className, + funcName + }) => { + if (!expectedMethod || !paramName || !moduleName || !className || !funcName) { + throw new Error(`Unexpected input to 'missing-a-method' error.`); + } + return `${moduleName}.${className}.${funcName}() expected the ` + `'${paramName}' parameter to expose a '${expectedMethod}' method.`; + }, + 'add-to-cache-list-unexpected-type': ({ + entry + }) => { + return `An unexpected entry was passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' The entry ` + `'${JSON.stringify(entry)}' isn't supported. You must supply an array of ` + `strings with one or more characters, objects with a url property or ` + `Request objects.`; + }, + 'add-to-cache-list-conflicting-entries': ({ + firstEntry, + secondEntry + }) => { + if (!firstEntry || !secondEntry) { + throw new Error(`Unexpected input to ` + `'add-to-cache-list-duplicate-entries' error.`); + } + return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${firstEntry} but different revision details. Workbox is ` + `unable to cache and version the asset correctly. Please remove one ` + `of the entries.`; + }, + 'plugin-error-request-will-fetch': ({ + thrownErrorMessage + }) => { + if (!thrownErrorMessage) { + throw new Error(`Unexpected input to ` + `'plugin-error-request-will-fetch', error.`); + } + return `An error was thrown by a plugins 'requestWillFetch()' method. ` + `The thrown error message was: '${thrownErrorMessage}'.`; + }, + 'invalid-cache-name': ({ + cacheNameId, + value + }) => { + if (!cacheNameId) { + throw new Error(`Expected a 'cacheNameId' for error 'invalid-cache-name'`); + } + return `You must provide a name containing at least one character for ` + `setCacheDetails({${cacheNameId}: '...'}). Received a value of ` + `'${JSON.stringify(value)}'`; + }, + 'unregister-route-but-not-found-with-method': ({ + method + }) => { + if (!method) { + throw new Error(`Unexpected input to ` + `'unregister-route-but-not-found-with-method' error.`); + } + return `The route you're trying to unregister was not previously ` + `registered for the method type '${method}'.`; + }, + 'unregister-route-route-not-registered': () => { + return `The route you're trying to unregister was not previously ` + `registered.`; + }, + 'queue-replay-failed': ({ + name + }) => { + return `Replaying the background sync queue '${name}' failed.`; + }, + 'duplicate-queue-name': ({ + name + }) => { + return `The Queue name '${name}' is already being used. ` + `All instances of backgroundSync.Queue must be given unique names.`; + }, + 'expired-test-without-max-age': ({ + methodName, + paramName + }) => { + return `The '${methodName}()' method can only be used when the ` + `'${paramName}' is used in the constructor.`; + }, + 'unsupported-route-type': ({ + moduleName, + className, + funcName, + paramName + }) => { + return `The supplied '${paramName}' parameter was an unsupported type. ` + `Please check the docs for ${moduleName}.${className}.${funcName} for ` + `valid input types.`; + }, + 'not-array-of-class': ({ + value, + expectedClass, + moduleName, + className, + funcName, + paramName + }) => { + return `The supplied '${paramName}' parameter must be an array of ` + `'${expectedClass}' objects. Received '${JSON.stringify(value)},'. ` + `Please check the call to ${moduleName}.${className}.${funcName}() ` + `to fix the issue.`; + }, + 'max-entries-or-age-required': ({ + moduleName, + className, + funcName + }) => { + return `You must define either config.maxEntries or config.maxAgeSeconds` + `in ${moduleName}.${className}.${funcName}`; + }, + 'statuses-or-headers-required': ({ + moduleName, + className, + funcName + }) => { + return `You must define either config.statuses or config.headers` + `in ${moduleName}.${className}.${funcName}`; + }, + 'invalid-string': ({ + moduleName, + funcName, + paramName + }) => { + if (!paramName || !moduleName || !funcName) { + throw new Error(`Unexpected input to 'invalid-string' error.`); + } + return `When using strings, the '${paramName}' parameter must start with ` + `'http' (for cross-origin matches) or '/' (for same-origin matches). ` + `Please see the docs for ${moduleName}.${funcName}() for ` + `more info.`; + }, + 'channel-name-required': () => { + return `You must provide a channelName to construct a ` + `BroadcastCacheUpdate instance.`; + }, + 'invalid-responses-are-same-args': () => { + return `The arguments passed into responsesAreSame() appear to be ` + `invalid. Please ensure valid Responses are used.`; + }, + 'expire-custom-caches-only': () => { + return `You must provide a 'cacheName' property when using the ` + `expiration plugin with a runtime caching strategy.`; + }, + 'unit-must-be-bytes': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'unit-must-be-bytes' error.`); + } + return `The 'unit' portion of the Range header must be set to 'bytes'. ` + `The Range header provided was "${normalizedRangeHeader}"`; + }, + 'single-range-only': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'single-range-only' error.`); + } + return `Multiple ranges are not supported. Please use a single start ` + `value, and optional end value. The Range header provided was ` + `"${normalizedRangeHeader}"`; + }, + 'invalid-range-values': ({ + normalizedRangeHeader + }) => { + if (!normalizedRangeHeader) { + throw new Error(`Unexpected input to 'invalid-range-values' error.`); + } + return `The Range header is missing both start and end values. At least ` + `one of those values is needed. The Range header provided was ` + `"${normalizedRangeHeader}"`; + }, + 'no-range-header': () => { + return `No Range header was found in the Request provided.`; + }, + 'range-not-satisfiable': ({ + size, + start, + end + }) => { + return `The start (${start}) and end (${end}) values in the Range are ` + `not satisfiable by the cached response, which is ${size} bytes.`; + }, + 'attempt-to-cache-non-get-request': ({ + url, + method + }) => { + return `Unable to cache '${url}' because it is a '${method}' request and ` + `only 'GET' requests can be cached.`; + }, + 'cache-put-with-no-response': ({ + url + }) => { + return `There was an attempt to cache '${url}' but the response was not ` + `defined.`; + }, + 'no-response': ({ + url, + error + }) => { + let message = `The strategy could not generate a response for '${url}'.`; + if (error) { + message += ` The underlying error is ${error}.`; + } + return message; + }, + 'bad-precaching-response': ({ + url, + status + }) => { + return `The precaching request for '${url}' failed` + (status ? ` with an HTTP status of ${status}.` : `.`); + }, + 'non-precached-url': ({ + url + }) => { + return `createHandlerBoundToURL('${url}') was called, but that URL is ` + `not precached. Please pass in a URL that is precached instead.`; + }, + 'add-to-cache-list-conflicting-integrities': ({ + url + }) => { + return `Two of the entries passed to ` + `'workbox-precaching.PrecacheController.addToCacheList()' had the URL ` + `${url} with different integrity values. Please remove one of them.`; + }, + 'missing-precache-entry': ({ + cacheName, + url + }) => { + return `Unable to find a precached response in ${cacheName} for ${url}.`; + }, + 'cross-origin-copy-response': ({ + origin + }) => { + return `workbox-core.copyResponse() can only be used with same-origin ` + `responses. It was passed a response with origin ${origin}.`; + }, + 'opaque-streams-source': ({ + type + }) => { + const message = `One of the workbox-streams sources resulted in an ` + `'${type}' response.`; + if (type === 'opaqueredirect') { + return `${message} Please do not use a navigation request that results ` + `in a redirect as a source.`; + } + return `${message} Please ensure your sources are CORS-enabled.`; + } + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const generatorFunction = (code, details = {}) => { + const message = messages$1[code]; + if (!message) { + throw new Error(`Unable to find message for code '${code}'.`); + } + return message(details); + }; + const messageGenerator = generatorFunction; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Workbox errors should be thrown with this class. + * This allows use to ensure the type easily in tests, + * helps developers identify errors from workbox + * easily and allows use to optimise error + * messages correctly. + * + * @private + */ + class WorkboxError extends Error { + /** + * + * @param {string} errorCode The error code that + * identifies this particular error. + * @param {Object=} details Any relevant arguments + * that will help developers identify issues should + * be added as a key on the context object. + */ + constructor(errorCode, details) { + const message = messageGenerator(errorCode, details); + super(message); + this.name = errorCode; + this.details = details; + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /* + * This method throws if the supplied value is not an array. + * The destructed values are required to produce a meaningful error for users. + * The destructed and restructured object is so it's clear what is + * needed. + */ + const isArray = (value, details) => { + if (!Array.isArray(value)) { + throw new WorkboxError('not-an-array', details); + } + }; + const hasMethod = (object, expectedMethod, details) => { + const type = typeof object[expectedMethod]; + if (type !== 'function') { + details['expectedMethod'] = expectedMethod; + throw new WorkboxError('missing-a-method', details); + } + }; + const isType = (object, expectedType, details) => { + if (typeof object !== expectedType) { + details['expectedType'] = expectedType; + throw new WorkboxError('incorrect-type', details); + } + }; + const isInstance = (object, + // Need the general type to do the check later. + // eslint-disable-next-line @typescript-eslint/ban-types + expectedClass, details) => { + if (!(object instanceof expectedClass)) { + details['expectedClassName'] = expectedClass.name; + throw new WorkboxError('incorrect-class', details); + } + }; + const isOneOf = (value, validValues, details) => { + if (!validValues.includes(value)) { + details['validValueDescription'] = `Valid values are ${JSON.stringify(validValues)}.`; + throw new WorkboxError('invalid-value', details); + } + }; + const isArrayOfClass = (value, + // Need general type to do check later. + expectedClass, + // eslint-disable-line + details) => { + const error = new WorkboxError('not-array-of-class', details); + if (!Array.isArray(value)) { + throw error; + } + for (const item of value) { + if (!(item instanceof expectedClass)) { + throw error; + } + } + }; + const finalAssertExports = { + hasMethod, + isArray, + isInstance, + isOneOf, + isType, + isArrayOfClass + }; + + // @ts-ignore + try { + self['workbox:routing:7.3.0'] && _(); + } catch (e) {} + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * The default HTTP method, 'GET', used when there's no specific method + * configured for a route. + * + * @type {string} + * + * @private + */ + const defaultMethod = 'GET'; + /** + * The list of valid HTTP methods associated with requests that could be routed. + * + * @type {Array} + * + * @private + */ + const validMethods = ['DELETE', 'GET', 'HEAD', 'PATCH', 'POST', 'PUT']; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * @param {function()|Object} handler Either a function, or an object with a + * 'handle' method. + * @return {Object} An object with a handle method. + * + * @private + */ + const normalizeHandler = handler => { + if (handler && typeof handler === 'object') { + { + finalAssertExports.hasMethod(handler, 'handle', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'handler' + }); + } + return handler; + } else { + { + finalAssertExports.isType(handler, 'function', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'handler' + }); + } + return { + handle: handler + }; + } + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A `Route` consists of a pair of callback functions, "match" and "handler". + * The "match" callback determine if a route should be used to "handle" a + * request by returning a non-falsy value if it can. The "handler" callback + * is called when there is a match and should return a Promise that resolves + * to a `Response`. + * + * @memberof workbox-routing + */ + class Route { + /** + * Constructor for Route class. + * + * @param {workbox-routing~matchCallback} match + * A callback function that determines whether the route matches a given + * `fetch` event by returning a non-falsy value. + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resolving to a Response. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + */ + constructor(match, handler, method = defaultMethod) { + { + finalAssertExports.isType(match, 'function', { + moduleName: 'workbox-routing', + className: 'Route', + funcName: 'constructor', + paramName: 'match' + }); + if (method) { + finalAssertExports.isOneOf(method, validMethods, { + paramName: 'method' + }); + } + } + // These values are referenced directly by Router so cannot be + // altered by minificaton. + this.handler = normalizeHandler(handler); + this.match = match; + this.method = method; + } + /** + * + * @param {workbox-routing-handlerCallback} handler A callback + * function that returns a Promise resolving to a Response + */ + setCatchHandler(handler) { + this.catchHandler = normalizeHandler(handler); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * RegExpRoute makes it easy to create a regular expression based + * {@link workbox-routing.Route}. + * + * For same-origin requests the RegExp only needs to match part of the URL. For + * requests against third-party servers, you must define a RegExp that matches + * the start of the URL. + * + * @memberof workbox-routing + * @extends workbox-routing.Route + */ + class RegExpRoute extends Route { + /** + * If the regular expression contains + * [capture groups]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references}, + * the captured values will be passed to the + * {@link workbox-routing~handlerCallback} `params` + * argument. + * + * @param {RegExp} regExp The regular expression to match against URLs. + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + */ + constructor(regExp, handler, method) { + { + finalAssertExports.isInstance(regExp, RegExp, { + moduleName: 'workbox-routing', + className: 'RegExpRoute', + funcName: 'constructor', + paramName: 'pattern' + }); + } + const match = ({ + url + }) => { + const result = regExp.exec(url.href); + // Return immediately if there's no match. + if (!result) { + return; + } + // Require that the match start at the first character in the URL string + // if it's a cross-origin request. + // See https://github.com/GoogleChrome/workbox/issues/281 for the context + // behind this behavior. + if (url.origin !== location.origin && result.index !== 0) { + { + logger.debug(`The regular expression '${regExp.toString()}' only partially matched ` + `against the cross-origin URL '${url.toString()}'. RegExpRoute's will only ` + `handle cross-origin requests if they match the entire URL.`); + } + return; + } + // If the route matches, but there aren't any capture groups defined, then + // this will return [], which is truthy and therefore sufficient to + // indicate a match. + // If there are capture groups, then it will return their values. + return result.slice(1); + }; + super(match, handler, method); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const getFriendlyURL = url => { + const urlObj = new URL(String(url), location.href); + // See https://github.com/GoogleChrome/workbox/issues/2323 + // We want to include everything, except for the origin if it's same-origin. + return urlObj.href.replace(new RegExp(`^${location.origin}`), ''); + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * The Router can be used to process a `FetchEvent` using one or more + * {@link workbox-routing.Route}, responding with a `Response` if + * a matching route exists. + * + * If no route matches a given a request, the Router will use a "default" + * handler if one is defined. + * + * Should the matching Route throw an error, the Router will use a "catch" + * handler if one is defined to gracefully deal with issues and respond with a + * Request. + * + * If a request matches multiple routes, the **earliest** registered route will + * be used to respond to the request. + * + * @memberof workbox-routing + */ + class Router { + /** + * Initializes a new Router. + */ + constructor() { + this._routes = new Map(); + this._defaultHandlerMap = new Map(); + } + /** + * @return {Map>} routes A `Map` of HTTP + * method name ('GET', etc.) to an array of all the corresponding `Route` + * instances that are registered. + */ + get routes() { + return this._routes; + } + /** + * Adds a fetch event listener to respond to events when a route matches + * the event's request. + */ + addFetchListener() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('fetch', event => { + const { + request + } = event; + const responsePromise = this.handleRequest({ + request, + event + }); + if (responsePromise) { + event.respondWith(responsePromise); + } + }); + } + /** + * Adds a message event listener for URLs to cache from the window. + * This is useful to cache resources loaded on the page prior to when the + * service worker started controlling it. + * + * The format of the message data sent from the window should be as follows. + * Where the `urlsToCache` array may consist of URL strings or an array of + * URL string + `requestInit` object (the same as you'd pass to `fetch()`). + * + * ``` + * { + * type: 'CACHE_URLS', + * payload: { + * urlsToCache: [ + * './script1.js', + * './script2.js', + * ['./script3.js', {mode: 'no-cors'}], + * ], + * }, + * } + * ``` + */ + addCacheListener() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('message', event => { + // event.data is type 'any' + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + if (event.data && event.data.type === 'CACHE_URLS') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { + payload + } = event.data; + { + logger.debug(`Caching URLs from the window`, payload.urlsToCache); + } + const requestPromises = Promise.all(payload.urlsToCache.map(entry => { + if (typeof entry === 'string') { + entry = [entry]; + } + const request = new Request(...entry); + return this.handleRequest({ + request, + event + }); + // TODO(philipwalton): TypeScript errors without this typecast for + // some reason (probably a bug). The real type here should work but + // doesn't: `Array | undefined>`. + })); // TypeScript + event.waitUntil(requestPromises); + // If a MessageChannel was used, reply to the message on success. + if (event.ports && event.ports[0]) { + void requestPromises.then(() => event.ports[0].postMessage(true)); + } + } + }); + } + /** + * Apply the routing rules to a FetchEvent object to get a Response from an + * appropriate Route's handler. + * + * @param {Object} options + * @param {Request} options.request The request to handle. + * @param {ExtendableEvent} options.event The event that triggered the + * request. + * @return {Promise|undefined} A promise is returned if a + * registered route can handle the request. If there is no matching + * route and there's no `defaultHandler`, `undefined` is returned. + */ + handleRequest({ + request, + event + }) { + { + finalAssertExports.isInstance(request, Request, { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'handleRequest', + paramName: 'options.request' + }); + } + const url = new URL(request.url, location.href); + if (!url.protocol.startsWith('http')) { + { + logger.debug(`Workbox Router only supports URLs that start with 'http'.`); + } + return; + } + const sameOrigin = url.origin === location.origin; + const { + params, + route + } = this.findMatchingRoute({ + event, + request, + sameOrigin, + url + }); + let handler = route && route.handler; + const debugMessages = []; + { + if (handler) { + debugMessages.push([`Found a route to handle this request:`, route]); + if (params) { + debugMessages.push([`Passing the following params to the route's handler:`, params]); + } + } + } + // If we don't have a handler because there was no matching route, then + // fall back to defaultHandler if that's defined. + const method = request.method; + if (!handler && this._defaultHandlerMap.has(method)) { + { + debugMessages.push(`Failed to find a matching route. Falling ` + `back to the default handler for ${method}.`); + } + handler = this._defaultHandlerMap.get(method); + } + if (!handler) { + { + // No handler so Workbox will do nothing. If logs is set of debug + // i.e. verbose, we should print out this information. + logger.debug(`No route found for: ${getFriendlyURL(url)}`); + } + return; + } + { + // We have a handler, meaning Workbox is going to handle the route. + // print the routing details to the console. + logger.groupCollapsed(`Router is responding to: ${getFriendlyURL(url)}`); + debugMessages.forEach(msg => { + if (Array.isArray(msg)) { + logger.log(...msg); + } else { + logger.log(msg); + } + }); + logger.groupEnd(); + } + // Wrap in try and catch in case the handle method throws a synchronous + // error. It should still callback to the catch handler. + let responsePromise; + try { + responsePromise = handler.handle({ + url, + request, + event, + params + }); + } catch (err) { + responsePromise = Promise.reject(err); + } + // Get route's catch handler, if it exists + const catchHandler = route && route.catchHandler; + if (responsePromise instanceof Promise && (this._catchHandler || catchHandler)) { + responsePromise = responsePromise.catch(async err => { + // If there's a route catch handler, process that first + if (catchHandler) { + { + // Still include URL here as it will be async from the console group + // and may not make sense without the URL + logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to route's Catch Handler.`); + logger.error(`Error thrown by:`, route); + logger.error(err); + logger.groupEnd(); + } + try { + return await catchHandler.handle({ + url, + request, + event, + params + }); + } catch (catchErr) { + if (catchErr instanceof Error) { + err = catchErr; + } + } + } + if (this._catchHandler) { + { + // Still include URL here as it will be async from the console group + // and may not make sense without the URL + logger.groupCollapsed(`Error thrown when responding to: ` + ` ${getFriendlyURL(url)}. Falling back to global Catch Handler.`); + logger.error(`Error thrown by:`, route); + logger.error(err); + logger.groupEnd(); + } + return this._catchHandler.handle({ + url, + request, + event + }); + } + throw err; + }); + } + return responsePromise; + } + /** + * Checks a request and URL (and optionally an event) against the list of + * registered routes, and if there's a match, returns the corresponding + * route along with any params generated by the match. + * + * @param {Object} options + * @param {URL} options.url + * @param {boolean} options.sameOrigin The result of comparing `url.origin` + * against the current origin. + * @param {Request} options.request The request to match. + * @param {Event} options.event The corresponding event. + * @return {Object} An object with `route` and `params` properties. + * They are populated if a matching route was found or `undefined` + * otherwise. + */ + findMatchingRoute({ + url, + sameOrigin, + request, + event + }) { + const routes = this._routes.get(request.method) || []; + for (const route of routes) { + let params; + // route.match returns type any, not possible to change right now. + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const matchResult = route.match({ + url, + sameOrigin, + request, + event + }); + if (matchResult) { + { + // Warn developers that using an async matchCallback is almost always + // not the right thing to do. + if (matchResult instanceof Promise) { + logger.warn(`While routing ${getFriendlyURL(url)}, an async ` + `matchCallback function was used. Please convert the ` + `following route to use a synchronous matchCallback function:`, route); + } + } + // See https://github.com/GoogleChrome/workbox/issues/2079 + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + params = matchResult; + if (Array.isArray(params) && params.length === 0) { + // Instead of passing an empty array in as params, use undefined. + params = undefined; + } else if (matchResult.constructor === Object && + // eslint-disable-line + Object.keys(matchResult).length === 0) { + // Instead of passing an empty object in as params, use undefined. + params = undefined; + } else if (typeof matchResult === 'boolean') { + // For the boolean value true (rather than just something truth-y), + // don't set params. + // See https://github.com/GoogleChrome/workbox/pull/2134#issuecomment-513924353 + params = undefined; + } + // Return early if have a match. + return { + route, + params + }; + } + } + // If no match was found above, return and empty object. + return {}; + } + /** + * Define a default `handler` that's called when no routes explicitly + * match the incoming request. + * + * Each HTTP method ('GET', 'POST', etc.) gets its own default handler. + * + * Without a default handler, unmatched requests will go against the + * network as if there were no service worker present. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {string} [method='GET'] The HTTP method to associate with this + * default handler. Each method has its own default. + */ + setDefaultHandler(handler, method = defaultMethod) { + this._defaultHandlerMap.set(method, normalizeHandler(handler)); + } + /** + * If a Route throws an error while handling a request, this `handler` + * will be called and given a chance to provide a response. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + */ + setCatchHandler(handler) { + this._catchHandler = normalizeHandler(handler); + } + /** + * Registers a route with the router. + * + * @param {workbox-routing.Route} route The route to register. + */ + registerRoute(route) { + { + finalAssertExports.isType(route, 'object', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.hasMethod(route, 'match', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.isType(route.handler, 'object', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route' + }); + finalAssertExports.hasMethod(route.handler, 'handle', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route.handler' + }); + finalAssertExports.isType(route.method, 'string', { + moduleName: 'workbox-routing', + className: 'Router', + funcName: 'registerRoute', + paramName: 'route.method' + }); + } + if (!this._routes.has(route.method)) { + this._routes.set(route.method, []); + } + // Give precedence to all of the earlier routes by adding this additional + // route to the end of the array. + this._routes.get(route.method).push(route); + } + /** + * Unregisters a route with the router. + * + * @param {workbox-routing.Route} route The route to unregister. + */ + unregisterRoute(route) { + if (!this._routes.has(route.method)) { + throw new WorkboxError('unregister-route-but-not-found-with-method', { + method: route.method + }); + } + const routeIndex = this._routes.get(route.method).indexOf(route); + if (routeIndex > -1) { + this._routes.get(route.method).splice(routeIndex, 1); + } else { + throw new WorkboxError('unregister-route-route-not-registered'); + } + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + let defaultRouter; + /** + * Creates a new, singleton Router instance if one does not exist. If one + * does already exist, that instance is returned. + * + * @private + * @return {Router} + */ + const getOrCreateDefaultRouter = () => { + if (!defaultRouter) { + defaultRouter = new Router(); + // The helpers that use the default Router assume these listeners exist. + defaultRouter.addFetchListener(); + defaultRouter.addCacheListener(); + } + return defaultRouter; + }; + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Easily register a RegExp, string, or function with a caching + * strategy to a singleton Router instance. + * + * This method will generate a Route for you if needed and + * call {@link workbox-routing.Router#registerRoute}. + * + * @param {RegExp|string|workbox-routing.Route~matchCallback|workbox-routing.Route} capture + * If the capture param is a `Route`, all other arguments will be ignored. + * @param {workbox-routing~handlerCallback} [handler] A callback + * function that returns a Promise resulting in a Response. This parameter + * is required if `capture` is not a `Route` object. + * @param {string} [method='GET'] The HTTP method to match the Route + * against. + * @return {workbox-routing.Route} The generated `Route`. + * + * @memberof workbox-routing + */ + function registerRoute(capture, handler, method) { + let route; + if (typeof capture === 'string') { + const captureUrl = new URL(capture, location.href); + { + if (!(capture.startsWith('/') || capture.startsWith('http'))) { + throw new WorkboxError('invalid-string', { + moduleName: 'workbox-routing', + funcName: 'registerRoute', + paramName: 'capture' + }); + } + // We want to check if Express-style wildcards are in the pathname only. + // TODO: Remove this log message in v4. + const valueToCheck = capture.startsWith('http') ? captureUrl.pathname : capture; + // See https://github.com/pillarjs/path-to-regexp#parameters + const wildcards = '[*:?+]'; + if (new RegExp(`${wildcards}`).exec(valueToCheck)) { + logger.debug(`The '$capture' parameter contains an Express-style wildcard ` + `character (${wildcards}). Strings are now always interpreted as ` + `exact matches; use a RegExp for partial or wildcard matches.`); + } + } + const matchCallback = ({ + url + }) => { + { + if (url.pathname === captureUrl.pathname && url.origin !== captureUrl.origin) { + logger.debug(`${capture} only partially matches the cross-origin URL ` + `${url.toString()}. This route will only handle cross-origin requests ` + `if they match the entire URL.`); + } + } + return url.href === captureUrl.href; + }; + // If `capture` is a string then `handler` and `method` must be present. + route = new Route(matchCallback, handler, method); + } else if (capture instanceof RegExp) { + // If `capture` is a `RegExp` then `handler` and `method` must be present. + route = new RegExpRoute(capture, handler, method); + } else if (typeof capture === 'function') { + // If `capture` is a function then `handler` and `method` must be present. + route = new Route(capture, handler, method); + } else if (capture instanceof Route) { + route = capture; + } else { + throw new WorkboxError('unsupported-route-type', { + moduleName: 'workbox-routing', + funcName: 'registerRoute', + paramName: 'capture' + }); + } + const defaultRouter = getOrCreateDefaultRouter(); + defaultRouter.registerRoute(route); + return route; + } + + /* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Returns a promise that resolves and the passed number of milliseconds. + * This utility is an async/await-friendly version of `setTimeout`. + * + * @param {number} ms + * @return {Promise} + * @private + */ + function timeout(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const _cacheNameDetails = { + googleAnalytics: 'googleAnalytics', + precache: 'precache-v2', + prefix: 'workbox', + runtime: 'runtime', + suffix: typeof registration !== 'undefined' ? registration.scope : '' + }; + const _createCacheName = cacheName => { + return [_cacheNameDetails.prefix, cacheName, _cacheNameDetails.suffix].filter(value => value && value.length > 0).join('-'); + }; + const eachCacheNameDetail = fn => { + for (const key of Object.keys(_cacheNameDetails)) { + fn(key); + } + }; + const cacheNames = { + updateDetails: details => { + eachCacheNameDetail(key => { + if (typeof details[key] === 'string') { + _cacheNameDetails[key] = details[key]; + } + }); + }, + getGoogleAnalyticsName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.googleAnalytics); + }, + getPrecacheName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.precache); + }, + getPrefix: () => { + return _cacheNameDetails.prefix; + }, + getRuntimeName: userCacheName => { + return userCacheName || _createCacheName(_cacheNameDetails.runtime); + }, + getSuffix: () => { + return _cacheNameDetails.suffix; + } + }; + + /* + Copyright 2020 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + function stripParams(fullURL, ignoreParams) { + const strippedURL = new URL(fullURL); + for (const param of ignoreParams) { + strippedURL.searchParams.delete(param); + } + return strippedURL.href; + } + /** + * Matches an item in the cache, ignoring specific URL params. This is similar + * to the `ignoreSearch` option, but it allows you to ignore just specific + * params (while continuing to match on the others). + * + * @private + * @param {Cache} cache + * @param {Request} request + * @param {Object} matchOptions + * @param {Array} ignoreParams + * @return {Promise} + */ + async function cacheMatchIgnoreParams(cache, request, ignoreParams, matchOptions) { + const strippedRequestURL = stripParams(request.url, ignoreParams); + // If the request doesn't include any ignored params, match as normal. + if (request.url === strippedRequestURL) { + return cache.match(request, matchOptions); + } + // Otherwise, match by comparing keys + const keysOptions = Object.assign(Object.assign({}, matchOptions), { + ignoreSearch: true + }); + const cacheKeys = await cache.keys(request, keysOptions); + for (const cacheKey of cacheKeys) { + const strippedCacheKeyURL = stripParams(cacheKey.url, ignoreParams); + if (strippedRequestURL === strippedCacheKeyURL) { + return cache.match(cacheKey, matchOptions); + } + } + return; + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * The Deferred class composes Promises in a way that allows for them to be + * resolved or rejected from outside the constructor. In most cases promises + * should be used directly, but Deferreds can be necessary when the logic to + * resolve a promise must be separate. + * + * @private + */ + class Deferred { + /** + * Creates a promise and exposes its resolve and reject functions as methods. + */ + constructor() { + this.promise = new Promise((resolve, reject) => { + this.resolve = resolve; + this.reject = reject; + }); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + // Callbacks to be executed whenever there's a quota error. + // Can't change Function type right now. + // eslint-disable-next-line @typescript-eslint/ban-types + const quotaErrorCallbacks = new Set(); + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Runs all of the callback functions, one at a time sequentially, in the order + * in which they were registered. + * + * @memberof workbox-core + * @private + */ + async function executeQuotaErrorCallbacks() { + { + logger.log(`About to run ${quotaErrorCallbacks.size} ` + `callbacks to clean up caches.`); + } + for (const callback of quotaErrorCallbacks) { + await callback(); + { + logger.log(callback, 'is complete.'); + } + } + { + logger.log('Finished running callbacks.'); + } + } + + // @ts-ignore + try { + self['workbox:strategies:7.3.0'] && _(); + } catch (e) {} + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + function toRequest(input) { + return typeof input === 'string' ? new Request(input) : input; + } + /** + * A class created every time a Strategy instance calls + * {@link workbox-strategies.Strategy~handle} or + * {@link workbox-strategies.Strategy~handleAll} that wraps all fetch and + * cache actions around plugin callbacks and keeps track of when the strategy + * is "done" (i.e. all added `event.waitUntil()` promises have resolved). + * + * @memberof workbox-strategies + */ + class StrategyHandler { + /** + * Creates a new instance associated with the passed strategy and event + * that's handling the request. + * + * The constructor also initializes the state that will be passed to each of + * the plugins handling this request. + * + * @param {workbox-strategies.Strategy} strategy + * @param {Object} options + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] The return value from the + * {@link workbox-routing~matchCallback} (if applicable). + */ + constructor(strategy, options) { + this._cacheKeys = {}; + /** + * The request the strategy is performing (passed to the strategy's + * `handle()` or `handleAll()` method). + * @name request + * @instance + * @type {Request} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * The event associated with this request. + * @name event + * @instance + * @type {ExtendableEvent} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * A `URL` instance of `request.url` (if passed to the strategy's + * `handle()` or `handleAll()` method). + * Note: the `url` param will be present if the strategy was invoked + * from a workbox `Route` object. + * @name url + * @instance + * @type {URL|undefined} + * @memberof workbox-strategies.StrategyHandler + */ + /** + * A `param` value (if passed to the strategy's + * `handle()` or `handleAll()` method). + * Note: the `param` param will be present if the strategy was invoked + * from a workbox `Route` object and the + * {@link workbox-routing~matchCallback} returned + * a truthy value (it will be that value). + * @name params + * @instance + * @type {*|undefined} + * @memberof workbox-strategies.StrategyHandler + */ + { + finalAssertExports.isInstance(options.event, ExtendableEvent, { + moduleName: 'workbox-strategies', + className: 'StrategyHandler', + funcName: 'constructor', + paramName: 'options.event' + }); + } + Object.assign(this, options); + this.event = options.event; + this._strategy = strategy; + this._handlerDeferred = new Deferred(); + this._extendLifetimePromises = []; + // Copy the plugins list (since it's mutable on the strategy), + // so any mutations don't affect this handler instance. + this._plugins = [...strategy.plugins]; + this._pluginStateMap = new Map(); + for (const plugin of this._plugins) { + this._pluginStateMap.set(plugin, {}); + } + this.event.waitUntil(this._handlerDeferred.promise); + } + /** + * Fetches a given request (and invokes any applicable plugin callback + * methods) using the `fetchOptions` (for non-navigation requests) and + * `plugins` defined on the `Strategy` object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - `requestWillFetch()` + * - `fetchDidSucceed()` + * - `fetchDidFail()` + * + * @param {Request|string} input The URL or request to fetch. + * @return {Promise} + */ + async fetch(input) { + const { + event + } = this; + let request = toRequest(input); + if (request.mode === 'navigate' && event instanceof FetchEvent && event.preloadResponse) { + const possiblePreloadResponse = await event.preloadResponse; + if (possiblePreloadResponse) { + { + logger.log(`Using a preloaded navigation response for ` + `'${getFriendlyURL(request.url)}'`); + } + return possiblePreloadResponse; + } + } + // If there is a fetchDidFail plugin, we need to save a clone of the + // original request before it's either modified by a requestWillFetch + // plugin or before the original request's body is consumed via fetch(). + const originalRequest = this.hasCallback('fetchDidFail') ? request.clone() : null; + try { + for (const cb of this.iterateCallbacks('requestWillFetch')) { + request = await cb({ + request: request.clone(), + event + }); + } + } catch (err) { + if (err instanceof Error) { + throw new WorkboxError('plugin-error-request-will-fetch', { + thrownErrorMessage: err.message + }); + } + } + // The request can be altered by plugins with `requestWillFetch` making + // the original request (most likely from a `fetch` event) different + // from the Request we make. Pass both to `fetchDidFail` to aid debugging. + const pluginFilteredRequest = request.clone(); + try { + let fetchResponse; + // See https://github.com/GoogleChrome/workbox/issues/1796 + fetchResponse = await fetch(request, request.mode === 'navigate' ? undefined : this._strategy.fetchOptions); + if ("development" !== 'production') { + logger.debug(`Network request for ` + `'${getFriendlyURL(request.url)}' returned a response with ` + `status '${fetchResponse.status}'.`); + } + for (const callback of this.iterateCallbacks('fetchDidSucceed')) { + fetchResponse = await callback({ + event, + request: pluginFilteredRequest, + response: fetchResponse + }); + } + return fetchResponse; + } catch (error) { + { + logger.log(`Network request for ` + `'${getFriendlyURL(request.url)}' threw an error.`, error); + } + // `originalRequest` will only exist if a `fetchDidFail` callback + // is being used (see above). + if (originalRequest) { + await this.runCallbacks('fetchDidFail', { + error: error, + event, + originalRequest: originalRequest.clone(), + request: pluginFilteredRequest.clone() + }); + } + throw error; + } + } + /** + * Calls `this.fetch()` and (in the background) runs `this.cachePut()` on + * the response generated by `this.fetch()`. + * + * The call to `this.cachePut()` automatically invokes `this.waitUntil()`, + * so you do not have to manually call `waitUntil()` on the event. + * + * @param {Request|string} input The request or URL to fetch and cache. + * @return {Promise} + */ + async fetchAndCachePut(input) { + const response = await this.fetch(input); + const responseClone = response.clone(); + void this.waitUntil(this.cachePut(input, responseClone)); + return response; + } + /** + * Matches a request from the cache (and invokes any applicable plugin + * callback methods) using the `cacheName`, `matchOptions`, and `plugins` + * defined on the strategy object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - cacheKeyWillBeUsed() + * - cachedResponseWillBeUsed() + * + * @param {Request|string} key The Request or URL to use as the cache key. + * @return {Promise} A matching response, if found. + */ + async cacheMatch(key) { + const request = toRequest(key); + let cachedResponse; + const { + cacheName, + matchOptions + } = this._strategy; + const effectiveRequest = await this.getCacheKey(request, 'read'); + const multiMatchOptions = Object.assign(Object.assign({}, matchOptions), { + cacheName + }); + cachedResponse = await caches.match(effectiveRequest, multiMatchOptions); + { + if (cachedResponse) { + logger.debug(`Found a cached response in '${cacheName}'.`); + } else { + logger.debug(`No cached response found in '${cacheName}'.`); + } + } + for (const callback of this.iterateCallbacks('cachedResponseWillBeUsed')) { + cachedResponse = (await callback({ + cacheName, + matchOptions, + cachedResponse, + request: effectiveRequest, + event: this.event + })) || undefined; + } + return cachedResponse; + } + /** + * Puts a request/response pair in the cache (and invokes any applicable + * plugin callback methods) using the `cacheName` and `plugins` defined on + * the strategy object. + * + * The following plugin lifecycle methods are invoked when using this method: + * - cacheKeyWillBeUsed() + * - cacheWillUpdate() + * - cacheDidUpdate() + * + * @param {Request|string} key The request or URL to use as the cache key. + * @param {Response} response The response to cache. + * @return {Promise} `false` if a cacheWillUpdate caused the response + * not be cached, and `true` otherwise. + */ + async cachePut(key, response) { + const request = toRequest(key); + // Run in the next task to avoid blocking other cache reads. + // https://github.com/w3c/ServiceWorker/issues/1397 + await timeout(0); + const effectiveRequest = await this.getCacheKey(request, 'write'); + { + if (effectiveRequest.method && effectiveRequest.method !== 'GET') { + throw new WorkboxError('attempt-to-cache-non-get-request', { + url: getFriendlyURL(effectiveRequest.url), + method: effectiveRequest.method + }); + } + // See https://github.com/GoogleChrome/workbox/issues/2818 + const vary = response.headers.get('Vary'); + if (vary) { + logger.debug(`The response for ${getFriendlyURL(effectiveRequest.url)} ` + `has a 'Vary: ${vary}' header. ` + `Consider setting the {ignoreVary: true} option on your strategy ` + `to ensure cache matching and deletion works as expected.`); + } + } + if (!response) { + { + logger.error(`Cannot cache non-existent response for ` + `'${getFriendlyURL(effectiveRequest.url)}'.`); + } + throw new WorkboxError('cache-put-with-no-response', { + url: getFriendlyURL(effectiveRequest.url) + }); + } + const responseToCache = await this._ensureResponseSafeToCache(response); + if (!responseToCache) { + { + logger.debug(`Response '${getFriendlyURL(effectiveRequest.url)}' ` + `will not be cached.`, responseToCache); + } + return false; + } + const { + cacheName, + matchOptions + } = this._strategy; + const cache = await self.caches.open(cacheName); + const hasCacheUpdateCallback = this.hasCallback('cacheDidUpdate'); + const oldResponse = hasCacheUpdateCallback ? await cacheMatchIgnoreParams( + // TODO(philipwalton): the `__WB_REVISION__` param is a precaching + // feature. Consider into ways to only add this behavior if using + // precaching. + cache, effectiveRequest.clone(), ['__WB_REVISION__'], matchOptions) : null; + { + logger.debug(`Updating the '${cacheName}' cache with a new Response ` + `for ${getFriendlyURL(effectiveRequest.url)}.`); + } + try { + await cache.put(effectiveRequest, hasCacheUpdateCallback ? responseToCache.clone() : responseToCache); + } catch (error) { + if (error instanceof Error) { + // See https://developer.mozilla.org/en-US/docs/Web/API/DOMException#exception-QuotaExceededError + if (error.name === 'QuotaExceededError') { + await executeQuotaErrorCallbacks(); + } + throw error; + } + } + for (const callback of this.iterateCallbacks('cacheDidUpdate')) { + await callback({ + cacheName, + oldResponse, + newResponse: responseToCache.clone(), + request: effectiveRequest, + event: this.event + }); + } + return true; + } + /** + * Checks the list of plugins for the `cacheKeyWillBeUsed` callback, and + * executes any of those callbacks found in sequence. The final `Request` + * object returned by the last plugin is treated as the cache key for cache + * reads and/or writes. If no `cacheKeyWillBeUsed` plugin callbacks have + * been registered, the passed request is returned unmodified + * + * @param {Request} request + * @param {string} mode + * @return {Promise} + */ + async getCacheKey(request, mode) { + const key = `${request.url} | ${mode}`; + if (!this._cacheKeys[key]) { + let effectiveRequest = request; + for (const callback of this.iterateCallbacks('cacheKeyWillBeUsed')) { + effectiveRequest = toRequest(await callback({ + mode, + request: effectiveRequest, + event: this.event, + // params has a type any can't change right now. + params: this.params // eslint-disable-line + })); + } + this._cacheKeys[key] = effectiveRequest; + } + return this._cacheKeys[key]; + } + /** + * Returns true if the strategy has at least one plugin with the given + * callback. + * + * @param {string} name The name of the callback to check for. + * @return {boolean} + */ + hasCallback(name) { + for (const plugin of this._strategy.plugins) { + if (name in plugin) { + return true; + } + } + return false; + } + /** + * Runs all plugin callbacks matching the given name, in order, passing the + * given param object (merged ith the current plugin state) as the only + * argument. + * + * Note: since this method runs all plugins, it's not suitable for cases + * where the return value of a callback needs to be applied prior to calling + * the next callback. See + * {@link workbox-strategies.StrategyHandler#iterateCallbacks} + * below for how to handle that case. + * + * @param {string} name The name of the callback to run within each plugin. + * @param {Object} param The object to pass as the first (and only) param + * when executing each callback. This object will be merged with the + * current plugin state prior to callback execution. + */ + async runCallbacks(name, param) { + for (const callback of this.iterateCallbacks(name)) { + // TODO(philipwalton): not sure why `any` is needed. It seems like + // this should work with `as WorkboxPluginCallbackParam[C]`. + await callback(param); + } + } + /** + * Accepts a callback and returns an iterable of matching plugin callbacks, + * where each callback is wrapped with the current handler state (i.e. when + * you call each callback, whatever object parameter you pass it will + * be merged with the plugin's current state). + * + * @param {string} name The name fo the callback to run + * @return {Array} + */ + *iterateCallbacks(name) { + for (const plugin of this._strategy.plugins) { + if (typeof plugin[name] === 'function') { + const state = this._pluginStateMap.get(plugin); + const statefulCallback = param => { + const statefulParam = Object.assign(Object.assign({}, param), { + state + }); + // TODO(philipwalton): not sure why `any` is needed. It seems like + // this should work with `as WorkboxPluginCallbackParam[C]`. + return plugin[name](statefulParam); + }; + yield statefulCallback; + } + } + } + /** + * Adds a promise to the + * [extend lifetime promises]{@link https://w3c.github.io/ServiceWorker/#extendableevent-extend-lifetime-promises} + * of the event associated with the request being handled (usually a + * `FetchEvent`). + * + * Note: you can await + * {@link workbox-strategies.StrategyHandler~doneWaiting} + * to know when all added promises have settled. + * + * @param {Promise} promise A promise to add to the extend lifetime promises + * of the event that triggered the request. + */ + waitUntil(promise) { + this._extendLifetimePromises.push(promise); + return promise; + } + /** + * Returns a promise that resolves once all promises passed to + * {@link workbox-strategies.StrategyHandler~waitUntil} + * have settled. + * + * Note: any work done after `doneWaiting()` settles should be manually + * passed to an event's `waitUntil()` method (not this handler's + * `waitUntil()` method), otherwise the service worker thread may be killed + * prior to your work completing. + */ + async doneWaiting() { + while (this._extendLifetimePromises.length) { + const promises = this._extendLifetimePromises.splice(0); + const result = await Promise.allSettled(promises); + const firstRejection = result.find(i => i.status === 'rejected'); + if (firstRejection) { + throw firstRejection.reason; + } + } + } + /** + * Stops running the strategy and immediately resolves any pending + * `waitUntil()` promises. + */ + destroy() { + this._handlerDeferred.resolve(null); + } + /** + * This method will call cacheWillUpdate on the available plugins (or use + * status === 200) to determine if the Response is safe and valid to cache. + * + * @param {Request} options.request + * @param {Response} options.response + * @return {Promise} + * + * @private + */ + async _ensureResponseSafeToCache(response) { + let responseToCache = response; + let pluginsUsed = false; + for (const callback of this.iterateCallbacks('cacheWillUpdate')) { + responseToCache = (await callback({ + request: this.request, + response: responseToCache, + event: this.event + })) || undefined; + pluginsUsed = true; + if (!responseToCache) { + break; + } + } + if (!pluginsUsed) { + if (responseToCache && responseToCache.status !== 200) { + responseToCache = undefined; + } + { + if (responseToCache) { + if (responseToCache.status !== 200) { + if (responseToCache.status === 0) { + logger.warn(`The response for '${this.request.url}' ` + `is an opaque response. The caching strategy that you're ` + `using will not cache opaque responses by default.`); + } else { + logger.debug(`The response for '${this.request.url}' ` + `returned a status code of '${response.status}' and won't ` + `be cached as a result.`); + } + } + } + } + } + return responseToCache; + } + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * An abstract base class that all other strategy classes must extend from: + * + * @memberof workbox-strategies + */ + class Strategy { + /** + * Creates a new instance of the strategy and sets all documented option + * properties as public instance properties. + * + * Note: if a custom strategy class extends the base Strategy class and does + * not need more than these properties, it does not need to define its own + * constructor. + * + * @param {Object} [options] + * @param {string} [options.cacheName] Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * to use in conjunction with this caching strategy. + * @param {Object} [options.fetchOptions] Values passed along to the + * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) + * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) + * `fetch()` requests made by this strategy. + * @param {Object} [options.matchOptions] The + * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + */ + constructor(options = {}) { + /** + * Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * + * @type {string} + */ + this.cacheName = cacheNames.getRuntimeName(options.cacheName); + /** + * The list + * [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * used by this strategy. + * + * @type {Array} + */ + this.plugins = options.plugins || []; + /** + * Values passed along to the + * [`init`]{@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters} + * of all fetch() requests made by this strategy. + * + * @type {Object} + */ + this.fetchOptions = options.fetchOptions; + /** + * The + * [`CacheQueryOptions`]{@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + * + * @type {Object} + */ + this.matchOptions = options.matchOptions; + } + /** + * Perform a request strategy and returns a `Promise` that will resolve with + * a `Response`, invoking all relevant plugin callbacks. + * + * When a strategy instance is registered with a Workbox + * {@link workbox-routing.Route}, this method is automatically + * called when the route matches. + * + * Alternatively, this method can be used in a standalone `FetchEvent` + * listener by passing it to `event.respondWith()`. + * + * @param {FetchEvent|Object} options A `FetchEvent` or an object with the + * properties listed below. + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] + */ + handle(options) { + const [responseDone] = this.handleAll(options); + return responseDone; + } + /** + * Similar to {@link workbox-strategies.Strategy~handle}, but + * instead of just returning a `Promise` that resolves to a `Response` it + * it will return an tuple of `[response, done]` promises, where the former + * (`response`) is equivalent to what `handle()` returns, and the latter is a + * Promise that will resolve once any promises that were added to + * `event.waitUntil()` as part of performing the strategy have completed. + * + * You can await the `done` promise to ensure any extra work performed by + * the strategy (usually caching responses) completes successfully. + * + * @param {FetchEvent|Object} options A `FetchEvent` or an object with the + * properties listed below. + * @param {Request|string} options.request A request to run this strategy for. + * @param {ExtendableEvent} options.event The event associated with the + * request. + * @param {URL} [options.url] + * @param {*} [options.params] + * @return {Array} A tuple of [response, done] + * promises that can be used to determine when the response resolves as + * well as when the handler has completed all its work. + */ + handleAll(options) { + // Allow for flexible options to be passed. + if (options instanceof FetchEvent) { + options = { + event: options, + request: options.request + }; + } + const event = options.event; + const request = typeof options.request === 'string' ? new Request(options.request) : options.request; + const params = 'params' in options ? options.params : undefined; + const handler = new StrategyHandler(this, { + event, + request, + params + }); + const responseDone = this._getResponse(handler, request, event); + const handlerDone = this._awaitComplete(responseDone, handler, request, event); + // Return an array of promises, suitable for use with Promise.all(). + return [responseDone, handlerDone]; + } + async _getResponse(handler, request, event) { + await handler.runCallbacks('handlerWillStart', { + event, + request + }); + let response = undefined; + try { + response = await this._handle(request, handler); + // The "official" Strategy subclasses all throw this error automatically, + // but in case a third-party Strategy doesn't, ensure that we have a + // consistent failure when there's no response or an error response. + if (!response || response.type === 'error') { + throw new WorkboxError('no-response', { + url: request.url + }); + } + } catch (error) { + if (error instanceof Error) { + for (const callback of handler.iterateCallbacks('handlerDidError')) { + response = await callback({ + error, + event, + request + }); + if (response) { + break; + } + } + } + if (!response) { + throw error; + } else { + logger.log(`While responding to '${getFriendlyURL(request.url)}', ` + `an ${error instanceof Error ? error.toString() : ''} error occurred. Using a fallback response provided by ` + `a handlerDidError plugin.`); + } + } + for (const callback of handler.iterateCallbacks('handlerWillRespond')) { + response = await callback({ + event, + request, + response + }); + } + return response; + } + async _awaitComplete(responseDone, handler, request, event) { + let response; + let error; + try { + response = await responseDone; + } catch (error) { + // Ignore errors, as response errors should be caught via the `response` + // promise above. The `done` promise will only throw for errors in + // promises passed to `handler.waitUntil()`. + } + try { + await handler.runCallbacks('handlerDidRespond', { + event, + request, + response + }); + await handler.doneWaiting(); + } catch (waitUntilError) { + if (waitUntilError instanceof Error) { + error = waitUntilError; + } + } + await handler.runCallbacks('handlerDidComplete', { + event, + request, + response, + error: error + }); + handler.destroy(); + if (error) { + throw error; + } + } + } + /** + * Classes extending the `Strategy` based class should implement this method, + * and leverage the {@link workbox-strategies.StrategyHandler} + * arg to perform all fetching and cache logic, which will ensure all relevant + * cache, cache options, fetch options and plugins are used (per the current + * strategy instance). + * + * @name _handle + * @instance + * @abstract + * @function + * @param {Request} request + * @param {workbox-strategies.StrategyHandler} handler + * @return {Promise} + * + * @memberof workbox-strategies.Strategy + */ + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const messages = { + strategyStart: (strategyName, request) => `Using ${strategyName} to respond to '${getFriendlyURL(request.url)}'`, + printFinalResponse: response => { + if (response) { + logger.groupCollapsed(`View the final response here.`); + logger.log(response || '[No response returned]'); + logger.groupEnd(); + } + } + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * An implementation of a + * [network-only](https://developer.chrome.com/docs/workbox/caching-strategies-overview/#network-only) + * request strategy. + * + * This class is useful if you want to take advantage of any + * [Workbox plugins](https://developer.chrome.com/docs/workbox/using-plugins/). + * + * If the network request fails, this will throw a `WorkboxError` exception. + * + * @extends workbox-strategies.Strategy + * @memberof workbox-strategies + */ + class NetworkOnly extends Strategy { + /** + * @param {Object} [options] + * @param {Array} [options.plugins] [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins} + * to use in conjunction with this caching strategy. + * @param {Object} [options.fetchOptions] Values passed along to the + * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters) + * of [non-navigation](https://github.com/GoogleChrome/workbox/issues/1796) + * `fetch()` requests made by this strategy. + * @param {number} [options.networkTimeoutSeconds] If set, any network requests + * that fail to respond within the timeout will result in a network error. + */ + constructor(options = {}) { + super(options); + this._networkTimeoutSeconds = options.networkTimeoutSeconds || 0; + } + /** + * @private + * @param {Request|string} request A request to run this strategy for. + * @param {workbox-strategies.StrategyHandler} handler The event that + * triggered the request. + * @return {Promise} + */ + async _handle(request, handler) { + { + finalAssertExports.isInstance(request, Request, { + moduleName: 'workbox-strategies', + className: this.constructor.name, + funcName: '_handle', + paramName: 'request' + }); + } + let error = undefined; + let response; + try { + const promises = [handler.fetch(request)]; + if (this._networkTimeoutSeconds) { + const timeoutPromise = timeout(this._networkTimeoutSeconds * 1000); + promises.push(timeoutPromise); + } + response = await Promise.race(promises); + if (!response) { + throw new Error(`Timed out the network response after ` + `${this._networkTimeoutSeconds} seconds.`); + } + } catch (err) { + if (err instanceof Error) { + error = err; + } + } + { + logger.groupCollapsed(messages.strategyStart(this.constructor.name, request)); + if (response) { + logger.log(`Got response from network.`); + } else { + logger.log(`Unable to get a response from the network.`); + } + messages.printFinalResponse(response); + logger.groupEnd(); + } + if (!response) { + throw new WorkboxError('no-response', { + url: request.url, + error + }); + } + return response; + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Claim any currently available clients once the service worker + * becomes active. This is normally used in conjunction with `skipWaiting()`. + * + * @memberof workbox-core + */ + function clientsClaim() { + self.addEventListener('activate', () => self.clients.claim()); + } + + /* + Copyright 2020 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A utility method that makes it easier to use `event.waitUntil` with + * async functions and return the result. + * + * @param {ExtendableEvent} event + * @param {Function} asyncFn + * @return {Function} + * @private + */ + function waitUntil(event, asyncFn) { + const returnPromise = asyncFn(); + event.waitUntil(returnPromise); + return returnPromise; + } + + // @ts-ignore + try { + self['workbox:precaching:7.3.0'] && _(); + } catch (e) {} + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + // Name of the search parameter used to store revision info. + const REVISION_SEARCH_PARAM = '__WB_REVISION__'; + /** + * Converts a manifest entry into a versioned URL suitable for precaching. + * + * @param {Object|string} entry + * @return {string} A URL with versioning info. + * + * @private + * @memberof workbox-precaching + */ + function createCacheKey(entry) { + if (!entry) { + throw new WorkboxError('add-to-cache-list-unexpected-type', { + entry + }); + } + // If a precache manifest entry is a string, it's assumed to be a versioned + // URL, like '/app.abcd1234.js'. Return as-is. + if (typeof entry === 'string') { + const urlObject = new URL(entry, location.href); + return { + cacheKey: urlObject.href, + url: urlObject.href + }; + } + const { + revision, + url + } = entry; + if (!url) { + throw new WorkboxError('add-to-cache-list-unexpected-type', { + entry + }); + } + // If there's just a URL and no revision, then it's also assumed to be a + // versioned URL. + if (!revision) { + const urlObject = new URL(url, location.href); + return { + cacheKey: urlObject.href, + url: urlObject.href + }; + } + // Otherwise, construct a properly versioned URL using the custom Workbox + // search parameter along with the revision info. + const cacheKeyURL = new URL(url, location.href); + const originalURL = new URL(url, location.href); + cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision); + return { + cacheKey: cacheKeyURL.href, + url: originalURL.href + }; + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A plugin, designed to be used with PrecacheController, to determine the + * of assets that were updated (or not updated) during the install event. + * + * @private + */ + class PrecacheInstallReportPlugin { + constructor() { + this.updatedURLs = []; + this.notUpdatedURLs = []; + this.handlerWillStart = async ({ + request, + state + }) => { + // TODO: `state` should never be undefined... + if (state) { + state.originalRequest = request; + } + }; + this.cachedResponseWillBeUsed = async ({ + event, + state, + cachedResponse + }) => { + if (event.type === 'install') { + if (state && state.originalRequest && state.originalRequest instanceof Request) { + // TODO: `state` should never be undefined... + const url = state.originalRequest.url; + if (cachedResponse) { + this.notUpdatedURLs.push(url); + } else { + this.updatedURLs.push(url); + } + } + } + return cachedResponse; + }; + } + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A plugin, designed to be used with PrecacheController, to translate URLs into + * the corresponding cache key, based on the current revision info. + * + * @private + */ + class PrecacheCacheKeyPlugin { + constructor({ + precacheController + }) { + this.cacheKeyWillBeUsed = async ({ + request, + params + }) => { + // Params is type any, can't change right now. + /* eslint-disable */ + const cacheKey = (params === null || params === void 0 ? void 0 : params.cacheKey) || this._precacheController.getCacheKeyForURL(request.url); + /* eslint-enable */ + return cacheKey ? new Request(cacheKey, { + headers: request.headers + }) : request; + }; + this._precacheController = precacheController; + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * @param {string} groupTitle + * @param {Array} deletedURLs + * + * @private + */ + const logGroup = (groupTitle, deletedURLs) => { + logger.groupCollapsed(groupTitle); + for (const url of deletedURLs) { + logger.log(url); + } + logger.groupEnd(); + }; + /** + * @param {Array} deletedURLs + * + * @private + * @memberof workbox-precaching + */ + function printCleanupDetails(deletedURLs) { + const deletionCount = deletedURLs.length; + if (deletionCount > 0) { + logger.groupCollapsed(`During precaching cleanup, ` + `${deletionCount} cached ` + `request${deletionCount === 1 ? ' was' : 's were'} deleted.`); + logGroup('Deleted Cache Requests', deletedURLs); + logger.groupEnd(); + } + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * @param {string} groupTitle + * @param {Array} urls + * + * @private + */ + function _nestedGroup(groupTitle, urls) { + if (urls.length === 0) { + return; + } + logger.groupCollapsed(groupTitle); + for (const url of urls) { + logger.log(url); + } + logger.groupEnd(); + } + /** + * @param {Array} urlsToPrecache + * @param {Array} urlsAlreadyPrecached + * + * @private + * @memberof workbox-precaching + */ + function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) { + const precachedCount = urlsToPrecache.length; + const alreadyPrecachedCount = urlsAlreadyPrecached.length; + if (precachedCount || alreadyPrecachedCount) { + let message = `Precaching ${precachedCount} file${precachedCount === 1 ? '' : 's'}.`; + if (alreadyPrecachedCount > 0) { + message += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? ' is' : 's are'} already cached.`; + } + logger.groupCollapsed(message); + _nestedGroup(`View newly precached URLs.`, urlsToPrecache); + _nestedGroup(`View previously precached URLs.`, urlsAlreadyPrecached); + logger.groupEnd(); + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + let supportStatus; + /** + * A utility function that determines whether the current browser supports + * constructing a new `Response` from a `response.body` stream. + * + * @return {boolean} `true`, if the current browser can successfully + * construct a `Response` from a `response.body` stream, `false` otherwise. + * + * @private + */ + function canConstructResponseFromBodyStream() { + if (supportStatus === undefined) { + const testResponse = new Response(''); + if ('body' in testResponse) { + try { + new Response(testResponse.body); + supportStatus = true; + } catch (error) { + supportStatus = false; + } + } + supportStatus = false; + } + return supportStatus; + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Allows developers to copy a response and modify its `headers`, `status`, + * or `statusText` values (the values settable via a + * [`ResponseInit`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Response/Response#Syntax} + * object in the constructor). + * To modify these values, pass a function as the second argument. That + * function will be invoked with a single object with the response properties + * `{headers, status, statusText}`. The return value of this function will + * be used as the `ResponseInit` for the new `Response`. To change the values + * either modify the passed parameter(s) and return it, or return a totally + * new object. + * + * This method is intentionally limited to same-origin responses, regardless of + * whether CORS was used or not. + * + * @param {Response} response + * @param {Function} modifier + * @memberof workbox-core + */ + async function copyResponse(response, modifier) { + let origin = null; + // If response.url isn't set, assume it's cross-origin and keep origin null. + if (response.url) { + const responseURL = new URL(response.url); + origin = responseURL.origin; + } + if (origin !== self.location.origin) { + throw new WorkboxError('cross-origin-copy-response', { + origin + }); + } + const clonedResponse = response.clone(); + // Create a fresh `ResponseInit` object by cloning the headers. + const responseInit = { + headers: new Headers(clonedResponse.headers), + status: clonedResponse.status, + statusText: clonedResponse.statusText + }; + // Apply any user modifications. + const modifiedResponseInit = modifier ? modifier(responseInit) : responseInit; + // Create the new response from the body stream and `ResponseInit` + // modifications. Note: not all browsers support the Response.body stream, + // so fall back to reading the entire body into memory as a blob. + const body = canConstructResponseFromBodyStream() ? clonedResponse.body : await clonedResponse.blob(); + return new Response(body, modifiedResponseInit); + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A {@link workbox-strategies.Strategy} implementation + * specifically designed to work with + * {@link workbox-precaching.PrecacheController} + * to both cache and fetch precached assets. + * + * Note: an instance of this class is created automatically when creating a + * `PrecacheController`; it's generally not necessary to create this yourself. + * + * @extends workbox-strategies.Strategy + * @memberof workbox-precaching + */ + class PrecacheStrategy extends Strategy { + /** + * + * @param {Object} [options] + * @param {string} [options.cacheName] Cache name to store and retrieve + * requests. Defaults to the cache names provided by + * {@link workbox-core.cacheNames}. + * @param {Array} [options.plugins] {@link https://developers.google.com/web/tools/workbox/guides/using-plugins|Plugins} + * to use in conjunction with this caching strategy. + * @param {Object} [options.fetchOptions] Values passed along to the + * {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters|init} + * of all fetch() requests made by this strategy. + * @param {Object} [options.matchOptions] The + * {@link https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions|CacheQueryOptions} + * for any `cache.match()` or `cache.put()` calls made by this strategy. + * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to + * get the response from the network if there's a precache miss. + */ + constructor(options = {}) { + options.cacheName = cacheNames.getPrecacheName(options.cacheName); + super(options); + this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true; + // Redirected responses cannot be used to satisfy a navigation request, so + // any redirected response must be "copied" rather than cloned, so the new + // response doesn't contain the `redirected` flag. See: + // https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1 + this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin); + } + /** + * @private + * @param {Request|string} request A request to run this strategy for. + * @param {workbox-strategies.StrategyHandler} handler The event that + * triggered the request. + * @return {Promise} + */ + async _handle(request, handler) { + const response = await handler.cacheMatch(request); + if (response) { + return response; + } + // If this is an `install` event for an entry that isn't already cached, + // then populate the cache. + if (handler.event && handler.event.type === 'install') { + return await this._handleInstall(request, handler); + } + // Getting here means something went wrong. An entry that should have been + // precached wasn't found in the cache. + return await this._handleFetch(request, handler); + } + async _handleFetch(request, handler) { + let response; + const params = handler.params || {}; + // Fall back to the network if we're configured to do so. + if (this._fallbackToNetwork) { + { + logger.warn(`The precached response for ` + `${getFriendlyURL(request.url)} in ${this.cacheName} was not ` + `found. Falling back to the network.`); + } + const integrityInManifest = params.integrity; + const integrityInRequest = request.integrity; + const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest; + // Do not add integrity if the original request is no-cors + // See https://github.com/GoogleChrome/workbox/issues/3096 + response = await handler.fetch(new Request(request, { + integrity: request.mode !== 'no-cors' ? integrityInRequest || integrityInManifest : undefined + })); + // It's only "safe" to repair the cache if we're using SRI to guarantee + // that the response matches the precache manifest's expectations, + // and there's either a) no integrity property in the incoming request + // or b) there is an integrity, and it matches the precache manifest. + // See https://github.com/GoogleChrome/workbox/issues/2858 + // Also if the original request users no-cors we don't use integrity. + // See https://github.com/GoogleChrome/workbox/issues/3096 + if (integrityInManifest && noIntegrityConflict && request.mode !== 'no-cors') { + this._useDefaultCacheabilityPluginIfNeeded(); + const wasCached = await handler.cachePut(request, response.clone()); + { + if (wasCached) { + logger.log(`A response for ${getFriendlyURL(request.url)} ` + `was used to "repair" the precache.`); + } + } + } + } else { + // This shouldn't normally happen, but there are edge cases: + // https://github.com/GoogleChrome/workbox/issues/1441 + throw new WorkboxError('missing-precache-entry', { + cacheName: this.cacheName, + url: request.url + }); + } + { + const cacheKey = params.cacheKey || (await handler.getCacheKey(request, 'read')); + // Workbox is going to handle the route. + // print the routing details to the console. + logger.groupCollapsed(`Precaching is responding to: ` + getFriendlyURL(request.url)); + logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`); + logger.groupCollapsed(`View request details here.`); + logger.log(request); + logger.groupEnd(); + logger.groupCollapsed(`View response details here.`); + logger.log(response); + logger.groupEnd(); + logger.groupEnd(); + } + return response; + } + async _handleInstall(request, handler) { + this._useDefaultCacheabilityPluginIfNeeded(); + const response = await handler.fetch(request); + // Make sure we defer cachePut() until after we know the response + // should be cached; see https://github.com/GoogleChrome/workbox/issues/2737 + const wasCached = await handler.cachePut(request, response.clone()); + if (!wasCached) { + // Throwing here will lead to the `install` handler failing, which + // we want to do if *any* of the responses aren't safe to cache. + throw new WorkboxError('bad-precaching-response', { + url: request.url, + status: response.status + }); + } + return response; + } + /** + * This method is complex, as there a number of things to account for: + * + * The `plugins` array can be set at construction, and/or it might be added to + * to at any time before the strategy is used. + * + * At the time the strategy is used (i.e. during an `install` event), there + * needs to be at least one plugin that implements `cacheWillUpdate` in the + * array, other than `copyRedirectedCacheableResponsesPlugin`. + * + * - If this method is called and there are no suitable `cacheWillUpdate` + * plugins, we need to add `defaultPrecacheCacheabilityPlugin`. + * + * - If this method is called and there is exactly one `cacheWillUpdate`, then + * we don't have to do anything (this might be a previously added + * `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin). + * + * - If this method is called and there is more than one `cacheWillUpdate`, + * then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so, + * we need to remove it. (This situation is unlikely, but it could happen if + * the strategy is used multiple times, the first without a `cacheWillUpdate`, + * and then later on after manually adding a custom `cacheWillUpdate`.) + * + * See https://github.com/GoogleChrome/workbox/issues/2737 for more context. + * + * @private + */ + _useDefaultCacheabilityPluginIfNeeded() { + let defaultPluginIndex = null; + let cacheWillUpdatePluginCount = 0; + for (const [index, plugin] of this.plugins.entries()) { + // Ignore the copy redirected plugin when determining what to do. + if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) { + continue; + } + // Save the default plugin's index, in case it needs to be removed. + if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) { + defaultPluginIndex = index; + } + if (plugin.cacheWillUpdate) { + cacheWillUpdatePluginCount++; + } + } + if (cacheWillUpdatePluginCount === 0) { + this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin); + } else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) { + // Only remove the default plugin; multiple custom plugins are allowed. + this.plugins.splice(defaultPluginIndex, 1); + } + // Nothing needs to be done if cacheWillUpdatePluginCount is 1 + } + } + PrecacheStrategy.defaultPrecacheCacheabilityPlugin = { + async cacheWillUpdate({ + response + }) { + if (!response || response.status >= 400) { + return null; + } + return response; + } + }; + PrecacheStrategy.copyRedirectedCacheableResponsesPlugin = { + async cacheWillUpdate({ + response + }) { + return response.redirected ? await copyResponse(response) : response; + } + }; + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Performs efficient precaching of assets. + * + * @memberof workbox-precaching + */ + class PrecacheController { + /** + * Create a new PrecacheController. + * + * @param {Object} [options] + * @param {string} [options.cacheName] The cache to use for precaching. + * @param {string} [options.plugins] Plugins to use when precaching as well + * as responding to fetch events for precached assets. + * @param {boolean} [options.fallbackToNetwork=true] Whether to attempt to + * get the response from the network if there's a precache miss. + */ + constructor({ + cacheName, + plugins = [], + fallbackToNetwork = true + } = {}) { + this._urlsToCacheKeys = new Map(); + this._urlsToCacheModes = new Map(); + this._cacheKeysToIntegrities = new Map(); + this._strategy = new PrecacheStrategy({ + cacheName: cacheNames.getPrecacheName(cacheName), + plugins: [...plugins, new PrecacheCacheKeyPlugin({ + precacheController: this + })], + fallbackToNetwork + }); + // Bind the install and activate methods to the instance. + this.install = this.install.bind(this); + this.activate = this.activate.bind(this); + } + /** + * @type {workbox-precaching.PrecacheStrategy} The strategy created by this controller and + * used to cache assets and respond to fetch events. + */ + get strategy() { + return this._strategy; + } + /** + * Adds items to the precache list, removing any duplicates and + * stores the files in the + * {@link workbox-core.cacheNames|"precache cache"} when the service + * worker installs. + * + * This method can be called multiple times. + * + * @param {Array} [entries=[]] Array of entries to precache. + */ + precache(entries) { + this.addToCacheList(entries); + if (!this._installAndActiveListenersAdded) { + self.addEventListener('install', this.install); + self.addEventListener('activate', this.activate); + this._installAndActiveListenersAdded = true; + } + } + /** + * This method will add items to the precache list, removing duplicates + * and ensuring the information is valid. + * + * @param {Array} entries + * Array of entries to precache. + */ + addToCacheList(entries) { + { + finalAssertExports.isArray(entries, { + moduleName: 'workbox-precaching', + className: 'PrecacheController', + funcName: 'addToCacheList', + paramName: 'entries' + }); + } + const urlsToWarnAbout = []; + for (const entry of entries) { + // See https://github.com/GoogleChrome/workbox/issues/2259 + if (typeof entry === 'string') { + urlsToWarnAbout.push(entry); + } else if (entry && entry.revision === undefined) { + urlsToWarnAbout.push(entry.url); + } + const { + cacheKey, + url + } = createCacheKey(entry); + const cacheMode = typeof entry !== 'string' && entry.revision ? 'reload' : 'default'; + if (this._urlsToCacheKeys.has(url) && this._urlsToCacheKeys.get(url) !== cacheKey) { + throw new WorkboxError('add-to-cache-list-conflicting-entries', { + firstEntry: this._urlsToCacheKeys.get(url), + secondEntry: cacheKey + }); + } + if (typeof entry !== 'string' && entry.integrity) { + if (this._cacheKeysToIntegrities.has(cacheKey) && this._cacheKeysToIntegrities.get(cacheKey) !== entry.integrity) { + throw new WorkboxError('add-to-cache-list-conflicting-integrities', { + url + }); + } + this._cacheKeysToIntegrities.set(cacheKey, entry.integrity); + } + this._urlsToCacheKeys.set(url, cacheKey); + this._urlsToCacheModes.set(url, cacheMode); + if (urlsToWarnAbout.length > 0) { + const warningMessage = `Workbox is precaching URLs without revision ` + `info: ${urlsToWarnAbout.join(', ')}\nThis is generally NOT safe. ` + `Learn more at https://bit.ly/wb-precache`; + { + logger.warn(warningMessage); + } + } + } + } + /** + * Precaches new and updated assets. Call this method from the service worker + * install event. + * + * Note: this method calls `event.waitUntil()` for you, so you do not need + * to call it yourself in your event handlers. + * + * @param {ExtendableEvent} event + * @return {Promise} + */ + install(event) { + // waitUntil returns Promise + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return waitUntil(event, async () => { + const installReportPlugin = new PrecacheInstallReportPlugin(); + this.strategy.plugins.push(installReportPlugin); + // Cache entries one at a time. + // See https://github.com/GoogleChrome/workbox/issues/2528 + for (const [url, cacheKey] of this._urlsToCacheKeys) { + const integrity = this._cacheKeysToIntegrities.get(cacheKey); + const cacheMode = this._urlsToCacheModes.get(url); + const request = new Request(url, { + integrity, + cache: cacheMode, + credentials: 'same-origin' + }); + await Promise.all(this.strategy.handleAll({ + params: { + cacheKey + }, + request, + event + })); + } + const { + updatedURLs, + notUpdatedURLs + } = installReportPlugin; + { + printInstallDetails(updatedURLs, notUpdatedURLs); + } + return { + updatedURLs, + notUpdatedURLs + }; + }); + } + /** + * Deletes assets that are no longer present in the current precache manifest. + * Call this method from the service worker activate event. + * + * Note: this method calls `event.waitUntil()` for you, so you do not need + * to call it yourself in your event handlers. + * + * @param {ExtendableEvent} event + * @return {Promise} + */ + activate(event) { + // waitUntil returns Promise + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return waitUntil(event, async () => { + const cache = await self.caches.open(this.strategy.cacheName); + const currentlyCachedRequests = await cache.keys(); + const expectedCacheKeys = new Set(this._urlsToCacheKeys.values()); + const deletedURLs = []; + for (const request of currentlyCachedRequests) { + if (!expectedCacheKeys.has(request.url)) { + await cache.delete(request); + deletedURLs.push(request.url); + } + } + { + printCleanupDetails(deletedURLs); + } + return { + deletedURLs + }; + }); + } + /** + * Returns a mapping of a precached URL to the corresponding cache key, taking + * into account the revision information for the URL. + * + * @return {Map} A URL to cache key mapping. + */ + getURLsToCacheKeys() { + return this._urlsToCacheKeys; + } + /** + * Returns a list of all the URLs that have been precached by the current + * service worker. + * + * @return {Array} The precached URLs. + */ + getCachedURLs() { + return [...this._urlsToCacheKeys.keys()]; + } + /** + * Returns the cache key used for storing a given URL. If that URL is + * unversioned, like `/index.html', then the cache key will be the original + * URL with a search parameter appended to it. + * + * @param {string} url A URL whose cache key you want to look up. + * @return {string} The versioned URL that corresponds to a cache key + * for the original URL, or undefined if that URL isn't precached. + */ + getCacheKeyForURL(url) { + const urlObject = new URL(url, location.href); + return this._urlsToCacheKeys.get(urlObject.href); + } + /** + * @param {string} url A cache key whose SRI you want to look up. + * @return {string} The subresource integrity associated with the cache key, + * or undefined if it's not set. + */ + getIntegrityForCacheKey(cacheKey) { + return this._cacheKeysToIntegrities.get(cacheKey); + } + /** + * This acts as a drop-in replacement for + * [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match) + * with the following differences: + * + * - It knows what the name of the precache is, and only checks in that cache. + * - It allows you to pass in an "original" URL without versioning parameters, + * and it will automatically look up the correct cache key for the currently + * active revision of that URL. + * + * E.g., `matchPrecache('index.html')` will find the correct precached + * response for the currently active service worker, even if the actual cache + * key is `'/index.html?__WB_REVISION__=1234abcd'`. + * + * @param {string|Request} request The key (without revisioning parameters) + * to look up in the precache. + * @return {Promise} + */ + async matchPrecache(request) { + const url = request instanceof Request ? request.url : request; + const cacheKey = this.getCacheKeyForURL(url); + if (cacheKey) { + const cache = await self.caches.open(this.strategy.cacheName); + return cache.match(cacheKey); + } + return undefined; + } + /** + * Returns a function that looks up `url` in the precache (taking into + * account revision information), and returns the corresponding `Response`. + * + * @param {string} url The precached URL which will be used to lookup the + * `Response`. + * @return {workbox-routing~handlerCallback} + */ + createHandlerBoundToURL(url) { + const cacheKey = this.getCacheKeyForURL(url); + if (!cacheKey) { + throw new WorkboxError('non-precached-url', { + url + }); + } + return options => { + options.request = new Request(url); + options.params = Object.assign({ + cacheKey + }, options.params); + return this.strategy.handle(options); + }; + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + let precacheController; + /** + * @return {PrecacheController} + * @private + */ + const getOrCreatePrecacheController = () => { + if (!precacheController) { + precacheController = new PrecacheController(); + } + return precacheController; + }; + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Removes any URL search parameters that should be ignored. + * + * @param {URL} urlObject The original URL. + * @param {Array} ignoreURLParametersMatching RegExps to test against + * each search parameter name. Matches mean that the search parameter should be + * ignored. + * @return {URL} The URL with any ignored search parameters removed. + * + * @private + * @memberof workbox-precaching + */ + function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) { + // Convert the iterable into an array at the start of the loop to make sure + // deletion doesn't mess up iteration. + for (const paramName of [...urlObject.searchParams.keys()]) { + if (ignoreURLParametersMatching.some(regExp => regExp.test(paramName))) { + urlObject.searchParams.delete(paramName); + } + } + return urlObject; + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Generator function that yields possible variations on the original URL to + * check, one at a time. + * + * @param {string} url + * @param {Object} options + * + * @private + * @memberof workbox-precaching + */ + function* generateURLVariations(url, { + ignoreURLParametersMatching = [/^utm_/, /^fbclid$/], + directoryIndex = 'index.html', + cleanURLs = true, + urlManipulation + } = {}) { + const urlObject = new URL(url, location.href); + urlObject.hash = ''; + yield urlObject.href; + const urlWithoutIgnoredParams = removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching); + yield urlWithoutIgnoredParams.href; + if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) { + const directoryURL = new URL(urlWithoutIgnoredParams.href); + directoryURL.pathname += directoryIndex; + yield directoryURL.href; + } + if (cleanURLs) { + const cleanURL = new URL(urlWithoutIgnoredParams.href); + cleanURL.pathname += '.html'; + yield cleanURL.href; + } + if (urlManipulation) { + const additionalURLs = urlManipulation({ + url: urlObject + }); + for (const urlToAttempt of additionalURLs) { + yield urlToAttempt.href; + } + } + } + + /* + Copyright 2020 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * A subclass of {@link workbox-routing.Route} that takes a + * {@link workbox-precaching.PrecacheController} + * instance and uses it to match incoming requests and handle fetching + * responses from the precache. + * + * @memberof workbox-precaching + * @extends workbox-routing.Route + */ + class PrecacheRoute extends Route { + /** + * @param {PrecacheController} precacheController A `PrecacheController` + * instance used to both match requests and respond to fetch events. + * @param {Object} [options] Options to control how requests are matched + * against the list of precached URLs. + * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will + * check cache entries for a URLs ending with '/' to see if there is a hit when + * appending the `directoryIndex` value. + * @param {Array} [options.ignoreURLParametersMatching=[/^utm_/, /^fbclid$/]] An + * array of regex's to remove search params when looking for a cache match. + * @param {boolean} [options.cleanURLs=true] The `cleanURLs` option will + * check the cache for the URL with a `.html` added to the end of the end. + * @param {workbox-precaching~urlManipulation} [options.urlManipulation] + * This is a function that should take a URL and return an array of + * alternative URLs that should be checked for precache matches. + */ + constructor(precacheController, options) { + const match = ({ + request + }) => { + const urlsToCacheKeys = precacheController.getURLsToCacheKeys(); + for (const possibleURL of generateURLVariations(request.url, options)) { + const cacheKey = urlsToCacheKeys.get(possibleURL); + if (cacheKey) { + const integrity = precacheController.getIntegrityForCacheKey(cacheKey); + return { + cacheKey, + integrity + }; + } + } + { + logger.debug(`Precaching did not find a match for ` + getFriendlyURL(request.url)); + } + return; + }; + super(match, precacheController.strategy); + } + } + + /* + Copyright 2019 Google LLC + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Add a `fetch` listener to the service worker that will + * respond to + * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests} + * with precached assets. + * + * Requests for assets that aren't precached, the `FetchEvent` will not be + * responded to, allowing the event to fall through to other `fetch` event + * listeners. + * + * @param {Object} [options] See the {@link workbox-precaching.PrecacheRoute} + * options. + * + * @memberof workbox-precaching + */ + function addRoute(options) { + const precacheController = getOrCreatePrecacheController(); + const precacheRoute = new PrecacheRoute(precacheController, options); + registerRoute(precacheRoute); + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Adds items to the precache list, removing any duplicates and + * stores the files in the + * {@link workbox-core.cacheNames|"precache cache"} when the service + * worker installs. + * + * This method can be called multiple times. + * + * Please note: This method **will not** serve any of the cached files for you. + * It only precaches files. To respond to a network request you call + * {@link workbox-precaching.addRoute}. + * + * If you have a single array of files to precache, you can just call + * {@link workbox-precaching.precacheAndRoute}. + * + * @param {Array} [entries=[]] Array of entries to precache. + * + * @memberof workbox-precaching + */ + function precache(entries) { + const precacheController = getOrCreatePrecacheController(); + precacheController.precache(entries); + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * This method will add entries to the precache list and add a route to + * respond to fetch events. + * + * This is a convenience method that will call + * {@link workbox-precaching.precache} and + * {@link workbox-precaching.addRoute} in a single call. + * + * @param {Array} entries Array of entries to precache. + * @param {Object} [options] See the + * {@link workbox-precaching.PrecacheRoute} options. + * + * @memberof workbox-precaching + */ + function precacheAndRoute(entries, options) { + precache(entries); + addRoute(options); + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + const SUBSTRING_TO_FIND = '-precache-'; + /** + * Cleans up incompatible precaches that were created by older versions of + * Workbox, by a service worker registered under the current scope. + * + * This is meant to be called as part of the `activate` event. + * + * This should be safe to use as long as you don't include `substringToFind` + * (defaulting to `-precache-`) in your non-precache cache names. + * + * @param {string} currentPrecacheName The cache name currently in use for + * precaching. This cache won't be deleted. + * @param {string} [substringToFind='-precache-'] Cache names which include this + * substring will be deleted (excluding `currentPrecacheName`). + * @return {Array} A list of all the cache names that were deleted. + * + * @private + * @memberof workbox-precaching + */ + const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND) => { + const cacheNames = await self.caches.keys(); + const cacheNamesToDelete = cacheNames.filter(cacheName => { + return cacheName.includes(substringToFind) && cacheName.includes(self.registration.scope) && cacheName !== currentPrecacheName; + }); + await Promise.all(cacheNamesToDelete.map(cacheName => self.caches.delete(cacheName))); + return cacheNamesToDelete; + }; + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Adds an `activate` event listener which will clean up incompatible + * precaches that were created by older versions of Workbox. + * + * @memberof workbox-precaching + */ + function cleanupOutdatedCaches() { + // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705 + self.addEventListener('activate', event => { + const cacheName = cacheNames.getPrecacheName(); + event.waitUntil(deleteOutdatedCaches(cacheName).then(cachesDeleted => { + { + if (cachesDeleted.length > 0) { + logger.log(`The following out-of-date precaches were cleaned up ` + `automatically:`, cachesDeleted); + } + } + })); + }); + } + + /* + Copyright 2018 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * NavigationRoute makes it easy to create a + * {@link workbox-routing.Route} that matches for browser + * [navigation requests]{@link https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests}. + * + * It will only match incoming Requests whose + * {@link https://fetch.spec.whatwg.org/#concept-request-mode|mode} + * is set to `navigate`. + * + * You can optionally only apply this route to a subset of navigation requests + * by using one or both of the `denylist` and `allowlist` parameters. + * + * @memberof workbox-routing + * @extends workbox-routing.Route + */ + class NavigationRoute extends Route { + /** + * If both `denylist` and `allowlist` are provided, the `denylist` will + * take precedence and the request will not match this route. + * + * The regular expressions in `allowlist` and `denylist` + * are matched against the concatenated + * [`pathname`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname} + * and [`search`]{@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search} + * portions of the requested URL. + * + * *Note*: These RegExps may be evaluated against every destination URL during + * a navigation. Avoid using + * [complex RegExps](https://github.com/GoogleChrome/workbox/issues/3077), + * or else your users may see delays when navigating your site. + * + * @param {workbox-routing~handlerCallback} handler A callback + * function that returns a Promise resulting in a Response. + * @param {Object} options + * @param {Array} [options.denylist] If any of these patterns match, + * the route will not handle the request (even if a allowlist RegExp matches). + * @param {Array} [options.allowlist=[/./]] If any of these patterns + * match the URL's pathname and search parameter, the route will handle the + * request (assuming the denylist doesn't match). + */ + constructor(handler, { + allowlist = [/./], + denylist = [] + } = {}) { + { + finalAssertExports.isArrayOfClass(allowlist, RegExp, { + moduleName: 'workbox-routing', + className: 'NavigationRoute', + funcName: 'constructor', + paramName: 'options.allowlist' + }); + finalAssertExports.isArrayOfClass(denylist, RegExp, { + moduleName: 'workbox-routing', + className: 'NavigationRoute', + funcName: 'constructor', + paramName: 'options.denylist' + }); + } + super(options => this._match(options), handler); + this._allowlist = allowlist; + this._denylist = denylist; + } + /** + * Routes match handler. + * + * @param {Object} options + * @param {URL} options.url + * @param {Request} options.request + * @return {boolean} + * + * @private + */ + _match({ + url, + request + }) { + if (request && request.mode !== 'navigate') { + return false; + } + const pathnameAndSearch = url.pathname + url.search; + for (const regExp of this._denylist) { + if (regExp.test(pathnameAndSearch)) { + { + logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL matches this denylist pattern: ` + `${regExp.toString()}`); + } + return false; + } + } + if (this._allowlist.some(regExp => regExp.test(pathnameAndSearch))) { + { + logger.debug(`The navigation route ${pathnameAndSearch} ` + `is being used.`); + } + return true; + } + { + logger.log(`The navigation route ${pathnameAndSearch} is not ` + `being used, since the URL being navigated to doesn't ` + `match the allowlist.`); + } + return false; + } + } + + /* + Copyright 2019 Google LLC + + Use of this source code is governed by an MIT-style + license that can be found in the LICENSE file or at + https://opensource.org/licenses/MIT. + */ + /** + * Helper function that calls + * {@link PrecacheController#createHandlerBoundToURL} on the default + * {@link PrecacheController} instance. + * + * If you are creating your own {@link PrecacheController}, then call the + * {@link PrecacheController#createHandlerBoundToURL} on that instance, + * instead of using this function. + * + * @param {string} url The precached URL which will be used to lookup the + * `Response`. + * @param {boolean} [fallbackToNetwork=true] Whether to attempt to get the + * response from the network if there's a precache miss. + * @return {workbox-routing~handlerCallback} + * + * @memberof workbox-precaching + */ + function createHandlerBoundToURL(url) { + const precacheController = getOrCreatePrecacheController(); + return precacheController.createHandlerBoundToURL(url); + } + + exports.NavigationRoute = NavigationRoute; + exports.NetworkOnly = NetworkOnly; + exports.cleanupOutdatedCaches = cleanupOutdatedCaches; + exports.clientsClaim = clientsClaim; + exports.createHandlerBoundToURL = createHandlerBoundToURL; + exports.precacheAndRoute = precacheAndRoute; + exports.registerRoute = registerRoute; + +})); diff --git a/packages/app/index.html b/packages/app/index.html index 13952479..0ac43e97 100644 --- a/packages/app/index.html +++ b/packages/app/index.html @@ -2,8 +2,15 @@ - - + + + + + + + + + AIUI diff --git a/packages/app/package.json b/packages/app/package.json index 2ce6c5f3..f2b5acbc 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -6,7 +6,9 @@ "license": "MIT", "type": "module", "scripts": { - "dev": "vite", + "dev": "tsx server/claude-proxy.ts & vite", + "dev:vite": "vite", + "dev:proxy": "tsx server/claude-proxy.ts", "build": "vue-tsc --noEmit && vite build", "preview": "vite preview", "test": "vitest run", @@ -16,18 +18,20 @@ }, "dependencies": { "@aiui/core": "workspace:*", + "pinia": "latest", "vue": "latest", - "vue-router": "latest", - "pinia": "latest" + "vue-router": "latest" }, "devDependencies": { + "@tailwindcss/vite": "latest", "@vitejs/plugin-vue": "latest", - "vite": "latest", - "vue-tsc": "latest", - "vitest": "latest", "eslint": "latest", - "typescript": "~5.8.0", "tailwindcss": "latest", - "@tailwindcss/vite": "latest" + "tsx": "^4.21.0", + "typescript": "~5.8.0", + "vite": "latest", + "vite-plugin-pwa": "^1.2.0", + "vitest": "latest", + "vue-tsc": "latest" } } diff --git a/packages/app/public/apple-touch-icon-180x180.png b/packages/app/public/apple-touch-icon-180x180.png new file mode 100644 index 0000000000000000000000000000000000000000..9ceecbe9ff53b7132564cd445fad6dc08dd717af GIT binary patch literal 22652 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⁢lcYal$Jn#aOaazmwU2+xQn@Z|-LwEIB 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 Ne9-p*=N~67{}(P=0LB0S literal 0 HcmV?d00001 diff --git a/packages/app/public/favicon.svg b/packages/app/public/favicon.svg new file mode 100644 index 00000000..83399c70 --- /dev/null +++ b/packages/app/public/favicon.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/app/public/icon.svg b/packages/app/public/icon.svg new file mode 100644 index 00000000..b5c2c8b1 --- /dev/null +++ b/packages/app/public/icon.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + AIUI + + diff --git a/packages/app/public/pwa-192x192.png b/packages/app/public/pwa-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..f3c8dfd28a8810b5b989343daab7a451bd91b70c GIT binary patch literal 24746 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 Ie)i`70T1%)>Hq)$ literal 0 HcmV?d00001 diff --git a/packages/app/public/pwa-512x512.png b/packages/app/public/pwa-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..b731afd101e88503c38970eacac29a49b8ad4e5a GIT binary patch literal 140280 zcmdR$d012D+U}jHqR~xA6!75^}O$sX|4DE zJ@>nkPq;d5+OU1YiWMt19sBZ&uUD*C1^l^c#e3_3UrTYlGT_%r)Ynd*uPEsjmf7P##tXgq@_22*21V7oINnNqx;EH2k z9Qr11<^1Teq9W`mh)ST3zyI{&ds|aox9UFQXo)xWeo}TXYisI_3mH`RT_9s9WDkS}_FA$@jEQ5vQmF&(k}P%2CYFbafKK!h-qULZG4(m$P zm8e0A=b#a6w*j`Br&dzcv8-hQNG%v$ZL<9HXrhT?Y&6k$={^J}^1zFD914#UW+N3J}()!WV zs{@yLeF-$0>Tn>p%nq~PjTyJVCFUxHPMBarbNsnNWlgfURsiRgjo2TO-Af{R3yK)R zf`|k~a$7QQzN2cE!-BQICWcQ6*N z?x1-w1b3COyt3N->8{$BlF5MR;#s?FH2W@cb}zE4_-ARl^aQ<7NL9k>yh&(?cRl5a zRaz_81w^bCS`yTsy^%Zi2N3uj(t7rd{0QGA0dOo!ZC1!(*SSO)nc_d;tCFG$j^tF< z<%zG*akB)g>48GwDTJy&=Z?pR#>yEdK4r>_a$eHORCHnzUK}=lm~bUUQ{@@&AIR2f z*#H$MdFerk#81{MDZ6D(S9XZ8b6tZ&`UYi=Q8Y92FxXf*VhKJJ5n{0e$>o>W;W12y z>S@R6di}U))c|7s%gQM8v3`*Yq&;+%X(kzyEOny?tD~o71JjOSo#*{9Uzu2r%!R7O zYw``W%Ih+-@Sqy;6(^k>{SrQ28m_3SDvGK+Y zh??@FHTv}ICqkVxzGDQfpnVs83*lLc`jx6$hD2u*8$@*uYL4#B60P~+B3AFz%>Zq9 zUkkJPG|j6)7ySf3O)g|Ku+#GIG~J=r`qeQ8+((rDY9zLn}T46@cz-e6w8ky+M})gFe(;3P$PNq{`R?KS%Z z*}!)qMH+NgcN+NU_Hp^Rha<|S_fWEkTf}F=-pAiyrK)bm z^miih)~98L*Co%j6J~3%1V|woGdK~iPO2!!^Zf`{q1=0mOHl;+hRHjZOk@vChOm4I zj?YV>E~nHdlqU0|;VT%j{%RgULS}P)m!BK(R7$2=IkSoDTJvF7wqu=RfS+PXPs9+A z7!5PayyF!EeK$^*m(~tUo__Z*6eAcJ3@k0QFR!Xp7Ybns^7=Hd0nmU-C>2wyiB!B- z>;RWYbXdM+BE2;VSN6iWl*Jv??iikaTxr~@n{XaXEu}Ldl3My`!>kK(NF6ZIFG>fY zX>%uv`H#SjD&09K5ad-2hYhRaocF`#R^_+f$_1f84dGVoa)UazSLjzUj53FBwEYKB zZ0mv)j~DbD@&K55W*j^=&=HkTJ$q|71+;R_PFRw9J^+T16a_#+B)8HNnnQ7$*?G_N8dAF_FF~Dr zT{ld-J#E}an3=SSF@2Jn=HITT>hc{-ghY>^7EhR?-Q`n0tVB#tCCJ*#xXw`z12>W! z2Y=&Ci1r}jr|*S=3|gS1w0aZcXM5-}Zz!G}iEN>`IPy4`l7idHc}2raK79Rj?6WmW z3w=z@zG*{2&uW+i1*?|dBTDa$dL*=Xcvnq9`qgOZnla6Zo41V~*UF=-=IJrgwU8ut z<|PkHi!7~W#j5M~wUi|RuDoSJ**cU~>R!4pr2a~GY=_AW_Crpt)@r$Jxq5tVb^ZsX zQFEitcy<#!1y1P0mRhm#+-^Y@y5M`!E;qLUuERpGB7*slFb8qBqb9)e`|&@f@UzDn(5YVmsK1hh8l;wQNQJ z-D|PDWFSG`8f}7}vSyyJDd{p*SIgFh5H@F(y|!g5o)=FjU}`tR^!q}K8SScm=LZYYN2DFH*fLTA0kR$ z4KFvqxnr&k%bZ&98-|#F8|q&eBnqz|EoK$u2l-xbB{Hvb;%OD6``Fxvp__;hM4p<9 zJX?F9)^`G(=MGNgkn3D>hObNEhvarghPOj8lzOC^F>GHZw4>>nGyA1ZEb*n9v6rPD zbEmoWUGrkN4*7L9(=f|!CV7pI3eh!8k=~D`tn9EoU3lK4aA@)~Q{<+}!uj|o_l)OKM8f&*R#6|Xc@>g z!v3F26)#KYjTbIzMdi@jmQk|x2MM#vHlm`97mJs~N~kFH!|H=!Gm0C5X(K zNpQ`bqg?m#GG%~{%fx&^=62O*Y$jF@co&Q1BTeKgfnPNu$~t+pE4jRP!J}H;qE;fP z53BK`b!tpuzgcw&Hdjhjz*H=lIB9rVoECc{a4B3qg<46K6;kWeZ7WMRGP|+#0B8Vl z1zB8KItr1t!5M0(3Vm<%%M(62!V8wVGHDodQ*LHTq-liH_$GnPRrcfc;;$eC-_GQ- zoDY$UZl-)?OGt5?cgTl1=okFlCr3d~Gr@0iw^oG(2ZU;tFuRk+9q(#!_XKtycwKdL zqv*C)j$Tv03%96Pz(B-%ni&sdH;W@*n1Hy@8u40F4^bIK!gpG-*B5uR3TyQg<>yftp-@C=%1Aw-SHfMb`#nA0x*%*(NmcG}k~0 z^~{&)^gW7P%&MEzl1wd?;#=ks_pnzZ+bHwxlnd(Dw;WTn6k`eWYwN_`-upSdj;@li zpc0G?^>JvYeFPuY;K8~1BxG?2Aqh^6r=N}(8&j6$06cexBqL|XuF4umh3+$%|F$~0Ylx>hN88OAu;rB=4F=Z0&L z9;$Gd*bi1EFJ{V$l?aPm6(&+;4=m-@g5nx^ws@f}XekmO_DC^DGxYtbO@0WC_=LX3 z1H`YlYIfwW2@V@6Xw>Qpx1yC+_|zZ2pdR&$6tprjuuZ%xiG|z49@{@YiuxeRm7AAK zwv3nOy=ibQ=zM_l}l)Pk{GliuJJ%Ug6I1?5qS| z>`eav?QCaOx&l9;M|=Z28fQ}jG2(9;pp0E+Do2?O>JzdiWAXke%svK-xMETwV(Vq1 zXVoKjGNp1yRl-dWNVEo1yBH3v+jZiC4NcxH`MbX>R=8pI#k$_aO^=&qf(s=Hzr}#7 zd$hci=P1NQe#L`sLjSVrhXR7(muyntlK?XyH|&>O)NheLj2nUW+L^u$`kt|hsp2xl z@HI1+u@+WOFu*HI#>jez6t&~(ab5w(SiWW_s1r8zH~8RGfQ&tt0u8C{78t{EUo<&8 zCK)fYh_T>W25)CufMFQVsRRx#&QVa}QYcHRw90wx5l57YXU_`E1vMlP*jwnaWv_*aQy6JE+LSfP3`9j|Bwt&L<~^m37>9jc$0 z@ZiTiZV?@i{UO|_ditlue${8lkikMo<4lXfOIdFVM~#NGy2aj02*Hb~bJ%EAY{K)p zy1lhAUIW#ooIWm|MqKq$G|PD%fv9h9^{S@#Db>qryz+~k1Kq4+lm}7DsuCoVlAbWR zJC=^_LdEFfmzzKs6eCg%;jRDK*;jCT6r_9&8eQJm+P_V5g`T?jvlcX5orhm0BU#&q z|EA*gMUbs%#WFE$;+Ms~TlC_Ru_F&>6*lS)#&AAR28#%eY3@26s%h807F3{mw47xQ z7na+q`=m@|HJ<6}RW=-Q#fvb_=9X^pE~e09{wr<3%PNu7>c>*I0ZJs@6zzMmi{%VG zd>1<<^pm!}X0Kl2L1J^`eNQgu!({oREE9E{0JDbSM_4g=PSwR%bn$f63%dO9v${S7 z2^X8%m9=Gp@l?ZPdF%1qsjKV#yMNZFB!;Xx#@eIiH8?`mIrX$0p0>9MdHH03X)s{ln+&HfEzc60bysI;gmIKJPahk5ch)GCri~+%52{- z@^o`~zwHm(Z#aR=j^ILfi$1@L=dI%4Y0hxv05^+H!?jp4m_`-Qg)H zs{OmVKt{Vr3}hC|=a7XbHL}C6nhNz&(IvvzQ2r)1(Zr;qa3vZJW9Kl9Zqo7;?n7>L zHHIp|#A;Uc5#wiyRlWsla;9ov{AF z8|QP$tU)L9tSN_R*NnQjD++QOrc;=Qt}rXX zTxb#JGc*FmJS#d{RSkPuZ(MRRa&dzfF|GtX+y$2D+sca~WId03rgj zS0f@KU4ekKyVWT_DffUPui>*Ef&;HM?&)1{p;Az?*w`>TWRPvHJKF4p#>W39Mu2ZK zm#W6dxqKCH-s1Nd#RAtaK%~4>!tiz$rRyd`XNnRI>?~aum41qBfRGC+5%S7)KR7xSR}EPi$J)WHkuRF47nSl)ghd|et%BFi6prrnLz%Rr8SB^iEtc`VnUA<^ zqR9nj&akgAiM0@u{e0Q~2c-oRBQhRlD(oZZj?*Yyck#KA5fs0iU93?s@#$QoDz}Dh zB($f_xLbztY9)h0cSRB1S9;YNzUE=O*DJKmPMBr*%a_A%@X}0tE&j;ZW@T~zh&g

PV8#5}*@94~56`F1t~E|HB=)&-ALP%PkoJ9w^bK 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 z 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∨8~!9O0F&dir;QY@Xv~9XFpjD-ov}f3|RF!RLdY5KvNh} z{xyxVHyMit8K2hgBI3kn;@FNCOsR&9{iP(HY?#2c7@FpY3CKp7?4-Dz@h+`BzszOs zGl*cgTkJGa%lMnxa9ePcn4lZQj35$l0ie5jLQ#P@9LbZaJ+mSR(2_YG00T)|RuB-rCYXC0f7AfC0sQv zW&ncdcPo%(Z9N46K$KAvLq15T(@3L0LM_0*W$Poe4JFc1)rImXa^0ow6s&@Ktv_27 z%BrU^TI@5mzwtqgGWPXRQDYMUlZPvy1-u`UUdA`#}o&xhfP|Owf zaIKcA#|8}?>Ad84LaX0reILIugJDSpYz>c z`}f2AU63yB4(-??)dKxl{mOzmK$d&iD&h3i`*+w+!lVnU=X#TiEHp%01N4BmWR40! zsy`@XCVHqmf~&O2!POm7YJ5ZRUKyK$Zda6`f~P>X_iq1TUCAC`()zgGjU5p_wXeE} zrL&<#uBAkEPbTWKTwHD;8}dgv@nViNm!*j89c;a)7KqJtHEIJAr(O8}Bhv~rsb8oe znC*76R==I%Qi|aU8qFs2`%Lja^>^kNE#!G|zICF&v%}awzx09K;AxlW%_w)!8I0Tkj|6@hA-wj~^Cgr}?#jL}&OZK~E$c1XtCwLMU<*jpFy>$Z+Q~XzhmwlXQu@Oo^e>K4E z(?rblRE~ar>CSq0gc*+nZhlg5Jg)&<vWb!OMeMog4zz&^SK_v4A$4 zqkeB0goRLZ1L}W=D6GD#ztiZFj=9I|a_Rz&80Ao%{F*q=OtvxJ%L+Xuj`rlQ4sI%G zBJJGOh7Opc0Jd9bvHspk12 zkz={8&UJyvh}Jc+Z*x{Yh5NACVI1;j(EC4iJ(?h-b$@TSA^!4S;THo58Sd!GH(!q^ zuf?5Vv}FZFu_Sr5eQ68uTbNt7^-@={>eUQ?ytmhPmAk0)>)f$}$Q0TIhaim{uHv8a z@N8du_tDXon$z*`33ay)mH>J+Qr|n14p+7KHLnf>We2{^gBn1S{a<1>DK?DNg5C*c z2XCn;i;4GOuY5@J3l-#tj3IwmDBs{pLgD5uRJ%?L(&@08xHpN*`?THfs{@Uyxi53W z*M!|Iem3>d`<`QoJr$fzo}kT*GqKp>Za<)(2c0o} zPU$saH-WbWh>=ZOMi_qSuJ35WG3_yU%TDol~F zRyQ_H|3o@5uj>{$h6kovu%~gR!{;H@Ce?Q0YZf`@gC~mKQOD}SiFtN#<_@@mYrl5T zLl7%~_KCPYvQpQ6SfuanUQw!}FzDRc)=EB4C&l%;`_?gQ;wx(C!-FLI#|`f3SsAeH zDCk-}lCk*o`DMOXf56ClukT#cqDpA7MZT#F@K&>#B`6r6_CDf|ZSpJ^r_L(A%-#)lc-ZOoOX^%(tLGY&!gonCylW@QOD$xdaYd z)u-%Bi58ky8KpTc0q4Ac|5KbiRHFYVS^t`gIAu00S+p+CcYkWBxFnTe*JUUwkGl{$ z+}9-9HnfHS^t0_G1qow8<+lz(#Y40QPxWPbqC;N>4B1cRWqtF4X*&0T%aOq0c3Xiu zlnw9)`4d%AzbAe1Ym_O|=uWKWRnnyU$(tIuZQ71QzKn>SlGV_P&CCg*; zbzkOn7odPGfU0EBa2oQx#f`a&P$IzsdZHH|1FciQH<>OSmnUGL@5Did+ym|oUq*;B zyz<%tYr*umbsiw2#xgwvo_Z)KUsYd}S3tKE@V$CNnQI=#GM59~dcOFyJt@A|!z>w? zN!HE@msVVG=2ptes2lEfdf{rpvTxhE8e5Y?I%^#e^Mkejv{F7@v&{SJ%C@guLeSuL zFyoSzctPMF!&B3_syY~F(C8kG36Ag%#HLi0BpK4;m^Krq^w|q;X%$1k%y1G!c4gu| z!aHm83UPyi2g8+JHvk@9QH*ztU5XGnS*>3)$?sc@Sfe{RJWVh-=gLDW6l7+^K}(FV zCq=*)_JA}p#f)XrW~f$ZkOwKvmV5JPKr+W!!){q_mJnA?mc3%q%6Sd2dNZLa^Kh|y z6xH^&ZFGf;YDz^KiUtnRg5+l?>Z87WOMftML)U)RAWq7R$9OC>ZhYQ2>hL`#m)&u{ z;Rqfh0cLUjjS`?xgRfOvv*;2H2uxF)s7w?ku5zJ{^ zUiiD7W94DoY`pd$*w~*2sO;nWpQ`M>A%M&+77RtzEJq6t?B!YDvTh>W;o5#~4Ilc2 zH5?-AE>AN$l=$pqKeXouHYL+a^@M#~G3-=rHvmtQFiX9Co`|(?_4oevtY|1oAY2(i z35XLo4B;g}UVA|z&$Sk4ZUxV7Ie*>rYfl7n)w@m$wsKrBuiq=d%AZder){yWvC(jP zH3+nBeYjL~AoXA)pxYyN$((@@xFCw|W=U?T1D>71nx{te1snN)HlkCKJHocSV-+Fc zvs-3v<;`RpIHzR^sg8SMw3aRU(`y4IC-AhMS09b7iaXktyx{k4Kk!6yMd($Vn*wY| z@+AZ-7(0;g)CsP#(u-~lsJ_Z7(>B}}V0u7y_~blr8}5f`wTlP~h%xUV+sR)V(aKM^PQ08lWr^&b1F=^J(jOR#Bh zHjXFEsE>HrmUv$Mnx)b{2LlpFOCAEMyq>?tHTSVPe@?PWbMzp^W1(49B>BR|=8!SL zAq;6Vl1P{xSrv%O!D~K}FiLVygq8B$B}vr#4e@_BjCXm1j%-~p5L`6N^lMtu)LqC$ zx|cTy?j>#Q+bAk5%;ZtsgyeU?oTteDcgyDE0EpE-qAR292iS-fKt9ts4CdF=i|^U3 zIJ+1(OSS_%MIOPrnn_--F9eg(z(dkDln<3p9t5nM-e^)qDlgF9k0^R;-c>izA<8xa(-KdO-$)`&! z5Hnmh;AlLS===4C^_>K7WHar2L9@@_FWLX5Y7G4eM-l(uaTLEnc3^Ll$$zxEB%4?X zHU-W~_JsXas_rWyY^f+8+Gvv>#MgyuE}0M2*;XK-)juH`d|yN~q>)?5`MB(UWQIwr zL$Eb{S-Y z{b!8An1dP#3&HU-v?er-Qte4RXzMk--{*7!v@}uW#Uce(*4HeM56W-f;6<@rq!6*n zlGH`KW`8oVK!ptaj0&mtN;5X}V{&VAJEmAd2UXGme2OS9frb>a#is9WdoFABr}Q z9fNZ`XUqrF?fq5T#6Bw04qODT1FaubgQUsGJ;2d@yfS8@cmjdbhfYX#05uHPu;Zh`^)vMM132&;3QB}_2>c6n_g@J7zu)a{zD6dh)L>VI;aDH_i~jsD#V%xi zRtN1n<+Q~~6OkrMAYQnxp!B2nW5S-h+jqX$-H!PekK;7Y#np?KS!*Zt_t}=$ExP-P zZqZR}iz8W~giK2e=)FQ^H_IE;=}HJIlCZ>uonx z&-XVD=`NXR01aYlsq2h8s)}!#nH#Q@w4rSdZ+XQk7{*08fnc^bOr^WxnGRR_M4k^! zs@hx}Vm@k@euT?CTsKthguK~?(teBskMpR<`nAdt#+%EbP@$j`_)s{j-Dixd=YIQt zYZP$!-pkZH8^8eI>}K_G#=8URH|((DErY&UkK9z(&7;DcGr4W`1%MA8AXR>^5B{mE z|3`bh!;b*AL2Q2;NqOgQpX{a7ta<#UyCvbS7}U7(e@-F%=!X9cHz;Nb-0j{>Ym!?H z=-U&N@c3ngqR6bZZ`BV{t=xWv~@Kg6kX=Ga6e3 z7#1MINUSOHeen7xz&!}~inwAubWrt4rk8t-8cHz2Z4<8S= z*;rK*Z8r9P-?TwGeq*RNlMdz8|0ZQaO4 z%m2U{Z$oQZfxnL>Nf{=uXF2S&g?#sa71Dm5{T4y3*4=ckMqIa9BksuN8d2#NWOMVQ z9?09>(H;?+FA-}(W6ADMoe=lyr|z7nW%aWP5vYnvj^<0?s6fCc@w{qId!HGBrd}bs zTRP0hYf5E<5M$$qv>E)r0MHM<~wy{Loi+4 z0nu9xn`_#JI8A8#jKW?IyIH_|UmanE&UVXqb*GqRz|mGm-xs^f_5a8Luk2G_U~Kr* zuF6LG>GQ_Gk{(c}a61)gH0N0}J8y*rqHtyXbE;`&Zxi#WF~9v;P8~VNe_>9&I)Q25 zdkp%??KQEvZSvmuGzE7K=c>E~{9yn><21kClsFGSY|-AGC3QNC?Af^9A>J6kUWCk~ z>+jF{mK7#wQ9$;aoS@*Q-A5+V<^TsguLGB1z9wc4SdVN{HHp~Y(w_)M$(1)9yoF=- zhw8K+=?~RXXqTrKc!4&tgZkW+zAK^M6lau%2v_5tAQzh=j}e^=fp)1FjsCn({MXyC z+EdT03;eUJ0Bsl>>c`xz_OqSK@)gJk%Y@uG5Wmg47G{%g?TmC2>yjpWCTxFuc*3Hkb=FQip1Fz# zb1idF>gu@+^l<+J{%RHJ!7`(qs2eeAwUIk@jgUEC^2^t4tSo{E zEmwUiTdLEH(mCh`-&C&^an@u7ZenIfn>IPWk|aAI%fH4t-%zIr*=b(<1!ha1x`F$U z#p|XaW0WrUc;dMoy(Zxsz?T-(%-dNat7NvbZ>;R1V%7v_wK2cWT!*u&Zou38(Q+w} zleBPCi_pJuB}_Z#*pk1zxeDN2U1J>aa%%k{-)|{a#(61_6qiC4(&w7%KF*Ne7cfVO z4K`Gooh7p2ZHx&foG#zeA_8II@`*sPFk{|CKEFKv0S&{at999%><6sUdRdfvFX6n^ zr2cfZd&qeQ0g+k;#NKl}sg!>I_Qp&aLr0?@;+G(*1ne~eL6(M+Sp;0u9KLk(uNiJQa9m`XY%CR2UoOmA9ait zP#Hm6p2o-tl`Kb$T>E2;oYM=GkL&eB;Zm5%V>}JG0fQZ+A_$Z<>#t^ym$T7h&Z|3 zWfmgpII@7#pK%vRIAHN7(|)k{!yjZ(wgPGIxhv1o-VSp@+z;ji=7)M|nHY$ypJNhd z^mmwGwVKrACCpTv5xbv{bp+3of(_JaRk&qF>c|4b|BwZU{k>TL?D;0h%O<+C{212d zajaD;Fm+RGa(Y%X03o(+fC5STjxg1t|BzAtxuwFsJU?yFkz4S19vXOzwS0X0tMt8V z6V?GK_Vy02Okf3^5vfiKLG|MQE~u`$0aobCZJ3f4;C8_Jri`od^&sf*bS912<`xQh z5@mDJC=kkY`RI#g-0yi`aEthp?SEs|0=TOzPG9d2W0g9GUw38o@pGKQ#!INqL+!%y)apWnM5>A%FzJLiS-iY`H!G zqznMRJLb(k&MV{EU5hyINvuEqYWzq2s5mXVAU*lRPV>`*#DQ-LRp)V?wE7Uh5+1<* zMHT@}!qXNj|KEtu&--$*eb?ITHO-vqN6K2z=>Hag=f}cg)9@ZjS@Qo=`wxk@qLq&yxBvc;;v_wPhu8zsK*7Oc;RQ z$uBxrz_4(xJKs}i9_FU9kJFwAb|#HJ&AnS_UH?^jT>~l*M|(SMX(2sBSm{C&-9pkIBt;_Z>%$`U3f)+@f^2qIKjJnJHolMPB{$j`F|_t@>o z@)PwFRK2{q-{(H-;!^#C@579~P<1RA8_>FMFq5T5r&Qk{U`Eui@7%>Yr0bLG{QUO* zlp0%kZI+tw09w_I4h7>np9FbblWh3BerZ+v?|I}WeECvi5H7!V-(?JPKsX) z$X6LLJG{0=gw7AifK(+wutTIf#y_8DdiQxXLU0={^Co;OTlA43G1z9({%{YvBkLbk z3!L$(9ZQ(_Au^#Zg}(bMB4gNIM$bz5mpAQN*5FiH4vG9vady(Wr7!LH^3?11w~lOb z4zWx-fem+TZ(!eXv#tKX;A_0I_3hVoe7gMQKR2u7CD9lran7Q9NX{GxO*wMp}SLw|wxhs)5z0uvQ zD!bU{fBvYpS6zuUNf0L)n%)62_p$OTl z8Ym2f^pr?+V%K30o8n^Qu9vm_)X19*ih+6f$G%L9=2jWbF|7ZZNnO(l9_C}`YYvLzU#Dh~o zy%kw0YyBcX@Ql9)1&p5~UJ+HxA5#w|PyCaYiYmFU-3eUte{*;C5sWA0RIf$B{x=ro z&Ka(+4*XM>Z+F%^XS;`}@A7-6^ua+f{Hs*>{eD$6>Z_|~Ltath`Qy{WZ(wBe4Mzwy z-pT10Sf!aGIQ zkyLMM2ilH;rWIj#obY-Hoqd-4x>UWbl5#ufP#5X*yA9=(%c*R9Vt4o1oO0&F-1`H6 zk)3jXgp3qN4|Wedjt3fc3jUfX9(eC3l^fav;$}Vk^cU}arhi+o*R?s;d9$SN zL5Xy=A2>hg(c4&`EmFDAq{7HbU0)3+j3H7&;jY2aMh{HU{*2Z@2V{RAj^X1>;5DjN^r|CnC0oV z11>~m?e($>uyt}sb!RRxjEciZK9gp0Zb`R-dEPjE;xgkE7l>=$><7oaoUSW(g^yNH zHdm$=96st>^>Tz~Z3A98RDJf|@Tf=;X-ydY;Ie9 zts9+s+6~H|hrrlZACxajo>_7Xv3#6#&A9g^c#pOGQcK4<>&QP-_C)T9U+WKB`{%B+ zxyj#%|Cj}<$+*8C7T;5wF7@*DTGPon0;yth z_M`M$*gB6rYBKz#&?h_q$mFRJ_}2KU6MPEPJY18=dJvUK#Qf<-lD_!{_pAHlLbr8! zs*@CcE-kp>eC_fYC3fCq)O~lpi1E=w%Ca{t=f*}lb63KEBcFX+IWEPgXa3227>Jrg=|cW zyh(E=o~3*egIzi8TeJI{bJYiw(@Ale6O>5VH0mL!zNmUCrpt8REqYq%y~yq0t4>+g z-N~Dltli!8Pm``(!7z3s*Ame;x^AV(|Hbi;hA8&-fpo7ooMl+Y+liEhqvqpPzL46@ zrfiU++6CEv1f$>86mQZM9@3lzlmBJ7_VFsTyge0sqigy|Pjq*PYa*kjz?bC3M-T<7*0H{kOJ|5HSRRr}3f#Hr}{Ps^gZ&IO+_ zwe>*K63BCp{#m$f?QTJhbQrQ%&xSCD4daDj6*&hgJF<=gr-#N3J8nj~<7PmdZ;sQx zA=hBehg!y8LtI`13!pY!A^;X&n3+TKDiu0+E2#G_KsCClXF7b|O8 z)|2Cz94D~kU`OgXtLqe6%E!XUA(>e6B|x4Te`QXbWJ@_H5PU!{Tm zM!{{=L#72^2YS+ZZ>{(3o$GE(t^)V(_j8Tj7Ws#9M2#jU?;=Z_$CJl+iY=?*HCX;d zzr&1xy90Hpsz0!a_pX++Z0U}h79+0uAUUy+PYCoB#h>rk#`2PFEvasscB%KyZNL%{ zTfKl)U?0`{eh&+M>2!A97r+;oTfdiq=BHnc85#mBZkJ0QxA>s>gOCpn#ZzbfJnc_z z`BXQ}W~HU3DBzL&aoT|VQdUxoD=0PPz5hemoyR4W|N8^CY;tCrv~tQ^(pH@rO*2Eq z1uH9SOv#+dT**u^l}rhDpmNI0t#Zr-mC{O0krej@ElpDqGZ7b5To6p$5fBjh9c#Y# z&i#Jx{oecg`}6U0&gUZ!IOlm@@6X9GBr;aglbEUHqfW*pnXZgMaTF~{xK_|4d0`2~ zf{1mf+7Z!??zFzy?7w;$3LPYOB5q30TdttlUK6LxG?#5KmP=1bmZM0f7tdIqf}VKF z*|5rwkefWQ%#V1(DO#;ud7#FOAke_J^Ytt+#vEwrH5hO@r7 z(}eT~o3W7_KPrFsCab2@dC<5_)z<*!*Bsw*N1xYBdyy3p=Knx&!i3c8%-L-gS5CXw zl*XS)i3+}s3%o(cPZF0G=-Xz!I;q@RgFUl>?7l-FK(|2TwF(R&4cu_`xuTV!I^25g@ z#O>y#$_8uUjPFpHzX>BOM|qd=_4#mEz*Dm1Kzp7x0(G-`s_l7XcG&6_+{0W2{)% z`6Y*HUZsL9zzF9%5om@qjliJp@$FAIm!gi>C-jDo~|=m7I;FQNAjrYmNrpn5dBxv(1S z-WZydj1~4i$vycu>o;qg!F65C_iN$-Mc(|pGR1*-FVukiHWpcHhFe>hHWeO@d@I}y z+2Y>9iX{YG&C|>Nv2KYTj;I|rnSP7Q)qp~x$mso}1t&-5Oue5=0xVBN%mM#725}~Y z8P2D^Jg^b0!ynQL5JL40CkmqB-os@!%j{Ia#(~RGKRyD!Ha3p7%70rAkBPJTK%7sHSI{X&Fnom=Q7X|_z>J6Ier)c{}Y)=u}ui#w55TA zW1X!~3o3ydE-(L5_NHdJ$9N=k*VZi~p3BN5NM}Zr*Kn#rf;V0@73?&?s)Y(Z&Kr(f zK9wT%QCIOzgKYIamB|y;Ge#3fIltgmGYzF>gk1XW594p~$~l+ozF)eTFFw3Y#gh4m ze=7XK+`N}8oFX}&wL!*%_6pT#^5bDjR?LnD$3Cyl52QPBIvZEu4EZ&sX><_er0~QZ zycRFXdSWhFGJqB}bV;!dK5O0F+SwxP$kDKf$fJ!q>Q!BwKae<`jaD$5O_<`uw5W+m z((LRVC1IZflQ{=J?S<8%`=M_BIGJ_Md zX!yI-=f={qgj%bX@SCTP!MPN^640Kq4 zT4of8i1UATsWp!#H(kP&u!;&QxEJH@zw`;i3ME~h*z8RU({NNv1BoxH&)(t4C9BSh ze0$UKE@AIY1-~SA7LLF$0&2*(h7Nskch`65-dk5JKk)vzV$Q(I8e5!ZFhqOo$_R9h z-WCxf*;FrHrDjZ>_Z>Ewuw-Vi-4upxke~W0wA8X2SEmxh-;Szhx_!{u)6yz0(rzl; zWpkdqLUBf)9G{yb!p38}$ADM5bi1qs6yfhlLm@=<$CVqyb~MHkHNG27-bm%nFzjjf zKw?ZmrFO(I_dZ_loj&)0xS{3pSsOQCCGemJZ*^h_#$IjCj)=aOySCbPF4#9vJg&VY zBCN&-TTY3JPEe|8-U;#P20311p;>C-sL|!`jw{}s>Mu1_L+~W_&(hyhK*fP%a0}9g zc2^Ji@rC~E^SY??#hFlN6w$^*&}olTe_ah)tw+|x)Y&a zx@Z#kV_{6@{5fH~EWXf$8L{4z^4?fMUsTr3Pg!(MD(=(i%C=~fw(HEzWETX^6wVzQ zYr9L7>liAV2#_4kTXmXd@Ums+_OOZ8QoR*17B^h;jQ6ts5bd5J??e@=M;jB+8Bw%M zL)jyElWm7ubarH8CyPcV8fwvnW1MNiBlVHCJ@)zsFqXK2mVfm(6?R3;7MA;H)+n^CfgEx1Zts-oeKr{o|a= zimF1_bU7_?YApD@){jjmIYUQ`TYW;2g zajKQ@;Oputgy#(>Z_$D}1HcZ4)6ns*$}rcgzfFkM&9|r;IN1lksKe|wO+(Y1|Is1x z)#;{;$$-2=>Bp`KJ$x(>3QxGchr*)*c#RtEyVJm|f@GD+w{EJbsZFo}KV>JENVR$2 zt?TW_jVD@;gZ=aW`*zLM@Ewh97s59mGrTniWpCrw1%<;;bhNKrQFLob*kkR_w}@B* zi=6igWy$ubiwUVAdPd_J5_KOI!7&q38f}@T> zJC1|7R)-WkY51Pd%bU4w;ZVzI#3_&$M+QRNSKn54ad)nT1^>xgfg=<-Ki+hg^_cB% zL@D7xo#hSTBrwh69(@{Ags96!O?H|nu^^3XWiQj^bZZYzLPvDf+88r{Or;_SuB-yQE6jFqxzlBs3 z#cCsvEVCV<`T>d(NjP>yzB2{*7@)E=o#mlED*$5sN51=pIm+VZg-u4%kwc3DI2$+r)!ArDcQS0yWY zPeskWK1zsg4K&vW!-;>~!y_ezT&3^t15Hd`j7D^MiKzV``VPX&z%I&sreSadhTd&o zb}6`j>1wdwtUpwk;AEP)64MaDWJY}HCUZ6bKhDg?qso*Cc#R4R{Dkac7EAcq>^VZV z;MlzwS_)irUVFA?Eu+T3Ya3o$(+z04Se|kL7xjl-5fLKOYd|{Zaa^rH!B^^2a)WXW_s_Eo9erNjFuLlf#iY*_gs>F)ORyt-PQhrN8 z^nE+UTiiPFjMYTZX|k<7_P*{`3pi26>!L?v(aproLwSAjO3W9Pov>TdRuewD&^}B8 z>*77Gvc~QxGI%G|o5NBoGt{#uQRfrGb4s3DAY`y2Ev4}XZ6@5vZ{|FrHZ6RF(_Zuy z--sg(TNPG%YSv&emT)XQ_^Ima?Y&a~`mUeSml=hB1lrs zI}BRCAJ;51`5)%>T+JbY{FBmPbXrh1V8`82w}PL!a(Z2%Zv1m2V)l8w-0t&~{Y&U0 zpjf{hZLLsuEy{{s;49RtcxPrB8hGP^M{lWCzV>!T+LT5CDUr7g$qhFmgsYOshLTs< z*Y&Tx8z8y$A0~KI4KX~ZDtVH8-4(v&jD|bWvL_?8q?h7HjHZomD#I=gEZT)yPG)J2i2L4wrHhmA>v=KB{@h7}}?E z#BEBP5#(;fgNMg}TlmG=4tD$bi;k^p$RFhrwYFY$>>)A+P?MB@o{W*U&v}L!b%G3E zGbDsN!$G7$?&#~MQZX6qPi2DWza{e;tN9j@uPYTXEl=>*$Luj1kLV78rKb=IjqoE! zOu*e~;W?reBfGg{i+Fmwi(o1flT(2l6{61?7D>ZSR%m!s0aPkY6r+S=)9^L3jTf-J{AXCQ zBsZdQyjBF~fg23FrMqmT9hHPkiLZWL$8N}CLxOiwkrgh|SS!H&E{lxv%aPZRa&f{+4ZP=twMmW$yB#CNK6Z2evZ2==&Jsx z)--2Wg)1)dPNII+@nfjqqyBT62_#jM`HHg!sg`DW_dz;PPlvPGlNT`}gU0aC^c zrW(R%u*{z!%4Q>1J4S%t?IW)hWR+Z}m9?3eiO8iaT@LuYPX*1n)%p0}aFeUISKSuE zy+tLnb1mP`nQ<@6L{3z0<+i!GwKkpB>J3AiCeAE;H?Y#mkL#M5CS(N7ee)0(@p{$q zAA14lMLwiYL83Sd&UrIPzYmKNIg5Rd4*1X&2noiBD8CZc`-D37H`P=hcmF)Ai5Y)L zhT}|e6MRyS{*<{%vW0W;z$^A|=8-O`ZlaCjFkXP#Z7cuW?W=%8*cO&^zdF>g6Ud!xG}J~N>DXt1IGE4#!Dic_*7 z;)3g*vulV{P?3R)i4+njo-&=8SC(t|T-3L(H6uMq5#lx2=BjkiDpkxXE+w4M*J8-Z zIRd3MjS(h$Oy4Mg+@U2^;^O8o4Ia8IIsMMdGruKc@Fr-~ zRr-0H28bQ`B3^l8`2NOUv(|56*$N<#ljuRg+lvQoTw7QXI3|-bA7Ffv58y@9Mz6N| zbgziBb+e`btyBbw_2! z%dADpi5LSHC+4c%&A2#^)@;GKQ@98;=h7B~Ji8)J`+yO$=+F)$E5vxEGrjCSY1BW? z*O3U#oE?kN8hNCgx$;Tb^jLbJ7WdkaSqp`00is=2`VBwydj-lgbCt^XbL2|!;BRl7236-J=^&###)^qMSQ#{vUZF8a9MjuFoxF^Adookhe4xuFA#ljhRhi_@J{1FP0leJJtZajjw6m zKLuw2cD7MJ?_L=jIj&_0yzI}7bK3-J&V7|#MLxTSSDS!0TP0trURVw5a>7se`+ar| zeLQ~IwKF1f>^XZ_Y&K}MHWx0vFRe#D<4S9xTJVo&4x~nyq92FTLe#BLD`-M+vW^bd zH@bjp98@ltg@D=D;lpLIID?BqbK=mjbWu3{CLH~K!4JLanf+lg`h4n6!F~6E=2EH++-N4z-2uc~bh#x%6z517EXW&~MEQ6d{ zMvL|-0fxC9PjFVOVUadhK=SPwX%;$$Zx=_q;28<#Tg=LH%4sYMb{zW!;EK+=v%jy| zOuv)?KObat_xS`^p?(FUOb;^cq$CThbArF>+lQqJLVY9-PUc?0)Z0|mQ+&V1_%T-- z2+gUVn1YgaiiJ(>d}4Fv`o@7(*1mot!ai)+z&|gRnPiE3+&n<q_ha)R zP}=pMq~~snT+eil|2pE){Dyx5HP|v*Zgl@J)bbX6TQ4K2a^r)bgPq=6k)!YmGoBeW zID+tHuEf9QDk!<14}o{?t^=_M-idW)A}?QiVhRWt3HjHGjX;2bI7O<_mG|q)DUY3W z8s3H6oGFdJy6as@o_T>|H*rKE8?{W1s&lOmDuY#?{Ee?LIJJJ8#j%s z(>yZm%DxN=v7DMGVpk)q(*u_!x%1h*N}n`*_6#yG$OEl=~b}Q2dt+Y(;Fv>RL)=4qwrJTe~br%~9E;ycpy=&Ffz;Bxh zRB+n?it(VleOFOA72mQrX_i6S$$;e>YW*oMrT)-xs*t@`f!JTJMB0%-idXsjH&YXR=2tzTKwzW)^41&9$Kwn-mbf#D-F2lH(aGSR!%32 zi~xZAoQD{Kv>ZopKIz!hi}tJWgP&E8>pcyhzJxxC^}z+|0cyu+-JL({CT1-prRc0J ze&2HMOudG0v1y!lwi)MF>CY7+KR$SDUYCzCgc-V4=8P?-kSCu~dzADLs zengSuAUEfjKJVrSeLtcDh$&pl>sbYFDmix~YI{Ni_+x}~QQZ*W$e4scmQRH{rg#RpvH|9qF zUZS6qK_`L-SP!^?C}9M6obf~D5OzAVG+2N6v%k4c5W;IOE{guB3r)Ij$S)|- z&iBY7m)KoU8Gt25gRm}I?^iw1panlmXV{O;t>2;*AEEy9%>F*Xy&A%OiJMr;T-p^F ze4r^uiE7uqp)f6#_z#lI!BZSON_ zjRHNxMSQFh-PHI0jDJY~&B}7)?R=BQRQbq#6APAB(y~48+_*WOW3`{2+ES`Ss<46d zJaoXB>1SNaQC1{IeBC^`Iz13i^X+=%=7hJy-2c+-X9}kq^^u-RTda;b8z6XXr~}lN zQlHAoE460{BD|!?7BN;JCJhTc7_)0L3Za$67xxb432!Is+@Jl` z3NgX#?=~x&zXy!MWl?&^ zdp0yIQ^bKY{qeM0)S`LFBL=Sr3OqL<#NEHw)t>Z?8e?Nzoa3=qgYqz7xakO`;DOQg z$#8zKTpx}6{pX9y>=E=obcjUOC1WssRx~`1_5n>EM{uucO$4vdp;Wht6=xMfxZisk zA)riP6nL+`tLT+RKB9icnv$Fn*86U|9JjC|YDQHFo{etKHehzwWX(g&$YV)e@lHL1 z4R>}k24wt$x4Uq%_es-Q;|aB^Ch6$3PIU0vsR*H{6RJtI2o8R!KTEsfTFCcAbM@>()jbWo;C22~pNl$-LVz*b-X#meC zoYDr%@WoD2Sdr6R5JY}6eb!0m$Wpcp-xqDA^ppNl*3Mg)an%k;^MBG?9wO>qfgK|| zICijJr4FFE!T2_CvRSx;CM6{(9K2eVpc5P?6>X`FgLxi%8s6Y$gUNnfiDm)6oF7ef zr&fIv?$Ar`|J6SXVkh5PEjQE`52v=7(ltQGCK3ONVsu+K!$B`w^h%FJ98?aW##hTG0vH6$@g7HZJ1KWJRjx0dqL># zDD>hlkcsQbNd^j^7;EC#{<{5(^;lRzBdKJ_0DXa4m8NF;R2man^;_hX`>35*&PPAjBwI`25U@TiDie1BcKHWL6$KN;Wqz2c0&WoS((&FQ_ zkz9V|!uvdh2}&3nE@LG$J@-r|DfWl+uN42T6`oYQ_yVyylB&CQ0vQnx=0H3{SaBAwz-=Wq{HB8$ z@G|eg7vj;c56EHp`{z|)Yc?faoYgBg<|?Z)m{Aie)tQ}PEf|*y%Ti&$4WWU=3?RFx zAW(y-Wf2L+EyfSGyy_}MF)-4Xi=#AdkI-ovju)v1X$PO^_8(%W+%WGIZ0VDo zze@{uIF+Q@)sL8&@lvXq{qD9kLk{-Xcs$)M(Pf6#7Ol7!?jiQ2sVW4P7U{akTSYd8 z0{bE(f_*APbf`Q1O(ttOV!#oZkrYS z{JDYE?&V3ShCq3%;e?TE0zW@j@z@-utt~IlP^Vhjn&Y`+%0J0rug0ww1gyL2x#!PWRhZ?X+qXGKZbiAvu#@8MA$jp>v zZTjiNg*%yN@1zs5!`OcT+)*vbt2l@rH;!)G(1jzL0sfXHNfG%`pnEdw%(iv@&EKX^ zE!B1wZZqCRJbzS6u^!x9mTbd0nQV&=b{e1`aayIcuDoh62g!GZ7eYH*gsZt&Ni=B| zInf^g#*3D-2Bu@-W#eE}VQ| zw9~A+2jjP3b*VwFjrlM$4b-D;V@FiL8zQ>XPx1IpA3`@iLyz83(4WKljX4XpCFBKK zRWDCA7o{76{f@%yTFOo!I2${mb2Y}G%XF15vBOWP$|RpbR(@L)NVR8kdDfO=R@K}= z+7)M5nZ4N8fV$zxcPA9@W@T20JxnL)cf7{p=)F#)?`{NjbNhQBu>dvA5BZHvmc{bj zz>z+Q<)^N)^XyiQJ2L1ucSRw#Bc}PWg&TnO0#55=Q*c|#B4uATh=2w|?AZ=X~85W4^e#_cnlgw9nPS>Hd(Coq?KRj1(h>j_m6l&+EgsG`1)XZCMwn zlY`BZHJ4zNJ2mSh=GBqy`>CbNZ1Bo-jh)+J(B;4INz}|g?U%tstkTAWFLK!hL=mX!=?}=8fPrxB-B`MX{laog=^`_FAq9_egs)BLY&@kf+0M z8M$Vm636tk(DX*SLT9(}W@46MK)7En;8@vJx?VTwk79t(+=DKzOPL7qK!-akC#B>WTi}d+hZBZi`6c9^k^+1RJ6x_K z@e|jM&qYJF&zF}17U&B_cr6U7Ha)FO0-fT6;Vq+teZb~$tll;)YvfNN1@*jxC(a~az7rUJx9{RC<@i|INF`%|Z)GKSn5I$^1V_jdc*J{2G{e}l3MfXz!dR)dL> zz{4Lr6^&<4`Liwj#(;wYc1AzR{nd4@##iZMM1PxOk7`M8JL;GU!FDS-2r#TXeJ&-S z8kZwE1*xcizlhu5ro@wS{ByW!b${YWRY`OOK-g{sju)o@_g9+Ve9)0Ac$r#WGJDwU z0N4-kv}As7no|2ApCPkm_w|@!H+uiy=a$nFbphZ*`o6E>z2#Eliu%)68QbMfA3NHQ z%h~tT<=Dy%l13H92-}<2H$@gL{r^~5z6tD9u4bKVEyAmQ7gX-Dv)6&UMh2)t2)p== z@SGK5NmP<*14!VlJtblZ;lQr`E?Jn9&fSCt4#l2L;aPG10HpJ z{`Zij99d7^w}3Oy8rgUex^_S*yO;SfECp&m7sDsO?ZPhr?q)k%P$8P)U2B|qTt1}5 zJB~muw>jcLZ@Tll()gwKgQ_XE_QR-;QOHkFMwP_t2U>_eI+%tt$Z;@Ga53=To!U{y zqPZ({ngF`?CDDht%4kS@sPW?+jeE;R4vD5NCj2F_GgR>we;u@JVGM9vukq&6w%oSe z7Pw5%Q5)B-Q?DRgK}5k@A7}qCZpXTyeYGQe{iLK$%nlph9F4hOkS8ZOJ4X<;w-B|MlMZbljfts;KBqgrX&d>VwF0_t%>*AW~qHl2%BE+ z9VgL#m|yPj&_T}@5fDFIOU^^CF|5>74Akg?~{Xyo;TRa zO`$Ijr=|r(WY!#o0+>WQ-51%|_Qj^oe6^|UebvPf-0BZTUz%@HixhO2yq;FUcgM-% zd6A$*VbM!>V%Zesooy__OZ&sKR&25y;sggU6%z55)!!B;HJkfCc$0P^U*Ic@GH{~i z(ldi>!XwSR;-bQJip%*Aip%{Hm}og0x-$ctl2{cee-mHEL<#X`EcPmW|5N@a?Uth^yh)R{9=Yh99&j1be%8zA z69bG?G!4eq8KW0z*XJ@9>0AV#j56pAkt22q_JcK7;%eWaDN-~g^rp{XZ5`85d=I5gY@Ldt^ z!H9T}t%DZhpRp>WV0pN&gu4IZw4KV=#7bn$%?* zn2l&q`za=*5QYWUr7S;=IGQeMDM+yZyLwCt0h_3$s+uv;x3X_{D9hP@d&}9%!PQQ% zZ=K7YM9;b`vPdtDk;SF4=Fz~GjgSFHa|cGmK+JAjX2n@WU`>*loc7GZfN|=xkbCt| ze3AwD0waPIsIy`4Db4@_i1r*3_jcggQcw~oYVP)E8)%{mh zoBg@3I|9Hv_ML#1hPC|-TMeVY+29eUq{6zLaykYXft@2p;mAzu+25<$bB%>3@DC!H z=h5@0De1?J`9Q7@z8_?i2)ASDQ>K$O%soxt{0}-0$;b~S2;a8eL%p>RsGn18@`)p@ZgZh z3oR=OPh3_jKTmhXXl)t)utQgJ+2-#-JJ&3z-0HF8ewU;`m``*gD=&}#H$xkSx(`kR zc|90^{;TbQfPku@SABzF*d?Jtg6I3ZHSc!7S7-1k;TKjT1q;N6hN89%tchg%^0Mmz3M*ipbO z_VfZWSKAQm;e7=;wf&fWd+ZYKjr$92Yo|q3C{C@*lIlq?R4G9;Ot;Ain03eOFaN1f z4jsluq{)|l*g5$xwlsxNZAw)r?`?}^rOWqmcdIy(V!3x$2QD(amH;%`4nd&7AEigx z4Hi5y($8@usiGcBCu@9KTszXpriCXcrc;;#)Q!bY z+vSwE;qtfrsemYbEQzD0C)c^LQGg`5{X0pj`t%_#-CyZy%W1Fa${mR7@$$E4V+gE>wT=1?3ZOT$$Yeo51XY3vSlH1&lHn^55o;%%S!Y3OLW<0Q2>22 zAf}3Luq+ZFXqF~uP>$ih%fcceqg9DYdSO6Z%uvip|D zxp|lLQNx!Gr~w5E;p(?_HY{j9Kk!Olq7$g0xD}@{MgO8+coqR4{#UOPk=u;))f^2B zGLr1q({>Tu*!4*V&q@Y`YZDht{1 z*r)?{z0K1*eu(Vj)<;=&&L%yV)%Igyo?+vUk?a60ULtF2HFYjrYY{{*Za*I2BleNB zSows^)oCK}v}LZbaC<%KjnPvJLwdaWE-ge%qar(+m;ZQ4%E!5U>MWE!i5cW~_$$*O=jqXL-bRf}2_#s7RKxvv2m{+HPGv zZ|%^h$LvQL`VV|XsU{sQikq+WCoqmd@J4pE|xKv~Y1up&{67DzccUAJz3Z ztk0C8$5g#>cc4`>YocC8m=AFvC3tP9b(+@2ir%H3U`EM|VCL}KNaKl7Xe1y?O#t$m z%adIKOu*aGT`AVN!=RSy#z3#GQH{x|&yB`qc8t1SEDIOQ#tqklKHfA4Q~ zrW-$g^B~~bMm6y4^3T~@jeMkz-EQ3$t21L7|B5ysdVAVXfp4*|=2{Un*q73y4Ivd2 z?s9csY8DN^AU=Q0Mkdm&JK9wjNcwB2r`0*tDHmBk&7e+AQjfxqYVchnWIrm_D^z2Vg{Z@hF2${Sy96NXlq10rE?(j?F#CnTesWl z%myXScDcE{xoAUV(R=d$H+vrwK5SwysPdPt79}x z(Qw|=%7OL@t2B{8FO$MRK^mKsXb38HC&xnW5p>h)`z>CweC|;g_8!==F97X_9nx`d z2a1j-$Zgx@j2m9WUH)1*T;%_?au^fbS6*-e4J^^Qe_21Euz0}jBxO)io0TVm-u|9QdR=aS37#r?o`tHt1ba~|8g7B^!N3ZK zSZ!^8u^Itg3;hyV<2Q$IY#fjGO8u%#7+3*p;7jlexiUasEN=iQzynA!e$j0#u|YOH z6;O2tcY>(e$=Rp7dTWYnU{H5tT-_cvDQXa80UiDk#G8`7iT=a7b}%$JoikB zLZBqS{r3A%hG3x7KqFXDCxiFkHidQI<5v} zaTgmOE@U)2xfS_&Zw)|y)c8xGLVf%nOe2Tl-@00lxUfGICeP>JNCC=L zfGF2L3=I6$z<%TO#f#S(zsyi<*JTD_d=v7;t%!_9C6Ky8JEZ6Pu~lm4BPtNz0hL8$WZ z*2&|=zZmbbEbCCe7J0n5&94IOtHk1?3{r%BdN)^MuCU@=*yacLV`l<+^_G+k1FTlQ z?_ocRj|oJ8XTaT5XsUhl`GK?2-%o~JkQ}LeJHN&?XDA<8Qsm!1tdLl9{?_HG$*0dY1f?1G`lVh?myGfLk(VadL+J;wL22MOMw)kIbm@bXqWQ$Q%-%J)9si1;dl#0YGFLbsqm?A* z%3WM}lMqzhvKvA3BA1LMp?MgaJDy3JO|7rUhD4<_HyXKXN9+DR+4mbo_cJP%|eY?`dH zSClK%v3M8MM#SY1UFC~MKjic?0?Y#SEVdlgOh&Qc9Peb~Ea#QS5 z*}7i&9^Krf4NstSUy`pW=&Gsr@O$G-R~r$R0&qt~_pBQjJWvE7lEKr*c_n;Dn<49m zg$Ly5azq!wg;a8dwA*(*MHg-$*ndfOvWZl`dI{|{wsz~ARZ2Jc1EY^t86qB}N^$sH zm3oEfEL&!kVVIZv&&Q84-hA$b?=ETLd)7BUHYrYejIFX$su}U87!~Jw!e!l|4at)I z*5;;>W<-fk!w|MikJqh8RVXi!MRsqNaDHiGFDkV;hXYQ0&ge0Mz#m;P5AF6zk~*qr`BW0ulHUq3~fSAput z=hS+8@!(%L$oZcVasLetY7J$}rM>ugO<8Ya@g=`b*!AQtpu};;Y~srNhIQM6GQ>b? z%`ghcyvC}|lYot*zNF%oy7`(nm)1jdS?`A^l}c0FOT7hPnr6yCs^=c@liamON%pfJ`kne;Si`fW4ww75lp$&FtJ>#$ z1OH)SP(AF|DMeDi#5|{A_ZI9;*jjUaC37--wsl5yTBF+%@3Qo=IPg@8y-^vdK%nYrkYied$v@6`}Oi45@&W zGIT(LPM-MLwCrqsKooOO_B_^?2w`$)(5A+#KbAboJX`ATt*j&avsXg#Yriu{r$SmL z7YO*w>Xt>4z6+1`5ZKJacNRVZprNzfI-mhjCk-+`*{IJHLqF}GZ8#zNP7cgHG-yzr zo`rq@x0^kM@VC4OYhT){b&Zf7yQl@4rwb-3TfrL^sL3K-O$5FJlP;s=PAp(k8ZM_q zbnSz@NBciB27Ec&h%*wYw`gv;bze<;U!hy_gFQjcVu{UvCWe!C!eAm zj3PZAd4Grwpjpl2{u%+^D@nSaR$pLb++RYZH6iyzMS4&h4jO;nn5A@;l?1-uh|X)N zke7UNKpJt!ug-No8~n*(Wh%N!v#)8A5pM91%YJr z;o@NW6i{INZ`GCce)iz;Ez!;v|4};oC5@-}`hQE~eJ$PXT(7&m?8lR0!=4U~5r7O^ zg({Fi1j2lO$og%RLI-KmD*K`R_`~7;+G;9BXAHt650&U9&7GIZi!{Var;ONV`C;4C z3@0Y+BZfn3IoRs7Mw&(l6%=JK->LQ3+5ldkT6sV0Ll6XcTxdnKt{Qwb zf%HyXJskN%#EAv(6XE9F3USbaTND2Nad43EdZwaE{GHZw=xAMbpleQU7&OWp9g zdv;ZBcrwplOo($o5Xd}L-qtw-)Er;>mzra`L_Hdg!oCrDywXRc{8L#je)i}6n@(GK&@MBFNv(#nirKVccBl+c1ON8)Xy=xpJjo8 zmA$ULFgc|B^Igd<3l+%dRtgx{s27s1SKd!)dZG@#nW}J8KMWDXGOr}@qt@(pqd$@| z4Q4Z&2I7U>xkvMLuF*lgZa1KngAW3G?{`jKlO8YrP&Bin{5i+% zm9WDOB1W;d=f3anL3ld=hxGi{ZR`#UJwxSW`(!3bkIW`8^^J6si^e}%^xA*Q!3q3J7iMo*iZ(?ZZw1)ZCW!%j&dF}1_4Ufu$8;Q~j0|g?@;FHqZM3#!EfBtX|IuPQRz~>)j7qkESyS#x ze$?-2d!PCjC;jJ1So6ptq-(XH;U;maC>x~&B(Lq~82%S|Pq}LID>13|gZ(r4q{psGWmfI?;%?0my(xb`925t%FruE63qBovwqz(4_E{}~ zYt!hcj28)Gde7&nJ?ozov`OS?mn7`Aa8@3w#EoY<&8(YZy~|3B(ak9Tge3^1C}*Lh z>6?zA7CpP8ZP@Aund`q07PjAcFLZSb{NTe?_Rdt%iy6%X>y4|&rGAv|Y{`tLwzfKU z#d(HfKZ<1Eqd`QV7rftp{zeH~Za~gM+rngA*goXbp|@Vo`{D)hZmFBg?G8ov9jodU zZT1(xA-npH6q>nOyv~C-T9S*#(Jr@0hx^XuTy>!@Y#B4Z>a-*)wzQ=PEN(l~%VH?= zf6eCXCsUDG2TL^p;I0MJyh>EFsdkAXmUqFv=Jk}{ACB$H89g?=CF(T8?@H3~-}wEn zK-77C>9mJ8_TboYvCZ_{d5^z!w8{{7nz@|tf`L#SS*h(l5h;9a6I#=F<`5`av^hD_4Vu4=_^2L%=Wd29bL3lctG{DrCer^Hun48pqfUX zLb4;hq9Ey;+>}Ybi&XURs`P5TrnnTmULv}`a-UXS+0hTITa7KMgl zg7)~e?-zpqf~@3-eT?hggq5gu{*4?=S-RI$M{H^X|E;4~Z>%!B-xu+^>QlGz|J;VV z4mhDFo@$Ht)kvjjr19{7paHbYK2|_^sKJk} z87L;kj0=n}-y%QAR7Vz-Y}g0f$>>xTW@>NEil6WRnSd@cs+!iD-kS7J3QzC0@Pi)| ziR-V`52qdDNi2Mf->SA^v4|&Em!|TUB5FXOHF|n^v+o{@_qmvDft1W*aJ=%?H*V`g ztKP(-=9u>K;=r121C`syCtE8l=0gwKNTO#tD4CDg3~s?5|m-T$IPeQ8Clz|nj^`y+H4m@ zG#yd~4IRH9{J{@n;F@I+Txd@GzUTWfFjKnW}_`xr#TIzCnaiijA zu{4u|5t2IDWaZm+(M*P-dvhqi^y|{HS>*h{_GG42H7zjxkWRJ_xTVm#Nl!esCgL8^qJsnwPEaa-b-LyfKxl&12j$G#2XoNJkk z*}0?NAOyV6GZc~dyO*!@&-8CJG%IEvACA91<@)>wc&spj$Kbg)Se(+94veWesX7~z zs@evlq4Y2bHChLcUT-e|9nS|x8W~YOjxSOY#{2ExgcA<{ExH##KHsf7gAi4W*VmKv z$tG%*&X$X6cXR?5A}Lxk_Zt4P9{V0@hUx}(s+UZ39`dWi*Bh@lu>RTPn;vFnuN~OA zw>MwiUUbhXcr=kiKrfPV^0?>U|C*#V@LV!U;)lDlFH5TQjV^*6W+?*w_Zq<20 zNgh_8=IDEqj5_gYlEK%=MoL#?|DFXx@wa*m zF{#MhNV9GulJoWn^&^baLdVj;SZeRjAuA`uUVaw+aD>`hYiSNQI;V&MUJB|2dJ#Il zD)2kg2_c?R9j7PUG@!~`eUQ6j=L!1Du?4GZoezLW$qvUc$IBW}YkHQkK1(S`&AXO9yNd6e1mdQy>xZ@nK{HmVd%AZ z^QjckjPs#FS=mm5=M#7Bhtt~mGpJV<3-5&i$~kZOZVQf9K&y1pmGD1+lpHy~W(@;q zVBgVc#;?EkpR51%$V5uEIEH_VfPJ2j|Dc6e@#fl=r&e^8j((&Gk#ku?DrCAHXgMEl zN=by_OY|-X`1Uti8xqt1IT0x+9<)Cb;G z8`&;QG?s4slT(#E$aO+?N9ge9kGgG;veQJEjGO2KulPsbd^Fiuw5{9>wIK?Z#j@y2c$1D$&1#t`9@9Oy}t>&q+ zcP^9BKgRp{k@eElWqEd1^sg<<>@jnZSjn`LJQL} z-Ewz;-?cCAZ8hO02oouz&P{XarSYI#THvY7XB1Zn3!1zgIXDr}c{0K8lQY$}TPwB1 zvsw3ndu&XCA683oi{h(NZ=&LH1RQRN?lG`&a0UlhD6U1;*?yH=ZFDcK z`45^`~ZYSCQFJ{D*di<4SD7GTzEc5GZC~ z#X0VA_j`~00{X*)V9u6;P1VxSduQA0!dmvBC}P=>nKQdt$iK*BRL`Z?Bc8zgR=|{k(c#w1^2vE0_5%; zTL3=vbeP`mV7~QfptV*-qX>DFhrUj%q07okb6$+8xhQ^YZ5@pSPdQ#TqdFsEC{(7R zq+uj_pym?C*@NaBQwBj~6wDN=efh8(DgyVc9p*Eilv|5 zOb+j1`MRrrh)6N@+{LV$zL|CU9yH_#_GEq+c6xY&IJYw^^aY;&vpAY+Xcf$16 zq`_V3?F5!##Pl)BX{2^TYisFa&{peN&RI75;27Mfe9Cd4<|$7*Q2VP>JeUtQ&_QY? z_pG%w7?{KAl$+TU%thd)4L=2iFMMn6A<8BDNwuG~&ggg$_~exO6?P$+ zN@t6Ge(ASwwhYpZv1>x_$j1EY2-I>O!${;hRN?Qi&fC3K5CastzA&ZVr^KDmvx*$ps=*_i4=ia6c@^Z#q3Q;T(-%uGTn|#^Q(43 zk{3)rcC&9sToIkUr8c`5&|1t2*3&Gh_x;@{piP{6=<7evCHq;0_WsN(nDFx{!E#uW z)2ycHqd8^L-wq&aT5Rd_{LBQ%3lgz$1uVoG^xx)4^7x}O4+6Gg*K32 zfvDe-+PtnjQ&$O|Tq9GMz|0%+)*9n-g_)QMNBg~!Q(Yf;X0;9bhchnwa2FC3Ma6uD z`+XO#8n61?0rO_F`;y~Fe~!C+4JskcM*f+(6qq%mO{~&uF)IYDLFo*6J2n74tK$V-DLV951+)~V{cf1mLb79L#O}}w?vFacpgHQ~$q~ai04VVf-(On2g+ND3? zYl$)0P6d456s(^+`DwC(iilUr?Ytk^s-k+{iu0mv; zj}Li6Oikt7(xo==O|3-JsL{{l-qKg3`rdb<*2}#cwA4)x`}_&2`t06_HQdIKp%O~) zdppoKX?iF|{{<|X$l`bSscWs|rtfM7wf~G@D>E*Zb1QOroYu)netH-N_5qP%7;$n4 zjdJnbjuQci;Q}}_d8M{+=9x5wqMEmTflWp>M6UFSTo>7d^}>y=YZDr9vMUf?TS-kS z3q$Tf`}elai$%CNiUWB@&IP`$oSA9L^3?U_%*i`N@hG1eJ8Z2pA~ycsYIm{@Qwzm; zPFe_U>Rp*N63%q45dHG}D4&p@qnVpbLqQ>)|&xPa->SaU%Bah5WfZ zs#KHh1NGr%*lRRzwy5cdx_o|ZD&w2>NYqf`M)2P*4eLk%n-$C<+dzdfanjeOli%iB zLOTa|zw)cSqGn-vN4_eN1S3_%SoVOpo@!>lVH;l~loy=V&hJ3X}bD*!$40W9u1zmjiHHhTw-f9Vr zb10pP7lxR6a6^OeX~6f(Ah5ay6$Mg({WoC_q$tl5ErNM}X{ITA7OXtc7h#ssk zuA+FVFgZ+rMg}@(l7xY^rfs&i;;DE`LK*Y)YD~fUe0c+T2s9h`{#8^l(xE1!>)}n82HL^!jPx&{V~=`05yrk+xe{Q0r;kn5gvDgSx6uAOOw(?4!tnen z%1w_LZC$LEDe-`qgvc~Z znHp=Wr1Rd{ObqBz=Trh3sP7BJL3~KyY9n>b->4y9St;4iY~ebwflTr8j5nGX>>YfF zN0C8W6A*tRMR$jIh0U_bjXI)^jg<1i(aFp~cSnuw=)((-H7qph%I=xXIt<~R=g-e5 zMOL`yu#t_H82pzxv0)DM<4KQ-n%DTi%g5ZpAI6g}h@5MA!smDeX5^^y3s_!Bk$uvy z;|_FZ|4ys0rA&Xh*pd0Vfgw6uHr}a|P~KIvhK|QlU|k=^P4kOyJV8lZ8ec<#)ySZh z_dQ;Fxp3v9QW5gZ%*oY)@;Ko+Ur{d-8po_Euv3IfBW9>GQ_=9gdYSsLAZMDO*aCZ^ zl$Ms5n3?F2d$Rc-^Ajxp`}DUY@3$5^{!}HcrcTBe&qgM&#Pw>r$z}8xAYOWrUlU7c zL7k6COps;cnV{z|CC*t+7g8gyqQjAm$Li6VLgMI$OQC?yiRkvSW*e{PbAH|Uuo=)^ z>ADy!@*11lqL=5q1X}u$^zRmpe~l;YR9z&3KXWhhtj@TQemLJ5*qlvkr~8Gkm)ff} zv~;n_5nnp5A?38T?#9c!IphjZ&7c=G~CvhG;0Nd zdCmLJ){iQ_EJK+f;u8nF`>tBge#eHmS|I5}-_i#wM{C!4!CwuPBVEd1Wc<|haB4&k zQbYT65-7-9!!~*S+WhJ8tac&xiud#61mKy1Zq;$45-32{;D(=MfR;eH(9Rf^IjYht z(t#dy$arZw=ZkrSy4dYyX7jsutCKD1u~Bl^1^792(Uezg#OC^sycms`sxsM*!*5-W zYLo!IBGO*i@AK9Y;JdGwuCo~dkDke~{wS~QjlR`rXMp0?&7j2$$ck%uQ&H6_!Ak+S zsmgDFEbA;~H{OF|H)2^x{UYfmh@fVZx0JCf)TzM=6Ln~Y+Zb*_yiNEz!xSW1QwhJw zPVZ*zPY$6^knw%uBaQuKDT#{~m^pCK&?9sYE3v_5-IFOY(Q_a*h z8nLcOQ zQ3--OThN_}^z6OWB}P2aBpbICxRhZ8=Gy}Qhy)^Tx(fPvvVifth;NUZBlm<0q{FJS zGe^_2iJ}k!es?DudRqTY{DB$&qUC-?rt?;~ARNWW081Y>WMP)?aK_Yl!GE4|Sntlc z$c##U`?^i=#fJF(>)2x&HkD!XW2P^lD|2hnHM@(k;(PPWhDT~P6_&2K5Ssh$&EoF* zZ$AuYs&14v7agJ-_+Ce+1xS{zjJw*$0|CMmEOU3`2--ex1ScuOGCcH6$pQH}%r19* zNsx@J3=hJM0WYi6rfB{M4*z7(CSya6&JGPTd)MG=C$KdKmru$hg!t3orbmdkxSi-DrCn%$fNdx(aSy*4;$_rd|Zv)ztwv` zdM<$n(dA_~K_CbXGgLA%hEm{YTb)uMJFG~JZEdgnBYLhqM2&YFtiPPwD$~i=4(&xI z;%dlIY?g6^G5Q40Bw2BxpIgFcCG3J(_|VLWz&In=C2D-P?V^6#b z+H1Ewynol>NA=j0?A19ln+vETxdBRiMLD_d6(MCWK7@la4Y>d(1}4aT@V1raJFoi9 zA8p)WiNB2FP@sNtkDQ(s75AFPN1m6fp$F=Qs=XA(Z_Q|K3tsxNYOh1lj8p*$H$C_I z3N+m)B@C0KTeYo;^u9r%JW9uStRnKq+=abMkb>SE^^iYF_28wp)OVhYwZ<_uc1o3^ zW?2eYP+_M@<)ZiEU|MCYJm6-CM3gSl{2qr6Ojov zqw?FzOX~`j)w|Iv3%NU2ot=ZoFB<9!<7fu@`jfvO?ab4tQXUHd7uA0&0b|L5wHcHy zl9S`8+)G>{y8zBxSvaX6??v!BGD3O*JVI>g@3oBjqoDUWmP1!PHuzBLsnU!e-dR?B zLajr0r4^I3^NHlft;|08Pzh~6Cg zt$liphe*bxZ3S8^^HI>N`kJ!;-i-*XsM2_>qKNg`w z;-_GKy9%();am*bSt=hKelt;#_s+gxeduUG+9FI6BL!ZSb6Ps|j(1cvg!!`1&eCOt z8~i{=n?ZwY6@3hT208;ELnXi#G>2G(p%6_Ic_pDS2 zz(s4|Bo0Flp0TxA%qDtc?de4`}maar)dR?HW1u$p6S?)|` zY~lO7XqaIO_0ffJmhr?qa-GL}l5Xbfk2%U*J>z2EI%g9bvdyM$#@=_HjLEo+$y{yP zQrJ5osJa`^fF=rt3F)R0MHRcmn1$X2w`(Bwmd!(v!PRi&UCTgF%&_CF$`1|QUZciS zE*jyD3E^ZUZgZ2_Yn+L4FYxWV?f36UQ44S__mScaXr4oF=}qTV}jwL$iz2h=8m?Jqqw%jaOP7{cg6cdX!MT3 za1O&V#N3szaa#_3EZc7sJd=+!x{N(5>$mq>alrA%k$2#rJKT>H8d}R=eIKs-XA0+7j5VIxVKhaE~I~ZKm8{NhVA3IFTRs zd74dz5ol{Fwy!1Oq2MVI+4rzK*Ylp%r0Njr?<6ficv}j8Ii{)rNNmhkUM-mUbdDx# zvnANINywxpi*?)rO?^}k98+`$26~qa3>2?VQH~MNH;>dp9`#PQZ+lpMkfZ4z)?+dT z0m6v<{V>L;kzX}0eQ*6#<*ACOBUs^JLHaB8Qu8Oj#k2W)9X8d)$#+I!IB$$>Z9IFp zSg$k6K&dWUJQ*r5flST74oq#n3IT6~g;dMIY_@%dV5LLW9LH2$`DaOi9|nh1GR#TV z!VEcly7MU>Yd0#(Z?P{qbdsn7a-p`YM7+yi22I&E8o?u%_v|2y5Yt|$1yqqa7=YS0{B}Rf_gn?c$S<;JkLG%y~XJ0X|ZGcS_r%uKtlM_s@8fjr&EoodI|-ZI#;(EeL>|fmNS5tU z_i|K#N;*u;)$=s?B;^dho!62F>}V-=XG;uEK5YNN)lwTCGz=N+$n-oPJXK$GWY?#C zYwEY2EH)W+Z~Ym}${mYBd`w%yAq3<3ao;D7=v4YLoWqud*DltI<{l8$o~x_>gU-oh z6P-nQD32WjC-07$^%E@iv|LaCwm zLGfmjque#6q|2@|4ZUqLtSFB_Pgm#p&J_|DxF?`E_)tVoX|@9d%MA)=rB2pGZ;jON zx*1rrKH6pt9V8jx2<=uEE}%<$^mvYeoUhop-tX;;97FnxDz|tmsbMB5MBeUjSd-g& znURhHxwr4$1##~OQB|54#=xWMGNPrEejr$X#8@R%xLq}bae6ovBw1R}-6wb?z1O*7 z^)0iEHCu)XxR=)v9W6*bkqkFOq}rH+9Q8nvJW@TPrTKL9w5i(!WUJpfRZdP7ygL2X zY+|qnQ_4K1-eey!eZfyk!%Gr10r}ey$5plvJ<0)dpqc~usM6}L>s|EBI17U%L1ZV~ z#KIKKYu5)C0?3Z`-;rIZfML8@ss;aW6&mXR*})vSl*dHb11NIJ6C2bpL(Ne2Rhd^9 zQXgp3-)IX(ZLdtH(_!BM8Co)yq#AAwZ!O>S$>z(3(RIb$GMf~V|G_UD7!N~UCUYJ; z_S&Aqa&Hn$GFIVITw@!4k=bEKw{G?OO~^U4wW&p6L!{10^q+=m8PAo@2i^aXXKFQQ zn!JcI4^JdnCnt8?38b%~NAXFR#k;1*4QQ>o1DxhPh}-;nZ0SZq#Hgx(X$5ypFCX0- z_6?j0#`nX--lbQq^+o=?>jc0_0x)2_J+ziX&CPZa%6tTrNi#Ys%;=)?tw&!S>_ zxb3R+hiOv{^Jl$WC2Z(HO^-yeR75N_WIWYI#jHS{iA@FeLPVTsH;&veZkVDDp#OMg z$ZXSRjy{5cv1<*00I)m}EtoJaLw7|TS5HEoD2fj&hB`K<5Pd7Pb1O!}k0`1`ebljAnbXx^IB$X77D@%iDu$fYHoH(07tTNi{2ime z@r-F10j6MGLZn^Ir4?OzSFuK}4$Meg(o7b8cRFVvCkFwd_vPAjj)b5cc(y;(tO9ZL zSt>{Gz($XLZ5OUUn|N}IFAVoF-Q?G{9YtdMP~#<=qoL*Jbc>l+@s7FaD1Q_pUvs(d z20L&pUd5b%-8ubO6`G#1zhncXJT~1GOdsd`;DT^p|4NVYNF8Q8`So@*lKy3B63AmA z=Lm@JuyLMMPHnxa$vZd7JC?xmTKeM3sDlQ}K_jnP(tNM#T@z&@1zk>;8$~=*NyY9y6YNe z_xNA9pnV5nf;AZ8- zDFA5s40v<(c9Wp-TD&zIRk@~b*%=Ao$^mJ%r^@80it{yk+lLjb$x^j__zxGUq|@ta zFjqL;_3za6UuTLa20j`S4(O+P6n%B5GfA2734D^X&A16=g1+2bMY5uY*5(#V?10Y; z08YxD4P7m~Gh?emn|SWwNf#!*Z$Fu|r5c_E(>tjC2c-DxtHehQg-pa@Dl zu8acR?F9A&2X7*uDr5&mS1T8oUfQJAXEfaQtsYA_q=7{tzjZasb=3d3fZR~*FF&(< zPbEdt!0Z*e(-E$-jeSs9?6G>vz4>>($}i(oKkpMP*O?hhJ+XY_96FW`r5CL7cAUM| zv4}js(OrNM;AW>SrQ|EOnd#dLEmGdLHgpF( zuyU`x43Ey-$)DVmT`chJ#%`&W&bwdgg`~U8)y}hEZ)Ab1*UR=(a!(pe^ljAY+raG! zh8GR;A0m1F4hY}x0(8ls31@EId;)$gAzfd2Vn~9lmv>=x0&+nvB}_LL$X~Ys7+qIc zw@uzw1O)vmr0L`p*Wq1<#ox;Gt{%;6Pt(v4C%LMmqpi)$ml4=)E&9N;(idAS=m5iW zwI}2Xx3b|$BNfqcGUN(pAhY*PVB(@Z3ER!YH;%`Bv(*>CvcDH^>1*cCEN=Pf!sX}`~k z_Eu+O}jHuwb?Cob)wkLfAZCQ<$Gip?Wo8 zM`Nb%7I_KFDZTC2iKZ6H zR$zN=S&4y9lu^16rV{xZ3)L4(hz?Ee5aAp1*8^#!7{XwB)z!;b8jfV$`HM|b@R8_f z?t#*v2K~!i_}dRo$8R`MQrYkNLexsbw#ya%i2j;%s@d#_jFno_udc2+ev8Bjf}vLb zH0sE$k=}X}zxTgz_;(~1l4$QbaYj?OHQ!>f7>}(F5&%w0t2j85ew{rCK4K(Td#I|j zeQwd&K@d5@%6<$bVfen`yxaH83t}3JXYIkKS9;qSc(5J2JfAC5NwJYk5>T0~{W$ki z(fd`nGxf&RdSE_SQhe};Uh>1!s04Y z+Wa#>E4Sb513XTWg!WsTJb2@L>S_4hR`S}E3saZYP~wxY-XDpjULL7 z7Cnf3m1Fuw-^JJX6(Me_Xk&9!O#L^Y!gLNLw6`2zz^G&mz@zG{Xe&77Uk~kKCk+nA z5ySi*GFwfH-gmLoq~0p;p=6PvNA3$2E0+kc^TEDa!}IWKu2Qnj*N9;*8c7hrRGdGu zp9AdVLY+^g$q!E{BqTpPEZ39m%8JUe!!EH`au093BC!Hw_o*%cdNBXhL&1*?k#$8+ z!KebdK6B>Mh`P0M0CfF;`D&}D5_bOC5&V9aM%dAPJJ1l=p#j37*2vyF+1EH%^t9nyi?|K*&T(TdqL|2%5vuk?T{qA_U79p&2xEVbAknX93_9%h^ z2$1RgV*Ttf0=o3<&*G~x>DOeCX5DZ~=Pqg3 z`|+z3>4gjLZmfK4HasL(l)=e;jihmR=9aKgwne{XP^A}RX6^JAkp@}ka_;?2dMwSs zTdVBV=80dfUlFVvxdhmrU=;5z`4-lw{CV2R=)q$x z=TdZOijNO)J~p=z$AZsVknI!)+meCQM(ExB2t+^${C6seP!>S+TdzW0nZNECR713k zF&?>L*uXKN1N+dJLNxvWK=_!?A9gAhP#Y5xXr}pnKkiWYK2%MJ@b#HWJ8go~c(+WdohGj~RB zYk8IYmzBOrS3GEB6mqigNK3`ZxRIuR90ga3xe&xW?{x~+*$|J}0^G;-`w>feVqmnmwHZ*A|9_68;=Sp1 z)o>PMuIsiWP?0pgrI^_BwVv-ecXs^Ol^oHt0o!nTicB_pz|%Oj$)Y4 zEup5LVb-XF3W52v@V_gFotnY4`+hHNr7vZUIBO_Tw<{tY#oOn<`{*mY`$2~bGP`S= z-9L0FO~k9-$*DzoIiAPQDpFJNgy_cp#-e%8yzHlx}hdRm7(Rop*GkyuS==Gtni3H%}1 z>zAY2;tr*&0L63z1RXChiunicS13>b?91lTQs${n8GzZU!JcI*YXH+@o?S9t?KJQ0 z1{l#g^LaW$?3dTiT1UT(Ls0c~o+Zw6ro zfO9ybYn``14MnA)L{|0*?2${#c4o8!sva{0w(m+-)9ssV^GSk&m7|w-jb9pTTC6kn z9ZPC#Uy4F;fswe8;Pz_%*~rv5OfPeo=CYa+>*RRJS-Jqgv>oV z%F(w|)jzmXmWykHv%HKLh6$HVQpYkuj^D(IXtyEwnNY?a8{O4i=#C~EWsGC-t#7Q`*9yl+;Y?&KfT5Z()f5_D!Ba|*2o zM8+4TiTnzFmGbQraT`%{lg|@|Sjym8!;R79n!;-FpSA4Fkl9}Fr!=#8O?_awUye<= z4qzZDP8)5n1m#F_(_Ui^sFx{YBSw_dq-MrBAab3!~&bteAaQUY?VXJ03L zI(e*z^|~%ZX?%9u`Mu+oI|OzC{IA-jX$q3+SK~sgZ1+3paERm@Q}Mnu-T*b1&Vm3` z{{z~1_w)9yb}{o!Aq^%J5C)nt^mu9Qr5g;NSH9AZmN-_{9r~mD`xTMaol$Q)^zO1wd~$vO8D3-WyRM&4lC$-ATB^+F$tNAU=HOi zsiG1}C0V}`-WBvM@NWR>wtK@Sar0v^y+4|G=)w+#w(=qL;k{&i?GqWeNAjbE?+ERhv0RKr;1x6~Kcxo`4Ji zZ14DgWP90uyDe&lSaeiY-%@pLAF%x4Wqqx>MsloOY^Kkt$Lu!EgZWiWJA}lW-^%jq zQwpHe>xt>aLL(Q$_B~C9KzHT~^*p6MLy;?-;j&(0w|GdqS>A(ZrI|3)`*}=3vSCr% zS+VSvR8!~Ij^P`Il#V2GaS7P9LvXJ)!-E&?w~Q?&^sN`NRvRgjp>f0J3bUM0yFr^H zuI2FL?L@yInBPpd~%?M#Hq-rW(ZM2m+9Oz7Z>2*Ee}tPq-IxeblA@fZYF zDS+%VYACk)JVTyZL6K^|r3}}c(Nr?j`G53GSDxt@E*xhO01fl8kuJ@6e(TizbI+D% zjeah?4@j5yp15e0|5H!Qu*@r&JY@?wnX{jq%(1A+jq|0GX4bC4)rM}aieM?U>5f?g z_SY_xQ(^VG6e`7T*s-VW>b+@o9c+1(Y-QLfw-`g*AN)Ft-~q6G(;D!HxNQr9C*uKQ zaxg{+#XBtGdbPHo;~FjrYAq-`rZDP1vSc7^RD|8@iBYmW)XWB->^$MdlsQrOFq7PRBRYk`qEHm#?{!u4sV2Soj*0dV-av$NVGPPxG;-0Y}doy>j&a7hitc z5IlUP-+39~=@FninP@ig1a1rW`^!AYC|R^JOznQw<^e9ppxAp9mszQPT{Ih04Za;XO^{$O{TUU|YHRr2y}9d9!^4|nMb&XX-BTI}XUj~~^{3yg(m!o7+WUec zx=GD7*NBmz-yHGPjOe56a!(Mo7;+#^Zq-S7`=6a|lK7EqW!9rI)_^Cu-F*=%A!ioR zzY)Its0Tjz*1ALC0*AMkc@#D)!PdknESo+oqv9p^X=htkn=UiTV{RNBgekFhU60Vn zyGh(u=X3=Cs~mu#$soM90u)aCzo6RxQ{n6fe)d26;i{YRlqRC#W-_ujr9LmeLuE_D zh29M-PR19f_AtsDKjsDjk|O{**Z%^Y^doy4VSAWEA8Wqwr{fnk;CpP`cGq0`q=%zD z&%!*Iza)R5D3F8t-EY*H)7@U}NJ3^k0ZjJg$W6yfUCZrpK+GdVFcxZ8?2<~KN*cT0O>Q0|tbH$A0_^Q%fp|L>3# zH>XCj5MjI5S<1DRj!Cq0g@9T~Joh$EqjZg{%6;T31+=KCY_vwt7haxw2v|BuuKCb0 z;$?4qVS6hUh06d8%_Q*58hP^QjD5vPdzXKm9g&9UZo4W$G(v$w_K(U*Y6LPV*IfQq z8({MS)a))NUF>9bBWKn!&dNkxe4*Tx2M%BsS~LTz9z)UnG7(E>-y*}g#oSIA4#I$+ zidHrUc9Zb{i2s7syz+`!LosO!d#aXox(}kjyQhI&B{Y|ci(K4lM4e``&A6$)p2&D{ zuU7%_bYcpq-1aLuMEHh@$*ieKw;6{ks~qxtA+8&%wRp({$qID2;kQ>ouD>T9 zwp!s|A0SdQ>=b8E(O;lx(%ZXSr94&*+2qE z)?LrG!A)06^V%&HGX!Kf*aO6D!}n9|$aYFAIX3S8y>kiBt=`0F9i4#HFSj;xzg{7YL~BO6lf8?x|A>v|D)$dkrc%;Q1tmn;z)jGQ;RykDbup zIw?&Zol*Q{*Q%0Xxj1vt=B;<4nQ?f{YGeD*pPWl(x}~R9fL98~soja{cPjIAiSU{uv4TyEMPm_ApxQaN3|TDIYty<6+ONuPyPQI1OVnB%3cs^s6_R|~`wdYy6d-_mV}U$yugV;% zpOh~=*h_)%yF4>vu_goqi7`KpTBQCGkp4mnIe8`-4t^==HqSl!@HkwflEY{i?~hj2 z%r(nNG|t_9Lm!wb3}JYB>gbSlemz>VmSsk)(cRkH-Ex1XZ0c?o1>^n1i6KuSRyF)X zxg4z4+nAPIkDdb zNB_(aKD#eu{-q&OEB7_T)^Sden8yA9jtR!}=lkSuGJHIJ@(`pf*%$uCI(#jY%IUQ% zl46>IFo6^OHQNKQY(}`qi#T<3u-9FJt#a+V$Cr{npgw|Bj2fJ{7tdVRAFzK`6(=F? zc@xJkbnWzf_VccaGcf4dYwdI` zpT^Dby1-He|o5%R=nWqmCNMn-k}7CzsRjyUE|t&7S;XzO`AmnQ+OSAmW!Of zYKGPNC+<|<-8z5&Tv|h6$G9ruL1nkNB>`XDYQBmFKwbRzV^hH!uM->} zw!CH%Uq+cy*}8*}65(a60gKU+(Dx5Nb6c{uU8e@av}Hp!HMdTVR9)MB#^yQ5px>aj zN3tW94v)oGY`TiAF+VaY<`NjA9gQ3Eds{lyhTgrSxyaT`an5Ta&kYLk*>zLvF@LLD zCw&AP=QtJgkWL3&=N%P^lcgW46a!fo~f)$OlI$e zG__k+H=T=@;22sH`kw*q;LAmE02u{~7&d#Kis1372)6$y!e&Y0;9A#|q7bBx?;ZP8 z1zljXiXva`|3})Jhc$KWZ@hXOXq~8~iV7t5Smm@JsECY7^w3IMg=ncDV-zYN2w@aL zCWk5_LbOzw6P0SDOd>O6P(dRCi5MV2Ab|uDLkJ-Wgpl!Wv^}T4;XL>E-23-hYwz`4 z&)&)2pZ&h?sybU5m=N;F)|ccu-_can_mJ=xCF|b()+(!Ioy)Xeb~I%jK-nRPsjZ=B z$G-S4w($36>VMh7|Bz}{e3SV`kg%@x&r-L0;j=9Rjbh6KQ8 z9s~HyO`?EB-7>{T-(0LcJT+%a!{aYJxjGQ^qPna5;!h;HDVWSg7(6J!6!isXIwvW< z#!~eA*460PCx?PvPhao3;zQ4KGgdGUu*G{7fE_{{u$K0NgdhKrDF8!IK~;kb)c)#ctPqKDJAz}nr(xA z;3ks|wS=5Pp%CZheAyYQ5vORYYUUx+#mA7L=hT0v#Z}GC)-9zcZJpY^RzHQ)p!mhu%&|MqG6H8!g z(ogKkF8q9m_GcDAAt$nS2k9`YE(4E_l~gze0A_JFxcH`Y%ibeY|B{hg@R`rMKqq5` zw!WcBS%B)(&QW}8MPwM@yjHZ7onGwQ5fY#cUua-nY5)O(&y>TMmQ(uQ)Gaj^c_CmB zed8X4(5AdPbN8Lin0_lgeGx_?8lU4AW-#(+TM~;euWL9T`uPPXzt3r8UodyOQ(e&}$>! zp#%|<2&*TVUP|UHO`0d(SYSUhfiV?Z6kQUrK~ zgV&DICQh-vBlH6vEMGklhM$!L&{EtD%Jg===>Tqu07Isl?m~@t!l&#vPo8!N~=uGkps@sr9$^D6*>Vo3G&`JwDRibZ?KEHsMU`F z&#Ol!1t8OSjxiauU)dj9wHuabh@Ui8P)wFXDa8E;MqPYMY?tR)WBgf`8LEBg^1L%l z+?ZBWF9^I`lHA#~t~4 z>Sj=Ovufg+uHrCl-56_0>uchJ7hn7#_IN{sgfQ^(6F*0Bo6kd!K|4gk_G+gH8!T zNr~DGza5xga#GQ@z9Db#IjuWaD1|~o0mu7C9Jl_gtO}D%@uMP*H_SRwzm2qZ_POLT zH*>{3)j_HL)L)F`{6!CzXXC;$3)_XYbnWz<7-t;P?24uwhOWt(whw4J7qW0Q{^842 zY1_4Da%9-TP;YFbbC(wFg{FXYO`AiXglQ+BduUtr?O@S#AB?x+DQqC^rCsRA)sulW zH-%mDexqSn3O6l4fT#tJQ%KN++sPL3T)$1=y!T>9U9~aJ>HZZC`a;%H$sU=*eOz0& zB|_aFWq}xaU$JwEll0>I<}!M^#rA`n|IWNJm^zV1e(BtGak6>|GEPQ;Rp9`IJX(bk zRIUvu4T)2}b*X6}DFDd$m!1Lq;im?CvUklVc@Q&n(SCB>vM|&cO2Y7F=juSF zt&3C&_{2$oPkcg8**NQhYZ~m2T|f;lAWX|aN(a`FDOp*M5x}#ekZ`+Tr%|Kx8E_@7 z;Ryk?SHQ}RI*3yvfy>TNqhzXE*o%7tXeS;8<9c>5W!I7;Feswd-a~56_1>HQ z{}r%yK}9dFRgnsUR4%-g|2Vz#)62;d6>xM%s@I>qu+pm2x}@)B-d~ODgmWLXpa$OB z5I`{+FX|}y?%$fz5y@;H9=iU^8gAc%C1I(yZ;Iw_pNXn;+Z!e|l`1&gj^suT!yqQy zAmja_!mv{v+M_YK)3=yQUU6bG79h6W5jih-84D>|mXRDKOwY*3v#b{n(+^#CF|wS$ z_u+4OtpEGTx>@SW&-h7+za@i#fxj&c97T%8$X81|6Q{vjE-L?Hf44 zs6I=RKMgw-gH(0Sr~X#gxENox!}kUumuy^|1&8x9BQ|v1ifzCv1zh*+uLE`#b}KvJmUS`s15gFnBIeWKZ<6+GYSXQyU50*IQ`3=c`vQF33u=Kg+EtgEHQRo@d?n9p1o(7*`Ai@JRM66GJK)ygfEwn`Zt`B& zb@We$Ja-;3X7BuRAm29X7seG-L{&yaRkQj4=EcVLe``&VN#PwakAXLagPRXlpR;#} zr2HWS^qn2l8?pj=b1l-X%?VE zd~K4yf3AP-{{WU>Fv0cXJ1^4bV9H;XiQ9i4bO&GgDICA79`}2zqjxNzf6YxL{CO4@ z_7~MV4P9*@vnvQq`CfzD7=sR!nw1mM;F4 zqL*&Wig&e+0Sx>s+(5|bf!D_Haw*Na3Rt+m6d~7r!2$^D02?&_ohSNtssI0Ol82th zt+=_~{^l2$fTS1IwRWN4qrO3IXC>YxloAh>-RN~GXkQdId7wuVWO{VR@HpwMpqLG; zN~O?q!m~C0#fkh67J2BZmJFv;%G?-WW1(or6cGSmn{pwe=qXcYKCy?K_TpvLJ4`NA zanGB)^hMxBRH*c9FZ8FX6rHs$P11KK`*xncud;fG?%r%_$9y+7q&e{|(-9J-J|{h1 z3)(6x1EKl1o%>pC1-Q{mx89r7IWs16s&RU*GclB9X800>)z~m=)3ZBjaD@=g{V0T8 zWwO8Gdogj0A7#Q+-NOoVTp}wfBanLtVd&KAzB3!Je{?a6q(gT&zv}v~*bOWFq^_?z z#V)>lD&vhem$OD%a)R>K%}UR&F|b^g16G}A*zwM`8WOPk_FiGVR=q>rF^;}=c08@> zq*`vBoK!1kEahAlBnDxlwx1_xK;c0eKxAd`U;tqWaoPOUW8_bG>)uI!X;O3o`xVuQ z&LacOk5(^sbl+RfdSNBN$F8^Hci3}v9q2{n}QMO z6zw|t&RICMOoci7th`J+ejutA|DNC$4obK1y^h*dZ|F+ZF&N&5SjG^O{x#xUF2{iK z@3`$&n>k$RtRwu>#>uw=i2&&rKZ@sFkk%m+Mw&KP#+H8`Ku<2|@l+d50(&kk^^vdZ zz!I|NOWdnM!ZEoa%t&Z5OBe-4r*ykk(WqHEkcHGOHK?USBL)N>5yOgH;!I6jl!ZG$jnga?nYgFfu(Y5^y7dzKv-(xw_pw)gBxi_ zs{A1e)if!8_>IarDsDF=rQv7uENg6Y%m>$jyV`-5R9Ab2x;%7M4C;JdYe@U#7Dko2c@`Cj%Bdv|MZ z9xy4@TJ=Iw+V+m=ao)mLVted34-a(H}BP+UH>ZUUusYB z!m^KC-vQ3^_G1p%xD9_}4CY)IzYG}58Bd-z48Yg7>jz4ZPtz_n`sE z@MOYX>=bb0#`NbM330e{yJ1a>@t0Pb<#y7lyO$tr%d#l7^DalTB~>W3dXrx)93_zF z!2UK%pzXmqC+OXVf<_K2q>b8(`3!hAY0U9VoFuZ6J+^hYDhsshLYWMKY zNh)r*8t?#_{faw}$r$5XgRS=u6B{%wPjCWFV4iD>HmJGN<-_Ut=s;Ulo>R3SPHB3Y zw|8yLJW}^OvrB3;z002SXnyi#5@FK%`w_ER+U9s=&S=H9gvUlUp7T7vVsojdE(j4~ zqecY`{B{SZ;qsEO)o;ZIVQVF6N!VHrC+Su8u|e&D*Zw-oKeV9!8vW|+d74W5uve20 zUK|9z-3NMu(Z4OXb@#JBJ(%CF?2DPO@)Y`1>QzbyoCOYcDCFS#*8VO9hN09WUQ0f8wIJ1$WR%A_)6| z^w#y86T{y#%52@akW7Lv7`v`Z1HPmI;4=0-w@vhKQSbC!_kQN$ZGZajX>p;!jH1CE>s?VT zYS~|up!D>Qw|~4j?LvIrn_DDj>tEd6Zqhl zu2rpIl2;nF>Whv$yfP{c8%eN@ItyW0c-n7U@|@=!&?zHfW15#IowcH;|1*=5MBn+; zY9;EsgX=>$-+MU#&%ag?lajwgRl-z4f$hth^TwxU*BT++w#%k64!3(7aA))}k22D= zLu>Vo4_5nX16T03*umfDbz;OYLob3Os;T(P4g_^ifXnCY~aUyVSwH>xLwhDPvV7n=-;O zcVkX?;n3pc%M*xL$(c9|@UC$yBWcMqPn~?kxRis4+lF7I9Fkaoe=o3uQ#li2CP(*j zXiXWOeg}OYWJFyZuhZ%~!q2M6cz#0LTiZJsvnP-Vo0o8^d4rr|RE6KH{FQ3u{}OBYAB^h%H5alQ zzKeH=svb_?fVE%PVZIa)*+~*KU)TW~TR3B)D<-3ab^Ha7XO#q#R}F!*3xAV3-Q?ot zhSrKq+o$<~0R#CfyXTjnh+aN#Y{|uiW7^eTi(@d_ih{a04quL2=+)HIGd?-bjE&<* zyp#mX4TCVmkv=sU9~ zerq$a6aPV@xOuO+fxZv=#Wnavk04Kr*>VN(0z+1MQGJk%KaQT>nanJ-PCW@o8|z=j zOmr^gXcDKMg$(SY4GjC?UTOn_myF>h?n_G09mq;xrzU$dP7nFzWs^DPF^{`fC7i1e zUpEeGrmd@E!%X;BPsqbJ=1VPdX>RtJt|d!>lM3evwq@om z@rl!b2|v_UR}j1Kd(dnw^56sc#zV)Z4lc{_p1NT6=I*8KjmIPQX9T2HxJ>5s-OhSg zP1&1qI(+JH^Z&H?viQ{fGrz7F437EvpM=zN-)H+D$~gPkNE@+sU;#~6^ce61Tuj2; zkBZEw95;q_1k+TJlU28Ik>JMYKGO4BPsE233EfzNi>z0*Q zWQo_!&#J6Fe?sTYo{WE1j*=)4}{YKQ&tbS6xpjHG4{FH14{GGeQ_ks2#EbfD{!2p z_Q9*^T%>PoM-IbdSw&BMwBvzeRNXbJ7juf>^2w)Jr&F@3AW&mVjk+@2y54LN#B@u> zE5)^z(<#z+2!#6x?j2HOC}P7d8IEHw;Mk8vGT zdH83FIu{a{5~AR6Ee>MaVC}m1hHY&>hBhIFVT|LmgEI6ZrGh2|OzO!}Qh_;=ubaI? zZxd?*J`bSItsnMEuF$wfO=mH~tX}M28sFT3a`YiCf8`Pv6z>^ABR(bJeQk zH|N(!!Bf(&nX9MVLHU%3dC0jqMx@{rZ|&?Y0%l^cnzZVpjq4G6%n+Oe_1Br1no~8^ z!o*Gwe;^PAu^|(NVwAF0)*ncu*^YG)8?lt>(`4H>eYR8CaN=OtWi`JcdN^;J4M=dA z+M3JQDL;ud59Zbu0<#+ISYo^!wJ|Ane*01Hsvh2PGnjT4undpTfW7~Vp(7n!t?0Cl+kN{G}o3dEYW1d;d z@`Q5*6nE%gg)}`xNiAqhgvUPAehr!Jv;c~KRIw^CrX?}_EE0lk=V7?WbFjJwLOFRnY5z98TH5OSg@89-H`y0jfZmNJaOgrJgT8S}6 z%#6S@-h9zm(?Q+EN9l7r$(hDOse=vCiY)Q{Qhj$YXRl3s_!L@Y%SUNlcaex9&p4gX zhlPHv9<|^$xqwo+GM(tg#6R=s%N8G|l^Wl$YL8iJKWkVAjNA*1q~f)k_^orDHex+C zN1ryqif0)+7svX>ocwyAk+~$`o{=P2_{kUN>}aV=^-`AVjdQjw`Nodl4wOqME@;K} zKJQE;LUTJA{N%n5_1Xa_9De~3mD!!$_YS zN244+nol7dg|E*qu`PH23w3R%ww>uO+60p(ZGkV%5mi34x7Ko1od=)i9f$`Qe&*^YW+h=g!f5|*>tv$YJF=XMi`5tGJtum^J@j+v zZQ5HT?Au4}L^{W|$lCJ|V}c!_4oS>t*lcOw-M^TUbj|#aGkY1|B^>fr5ws=jE=Q7X zmd%>bT!1y!l`xmX>~Gmy@XCRnobnosT@@tN2k)HhL64zu zx+vRyBEp@c!BuPq?uX=~{O`Ls&W8SOnf`Z0n4?Mr>QT;|L4MT7Xz7(iz^0xJp&v|2 zivnXJQ*nVM+&oP17#_7y6?|vkVDKY~VL( zW4~gW`sUTJ1m!7`$ln%|tRNh-ySpC2`5lH=vi25B5qdOQBJc-<>+*Gd_^ zosN-@&*pQ%3xU`^M??G*e_A#*ZawUTn2*$}_{?c)YjueqN3A}Jwi%J0;f+LOFofl`1SQ8W}eg4EGMLQ?8pTY zfoT^!f4`Rn&BkA`eIfaQ^;1SiMCwS;e6fJrM2XonfulJX(qS-5Nx(XYkaFWabET^Gb3_L~>wQ~BNB(ggdKo1>Mql{q>I z7}`F0W*=Cmsw%4buG?{gyJ>6Ffrhp~pbK5FZ-qHJ{=?Bxj>ZIS(?j9Fc|vhV zokObUx~MBc#wy_4e`(E4BQ1Y-IPN3l9$ZrA;)?@b*>LmWj+7qNep@1M)}NCQ@J-mO zd_7;exWE(fO50D|w46fcsaSr6E#s`$y5;&C^H<9&cD`IVT9P4F43jfvcO5|#fLcy3 z!g#IN=cje5TIzjC3qe1vBRGDnPa|-dQRw&}h^uh!<0vgp3PlYSy zzvVeShda2DT!|;TYfLt+vevFt%_SDyH2Y3gZW6Nf^U-{7qo9YBW-M#sC#Un(-@xub zUe#Qt+;mwaOZCY@633+CXA|B=#K1 zUn)E`SK$i6=t#}fGZVlt`S@0Xhapf@=0K9MOvzMDiD_UV6wHg)HxU*mw-&vdiBxbc z`s!3XW$eN!u052 zINLe#*ip*~IEH;26sYwwd?@ogD_3~$EX;?~acFPo9;39{Y-IVnmvx296B=$M_5egY0hbAsV6(y$v1{SCT5m9pY) z;!zvcuB&t39VM)1PwiE`>;5#2KOij(%i|y%QPPB*Dt>mE94Z(i+G3{aBblD=kdD!& z`3$CEHdCHH^$V+COLZmkGMg8+_RNuei!=O{o>hhUe^Z)=&8(bVm7K!Q?VocyFyf%e zODn-J%{dkG=)}2E?{i2w5BhhF8Io$6r4dFJ2|ocxht2?z6=BVg`-Wd+@{cE+W!?J& zDr;IoIp&AUpb^F~-mvNb7|F6Q3w9Cqo$Voocw(Mq#<{3XM%4_2atfV?p!LdKcfc2r zP12Ten3@}oRh1fBW>ikE-b#NR9q448MtkHkD7geQSADL*HgQTOjB{{@*68rcJQ76{ z5#(o=Dd~hosDLXWKo)U6fn@ufE4CUZem81V!paV1PK6}Mm_R6+9Az)0b`@^+OL1H~+kFi6!oqlpRr8%}4 zuV>&rp*_I*Vh+8T?$^nRuqzelT2y(>z!_tDt9Ll+rb)iPax7`Exj;a&y>7Lx*NA*TEa=zPOXS-h{^t zkI(*`iNuR}e!3QH&w89gW9nS|h;5_C3ey?gk1vaP4cMbId5pI&!hV^j`Sy1?qJ~M$ z3tSz%d&k4|jx#~w6t`ZH%D9O99B#mC+QGDURzCi$@2bsc&Nl2TZRce3Q=qKLL!jEA z^hD05!aCBsxeIete)Sd33UK@;_5<8d(4tWC*Dh=icgS|^lt1UWCrpvHZ#|hAiSkLB{(fy|v zhO>ojov&}$*IjbOya6Suduan-sGXk?GWyDL)0S!dmY1_#&f}?mP3rLZ;`@QmtnUnh z+UY8<1#9E@js+Vcl^SgLjzC#hF5Z}feduRw9TP*tb!&eH)5Ws`3*z-x$tK*~xf@Lj zzZ8X)%U+a^_DmHr-3%S-Yjp&5!(oWl_8jY)=lt;n8<6R-Yzb{e)ruSwnPsv-F=6x@of%D^Mofef5Hdjk{u zuBQf?j5$^%u54C^Y-aG$)07BobU*M4f<~m=1UJGE$fEoe%2&2ESlsMoFvS(vwTks= zJ8_iQ6|TE0r9`BP%Qknf;iJDT@&0Y`vJ>#_$B-En2R6fK)b9pbXZaaHx>rb3=Y(X2 z5f4V{21Pxk*C;KsB)H>plS`V>&6bm|y6R?PpOyVbYG$C&e`-d$o zq|)b}5qDmNv;mc?4{=b8DW>=Cf=#rAgJz54b1sg=!McveQE-0C2sGMVesXm2(W<)V z3!rz~fu}=}g)|#kEq>$7d0#3z0eRB%n~fFE2F5N?4|zqm4Orvn#>v$Uqkh)YLp`kK zC`Iq1Ld&qq)r!#_4YNHvAIgG~Gv4}!#+G&7cRLe6pAJk+bvWRdTDz?yjnFrpU5!rJ zjr^z^;ocQRO19nZxc*I}Lt^fXPul(v)%}G{vEp#m50({&Fbm)A*2B&be&m~K(Hlsn zcWlcQkT3XFk0A}E!;0Q>DX377k=>Xy=ssPQpXYB08=o2**tT;7n8R>iPwa_WhRig~EG?%8@-sJEbRfCm744CSKw%4kNJs8d#Z)%=UAHX9kZ(c1_Y~BcX#MD={<=4$WSKBf+nPh zmj2rmWKXL%c;$Xocb{YW?S3Z*Holcbn{e9+Q*u7dW>4DcM#qfK9K`6x=H^~5 zvp?evphf){lBoNgt5>vA_Rr3kBa!>{g9Zlu$8Xa%m>O87&&^-gZ9~!9shJGOoU#3K zlLgFZpKM~lerbWQ&Wf1_OYzktz0K7o8eX?XWUhAO({h=m=om{U2aEW5IEO{osd1l* z(;(ja7m-i>Olr{4-I@J+l z4%o^QH!jydBbMbJsm3Skr#e02t2Fxv?j=xt$Gd5d2B3AcO#DdriSTEGq!} zvTBoeUW527v{eE;2lU$TR~8)1JG^Ut!p56h5|rS8RqRi14lrjqMGztNj!@mzshnP> zHdRjzpcYwpAh*N~RJynbC&d04Rm?L={P+35(6x{ExZt8c>i$Pg5`NcG#bP0|!425scYGRv<;-!Z{Z;S?)5(W1a8yaB?ty{OWv@UrTd)-c_!9nD=;- ziirmCjQ7yyNYhj7ygj2-j30MvMJ`$@c28}1mpn7*CfF5o3C>e2Jx?9TbTLe(LFHFI zCP%&bv?7yHn!RW>FFwMue*{(hW7uI9n1fh+1q;%yRNRCnw-UFcIrzp^^O6~2bbl6ska}gS=0gMjs(v z?(2Iea-VK&;$!tMN_M}3@ll({_i}g0yeAz$iLW(%52cNMta+#I?ErSn`>MNXvnb*^ zi6ZC84y)%0%@2OGBKRLOIah+uCQ8mU90*zXu6o1SOMyM40`_E#|5w_k#>MKiqZa#}qI(a# zZ9Keg{+Akk-jR487|pr))Pj4HX+SAGD{{lfk`bW3wH%!vEA}1%)g9r$`>bH32uE2= z8Z@wEu#92#t^=wPzP`M7?bJ?~wvk`qIcmt2(R^u!8C9dp&*HL+=1|-hGxd&IP4bFD zeg~JHL$>OfXo^P=lq1K)hjn2@4;(%@OoDZ%yTTJI$xJe$jhlARSA3_|=mvCbMEtCiAdl;3iEpAh3V>Jbu$O~GYO{i?x~2TPcsJYhT*TS?P5F1f;eN~A zwzuyHO$m2saW-gx=aNzBh%vaUhFmDtSC!&W#~efCHPR|}n^gbUx%sZK$C*DbbXpcV zZ830n{dly$)yv)#B=(YVVk9 zs^Z$AW1$-qhtSfZlQ|%8z00*S2~WFHGJlka-$MOzkLi>)`B7Cr33(;bYl+G_?Z9w4 zV&*;^XkoziTT%w`Im>Tx@ex-DY8>4-$lGiBS>|)WoCn(dRvUHFq~|0*i%T?d>f@vZ zV&A7(u<~|t(s1zxThGyEvA(SHn-pw2-hM<-rZDGzc^=9z#1Uo)H4FSF6Vx?w-5{0g zZ7uh}x&Iw`lakCxQ@ftg@=>8~_@YfjrhG!K1%Z9kBzGUz+Ms58%o~)Kwa*-if#=QT zTbU^0D+d~Y7v>67h%WNnfhG33$LV>RPvv2P`LI>T`(^rnUx(kMAvFVnAQvHV)Y zOyF~2o69~Ij_o}fqg-W6ul6?|3|Kw$Rdjr8aUCP87w%h~52ZHc2IE7kwm#MgsxOHe z8{N<)TMQEu84@;H+B`3=H(u-(m#NmD?NoJM2per$>WDUZ zc*H>zYFebAiII4{SCixGA>OhAmjTG!GjcFHoBX7+aRgOP zJ_-T&Enl-ucJ#1Nw%6`v0U+IC2M!Mj2iWHjyHZhe)8&=phL;hOJ{M8H{_3$D z<##Hk!tuL%^sm%7S>lTaV37Jof?ktPnb?_0hQ#R{xWRTLxv>$cYZRil;S3zSVV1Z+ z5zp%ACS4}oD5cZp^r4n0CqC?4+G<|1vOvWxZDz!g6drY9x?v6|Z2tFv(&Lq;LxWBeIVeWj7!vt6y@I6YZ!paaAutrL zJ@azxf`_?DWtvq6&q>M|To?U4mHDt_!y$oe*fk7n>N067GHvljr})L0pPP()6K5Q+ z1=Hiu5`nSZyU|67J*CUNM3Fqk!H8^D^2U{}mS8h*h(bixs*$TkOSo|@gE!z}M_ z)W0I=UyVzFi^mMDi_(sWp$oYXf-Ay>SZtg{7sqntnxZ zKUuO}(cKPrKn-{{Rm>`ScQ&?K#tWjDrWA2_n4?Rl$|+sTCgJKuYVI0&#)dRT@iN0$ z(9YA1*k_z;wWq*oT- zb&K>`0@g07^dDkzFFVghR_PjZdBpAbB*dCuIdF)@O@hxE*`l8l<6J?IzgRR5?5L){ z0a(N>Lo1JUxEK0yfdh@(yfh-kpN%8CmVV&sj zU>Jt4{t-hfv6auTB8=!Jmu;e*S7ooSPes21?|ZGsxNj$IYnBtu;*g#r%~eM?A2nW- zIVz}&q3Nc(Ax1u)xYeymD|EGmgGST0 zFG@L@4;%5xH!{zv&q9Z@7nXhf$kioWxF7QKoz;guVv`1kbA>(kJg{|XxV`IKAn)6$lJ7}jg;$o^Ff)$&>s;YkHm7nss9LZ7w41S_tTXn}(#zB_ z)u+qxu`hZTu5Y%znx4^O>^uwHef-(={HM6hb->0Qzt_0yhieSOFO2hqT47yI<9%vn z3ifhou#{j>88Ths@Kt-dc3{QzK9Ef>&!m8REZ3ukaD5M`QG0*eYnL9+pG(UwD;2 z1DSbVb#oJWO&d6a0Cd*Q?AS1adQSF@6?K=fy+*LXHR2I-ye60IuowbRYoP>t4NdAj z3S^v=NA-Aupot4I*Hl~qQSapIn~y&@y786nZ^~bFeTWC}g=uP4#)Eic;^6tcE#2KP zwIjZT%=vObQB0E*&%8tTV{6=rszw^i%X&nWNtQyLa(&H#<7s|}pkJO)A4GyXJ$!lC z4r-I6Hek4~?iUx!(m;V8I*}Weg6bpjN9`dNEYSFqIrlSZQwiunUT&Ej1tb|o0&@Gp zyzET)2$oA~wSMSmx{=r9u-KB?56xJ;;HmyTHeM;Zzf>IAe*-%o|FSbUA5#rMs@P>w zH)nV&eNrk9?O)gYF6pO3)ac0FEl|%YNrA&iOsPusTw~F7Ss&goE2tiy-U-lBh|lBL z&iQ9e4L`WG}k3H||ID)v2SyhrT@BNo2>v*(>H zBwjCd?tvpUz0_sojMR>O{Cn1#3q2!TI?xuEx9=YMd7`ba@!t}!V8usizDPhm-Jx8-3_)fO5V{`|A#CI$q z@g;JcaZuY=Regp1e@DSpw{2TR+aHg~qulzP^zkccWqwunYv_|ti`UDJL)_y3&Z-@%%B}zc6!NUH0w{t_jQxfx z>PbWVF}ajzIuY5Ldq34Mwyg~ph|p1wrrpj^|He;c(HHnU;*mW53k?37l$N?8uPQOa z%4f4N1oIj1#W#_KZ1EfPCu}t>@lY#oL!4`BNCYRC98mAiXf6(ql;jVdizZ0m*~PEe z=)$7DUHP8bV1XYu+fVmnRkyQMOaLwY5)7RnFlJ+{{=+auqeE8_r*%nV3)U zHGgISc<=s4qa(_5PQPbcM#wSx%)MNoYYOKOj>z=zPlLuBs>OB+?};;e-v}>hQ_WLD zbVX%tUuhZ6TF?F>eER%a4nWTUn)?|ypEB>A9Qw5v*q!zDgtI|fjnuzHdIn8PTaCO} ziWAAueQ)jcQi5j~5Ub+IsX@OHbU)*-pK6(^{oM`RaCeY4A^8rb^Y-F5=r@R*O?}B` z&h)Z7G+Au!jQcAV`vZpkzfYEua3U5w$}0hW$Z-uoEtxTg64eP9^9wzL(JPzx-)!2L zpHaUdgF?}bUmB=fiaHR7>uv;8ZtlKFc(^2GoQozD?0R=sPOC%2eu{`H>}0nzvwW7? z;iT#-tcyoNneA|kls9Jmi|v6Koi*1DgmW`1C)Qu`XSElWMUph{S~o+@98%rjF$k42 zA{jI6GT)+Hbr>zZ;)od^R{*yCS}{>%&DULz7qPkMhXgaiG9Y5uH||7HGXC(*8{rP)#PxgXYw?z-`oU)%n5?w6+`qmyF-DKZ9l zRnvaKrYTZTWJqcQ91~BF#F8K%REY(oKctwEFHZ#gXF(+%o{x`K{c_MBy6asiXUJ=y z1@dsl(;_(8l<|OP=m2%9Txi<<8mN8}VLan!nMgB-BCaOKhn_deWY`0+2(cwpv80n6 zh^#48O?8n*rnWR?>e2HM-VM!*`p(2>Ze9@mT$%$@Uczs~bi!dWu+JTo6Ld2xWR`R* zvUJ!;drr)O4Z0O8Mqd( zrRMh5fKZtQi5sCEjuK>hEZf^q>(ZMO@!Fj%TW&iqd4fJaQq&>x!HJT67d~^jJ}+@A zpZti7jPR6^OEJ2hi);d^02C0Y_HLUZti3Kl=Vr(e_*S)Tm_p`a<_p8!r{&2#k@c_n z8(zK6Up@KdB4v5kzKY{V*~ve2U9@OV|1@gSN~T;iQRiDZ)R|c=hmNbk6p&UI{1aWE z?=Gt&2j*3ny@-K$Q{7rO9fotU?UT{D_!s5QQ{0iSh^;e@@t;ZijeSXD9eY4U`s#U( zPM!bb3(}6^mLhJpur^adS}duX%38ZL^QqqFazEdHAkGLdGn zJq`HJM)OVq|4p%?%D!pmXj6)EsBAHSro7FdPd5%DY3hX@Bu@2t+TYXzD&RG%-H)jJ zm8x8!;T>TN`S~ZC?*R}U=8*USTwD?6>LhtDwFK^3nRM{z$kztNU!;zrG<$mNVriG0 zD1Y!Kk4Q(AV2@T|1VlJ;{y*qN(R<^B#DSypSsDMUoba>2@e8i?_zhK$D<8xn|DJMA@zAAl+^uUyYux05uBz8}2AiTtDVxiT=85vzKyhKvN%kcDER5#O$Ec&gA#NJh!{ zs2rCz(RCaCNq2JK8kZ-jHtZVL1|H18b&<)Mmx6i~hr+HQ`Kb|90kGxlNJroM)6ON1 zsoHMC0!ooi-7cG3h2pxL49AVFmzY0xaJu{z>=peq_`xQ-0fy6yr#*dNaf4et3k zsuy6Pz$t`)S`<;Ape!X5B9w{+>;JCaysup&lM2ww!kM=&U9MeBC>Q=>dv%+a{`ek; zAohbUO?6rc2)N6qdyEq~;jI(c-=bpvALhd)RDEJ#rtmq*MjF%rJu-APF|P;NGOMw zq26v^pc=LOtGrM56ol zFKoYd@tq#G2R^f5?B~Z0rJq1;j|2~iubc}$HT;9=O$1dV)PA)A`+&xSJwe10I`vQ~ zJP_8-=Kpl=UkV%j#O=@b;`yH*?&=)s%m$S4Z@zo7 z=f`5}2R*y;(WN~h8+bvSg1V-mFX;zIi?cF-pJ!A_%x=?3a^=F{pmKtIE>Z%3@C2wB zvtK#f9T$wP*ob)Y1O0G3tg>lOQ)PsRgS*Y>MME79fz~P*fAfkrdCY~JYHfe0JE_D) zR&X|=P<(#jwROdVArJJ{{9}IbA$P3lp#4-u<^iAyx?yuX^V0!$Eto||I|mvS{BkXU18i*1s}bQ(Q$AIYh{-&c9HgR%~NU|EyTf1N$=xV z4_r&Qz#xz|wlPR{%k}$X)h4*Oo@;8Xl<-sIbE zo~KE;G%z`-BQcvca$u_vuI@D(tf@fv#~Y3AB>x!0jXS}HVctOry0x%04BD<(aWu^D zERfm^csJmUXXnwUB}cO-C0ZucaBGWqowhe1qTcR}NLLm=JDQyp{)k4ndM7x8%W7=B3mlBSqqT%U-H&EIbUAq5SJ2iX z>0o6BrwM^p(CM|s1u-;PW8jPjuj$^+2IMmQ?@O{-57D~@j}e+-=;GYt&{6i}`0%!p z!b&Vv@t_@Kdb2O`BKHfaB$s=Bo4_{{UNt#!DRR3g42m8Yu7(<(JEQrM7H^M8iDw~b zCbx72V#%Oe^`;2UUQ5P&pLt|WIXO@pOx6eI*Goio1v9C}D!LbUVjJ&AtLtcY{Oy9~ z3`yEVSox-&v5Wcw+7?^l0Do@=LcHsohi-*-aldatDR8L7aqH%Mi~dLQZW2ZZ`jJ*q zWVt2*{}8c-?#*sq?=o_Zjr^V#mmZ!LR$hp3bY-{&rV%JWv{IX~1M!H)Mi#cmZ6FME zz^3(x7TIJdy{$aCw*0+-!EM}PAgGqzkMQGWx$l|tE~`5!bp((uKmWYlu&WgO&G<(> z0woDV|4odyuFCh(v`}yHKMD0-#H0;i^2G4DPiEzRGv3TE8xD)pg&i&t9o8TEkbAF_ z{#s9aTA1$ACTm^9D0w1+e1v`HL?xgzntTX?FB*y&z|y~y#yt{Yt3ry)vg2bL)x6Jn zyAYnd7b-{N-wh*#B!2#JSEv5(tyl=@kI5BB(vqj;btIn>( zpZJ|p&hbJi7o)Gbe@m0GFC{Z%s<0^K_v*r6&L+vAb>QIzh@oY-iPobjib-x<+tbyu zll}%ynMr-f4<5&EeD}^(=vk3975fu4VicdOJx5CUG+ns|C6Ap6L+tq&VtUJ4NjM05 zrvg3V{F)Rl;^p9O=vz>ynEB{P$hy*=!H_TMZ*269;ynO_Y*S}NQ|`((l0;6EE+k%Q z8KGLd=l0G%W4*QsI3DSb$8(AwGxN0YHpvmdx^Rv5J5iz~GN6)Uy+M(&U{%5K%>1HZ z-!hb*yQXACPg8^}7Q)LArlVd0oQn zSP}c#=pa5V2~fm|_0RkcM+qcxq+v zLoA&%5H`@loN2%GMXjbcElKHZqdQ_Hx{D3&w8;m#vd^Hnr=OJeNKR>5xT7upkBd6X zg+rbi-Eh5H#*iWMk-r=}5;BwtH3BTLyC&BBUuV_RUY@(o&OMcw&a zXQt;ck2)NLwHbc+tK?J5_?|5bn00e*An$io>&SKn z&Ah;;?}KaY$bDg5r|~{XmZDAq+6&{ueEyjCRD}$GK$m`SEf96ZY#rhELV@rn5wlo% zvPc?X`&vX_aRkwv11SuCT`?ur9}lo6GJjB>>pvisI+&0trfPhVXCLdI<0t zDSf=is`e(rv-(}z>B5lH(veNz!Rb@#^$Bx)4n;O`Xk)k!(G$R>KQwe=0Iuy?PBBTb zQ5x4|W%rTgQs6S$S;b|_LAl_-i^re?sZ?|cs&YRVD+lWb%D;uphaK;_Vfr?&laZUS zsc6zY*vFq)ye+TfQxDoF=i|IY&kS7|v|XoJ{>5*$0*RGiz~9w*Uba%VHM#8{u%@6) zPDUScp)BQ8(FNi+D>g3eDZ{0UKc*(?-H6orkKUx9uzCd}v6mJxggxRIjzLUSBk~hm=;B|bY))*9l@fuVDniQvS z4oJ0xdE-d$%m)M3s6hjq_V(B~BP^)&D$4sZITXe{q*xJvZEj>!<%H1{t1`oNM*gNH zmdfE^{NS78lE*$JM+`~Z{A({7%96^WSHEYJQC`GLEVX2>k=OLGJE0% ziF~rz=PRWfa(D&rgOSgqb+!21&hJ9ThTE&hLQ-$EU?&fL=W4kWO5U_Bz`Sb*)bc9L z@mre4X9D2Ep%thZE$ue*qRq5Lk6K=1WHtIdRkYVz0$%Gu&N)SaKCvJEG%|c#Y>p_W zhqv)$UfROL{<<(6$*!l7&mmSkqLc<$t_0M}lyA|B%*#KovolN4O-GD9#m;O>3tZp2 z1wQgd0ewo(6nJ@pCk78nygPnC0;;rfgdm)f%c}W$P2ntBbNpP|tb+Q|92$^Za=WR| zVNU$e{@9fI+moaJ;>qb3wEZ0!{u;@?>OHOm#gR1x*SL{%Z~JpE)ZhMb2)*Q+b+o%K z@Jyndd`b483VJA8{aGY<6Y_cv%`O0S(O}ZVyFbKw$&6>o3<<%s5J+XP+xUz7$J&8} zpz(gM(p-moar1$Q^C^XVed_>yiYj#MM{-!f-u(3;abXhmdV*0 zikLMKqI^Ajgj$bivJNXh1vi1D<|z3Jk_bZ-{ouCP5ht}&NO1&V;~-_HCiMj1;I$7a zPS-hxt~8(F(WlU5H0Q^qX)I?*nk(|s@Q-*f6nE;B%%go}(`=`a*Lgl>4Y%!^qF~wn zw79B^Gmj5N{zKcT z$csJyb$+u@e0+TP;7Q+`E_hcj|2jKxd9bgxwtAo?Y$Vk(=3d6scI;l~nwkHrluhyU z=SqZPM-J|hX>I6KUcy4z9@9w32yUfEds|^A`&r3r`t%QhcSYf_GWux8L7dx3$EeVL z=*t#sE^jiofbgglZ*D=5CV|A3yzC*|H#3`Kt9ocy5EZbFoSaIYsv$4!);u=6#m~1r z%lDenH9kqx6>ul6=4c&uEi|j?lz?hipzMnG@?MAB0fd(I#;1y?cv2Sr24%qU z%AA}qD_=I6ZCrl@P8cql-MJKINZn9gAG0=s5uQIblJzK1r7l`0^u8tv6D9gaxENGy z8JYyo>NaP919j(arvje`f|N#S|A~5m{sV8ok2^4MBbm9fM?V)a`AY-TJ_r@)KA|q{ z6wkZ_8)C~wef`7-S|r0+V_(={Bst8Lf$J>y=YF(UItiBQ!A;PwtPh~pkJ~X1>PRHu z6?9@CG7mrHIEI)!ma9*REC$}nY2{d_tj38(mddqq=HUI((i#6f7&hT4Zz+T>k5>lW2}7^Q9;Ib&Q{ zDML@eN~q-)JZXTV$KQ58`aS1p_x32j8mj4hp#n30GI#1!VJLBT7-GL_Kpiu{`Gf^) zGLb^589{{>2?5_xmVvjA0XipSQavO3?C!r1h6zQ_>buyZ2Lf1=)EVe6>1MUmuHJ^S z%5uY1`Hso_{D8ng+wAfSOIry30IpYA*nrR$m9nr#%Jm)b_^O3cB3^9H(@y5?>Yb~Z z;%cW{fq&+?uE2Mcmql3lkKkG?$F^9Q^>7)A+PZBO*5{bK{;Z2*AizE_dEm38wbc@G zdW%`fKY=}-;LkO``62gV)-VO~AR>EPX^`H1>gSfBTY0|pIZl)8B)BhxD+Gnwmbnh# z?-g$4=Cnn7L8Inh;|4>lRE;O_DCmFjDX3v?$CcR__G=$57(et3Fpv7V@_N3%oO-ph z9bWH-*pJ&DSqsPY@3uFusJZ4NT@rU2&*uyuqsv9;k=?{tkWF_9$nW(+LaHzD0CPO6 zK);>XCFZWZ3cMG#xb(nA4DpB!OG$Z$NV0l1lD@*>K- z=&cX|(Xc>Zwtc7&o4aAUxWe z;gIy6ax;y4Wl%Tq?-XcVshpqWpp?>M-$LG_9I=v9vtIe>)8mhp=F zvkgg=)A}|vHCC^HMp`*psR?tmwW?domL1~e+<-dsB2%rOMta?BlkJ^MOn?4eUUR$3 z#iZE4fCyh&N&mBi%V>!C(brTv&9B(g{CdCEuF-l!TnnJ{Kc+=+>o$)74F#+c*qn9) zedfe4@spe!w%_TMq?k?khoCwh@INEe`ozulqE(h z&!CZ0X61owG4@$(K-T@a{@f$0ym`ydjNd$IvQ!Xkpm1A!t|^Ft<@eJ`BXnaAq6o^U zvyZts#>TQCli3kCtqDQ^bjb(YefaYVv?Icnx4BHRG1Dein;DiU%?IWYt9p%{qo*G{ z9gcNPvvN9M+zS_Lk}c)4VR0hUzy+aXz}#vkk2q|4W})b?<8;3CwNKxPvt6nuwb$kp zuM5GJJrfU-(%u54uC)v|8mu>Vl+7pIELaT2SEH0&`i8cf!SqGY$-2Z&`a?+v-Ej@; zOt;LSJ)}EU{}SP2jKJxa1l5g9JLQx`4Eu4;By4gr_4#j{Fkm4z=pfzcP~sxqJ( zb@+H=@XYtF^WBR$~ozIp|=*d2o!cl1{p^(tw-X79>8hCVSp%-jqOA3QfHIpxccn;wfE8_(?YmPZuOZ|JKs z;O{-69Az)l7#L(?tj_|a>$k+&=m~6wXP|o4lD_vQ>AO+k$^cQY(kO%2WjQE^5yjI* zcw;Y9&A-sJHi;HYTD>-SAiAx#%{1?G&4=>$9pWKneJgTOYT}yW#m%Q8P=#<}-}CH# zX6k^zByc3M700+|!F8O`w6?L6Q|!79pz|!YGA%^wE|gMn$T5`QVpr!&_R?T!Vu#FC_!H$B|Mtnopd#Vy71Atkh=Sr z!8vQ1N+c84$}&(sLV_YNKmS|9ZAMq_PW`Tj<+hIt7J5O^>UH$GJbj7{NaAY4?1o>g zX+N>I{{Y&^X_!(4~bp*HB@DAH@jXjBfoFmyzO~qTtkUp0QuZs167Q zSpnqQ5`P=Ty@TgWshxIrbp0W&tV?|O5OjF?aXd#YrS6#+*t6U87I33*WR3sC=RIl3nvM796K^(f zBuXQS=BS{MjU`K2VbzqSEVKRFu!Yp+`S-Fb%O1ud92W%;<+xK#b{2B5bUDz3Y)Uxg zlkUIkMn&aQYLKk(C`ppDJEqMjDM=Ew@{w9BjK0m`m3g=@>kA4U!%(ti$N65A_*`wqId2c)jO|Bf9v*sjJM~rC zX@d{1ae2PrEkNJ`UMiE9r0I;lv~7$rAU?eRq~Rh>UxPvMvWT+buN@B)ClgB9wr1s1 zKP$Yn7(Mzmsv2#dyqgH^#%V22K@i*0vK_SXiB}64z0O2b_xHW7I1c!F!nW;!n&E_q zl&{beSLXWK8CZK!iH##)gNml|mf{PMe~V9Xw6c7MG%ym~$8@znA#9YJ0e=#Bs zcMS0QshlHddV0hn;rp>#P7p4FL0)dp)6RVT#%B+dyWI-Y+`epwIus?U+NoB~Evp}g zq}W2RRPL(}fu)3#^&GcQTWgXtOO%3VaF12>2HltJr%6f$_jCP7!JRmGekm)Q0+RfF=;cZ%<08;{&T+#6j{ zpVz*nk`~Pm7OjJzObD}SqTleXVkiWQ9Vu9YKUpc8IIBXY=z#>5u-68&gNa$-OCh)@ zIMtF=MC*Z za=)>H8bYnvq20qMVkCicxOIS?v)3gaNaG-*F2=0&BWRDhdVi9!&i1*bd1)t3a4K1N z;12OghU8AYe#hK|V_IU{X3{1bKiAi|dfjMuJI24pt$12EbpO^E$0amQv!J%^tCln5 zeHhobSa$?x(p@?HXgOZoMrb~!Ke74_=$*}&55u;!RZNch;e~D3iT>TmmV=Y>Gf7}% zW3}?`v+$wcJeJ&Pk7c7f{^C2v(P2)_?|@u%WmwkQrg?!&-Ib5ZOk2}Z z#$dvKe6w{!ALx$fy*VE9Xvel~@2yr`%N&U*Aw_SXkB$_8{VD-R=2ia}KFDHXTSk86 zc*D@$AD~|IshY&vj5cNoElulJ{kuWnr~lEQc1mF{J`qkxbD8nxPSnTe!KZ}@jesfA z@T)0uFdFBpctb>JYNN!KFUDIY)J1^PaJ-mzlV4v-^CdJjGbf^2-7C#`WuThffyRm9 z-avP~Ocq4mRgw_`fllT*otcHcaeA)^OiD$<=x}=ta;2iFDcOE=qbi+59rN-PK0cF{ zx7u5uHy9KEED>Xk-Q)-tg*y}=3CP3h@DcJDG-0Vjy>uVX9bc%bAS>Tu*~iA~NwDhZ z0=@ow?I!F+$w_Q+N%3Hp7kTcC5dP%Jw#9`#A3Ov)hfR1IQY{-REqaX9STZYCbSD&e zjm|OBCE&(0`z+M+F?kZ6{fL?#$x!s7To1)JjXVi6d-u?APLaBPCeaZRx zKuHh`cmma%xjATo7(w`hR0g~}%_)^pY8!E5r41p-PIr&DRl{sRS?KgaGC~8wW5PX0 z&99U+(?T58|E>_{UrhIfOJ?r*cH>$0{>aob1H*3!Jz6*S29<(;?dzq>>onc2_9{7< z{I)Q<-~3%jBA^fT4GnwXg3s{E-v*?8z3<)I9|+_}8hoLxKv%KKMGuBI|E|>;&;={= z(8`o6q{+dP!1RvJ?>2#d)%lp=+k0#2K|6_8y#JquuL3R_#IWm!!P>9Uab?fmjR7Ps zvW)HFq(A9r{+;wDay!u}%z^p<-JY1r>kXBZ5-IU5S}bmB`#LwkPpfx>vUH! zI?}l|D3~|(kMNp_)7SQU1A-fM?xHB}i~ebLXaBT>F7K`Qaqn*zT`k(`$5jEY(WTLy zPd%hD=v3XiZqD?9>1B3-2)>o&$*W7C>T5DB^39yognQ)lBtNq0&EQN1dMZEXqBIU4 zu0*LPTC#Edt6?&-XQ(&*#1hF51K2&6s31ulkPin{I1H!7@s5#nbYfg0i+Lqe;~ zrM&9)0Jo82flS-^oylZ$Kax8_PH_O~n=CxFTEV9+nff+NH(Bi7FfYM8+LeA_)9v|x*0-2# zG|?H=Y=vdCn()S@*#jw~Id=!HG;INQOn2lOUVH|=*?c;-q=%l=y`SdeA2@bf+2b^1 zrOLG-fRC%>YG&}WscN8C*W#>a=!Ws&{OqJ=JmBNv1$oun!;Am1(GQM~OS>W4yUEWJ z;(y|QDjK_2HQ6xili#^c3o2oO$KfV6Ux)*;A>%#U z)TB1{h?@8t+4(NjK*Xkpc-=Fx{5_*s=q677~3)4=V2Lr`3P-CsNyiGYbR^ul&JO6u>u!gq(6BB z>?GYEd(pm`GahljV(!#WM=R=*JQ-ls(tzI`V6nx;5LF?&fax-@{{Apo=!j9G92}20 z!DZQ?v1Ib5YG%O9#F3vaAE!hBjip0eAM#F_tP^1sfSz*$g5<<>|sg zHjO{2qFqbgmk2$J;O5}%L+#6R=Xf^{oG*!J4{_bfJ0-hcL*pjzdnYo$uGl?Jh4j4W za&>odP|BB(q9^+jy zT6E?`6#7rmYjbtJ+~LpjSKBU={&cW`ONIXLIQsm-6FHX5a8vJ#)?7{5CQFs0ox0eUH#|Ze-kZ==n;08VgQAXY zN=s_bZRgqkS~+sO>0~<|m&OL#sGad6j}%mBAk}?=)m^8ir73#HU6U`PzETzK;7BNx z2k&h?zi0J#`-Ja3{QJq`t*^h+c>LXcM^BuXJwn^lLftsw#yq&?wKosNimKNg#}H|C z5VV&n#$-FaPxH=ra6oNS8Z{z~DhhnKC;!evPqb#OH$BBz)Y#nBQr@pi1C`r3%2KrC zYF#Z`C8F!UAK#RL7OYNT>JDPqag#TY+K$zrnuqduUO2_~bkmIzOhQ`81&E1e6+E7j zpap3KiW_?+230%um#oryEOJpzw7ClTGI)oHO)A9LEJvu$O(jK*hj)jo^9trlao*Ay z@5E)PECv49gt#oU(sMEEqY$y;pwbhr{|KqCZDft=%$U5;IB7Ip--9(C80-LHR7bGS z;>^rS1j2^Z+-)i74jD-$A}NAoZS#e5JGJ79c78Vh0z_pobkdamEJ6{b%vFTx8fF`* zaf?F?g1*qcuvZH(^*td8$1#gB^6DB=9U(EAiL!Ous1&4 z-1>!9%rEJ_bv{_S+Ga_`)OJ_swVoNZTxOKAT0i*s(G847(Qde1r$ff`xE8(mKtTW# z-O+Cmgi=HjX25c~q)r7Dy;@zkd}?ye9)9P?U)RR?JidMq35R0NWd&Y}4(m@cD4vU$ zK?rdt_F};?dAZ>-yLb@;K40l?ZvEE!hxq%51mst$E!dzna867Rx7#^jSdf&K@LX1z z#GNQdUudqe3a)qM5RzipxauS}IN?J(N1HUB@SOj{eSJUea%)JkbA`pzD@eQp-*reb zsJwnbIRK5W#4|d^EE6f9x zdDdY2>+c4x+i)FcCgAtN#V7B|J*l|Rlr)1uU0S}xw7Y8gs5fOqE)$=F=Yw`^WHjuA zHm#}Taw+ItGD)s_#G8`Dx(s@%O7ndjcATi3pHDau8`oEQL|J)_=h1s0v%2qzSBWqe zv?D?L%W|KAMX+GszPj>Z?I(;I1ZQm6Q0soc=pUwAmXel%eoA2#+u?@_x;rzsU=D=` zXg)6D%>BcXoNGE~>?e^d>c?(YDYfc+x%SZ(LQg!!_&z;80oFUey<;y}^D&nr9R3Vc zXUPkDK=1237(hXB-VXOr6nxgpJz!N15Ul0RCDMa;0aR|!*I7XU$F|f^LSyc4f%8Vy^D{C6&GdrxsO{8@q+qP zmyacxo)+{MejkJ{5PPGPtrl3e<%c$ay_o=(ByVgLbx?I0xd=@zuKQ=#R4cDchvf!NZ4X|}te7IoUHb=~c^JKh1 zu)F;iZvuLEuJ-;_)qz3mM{eX#3-ZyePkD>@gHkw$*;#elMOxZ9fKMI9EyhxxH26G~ z%RHGAj86j1H8Aa=pf#iSgOSyf-f{KttyJHMv7963O--w9$!**1>P}Fsb9;XDf4seZ zL_0Qdm?7y-ig}ie5+;p-G+5(dC@qy&5O!?wSoGdHxQQd8rm^t_iwi= zzr)34xn60anbkF!pGBkfM@A?WX_!@HdH@gIDb#$uQChd$m8__d_JF?$MhS5p0sYt- zq&+iq1c_-?QPVeBi=?Dvb2@dxJ5W?cdP9!TU9A!AfUwG1>tt+Rv>7AmVwqZdncjwN zSrT;-S$l(&*_0p$VMDx@sQBw6JdFtgJ zcHfq!&JtefY9i(<mZNgx7R6#JzA|Cpqv|3!4D1C%+0*YHi6+29JjFIl27GEz zGbTm{xxd)?NF2x9()?6~Nr8vJYq_jY1~DCzrKu}EIk!`x_71I-Smoag8$iJf&ww~- zJVg{<2MROA@gE#Z(r3C&uRUR*l)&;lDpARyRZwz{nQIiyn7t(fXqyu@dO2r9shp5? zqCkeQ4UP;~A!{WS>IZ9X3ggGq_qu6;zkmZk%kf%dMpz{&+2U1+Nd~3)7UwV+7w6)K zsum#U_;?RAfXiiRhS+v(Dkrx0B&aQnK&*~?wuOFdQ{W`vqR~Wq<(Koyu^w7>=2Pf~ zSqQ`$595=A%LMbn!ye?|cQ?sKv`Lai5Q8$|&i`2iYdHo!5_2Lj+s$pfpV~QIYhe{* z#s$f~wvPkH44uHKD2oPKpT9bly;2d+*7tk{X`A;K+e(W`IjX*T3SuhxTmLt22H&0= zMZ%lM221uDM+oKeMi?!}G$s-LehM%u{;98%<2+Zh*`(VafP+yGQ!=o%`}_ko}z(LNUCuR)}Zo~gC%wNq10;R z6eh~R+@Cv^UUap-kU47X?9Hu42X9R;nx+ zyiFN@Iyl!?ynm7A19G}SP}Ib5@zC7TrzG@a<@_)r3@ySd440!ffr82DRpnN}jsVSS zMxgCfQ**CMAk?YAddrj5rIZp#NY5^k^1276i#b)$f1yT1p~-(gl^@_iHp29@KI!Rp zcddYak8PtjfiIoriqn${g`*>K6~*xU7Yd@QZXiu{gQ?2`4TvyDAi?!D>7=Lzh5ny2~$9=anpVGZm|PMVLyYsOsGEsyyJXNP9JQ-E}# zW22}LF}en6?yKvrz`h&lHh$Ub;E_*dOs9}7Dh@&8v4;~gfx zHGSBI$uRIAPYVQBPmLGMSiUCa*0uZJjjMVum!rJN@<`RK1iOp8q1P|Pz_NUxOgSJB zEh-Q&Ym0H(Ga&t>A1Ve}ty9(wLvN*#2cg%4@>EZ*W6{2m9luMu<>GrrF?}s6pBS|{gs-=(18`cZDR9AT( zCaxx{G04XagDkb`Hho$yUG9Uln}Q3Sq@dG{nq+KbU#p>L zKj}mZt9n#Nry6^9cEx|>!f=BM;N~#K4Jd-xWPNhT+Au~5)-=x&>3iyLfl6W*@z7Dg z05&jy=B3CnW&SJiJZmH|Nxq%|Ow%m9C`HSoZ8tY=S)@y$nPl1--+T&~YX@!??9}H_vWDJLJh`YO ze$OQ|l#v6d=+Q&eC5qqE;$4Goq_Lb}*@jfoB$T3i@Ss)}i5LofCx2(~RO`SuDtTuv z%sf#b5I{Jfz{8y15##?brkchAOkZ*^k6D2oYk~Wkmc4uQd-Rj;;0Nz!c#AEvi6@n} zmzyq6SwJ2&wRTphL$fmnQ#5%54ibjb7LQO^)kR9;psXgG2$*;HBHSaLLY+Zi)ef}9-;XBR0a_eY(*5DTLz=+}}5GKgR zdFIb7S0C3rBLFnK9`E68UQkn8A2KY6k0b}+BIVB5r;H}bDki4?oLgFMdC7T=xO2j^ zkJVavZ)yF0Jr+RWKP@>Fbb$fHmUFx@S6U_ViJvHO#0c+!cFjl?G(^3g)ss?q%@sgs zothX0?P>1B3@!^-S4QE5cb0Ep;mnF_VA9`ye!KZAj<3-5r$&706ES~HlWEb91>L0N zdeN4-otmow4FPWYG1*7@%sE~)b@EBcce?exs7Mp;{{yDIJN9|6r?ig>w0G520X*FM zhZ9Fk2r0m*>4Q>!PPoLT!D-1#6tMMCO za3$7>twnbh2LV_pty8iMU-9J6-e+=fh?3$(#^)u>7=oLBe86&{J8p7IJ)v~}MSFGP zN{12PziY?9lZso5q}kgr7{)AOf>^}4Xj zIgp=PnnDtW5xEIE)GI0#{BKfe&8rQ-|GWX#fXTAld&$*gHSKSCVe{j^nH9_WCM2Iw zyaKrflf%za*Y%78fVc*&*`(#60s7Redcl{;b)X-4?FG_009;p>XvJ^7z(=+B-I5w4 zc%)#A-5W>-c^Q}>MFup))82~WRTDy>xcnm34&L{=0Q1vc)pc6m4uv>PBE4k=p;Uc% zg*rOlvLZ}tY~`80g0S{8brg_bs^kJ$d6?35E=V*=xns!b5J@Zj9T`m-H6g&_8&~|w z(`Tl68uoQpi1s+|7yb=e-<`#pI{m;Hk~CEzKk$OKf#|`eWTB!%sCgD=x@Di7|KYOD z#~WMm>m=s`mKWSpwleNzm_?;%VJ9K(`bNCziL5n#HPf7Amj4cI`|`Pgow-T&zVlt# zI~&$_3cL_@wkV-8$@7Q{kSf3nrYhHKNi!${e77;Aby#^;zeO{`Ha7S5*C~@$`hQhYgCDBJ=?l(Z z6=}unbapE7-=J^B@RM-o(K4^$b{vMAn*wIW)Xqw4JtiAlKn`M$>ei3PiXb3WU(X@& zmHIlQlQFj}5pVzk4QS$7nmgMM3SaW+_J0YAJyGJ5ihfnO{1@-gH4lpJ1GVE+;Ye1T zEuPQHQdXZQU0FP7NvgY@6E!z2VGOu$O3V!PhLK@QCX~>k@Xs{H>CjcMU@bt!ttSGKkbGe~Y zH&8BY!0V7aZiN{DRH+&=jkXCIZ{W<`cFIoMXkigDdGWuQnmfX>O`>3HgU{a1urvqI zkC#-yxsvXp+9wo%;6yBH5@<_A$~g=;De4g^*ePg!^pn*#NkE>ftQF3|32{-9TTi+V-%bgZn@0DAMUh|PY2QnB1>XP5QFHLpEP*N4RABOD;~@b& zExOJf`)>UIbBg_Up!$kpbMjF$*1uacKt)3Ey6qR^K`~Hu~4|d7+mdc{&E6K<1US@}`mL1~2E%-F8Di0Q?A5X&(JJl zR=V-A5*tahjDP^}mH8akveTg6wNz2pfxd3>-4|T_SV;s1jIM=j03A;5mP5hnYWgh@ znPj6u97M?^`$>+kQZG@XT8Ckc&1X9KSn(?#E4r8S z#Jh+E!rs%aZiKT9qTVLve-ID-N{JpcXzwQ+Y0XJEjPgmrdy0!<3;Mgmgg|E!HT<$Q z9aZsyo|%89=ODx?giX?ZI?w!styVW2&d&y+RqMk_l+l2x#{7$phHG8xQ_QkqrE2pY zb9wzdlHNKE-EvbLb~hk|J9~`XOEdLxA@?A{gmUM@bLS2%*itYSF^lx~Z*$g{kmpT( z9}Hry%RGFh$8kz39DJzK8ZBZl?A=(kXJ7+sI{|=O-vZ%0 zpeW2P;)i1O{HF{zOioFkbMYJ%NCjX#wDL4?Q&~!QyjzLiUqbrS3rM#g`E~W_XPB-G zn|##V<1O_OMNQBdq~|WA=dvFj1ud$CI2Qff*LYF7ExNuIFNj%mvHT^529<&a183>< z-!hk=^2cg*$70ODd2wlK%X0Q_HW%XU2bPRI^%mRP{##L{$H%){x{3WV20fl zDt!g)#(xHOWv8@%xc60^n)=UmYPJOwM(i!e+;e6GdV!2UK0>4Qona{1LAK8M@I>3s z4g=3Fl4VTH|F9=H-}M*yH?AUbxh+l(-cfY>Dl}k zlHT~U;c#S*aajArHU!$qxvr3c4}v!Zt=_2?kIRMl!-|^^H)Ebi0U%~0LVgd-Qm;-Y zFl%__{Il5ON@{sg?H7lyiFQG!OUdzzXfRh7jN`wq_G&8y$uuzl%r7dAFfe5`RO2cH!vfQOSElBWlnS6st?DgyRks62Ln3c_0EK316}6U1`r86y zP$^2^NmM(!Pa00~5EE3AUO-o|K-$74ZRT~u+N&} z*8o2;cg((e{J3-D5bF5=p0irao*dDSQLWt!RB|`~+%GEJPE;>)7Mk(*$jYxEpaeyC z%$$ES^@_z={?;N)2BiaoC$*r=YY+rgu8!MK1Kb=VBs4nNI zC77*2;a} z^RQtAtg0J;#=Er~s%Sa}_uzZ=<1Xd~BhBb2V(5=YCv*CQq z#~GE}DN@>?`9+sQH1BQ0Hv{>GZxZ_#)>z_+Km}Y&IGj1Y+PSRVN<|wlz*2r+AJ?+? z2R_9vg6%BXDLuz|9FK+kWS34_wfQq}eMB`EZ{yi&9LA(4rFBXaHPD{6ZQjPDxpXv1We9*GlZ1Kxy zwaLR5_R62V2pzJSmlS}4LLS8;`j}09L*>NJIrz~{A+{?$8jC*2ACr`RwuW1e1ZKge ze#DukXZ0DB$#I&F!FN%_452rsjA4A=pt&O(oXAaLsf40h@r~xq63Yk`tl5fC?;Ppd z-_$(p(U~ctG15YM`fS)?B>_{`J9VS>H=_>SbJA5D`To?P@9EaVdMlqf(~A2uIM;Q;LtwmcG5hbnIZqFszzwR`o7c$OiBI z-zoH3QRsH-*U(bzIDSiSzxfG~=&z|xbo;TK*TWP`wgG1j z4wiHyW=sUnc*<8Ad~ArRH@=;Hd^368STXHyU+-DAAsIiF+AI4Fw=aV>V{Kj%xjwk8 zVV2L}n87%HC_mf$s$6{>YkU-d*(H_hH~wYZwbSg0wc&3s_R?RD?(NO#^>)E1x(;M* z6f%J>6D-&&o;X(J%pE8W{W*8Q_jnBBnKqQ|58r@#aj544as51@0=pY%u*$t{rF#bg z(^AM13_kp8`^$R1Gv%HB7`wfL1q#WNFWT6F)}0}37LoeZm{;W zr+xZ+hVx$U?|HfSi@ny~D12f{*$BO&^gtL3FtL*%s^z$tZqC%}I8_$lTj19>^)y`f~Kit^{ zD=BYl&h3{*4d!Oo_>@fbSy29nZX5f^GWZ5b0teO*knv|bAY1zDLH1t|;qX9*zFJnF zr()o93HzJh+Z!kSS=|%{y(e>Tfnl~5ol7m;yA=yQ3Zo$+O-gk{RpdFoy&~wpmg+Dna5Z=%_?XZG2%bJfm z?Wh6a#uFvp1H_V<$=d$G6AU&;O}*j0*>AG_%-`|ecuD}X^{uUtz+ukX3dP93wH4e* z|6q}gGzW+=TOdzhPDA9N+j~f6YJ38TojSVN?GesI8*qk+pH46#j$`eY%HM+A7RA0) zB1n3hrJ3Q-DUPQ9xkR13RuF(7{f;Le@OJu`Tv>7`YmK_RAOmW+i@ydf`5g@|n3}!F zX>92hr|C$vGe+wv{NfFe{wq%YCm@}|J^=m`{u#OxOXN4_X*#G~L#N=%f(I_^hQRYAu9 zergUVs0eB4ntc(v>AJfrj3SbxhoDi(;1ohen0LIgwl}u{5b9mS}$<12UYU zfo9UFA4KYt&(ZD4?_-#n*|pLd(pOnbz*9F<_@Gy}xi9duq7`%Dz2Othff)ITVh_WI zWy7Vp)HKj1kXPnf&GG7oz+ISX8d?>3n6ESx;@HUpf*rF7 z31fnU`(XC&3%UnFLt8UTUgka7m=UIAcWZY{7>o2Z!yAqZXImU&;yvDw0e+1U1KEl^ z`h!CJz%ud=nLeQJ;nas0J|E=hm3}QPZ;y7Q@v`Tvi3)KA{BMH&zF%2)*(lLV%rQ>F zPfa4V9>D7z^06?1i5^_MZ|a=j;~=%b*h@}$e0_BCEB1lZrCs`}WE-sb=*>2C3zQX? z@Jd^DZwFpMcukt2<_GSVOR^u^WLaF#j}fb7!WtK_BIOqRwFIQi2k2J6kK`q36SI*# z80ep9bbFiUcTC>T9iC{zcwcu&;cQ4g2cqo%6NjOyK+d-#fS~-GyD=cX{pQ?(EWEr~ z`s`QdWV)|pmQ#?&pbnw3DpHQSaKKfmG%P&@kU8SazLd{co-v+$h1OrhJOw@ocnq=M z&nSez%HL1i*Z)(=ETaC&GU11R!rQ6A>;EFC$9b`86%pZf;+^vUGH3oj@frRWZ~qOt zPnp1@tNpuct1Q@5_4JGPFbsp59PK32ccKhel}X?nbQ?K&I+v`?Wu3?i*_+D>e1Tid z)ydDtYVYuO$wV-Xs3qQ;x#mRj>GDH?L`7UI$~eViI77sBGgXE+j)S0eHvf0;W#RAB ztexa1?a#p-`)gtc-+=EF0f-L#eOIb3L`p3Io{;1s5MHmN-Vg^?PrsqpTO?rqZx3Z^ z-Ky=#O3R+WKE0fY4@wV9d5*WOx&p>RU#hrzGgxdLa-O~pA(MFj9W89Ef8*;_=B}OGHmK`f8&G%4xt5= zYZT=Vsw!xteQjtK%Bka2%&XTMA)FkwEY%R-Sda{r7T^MyHsED8|I-KolE6LuUJdic zLJ4^e0?ie&423u)Ac8I@QrTeaZU8FHKgv@jm>3p5LB4x6;)o4wPcN)%CKS5bJpSc% zp_!^rl!+5eMq|0#X-U zt7go*@$CFI!NM8ryVt*;988@<3_1zTaqPZpsvQ%Vg8i>|H zr4Az=J*HGgiGz?f898M8z|p>-J)SM#JbqC)%pO$O1tZ8b;V4*C@zFwa&_S2KK01=xNX@$5RLlE+08;rfyt--hP-VbPq{9G+pCrf zM$5l3yhGI7%cd}`?17ulR<(2_r zpN9cy)^?zA*1`ong9@K3=c*N5?g@RVOnz=>RYTg94(NSRF%mNzmAl?FZn7XjS#FtF zipnRX&-LmJAT#Sny}g#pxMq^mZR_N~MQ?(NOWE2}aRQ(LGRRwG4panEqXOc&zr zfcu+a5N6Ggoc?|qg~TSfR@TrizP%J(Wl`Y1C6++e%#c11qyq*XtBR^YDsqkcJ6+j; zq~(dL(J5c>sot73Odv{WfShcM_1$Z(k7kK^?xfqV1coZIN`3xT3T(IdIL6O)$3XQd zaH)IIa_h@~ZQeHUmLAer;DKqb&H^-$(*f|eOUTy5$ub6no3FxjYOwlpN;nlZ871ptk44%s>+vVV@$@A! zYN8&*Sd|ERQA-mVp4p&)yh6%skuo&_0G_kd=IMzcSfeR<+LWcv1!ic0#$~J)n#qjc z4`eM07;ng4C27}<-I8oOWiQTeczVLWOFy0|r1(M{I5wKm;)yEaz=_kbug+O92N2n! z$c?~(fW@phV^`AhXhBou-Kxfc-&5J$}M;E~{ZNYRMpUxCwKx(0X!M+Tgb_$vwFX>ok`qXha-uZLwmrk>Q^<~LKD=~MIq4rSFtFG3<=PEN0fkuT zw>4Rnu&%Ut#pXE0ov-`23Qig?aug;kM9-!Fb3TFyQL?2cK29-o0AaXWB1cKsU;EL2 zR}qkSA`+|!2rVb}vG0>5Fku!U#KGY=3nR-ZrMHmCw}zUNCVJq`E$pJm-<?*Z~K8 z!j{OGsw{lp-M^?VU-Rq1Kb0YXG(*+!=rebHOU-@>RVIG#k7WoTCQ(KNE)VbqjG-jf z6-J3ntZ5-@pg3KrR%v;LroKQ^4-o*dz)<@1`uB-a6*U=|9QJ#i$_hf- z_^=su5elqM=aSKsp2Ue7zicNOJ97Z`Pn`eeU)G5Kt{&hGYVg)^7%r|>a-nmef_qK; zzZ9>}78@j>9OjA*;+!(0Wn-ClF%a=`*Q#ja+tT-#UrXPKl{PNuzqCT$)Ycoue>?lX z)YkVfL1U!GO5J=1>4Gr-6 zjJDPEr*3E?ON$0VXG9hHb=$k4YG*F8`)~ z>16sm?dRLfnIG^` z6iY26Yge3k&*01=z59YZC>fvcz{S}bGcfWn8vr>EkYS81$!+kViCvBM8EqI8GHd|z z;cMDiFanC?5SCOJk*9xKFkb1fPGV5)%(FrGCG z)s#aziU>9~FDKwYF471-C(+1w)x%h*xZ(69H97gQmJQ`LuvjF4>pZ|H0CefBb6C|; z^3G|Lu?eXeN+zq5DaPG~89S2-%jwxn4Nz16(Wkki^B$R9>l4Dd_8MX;OKW7&vix$R zW$`aL1RGAR{-Udl{s5trRmeePzm4!#*he4o;QE&k>ba0_Rk%@!HRf|T8bk}$$*I5U z@BXi1{;B+NxjA6Lc(wTRd+fi;OARyr9g-hhYV3npiH1`jTq3yxle5Paxx2I`5)A)cksAOwQ7Y53n&C> ztZ8%OvlNUz(=dcG*<_e~&N0;n7N9~JpC-kdgY&j2+9EMz-D}GvvXKL5&aq_c{G}({ z&tjMr@gDY!(pJBA_km2jP&_pCwPL(#D6X|4KCva-UViX&x@xRX16FaeREbh>r1GUb zVF>eT0fMY&X$44$t0XgCp&?bycF|@9ii@w4msK`|RZm`?J==?ku3X7Qp(7R}SV_1m zuUXYUTuMT~2nY-rp*mMS{RQq|JQlB=1tk*nlVpQ;HsAx^I%7Lrmw?|>V=Yw1IvuEA zvTXrr7^hE#0K3n$G!XWhi@q|ve8pfHL{P15QkD7l$+9IgQ(-b=OF7?{1j@(~w39peDzrlN3sM15f~EVrtOL zsxD6&D||R#85h`pdr%#gL${l98*MTr-*L&detTieL11Adpc^>MWAGb|0Y>$ zieurYPM6OKXXR|TJ~ZfLY(BTNruf9`Ir)86erOoJDW0C5E<9qCEekLkRlILTlcH_> zyCZaplu)KNkxxBeKv@DGlRs}ih!M|p!ijGvgFv(s7<+;Zn&Seb)@u^ulj#}f%{V35 zU2iFZ+q_+PkMiu%p*CM*mJeMHPK!IZVX~A+GGG!NM7l;DR=`2`F`<~@0FK{;JObT= z&F*TBw+G*F@E1W*;_HN_;YjTDs$seeE4DYpF$$)fIH3tb30KGx6iu1~+WtzV!k^0A z_nKqWG2#Lf0>ObVc2UoPKR0U3rQUm9W9%j%pZ(Y(p!rRihS#KT$1pG8*#s+_Vsn*6 zb+agd4R>*(Vk4au1D1p_DSF^BJ9LzTe@@LVFn(c<#Wa>QmUQd2U|qE9EardBuZ?&p z_IVKrjRB={EBLw93`_9G+J%irX;8&vFQ>PQ9)%v*MD1z?ZV_V>{@IcP06GMq<7;*x zXLh8UgTifM+k75jPJDQfK-- zSytUR`$HwPU_?&{oE~43tNgqMF21xu?9Gx5-6}*(O@(RoTBIKRvno}!rcbp}T$O}a z51+hP)j_Y`@>ziyT$cgfLXl*>E^E4CUkw(C2K5bJIKr+N63=Xair2W{FdaY(4M0nh z8BC+GyM{cIE2z@(04+w6JZ!0$-5rB0RRKl;aEJDUHCjDxXR<8fsXzlK3#EH|Q>LDT zLS7kfpJn>KrhKUHHOXc4-Bj$2jGq)lwf^u(QDti!nHcR1G=~Nb=oO;(;E_?i!oi$O z-NDV~%{>4-aHXe!9#&I56tu{FgcU|Dv3Iwu=3{c;V<=8O3nAQ8ylk@uX3aDxtA&I9JAT zBk(gxOHL)9en`{i)3ieZeI{96O4tT1Hh-BfP9X!l9}LTqjPEW;Ef)0I>I33Ch>}yz z)qar!A(DFttV>HDxEe;t!9MP!rjt+2$T?3a0T1*SHBe2i;mn-U6pag( z^`)0u473r*gtMBiBUo(yDC9hdw!a>f`E{@?UwgNGTU(_OOT0I-woXlbSqd&;FlxER z-5+$W2@Cr3eM4hi1&015W9Vcm_3m}@Y9`S(C%FaZHMiI1tp+C#bl?tdz82^iw;ShplRJ%O#;3?wy;l;J2^R$*=LLV40w@K>-t>x^ zSMuix+YPd>FnZQ(;l?lqd+KJQM>sXm*aOzEC$b$o`dg7;3A>x!KNI%9mX-gvC+yU! zH{d=uF+c>q%jdl@a7o&fK$k$4^kcyJq8MlLE^rem$1>GDG(%51Gy)S`Ioz-s0F-R2 zk+PC^YpWi7lze#q#>G!RTJr9P;Z_-E*8jL5@74!a+pL~^_28SO$=oGb86VAC>9aF+ z`-k7y<^`WT`o+0dKRx^E+?`cmqX*zDLffZ1aXc|Woea-5W5@C0c~xK$SB?`_S}b1tq_2Ur>(GY!W#|PJ^UV*6rk3Pg*A{A1Bwu$U9dfa+H-Z zdOz${L06Vtr3p&O^*R7H=W%hOeF$l#SK9{_gXvYqHN-+TLwJ3$rsGm=wHpG%cHBH`4h3}%3 z$4^-WccKwt+|{Hp7%w=xRdQ0EdY4ufDRf*M+Dk#eCfdx~^C%07D9)E!jt53fC~s-T zegTj3g5K*agC<6GWCqW3(fAu9%%Ufy*BU zayL3q;+pb%&y8hXA@S=2(jC9)WzID1!!du{U1Jqo-2HqLs{cP8K-l)`v z`KV=%kcqBwtUK(KBrp0Uk6jvKxgf65iCq6GuJHq&YXi~wmYL#Kqd{v9o5ck;gJB zJRh|^3?eUl^>tQv1>{w`2ZZ{$d9eSnd0*Z@TGdG`2(;*1YexM%T2p&_qPQh4jjxBU zxtfxWtq3~SU(#w6W(C>z8r!4GtQsH0C_l$qwN_iuOJBer754?UYPeCN6#>|muIv&{ z7JWFZn%ivSgw(jluo>5d+85Df{vw#JRkM{@A67KwD8C{I5)#AWip~BlUD&%@dX3pj zHRlpa1sQ}6FIO)!g!+}8i=%s=U$@qWPhFBfQ=Zie;w$2}fvx&Q+jcTW<>QXjB8 zx~?uLEuzR*Q)(Hcs47vf`y!tBx?av| zMf+)52{w-MIP)xq0cIN2fTZcJw7lQ8qGIoKra(V-fvV3>I0}Au5(bxIwn%&GUe<4K zFteO)7GT~TS$jBSWbxkKWnZA%Gi2)Sv80{?$Bp<#A3JFCIoKu#Xfmx#`oTSyaN*U0 zVD~uUN%=OL`qZQ-?l-?RKtAePpZ1s?QhmpHMEbC8LELKB#m&AusMVjDjWw26TNxV< zW^Q@8HCK9(`%^=Mi`mGLzSW;$mqp9&xZSWFmPM&;{lbU#OlH+@IJCnC((Cq9a%9l0 zEa%Rq6xrdlOD!#f=_gAs*cRa}=)ueWasa=L(6h4`|1{H7_D!ZEEaBVV21ssm=CwjI zqREiYH>6@6QLh8qxCjcyq=n20R{=Ns}^k&t2#Ws z_G8xwKKDw&9^z*5Xh&{Zdb5uc_~|%tGQ?PTu4Z%Lh4tb1kuN@EKueFlIedjCUv2Jm z{-90O^3rQ`(!|SycIeCMU}JMG${KPl_XIo0zx6w+V6|J07TaTo%ykIA7Paz1FXhlf z*|<-G$7mBL?o!H{9UIaElKIVOWOPWu|Lo$FJogNiZ2Zb(j;u8#{6+Z<$H%hnxQ(2t?gP4FabDMthweb8utX+`rUv=HC zj{XYYcPqH(@HL7p`_wr!_2GyQ+|GlE2xkB2B8mNw_GnAL~%4cmLgF=`4LcDFv3 zD=9B5-IbZ)9wRDh33z$zl0Pr%JD|x1IEg|TnIewYblC7+XyW)xEx0!}xC1x`h7!#` zvsax3aQ$#pn}n%{StX@%>KXCcCkvdfY{;ekh%lS5C<*Lp#4@uE8S3tSH=*P!sd3jj zP&;v`l_lKkH{wgR7d#(!ib?}~#twKRKd5m((0a)4=tS3qox}5Q8N3*;n`oF}=Ztc{ zV_5iwd~^Y={3Fl)z+UI$ful1k+IxMT7nZKO7g$6Z`u5A{gmB)~|K!PI9Jd6%lI?Sq zq@@RHu+~$PbQVe5!y(0pP0xnvKh^uxnB3aVT-8We#WUv3J4AXvDSd%D;#0H-$?wc} z%L&sKt{0)Byc>wdM(ay$8(rYitNdH(;e4M}6XpA=JDM+yO`N;r-*Lo{Y~VN!K1`z8 zre7OL4@>y^1U1d_IlL$~T=fU4&iZ_e$qN`{LG`#7F2e|Jy;kH z_6g%3>WuGet$#5)xSY0+z+IK?7TujzxDFjDI+LeeCvd(HT408O5qB%AyVi4vCq2em z4!9MPHD_-{(ANnPzqnt7AdXJ2so<3HM{cHz8i^GblMQ6!y$6-yO0C$ZT|ZHaUQWBL zJ6YhBt?5o{r4*F!^1<(BhJDy|0K$w?Uz)=HcI3zNN0`uHn(S(BD@HMFEiJV)HVP+6 z0^NY>9;IgLczNzthsH%F8)9GIP98(r)b;8-Ew7|DEFPABC|>r;eg)IECoyp7e6eMq zz&_c#m>(R9)ZVw&!J6A)H*p4q94kxc^`k^o|Ps zLwJ>IEPH&(zg%Vri&4&pxrHuLel7{kBMR5EEcIn9RcWMn$f|xRzw~LtLY06F%rv8! zQC{(DrAuSxZDSw};Fj_2cl$#| zPYeRI!t~6T(6lfo9FOLY76gj+?kos5=8?J%ISES+hB}cxROTUdlCcM9-HH;F+(S_k zF_x~ryk6n)(8JIJt}gSyC^ugm!HURyAi9)W#0`h@8BMw21AAZPv1*M-9XW=P+D{g* z_@Jn)7xy@^q!`w8yeL%uZZ>0jjlNpK&E&^DP2jkzzNV8D1;W0i($m|aCf~hpK2HK_ zx3Og5PsXuMURidyZDS9N$+mg!s4qw2!*MjhfDY|L=%r0)G zi_&t4--GAZDR$v^mmlyTDQ_tAl;3){(U}ziqA6JTW9?B2t?!^UtS5-?OXufX_LP=6 zzaZEqcv}`RyGQL92Rzu{0=`b7ecrOtG7aUKwuEyzoMoLB^)r3ab#aWX%9kIkcn z_WOzUwQHIhP8=hvL+jFBekqC+ za)_JXoBXn;WO_A~z35qFw1Pu6;t}r`ji<#3KfUwt;PX=AkZ(&|E8OcbFCxvNgwEf9*pav^EM0bi zmob**!VhyrrKW0;g}?&SI^EBgWd!=<_7{>}9gN%@rj8 zjH+C4o-EF)vp$u!C8%7ke*O!n8|d=Av@Mow%=@iw3f~2msc^@jX~fU2rmb#5i#DII z{Q{!qZ&X{q&1ON??D6R^dU_dA%>SHow(?K5|V4ty@& z<8q^He#Cpna&!l_Bd{89V`%r}{wHIRcd7X1l=|s4=J9}#wK4(r#aPBmcKokh%#~^uUx}pk z=pJqs>>u8Z6z}WZs{VnMAgNL9Cy!t~q2`A9XV&+el8^yiE=2#z6s1m{+`jHk*O-%e z%o)Llw-zH^M$q>9^iLe+1*x1{h+1IJ39Rsnd&J%n%CTo!>D8u^q*Be+?8n| zpVAzK06o1nz0p%m+rtKe4Z(eOcdWWc{Zh8r%4amYEih8sdd)@iET-JeuE_0j14g0i z%tb_hLGH#L*SZj!{7t&8CG&~X=ODyqt_%B)1iy4iUe>bf42Jc}a(>^Zjf9Q;m+!#t zRDT9diyijcnBd*(Uvbenjb8s1Om!L^55Zb6vM zBq5cM-AtS5e_6W+-xOf-;`Qt&Qp1?9hR+v&9kbAu5EWIY{$!EELiHDm&tVQ9^+?Kp z&fZ$022kKU^hiOGey=uxi$lSHL(E9L|CP@KgR8tKjN}sJ*wI&TTom_e2d2ff7!j6! z^gsdGBG{~WDKg=hw{!QzgEjRdVN7YsguLM~zL8MAt7B9&IECv(mUbR4s6DazN&^EY zEtE}_WZifeifix8sxck{I(^Q0pg;U%J0+c zpt{`kB7W|}G>Yf4GW^-)r58eda_kRzLcaF)`#PYD`<)O=?mT_E+CTJx==kR}|I)V- zridmT;mVu>!+D=t@XQB0xTd1f2S%y1whZsrR)5nDmI!X3qdW0N3ss4IhGlDseC@3o zf3}VmJ#wmO?Zd~4r{JUvArP*tqRAzRRRZTENrFIkZ+2T-N}bSflDE~NXQ_$hDDD&T z>m85`+~ZTV77IqVoi|;Mw5U@#^;|yXR-X4tWVtaJ)^vnGZ0M?XCn-^)h%Z5PQ~XBV z#BFs53va)7B0V5sGK#W!jV-U#ic2Q$hn4$v*=nhJg`BVEH7C%_iXZxh>Y@h9`v;!FVXnKmx_rAGN+6%8m`A50@4}Itdk&&NYudFEx zYp!k{x4Xm0z33a}`E|`(2~_;K{0mSV4P<|DqR8G+5vo{0Ihx-aR&}qnAd9p%KH>h2 z(z3eFf-aQ*#k&!7QN||vf9B+2@-#>2N1Ds9qkZihP0|X0%h41q8;I!*mp1_woWzKi zlwT5k{Y}b8nR2S66|!`ia;(N^yK9W3+^4#Ojt82FI8zgo}$R@Fug_fkR%S0P!fL@r} zi(@73joJI$p^a*k{v*DLwOdpEPR)7NUT$2flBvet%}V@&_& zwOTVB3m!8O`RKXo#;UgbISmxo8d2Kh1nIr3iCW1B4rMnIyzW%Kkw1o$b4Ru#%#0G@ zFOpt;T}4GYJq?_vRRl1jcQ>Z@B#QC0OmZ>lmx_-xE#mo4Qq|xHiCT375@8r~WyL*9 z`l|2TqGRPdt|SkOy_YX$A@aB>^UQv%*yHAFmxo^;O;uUJHa>!W+U05w$`db5F|$~h&}ON>oUJmc7(Q&c|_UPGi;!}=`zq`RQ;?ZhG0=ykucd;Z^6wkYSHDQesh&0IGPYG-Aiz&}Q~ zg12fgs_~rvJEwjcx%P?aN>fwwg>IGUOCAMcc?(>GQ!}S*TJuF)N?*SeKaMJy22k7v zFSv6<=}pEYs<;40SAKe@%Z0ojIhk?ApL;*1%en!gzyblHS}ljRx}VhVa-??+%CD$b z`2a-2HsPy&5yillSczyIZbnTh!Uz!p_`nhADptcnARYfwn1ea5A5h3+kjU5aY*n?e zPqHAZPFeZF*`zllyOL?^LYR?ApHE%HbWE?flbyZjHUW ztakdZ?nLgrwB9UM-@d26alLC0_w3~EV*CH9lu1@#^ah$Pk|mr=QG(cv93z*3$o)^7!}5oOe(#T(Ohz9|M8AvkWU#3(aJ&MkJgkel+tFSu>h< zDCS}P?g8u&Z}x4fr;xfZP(+@|fl#yMS;AwlAC=MbmYS&QX73W?o*3=R)2e;~a@;zp zPddT4V`^=B&h#jyWnRPfccP9w`C)z;ns#9%;mHN%jXVbsXift|t_&5)42p0(^6AVGfE#3WsfS?=$qYNl=YQ~B;!~vM%Ni1u6ZA#+s0@{kL2>QrF zSW{3zo8pfAdrs4U`LTQ$+bCQKzy%t%##K)PKWqCYE?S^R7M)4>5%=EoLlZOO)T!mm zt$^A+q&DS~uNs~?Z9p(;_aRaF74;sx*rNgf^`pdMh&F(`*vo znYX&}Flo0obVT%UZ6s`JYiObNHN2QRuAjObs}14#2Yq}_vu3>DGNa*Q-ROhKyoVDx zlJY~j@)D1s@!SA>YSMdS*k9o%)GUH#Y(0&?yM84D_OEd@v4*;2xoPH+g1|?$am8=Xy-qn*7t5#_2D@) zpz)L#KXTdQ7u2$vjnnV0qM4dnqaV7hUO6a(>{K|7Ay<81zhha9%}B@!c-!UQWX4R( z9u{~f4xf0KinatcdlY{z%JK=^e4ca4YaHFH$X|y_b)M;ZMhLPW7`?P*>~Zd6A1KrU zyk|2>^{p#}zc`^ncf%&W$R5##i3-{{i9g3gn5tGt&TpEQQ@=fFQ+=*^$pFEpy^{Xn z;2Q38m%wm+d%0#TGgrk_)vUlwwpc#%(6&%nUpSaV*%>C#tPFAGWbybwf`m#IeICS* zd)1h_(QKN1UH;_p|83zD=8-0{oKYhRmt*zNxF*l*zo7l6?pK+dGK)I*4mn;83hGRf zei#B7uexQ^$L+f~Hkx#@*pVo@KN;)HZ6a^Brbr)mMQqn~-|Ki-dN@!hb=QpXS)a}7jiDc1 znTrC<`H$PK6?`|GAZsfn?+XO=#`6zw#HE!Ek3%vyQ1)D^SR?DoKKB9I^zCIFR&8*3qgDmU#!Kfk+r@FGq zS;ARgJy3BU-6j|~#K)lhrcTX!@Tftfd;%p&Q^p6AA=!|=9ZzWQN{~DK2+_mD_t{MKY6~W7SZyrX?3$J+#sZq3hwWAD;^-donox*2$loDY%dH;1h~U zGE8DP`%+-~?#EQWnq!;iSD!b6qar3?qcY(f#xa>Ova z)U3>RIm0)q+gcFmj7z8KpekSPcVJLqrE58q@0hKC|Aj1I5%uyQH`o5t9Wz7btXR@? zre2M%rRw?}WA=+r%{$d;kCv6^Pd{w1$uv$UBflnt-<;f82e)H59f<%^&(5Z8E6C5f zk#0}Xe(LsjSwmmt>ytU;cR}5D0AurJl1|?L|4vZxFDc07)tL0LYgMef&z59yCN$!j z^swTJ6P4h->)vdH5&v{);6`^q!$GQ&6Z0ZhdkE$O3)IJUtTeRMIGBJxdv|&7EdJ{7 G+5ZRj$K?M2 literal 0 HcmV?d00001 diff --git a/packages/app/server/claude-proxy.ts b/packages/app/server/claude-proxy.ts new file mode 100644 index 00000000..a609648c --- /dev/null +++ b/packages/app/server/claude-proxy.ts @@ -0,0 +1,139 @@ +import { spawn } from 'child_process' +import { createServer } from 'http' +import { resolve } from 'path' + +const PORT = 3141 +const CLAUDE_BIN = resolve(process.env.HOME ?? '', '.local/bin/claude') + +const server = createServer((req, res) => { + if (req.method === 'OPTIONS') { + res.writeHead(204, { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type', + }) + res.end() + return + } + + if (req.method !== 'POST' || req.url !== '/v1/messages') { + res.writeHead(404, { 'Content-Type': 'application/json' }) + res.end(JSON.stringify({ error: 'Not found' })) + return + } + + let body = '' + req.on('data', (chunk) => { body += chunk }) + req.on('end', () => { + try { + const { model, messages, system } = JSON.parse(body) + + const modelFlag = model?.includes('opus') ? 'opus' + : model?.includes('haiku') ? 'haiku' + : 'sonnet' + + const history = (messages ?? []) as { role: string; content: string }[] + const userMessages = history.filter((m) => m.role === 'user') + const lastUserMsg = userMessages[userMessages.length - 1]?.content ?? '' + + const contextParts: string[] = [] + if (system) contextParts.push(system) + const prior = history.slice(0, -1) + if (prior.length > 0) { + contextParts.push( + 'Conversation so far:\n' + + prior.map((m) => `${m.role}: ${m.content}`).join('\n') + ) + } + + const systemPrompt = contextParts.length > 0 ? contextParts.join('\n\n') : undefined + + const args = ['-p', '--model', modelFlag] + if (systemPrompt) args.push('--system-prompt', systemPrompt) + args.push('--', lastUserMsg) + + console.log(`[proxy] → claude -p --model ${modelFlag} "${lastUserMsg.slice(0, 60)}..."`) + + const proc = spawn(CLAUDE_BIN, args, { + stdio: ['pipe', 'pipe', 'pipe'], + env: { ...process.env, NO_COLOR: '1', TERM: 'dumb' }, + detached: false, + }) + + proc.stdin.end('') + + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Access-Control-Allow-Origin': '*', + 'X-Accel-Buffering': 'no', + }) + + let fullOutput = '' + let clientDisconnected = false + + proc.stdout.on('data', (chunk: Buffer) => { + const text = chunk.toString() + fullOutput += text + console.log(`[proxy] stdout +${text.length}b total=${fullOutput.length}b`) + + if (!clientDisconnected) { + const sseData = { + type: 'content_block_delta', + delta: { type: 'text_delta', text }, + } + res.write(`data: ${JSON.stringify(sseData)}\n\n`) + } + }) + + proc.stderr.on('data', (chunk: Buffer) => { + const msg = chunk.toString().trim() + if (msg) console.error('[proxy] stderr:', msg) + }) + + proc.on('error', (err) => { + console.error('[proxy] spawn error:', err) + if (!clientDisconnected) { + const errData = { + type: 'error', + error: { message: `Spawn error: ${err.message}` }, + } + res.write(`data: ${JSON.stringify(errData)}\n\n`) + res.write('data: [DONE]\n\n') + res.end() + } + }) + + proc.on('close', (code, signal) => { + console.log(`[proxy] ← exit code=${code} signal=${signal} output=${fullOutput.length}b`) + if (!clientDisconnected) { + res.write('data: [DONE]\n\n') + res.end() + } + }) + + res.on('close', () => { + clientDisconnected = true + if (proc.exitCode === null && !proc.killed) { + console.log('[proxy] Client disconnected, killing process') + proc.kill('SIGTERM') + } + }) + + } catch (err) { + console.error('[proxy] Parse error:', err) + res.writeHead(400, { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }) + res.end(JSON.stringify({ error: String(err) })) + } + }) +}) + +server.listen(PORT, () => { + console.log(`\n Claude proxy → http://localhost:${PORT}`) + console.log(` Binary: ${CLAUDE_BIN}`) + console.log(` Using your Max subscription\n`) +}) diff --git a/packages/app/src/App.vue b/packages/app/src/App.vue index f266357c..acf20cfc 100644 --- a/packages/app/src/App.vue +++ b/packages/app/src/App.vue @@ -1,9 +1,17 @@ diff --git a/packages/app/src/components/chat/ChatHeader.vue b/packages/app/src/components/chat/ChatHeader.vue index a0cee5b8..40ade87b 100644 --- a/packages/app/src/components/chat/ChatHeader.vue +++ b/packages/app/src/components/chat/ChatHeader.vue @@ -1,15 +1,22 @@