From d0f3209dff29002e6dd6fa1cc47b5769d5c75106 Mon Sep 17 00:00:00 2001 From: Nate Sesti <33237525+sestinj@users.noreply.github.com> Date: Sun, 28 Jul 2024 23:16:18 -0700 Subject: [PATCH] Preview (#1750) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * update package.json version * handlebars import * cmd+I improvements (#1728) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> * Dev (#1740) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> * update jetbrains build * jetbrains build update * Dev (#1780) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> * fix tests (#1781) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> * Dev (#1784) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version --------- Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Nate Sesti Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> * test: skip failing tests * Dev (#1807) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback * Improved walkDir performance (#1814) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version * feat: add Llama 3.1 8B to cloudflare provider options (#1811) Co-authored-by: jdelorey@cloudflare.com * increase gemini pro contextLength (#1809) * fix indentation (#1808) * Llama 3.1 405b model selection (#1813) * add support for llama3 405b * 3.1 * name mapping * updates to model setup * fix walkDir tests on windows --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com * config loading (#1820) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version * feat: add Llama 3.1 8B to cloudflare provider options (#1811) Co-authored-by: jdelorey@cloudflare.com * increase gemini pro contextLength (#1809) * fix indentation (#1808) * Llama 3.1 405b model selection (#1813) * add support for llama3 405b * 3.1 * name mapping * updates to model setup * fix walkDir tests on windows * chore: add docs as top level config (#1816) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider (#1818) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider * docs schema * Nate/dev (#1819) * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * jetbrains login * fix jetbrains login * change beta wording * proxy context provider * fix proxy context provider * revert to prod id, url * update package.json version --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com * Improved indexing performance (#1845) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version * feat: add Llama 3.1 8B to cloudflare provider options (#1811) Co-authored-by: jdelorey@cloudflare.com * increase gemini pro contextLength (#1809) * fix indentation (#1808) * Llama 3.1 405b model selection (#1813) * add support for llama3 405b * 3.1 * name mapping * updates to model setup * fix walkDir tests on windows * chore: add docs as top level config (#1816) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider (#1818) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider * docs schema * Nate/dev (#1819) * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * jetbrains login * fix jetbrains login * change beta wording * proxy context provider * fix proxy context provider * revert to prod id, url * update package.json version * Add CodeGeeX4 code completion support (#1815) Includes support for context through code snippets and relative filename resolution. * manually stop at stop tokens for all providers * chore: bump tree-sitter (#1828) * Add Missing Tokens for CodeGeeX4 AutoComplete (#1827) Previous attempts at using the normal pipe char with CodeGeeX FIM tokens resulted in empty completion output. However, this was due to <|user|> and <|assistant|> tokens being necessary for completion. The earlier working change ommitted these tokens, and its functionality using deepseek pipes was merely coincidental. This change now properly follows the CodeGeeX infill guides and should match what the model expects. In addition to <|user|> and <|assistant|>, the <|endoftext|> token was added as a stop token. * additional analytics providers * fix import error in jetbrains plugin * explicitly include default context providers * Remove a copy / pasta section that duplicated the work done in ChunkCodebaseIndexer (#1834) This cuts the amount of time spent in this section of indexing in half Co-authored-by: Rob Leidle * respect VS Code isTelemetryEnabled * Update OllamaEmbeddingsProvider.ts (#1839) * feat: include recently + open files in codebase search (#1833) * feat: include recently + open files in codebase search * cleanup * Update BaseRetrievalPipeline.ts * add params object to chunkDocument * Update package-lock.json * Offload all token counting to worker processes as well as some optimizations to do more token counting in parallel Adding the workerpool logic broke gui as vite does not support __dirname or path.join(...). To work around this, moved the gui dependency of stripImages out of countTokens.ts * Create CODE_OF_CONDUCT.md (#1843) * tweaks to new tokenizing * temporarily skip code chunking tests due to worker files not being present * update changelog * update version --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com Co-authored-by: ekatiyar * proxy updates (#1861) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version * feat: add Llama 3.1 8B to cloudflare provider options (#1811) Co-authored-by: jdelorey@cloudflare.com * increase gemini pro contextLength (#1809) * fix indentation (#1808) * Llama 3.1 405b model selection (#1813) * add support for llama3 405b * 3.1 * name mapping * updates to model setup * fix walkDir tests on windows * chore: add docs as top level config (#1816) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider (#1818) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider * docs schema * Nate/dev (#1819) * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * jetbrains login * fix jetbrains login * change beta wording * proxy context provider * fix proxy context provider * revert to prod id, url * update package.json version * Add CodeGeeX4 code completion support (#1815) Includes support for context through code snippets and relative filename resolution. * manually stop at stop tokens for all providers * chore: bump tree-sitter (#1828) * Add Missing Tokens for CodeGeeX4 AutoComplete (#1827) Previous attempts at using the normal pipe char with CodeGeeX FIM tokens resulted in empty completion output. However, this was due to <|user|> and <|assistant|> tokens being necessary for completion. The earlier working change ommitted these tokens, and its functionality using deepseek pipes was merely coincidental. This change now properly follows the CodeGeeX infill guides and should match what the model expects. In addition to <|user|> and <|assistant|>, the <|endoftext|> token was added as a stop token. * additional analytics providers * fix import error in jetbrains plugin * explicitly include default context providers * Remove a copy / pasta section that duplicated the work done in ChunkCodebaseIndexer (#1834) This cuts the amount of time spent in this section of indexing in half Co-authored-by: Rob Leidle * respect VS Code isTelemetryEnabled * Update OllamaEmbeddingsProvider.ts (#1839) * feat: include recently + open files in codebase search (#1833) * feat: include recently + open files in codebase search * cleanup * Update BaseRetrievalPipeline.ts * add params object to chunkDocument * Update package-lock.json * Offload all token counting to worker processes as well as some optimizations to do more token counting in parallel Adding the workerpool logic broke gui as vite does not support __dirname or path.join(...). To work around this, moved the gui dependency of stripImages out of countTokens.ts * Create CODE_OF_CONDUCT.md (#1843) * tweaks to new tokenizing * temporarily skip code chunking tests due to worker files not being present * update changelog * update version * jetbrains refresh token updates * refresh submenu items on workspace switch * OpenAI Adapters (#1859) * embeddings support in openai-adapters * rerank support in openai-adapters * cohere embed/rerank * continue-proxy reranker and embeddings providers * test for openai-adapters * embeddings provider and reranker for continue proxy * fix: missing Content-Type header in OllamaEmbeddingsProvider (#1855) * Add Language Name Param to AutocompleteTemplate (#1853) Language name was previously added as a parameter only for string autocomplete templates. This change provides this same information to template functions that implement the AutocompleteTemplate interface. Language name is explicitly supported for the CodeGeeX4 autocomplete template, and is added here in this change. Explicit language awareness could also be added for other templates in a future change, like the holeFillerTemplate used for models without explicit completion support. * update package.json version --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com Co-authored-by: ekatiyar Co-authored-by: Simo * DeepSeek FIM Support (#1863) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version * feat: add Llama 3.1 8B to cloudflare provider options (#1811) Co-authored-by: jdelorey@cloudflare.com * increase gemini pro contextLength (#1809) * fix indentation (#1808) * Llama 3.1 405b model selection (#1813) * add support for llama3 405b * 3.1 * name mapping * updates to model setup * fix walkDir tests on windows * chore: add docs as top level config (#1816) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider (#1818) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider * docs schema * Nate/dev (#1819) * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * jetbrains login * fix jetbrains login * change beta wording * proxy context provider * fix proxy context provider * revert to prod id, url * update package.json version * Add CodeGeeX4 code completion support (#1815) Includes support for context through code snippets and relative filename resolution. * manually stop at stop tokens for all providers * chore: bump tree-sitter (#1828) * Add Missing Tokens for CodeGeeX4 AutoComplete (#1827) Previous attempts at using the normal pipe char with CodeGeeX FIM tokens resulted in empty completion output. However, this was due to <|user|> and <|assistant|> tokens being necessary for completion. The earlier working change ommitted these tokens, and its functionality using deepseek pipes was merely coincidental. This change now properly follows the CodeGeeX infill guides and should match what the model expects. In addition to <|user|> and <|assistant|>, the <|endoftext|> token was added as a stop token. * additional analytics providers * fix import error in jetbrains plugin * explicitly include default context providers * Remove a copy / pasta section that duplicated the work done in ChunkCodebaseIndexer (#1834) This cuts the amount of time spent in this section of indexing in half Co-authored-by: Rob Leidle * respect VS Code isTelemetryEnabled * Update OllamaEmbeddingsProvider.ts (#1839) * feat: include recently + open files in codebase search (#1833) * feat: include recently + open files in codebase search * cleanup * Update BaseRetrievalPipeline.ts * add params object to chunkDocument * Update package-lock.json * Offload all token counting to worker processes as well as some optimizations to do more token counting in parallel Adding the workerpool logic broke gui as vite does not support __dirname or path.join(...). To work around this, moved the gui dependency of stripImages out of countTokens.ts * Create CODE_OF_CONDUCT.md (#1843) * tweaks to new tokenizing * temporarily skip code chunking tests due to worker files not being present * update changelog * update version * jetbrains refresh token updates * refresh submenu items on workspace switch * OpenAI Adapters (#1859) * embeddings support in openai-adapters * rerank support in openai-adapters * cohere embed/rerank * continue-proxy reranker and embeddings providers * test for openai-adapters * embeddings provider and reranker for continue proxy * fix: missing Content-Type header in OllamaEmbeddingsProvider (#1855) * Add Language Name Param to AutocompleteTemplate (#1853) Language name was previously added as a parameter only for string autocomplete templates. This change provides this same information to template functions that implement the AutocompleteTemplate interface. Language name is explicitly supported for the CodeGeeX4 autocomplete template, and is added here in this change. Explicit language awareness could also be added for other templates in a future change, like the holeFillerTemplate used for models without explicit completion support. * update package.json version * deepseek FIM endpoint (#1862) * update package.json version --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com Co-authored-by: ekatiyar Co-authored-by: Simo * update gradle version [skip ci] (#1865) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs * Dev (#1689) * Fix an issue where CMD+K does not clear the terminal when the terminal has focus (#1671) On MacOS, ⌘+K is bound, by default, to Terminal:Clear. Without this change ⌘+K does not clear the terminal but instead iniates a chord sequence and waits for the next stroke of the chord. Co-authored-by: Rob Leidle * Change treeSitter to cache the Language objects it loads from wasm (#1672) Without this change, for a repository with 600 typescript files, the indexer would fail to finish correctly and there would be many of the following errors in the webview console log: 'Unable to load language for file ${path} RuntimeError: table index is out of bounds' The following bash will create a repo that reproduces the problem: current_path="." for ((i=1; i<=20; i++)); do new_folder="folder-$i" mkdir -p "$current_path/$new_folder" current_path="$current_path/$new_folder" for ((a=1; a<=30; a++)); do head -c 10000 /dev/urandom | base64 > "$current_path/file-$a.ts" done done Co-authored-by: Rob Leidle * acknowledge sourcemap flag in esbuild.js * don't run jetbrains-release.yaml on vscode releases * further testing for walkDir * chore: add telemetry to commands (#1673) * test: Add basic unit test to baseLLM (#1668) * update version * test: Add basic unit test to baseLLM --------- Co-authored-by: Nate Sesti Co-authored-by: inimaz * feat: add Quick Actions CodeLens feature (#1674) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: add quick actions * Update index.d.ts * quick actions mvp * update docs * subscribe to vscode change settings * Update commands.ts * cleanup * Update quick-actions.md * Update VerticalPerLineCodeLensProvider.ts * resolve feedback --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * chore: add `isCommandEvent` to command telemetry (#1675) * chore: add `isCommandEvent` to command telemetry * Update commands.ts * Nate/better retrieval (#1677) * deduplicatearray tests * break out separate retrieval pipelines * IConfigHandler * tests for codebase indexer * better .continueignore for continue * indexing fixes * ignore .gitignore and .continueignore when indexing * retrieval pipeline improvements * fix formatting err in out .continueignore * add necessary filter to lance_db_cache * update package.json version * skip unused tests * don't ignore .prompt files * update version * Update pull_request_template.md * don't use multi-media format when there are multiple text items * add free trial experience (#1685) * fix: add code range for quick actions/fixes (#1687) * fix: add code range for quick actions/fixes * Update test.js * add pathSep message type * docs improvements * jetbrains fix * update package.json version --------- Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: Patrick Erichsen Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: Jonah Wagner Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> * update package.json version * skip extension tests * update package.json version * handlebars import * don't push package.json version change from CI * fix: scroll issues w/ code blocks (#1688) * fix: scroll issues w/ code blocks * chore: name offset * chore: remove docs start * chore: update headings on troubleshooting.md (#1696) * ignore .svn folder for indexing (#1699) * chore: clearer naming for `useSuffix` (#1702) * chore: clearer naming for `useSuffix` * schema updates * fix: cmd+shft+l closes sidebar if focused (#1638) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * add voyage rerank-1 * import Handlebars * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * small UI tweaks * media query * feat: add best experience onboarding * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * chore: add telemetry for full screen toggle (#1618) * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * manually implement stop tokens for hf inference api * chore: onboarding metrics (#1626) * fix: pageview tracking * feat: add onboarding telemetry * create single `onboardingStatus` type * improved var naming * remove console logs * fix windows performance issue * rename vscodeExtension.ts * migration of onboarding variables * "stash" instead of "delete" in indexing progress * fix preview.yaml * also fix main.yaml * Update troubleshooting.md (#1637) * feat: close panel if main input is focused * add skip param * Update TipTapEditor.tsx * merge dev * Update commands.ts --------- Co-authored-by: Nate Sesti Co-authored-by: Nate Sesti <33237525+sestinj@users.noreply.github.com> Co-authored-by: Jonah Wagner * bugfix: quick actions undefined array (#1704) * feat: add rich quick pick for quick edit (#1706) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * Create deepseek.md (#1708) * style: add max height to model selector (#1712) * update styling * remove testing code * remove comments * feat: add tutorial card (#1716) * feat: create tutorial card * Update TutorialCard.tsx * feat: add file search to quick edit (#1714) * feat: multistep quick pick * fix: multi step for context provider * Update test.js * add file search * complete file search * remove unused import * add comments * Update utils.ts * update naming * chore: move quick pick instantiation (#1723) * Break out into NPM modules (#1726) * config.json types * export all schemas * break out request logic into packages * update openai adapters to export body types * update packaging of npm modules * update packages * continue proxy * mistral * Fix typo in documentation (#1722) In set-up-codestral.md "Trobleshooting" -> "Troubleshooting" * update package.json version * πŸͺ„ model dropdown, control plane (#1692) * Nate/control plane client (#1691) * docs: add docs and schema for "OS" provider (#1536) * ignore .env * fix(gui): ctx rendering w/ renderInlineAs: "" (#1541) * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * fix codeqwen autocomplete leading space * add voyage rerank-1 * feat: `--noEmit` for tsc checks in CI (#1559) * docs: update CustomContextProvider docs (#1557) * add stop tokens to qwen prompt * update docs to reflect 3.5 sonnet being best * docs: comment out unused providers (#1561) * import Handlebars * feat: toast notification for config updates (#1560) * feat: toast notification for config updates * feat: only trigger toast on config.json save * displayRawMarkdown option * feat: open pane on install (#1564) * feat: open pane on activation * comment out testing code * update to reflect 16 stop words limit for deepseek * feat: only trigger config update toast in vscode (#1571) * docs(prompt-files): fix typos + clarify (#1575) * doc: prompt file typo + clarifications * fix: add back correct docs * chore: add telemetry for pageviews (#1576) * feat: update onboarding w/ embeddings model (#1570) * chore(gui): remove unused pages * feat: add embeddings step * feat: update styles * feat: copy button updates * fix: correct pull command for embed model * fix: remove commented code * fix: remove commented code * feat: simplify copy btn props * chore: rename onboarding selection event * feat: add provider config * fix: undo msg name * remove dead code * fix: invalid mode check * fix: remove testing logic * docs(telemetry): add pageviews to tracking list (#1581) * Add reranker configuration options to codebase embedding docs (#1584) - Introduce reranker concept - List available reranker options - Provide configuration instructions - Update keywords to include "reranker" * chore: update pr template with screenshots (#1590) * Refactor ConfirmationDialog to use SecondaryButton for cancel action (#1586) * Added instructions for running docs server locally (#1578) - Added NPM script method - Added VS Code task method - Update contributing guidelines * Update branch policy (#1577) - Change PR target to `dev` branch - Update `CONTRIBUTING.md` instructions * Consolidate example configurations into the main configuration guide (#1579) - Moved examples to configuration.md - Deleted the separate examples.md file - Updated sidebar order and links - Improved readability and structure in configuration.md * fix: fullscreen gui retains context when hidden, fixed fullscreen focusing (#1582) * Update completionProvider.ts (warning tab-autocomplete models) (#1566) * feat: enhanced IndexingProgressBar with blinking dot feature - Integrated BlinkingDot component - Added STATUS_COLORS for various states - Replaced CircleDiv with BlinkingDot in UI - Updated status messages and layout * small UI tweaks * feat(gui): enhance ModelCard, ModelProviderTag, and Toggle components (#1595) - add styling and adjustments to ModelCard - update ModelProviderTag font size - remove box shadow from Toggle component - tweak icon styles in ModelCard - improve alignment and spacing * media query * feat: add best experience onboarding * fix: file rename * stop movement on button hover by keeping same border thickness * fix mistake in setting cursor: pointer * fix when free trial option is shown * Support Node.js versions below 20 for streaming response handling (#1591) - Add fallback for Node < 20 - Implement toAsyncIterable for streaming - Use TextDecoder for manual decoding - Maintain existing streaming for Node 20+ * small fixes * feat: add free trial card to onboarding (#1600) * feat: add free trial card to onboarding * add import * fix hasPassedFTL * fix /edit cancellation from UI * feat: add `applyCodeBlock` experimental prop (#1601) * feat: add new model styling improvements (#1609) * feat: add new model styling improvements * better gap size * feat: update bug_report.yml (#1610) * chore: update bug_report.yml * typo fix * feat: add labels to "Add docs" dialog (#1612) * feat: add labels to "Add docs" dialog * remove autofocus * don't double load config * small fixes * speed up directory traversal, and use correct native path module * option not to show config update toast * merge air-gapped and recommended setup pages * chore: add telemetry for full screen toggle (#1618) * Fix headings in codebase-embeddings.md (#1617) * mention jetbrains * docs: update changie (#1619) * feat: updated changie config * hide toc and autogenerate * Update changelog.mdx * link to deeper explanation of embeddings models * ensure target="_blank" for all links in sidebar * fix gif links in intellij README.md * don't require rust in dependency installation * chore: fix padding on gh button (#1620) * chore: adjust button padding * Update tasks.json * escape colons in diff path * smoother lancedb indexing reporting * smooth progress updates for indexing * fix tsc err * rerank-lite-1 * remove doccs * basic tests for VS Code extension * improved testing of VS Code extension * docs: add docs and schema for "OS" provider (#1536) * ignore .env * πŸš‘ fix constant warnings when onboarding with Ollama * ✨ use and cache imports for autocomplete (#1456) * ✨ use and cache imports for autocomplete * fix tsc * team analytics * apply control plane settings * workos auth * ide protocol get session info * UI for auth * profile switching * small fixes * updates * refresh tokens * updates * fix tsc errs * model select in toolbar to make room for profile selector * prod client id * link to prod URL * internal beta option * profiles change listener --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * temporary patch for type errs --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu * skip extension tests * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * fix: wrap editor buttons when out of space (#1727) * Add .continuerc file to config directory on activation to prevent it's indexing. (#1733) * Updated the content links that were deprecated in the document (#1709) Co-authored-by: Ihe Fan * Nate/dev (#1739) * JetBrains status bar spinner for autocomplete * Remove unused images * partial accept jetbrains * fix double-rendering of jetbrains completions * fix offset of multi-line jetbrains completions * enable/disable actions * upgrade to version 0.0.54 * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * update jetbrains ci to build gui * feat: single default quick pick to edit (#1743) * feat: single default quick pick to edit * Update quick-actions.md * Update quick-actions.md * use defaultQuickAction * quick fixes * fix: handle line removal diff (#1744) * fix: handle line removal diff * remove comments * Configurable `maxChunkSize` for embedding providers (#1746) * Add `maxChunkSize` to `EmbeddingsProvider` * Add `maxChunkSize` to schema * add support for docs via config (#1594) * mistral mamba (#1748) * 🐍 mistral mamba * autoscale retrieval based on context length * autoscale retrieval based on context length * fix input box movement * update jetbrains build * test: add myers diff tests (#1754) * feat: enhance help center (#1755) * feat: enhance help center * Update help.tsx * feat: add azure provider config (#1764) * autocomplete reload fix * logout of control plane * Update QuickEditQuickPick.ts (#1772) * Update QuickEditQuickPick.ts * updates * Update QuickEditQuickPick.ts * pass refreshed access token to continue-proxy model * test: add dir read check for walkDir (#1773) * test: add dir read check for walkDir * Update ignore.ts * Update walkDir.test.ts * Update walkDir.test.ts * gpt-4o-mini * gpt-4o-mini * gpt4omini to ui selector * fix: layout alignment (#1779) * fix: delete old docs index on force re-index (#1778) * add "Codebase Force Re-Index" command (#1757) * Add `HuggingFaceTEIReranker` (#1711) * Add `HuggingFaceTEIReranker` * Add `huggingface-tei` to `config_schema.json` * update package.json version * update config schemas * skip test failing only due to type error * fix: convert `walkDir` to an async generator (#1783) * walkdir to async generator * add yields * handle ignore files * Update CodebaseIndexer.ts * Update walkDir.ts * chore: bump VS Code ext version * fix completions support in ContinueProxy * add test for walkDir * IAnalyticsProvider * feat: crawl `.mdx` docs * update workspaces on session info change * rename from profile to workspace (user-facing) * update config schema files * feat: improve chat thread ui for better readability (#1786) * add "language" template variable for autocomplete * Enable debug logs (#1800) * Add an enableDebugLogs flag * Send logs to VSCode * Refresh index fixes (#1795) * Use the resultType given to markComplete This fixes an issue where if there were multiple result types in itemToAction such as an update with UpdateNewVersion and UpdateOldVersion, only the UpdateOldVersion would be hit (which is a noop) and the UpdateNewVersion would never be fired, causing us to never update the timestamp of the tag_catalog. * Add a Compute and UpdateLastUpdated to refreshIndex Removes the ability to insert duplicate rows if we're just computing the result. Instead we replace the existing row instead. * Don't insert compute tags They are REPLACEd in markComplete now. * docs: change page heading to model providers (#1684) * feat: allow JetBrains users to index docs (#1797) * feat: allow JetBrains users to index docs * update docs service * update global context * throw error popup on jetbrains + transformers * update toast notifications * update typings * fix tsc errors * Index on file change (#1785) * Reload the submenu items when the context provider data is refreshed * update version * Just call refreshSubmenuItems * remove log statements * cleanup * Remove the Promise declaration * Copy currentFiles to a new dict since we're going to mutate it Don't mutate the caller's currentFiles unexpectedly * Remove reIndexFile and just call index/forceReIndex * We MUST await the refreshCodebaseIndex call * Expose send on core * remove unused import * Reindex the workspaces on save * Call core.send Ideally, we can implement externalRequest on the webview later so we don't have to expose messenger to the VSCode extension * Always refreshSubmenuItems in refreshCodebaseIndex * whitespace * Change messenger back to private * Add Pause Codebase On Start setting (#1788) * Add a skipInitialSync function * Add pauseInitialCodebaseIndex * docs * version bump * Rename to pauseCodebaseIndexOnStart * Un-shadow file context provider (#1801) * allow FileContextProvider to handle files * remove commented-out lines * chore: add telemetry to alt-enter (#1805) * Set the indexProgress indicator to paused on startup if pauseCodebaseIndexOnStart is set (#1804) * Fix Input Toolbar layout (#1792) * set to flex flex-column * Remove fixed height and always show the StyledDivs content to hold its size * Add a Delete Message button to the StepContainer (#1790) * Add a delete button * add a delete message action to the GUI * Fix off by one error * format * This index should be less than length * Update to trash icon * Simplify walkDir(...) and improve performance by roughly 10x in larger repos (#1806) The performance of WalkDir is improved by replacing the recursive DFS with a stack based implementation (less memory in-use during peak exploration). In addition, some unnecessary flags and options were removed which allowed the code to be overall simplified. Much less rule matching is occuring with the same files returned. Some performance results on my linux host: small repo: - 649 files returned by walkDir() - 9 .gitignore files - walkDir() old vs new duration: 918 ms to 143 ms medium sized repo: - 9271 returned by walkDir() - 35 .gitignore files - walkDir() old vs new duration: 10,886 ms to 970ms large sized repo: - 197,900 files returned by walkDir() - 929 .gitignore files - walkDir() old vs new duration: 498,151 ms to 37,353 ms Co-authored-by: Rob Leidle * modified assistant indicator in UI * update package.json version * feat: add Llama 3.1 8B to cloudflare provider options (#1811) Co-authored-by: jdelorey@cloudflare.com * increase gemini pro contextLength (#1809) * fix indentation (#1808) * Llama 3.1 405b model selection (#1813) * add support for llama3 405b * 3.1 * name mapping * updates to model setup * fix walkDir tests on windows * chore: add docs as top level config (#1816) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider (#1818) * chore: add docs as top level config * Update core.ts * feat: make @codebase a hardcoded ctx provider * docs schema * Nate/dev (#1819) * llm-info package * small profile switching improvements * instruct cmd+I not to leave placeholders * @ files in context-providers docs * onboarding fix * jetbrains login * fix jetbrains login * change beta wording * proxy context provider * fix proxy context provider * revert to prod id, url * update package.json version * Add CodeGeeX4 code completion support (#1815) Includes support for context through code snippets and relative filename resolution. * manually stop at stop tokens for all providers * chore: bump tree-sitter (#1828) * Add Missing Tokens for CodeGeeX4 AutoComplete (#1827) Previous attempts at using the normal pipe char with CodeGeeX FIM tokens resulted in empty completion output. However, this was due to <|user|> and <|assistant|> tokens being necessary for completion. The earlier working change ommitted these tokens, and its functionality using deepseek pipes was merely coincidental. This change now properly follows the CodeGeeX infill guides and should match what the model expects. In addition to <|user|> and <|assistant|>, the <|endoftext|> token was added as a stop token. * additional analytics providers * fix import error in jetbrains plugin * explicitly include default context providers * Remove a copy / pasta section that duplicated the work done in ChunkCodebaseIndexer (#1834) This cuts the amount of time spent in this section of indexing in half Co-authored-by: Rob Leidle * respect VS Code isTelemetryEnabled * Update OllamaEmbeddingsProvider.ts (#1839) * feat: include recently + open files in codebase search (#1833) * feat: include recently + open files in codebase search * cleanup * Update BaseRetrievalPipeline.ts * add params object to chunkDocument * Update package-lock.json * Offload all token counting to worker processes as well as some optimizations to do more token counting in parallel Adding the workerpool logic broke gui as vite does not support __dirname or path.join(...). To work around this, moved the gui dependency of stripImages out of countTokens.ts * Create CODE_OF_CONDUCT.md (#1843) * tweaks to new tokenizing * temporarily skip code chunking tests due to worker files not being present * update changelog * update version * jetbrains refresh token updates * refresh submenu items on workspace switch * OpenAI Adapters (#1859) * embeddings support in openai-adapters * rerank support in openai-adapters * cohere embed/rerank * continue-proxy reranker and embeddings providers * test for openai-adapters * embeddings provider and reranker for continue proxy * fix: missing Content-Type header in OllamaEmbeddingsProvider (#1855) * Add Language Name Param to AutocompleteTemplate (#1853) Language name was previously added as a parameter only for string autocomplete templates. This change provides this same information to template functions that implement the AutocompleteTemplate interface. Language name is explicitly supported for the CodeGeeX4 autocomplete template, and is added here in this change. Explicit language awareness could also be added for other templates in a future change, like the holeFillerTemplate used for models without explicit completion support. * update package.json version * deepseek FIM endpoint (#1862) * update package.json version * continue teams beta setting * update jetbrains version --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com Co-authored-by: ekatiyar Co-authored-by: Simo --------- Co-authored-by: Patrick Erichsen Co-authored-by: Priyash <38959321+priyashpatil@users.noreply.github.com> Co-authored-by: Jonah Wagner Co-authored-by: YohannZe <99359799+YohannZe@users.noreply.github.com> Co-authored-by: Dan Dascalescu Co-authored-by: Rob Leidle Co-authored-by: Rob Leidle Co-authored-by: inimaz <49730431+inimaz@users.noreply.github.com> Co-authored-by: inimaz Co-authored-by: AnaΓ«l Bonnafous <71386173+AnaelBonnafous@users.noreply.github.com> Co-authored-by: Huy Tran <119860259+tranquochuy645@users.noreply.github.com> Co-authored-by: Gabriel Gordbegli Co-authored-by: Raven-1027 <83693755+Raven-1027@users.noreply.github.com> Co-authored-by: Ihe Fan Co-authored-by: Lukas Kreussel <65088241+LLukas22@users.noreply.github.com> Co-authored-by: Josh Vera Co-authored-by: Peter Zaback Co-authored-by: James Delorey Co-authored-by: jdelorey@cloudflare.com Co-authored-by: ekatiyar Co-authored-by: Simo --- .../unreleased/Added-20240726-153514.yaml | 4 + .../unreleased/Changed-20240726-153458.yaml | 4 + .../unreleased/Changed-20240726-153542.yaml | 5 + .github/workflows/jetbrains-build.yaml | 24 +- .github/workflows/jetbrains-release.yaml | 30 +- .github/workflows/main.yaml | 52 +- .github/workflows/preview.yaml | 28 +- .vscode/launch.json | 40 +- .vscode/settings.json | 14 +- CODE_OF_CONDUCT.md | 73 + binary/build.js | 17 +- binary/package-lock.json | 10 +- binary/test/binary.test.ts | 6 +- core/autocomplete/ImportDefinitionsService.ts | 8 +- core/autocomplete/README.md | 2 +- core/autocomplete/completionProvider.ts | 40 +- core/autocomplete/languages.ts | 24 + core/autocomplete/templates.ts | 45 +- core/commands/index.ts | 2 +- core/commands/slash/commit.ts | 2 +- core/commands/slash/draftIssue.ts | 2 +- core/commands/slash/edit.ts | 2 +- core/commands/slash/review.ts | 2 +- core/commands/slash/share.ts | 2 +- core/commands/slash/stackOverflow.ts | 3 +- core/config/ConfigHandler.ts | 299 +- core/config/IConfigHandler.ts | 17 - core/config/default.ts | 96 +- core/config/load.ts | 138 +- core/config/onboarding.ts | 5 - .../profile/ControlPlaneProfileLoader.ts | 57 + core/config/profile/IProfileLoader.ts | 11 + core/config/profile/LocalProfileLoader.ts | 29 + core/config/profile/doLoadConfig.ts | 82 + core/config/promptFile.ts | 2 +- core/config/types.ts | 3 +- core/context/index.ts | 1 + .../providers/ContinueProxyContextProvider.ts | 76 + core/context/providers/DocsContextProvider.ts | 214 +- core/context/providers/index.ts | 11 +- .../rerankers/ContinueProxyReranker.ts | 46 + core/context/rerankers/index.ts | 4 + core/context/rerankers/tei.ts | 49 + .../pipelines/BaseRetrievalPipeline.ts | 46 +- .../pipelines/NoRerankerRetrievalPipeline.ts | 40 +- .../pipelines/RerankerRetrievalPipeline.ts | 39 +- .../retrieval/recentlyEditedFilesCache.ts | 15 + core/context/retrieval/retrieval.ts | 40 +- core/control-plane/TeamAnalytics.ts | 55 + .../ContinueProxyAnalyticsProvider.ts | 32 + .../analytics/IAnalyticsProvider.ts | 11 + .../analytics/LogStashAnalyticsProvider.ts | 42 + .../analytics/PostHogAnalyticsProvider.ts | 37 + core/control-plane/auth/index.ts | 20 + core/control-plane/client.ts | 97 + core/control-plane/schema.ts | 128 + core/core.ts | 254 +- core/diff/streamDiff.ts | 69 +- core/diff/util.ts | 38 +- core/index.d.ts | 38 +- core/indexing/CodebaseIndexer.ts | 13 +- core/indexing/LanceDbIndex.ts | 26 +- core/indexing/chunk/ChunkCodebaseIndex.ts | 43 +- core/indexing/chunk/basic.ts | 24 +- core/indexing/chunk/chunk.ts | 57 +- core/indexing/chunk/code.ts | 61 +- core/indexing/chunk/markdown.ts | 2 +- core/indexing/docs/DocsService.ts | 133 +- core/indexing/docs/article.ts | 10 +- core/indexing/docs/crawl.ts | 12 +- core/indexing/docs/preIndexedDocs.ts | 108 +- .../embeddings/BaseEmbeddingsProvider.ts | 21 +- .../embeddings/CohereEmbeddingsProvider.ts | 4 +- .../ContinueProxyEmbeddingsProvider.ts | 25 + .../embeddings/DeepInfraEmbeddingsProvider.ts | 3 +- .../embeddings/FreeTrialEmbeddingsProvider.ts | 7 +- .../embeddings/GeminiEmbeddingsProvider.ts | 10 +- .../HuggingFaceTEIEmbeddingsProvider.ts | 25 +- .../embeddings/OllamaEmbeddingsProvider.ts | 18 +- .../embeddings/OpenAIEmbeddingsProvider.ts | 3 +- .../TransformersJsEmbeddingsProvider.ts | 7 +- core/indexing/embeddings/index.ts | 6 +- core/indexing/ignore.ts | 2 + core/indexing/refreshIndex.ts | 160 +- core/indexing/types.ts | 1 + core/indexing/walkDir.ts | 485 +- core/llm/asyncEncoder.ts | 47 + core/llm/autodetect.ts | 1 + core/llm/constants.ts | 1 + core/llm/countTokens.ts | 54 +- core/llm/images.ts | 11 + core/llm/index.ts | 26 +- core/llm/llamaTokenizer.mjs | 486 + core/llm/llamaTokenizerWorkerPool.mjs | 10 + core/llm/llms/Anthropic.ts | 2 +- core/llm/llms/Azure.ts | 8 + core/llm/llms/Bedrock.ts | 2 +- core/llm/llms/Cloudflare.ts | 3 +- core/llm/llms/Cohere.ts | 2 +- core/llm/llms/Deepseek.ts | 38 +- core/llm/llms/Flowise.ts | 2 +- core/llm/llms/FreeTrial.ts | 3 +- core/llm/llms/Gemini.ts | 2 +- core/llm/llms/Groq.ts | 3 + core/llm/llms/HuggingFaceInferenceAPI.ts | 3 +- core/llm/llms/Mistral.ts | 9 +- core/llm/llms/Ollama.ts | 5 +- core/llm/llms/OpenAI.ts | 3 +- core/llm/llms/Replicate.ts | 3 + core/llm/llms/Together.ts | 3 + core/llm/llms/index.ts | 2 + core/llm/llms/stubs/ContinueProxy.ts | 20 +- core/llm/templates/chat.ts | 2 +- core/llm/templates/edit.ts | 4 +- core/package-lock.json | 565 +- core/package.json | 8 +- core/protocol/core.ts | 13 +- core/protocol/coreWebview.ts | 9 +- core/protocol/ide.ts | 14 + core/protocol/index.ts | 13 +- core/protocol/passThrough.ts | 8 +- core/protocol/webview.ts | 1 + core/test/diff.test.ts | 150 - core/test/indexing/CodebaseIndexer.skip.ts | 1 + core/test/indexing/chunk/code.test.ts | 2 +- core/test/streamDiff.test.ts | 180 + core/test/walkDir.test.ts | 79 +- core/util/GlobalContext.ts | 9 + core/util/filesystem.ts | 7 +- core/util/parameters.ts | 2 +- core/util/paths.ts | 32 +- core/util/posthog.ts | 11 +- core/util/verticalEdit.ts | 12 +- docs/docs/customization/context-providers.md | 30 + docs/docs/customization/overview.md | 2 +- docs/docs/features/codebase-embeddings.md | 19 +- docs/docs/features/quick-actions.md | 11 +- docs/docs/features/tab-autocomplete.md | 2 +- .../reference/Model Providers/deepseek.md | 16 + .../reference/Model Providers/freetrial.md | 2 +- .../docs/reference/Model Providers/mistral.md | 4 +- docs/docs/setup/configuration.md | 4 +- ...{select-provider.md => model-providers.md} | 27 +- docs/docs/setup/overview.md | 2 +- docs/docs/setup/select-model.md | 2 +- docs/docs/troubleshooting.md | 16 +- docs/docs/walkthroughs/set-up-codestral.md | 4 +- docs/docusaurus.config.js | 4 + docs/sidebars.js | 2 +- docs/static/schemas/config.json | 156 +- eval/.gitignore | 1 + extensions/intellij/gradle.properties | 2 +- .../ContinuePluginStartupActivity.kt | 30 + .../auth/AuthListener.kt | 12 + .../auth/ContinueAuthDialog.kt | 34 + .../auth/ContinueAuthService.kt | 223 + .../autocomplete/AutocompleteActionGroup.kt | 29 + .../AutocompleteEditorListener.kt | 15 +- .../autocomplete/AutocompleteService.kt | 79 +- .../AutocompleteSpinnerWidgetFactory.kt | 111 + .../ContinueCustomElementRenderer.kt | 3 +- .../ContinueMultilineCustomElementRenderer.kt | 11 +- .../DisableTabAutocompleteAction.kt | 12 + .../EnableTabAutocompleteAction.kt | 12 + .../PartialAcceptAutocompleteAction.kt | 3 +- .../continue/CoreMessenger.kt | 7 +- .../continue/IdeProtocolClient.kt | 23 +- .../editor/InlineEditAction.kt | 4 +- .../ContinueExtensionSettingsService.kt | 21 +- .../toolWindow/ContinueBrowser.kt | 7 +- .../src/main/resources/META-INF/plugin.xml | 13 +- .../src/main/resources/config_schema.json | 156 +- .../resources/webview/continue-dev-square.png | Bin 36355 -> 0 bytes .../src/main/resources/webview/continue.gif | Bin 5242 -> 0 bytes .../main/resources/webview/play_button.png | Bin 1017 -> 0 bytes extensions/vscode/CHANGELOG.md | 71 +- extensions/vscode/config_schema.json | 156 +- extensions/vscode/continue_rc_schema.json | 174 +- extensions/vscode/package-lock.json | 18 +- extensions/vscode/package.json | 34 +- extensions/vscode/scripts/prepackage.js | 15 +- ...l.ts => ContinueGUIWebviewViewProvider.ts} | 76 +- extensions/vscode/src/activation/activate.ts | 13 +- .../vscode/src/activation/languageClient.ts | 3 +- .../src/autocomplete/completionProvider.ts | 4 +- extensions/vscode/src/commands.ts | 132 +- .../vscode/src/diff/oldVerticalPerLine.ts | 94 - .../src/diff/verticalPerLine/manager.ts | 4 +- extensions/vscode/src/extension.ts | 10 +- .../vscode/src/extension/VsCodeExtension.ts | 60 +- .../vscode/src/extension/VsCodeMessenger.ts | 37 +- extensions/vscode/src/ideProtocol.ts | 21 +- .../providers/QuickActionsCodeLensProvider.ts | 27 +- .../providers/TutorialCodeLensProvider.ts | 3 +- .../quickEdit/ContextProvidersQuickPick.ts | 88 + .../vscode/src/quickEdit/HistoryQuickPick.ts | 42 + .../src/quickEdit/InputBoxWithHistory.ts | 181 - .../src/quickEdit/ModelSelectionQuickPick.ts | 32 + extensions/vscode/src/quickEdit/QuickEdit.ts | 194 - .../src/quickEdit/QuickEditQuickPick.ts | 454 + extensions/vscode/src/quickEdit/index.ts | 0 .../vscode/src/stubs/WorkOsAuthProvider.ts | 421 + extensions/vscode/src/stubs/promiseUtils.ts | 57 + extensions/vscode/src/suggestions.ts | 60 +- extensions/vscode/src/util/cleanSlate.ts | 3 + .../vscode/src/util/loadAutocompleteModel.ts | 6 +- extensions/vscode/src/webviewProtocol.ts | 43 +- gui/package-lock.json | 15363 ++++++++++++++-- gui/package.json | 8 +- gui/public/continue-dev-square.png | Bin 36355 -> 0 bytes gui/public/continue.gif | Bin 5242 -> 0 bytes gui/public/play_button.png | Bin 1017 -> 0 bytes gui/src/components/ChatScrollAnchor.tsx | 32 + gui/src/components/Layout.tsx | 48 +- gui/src/components/Logo.tsx | 22 + gui/src/components/PosthogPageView.ts | 4 +- gui/src/components/ProfileSwitcher.tsx | 260 + gui/src/components/dialogs/AddDocsDialog.tsx | 1 + .../components/dialogs/ConfirmationDialog.tsx | 35 +- gui/src/components/dialogs/index.tsx | 4 +- gui/src/components/gui/StepContainer.tsx | 123 +- .../loaders/IndexingProgressBar.tsx | 8 +- gui/src/components/loaders/StatusDot.tsx | 2 +- .../components/mainInput/ContextItemsPeek.tsx | 13 +- gui/src/components/mainInput/InputToolbar.tsx | 226 +- gui/src/components/mainInput/TipTapEditor.css | 1 + gui/src/components/mainInput/TipTapEditor.tsx | 43 +- gui/src/components/mainInput/TutorialCard.tsx | 86 + gui/src/components/mainInput/resolveInput.ts | 50 +- .../modelSelection/LegacyModelSelect.tsx | 305 + .../components/modelSelection/ModelSelect.tsx | 320 +- gui/src/hooks/useAuth.tsx | 78 + gui/src/hooks/useChatHandler.ts | 2 +- gui/src/hooks/useHistory.tsx | 2 +- gui/src/hooks/useSetup.ts | 20 +- gui/src/hooks/useSubmenuContextProviders.tsx | 150 +- gui/src/hooks/useWebviewListener.ts | 34 +- gui/src/pages/AddNewModel/AddNewModel.tsx | 265 +- gui/src/pages/AddNewModel/configs/models.ts | 285 +- .../pages/AddNewModel/configs/providers.ts | 35 +- gui/src/pages/gui.tsx | 301 +- gui/src/pages/help.tsx | 215 +- .../pages/onboarding/ApiKeysOnboarding.tsx | 6 +- gui/src/pages/onboarding/LocalOnboarding.tsx | 6 +- gui/src/pages/onboarding/utils.ts | 1 + gui/src/pages/stats.tsx | 2 +- gui/src/redux/slices/stateSlice.ts | 29 +- gui/src/util/localStorage.ts | 3 + packages/config-types/package-lock.json | 40 + packages/config-types/package.json | 20 + packages/config-types/src/index.ts | 226 + packages/config-types/tsconfig.json | 23 + packages/fetch/jest.config.d.ts | 7 + packages/fetch/jest.config.js | 143 + packages/fetch/jest.config.ts | 199 + packages/fetch/package-lock.json | 3665 ++++ packages/fetch/package.json | 25 + packages/fetch/src/fetch.ts | 117 + packages/fetch/src/index.ts | 16 + packages/fetch/src/stream.ts | 113 + packages/fetch/tsconfig.json | 23 + packages/llm-info/README.md | 3 + packages/llm-info/package.json | 18 + packages/llm-info/src/index.ts | 18 + packages/llm-info/src/models/anthropic.ts | 60 + packages/llm-info/src/models/google.ts | 22 + packages/llm-info/src/models/mistral.ts | 75 + packages/llm-info/src/models/openai.ts | 74 + packages/llm-info/src/types.ts | 30 + packages/llm-info/tsconfig.json | 23 + packages/openai-adapters/.npmignore | 2 + packages/openai-adapters/jest.config.mjs | 22 + packages/openai-adapters/package-lock.json | 4496 +++++ packages/openai-adapters/package.json | 26 + .../openai-adapters/src/apis/AzureOpenAI.ts | 254 + packages/openai-adapters/src/apis/Cohere.ts | 116 + packages/openai-adapters/src/apis/OpenAI.ts | 118 + packages/openai-adapters/src/apis/base.ts | 70 + packages/openai-adapters/src/index.ts | 51 + packages/openai-adapters/test/main.test.ts | 206 + packages/openai-adapters/tsconfig.json | 23 + 281 files changed, 32740 insertions(+), 5335 deletions(-) create mode 100644 .changes/unreleased/Added-20240726-153514.yaml create mode 100644 .changes/unreleased/Changed-20240726-153458.yaml create mode 100644 .changes/unreleased/Changed-20240726-153542.yaml create mode 100644 CODE_OF_CONDUCT.md delete mode 100644 core/config/IConfigHandler.ts create mode 100644 core/config/profile/ControlPlaneProfileLoader.ts create mode 100644 core/config/profile/IProfileLoader.ts create mode 100644 core/config/profile/LocalProfileLoader.ts create mode 100644 core/config/profile/doLoadConfig.ts create mode 100644 core/context/providers/ContinueProxyContextProvider.ts create mode 100644 core/context/rerankers/ContinueProxyReranker.ts create mode 100644 core/context/rerankers/tei.ts create mode 100644 core/context/retrieval/recentlyEditedFilesCache.ts create mode 100644 core/control-plane/TeamAnalytics.ts create mode 100644 core/control-plane/analytics/ContinueProxyAnalyticsProvider.ts create mode 100644 core/control-plane/analytics/IAnalyticsProvider.ts create mode 100644 core/control-plane/analytics/LogStashAnalyticsProvider.ts create mode 100644 core/control-plane/analytics/PostHogAnalyticsProvider.ts create mode 100644 core/control-plane/auth/index.ts create mode 100644 core/control-plane/client.ts create mode 100644 core/control-plane/schema.ts create mode 100644 core/indexing/embeddings/ContinueProxyEmbeddingsProvider.ts create mode 100644 core/llm/asyncEncoder.ts create mode 100644 core/llm/images.ts create mode 100644 core/llm/llamaTokenizer.mjs create mode 100644 core/llm/llamaTokenizerWorkerPool.mjs create mode 100644 core/llm/llms/Azure.ts delete mode 100644 core/test/diff.test.ts create mode 100644 core/test/streamDiff.test.ts create mode 100644 docs/docs/reference/Model Providers/deepseek.md rename docs/docs/setup/{select-provider.md => model-providers.md} (82%) create mode 100644 eval/.gitignore create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/AuthListener.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthDialog.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthService.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteActionGroup.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteSpinnerWidgetFactory.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/DisableTabAutocompleteAction.kt create mode 100644 extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/EnableTabAutocompleteAction.kt delete mode 100644 extensions/intellij/src/main/resources/webview/continue-dev-square.png delete mode 100644 extensions/intellij/src/main/resources/webview/continue.gif delete mode 100644 extensions/intellij/src/main/resources/webview/play_button.png rename extensions/vscode/src/{debugPanel.ts => ContinueGUIWebviewViewProvider.ts} (66%) delete mode 100644 extensions/vscode/src/diff/oldVerticalPerLine.ts create mode 100644 extensions/vscode/src/quickEdit/ContextProvidersQuickPick.ts create mode 100644 extensions/vscode/src/quickEdit/HistoryQuickPick.ts delete mode 100644 extensions/vscode/src/quickEdit/InputBoxWithHistory.ts create mode 100644 extensions/vscode/src/quickEdit/ModelSelectionQuickPick.ts delete mode 100644 extensions/vscode/src/quickEdit/QuickEdit.ts create mode 100644 extensions/vscode/src/quickEdit/QuickEditQuickPick.ts create mode 100644 extensions/vscode/src/quickEdit/index.ts create mode 100644 extensions/vscode/src/stubs/WorkOsAuthProvider.ts create mode 100644 extensions/vscode/src/stubs/promiseUtils.ts delete mode 100644 gui/public/continue-dev-square.png delete mode 100644 gui/public/continue.gif delete mode 100644 gui/public/play_button.png create mode 100644 gui/src/components/ChatScrollAnchor.tsx create mode 100644 gui/src/components/Logo.tsx create mode 100644 gui/src/components/ProfileSwitcher.tsx create mode 100644 gui/src/components/mainInput/TutorialCard.tsx create mode 100644 gui/src/components/modelSelection/LegacyModelSelect.tsx create mode 100644 gui/src/hooks/useAuth.tsx create mode 100644 packages/config-types/package-lock.json create mode 100644 packages/config-types/package.json create mode 100644 packages/config-types/src/index.ts create mode 100644 packages/config-types/tsconfig.json create mode 100644 packages/fetch/jest.config.d.ts create mode 100644 packages/fetch/jest.config.js create mode 100644 packages/fetch/jest.config.ts create mode 100644 packages/fetch/package-lock.json create mode 100644 packages/fetch/package.json create mode 100644 packages/fetch/src/fetch.ts create mode 100644 packages/fetch/src/index.ts create mode 100644 packages/fetch/src/stream.ts create mode 100644 packages/fetch/tsconfig.json create mode 100644 packages/llm-info/README.md create mode 100644 packages/llm-info/package.json create mode 100644 packages/llm-info/src/index.ts create mode 100644 packages/llm-info/src/models/anthropic.ts create mode 100644 packages/llm-info/src/models/google.ts create mode 100644 packages/llm-info/src/models/mistral.ts create mode 100644 packages/llm-info/src/models/openai.ts create mode 100644 packages/llm-info/src/types.ts create mode 100644 packages/llm-info/tsconfig.json create mode 100644 packages/openai-adapters/.npmignore create mode 100644 packages/openai-adapters/jest.config.mjs create mode 100644 packages/openai-adapters/package-lock.json create mode 100644 packages/openai-adapters/package.json create mode 100644 packages/openai-adapters/src/apis/AzureOpenAI.ts create mode 100644 packages/openai-adapters/src/apis/Cohere.ts create mode 100644 packages/openai-adapters/src/apis/OpenAI.ts create mode 100644 packages/openai-adapters/src/apis/base.ts create mode 100644 packages/openai-adapters/src/index.ts create mode 100644 packages/openai-adapters/test/main.test.ts create mode 100644 packages/openai-adapters/tsconfig.json diff --git a/.changes/unreleased/Added-20240726-153514.yaml b/.changes/unreleased/Added-20240726-153514.yaml new file mode 100644 index 000000000..f7e781d61 --- /dev/null +++ b/.changes/unreleased/Added-20240726-153514.yaml @@ -0,0 +1,4 @@ +project: extensions/vscode +kind: Added +body: Support for Llama 3.1 and gpt-4o-mini +time: 2024-07-26T15:35:14.411895-07:00 diff --git a/.changes/unreleased/Changed-20240726-153458.yaml b/.changes/unreleased/Changed-20240726-153458.yaml new file mode 100644 index 000000000..3b251034c --- /dev/null +++ b/.changes/unreleased/Changed-20240726-153458.yaml @@ -0,0 +1,4 @@ +project: extensions/vscode +kind: Changed +body: Significant improvements to indexing performance +time: 2024-07-26T15:34:58.457908-07:00 diff --git a/.changes/unreleased/Changed-20240726-153542.yaml b/.changes/unreleased/Changed-20240726-153542.yaml new file mode 100644 index 000000000..5e5284e45 --- /dev/null +++ b/.changes/unreleased/Changed-20240726-153542.yaml @@ -0,0 +1,5 @@ +project: extensions/vscode +kind: Changed +body: Improved @codebase quality by more accurately searching over file names and + paths +time: 2024-07-26T15:35:42.390496-07:00 diff --git a/.github/workflows/jetbrains-build.yaml b/.github/workflows/jetbrains-build.yaml index 871571043..a9696872d 100644 --- a/.github/workflows/jetbrains-build.yaml +++ b/.github/workflows/jetbrains-build.yaml @@ -16,7 +16,7 @@ name: Build on: # Trigger the workflow on pushes to only the 'main' branch (this avoids duplicate checks being run e.g., for dependabot pull requests) push: - branches: [main] + branches: [main, preview] # Trigger the workflow on any pull request # pull_request: @@ -97,6 +97,12 @@ jobs: path: binary/node_modules key: ${{ runner.os }}-node-${{ hashFiles('binary/package-lock.json') }} + - name: Cache gui node_modules + uses: actions/cache@v3 + with: + path: gui/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('gui/package-lock.json') }} + # npm install core - name: Install core node_modules run: | @@ -109,6 +115,18 @@ jobs: cd ../../binary npm ci + # npm install gui + - name: Install gui node_modules + run: | + cd ../../gui + npm ci + + # build gui + - name: Build gui + run: | + cd ../../gui + npm run build + # Run prepackage.js script - name: Run prepackage script run: | @@ -134,11 +152,11 @@ jobs: id: artifact shell: bash run: | - cd ${{ github.workspace }}/extensions/intellij/build/distributions + cd ../../extensions/intellij/build/distributions FILENAME=`ls *.zip` unzip "$FILENAME" -d content - echo "filename=${FILENAME:0:-4}" >> $GITHUB_OUTPUT + echo "filename=${FILENAME%.????}" >> $GITHUB_OUTPUT # Store already-built plugin as an artifact for downloading - name: Upload artifact diff --git a/.github/workflows/jetbrains-release.yaml b/.github/workflows/jetbrains-release.yaml index 6c9e23ef9..291d9ebef 100644 --- a/.github/workflows/jetbrains-release.yaml +++ b/.github/workflows/jetbrains-release.yaml @@ -87,6 +87,12 @@ jobs: path: binary/node_modules key: ${{ runner.os }}-node-${{ hashFiles('binary/package-lock.json') }} + - name: Cache gui node_modules + uses: actions/cache@v3 + with: + path: gui/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('gui/package-lock.json') }} + # npm install core - name: Install core node_modules run: | @@ -99,6 +105,18 @@ jobs: cd ../../binary npm ci + # npm install gui + - name: Install gui node_modules + run: | + cd ../../gui + npm ci + + # build gui + - name: Build gui + run: | + cd ../../gui + npm run build + # Run prepackage.js script - name: Run prepackage script run: | @@ -120,6 +138,12 @@ jobs: run: | ./gradlew patchChangelog --release-note="$CHANGELOG" + # Upload artifact as a release asset + - name: Upload Release Asset + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* + # Publish the plugin to JetBrains Marketplace - name: Publish Plugin env: @@ -129,12 +153,6 @@ jobs: PRIVATE_KEY_PASSWORD: ${{ secrets.JETBRAINS_PRIVATE_KEY_PASSWORD }} run: ./gradlew publishPlugin - # Upload artifact as a release asset - - name: Upload Release Asset - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh release upload ${{ github.event.release.tag_name }} ./build/distributions/* - # Create a pull request - name: Create Pull Request if: ${{ steps.properties.outputs.changelog != '' }} diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 166fe5c95..107162244 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -125,19 +125,19 @@ jobs: # 4. Run tests for the extension # - name: Install Xvfb for Linux and run tests - # run: | - # sudo apt-get install -y xvfb # Install Xvfb - # Xvfb :99 & # Start Xvfb - # export DISPLAY=:99 # Export the display number to the environment - # cd extensions/vscode - # npm run test - # if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get install -y xvfb # Install Xvfb + Xvfb :99 & # Start Xvfb + export DISPLAY=:99 # Export the display number to the environment + cd extensions/vscode + npm run test + if: matrix.os == 'ubuntu-latest' - # - name: Run extension tests - # run: | - # cd extensions/vscode - # npm run test - # if: matrix.os != 'ubuntu-latest' + - name: Run extension tests + run: | + cd extensions/vscode + npm run test + if: matrix.os != 'ubuntu-latest' # 5. Package the extension - name: Package the extension @@ -231,22 +231,22 @@ jobs: npx ovsx publish -p ${{ secrets.VSX_REGISTRY_TOKEN }} --packagePath ../../alpine-x64/*.vsix ../../darwin-arm64/*.vsix ../../darwin-x64/*.vsix ../../linux-arm64/*.vsix ../../linux-armhf/*.vsix ../../linux-x64/*.vsix ../../win32-x64/*.vsix ../../win32-arm64/*.vsix # 4. Update the package.json version and push changes - - name: Update version in package.json - run: | - cd extensions/vscode - npm version patch + # - name: Update version in package.json + # run: | + # cd extensions/vscode + # npm version patch - - name: Commit changes - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git commit -am "πŸ’š Update package.json version [skip ci]" + # - name: Commit changes + # run: | + # git config --local user.email "action@github.com" + # git config --local user.name "GitHub Action" + # git commit -am "πŸ’š Update package.json version [skip ci]" - - name: Push changes - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: ${{ github.ref }} + # - name: Push changes + # uses: ad-m/github-push-action@master + # with: + # github_token: ${{ secrets.GITHUB_TOKEN }} + # branch: ${{ github.ref }} # 5 Send to Discord Webhook - name: Discord Commits diff --git a/.github/workflows/preview.yaml b/.github/workflows/preview.yaml index 9c5c50c33..a04591c89 100644 --- a/.github/workflows/preview.yaml +++ b/.github/workflows/preview.yaml @@ -223,19 +223,19 @@ jobs: npx ovsx publish --pre-release -p ${{ secrets.VSX_REGISTRY_TOKEN }} --packagePath ../../alpine-x64/*.vsix ../../darwin-arm64/*.vsix ../../darwin-x64/*.vsix ../../linux-arm64/*.vsix ../../linux-armhf/*.vsix ../../linux-x64/*.vsix ../../win32-x64/*.vsix ../../win32-arm64/*.vsix # 4. Update the package.json version and push changes - - name: Update version in package.json - run: | - cd extensions/vscode - npm version patch + # - name: Update version in package.json + # run: | + # cd extensions/vscode + # npm version patch - - name: Commit changes - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git commit -am "πŸ’š Update package.json version [skip ci]" + # - name: Commit changes + # run: | + # git config --local user.email "action@github.com" + # git config --local user.name "GitHub Action" + # git commit -am "πŸ’š Update package.json version [skip ci]" - - name: Push changes - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: ${{ github.ref }} + # - name: Push changes + # uses: ad-m/github-push-action@master + # with: + # github_token: ${{ secrets.GITHUB_TOKEN }} + # branch: ${{ github.ref }} diff --git a/.vscode/launch.json b/.vscode/launch.json index 8e79d0a32..4b89cbed9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -68,7 +68,10 @@ "${workspaceFolder}/extensions/vscode/out/extension.js", "/Users/natesesti/.continue/config.ts" ], - "preLaunchTask": "vscode-extension:build" + "preLaunchTask": "vscode-extension:build", + "env": { + // "CONTROL_PLANE_ENV": "local" + } }, // Has to be run after starting the server (separately or using the compound configuration) { @@ -95,6 +98,41 @@ // Avoid timing out when stopping on breakpoints during debugging in VSCode "MOCHA_TIMEOUT": "0" } + }, + { + "name": "[Core] Jest Test Debugger, Current Open File", + "type": "node", + "request": "launch", + "runtimeArgs": [ + "--inspect-brk", + "${workspaceRoot}/core/node_modules/jest/bin/jest.js", + "--runInBand", + "--config", + "${workspaceRoot}/core/jest.config.js", + "${relativeFile}" + ], + "cwd": "${workspaceRoot}/core", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" } + // { + // "name": "[openai-adapters] Jest Test Debugger, Current Open File", + // "type": "node", + // "request": "launch", + // "runtimeArgs": [ + // "--inspect-brk", + // "${workspaceRoot}/packages/openai-adapters/node_modules/jest/bin/jest.js", + // "--runInBand", + // "--config", + // "${workspaceRoot}/packages/openai-adapters/jest.config.mjs", + // "${relativeFile}" + // ], + // "cwd": "${workspaceRoot}/packages/openai-adapters", + // "console": "integratedTerminal", + // "internalConsoleOptions": "neverOpen", + // "env": { + // "NODE_OPTIONS": "--experimental-vm-modules" + // } + // } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 2224a7a16..49c41d928 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,10 +7,14 @@ "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, "terminal.integrated.defaultProfile.linux": "bash", - "terminal.integrated.profiles.linux": { - "bash": { - "path": "bash", - "args": ["-l"] - } + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash", + "args": ["-l"] } + }, + "search.exclude": { + "./binary": true, + "**/core/vendor/**": true + } } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..52d2a1541 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at hi@continue.dev. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/binary/build.js b/binary/build.js index 5ea5c7aad..506fcb18e 100644 --- a/binary/build.js +++ b/binary/build.js @@ -158,11 +158,18 @@ async function installNodeModuleInTempDirAndCopyToCurrent(packageName, toCopy) { ); }); - fs.copyFileSync( - path.join(__dirname, "../core/vendor/tree-sitter.wasm"), - path.join(__dirname, "out/tree-sitter.wasm"), - ); - console.log("[info] Copied tree-sitter wasms"); + const filesToCopy = [ + "../core/vendor/tree-sitter.wasm", + "../core/llm/llamaTokenizerWorkerPool.mjs", + "../core/llm/llamaTokenizer.mjs", + ]; + for (const f of filesToCopy) { + fs.copyFileSync( + path.join(__dirname, f), + path.join(__dirname, "out", path.basename(f)), + ); + console.log(`[info] Copied ${path.basename(f)}`); + } console.log("[info] Cleaning up artifacts from previous builds..."); diff --git a/binary/package-lock.json b/binary/package-lock.json index 4ed57c259..078ccc165 100644 --- a/binary/package-lock.json +++ b/binary/package-lock.json @@ -46,6 +46,8 @@ "dependencies": { "@aws-sdk/client-bedrock-runtime": "^3.574.0", "@aws-sdk/credential-providers": "^3.596.0", + "@continuedev/config-types": "^1.0.10", + "@continuedev/llm-info": "^1.0.1", "@mozilla/readability": "^0.5.0", "@octokit/rest": "^20.0.2", "@types/jsdom": "^21.1.6", @@ -61,7 +63,7 @@ "commander": "^12.0.0", "comment-json": "^4.2.3", "dbinfoz": "^0.1.4", - "dotenv": "^16.3.1", + "dotenv": "^16.4.5", "fastest-levenshtein": "^1.0.16", "follow-redirects": "^1.15.5", "handlebars": "^4.7.8", @@ -80,6 +82,7 @@ "openai": "^4.20.1", "pg": "^8.11.3", "posthog-node": "^3.6.3", + "quick-lru": "^7.0.0", "replicate": "^0.26.0", "request": "^2.88.2", "socket.io-client": "^4.7.3", @@ -91,7 +94,9 @@ "vectordb": "^0.4.20", "web-tree-sitter": "^0.21.0", "win-ca": "^3.5.1", - "yaml": "^2.4.2" + "workerpool": "^9.1.3", + "yaml": "^2.4.2", + "zod": "^3.23.8" }, "devDependencies": { "@babel/preset-env": "^7.24.7", @@ -106,6 +111,7 @@ "eslint": "^8", "eslint-plugin-import": "^2.29.1", "jest": "^29.7.0", + "myers-diff": "^2.1.0", "onnxruntime-common": "1.14.0", "onnxruntime-web": "1.14.0", "ts-jest": "^29.1.1" diff --git a/binary/test/binary.test.ts b/binary/test/binary.test.ts index 5db4ff52f..fdd9f2ced 100644 --- a/binary/test/binary.test.ts +++ b/binary/test/binary.test.ts @@ -107,7 +107,7 @@ describe("Test Suite", () => { // Many of the files are only created when trying to load the config const config = await messenger.request( - "config/getBrowserSerialized", + "config/getSerializedProfileInfo", undefined, ); @@ -128,8 +128,8 @@ describe("Test Suite", () => { }); it("should properly edit config", async () => { - const config = await messenger.request( - "config/getBrowserSerialized", + const { config } = await messenger.request( + "config/getSerializedProfileInfo", undefined, ); expect(config).toHaveProperty("models"); diff --git a/core/autocomplete/ImportDefinitionsService.ts b/core/autocomplete/ImportDefinitionsService.ts index 19287bf81..a17e3a0c9 100644 --- a/core/autocomplete/ImportDefinitionsService.ts +++ b/core/autocomplete/ImportDefinitionsService.ts @@ -1,11 +1,11 @@ -import { IDE } from ".."; -import { RangeInFileWithContents } from "../commands/util"; -import { PrecalculatedLruCache } from "../util/LruCache"; +import { IDE } from "../index.js"; +import { RangeInFileWithContents } from "../commands/util.js"; +import { PrecalculatedLruCache } from "../util/LruCache.js"; import { TSQueryType, getParserForFile, getQueryForFile, -} from "../util/treeSitter"; +} from "../util/treeSitter.js"; interface FileInfo { imports: { [key: string]: RangeInFileWithContents[] }; diff --git a/core/autocomplete/README.md b/core/autocomplete/README.md index c82509cbd..4e25c9fef 100644 --- a/core/autocomplete/README.md +++ b/core/autocomplete/README.md @@ -90,7 +90,7 @@ This is just another object like the ones in the `"models"` array of `config.jso This object allows you to customize the behavior of tab-autocomplete. The available options are: - `useCopyBuffer`: Determines whether the copy buffer will be considered when constructing the prompt. (Boolean) -- `useSuffix`: Determines whether to use the file suffix in the prompt. (Boolean) +- `useFileSuffix`: Determines whether to use the file suffix in the prompt. (Boolean) - `maxPromptTokens`: The maximum number of prompt tokens to use. A smaller number will yield faster completions, but less context. (Number) - `debounceDelay`: The delay in milliseconds before triggering autocomplete after a keystroke. (Number) - `maxSuffixPercentage`: The maximum percentage of the prompt that can be dedicated to the suffix. (Number) diff --git a/core/autocomplete/completionProvider.ts b/core/autocomplete/completionProvider.ts index 2a54f491d..f74b6c13e 100644 --- a/core/autocomplete/completionProvider.ts +++ b/core/autocomplete/completionProvider.ts @@ -1,10 +1,9 @@ -import Handlebars from "handlebars"; import ignore from "ignore"; import OpenAI from "openai"; import path from "path"; import { v4 as uuidv4 } from "uuid"; import { RangeInFileWithContents } from "../commands/util.js"; -import { IConfigHandler } from "../config/IConfigHandler.js"; +import { ConfigHandler } from "../config/ConfigHandler.js"; import { TRIAL_FIM_MODEL } from "../config/onboarding.js"; import { streamLines } from "../diff/util.js"; import { @@ -29,6 +28,7 @@ import AutocompleteLruCache from "./cache.js"; import { noFirstCharNewline, onlyWhitespaceAfterEndOfLine, + stopAtStopTokens, } from "./charStream.js"; import { constructAutocompletePrompt, @@ -50,6 +50,8 @@ import { AutocompleteSnippet } from "./ranking.js"; import { RecentlyEditedRange } from "./recentlyEdited.js"; import { getTemplateForModel } from "./templates.js"; import { GeneratorReuseManager } from "./util.js"; +// @prettier-ignore +import Handlebars from "handlebars"; export interface AutocompleteInput { completionId: string; @@ -145,7 +147,7 @@ export class CompletionProvider { private static lastUUID: string | undefined = undefined; constructor( - private readonly configHandler: IConfigHandler, + private readonly configHandler: ConfigHandler, private readonly ide: IDE, private readonly getLlm: () => Promise, private readonly _onError: (e: any) => void, @@ -201,13 +203,17 @@ export class CompletionProvider { const outcome = this._outcomes.get(completionId)!; outcome.accepted = true; logDevData("autocomplete", outcome); - Telemetry.capture("autocomplete", { - accepted: outcome.accepted, - modelName: outcome.modelName, - modelProvider: outcome.modelProvider, - time: outcome.time, - cacheHit: outcome.cacheHit, - }); + Telemetry.capture( + "autocomplete", + { + accepted: outcome.accepted, + modelName: outcome.modelName, + modelProvider: outcome.modelProvider, + time: outcome.time, + cacheHit: outcome.cacheHit, + }, + true, + ); this._outcomes.delete(completionId); this.bracketMatchingService.handleAcceptedCompletion( @@ -358,9 +364,13 @@ export class CompletionProvider { outcome.accepted = false; logDevData("autocomplete", outcome); const { prompt, completion, ...restOfOutcome } = outcome; - Telemetry.capture("autocomplete", { - ...restOfOutcome, - }); + Telemetry.capture( + "autocomplete", + { + ...restOfOutcome, + }, + true, + ); this._logRejectionTimeouts.delete(completionId); }, COUNT_COMPLETION_REJECTED_AFTER); this._outcomes.set(completionId, outcome); @@ -572,10 +582,11 @@ export class CompletionProvider { suffix, filename, reponame, + language: lang.name, }); } else { // Let the template function format snippets - prompt = template(prefix, suffix, filepath, reponame, snippets); + prompt = template(prefix, suffix, filepath, reponame, lang.name, snippets); } // Completion @@ -652,6 +663,7 @@ export class CompletionProvider { lang.endOfLine, fullStop, ); + charGenerator = stopAtStopTokens(charGenerator, stop); charGenerator = this.bracketMatchingService.stopOnUnmatchedClosingBracket( charGenerator, prefix, diff --git a/core/autocomplete/languages.ts b/core/autocomplete/languages.ts index 3360c3a9b..a558dee00 100644 --- a/core/autocomplete/languages.ts +++ b/core/autocomplete/languages.ts @@ -1,6 +1,7 @@ import type { LineFilter } from "./lineStream"; export interface AutocompleteLanguageInfo { + name: string; topLevelKeywords: string[]; singleLineComment: string; endOfLine: string[]; @@ -14,6 +15,7 @@ export interface AutocompleteLanguageInfo { // TypeScript export const Typescript = { + name: "TypeScript", topLevelKeywords: ["function", "class", "module", "export", "import"], singleLineComment: "//", endOfLine: [";"], @@ -21,6 +23,7 @@ export const Typescript = { // Python export const Python = { + name: "Python", // """"#" is for .ipynb files, where we add '"""' surrounding markdown blocks. // This stops the model from trying to complete the start of a new markdown block topLevelKeywords: ["def", "class", '"""#'], @@ -30,6 +33,7 @@ export const Python = { // Java export const Java = { + name: "Java", topLevelKeywords: ["class", "function"], singleLineComment: "//", endOfLine: [";"], @@ -37,6 +41,7 @@ export const Java = { // C++ export const Cpp = { + name: "C++", topLevelKeywords: ["class", "namespace", "template"], singleLineComment: "//", endOfLine: [";"], @@ -44,6 +49,7 @@ export const Cpp = { // C# export const CSharp = { + name: "C#", topLevelKeywords: ["class", "namespace", "void"], singleLineComment: "//", endOfLine: [";"], @@ -51,6 +57,7 @@ export const CSharp = { // C export const C = { + name: "C", topLevelKeywords: ["if", "else", "while", "for", "switch", "case"], singleLineComment: "//", endOfLine: [";"], @@ -58,6 +65,7 @@ export const C = { // Scala export const Scala = { + name: "Scala", topLevelKeywords: ["def", "val", "var", "class", "object", "trait"], singleLineComment: "//", endOfLine: [";"], @@ -65,6 +73,7 @@ export const Scala = { // Go export const Go = { + name: "Go", topLevelKeywords: ["func", "package", "import", "type"], singleLineComment: "//", endOfLine: [], @@ -72,6 +81,7 @@ export const Go = { // Rust export const Rust = { + name: "Rust", topLevelKeywords: ["fn", "mod", "pub", "struct", "enum", "trait"], singleLineComment: "//", endOfLine: [";"], @@ -79,6 +89,7 @@ export const Rust = { // Haskell export const Haskell = { + name: "Haskell", topLevelKeywords: [ "data", "type", @@ -95,6 +106,7 @@ export const Haskell = { // PHP export const PHP = { + name: "PHP", topLevelKeywords: ["function", "class", "namespace", "use"], singleLineComment: "//", endOfLine: [";"], @@ -102,6 +114,7 @@ export const PHP = { // Ruby on Rails export const RubyOnRails = { + name: "Ruby on Rails", topLevelKeywords: ["def", "class", "module"], singleLineComment: "#", endOfLine: [], @@ -109,6 +122,7 @@ export const RubyOnRails = { // Swift export const Swift = { + name: "Swift", topLevelKeywords: ["func", "class", "struct", "import"], singleLineComment: "//", endOfLine: [";"], @@ -116,6 +130,7 @@ export const Swift = { // Kotlin export const Kotlin = { + name: "Kotlin", topLevelKeywords: ["fun", "class", "package", "import"], singleLineComment: "//", endOfLine: [";"], @@ -123,6 +138,7 @@ export const Kotlin = { // Ruby export const Ruby = { + name: "Ruby", topLevelKeywords: ["class", "module", "def"], singleLineComment: "#", endOfLine: [], @@ -130,6 +146,7 @@ export const Ruby = { // Clojure export const Clojure = { + name: "Clojure", topLevelKeywords: ["def", "fn", "let", "do", "if", "defn", "ns", "defmacro"], singleLineComment: ";", endOfLine: [], @@ -137,6 +154,7 @@ export const Clojure = { // Julia export const Julia = { + name: "Julia", topLevelKeywords: [ "function", "macro", @@ -155,6 +173,7 @@ export const Julia = { // F# export const FSharp = { + name: "F#", topLevelKeywords: [ "let", "type", @@ -173,6 +192,7 @@ export const FSharp = { // R export const R = { + name: "R", topLevelKeywords: [ "function", "if", @@ -189,6 +209,7 @@ export const R = { // Dart export const Dart = { + name: "Dart", topLevelKeywords: ["class", "import", "void", "enum"], singleLineComment: "//", endOfLine: [";"], @@ -196,6 +217,7 @@ export const Dart = { // Solidity export const Solidity = { + name: "Solidity", topLevelKeywords: [ "contract", "event", @@ -218,6 +240,7 @@ export const Solidity = { // YAML export const YAML: AutocompleteLanguageInfo = { + name: "YAML", topLevelKeywords: [], singleLineComment: "#", endOfLine: [], @@ -258,6 +281,7 @@ export const YAML: AutocompleteLanguageInfo = { }; export const Markdown: AutocompleteLanguageInfo = { + name: "Markdown", topLevelKeywords: [], singleLineComment: "", endOfLine: [], diff --git a/core/autocomplete/templates.ts b/core/autocomplete/templates.ts index 4de43739a..53aa034a9 100644 --- a/core/autocomplete/templates.ts +++ b/core/autocomplete/templates.ts @@ -19,6 +19,7 @@ interface AutocompleteTemplate { suffix: string, filepath: string, reponame: string, + language: string, snippets: AutocompleteSnippet[], ) => string); completionOptions?: Partial; @@ -78,6 +79,7 @@ const codestralMultifileFimTemplate: AutocompleteTemplate = { suffix: string, filepath: string, reponame: string, + language: string, snippets: AutocompleteSnippet[], ): string => { return `[SUFFIX]${suffix}[PREFIX]${prefix}`; @@ -109,6 +111,7 @@ const starcoder2FimTemplate: AutocompleteTemplate = { suffix: string, filename: string, reponame: string, + language: string, snippets: AutocompleteSnippet[], ): string => { const otherFiles = @@ -155,9 +158,40 @@ const deepseekFimTemplate: AutocompleteTemplate = { }, }; -const deepseekFimTemplateWrongPipeChar: AutocompleteTemplate = { - template: "<|fim▁begin|>{{{prefix}}}<|fim▁hole|>{{{suffix}}}<|fim▁end|>", - completionOptions: { stop: ["<|fim▁begin|>", "<|fim▁hole|>", "<|fim▁end|>"] }, +// https://github.com/THUDM/CodeGeeX4/blob/main/guides/Infilling_guideline.md +const codegeexFimTemplate: AutocompleteTemplate = { + template: ( + prefix: string, + suffix: string, + filepath: string, + reponame: string, + language: string, + snippets: AutocompleteSnippet[], + ): string => { + const relativePaths = shortestRelativePaths([ + ...snippets.map((snippet) => snippet.filepath), + filepath, + ]); + const baseTemplate = `###PATH:${relativePaths[relativePaths.length - 1]}\n###LANGUAGE:${language}\n###MODE:BLOCK\n<|code_suffix|>${suffix}<|code_prefix|>${prefix}<|code_middle|>`; + if (snippets.length == 0) { + return `<|user|>\n${baseTemplate}<|assistant|>\n`; + } + const references = `###REFERENCE:\n${snippets + .map((snippet, i) => `###PATH:${relativePaths[i]}\n${snippet.contents}\n`) + .join("###REFERENCE:\n")}`; + const prompt = `<|user|>\n${references}\n${baseTemplate}<|assistant|>\n`; + return prompt; + }, + completionOptions: { + stop: [ + "<|user|>", + "<|code_suffix|>", + "<|code_prefix|>", + "<|code_middle|>", + "<|assistant|>", + "<|endoftext|>", + ], + }, }; const gptAutocompleteTemplate: AutocompleteTemplate = { @@ -175,6 +209,7 @@ const holeFillerTemplate: AutocompleteTemplate = { suffix: string, filename: string, reponame: string, + language: string, snippets: AutocompleteSnippet[], ) => { // From https://github.com/VictorTaelin/AI-scripts @@ -307,6 +342,10 @@ export function getTemplateForModel(model: string): AutocompleteTemplate { return deepseekFimTemplate; } + if (lowerCaseModel.includes("codegeex")) { + return codegeexFimTemplate; + } + if ( lowerCaseModel.includes("gpt") || lowerCaseModel.includes("davinci-002") || diff --git a/core/commands/index.ts b/core/commands/index.ts index 6978b3fcf..2b1a67bbd 100644 --- a/core/commands/index.ts +++ b/core/commands/index.ts @@ -3,7 +3,7 @@ import { SlashCommand, SlashCommandDescription, } from "../index.js"; -import { stripImages } from "../llm/countTokens.js"; +import { stripImages } from "../llm/images.js"; import { renderTemplatedString } from "../llm/llms/index.js"; import SlashCommands from "./slash/index.js"; diff --git a/core/commands/slash/commit.ts b/core/commands/slash/commit.ts index 37985dd1f..899222998 100644 --- a/core/commands/slash/commit.ts +++ b/core/commands/slash/commit.ts @@ -1,5 +1,5 @@ import { SlashCommand } from "../../index.js"; -import { stripImages } from "../../llm/countTokens.js"; +import { stripImages } from "../../llm/images.js"; const CommitMessageCommand: SlashCommand = { name: "commit", diff --git a/core/commands/slash/draftIssue.ts b/core/commands/slash/draftIssue.ts index 0149f253d..25da6b559 100644 --- a/core/commands/slash/draftIssue.ts +++ b/core/commands/slash/draftIssue.ts @@ -1,5 +1,5 @@ import { ChatMessage, SlashCommand } from "../../index.js"; -import { stripImages } from "../../llm/countTokens.js"; +import { stripImages } from "../../llm/images.js"; import { removeQuotesAndEscapes } from "../../util/index.js"; const PROMPT = ( diff --git a/core/commands/slash/edit.ts b/core/commands/slash/edit.ts index 44ae2c9ed..a0fbfdd26 100644 --- a/core/commands/slash/edit.ts +++ b/core/commands/slash/edit.ts @@ -8,7 +8,7 @@ import { } from "../../autocomplete/lineStream.js"; import { streamLines } from "../../diff/util.js"; import { ContextItemWithId, ILLM, SlashCommand } from "../../index.js"; -import { stripImages } from "../../llm/countTokens.js"; +import { stripImages } from "../../llm/images.js"; import { dedentAndGetCommonWhitespace, getMarkdownLanguageTagForFile, diff --git a/core/commands/slash/review.ts b/core/commands/slash/review.ts index aebefc33a..34859d94c 100644 --- a/core/commands/slash/review.ts +++ b/core/commands/slash/review.ts @@ -1,5 +1,5 @@ import { ChatMessage, SlashCommand } from "../../index.js"; -import { stripImages } from "../../llm/countTokens.js"; +import { stripImages } from "../../llm/images.js"; const prompt = ` Review the following code, focusing on Readability, Maintainability, Code Smells, Speed, and Memory Performance. Provide feedback with these guidelines: diff --git a/core/commands/slash/share.ts b/core/commands/slash/share.ts index 1b52116a0..a615ec70d 100644 --- a/core/commands/slash/share.ts +++ b/core/commands/slash/share.ts @@ -3,7 +3,7 @@ import { homedir } from "node:os"; import path from "path"; import { languageForFilepath } from "../../autocomplete/constructPrompt.js"; import { SlashCommand } from "../../index.js"; -import { stripImages } from "../../llm/countTokens.js"; +import { stripImages } from "../../llm/images.js"; // If useful elsewhere, helper funcs should move to core/util/index.ts or similar function getOffsetDatetime(date: Date): Date { diff --git a/core/commands/slash/stackOverflow.ts b/core/commands/slash/stackOverflow.ts index 777a39722..92a34a988 100644 --- a/core/commands/slash/stackOverflow.ts +++ b/core/commands/slash/stackOverflow.ts @@ -1,6 +1,7 @@ import { constants } from "../../deploy/constants.js"; import { ChatMessageRole, FetchFunction, SlashCommand } from "../../index.js"; -import { pruneStringFromBottom, stripImages } from "../../llm/countTokens.js"; +import { pruneStringFromBottom } from "../../llm/countTokens.js"; +import { stripImages } from "../../llm/images.js"; const PROMPT = ( input: string, diff --git a/core/config/ConfigHandler.ts b/core/config/ConfigHandler.ts index 1d9a8c958..2180ce0a1 100644 --- a/core/config/ConfigHandler.ts +++ b/core/config/ConfigHandler.ts @@ -1,116 +1,277 @@ +import { + ControlPlaneClient, + ControlPlaneSessionInfo, +} from "../control-plane/client.js"; import { BrowserSerializedContinueConfig, ContinueConfig, - ContinueRcJson, IContextProvider, IDE, IdeSettings, ILLM, } from "../index.js"; -import { Telemetry } from "../util/posthog.js"; -import { IConfigHandler } from "./IConfigHandler.js"; -import { finalToBrowserConfig, loadFullConfigNode } from "./load.js"; +import { GlobalContext } from "../util/GlobalContext.js"; +import { finalToBrowserConfig } from "./load.js"; +import ControlPlaneProfileLoader from "./profile/ControlPlaneProfileLoader.js"; +import { IProfileLoader } from "./profile/IProfileLoader.js"; +import LocalProfileLoader from "./profile/LocalProfileLoader.js"; -export class ConfigHandler implements IConfigHandler { +export interface ProfileDescription { + title: string; + id: string; +} + +// Separately manages saving/reloading each profile +class ProfileLifecycleManager { private savedConfig: ContinueConfig | undefined; private savedBrowserConfig?: BrowserSerializedContinueConfig; + private pendingConfigPromise?: Promise; + + constructor(private readonly profileLoader: IProfileLoader) {} + + get profileId() { + return this.profileLoader.profileId; + } + + get profileTitle() { + return this.profileLoader.profileTitle; + } + + get profileDescription(): ProfileDescription { + return { + title: this.profileTitle, + id: this.profileId, + }; + } + + clearConfig() { + this.savedConfig = undefined; + this.savedBrowserConfig = undefined; + this.pendingConfigPromise = undefined; + } + + // Clear saved config and reload + reloadConfig(): Promise { + this.savedConfig = undefined; + this.savedBrowserConfig = undefined; + this.pendingConfigPromise = undefined; + + return this.profileLoader.doLoadConfig(); + } + + async loadConfig( + additionalContextProviders: IContextProvider[], + ): Promise { + // If we already have a config, return it + if (this.savedConfig) { + return this.savedConfig; + } else if (this.pendingConfigPromise) { + return this.pendingConfigPromise; + } + + // Set pending config promise + this.pendingConfigPromise = new Promise(async (resolve, reject) => { + const newConfig = await this.profileLoader.doLoadConfig(); + + // Add registered context providers + newConfig.contextProviders = (newConfig.contextProviders ?? []).concat( + additionalContextProviders, + ); + + this.savedConfig = newConfig; + resolve(newConfig); + }); + + // Wait for the config promise to resolve + this.savedConfig = await this.pendingConfigPromise; + this.pendingConfigPromise = undefined; + return this.savedConfig; + } + + async getSerializedConfig( + additionalContextProviders: IContextProvider[], + ): Promise { + if (!this.savedBrowserConfig) { + const continueConfig = await this.loadConfig(additionalContextProviders); + this.savedBrowserConfig = finalToBrowserConfig(continueConfig); + } + return this.savedBrowserConfig; + } +} + +export class ConfigHandler { + private readonly globalContext = new GlobalContext(); private additionalContextProviders: IContextProvider[] = []; + private profiles: ProfileLifecycleManager[]; + private selectedProfileId: string; + + // This will be the local profile + private get fallbackProfile() { + return this.profiles[0]; + } + + get currentProfile() { + return ( + this.profiles.find((p) => p.profileId === this.selectedProfileId) ?? + this.fallbackProfile + ); + } + + get inactiveProfiles() { + return this.profiles.filter((p) => p.profileId !== this.selectedProfileId); + } + + private async fetchControlPlaneProfiles() { + // Get the profiles and create their lifecycle managers + this.controlPlaneClient.listWorkspaces().then(async (workspaces) => { + this.profiles = this.profiles.filter( + (profile) => profile.profileId === "local", + ); + workspaces.forEach((workspace) => { + const profileLoader = new ControlPlaneProfileLoader( + workspace.id, + workspace.name, + this.controlPlaneClient, + this.ide, + this.ideSettingsPromise, + this.writeLog, + this.reloadConfig.bind(this), + ); + this.profiles.push(new ProfileLifecycleManager(profileLoader)); + }); + + this.notifyProfileListeners( + this.profiles.map((profile) => profile.profileDescription), + ); + + // Check the last selected workspace, and reload if it isn't local + const workspaceId = await this.getWorkspaceId(); + const lastSelectedWorkspaceIds = + this.globalContext.get("lastSelectedProfileForWorkspace") ?? {}; + const selectedWorkspaceId = lastSelectedWorkspaceIds[workspaceId]; + if (selectedWorkspaceId) { + this.selectedProfileId = selectedWorkspaceId; + this.loadConfig(); + } else { + // Otherwise we stick with local profile, and record choice + lastSelectedWorkspaceIds[workspaceId] = this.selectedProfileId; + this.globalContext.update( + "lastSelectedProfileForWorkspace", + lastSelectedWorkspaceIds, + ); + } + }); + } constructor( private readonly ide: IDE, private ideSettingsPromise: Promise, private readonly writeLog: (text: string) => Promise, + private controlPlaneClient: ControlPlaneClient, ) { this.ide = ide; this.ideSettingsPromise = ideSettingsPromise; this.writeLog = writeLog; + + // Set local profile as default + const localProfileLoader = new LocalProfileLoader( + ide, + ideSettingsPromise, + controlPlaneClient, + writeLog, + ); + this.profiles = [new ProfileLifecycleManager(localProfileLoader)]; + this.selectedProfileId = localProfileLoader.profileId; + + // Always load local profile immediately in case control plane doesn't load try { this.loadConfig(); } catch (e) { console.error("Failed to load config: ", e); } + + // Load control plane profiles + this.fetchControlPlaneProfiles(); } + async setSelectedProfile(profileId: string) { + this.selectedProfileId = profileId; + const newConfig = await this.loadConfig(); + this.notifyConfigListeners(newConfig); + const selectedProfiles = + this.globalContext.get("lastSelectedProfileForWorkspace") ?? {}; + selectedProfiles[await this.getWorkspaceId()] = profileId; + this.globalContext.update( + "lastSelectedProfileForWorkspace", + selectedProfiles, + ); + } + + // A unique ID for the current workspace, built from folder names + private async getWorkspaceId(): Promise { + const dirs = await this.ide.getWorkspaceDirs(); + return dirs.join("&"); + } + + // Automatically refresh config when Continue-related IDE (e.g. VS Code) settings are changed updateIdeSettings(ideSettings: IdeSettings) { this.ideSettingsPromise = Promise.resolve(ideSettings); this.reloadConfig(); } + updateControlPlaneSessionInfo( + sessionInfo: ControlPlaneSessionInfo | undefined, + ) { + this.controlPlaneClient = new ControlPlaneClient( + Promise.resolve(sessionInfo), + ); + this.fetchControlPlaneProfiles(); + } + + private profilesListeners: ((profiles: ProfileDescription[]) => void)[] = []; + onDidChangeAvailableProfiles( + listener: (profiles: ProfileDescription[]) => void, + ) { + this.profilesListeners.push(listener); + } + + private notifyProfileListeners(profiles: ProfileDescription[]) { + for (const listener of this.profilesListeners) { + listener(profiles); + } + } + + private notifyConfigListeners(newConfig: ContinueConfig) { + // Notify listeners that config changed + for (const listener of this.updateListeners) { + listener(newConfig); + } + } + private updateListeners: ((newConfig: ContinueConfig) => void)[] = []; onConfigUpdate(listener: (newConfig: ContinueConfig) => void) { this.updateListeners.push(listener); } async reloadConfig() { - this.savedConfig = undefined; - this.savedBrowserConfig = undefined; - this._pendingConfigPromise = undefined; - - const newConfig = await this.loadConfig(); - - for (const listener of this.updateListeners) { - listener(newConfig); - } + // TODO: this isn't right, there are two different senses in which you want to "reload" + const newConfig = await this.currentProfile.reloadConfig(); + this.inactiveProfiles.forEach((profile) => profile.clearConfig()); + this.notifyConfigListeners(newConfig); } - async getSerializedConfig(): Promise { - if (!this.savedBrowserConfig) { - this.savedConfig = await this.loadConfig(); - this.savedBrowserConfig = finalToBrowserConfig(this.savedConfig); - } - return this.savedBrowserConfig; + getSerializedConfig(): Promise { + return this.currentProfile.getSerializedConfig( + this.additionalContextProviders, + ); + } + + listProfiles(): ProfileDescription[] { + return this.profiles.map((p) => p.profileDescription); } - private _pendingConfigPromise?: Promise; async loadConfig(): Promise { - if (this.savedConfig) { - return this.savedConfig; - } else if (this._pendingConfigPromise) { - return this._pendingConfigPromise; - } - - this._pendingConfigPromise = new Promise(async (resolve, reject) => { - let workspaceConfigs: ContinueRcJson[] = []; - try { - workspaceConfigs = await this.ide.getWorkspaceConfigs(); - } catch (e) { - console.warn("Failed to load workspace configs"); - } - - const ideInfo = await this.ide.getIdeInfo(); - const uniqueId = await this.ide.getUniqueId(); - const ideSettings = await this.ideSettingsPromise; - - const newConfig = await loadFullConfigNode( - this.ide, - workspaceConfigs, - ideSettings, - ideInfo.ideType, - uniqueId, - this.writeLog, - ); - newConfig.allowAnonymousTelemetry = - newConfig.allowAnonymousTelemetry && - (await this.ide.isTelemetryEnabled()); - - // Setup telemetry only after (and if) we know it is enabled - await Telemetry.setup( - newConfig.allowAnonymousTelemetry ?? true, - await this.ide.getUniqueId(), - ideInfo.extensionVersion, - ); - - (newConfig.contextProviders ?? []).push( - ...this.additionalContextProviders, - ); - - this.savedConfig = newConfig; - resolve(newConfig); - }); - - this.savedConfig = await this._pendingConfigPromise; - this._pendingConfigPromise = undefined; - return this.savedConfig; + return this.currentProfile.loadConfig(this.additionalContextProviders); } async llmFromTitle(title?: string): Promise { diff --git a/core/config/IConfigHandler.ts b/core/config/IConfigHandler.ts deleted file mode 100644 index 8177e7e03..000000000 --- a/core/config/IConfigHandler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { - BrowserSerializedContinueConfig, - ContinueConfig, - IContextProvider, - IdeSettings, - ILLM, -} from "../index.js"; - -export interface IConfigHandler { - updateIdeSettings(ideSettings: IdeSettings): void; - onConfigUpdate(listener: (newConfig: ContinueConfig) => void): void; - reloadConfig(): Promise; - getSerializedConfig(): Promise; - loadConfig(): Promise; - llmFromTitle(title?: string): Promise; - registerCustomContextProvider(contextProvider: IContextProvider): void; -} diff --git a/core/config/default.ts b/core/config/default.ts index 08d28d649..b4a05f6f5 100644 --- a/core/config/default.ts +++ b/core/config/default.ts @@ -32,39 +32,21 @@ export const FREE_TRIAL_MODELS: ModelDescription[] = [ }, ]; -export const defaultConfig: SerializedContinueConfig = { - models: [], - customCommands: [ - { - name: "test", - prompt: - "{{{ input }}}\n\nWrite a comprehensive set of unit tests for the selected code. It should setup, run tests that check for correctness including important edge cases, and teardown. Ensure that the tests are complete and sophisticated. Give the tests just as chat output, don't edit any file.", - description: "Write unit tests for highlighted code", - }, - ], - tabAutocompleteModel: { - title: "Starcoder2 3b", - provider: "ollama", - model: "starcoder2:3b", - }, -}; +export const defaultContextProvidersVsCode: ContextProviderWithParams[] = [ + { name: "code", params: {} }, + { name: "docs", params: {} }, + { name: "diff", params: {} }, + { name: "terminal", params: {} }, + { name: "problems", params: {} }, + { name: "folder", params: {} }, + { name: "codebase", params: {} }, +]; -export const defaultConfigJetBrains: SerializedContinueConfig = { - models: FREE_TRIAL_MODELS, - customCommands: [ - { - name: "test", - prompt: - "{{{ input }}}\n\nWrite a comprehensive set of unit tests for the selected code. It should setup, run tests that check for correctness including important edge cases, and teardown. Ensure that the tests are complete and sophisticated. Give the tests just as chat output, don't edit any file.", - description: "Write unit tests for highlighted code", - }, - ], - tabAutocompleteModel: { - title: "Starcoder2 3b", - provider: "ollama", - model: "starcoder2:3b", - }, -}; +export const defaultContextProvidersJetBrains: ContextProviderWithParams[] = [ + { name: "diff", params: {} }, + { name: "folder", params: {} }, + { name: "codebase", params: {} }, +]; export const defaultSlashCommandsVscode: SlashCommandDescription[] = [ { @@ -108,18 +90,40 @@ export const defaultSlashCommandsJetBrains = [ }, ]; -export const defaultContextProvidersVsCode: ContextProviderWithParams[] = [ - { name: "code", params: {} }, - { name: "docs", params: {} }, - { name: "diff", params: {} }, - { name: "terminal", params: {} }, - { name: "problems", params: {} }, - { name: "folder", params: {} }, - { name: "codebase", params: {} }, -]; +export const defaultConfig: SerializedContinueConfig = { + models: [], + customCommands: [ + { + name: "test", + prompt: + "{{{ input }}}\n\nWrite a comprehensive set of unit tests for the selected code. It should setup, run tests that check for correctness including important edge cases, and teardown. Ensure that the tests are complete and sophisticated. Give the tests just as chat output, don't edit any file.", + description: "Write unit tests for highlighted code", + }, + ], + tabAutocompleteModel: { + title: "Starcoder2 3b", + provider: "ollama", + model: "starcoder2:3b", + }, + contextProviders: defaultContextProvidersVsCode, + slashCommands: defaultSlashCommandsVscode, +}; -export const defaultContextProvidersJetBrains: ContextProviderWithParams[] = [ - { name: "diff", params: {} }, - { name: "folder", params: {} }, - { name: "codebase", params: {} }, -]; +export const defaultConfigJetBrains: SerializedContinueConfig = { + models: FREE_TRIAL_MODELS, + customCommands: [ + { + name: "test", + prompt: + "{{{ input }}}\n\nWrite a comprehensive set of unit tests for the selected code. It should setup, run tests that check for correctness including important edge cases, and teardown. Ensure that the tests are complete and sophisticated. Give the tests just as chat output, don't edit any file.", + description: "Write unit tests for highlighted code", + }, + ], + tabAutocompleteModel: { + title: "Starcoder2 3b", + provider: "ollama", + model: "starcoder2:3b", + }, + contextProviders: defaultContextProvidersJetBrains, + slashCommands: defaultSlashCommandsJetBrains, +}; diff --git a/core/config/load.ts b/core/config/load.ts index 69521ddaa..faf65dfc9 100644 --- a/core/config/load.ts +++ b/core/config/load.ts @@ -36,6 +36,8 @@ import CustomLLMClass from "../llm/llms/CustomLLM.js"; import FreeTrial from "../llm/llms/FreeTrial.js"; import { llmFromDescription } from "../llm/llms/index.js"; +import CodebaseContextProvider from "../context/providers/CodebaseContextProvider.js"; +import ContinueProxyContextProvider from "../context/providers/ContinueProxyContextProvider.js"; import { fetchwithRequestOptions } from "../util/fetchWithOptions.js"; import { copyOf } from "../util/index.js"; import mergeJson from "../util/merge.js"; @@ -46,7 +48,6 @@ import { getConfigJsonPathForRemote, getConfigTsPath, getContinueDotEnv, - migrate, readAllGlobalPromptFiles, } from "../util/paths.js"; import { @@ -60,6 +61,7 @@ import { getPromptFiles, slashCommandFromPromptFile, } from "./promptFile.js"; + const { execSync } = require("child_process"); function resolveSerializedConfig(filepath: string): SerializedContinueConfig { @@ -95,32 +97,22 @@ function loadSerializedConfig( workspaceConfigs: ContinueRcJson[], ideSettings: IdeSettings, ideType: IdeType, + overrideConfigJson: SerializedContinueConfig | undefined, ): SerializedContinueConfig { const configPath = getConfigJsonPath(ideType); - let config: SerializedContinueConfig; - try { - config = resolveSerializedConfig(configPath); - } catch (e) { - throw new Error(`Failed to parse config.json: ${e}`); + let config: SerializedContinueConfig = overrideConfigJson!; + if (!config) { + try { + config = resolveSerializedConfig(configPath); + } catch (e) { + throw new Error(`Failed to parse config.json: ${e}`); + } } if (config.allowAnonymousTelemetry === undefined) { config.allowAnonymousTelemetry = true; } - migrate("codeContextProvider", () => { - const gpt = config.models.find( - (model) => - model.model.startsWith("gpt-4") && model.provider === "free-trial", - ); - if (gpt) { - gpt.systemMessage = - "You are an expert software developer. You give helpful and concise responses."; - } - - fs.writeFileSync(configPath, JSON.stringify(config, undefined, 2), "utf8"); - }); - if (ideSettings.remoteConfigServerUrl) { try { const remoteConfigJson = resolveSerializedConfig( @@ -157,6 +149,7 @@ function loadSerializedConfig( async function serializedToIntermediateConfig( initial: SerializedContinueConfig, ide: IDE, + loadPromptFiles: boolean = true, ): Promise { const slashCommands: SlashCommand[] = []; for (const command of initial.slashCommands || []) { @@ -172,25 +165,27 @@ async function serializedToIntermediateConfig( const workspaceDirs = await ide.getWorkspaceDirs(); const promptFolder = initial.experimental?.promptPath; - let promptFiles: { path: string; content: string }[] = []; - promptFiles = ( - await Promise.all( - workspaceDirs.map((dir) => - getPromptFiles( - ide, - path.join(dir, promptFolder ?? DEFAULT_PROMPTS_FOLDER), + if (loadPromptFiles) { + let promptFiles: { path: string; content: string }[] = []; + promptFiles = ( + await Promise.all( + workspaceDirs.map((dir) => + getPromptFiles( + ide, + path.join(dir, promptFolder ?? DEFAULT_PROMPTS_FOLDER), + ), ), - ), + ) ) - ) - .flat() - .filter(({ path }) => path.endsWith(".prompt")); + .flat() + .filter(({ path }) => path.endsWith(".prompt")); - // Also read from ~/.continue/.prompts - promptFiles.push(...readAllGlobalPromptFiles()); + // Also read from ~/.continue/.prompts + promptFiles.push(...readAllGlobalPromptFiles()); - for (const file of promptFiles) { - slashCommands.push(slashCommandFromPromptFile(file.path, file.content)); + for (const file of promptFiles) { + slashCommands.push(slashCommandFromPromptFile(file.path, file.content)); + } } const config: Config = { @@ -221,9 +216,11 @@ async function intermediateToFinalConfig( ideSettings: IdeSettings, uniqueId: string, writeLog: (log: string) => Promise, + workOsAccessToken: string | undefined, + allowFreeTrial: boolean = true, ): Promise { // Auto-detect models - const models: BaseLLM[] = []; + let models: BaseLLM[] = []; for (const desc of config.models) { if (isModelDescription(desc)) { const llm = await llmFromDescription( @@ -304,15 +301,20 @@ async function intermediateToFinalConfig( }; } - // Obtain auth token (only if free trial being used) - const freeTrialModels = models.filter( - (model) => model.providerName === "free-trial", - ); - if (freeTrialModels.length > 0) { - const ghAuthToken = await ide.getGitHubAuthToken(); - for (const model of freeTrialModels) { - (model as FreeTrial).setupGhAuthToken(ghAuthToken); + if (allowFreeTrial) { + // Obtain auth token (iff free trial being used) + const freeTrialModels = models.filter( + (model) => model.providerName === "free-trial", + ); + if (freeTrialModels.length > 0) { + const ghAuthToken = await ide.getGitHubAuthToken(); + for (const model of freeTrialModels) { + (model as FreeTrial).setupGhAuthToken(ghAuthToken); + } } + } else { + // Remove free trial models + models = models.filter((model) => model.providerName !== "free-trial"); } // Tab autocomplete model @@ -336,6 +338,10 @@ async function intermediateToFinalConfig( ); if (llm?.providerName === "free-trial") { + if (!allowFreeTrial) { + // This shouldn't happen + throw new Error("Free trial cannot be used with control plane"); + } const ghAuthToken = await ide.getGitHubAuthToken(); (llm as FreeTrial).setupGhAuthToken(ghAuthToken); } @@ -348,16 +354,39 @@ async function intermediateToFinalConfig( ).filter((x) => x !== undefined) as BaseLLM[]; } + // These context providers are always included, regardless of what, if anything, + // the user has configured in config.json + const DEFAULT_CONTEXT_PROVIDERS = [ + new FileContextProvider({}), + new CodebaseContextProvider({}), + ]; + + const DEFAULT_CONTEXT_PROVIDERS_TITLES = DEFAULT_CONTEXT_PROVIDERS.map( + ({ description: { title } }) => title, + ); + // Context providers - const contextProviders: IContextProvider[] = [new FileContextProvider({})]; + const contextProviders: IContextProvider[] = DEFAULT_CONTEXT_PROVIDERS; + for (const provider of config.contextProviders || []) { if (isContextProviderWithParams(provider)) { const cls = contextProviderClassFromName(provider.name) as any; if (!cls) { - console.warn(`Unknown context provider ${provider.name}`); + if (!DEFAULT_CONTEXT_PROVIDERS_TITLES.includes(provider.name)) { + console.warn(`Unknown context provider ${provider.name}`); + } + continue; } - contextProviders.push(new cls(provider.params)); + const instance: IContextProvider = new cls(provider.params); + + // Handle continue-proxy + if (instance.description.title === "continue-proxy") { + (instance as ContinueProxyContextProvider).workOsAccessToken = + workOsAccessToken; + } + + contextProviders.push(instance); } else { contextProviders.push(new CustomContextProviderClass(provider)); } @@ -537,10 +566,21 @@ async function loadFullConfigNode( ideType: IdeType, uniqueId: string, writeLog: (log: string) => Promise, + workOsAccessToken: string | undefined, + overrideConfigJson: SerializedContinueConfig | undefined, ): Promise { - let serialized = loadSerializedConfig(workspaceConfigs, ideSettings, ideType); + // Serialized config + let serialized = loadSerializedConfig( + workspaceConfigs, + ideSettings, + ideType, + overrideConfigJson, + ); + + // Convert serialized to intermediate config let intermediate = await serializedToIntermediateConfig(serialized, ide); + // Apply config.ts to modify intermediate config const configJsContents = await buildConfigTs(); if (configJsContents) { try { @@ -557,7 +597,7 @@ async function loadFullConfigNode( } } - // Remote config.js + // Apply remote config.js to modify intermediate config if (ideSettings.remoteConfigServerUrl) { try { const configJsPathForRemote = getConfigJsPathForRemote( @@ -574,12 +614,14 @@ async function loadFullConfigNode( } } + // Convert to final config format const finalConfig = await intermediateToFinalConfig( intermediate, ide, ideSettings, uniqueId, writeLog, + workOsAccessToken, ); return finalConfig; } diff --git a/core/config/onboarding.ts b/core/config/onboarding.ts index c1062e421..5b727c34f 100644 --- a/core/config/onboarding.ts +++ b/core/config/onboarding.ts @@ -10,11 +10,6 @@ export function setupApiKeysMode( return { ...config, models: config.models.filter((model) => model.provider !== "free-trial"), - tabAutocompleteModel: { - title: "Tab Autocomplete", - provider: "free-trial", - model: TRIAL_FIM_MODEL, - }, embeddingsProvider: { provider: "free-trial", }, diff --git a/core/config/profile/ControlPlaneProfileLoader.ts b/core/config/profile/ControlPlaneProfileLoader.ts new file mode 100644 index 000000000..0602088bd --- /dev/null +++ b/core/config/profile/ControlPlaneProfileLoader.ts @@ -0,0 +1,57 @@ +import { ConfigJson } from "@continuedev/config-types"; +import { + ContinueConfig, + IDE, + IdeSettings, + SerializedContinueConfig, +} from "../.."; +import { ControlPlaneClient } from "../../control-plane/client"; +import { IProfileLoader } from "./IProfileLoader"; +import doLoadConfig from "./doLoadConfig"; + +export default class ControlPlaneProfileLoader implements IProfileLoader { + private static RELOAD_INTERVAL = 1000 * 60 * 15; // every 15 minutes + + readonly profileId: string; + profileTitle: string; + + workspaceSettings: ConfigJson | undefined; + + constructor( + private readonly workspaceId: string, + private workspaceTitle: string, + private readonly controlPlaneClient: ControlPlaneClient, + private readonly ide: IDE, + private ideSettingsPromise: Promise, + private writeLog: (message: string) => Promise, + private readonly onReload: () => void, + ) { + this.profileId = workspaceId; + this.profileTitle = workspaceTitle; + + setInterval(async () => { + this.workspaceSettings = + await this.controlPlaneClient.getSettingsForWorkspace(this.profileId); + this.onReload(); + }, ControlPlaneProfileLoader.RELOAD_INTERVAL); + } + + async doLoadConfig(): Promise { + const settings = + this.workspaceSettings ?? + ((await this.controlPlaneClient.getSettingsForWorkspace( + this.profileId, + )) as any); + const serializedConfig: SerializedContinueConfig = settings; + + return doLoadConfig( + this.ide, + this.ideSettingsPromise, + this.controlPlaneClient, + this.writeLog, + serializedConfig, + ); + } + + setIsActive(isActive: boolean): void {} +} diff --git a/core/config/profile/IProfileLoader.ts b/core/config/profile/IProfileLoader.ts new file mode 100644 index 000000000..ffd6e94fb --- /dev/null +++ b/core/config/profile/IProfileLoader.ts @@ -0,0 +1,11 @@ +// ProfileHandlers manage the loading of a config, allowing us to abstract over different ways of getting to a ContinueConfig + +import { ContinueConfig } from "../.."; + +// After we have the ContinueConfig, the ConfigHandler takes care of everything else (loading models, lifecycle, etc.) +export interface IProfileLoader { + profileTitle: string; + profileId: string; + doLoadConfig(): Promise; + setIsActive(isActive: boolean): void; +} diff --git a/core/config/profile/LocalProfileLoader.ts b/core/config/profile/LocalProfileLoader.ts new file mode 100644 index 000000000..a79406d49 --- /dev/null +++ b/core/config/profile/LocalProfileLoader.ts @@ -0,0 +1,29 @@ +import { ContinueConfig, IDE, IdeSettings } from "../.."; +import { ControlPlaneClient } from "../../control-plane/client"; +import doLoadConfig from "./doLoadConfig"; +import { IProfileLoader } from "./IProfileLoader"; + +export default class LocalProfileLoader implements IProfileLoader { + static ID = "local"; + profileId = LocalProfileLoader.ID; + profileTitle = "Local Config"; + + constructor( + private ide: IDE, + private ideSettingsPromise: Promise, + private controlPlaneClient: ControlPlaneClient, + private writeLog: (message: string) => Promise, + ) {} + + async doLoadConfig(): Promise { + return doLoadConfig( + this.ide, + this.ideSettingsPromise, + this.controlPlaneClient, + this.writeLog, + undefined, + ); + } + + setIsActive(isActive: boolean): void {} +} diff --git a/core/config/profile/doLoadConfig.ts b/core/config/profile/doLoadConfig.ts new file mode 100644 index 000000000..400e93aa1 --- /dev/null +++ b/core/config/profile/doLoadConfig.ts @@ -0,0 +1,82 @@ +import { + ContinueRcJson, + IDE, + IdeSettings, + SerializedContinueConfig, +} from "../.."; +import { ContinueProxyReranker } from "../../context/rerankers/ContinueProxyReranker"; +import { ControlPlaneClient } from "../../control-plane/client"; +import { TeamAnalytics } from "../../control-plane/TeamAnalytics"; +import ContinueProxyEmbeddingsProvider from "../../indexing/embeddings/ContinueProxyEmbeddingsProvider"; +import ContinueProxy from "../../llm/llms/stubs/ContinueProxy"; +import { Telemetry } from "../../util/posthog"; +import { loadFullConfigNode } from "../load"; + +export default async function doLoadConfig( + ide: IDE, + ideSettingsPromise: Promise, + controlPlaneClient: ControlPlaneClient, + writeLog: (message: string) => Promise, + overrideConfigJson: SerializedContinueConfig | undefined, +) { + let workspaceConfigs: ContinueRcJson[] = []; + try { + workspaceConfigs = await ide.getWorkspaceConfigs(); + } catch (e) { + console.warn("Failed to load workspace configs"); + } + + const ideInfo = await ide.getIdeInfo(); + const uniqueId = await ide.getUniqueId(); + const ideSettings = await ideSettingsPromise; + const workOsAccessToken = await controlPlaneClient.getAccessToken(); + + const newConfig = await loadFullConfigNode( + ide, + workspaceConfigs, + ideSettings, + ideInfo.ideType, + uniqueId, + writeLog, + workOsAccessToken, + overrideConfigJson, + ); + newConfig.allowAnonymousTelemetry = + newConfig.allowAnonymousTelemetry && (await ide.isTelemetryEnabled()); + + // Setup telemetry only after (and if) we know it is enabled + await Telemetry.setup( + newConfig.allowAnonymousTelemetry ?? true, + await ide.getUniqueId(), + ideInfo.extensionVersion, + ); + + if (newConfig.analytics) { + await TeamAnalytics.setup( + newConfig.analytics as any, // TODO: Need to get rid of index.d.ts once and for all + uniqueId, + ideInfo.extensionVersion, + ); + } + + [...newConfig.models, ...(newConfig.tabAutocompleteModels ?? [])].forEach( + async (model) => { + if (model.providerName === "continue-proxy") { + (model as ContinueProxy).workOsAccessToken = workOsAccessToken; + } + }, + ); + + if (newConfig.embeddingsProvider?.providerName === "continue-proxy") { + ( + newConfig.embeddingsProvider as ContinueProxyEmbeddingsProvider + ).workOsAccessToken = workOsAccessToken; + } + + if (newConfig.reranker?.name === "continue-proxy") { + (newConfig.reranker as ContinueProxyReranker).workOsAccessToken = + workOsAccessToken; + } + + return newConfig; +} diff --git a/core/config/promptFile.ts b/core/config/promptFile.ts index a207d1b2c..c6e52234f 100644 --- a/core/config/promptFile.ts +++ b/core/config/promptFile.ts @@ -3,7 +3,7 @@ import path from "path"; import * as YAML from "yaml"; import type { IDE, SlashCommand } from ".."; import { walkDir } from "../indexing/walkDir"; -import { stripImages } from "../llm/countTokens.js"; +import { stripImages } from "../llm/images"; import { renderTemplatedString } from "../llm/llms/index.js"; import { getBasename } from "../util/index.js"; diff --git a/core/config/types.ts b/core/config/types.ts index 30fe8a4c7..d950c15f7 100644 --- a/core/config/types.ts +++ b/core/config/types.ts @@ -523,6 +523,7 @@ declare global { | "gpt-4-32k" | "gpt-4-turbo" | "gpt-4o" + | "gpt-4o-mini" | "gpt-4-turbo-preview" | "gpt-4-vision-preview" // Mistral @@ -676,7 +677,7 @@ declare global { export interface TabAutocompleteOptions { disable: boolean; useCopyBuffer: boolean; - useSuffix: boolean; + useFileSuffix: boolean; maxPromptTokens: number; debounceDelay: number; maxSuffixPercentage: number; diff --git a/core/context/index.ts b/core/context/index.ts index 6e98fa456..7ad48f112 100644 --- a/core/context/index.ts +++ b/core/context/index.ts @@ -6,6 +6,7 @@ import type { IContextProvider, LoadSubmenuItemsArgs, } from "../index.js"; + export abstract class BaseContextProvider implements IContextProvider { options: { [key: string]: any }; diff --git a/core/context/providers/ContinueProxyContextProvider.ts b/core/context/providers/ContinueProxyContextProvider.ts new file mode 100644 index 000000000..dc1c9ef22 --- /dev/null +++ b/core/context/providers/ContinueProxyContextProvider.ts @@ -0,0 +1,76 @@ +import { CONTROL_PLANE_URL } from "../../control-plane/client.js"; +import { + ContextItem, + ContextProviderDescription, + ContextProviderExtras, + ContextSubmenuItem, + LoadSubmenuItemsArgs, +} from "../../index.js"; +import { BaseContextProvider } from "../index.js"; + +class ContinueProxyContextProvider extends BaseContextProvider { + static description: ContextProviderDescription = { + title: "continue-proxy", + displayTitle: "Continue Proxy", + description: "Retrieve a context item from a Continue for Teams add-on", + type: "submenu", + }; + + workOsAccessToken: string | undefined = undefined; + + override get description(): ContextProviderDescription { + return { + title: + this.options.title || ContinueProxyContextProvider.description.title, + displayTitle: + this.options.displayTitle || + ContinueProxyContextProvider.description.displayTitle, + description: + this.options.description || + ContinueProxyContextProvider.description.description, + type: this.options.type || ContinueProxyContextProvider.description.type, + }; + } + + async loadSubmenuItems( + args: LoadSubmenuItemsArgs, + ): Promise { + const response = await args.fetch( + new URL(`/proxy/context/${this.options.id}/list`, CONTROL_PLANE_URL), + { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${this.workOsAccessToken}`, + }, + }, + ); + const data = await response.json(); + return data.items; + } + + async getContextItems( + query: string, + extras: ContextProviderExtras, + ): Promise { + const response = await extras.fetch( + new URL(`/proxy/context/${this.options.id}/retrieve`, CONTROL_PLANE_URL), + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${this.workOsAccessToken}`, + }, + body: JSON.stringify({ + query: query || "", + fullInput: extras.fullInput, + }), + }, + ); + + const items: any = await response.json(); + return items; + } +} + +export default ContinueProxyContextProvider; diff --git a/core/context/providers/DocsContextProvider.ts b/core/context/providers/DocsContextProvider.ts index b9e98c171..c2c6af7f0 100644 --- a/core/context/providers/DocsContextProvider.ts +++ b/core/context/providers/DocsContextProvider.ts @@ -1,14 +1,16 @@ -import fetch from "node-fetch"; import { + Chunk, ContextItem, ContextProviderDescription, ContextProviderExtras, ContextSubmenuItem, + EmbeddingsProvider, LoadSubmenuItemsArgs, + Reranker, } from "../../index.js"; import { DocsService } from "../../indexing/docs/DocsService.js"; -import configs from "../../indexing/docs/preIndexedDocs.js"; -import TransformersJsEmbeddingsProvider from "../../indexing/embeddings/TransformersJsEmbeddingsProvider.js"; +import preIndexedDocs from "../../indexing/docs/preIndexedDocs.js"; +import { Telemetry } from "../../util/posthog.js"; import { BaseContextProvider } from "../index.js"; class DocsContextProvider extends BaseContextProvider { @@ -20,6 +22,7 @@ class DocsContextProvider extends BaseContextProvider { description: "Type to search docs", type: "submenu", }; + private docsService: DocsService; constructor(options: any) { @@ -27,34 +30,96 @@ class DocsContextProvider extends BaseContextProvider { this.docsService = DocsService.getInstance(); } - private async _getIconDataUrl(url: string): Promise { + private async _rerankChunks( + chunks: Chunk[], + reranker: NonNullable, + fullInput: ContextProviderExtras["fullInput"], + ) { + let chunksCopy = [...chunks]; + try { - const response = await fetch(url); - if (!response.headers.get("content-type")?.startsWith("image/")) { - console.log("Not an image: ", await response.text()); - return undefined; - } - const buffer = await response.buffer(); - const base64data = buffer.toString("base64"); - return `data:${response.headers.get("content-type")};base64,${base64data}`; + const scores = await reranker.rerank(fullInput, chunksCopy); + + chunksCopy.sort( + (a, b) => scores[chunksCopy.indexOf(b)] - scores[chunksCopy.indexOf(a)], + ); + + chunksCopy = chunksCopy.splice( + 0, + this.options?.nFinal ?? DocsContextProvider.DEFAULT_N_FINAL, + ); } catch (e) { - console.log("E: ", e); - return undefined; + console.warn(`Failed to rerank docs results: ${e}`); + + chunksCopy = chunksCopy.splice( + 0, + this.options?.nFinal ?? DocsContextProvider.DEFAULT_N_FINAL, + ); } + + return chunksCopy; + } + + private _sortByPreIndexedDocs( + submenuItems: ContextSubmenuItem[], + ): ContextSubmenuItem[] { + // Sort submenuItems such that the objects with titles which don't occur in configs occur first, and alphabetized + return submenuItems.sort((a, b) => { + const aTitleInConfigs = a.metadata?.preIndexed ?? false; + const bTitleInConfigs = b.metadata?.preIndexed ?? false; + + // Primary criterion: Items not in configs come first + if (!aTitleInConfigs && bTitleInConfigs) { + return -1; + } else if (aTitleInConfigs && !bTitleInConfigs) { + return 1; + } else { + // Secondary criterion: Alphabetical order when both items are in the same category + return a.title.toString().localeCompare(b.title.toString()); + } + }); } async getContextItems( query: string, extras: ContextProviderExtras, ): Promise { - // Not supported in JetBrains IDEs right now - if ((await extras.ide.getIdeInfo()).ideType === "jetbrains") { - throw new Error( - "The @docs context provider is not currently supported in JetBrains IDEs. We'll have an update soon!", + const ideInfo = await extras.ide.getIdeInfo(); + const isJetBrains = ideInfo.ideType === "jetbrains"; + + const isJetBrainsAndPreIndexedDocsProvider = + this.docsService.isJetBrainsAndPreIndexedDocsProvider( + ideInfo, + extras.embeddingsProvider.id, ); + + if (isJetBrainsAndPreIndexedDocsProvider) { + extras.ide.errorPopup( + `${DocsService.preIndexedDocsEmbeddingsProvider.id} is configured as ` + + "the embeddings provider, but it cannot be used with JetBrains. " + + "Please select a different embeddings provider to use the '@docs' " + + "context provider.", + ); + + return []; + } + + const preIndexedDoc = preIndexedDocs[query]; + + let embeddingsProvider: EmbeddingsProvider; + + if (!!preIndexedDoc && !isJetBrains) { + // Pre-indexed docs should be filtered out in `loadSubmenuItems`, + // for JetBrains users, but we sanity check that here + Telemetry.capture("docs_pre_indexed_doc_used", { + doc: preIndexedDoc["title"], + }); + + embeddingsProvider = DocsService.preIndexedDocsEmbeddingsProvider; + } else { + embeddingsProvider = extras.embeddingsProvider; } - const embeddingsProvider = new TransformersJsEmbeddingsProvider(); const [vector] = await embeddingsProvider.embed([extras.fullInput]); let chunks = await this.docsService.retrieve( @@ -65,22 +130,11 @@ class DocsContextProvider extends BaseContextProvider { ); if (extras.reranker) { - try { - const scores = await extras.reranker.rerank(extras.fullInput, chunks); - chunks.sort( - (a, b) => scores[chunks.indexOf(b)] - scores[chunks.indexOf(a)], - ); - chunks = chunks.splice( - 0, - this.options?.nFinal ?? DocsContextProvider.DEFAULT_N_FINAL, - ); - } catch (e) { - console.warn(`Failed to rerank docs results: ${e}`); - chunks = chunks.splice( - 0, - this.options?.nFinal ?? DocsContextProvider.DEFAULT_N_FINAL, - ); - } + chunks = await this._rerankChunks( + chunks, + extras.reranker, + extras.fullInput, + ); } return [ @@ -95,7 +149,7 @@ class DocsContextProvider extends BaseContextProvider { .slice(1) .join("/") : chunk.otherMetadata?.title || chunk.filepath, - description: chunk.filepath, // new URL(chunk.filepath, query).toString(), + description: chunk.filepath, content: chunk.content, })) .reverse(), @@ -103,7 +157,10 @@ class DocsContextProvider extends BaseContextProvider { name: "Instructions", description: "Instructions", content: - "Use the above documentation to answer the following question. You should not reference anything outside of what is shown, unless it is a commonly known concept. Reference URLs whenever possible using markdown formatting. If there isn't enough information to answer the question, suggest where the user might look to learn more.", + "Use the above documentation to answer the following question. You should not reference " + + "anything outside of what is shown, unless it is a commonly known concept. Reference URLs " + + "whenever possible using markdown formatting. If there isn't enough information to answer " + + "the question, suggest where the user might look to learn more.", }, ]; } @@ -111,57 +168,50 @@ class DocsContextProvider extends BaseContextProvider { async loadSubmenuItems( args: LoadSubmenuItemsArgs, ): Promise { - const docs = await this.docsService.list(); - const submenuItems: ContextSubmenuItem[] = docs.map((doc) => ({ - title: doc.title, - description: new URL(doc.baseUrl).hostname, - id: doc.baseUrl, - metadata: { - preIndexed: !!configs.find((config) => config.title === doc.title), - }, - })); + const ideInfo = await args.ide.getIdeInfo(); + const isJetBrains = ideInfo.ideType === "jetbrains"; + const configSites = [ + ...new Set([...(this.options?.sites || []), ...(args.config.docs || [])]), + ]; + const submenuItemsMap = new Map(); - submenuItems.push( - ...configs - // After it's actually downloaded, we don't want to show twice - .filter( - (config) => !submenuItems.some((item) => item.id === config.startUrl), - ) - .map((config) => ({ - title: config.title, - description: new URL(config.startUrl).hostname, - id: config.startUrl, + if (!isJetBrains) { + // Currently, we generate and host embeddings for pre-indexed docs using transformers.js. + // However, we don't ship transformers.js with the JetBrains extension. + // So, we only include pre-indexed docs in the submenu for non-JetBrains IDEs. + for (const { startUrl, title } of Object.values(preIndexedDocs)) { + submenuItemsMap.set(startUrl, { + title, + id: startUrl, + description: new URL(startUrl).hostname, metadata: { preIndexed: true, }, - // iconUrl: config.faviconUrl, - })), - ); - - // Sort submenuItems such that the objects with titles which don't occur in configs occur first, and alphabetized - submenuItems.sort((a, b) => { - const aTitleInConfigs = a.metadata?.preIndexed; - const bTitleInConfigs = b.metadata?.preIndexed; - - // Primary criterion: Items not in configs come first - if (!aTitleInConfigs && bTitleInConfigs) { - return -1; - } else if (aTitleInConfigs && !bTitleInConfigs) { - return 1; - } else { - // Secondary criterion: Alphabetical order when both items are in the same category - return a.title.toString().localeCompare(b.title.toString()); + }); } - }); + } - // const icons = await Promise.all( - // submenuItems.map(async (item) => - // item.iconUrl ? this._getIconDataUrl(item.iconUrl) : undefined, - // ), - // ); - // icons.forEach((icon, i) => { - // submenuItems[i].iconUrl = icon; - // }); + for (const { title, baseUrl } of await this.docsService.list()) { + submenuItemsMap.set(baseUrl, { + title, + id: baseUrl, + description: new URL(baseUrl).hostname, + }); + } + + for (const { startUrl, title } of configSites) { + submenuItemsMap.set(startUrl, { + title, + id: startUrl, + description: new URL(startUrl).hostname, + }); + } + + const submenuItems = Array.from(submenuItemsMap.values()); + + if (!isJetBrains) { + return this._sortByPreIndexedDocs(submenuItems); + } return submenuItems; } diff --git a/core/context/providers/index.ts b/core/context/providers/index.ts index 72c47f044..462fe0db4 100644 --- a/core/context/providers/index.ts +++ b/core/context/providers/index.ts @@ -2,6 +2,7 @@ import { ContextProviderName } from "../../index.js"; import { BaseContextProvider } from "../index.js"; import CodeContextProvider from "./CodeContextProvider.js"; import CodebaseContextProvider from "./CodebaseContextProvider.js"; +import ContinueProxyContextProvider from "./ContinueProxyContextProvider.js"; import CurrentFileContextProvider from "./CurrentFileContextProvider.js"; import DatabaseContextProvider from "./DatabaseContextProvider.js"; import DiffContextProvider from "./DiffContextProvider.js"; @@ -40,7 +41,6 @@ const Providers: (typeof BaseContextProvider)[] = [ HttpContextProvider, SearchContextProvider, OSContextProvider, - CodebaseContextProvider, ProblemsContextProvider, FolderContextProvider, DocsContextProvider, @@ -51,16 +51,11 @@ const Providers: (typeof BaseContextProvider)[] = [ CodeContextProvider, CurrentFileContextProvider, URLContextProvider, + ContinueProxyContextProvider, ]; export function contextProviderClassFromName( name: ContextProviderName, ): typeof BaseContextProvider | undefined { - const cls = Providers.find((cls) => cls.description.title === name); - - if (!cls) { - return undefined; - } - - return cls; + return Providers.find((cls) => cls.description.title === name); } diff --git a/core/context/rerankers/ContinueProxyReranker.ts b/core/context/rerankers/ContinueProxyReranker.ts new file mode 100644 index 000000000..abeff24dc --- /dev/null +++ b/core/context/rerankers/ContinueProxyReranker.ts @@ -0,0 +1,46 @@ +import fetch from "node-fetch"; +import { CONTROL_PLANE_URL } from "../../control-plane/client.js"; +import { Chunk, Reranker } from "../../index.js"; + +export class ContinueProxyReranker implements Reranker { + name = "continue-proxy"; + + private _workOsAccessToken: string | undefined = undefined; + + get workOsAccessToken(): string | undefined { + return this._workOsAccessToken; + } + + set workOsAccessToken(value: string | undefined) { + if (this._workOsAccessToken !== value) { + this._workOsAccessToken = value; + this.params.apiKey = value!; + } + } + + constructor( + private readonly params: { + apiKey: string; + model?: string; + }, + ) {} + + async rerank(query: string, chunks: Chunk[]): Promise { + const url = new URL("/model-proxy/v1/rerank", CONTROL_PLANE_URL); + const resp = await fetch(url, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${this.params.apiKey}`, + }, + body: JSON.stringify({ + query, + documents: chunks.map((chunk) => chunk.content), + model: this.params.model, + }), + }); + const data: any = await resp.json(); + const results = data.data.sort((a: any, b: any) => a.index - b.index); + return results.map((result: any) => result.relevance_score); + } +} diff --git a/core/context/rerankers/index.ts b/core/context/rerankers/index.ts index 0a7cc685a..c60c0825a 100644 --- a/core/context/rerankers/index.ts +++ b/core/context/rerankers/index.ts @@ -1,7 +1,9 @@ import { RerankerName } from "../../index.js"; import { CohereReranker } from "./cohere.js"; +import { ContinueProxyReranker } from "./ContinueProxyReranker.js"; import { FreeTrialReranker } from "./freeTrial.js"; import { LLMReranker } from "./llm.js"; +import { HuggingFaceTEIReranker } from "./tei.js"; import { VoyageReranker } from "./voyage.js"; export const AllRerankers: { [key in RerankerName]: any } = { @@ -9,4 +11,6 @@ export const AllRerankers: { [key in RerankerName]: any } = { llm: LLMReranker, voyage: VoyageReranker, "free-trial": FreeTrialReranker, + "huggingface-tei": HuggingFaceTEIReranker, + "continue-proxy": ContinueProxyReranker, }; diff --git a/core/context/rerankers/tei.ts b/core/context/rerankers/tei.ts new file mode 100644 index 000000000..667181ae3 --- /dev/null +++ b/core/context/rerankers/tei.ts @@ -0,0 +1,49 @@ +import fetch from "node-fetch"; +import { Chunk, Reranker } from "../../index.js"; + +export class HuggingFaceTEIReranker implements Reranker { + name = "huggingface-tei"; + + static defaultOptions = { + apiBase: "http://localhost:8080", + truncate: true, + truncation_direction: "Right" + }; + + constructor( + private readonly params: { + apiBase?: string; + truncate?: boolean; + truncation_direction?: string; + }, + ) {} + + async rerank(query: string, chunks: Chunk[]): Promise { + let apiBase = this.params.apiBase ?? HuggingFaceTEIReranker.defaultOptions.apiBase; + if (!apiBase.endsWith("/")) { + apiBase += "/"; + } + + const resp = await fetch(new URL("rerank", apiBase), { + method: "POST", + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + query: query, + return_text: false, + raw_scores: false, + texts: chunks.map((chunk) => chunk.content), + truncation_direction: this.params.truncation_direction ?? HuggingFaceTEIReranker.defaultOptions.truncation_direction, + truncate: this.params.truncate ?? HuggingFaceTEIReranker.defaultOptions.truncate + }), + }); + + if (!resp.ok) { + throw new Error(await resp.text()); + } + + const data = (await resp.json()) as any; + // Resort into original order and extract scores + const results = data.sort((a: any, b: any) => a.index - b.index); + return results.map((result: any) => result.score); + } +} diff --git a/core/context/retrieval/pipelines/BaseRetrievalPipeline.ts b/core/context/retrieval/pipelines/BaseRetrievalPipeline.ts index b993aea07..6c1f9f578 100644 --- a/core/context/retrieval/pipelines/BaseRetrievalPipeline.ts +++ b/core/context/retrieval/pipelines/BaseRetrievalPipeline.ts @@ -4,9 +4,12 @@ import { EmbeddingsProvider, IDE, Reranker, -} from "../../.."; -import { LanceDbIndex } from "../../../indexing/LanceDbIndex"; -import { retrieveFts } from "../fullTextSearch"; +} from "../../../index.js"; +import { chunkDocument } from "../../../indexing/chunk/chunk.js"; +import { LanceDbIndex } from "../../../indexing/LanceDbIndex.js"; +import { MAX_CHUNK_SIZE } from "../../../llm/constants.js"; +import { retrieveFts } from "../fullTextSearch.js"; +import { recentlyEditedFilesCache } from "../recentlyEditedFilesCache.js"; export interface RetrievalPipelineOptions { ide: IDE; @@ -32,6 +35,43 @@ export default class BaseRetrievalPipeline implements IRetrievalPipeline { ); } + protected async retrieveAndChunkRecentlyEditedFiles( + n: number, + ): Promise { + const recentlyEditedFilesSlice = Array.from( + recentlyEditedFilesCache.keys(), + ).slice(0, n); + + // If the number of recently edited files is less than the retrieval limit, + // include additional open files. This is useful in the case where a user + // has many tabs open and reloads their IDE. They now have 0 recently edited files, + // but many open tabs that represent what they were working on prior to reload. + if (recentlyEditedFilesSlice.length < n) { + const openFiles = await this.options.ide.getOpenFiles(); + recentlyEditedFilesSlice.push( + ...openFiles.slice(0, n - recentlyEditedFilesSlice.length), + ); + } + + const chunks: Chunk[] = []; + + for (const filepath of recentlyEditedFilesSlice) { + const contents = await this.options.ide.readFile(filepath); + const fileChunks = chunkDocument({ + filepath, + contents, + maxChunkSize: MAX_CHUNK_SIZE, + digest: filepath, + }); + + for await (const chunk of fileChunks) { + chunks.push(chunk); + } + } + + return chunks; + } + protected async retrieveFts(input: string, n: number): Promise { return retrieveFts( input, diff --git a/core/context/retrieval/pipelines/NoRerankerRetrievalPipeline.ts b/core/context/retrieval/pipelines/NoRerankerRetrievalPipeline.ts index 7ad1819d5..344d10b5c 100644 --- a/core/context/retrieval/pipelines/NoRerankerRetrievalPipeline.ts +++ b/core/context/retrieval/pipelines/NoRerankerRetrievalPipeline.ts @@ -1,26 +1,38 @@ -import { Chunk } from "../../.."; -import { deduplicateChunks } from "../util"; -import BaseRetrievalPipeline from "./BaseRetrievalPipeline"; +import { Chunk } from "../../../index.js"; +import { deduplicateChunks } from "../util.js"; +import BaseRetrievalPipeline from "./BaseRetrievalPipeline.js"; export default class NoRerankerRetrievalPipeline extends BaseRetrievalPipeline { async run(): Promise { - const { input } = this.options; + const { input, nFinal } = this.options; + + // We give 1/4 weight to recently edited files, 1/4 to full text search, + // and the remaining 1/2 to embeddings + const recentlyEditedNFinal = nFinal * 0.25; + const ftsNFinal = nFinal * 0.25; + const embeddingsNFinal = nFinal - recentlyEditedNFinal - ftsNFinal; - // Get all retrieval results const retrievalResults: Chunk[] = []; - // Full-text search - const ftsResults = await this.retrieveFts(input, this.options.nFinal / 2); - retrievalResults.push(...ftsResults); + const ftsChunks = await this.retrieveFts(input, ftsNFinal); - // Embeddings - const embeddingResults = await this.retrieveEmbeddings( + const embeddingsChunks = await this.retrieveEmbeddings( input, - this.options.nFinal / 2, + embeddingsNFinal, ); - retrievalResults.push(...embeddingResults); - const finalResults: Chunk[] = deduplicateChunks(retrievalResults); - return finalResults; + const recentlyEditedFilesChunks = + await this.retrieveAndChunkRecentlyEditedFiles(recentlyEditedNFinal); + + retrievalResults.push( + ...recentlyEditedFilesChunks, + ...ftsChunks, + ...embeddingsChunks, + ); + + const deduplicatedRetrievalResults: Chunk[] = + deduplicateChunks(retrievalResults); + + return deduplicatedRetrievalResults; } } diff --git a/core/context/retrieval/pipelines/RerankerRetrievalPipeline.ts b/core/context/retrieval/pipelines/RerankerRetrievalPipeline.ts index 47b0f1f9d..62c227a21 100644 --- a/core/context/retrieval/pipelines/RerankerRetrievalPipeline.ts +++ b/core/context/retrieval/pipelines/RerankerRetrievalPipeline.ts @@ -1,27 +1,30 @@ -import { Chunk } from "../../.."; -import { RETRIEVAL_PARAMS } from "../../../util/parameters"; -import { deduplicateChunks } from "../util"; -import BaseRetrievalPipeline from "./BaseRetrievalPipeline"; +import { Chunk } from "../../../index.js"; +import { RETRIEVAL_PARAMS } from "../../../util/parameters.js"; +import { recentlyEditedFilesCache } from "../recentlyEditedFilesCache.js"; +import { deduplicateChunks } from "../util.js"; +import BaseRetrievalPipeline from "./BaseRetrievalPipeline.js"; export default class RerankerRetrievalPipeline extends BaseRetrievalPipeline { private async _retrieveInitial(): Promise { const { input, nRetrieve } = this.options; - // Get all retrieval results const retrievalResults: Chunk[] = []; - // Full-text search - const ftsResults = await this.retrieveFts(input, nRetrieve / 2); - retrievalResults.push(...ftsResults); + const ftsChunks = await this.retrieveFts(input, nRetrieve); + const embeddingsChunks = await this.retrieveEmbeddings(input, nRetrieve); + const recentlyEditedFilesChunks = + await this.retrieveAndChunkRecentlyEditedFiles(nRetrieve); - // Embeddings - const embeddingResults = await this.retrieveEmbeddings(input, nRetrieve); retrievalResults.push( - ...embeddingResults.slice(0, nRetrieve - ftsResults.length), + ...recentlyEditedFilesChunks, + ...ftsChunks, + ...embeddingsChunks, ); - const results: Chunk[] = deduplicateChunks(retrievalResults); - return results; + const deduplicatedRetrievalResults: Chunk[] = + deduplicateChunks(retrievalResults); + + return deduplicatedRetrievalResults; } private async _rerank(input: string, chunks: Chunk[]): Promise { @@ -74,12 +77,8 @@ export default class RerankerRetrievalPipeline extends BaseRetrievalPipeline { } async run(): Promise { - // Retrieve initial results - let results = await this._retrieveInitial(); - - // Rerank - const { input } = this.options; - results = await this._rerank(input, results); + const intialResults = await this._retrieveInitial(); + const rankedResults = await this._rerank(this.options.input, intialResults); // // // Expand top reranked results // const expanded = await this._expandRankedResults(results); @@ -93,7 +92,7 @@ export default class RerankerRetrievalPipeline extends BaseRetrievalPipeline { // TODO: stitch together results - return results; + return rankedResults; } } diff --git a/core/context/retrieval/recentlyEditedFilesCache.ts b/core/context/retrieval/recentlyEditedFilesCache.ts new file mode 100644 index 000000000..1f74ea3c9 --- /dev/null +++ b/core/context/retrieval/recentlyEditedFilesCache.ts @@ -0,0 +1,15 @@ +import QuickLRU from "quick-lru"; +import { ToWebviewOrCoreFromIdeProtocol } from "../../protocol/ide.js"; + +// The cache key and value are both a filepath string +export type RecentlyEditedFilesCacheKeyAndValue = + ToWebviewOrCoreFromIdeProtocol["didChangeActiveTextEditor"][0]["filepath"]; + +const MAX_NUM_RECENTLY_EDITED_FILES = 100; + +export const recentlyEditedFilesCache = new QuickLRU< + RecentlyEditedFilesCacheKeyAndValue, + RecentlyEditedFilesCacheKeyAndValue +>({ + maxSize: MAX_NUM_RECENTLY_EDITED_FILES, +}); diff --git a/core/context/retrieval/retrieval.ts b/core/context/retrieval/retrieval.ts index 65ce26e4e..9d07ae5cc 100644 --- a/core/context/retrieval/retrieval.ts +++ b/core/context/retrieval/retrieval.ts @@ -3,9 +3,8 @@ import { ContextItem, ContextProviderExtras, } from "../../index.js"; - +import TransformersJsEmbeddingsProvider from "../../indexing/embeddings/TransformersJsEmbeddingsProvider.js"; import { getRelativePath } from "../../util/index.js"; -import { RETRIEVAL_PARAMS } from "../../util/parameters.js"; import { RetrievalPipelineOptions } from "./pipelines/BaseRetrievalPipeline.js"; import NoRerankerRetrievalPipeline from "./pipelines/NoRerankerRetrievalPipeline.js"; import RerankerRetrievalPipeline from "./pipelines/RerankerRetrievalPipeline.js"; @@ -20,22 +19,20 @@ export async function retrieveContextItemsFromEmbeddings( } // transformers.js not supported in JetBrains IDEs right now - if ( - extras.embeddingsProvider.id === "all-MiniLM-L6-v2" && - (await extras.ide.getIdeInfo()).ideType === "jetbrains" - ) { + + const isJetBrainsAndTransformersJs = + extras.embeddingsProvider.id === TransformersJsEmbeddingsProvider.model && + (await extras.ide.getIdeInfo()).ideType === "jetbrains"; + + if (isJetBrainsAndTransformersJs) { throw new Error( - "The transformers.js context provider is not currently supported in JetBrains. For now, you can use Ollama to set up local embeddings, or use our 'free-trial' embeddings provider. See here to learn more: https://docs.continue.dev/features/codebase-embeddings#embeddings-providers", + "The 'transformers.js' context provider is not currently supported in JetBrains. " + + "For now, you can use Ollama to set up local embeddings, or use our 'free-trial' " + + "embeddings provider. See here to learn more: " + + "https://docs.continue.dev/walkthroughs/codebase-embeddings#embeddings-providers", ); } - const nFinal = options?.nFinal || RETRIEVAL_PARAMS.nFinal; - const useReranking = extras.reranker !== undefined; - const nRetrieve = - useReranking === false - ? nFinal - : options?.nRetrieve || RETRIEVAL_PARAMS.nRetrieve; - // Get tags to retrieve for const workspaceDirs = await extras.ide.getWorkspaceDirs(); @@ -43,6 +40,14 @@ export async function retrieveContextItemsFromEmbeddings( throw new Error("No workspace directories found"); } + // Fill half of the context length, up to a max of 100 snippets + const contextLength = extras.llm.contextLength; + const tokensPerSnippet = 512; + const nFinal = + options?.nFinal ?? Math.min(50, contextLength / tokensPerSnippet / 2); + const useReranking = !!extras.reranker; + const nRetrieve = useReranking ? options?.nRetrieve || 2 * nFinal : nFinal; + const branches = (await Promise.race([ Promise.all(workspaceDirs.map((dir) => extras.ide.getBranch(dir))), new Promise((resolve) => { @@ -51,6 +56,7 @@ export async function retrieveContextItemsFromEmbeddings( }, 500); }), ])) as string[]; + const tags: BranchAndDir[] = workspaceDirs.map((directory, i) => ({ directory, branch: branches[i], @@ -59,6 +65,7 @@ export async function retrieveContextItemsFromEmbeddings( const pipelineType = useReranking ? RerankerRetrievalPipeline : NoRerankerRetrievalPipeline; + const pipelineOptions: RetrievalPipelineOptions = { nFinal, nRetrieve, @@ -69,6 +76,7 @@ export async function retrieveContextItemsFromEmbeddings( ide: extras.ide, input: extras.fullInput, }; + const pipeline = new pipelineType(pipelineOptions); const results = await pipeline.run(); @@ -80,7 +88,9 @@ export async function retrieveContextItemsFromEmbeddings( return [ ...results.map((r) => { - const name = `${getRelativePath(r.filepath, workspaceDirs)} (${r.startLine}-${r.endLine})`; + const name = `${getRelativePath(r.filepath, workspaceDirs)} (${ + r.startLine + }-${r.endLine})`; const description = `${r.filepath} (${r.startLine}-${r.endLine})`; return { name, diff --git a/core/control-plane/TeamAnalytics.ts b/core/control-plane/TeamAnalytics.ts new file mode 100644 index 000000000..2e19ed2ec --- /dev/null +++ b/core/control-plane/TeamAnalytics.ts @@ -0,0 +1,55 @@ +import { Analytics } from "@continuedev/config-types"; +import os from "node:os"; +import ContinueProxyAnalyticsProvider from "./analytics/ContinueProxyAnalyticsProvider"; +import { IAnalyticsProvider } from "./analytics/IAnalyticsProvider"; +import LogStashAnalyticsProvider from "./analytics/LogStashAnalyticsProvider"; +import PostHogAnalyticsProvider from "./analytics/PostHogAnalyticsProvider"; + +function createAnalyticsProvider( + config: Analytics, +): IAnalyticsProvider | undefined { + // @ts-ignore + switch (config.provider) { + case "posthog": + return new PostHogAnalyticsProvider(); + case "logstash": + return new LogStashAnalyticsProvider(); + case "continue-proxy": + return new ContinueProxyAnalyticsProvider(); + default: + return undefined; + } +} + +export class TeamAnalytics { + static provider: IAnalyticsProvider | undefined = undefined; + static uniqueId = "NOT_UNIQUE"; + static os: string | undefined = undefined; + static extensionVersion: string | undefined = undefined; + + static async capture(event: string, properties: { [key: string]: any }) { + TeamAnalytics.provider?.capture(event, { + ...properties, + os: TeamAnalytics.os, + extensionVersion: TeamAnalytics.extensionVersion, + }); + } + + static async setup( + config: Analytics, + uniqueId: string, + extensionVersion: string, + ) { + TeamAnalytics.uniqueId = uniqueId; + TeamAnalytics.os = os.platform(); + TeamAnalytics.extensionVersion = extensionVersion; + + if (!config) { + await TeamAnalytics.provider?.shutdown(); + TeamAnalytics.provider = undefined; + } else { + TeamAnalytics.provider = createAnalyticsProvider(config); + await TeamAnalytics.provider?.setup(config, uniqueId); + } + } +} diff --git a/core/control-plane/analytics/ContinueProxyAnalyticsProvider.ts b/core/control-plane/analytics/ContinueProxyAnalyticsProvider.ts new file mode 100644 index 000000000..b586c525d --- /dev/null +++ b/core/control-plane/analytics/ContinueProxyAnalyticsProvider.ts @@ -0,0 +1,32 @@ +import { Analytics } from "@continuedev/config-types"; +import fetch from "node-fetch"; +import { CONTROL_PLANE_URL } from "../client"; +import { IAnalyticsProvider } from "./IAnalyticsProvider"; + +export default class ContinueProxyAnalyticsProvider + implements IAnalyticsProvider +{ + uniqueId?: string; + addOnId?: string; + + async capture( + event: string, + properties: { [key: string]: any }, + ): Promise { + fetch(new URL(`/proxy/analytics/${this.addOnId}`, CONTROL_PLANE_URL), { + method: "POST", + body: JSON.stringify({ + event, + properties, + uniqueId: this.uniqueId, + }), + }); + } + + async setup(config: Analytics, uniqueId: string): Promise { + this.uniqueId = uniqueId; + this.addOnId = config.url?.split("/").slice(-1)[0]; + } + + async shutdown(): Promise {} +} diff --git a/core/control-plane/analytics/IAnalyticsProvider.ts b/core/control-plane/analytics/IAnalyticsProvider.ts new file mode 100644 index 000000000..8a04ba1ce --- /dev/null +++ b/core/control-plane/analytics/IAnalyticsProvider.ts @@ -0,0 +1,11 @@ +import { Analytics } from "@continuedev/config-types"; + +export interface AnalyticsMetadata { + extensionVersion: string; +} + +export interface IAnalyticsProvider { + capture(event: string, properties: { [key: string]: any }): Promise; + setup(config: Analytics, uniqueId: string): Promise; + shutdown(): Promise; +} diff --git a/core/control-plane/analytics/LogStashAnalyticsProvider.ts b/core/control-plane/analytics/LogStashAnalyticsProvider.ts new file mode 100644 index 000000000..1fe5aec47 --- /dev/null +++ b/core/control-plane/analytics/LogStashAnalyticsProvider.ts @@ -0,0 +1,42 @@ +import { Analytics } from "@continuedev/config-types"; +import net from "node:net"; +import { IAnalyticsProvider } from "./IAnalyticsProvider"; + +export default class LogStashAnalyticsProvider implements IAnalyticsProvider { + private host?: string; + private port?: number; + private uniqueId?: string; + + async capture( + event: string, + properties: { [key: string]: any }, + ): Promise { + if (this.host === undefined || this.port === undefined) { + console.warn("LogStashAnalyticsProvider not set up yet."); + } + + const payload = { + event, + properties, + uniqueId: this.uniqueId, + }; + const client = new net.Socket(); + + client.connect(this.port!, this.host!, () => { + client.write(JSON.stringify(payload)); + client.end(); + }); + } + + async setup(config: Analytics, uniqueId: string): Promise { + if (!config.url) { + throw new Error("Missing url in analytics config"); + } + const url = new URL(config.url); + this.host = url.hostname; + this.port = parseInt(url.port); + this.uniqueId = uniqueId; + } + + async shutdown(): Promise {} +} diff --git a/core/control-plane/analytics/PostHogAnalyticsProvider.ts b/core/control-plane/analytics/PostHogAnalyticsProvider.ts new file mode 100644 index 000000000..f32a0737b --- /dev/null +++ b/core/control-plane/analytics/PostHogAnalyticsProvider.ts @@ -0,0 +1,37 @@ +import { Analytics } from "@continuedev/config-types"; +import { IAnalyticsProvider } from "./IAnalyticsProvider"; + +export default class PostHogAnalyticsProvider implements IAnalyticsProvider { + client?: any; + uniqueId?: string; + + async capture( + event: string, + properties: { [key: string]: any }, + ): Promise { + this.client?.capture({ + distinctId: this.uniqueId, + event, + properties, + }); + } + + async setup(config: Analytics, uniqueId: string): Promise { + if (!config || !config.clientKey || !config.url) { + this.client = undefined; + } else { + try { + this.uniqueId = uniqueId; + + const { PostHog } = await import("posthog-node"); + this.client = new PostHog(config.clientKey, { + host: config.url, + }); + } catch (e) { + console.error(`Failed to setup telemetry: ${e}`); + } + } + } + + async shutdown(): Promise {} +} diff --git a/core/control-plane/auth/index.ts b/core/control-plane/auth/index.ts new file mode 100644 index 000000000..ecb6221c7 --- /dev/null +++ b/core/control-plane/auth/index.ts @@ -0,0 +1,20 @@ +import { v4 as uuidv4 } from "uuid"; + +const CLIENT_ID = "client_01J0FW6XN8N2XJAECF7NE0Y65J"; +// const CLIENT_ID = "client_01J0FW6XCPMJMQ3CG51RB4HBZQ"; // Staging + +export async function getAuthUrlForTokenPage(): Promise { + const url = new URL("https://api.workos.com/user_management/authorize"); + const params = { + response_type: "code", + client_id: CLIENT_ID, + redirect_uri: "https://app.continue.dev/tokens/callback", + // redirect_uri: "http://localhost:3000/tokens/callback", + state: uuidv4(), + provider: "authkit", + }; + Object.keys(params).forEach((key) => + url.searchParams.append(key, params[key as keyof typeof params]), + ); + return url.toString(); +} diff --git a/core/control-plane/client.ts b/core/control-plane/client.ts new file mode 100644 index 000000000..2a7669c48 --- /dev/null +++ b/core/control-plane/client.ts @@ -0,0 +1,97 @@ +import { ConfigJson } from "@continuedev/config-types"; +import fetch, { RequestInit, Response } from "node-fetch"; +import { ModelDescription } from ".."; + +export interface ControlPlaneSessionInfo { + accessToken: string; + account: { + label: string; + id: string; + }; +} + +export interface ControlPlaneWorkspace { + id: string; + name: string; + settings: ConfigJson; +} + +export interface ControlPlaneModelDescription extends ModelDescription {} + +export const CONTROL_PLANE_URL = + process.env.CONTROL_PLANE_ENV === "local" + ? "http://localhost:3001" + : "https://control-plane-api-service-i3dqylpbqa-uc.a.run.app"; + +export class ControlPlaneClient { + private static URL = CONTROL_PLANE_URL; + private static ACCESS_TOKEN_VALID_FOR_MS = 1000 * 60 * 5; // 5 minutes + + private lastAccessTokenRefresh = 0; + + constructor( + private readonly sessionInfoPromise: Promise< + ControlPlaneSessionInfo | undefined + >, + ) {} + + get userId(): Promise { + return this.sessionInfoPromise.then( + (sessionInfo) => sessionInfo?.account.id, + ); + } + + async getAccessToken(): Promise { + return (await this.sessionInfoPromise)?.accessToken; + } + + private async request(path: string, init: RequestInit): Promise { + const accessToken = await this.getAccessToken(); + if (!accessToken) { + throw new Error("No access token"); + } + const resp = await fetch(new URL(path, ControlPlaneClient.URL).toString(), { + ...init, + headers: { + ...init.headers, + Authorization: `Bearer ${accessToken}`, + }, + }); + + if (!resp.ok) { + throw new Error( + `Control plane request failed: ${resp.status} ${await resp.text()}`, + ); + } + + return resp; + } + + public async listWorkspaces(): Promise { + const userId = await this.userId; + if (!userId) { + return []; + } + + try { + const resp = await this.request(`/workspaces`, { + method: "GET", + }); + return (await resp.json()) as any; + } catch (e) { + return []; + } + } + + async getSettingsForWorkspace(workspaceId: string): Promise { + const userId = await this.userId; + if (!userId) { + throw new Error("No user id"); + } + + const resp = await this.request(`/workspaces/${workspaceId}`, { + method: "GET", + }); + return ((await resp.json()) as any).settings; + } +} diff --git a/core/control-plane/schema.ts b/core/control-plane/schema.ts new file mode 100644 index 000000000..5557eff13 --- /dev/null +++ b/core/control-plane/schema.ts @@ -0,0 +1,128 @@ +import { z } from "zod"; + +const modelDescriptionSchema = z.object({ + title: z.string(), + provider: z.enum([ + "openai", + "anthropic", + "cohere", + "ollama", + "huggingface-tgi", + "huggingface-inference-api", + "replicate", + "gemini", + "mistral", + "bedrock", + "cloudflare", + "azure", + ]), + model: z.string(), + apiKey: z.string().optional(), + apiBase: z.string().optional(), + contextLength: z.number().optional(), + template: z + .enum([ + "llama2", + "alpaca", + "zephyr", + "phi2", + "phind", + "anthropic", + "chatml", + "none", + "openchat", + "deepseek", + "xwin-coder", + "neural-chat", + "codellama-70b", + "llava", + "gemma", + "llama3", + ]) + .optional(), + completionOptions: z + .object({ + temperature: z.number().optional(), + topP: z.number().optional(), + topK: z.number().optional(), + minP: z.number().optional(), + presencePenalty: z.number().optional(), + frequencyPenalty: z.number().optional(), + mirostat: z.number().optional(), + stop: z.array(z.string()).optional(), + maxTokens: z.number().optional(), + numThreads: z.number().optional(), + keepAlive: z.number().optional(), + raw: z.boolean().optional(), + stream: z.boolean().optional(), + }) + .optional(), + systemMessage: z.string().optional(), + requestOptions: z + .object({ + timeout: z.number().optional(), + verifySsl: z.boolean().optional(), + caBundlePath: z.union([z.string(), z.array(z.string())]).optional(), + proxy: z.string().optional(), + headers: z.record(z.string()).optional(), + extraBodyProperties: z.record(z.any()).optional(), + noProxy: z.array(z.string()).optional(), + }) + .optional(), + promptTemplates: z.record(z.string()).optional(), +}); + +const embeddingsProviderSchema = z.object({ + provider: z.enum([ + "transformers.js", + "ollama", + "openai", + "cohere", + "free-trial", + "gemini", + ]), + apiBase: z.string().optional(), + apiKey: z.string().optional(), + model: z.string().optional(), + engine: z.string().optional(), + apiType: z.string().optional(), + apiVersion: z.string().optional(), + requestOptions: z + .object({ + timeout: z.number().optional(), + verifySsl: z.boolean().optional(), + caBundlePath: z.union([z.string(), z.array(z.string())]).optional(), + proxy: z.string().optional(), + headers: z.record(z.string()).optional(), + extraBodyProperties: z.record(z.any()).optional(), + noProxy: z.array(z.string()).optional(), + }) + .optional(), +}); + +const rerankerSchema = z.object({ + name: z.enum(["cohere", "voyage", "llm"]), + params: z.record(z.any()).optional(), +}); + +const analyticsSchema = z.object({ + url: z.string().optional(), + clientKey: z.string().optional(), +}); + +export type ControlPlaneAnalytics = z.infer; + +const devDataSchema = z.object({ + url: z.string().optional(), +}); + +export const controlPlaneSettingsSchema = z.object({ + models: z.array(modelDescriptionSchema), + tabAutocompleteModel: modelDescriptionSchema, + embeddingsModel: embeddingsProviderSchema, + reranker: rerankerSchema, + analytics: analyticsSchema, + devData: devDataSchema, +}); + +export type ControlPlaneSettings = z.infer; diff --git a/core/core.ts b/core/core.ts index 6e6b8b997..1ae493aaf 100644 --- a/core/core.ts +++ b/core/core.ts @@ -1,13 +1,13 @@ import { v4 as uuidv4 } from "uuid"; import type { ContextItemId, + EmbeddingsProvider, IDE, IndexingProgressUpdate, SiteIndexingConfig, } from "."; import { CompletionProvider } from "./autocomplete/completionProvider.js"; import { ConfigHandler } from "./config/ConfigHandler.js"; -import { IConfigHandler } from "./config/IConfigHandler"; import { setupApiKeysMode, setupFreeTrialMode, @@ -16,10 +16,12 @@ import { } from "./config/onboarding.js"; import { createNewPromptFile } from "./config/promptFile.js"; import { addModel, addOpenAIKey, deleteModel } from "./config/util.js"; +import { recentlyEditedFilesCache } from "./context/retrieval/recentlyEditedFilesCache.js"; import { ContinueServerClient } from "./continueServer/stubs/client.js"; +import { getAuthUrlForTokenPage } from "./control-plane/auth/index.js"; +import { ControlPlaneClient } from "./control-plane/client"; import { CodebaseIndexer, PauseToken } from "./indexing/CodebaseIndexer.js"; -import { DocsService } from "./indexing/docs/DocsService"; -import TransformersJsEmbeddingsProvider from "./indexing/embeddings/TransformersJsEmbeddingsProvider.js"; +import { DocsService } from "./indexing/docs/DocsService.js"; import Ollama from "./llm/llms/Ollama.js"; import type { FromCoreProtocol, ToCoreProtocol } from "./protocol"; import { GlobalContext } from "./util/GlobalContext.js"; @@ -34,11 +36,12 @@ import { streamDiffLines } from "./util/verticalEdit.js"; export class Core { // implements IMessenger - configHandler: IConfigHandler; + configHandler: ConfigHandler; codebaseIndexerPromise: Promise; completionProvider: CompletionProvider; continueServerClientPromise: Promise; indexingState: IndexingProgressUpdate; + controlPlaneClient: ControlPlaneClient; private globalContext = new GlobalContext(); private docsService = DocsService.getInstance(); private readonly indexingPauseToken = new PauseToken( @@ -64,6 +67,14 @@ export class Core { return this.messenger.invoke(messageType, data); } + send( + messageType: T, + data: FromCoreProtocol[T][0], + messageId?: string, + ): string { + return this.messenger.send(messageType, data); + } + // TODO: It shouldn't actually need an IDE type, because this can happen // through the messenger (it does in the case of any non-VS Code IDEs already) constructor( @@ -72,16 +83,39 @@ export class Core { private readonly onWrite: (text: string) => Promise = async () => {}, ) { this.indexingState = { status: "loading", desc: "loading", progress: 0 }; + const ideSettingsPromise = messenger.request("getIdeSettings", undefined); + const sessionInfoPromise = messenger.request("getControlPlaneSessionInfo", { + silent: true, + }); + + this.controlPlaneClient = new ControlPlaneClient(sessionInfoPromise); + this.configHandler = new ConfigHandler( this.ide, ideSettingsPromise, this.onWrite, + this.controlPlaneClient, ); + this.configHandler.onConfigUpdate( (() => this.messenger.send("configUpdate", undefined)).bind(this), ); + this.configHandler.onConfigUpdate(async ({ embeddingsProvider }) => { + if ( + await this.shouldReindexDocsOnNewEmbeddingsProvider( + embeddingsProvider.id, + ) + ) { + await this.reindexDocsOnNewEmbeddingsProvider(embeddingsProvider); + } + }); + + this.configHandler.onDidChangeAvailableProfiles((profiles) => + this.messenger.send("didChangeAvailableProfiles", { profiles }), + ); + // Codebase Indexer and ContinueServerClient depend on IdeSettings let codebaseIndexerResolve: (_: any) => void | undefined; this.codebaseIndexerPromise = new Promise( @@ -108,9 +142,21 @@ export class Core { continueServerClient, ), ); - this.ide - .getWorkspaceDirs() - .then((dirs) => this.refreshCodebaseIndex(dirs)); + + // Index on initialization + this.ide.getWorkspaceDirs().then(async (dirs) => { + // Respect pauseCodebaseIndexOnStart user settings + if (ideSettings.pauseCodebaseIndexOnStart) { + await this.messenger.request("indexProgress", { + progress: 100, + desc: "Initial Indexing Skipped", + status: "paused", + }); + return; + } + + this.refreshCodebaseIndex(dirs); + }); }); const getLlm = async () => { @@ -206,22 +252,14 @@ export class Core { on("config/ideSettingsUpdate", (msg) => { this.configHandler.updateIdeSettings(msg.data); }); + on("config/listProfiles", (msg) => { + return this.configHandler.listProfiles(); + }); // Context providers on("context/addDocs", async (msg) => { - const siteIndexingConfig: SiteIndexingConfig = { - startUrl: msg.data.startUrl, - rootUrl: msg.data.rootUrl, - title: msg.data.title, - maxDepth: msg.data.maxDepth, - faviconUrl: new URL("/favicon.ico", msg.data.rootUrl).toString(), - }; + await this.getEmbeddingsProviderAndIndexDoc(msg.data); - for await (const _ of this.docsService.indexAndAdd( - siteIndexingConfig, - new TransformersJsEmbeddingsProvider(), - )) { - } this.ide.infoPopup(`Successfully indexed ${msg.data.title}`); this.messenger.send("refreshSubmenuItems", undefined); }); @@ -230,11 +268,36 @@ export class Core { await this.docsService.delete(baseUrl); this.messenger.send("refreshSubmenuItems", undefined); }); + on("context/indexDocs", async (msg) => { + const config = await this.config(); + const provider: any = config.contextProviders?.find( + (provider) => provider.description.title === "docs", + ); + + if (!provider) { + this.ide.infoPopup("No docs in configuration"); + return; + } + + const siteIndexingOptions: SiteIndexingConfig[] = ((mProvider) => [ + ...new Set([ + ...(mProvider?.options?.sites || []), + ...(config.docs || []), + ]), + ])({ ...provider }); + + for (const site of siteIndexingOptions) { + await this.getEmbeddingsProviderAndIndexDoc(site, msg.data.reIndex); + } + + this.ide.infoPopup("Docs indexing completed"); + }); on("context/loadSubmenuItems", async (msg) => { const config = await this.config(); - const items = config.contextProviders + const items = await config.contextProviders ?.find((provider) => provider.description.title === msg.data.title) ?.loadSubmenuItems({ + config, ide: this.ide, fetch: (url, init) => fetchwithRequestOptions(url, init, config.requestOptions), @@ -268,9 +331,13 @@ export class Core { fetchwithRequestOptions(url, init, config.requestOptions), }); - Telemetry.capture("useContextProvider", { - name: provider.description.title, - }); + Telemetry.capture( + "useContextProvider", + { + name: provider.description.title, + }, + true, + ); return items.map((item) => ({ ...item, @@ -282,12 +349,15 @@ export class Core { } }); - on("config/getBrowserSerialized", (msg) => { - return this.configHandler.getSerializedConfig(); + on("config/getSerializedProfileInfo", async (msg) => { + return { + config: await this.configHandler.getSerializedConfig(), + profileId: this.configHandler.currentProfile.profileId, + }; }); async function* llmStreamChat( - configHandler: IConfigHandler, + configHandler: ConfigHandler, abortedMessageIds: Set, msg: Message, ) { @@ -322,7 +392,7 @@ export class Core { ); async function* llmStreamComplete( - configHandler: IConfigHandler, + configHandler: ConfigHandler, abortedMessageIds: Set, msg: Message, @@ -388,7 +458,7 @@ export class Core { }); async function* runNodeJsSlashCommand( - configHandler: IConfigHandler, + configHandler: ConfigHandler, abortedMessageIds: Set, msg: Message, messenger: IMessenger, @@ -413,9 +483,13 @@ export class Core { throw new Error(`Unknown slash command ${slashCommandName}`); } - Telemetry.capture("useSlashCommand", { - name: slashCommandName, - }); + Telemetry.capture( + "useSlashCommand", + { + name: slashCommandName, + }, + true, + ); const checkActiveInterval = setInterval(() => { if (abortedMessageIds.has(msg.messageId)) { @@ -477,7 +551,7 @@ export class Core { }); async function* streamDiffLinesGenerator( - configHandler: IConfigHandler, + configHandler: ConfigHandler, abortedMessageIds: Set, msg: Message, ) { @@ -566,7 +640,7 @@ export class Core { }); on("index/forceReIndex", async (msg) => { const dirs = msg.data ? [msg.data] : await this.ide.getWorkspaceDirs(); - this.refreshCodebaseIndex(dirs); + await this.refreshCodebaseIndex(dirs); }); on("index/setPaused", (msg) => { new GlobalContext().update("indexingPaused", msg.data); @@ -579,6 +653,22 @@ export class Core { this.messenger.request("indexProgress", this.indexingState); } }); + + on("didChangeSelectedProfile", (msg) => { + this.configHandler.setSelectedProfile(msg.data.id); + this.configHandler.reloadConfig(); + }); + on("didChangeControlPlaneSessionInfo", async (msg) => { + this.configHandler.updateControlPlaneSessionInfo(msg.data.sessionInfo); + }); + on("auth/getAuthUrl", async (msg) => { + const url = await getAuthUrlForTokenPage(); + return { url }; + }); + + on("didChangeActiveTextEditor", ({ data: { filepath } }) => { + recentlyEditedFilesCache.set(filepath, filepath); + }); } private indexingCancellationController: AbortController | undefined; @@ -595,5 +685,103 @@ export class Core { this.messenger.request("indexProgress", update); this.indexingState = update; } + + this.messenger.send("refreshSubmenuItems", undefined); + } + + private async shouldReindexDocsOnNewEmbeddingsProvider( + curEmbeddingsProviderId: EmbeddingsProvider["id"], + ): Promise { + const ideInfo = await this.ide.getIdeInfo(); + const isJetBrainsAndPreIndexedDocsProvider = + this.docsService.isJetBrainsAndPreIndexedDocsProvider( + ideInfo, + curEmbeddingsProviderId, + ); + + if (isJetBrainsAndPreIndexedDocsProvider) { + try { + this.ide.errorPopup( + "The 'transformers.js' embeddings provider currently cannot be used to index " + + "documentation in JetBrains. To enable documentation indexing, you can use " + + "any of the other providers described in the docs: " + + "https://docs.continue.dev/walkthroughs/codebase-embeddings#embeddings-providers", + ); + } catch (error) { + console.error("Failed to show error popup:", error); + } + this.globalContext.update( + "curEmbeddingsProviderId", + curEmbeddingsProviderId, + ); + + return false; + } + + const lastEmbeddingsProviderId = this.globalContext.get( + "curEmbeddingsProviderId", + ); + + if (!lastEmbeddingsProviderId) { + // If it's the first time we're setting the `curEmbeddingsProviderId` + // global state, we don't need to reindex docs + this.globalContext.update( + "curEmbeddingsProviderId", + curEmbeddingsProviderId, + ); + + return false; + } + + return lastEmbeddingsProviderId !== curEmbeddingsProviderId; + } + + private async getEmbeddingsProviderAndIndexDoc( + site: SiteIndexingConfig, + reIndex: boolean = false, + ): Promise { + const config = await this.config(); + const { embeddingsProvider } = config; + + for await (const update of this.docsService.indexAndAdd( + site, + embeddingsProvider, + reIndex, + )) { + // Temporary disabled posting progress updates to the UI due to + // possible collision with code indexing progress updates. + // this.messenger.request("indexProgress", update); + // this.indexingState = update; + } + } + + private async reindexDocsOnNewEmbeddingsProvider( + embeddingsProvider: EmbeddingsProvider, + ) { + const docs = await this.docsService.list(); + + if (docs.length === 0) { + return; + } + + this.ide.infoPopup("Reindexing docs with new embeddings provider"); + + for (const { title, baseUrl } of docs) { + await this.docsService.delete(baseUrl); + + const generator = this.docsService.indexAndAdd( + { title, startUrl: baseUrl, rootUrl: baseUrl }, + embeddingsProvider, + ); + + while (!(await generator.next()).done) {} + } + + // Important that this only is invoked after we have successfully + // cleared and reindex the docs so that the table cannot end up in an + // invalid state. + this.globalContext.update("curEmbeddingsProviderId", embeddingsProvider.id); + + this.ide.infoPopup("Completed reindexing of all docs"); } } diff --git a/core/diff/streamDiff.ts b/core/diff/streamDiff.ts index 3bac09aec..42c8409b9 100644 --- a/core/diff/streamDiff.ts +++ b/core/diff/streamDiff.ts @@ -1,11 +1,11 @@ -import { DiffLine } from "../index.js"; +import { DiffLine, DiffLineType } from "../index.js"; import { LineStream, matchLine } from "./util.js"; /** * https://blog.jcoglan.com/2017/02/12/the-myers-diff-algorithm-part-1/ * Invariants: * - new + same = newLines.length - * - old + same = oldLines.length + * - old + same = oldLinesCopy.length * ^ (above two guarantee that all lines get represented) * - Lines are always output in order, at least among old and new separately */ @@ -13,52 +13,77 @@ export async function* streamDiff( oldLines: string[], newLines: LineStream, ): AsyncGenerator { - const mutatedOldLines = [...oldLines]; // be careful + const oldLinesCopy = [...oldLines]; // If one indentation mistake is made, others are likely. So we are more permissive about matching let seenIndentationMistake = false; let newLineResult = await newLines.next(); - while (oldLines.length > 0 && !newLineResult.done) { - const [matchIndex, isPerfectMatch, newLine] = matchLine( + + while (oldLinesCopy.length > 0 && !newLineResult.done) { + const { matchIndex, isPerfectMatch, newLine } = matchLine( newLineResult.value, - oldLines, + oldLinesCopy, seenIndentationMistake, ); + if (!seenIndentationMistake && newLineResult.value !== newLine) { seenIndentationMistake = true; } - if (matchIndex < 0) { - // Insert new line - yield { type: "new", line: newLine }; + let type: DiffLineType; + + let isLineRemoval = false; + const isNewLine = matchIndex === -1; + + if (isNewLine) { + type = "new"; } else { // Insert all deleted lines before match for (let i = 0; i < matchIndex; i++) { - yield { type: "old", line: oldLines.shift()! }; + yield { type: "old", line: oldLinesCopy.shift()! }; } - if (isPerfectMatch) { - // Same - yield { type: "same", line: oldLines.shift()! }; - } else { - // Delete old line and insert the new - yield { type: "old", line: oldLines.shift()! }; - yield { type: "new", line: newLine }; - } + type = isPerfectMatch ? "same" : "old"; } - newLineResult = await newLines.next(); + switch (type) { + case "new": + yield { type, line: newLine }; + break; + + case "same": + yield { type, line: oldLinesCopy.shift()! }; + break; + + case "old": + yield { type, line: oldLinesCopy.shift()! }; + + if (oldLinesCopy[0] !== newLine) { + yield { type: "new", line: newLine }; + } else { + isLineRemoval = true; + } + + break; + + default: + console.error(`Error streaming diff, unrecognized diff type: ${type}`); + } + + if (!isLineRemoval) { + newLineResult = await newLines.next(); + } } // Once at the edge, only one choice - if (newLineResult.done === true && oldLines.length > 0) { - for (const oldLine of oldLines) { + if (newLineResult.done && oldLinesCopy.length > 0) { + for (const oldLine of oldLinesCopy) { yield { type: "old", line: oldLine }; } } - if (!newLineResult.done && oldLines.length === 0) { + if (!newLineResult.done && oldLinesCopy.length === 0) { yield { type: "new", line: newLineResult.value }; for await (const newLine of newLines) { yield { type: "new", line: newLine }; diff --git a/core/diff/util.ts b/core/diff/util.ts index aff11a3c5..b3a895da9 100644 --- a/core/diff/util.ts +++ b/core/diff/util.ts @@ -1,9 +1,19 @@ import { distance } from "fastest-levenshtein"; import { ChatMessage } from "../index.js"; -import { stripImages } from "../llm/countTokens.js"; +import { stripImages } from "../llm/images.js"; export type LineStream = AsyncGenerator; +export type MatchLineResult = { + /** + * -1 if it's a new line, otherwise the index of the first match + * in the old lines. + */ + matchIndex: number; + isPerfectMatch: boolean; + newLine: string; +}; + function linesMatchPerfectly(lineA: string, lineB: string): boolean { return lineA === lineB && lineA !== ""; } @@ -18,6 +28,7 @@ function linesMatch(lineA: string, lineB: string, linesBetween = 0): boolean { } const d = distance(lineA, lineB); + return ( // Should be more unlikely for lines to fuzzy match if they are further away (d / Math.max(lineA.length, lineB.length) < 0.5 - linesBetween * 0.05 || @@ -27,6 +38,8 @@ function linesMatch(lineA: string, lineB: string, linesBetween = 0): boolean { } /** + * Used to find a match for a new line in an array of old lines. + * * Return the index of the first match and whether it is a perfect match * Also return a version of the line with correct indentation if needs fixing */ @@ -34,21 +47,26 @@ export function matchLine( newLine: string, oldLines: string[], permissiveAboutIndentation = false, -): [number, boolean, string] { +): MatchLineResult { // Only match empty lines if it's the next one: if (newLine.trim() === "" && oldLines[0]?.trim() === "") { - return [0, true, newLine.trim()]; + return { + matchIndex: 0, + isPerfectMatch: true, + newLine: newLine.trim(), + }; } const isEndBracket = END_BRACKETS.includes(newLine.trim()); + for (let i = 0; i < oldLines.length; i++) { // Don't match end bracket lines if too far away if (i > 4 && isEndBracket) { - return [-1, false, newLine]; + return { matchIndex: -1, isPerfectMatch: false, newLine }; } if (linesMatchPerfectly(newLine, oldLines[i])) { - return [i, true, newLine]; + return { matchIndex: i, isPerfectMatch: true, newLine }; } if (linesMatch(newLine, oldLines[i], i)) { // This is a way to fix indentation, but only for sufficiently long lines to avoid matching whitespace or short lines @@ -56,13 +74,17 @@ export function matchLine( newLine.trimStart() === oldLines[i].trimStart() && (permissiveAboutIndentation || newLine.trim().length > 8) ) { - return [i, true, oldLines[i]]; + return { + matchIndex: i, + isPerfectMatch: true, + newLine: oldLines[i], + }; } - return [i, false, newLine]; + return { matchIndex: i, isPerfectMatch: false, newLine }; } } - return [-1, false, newLine]; + return { matchIndex: -1, isPerfectMatch: false, newLine }; } /** diff --git a/core/index.d.ts b/core/index.d.ts index 99c6ad755..481fc3165 100644 --- a/core/index.d.ts +++ b/core/index.d.ts @@ -137,6 +137,7 @@ export interface ContextProviderExtras { } export interface LoadSubmenuItemsArgs { + config: ContinueConfig; ide: IDE; fetch: FetchFunction; } @@ -374,8 +375,10 @@ export type CustomLLM = RequireAtLeastOne< // IDE +export type DiffLineType = "new" | "old" | "same"; + export interface DiffLine { - type: "new" | "old" | "same"; + type: DiffLineType; line: string; } @@ -419,6 +422,9 @@ export interface IdeSettings { remoteConfigServerUrl: string | undefined; remoteConfigSyncPeriod: number; userToken: string; + enableControlServerBeta: boolean; + pauseCodebaseIndexOnStart: boolean; + enableDebugLogs: boolean; } export interface IDE { @@ -595,6 +601,7 @@ export type ModelName = | "gpt-3.5-turbo-0613" | "gpt-4-32k" | "gpt-4o" + | "gpt-4o-mini" | "gpt-4-turbo" | "gpt-4-turbo-preview" | "gpt-4-vision-preview" @@ -732,7 +739,9 @@ export type EmbeddingsProviderName = | "openai" | "cohere" | "free-trial" - | "gemini"; + | "gemini" + | "continue-proxy" + | "deepinfra"; export interface EmbedOptions { apiBase?: string; @@ -742,6 +751,7 @@ export interface EmbedOptions { apiType?: string; apiVersion?: string; requestOptions?: RequestOptions; + maxChunkSize?: number; } export interface EmbeddingsProviderDescription extends EmbedOptions { @@ -750,10 +760,18 @@ export interface EmbeddingsProviderDescription extends EmbedOptions { export interface EmbeddingsProvider { id: string; + providerName: EmbeddingsProviderName; + maxChunkSize: number; embed(chunks: string[]): Promise; } -export type RerankerName = "cohere" | "voyage" | "llm" | "free-trial"; +export type RerankerName = + | "cohere" + | "voyage" + | "llm" + | "free-trial" + | "huggingface-tei" + | "continue-proxy"; export interface RerankerDescription { name: RerankerName; @@ -768,7 +786,7 @@ export interface Reranker { export interface TabAutocompleteOptions { disable: boolean; useCopyBuffer: boolean; - useSuffix: boolean; + useFileSuffix: boolean; maxPromptTokens: number; debounceDelay: number; maxSuffixPercentage: number; @@ -845,6 +863,12 @@ interface ExperimentalConfig { quickActions?: QuickActionConfig[]; } +interface AnalyticsConfig { + type: string; + url?: string; + clientKey?: string; +} + // config.json export interface SerializedContinueConfig { env?: string[]; @@ -865,6 +889,7 @@ export interface SerializedContinueConfig { ui?: ContinueUIConfig; reranker?: RerankerDescription; experimental?: ExperimentalConfig; + analytics?: AnalyticsConfig; } export type ConfigMergeType = "merge" | "overwrite"; @@ -915,6 +940,8 @@ export interface Config { reranker?: RerankerDescription | Reranker; /** Experimental configuration */ experimental?: ExperimentalConfig; + /** Analytics configuration */ + analytics?: AnalyticsConfig; } // in the actual Continue source code @@ -935,6 +962,8 @@ export interface ContinueConfig { ui?: ContinueUIConfig; reranker?: Reranker; experimental?: ExperimentalConfig; + analytics?: AnalyticsConfig; + docs?: SiteIndexingConfig[]; } export interface BrowserSerializedContinueConfig { @@ -952,4 +981,5 @@ export interface BrowserSerializedContinueConfig { ui?: ContinueUIConfig; reranker?: RerankerDescription; experimental?: ExperimentalConfig; + analytics?: AnalyticsConfig; } diff --git a/core/indexing/CodebaseIndexer.ts b/core/indexing/CodebaseIndexer.ts index 5b90e0775..939487aad 100644 --- a/core/indexing/CodebaseIndexer.ts +++ b/core/indexing/CodebaseIndexer.ts @@ -1,4 +1,4 @@ -import { IConfigHandler } from "../config/IConfigHandler.js"; +import { ConfigHandler } from "../config/ConfigHandler.js"; import { IContinueServerClient } from "../continueServer/interface.js"; import { IDE, IndexTag, IndexingProgressUpdate } from "../index.js"; import { CodeSnippetsCodebaseIndex } from "./CodeSnippetsIndex.js"; @@ -6,7 +6,7 @@ import { FullTextSearchCodebaseIndex } from "./FullTextSearch.js"; import { LanceDbIndex } from "./LanceDbIndex.js"; import { ChunkCodebaseIndex } from "./chunk/ChunkCodebaseIndex.js"; import { getComputeDeleteAddRemove } from "./refreshIndex.js"; -import { CodebaseIndex } from "./types.js"; +import { CodebaseIndex, IndexResultType } from "./types.js"; import { walkDir } from "./walkDir.js"; export class PauseToken { @@ -23,7 +23,7 @@ export class PauseToken { export class CodebaseIndexer { constructor( - private readonly configHandler: IConfigHandler, + private readonly configHandler: ConfigHandler, private readonly ide: IDE, private readonly pauseToken: PauseToken, private readonly continueServerClient: IContinueServerClient, @@ -36,6 +36,7 @@ export class CodebaseIndexer { new ChunkCodebaseIndex( this.ide.readFile.bind(this.ide), this.continueServerClient, + config.embeddingsProvider.maxChunkSize, ), // Chunking must come first new LanceDbIndex( config.embeddingsProvider, @@ -111,7 +112,7 @@ export class CodebaseIndexer { branch, artifactId: codebaseIndex.artifactId, }; - const [results, markComplete] = await getComputeDeleteAddRemove( + const [results, lastUpdated, markComplete] = await getComputeDeleteAddRemove( tag, { ...stats }, (filepath) => this.ide.readFile(filepath), @@ -158,6 +159,10 @@ export class CodebaseIndexer { }; } + lastUpdated.forEach((lastUpdated, path) => { + markComplete([lastUpdated], IndexResultType.UpdateLastUpdated); + }); + completedRelativeExpectedTime += codebaseIndex.relativeExpectedTime; yield { progress: diff --git a/core/indexing/LanceDbIndex.ts b/core/indexing/LanceDbIndex.ts index 1f6ea709e..4b98040d9 100644 --- a/core/indexing/LanceDbIndex.ts +++ b/core/indexing/LanceDbIndex.ts @@ -9,7 +9,6 @@ import { IndexTag, IndexingProgressUpdate, } from "../index.js"; -import { MAX_CHUNK_SIZE } from "../llm/constants.js"; import { getBasename } from "../util/index.js"; import { getLanceDbPath, migrate } from "../util/paths.js"; import { chunkDocument } from "./chunk/chunk.js"; @@ -36,8 +35,6 @@ export class LanceDbIndex implements CodebaseIndex { return `vectordb::${this.embeddingsProvider.id}`; } - static MAX_CHUNK_SIZE = MAX_CHUNK_SIZE; - constructor( private readonly embeddingsProvider: EmbeddingsProvider, private readonly readFile: (filepath: string) => Promise, @@ -64,10 +61,13 @@ export class LanceDbIndex implements CodebaseIndex { migrate( "lancedb_sqlite_artifact_id_column", async () => { - await db.exec( - `ALTER TABLE lance_db_cache ADD COLUMN artifact_id TEXT NOT NULL DEFAULT 'UNDEFINED'`, - ); - resolve(undefined); + try { + await db.exec( + "ALTER TABLE lance_db_cache ADD COLUMN artifact_id TEXT NOT NULL DEFAULT 'UNDEFINED'", + ); + } finally { + resolve(undefined); + } }, () => resolve(undefined), ), @@ -96,12 +96,12 @@ export class LanceDbIndex implements CodebaseIndex { let hasEmptyChunks = false; - for await (const chunk of chunkDocument( - items[i].path, - content, - LanceDbIndex.MAX_CHUNK_SIZE, - items[i].cacheKey, - )) { + for await (const chunk of chunkDocument({ + filepath: items[i].path, + contents: content, + maxChunkSize: this.embeddingsProvider.maxChunkSize, + digest: items[i].cacheKey, + })) { if (chunk.content.length == 0) { hasEmptyChunks = true; break; diff --git a/core/indexing/chunk/ChunkCodebaseIndex.ts b/core/indexing/chunk/ChunkCodebaseIndex.ts index d1eb2a20c..d80bb1c4f 100644 --- a/core/indexing/chunk/ChunkCodebaseIndex.ts +++ b/core/indexing/chunk/ChunkCodebaseIndex.ts @@ -1,6 +1,5 @@ import { IContinueServerClient } from "../../continueServer/interface.js"; import { Chunk, IndexTag, IndexingProgressUpdate } from "../../index.js"; -import { MAX_CHUNK_SIZE } from "../../llm/constants.js"; import { getBasename } from "../../util/index.js"; import { DatabaseConnection, SqliteDb, tagToString } from "../refreshIndex.js"; import { @@ -19,6 +18,7 @@ export class ChunkCodebaseIndex implements CodebaseIndex { constructor( private readonly readFile: (filepath: string) => Promise, private readonly continueServerClient: IContinueServerClient, + private readonly maxChunkSize: number, ) { this.readFile = readFile; } @@ -105,13 +105,15 @@ export class ChunkCodebaseIndex implements CodebaseIndex { const item = results.compute[i]; // Insert chunks - for await (const chunk of chunkDocument( - item.path, - contents[i], - MAX_CHUNK_SIZE, - item.cacheKey, - )) { - handleChunk(chunk); + if (contents.length) { + for await (const chunk of chunkDocument({ + filepath: item.path, + contents: contents[i], + maxChunkSize: this.maxChunkSize, + digest: item.cacheKey, + })) { + await handleChunk(chunk); + } } accumulatedProgress = @@ -125,17 +127,22 @@ export class ChunkCodebaseIndex implements CodebaseIndex { } // Add tag - for (const item of results.addTag) { - const chunksWithPath = await db.all( - "SELECT * FROM chunks WHERE cacheKey = ?", - [item.cacheKey], - ); + const addContents = await Promise.all( + results.addTag.map(({ path }) => this.readFile(path)), + ); + for (let i = 0; i < results.addTag.length; i++) { + const item = results.addTag[i]; - for (const chunk of chunksWithPath) { - await db.run("INSERT INTO chunk_tags (chunkId, tag) VALUES (?, ?)", [ - chunk.id, - tagString, - ]); + // Insert chunks + if (contents.length) { + for await (const chunk of chunkDocument({ + filepath: item.path, + contents: contents[i], + maxChunkSize: this.maxChunkSize, + digest: item.cacheKey, + })) { + handleChunk(chunk); + } } markComplete([item], IndexResultType.AddTag); diff --git a/core/indexing/chunk/basic.ts b/core/indexing/chunk/basic.ts index ce2f06344..a9b87d43a 100644 --- a/core/indexing/chunk/basic.ts +++ b/core/indexing/chunk/basic.ts @@ -1,10 +1,10 @@ import { ChunkWithoutID } from "../../index.js"; -import { countTokens } from "../../llm/countTokens.js"; +import { countTokensAsync } from "../../llm/countTokens.js"; -export function* basicChunker( +export async function* basicChunker( contents: string, maxChunkSize: number, -): Generator { +): AsyncGenerator { if (contents.trim().length === 0) { return; } @@ -14,18 +14,24 @@ export function* basicChunker( let startLine = 0; let currLine = 0; - for (const line of contents.split("\n")) { - const lineTokens = countTokens(line); - if (chunkTokens + lineTokens > maxChunkSize - 5) { + const lineTokens = await Promise.all(contents.split("\n").map(async l => { + return { + line: l, + tokenCount: await countTokensAsync(l), + }; + })); + + for (const lt of lineTokens) { + if (chunkTokens + lt.tokenCount > maxChunkSize - 5) { yield { content: chunkContent, startLine, endLine: currLine - 1 }; chunkContent = ""; chunkTokens = 0; startLine = currLine; } - if (lineTokens < maxChunkSize) { - chunkContent += `${line}\n`; - chunkTokens += lineTokens + 1; + if (lt.tokenCount < maxChunkSize) { + chunkContent += `${lt.line}\n`; + chunkTokens += lt.tokenCount + 1; } currLine++; diff --git a/core/indexing/chunk/chunk.ts b/core/indexing/chunk/chunk.ts index 04e4f7048..2bdf446a8 100644 --- a/core/indexing/chunk/chunk.ts +++ b/core/indexing/chunk/chunk.ts @@ -1,10 +1,16 @@ import { Chunk, ChunkWithoutID } from "../../index.js"; -import { MAX_CHUNK_SIZE } from "../../llm/constants.js"; -import { countTokens } from "../../llm/countTokens.js"; +import { countTokens, countTokensAsync } from "../../llm/countTokens.js"; import { supportedLanguages } from "../../util/treeSitter.js"; import { basicChunker } from "./basic.js"; import { codeChunker } from "./code.js"; +export type ChunkDocumentParam = { + filepath: string; + contents: string; + maxChunkSize: number; + digest: string; +}; + async function* chunkDocumentWithoutId( filepath: string, contents: string, @@ -31,32 +37,41 @@ async function* chunkDocumentWithoutId( yield* basicChunker(contents, maxChunkSize); } -export async function* chunkDocument( - filepath: string, - contents: string, - maxChunkSize: number, - digest: string, -): AsyncGenerator { +export async function* chunkDocument({ + filepath, + contents, + maxChunkSize, + digest, +}: ChunkDocumentParam): AsyncGenerator { let index = 0; + const chunkPromises: Promise[] = []; for await (const chunkWithoutId of chunkDocumentWithoutId( filepath, contents, maxChunkSize, )) { - if (countTokens(chunkWithoutId.content) > MAX_CHUNK_SIZE) { - console.warn( - `Chunk with more than ${maxChunkSize} tokens constructed: `, + chunkPromises.push(new Promise(async (resolve) => { + if (await countTokensAsync(chunkWithoutId.content) > maxChunkSize) { + console.warn( + `Chunk with more than ${maxChunkSize} tokens constructed: `, + filepath, + countTokens(chunkWithoutId.content), + ); + return resolve(undefined); + } + resolve({ + ...chunkWithoutId, + digest, + index, filepath, - countTokens(chunkWithoutId.content), - ); - continue; - } - yield { - ...chunkWithoutId, - digest, - index, - filepath, - }; + }); + })); index++; } + for await (const chunk of chunkPromises) { + if (!chunk) { + continue; + } + yield chunk; + } } diff --git a/core/indexing/chunk/code.ts b/core/indexing/chunk/code.ts index faf2248b9..724f43641 100644 --- a/core/indexing/chunk/code.ts +++ b/core/indexing/chunk/code.ts @@ -1,6 +1,6 @@ import { SyntaxNode } from "web-tree-sitter"; import { ChunkWithoutID } from "../../index.js"; -import { countTokens } from "../../llm/countTokens.js"; +import { countTokens, countTokensAsync } from "../../llm/countTokens.js"; import { getParserForFile } from "../../util/treeSitter.js"; function collapsedReplacement(node: SyntaxNode): string { @@ -22,14 +22,14 @@ function firstChild( return node.children.find((child) => child.type === grammarName) || null; } -function collapseChildren( +async function collapseChildren( node: SyntaxNode, code: string, blockTypes: string[], collapseTypes: string[], collapseBlockTypes: string[], maxChunkSize: number, -): string { +): Promise { code = code.slice(0, node.endIndex); const block = firstChild(node, blockTypes); const collapsedChildren = []; @@ -58,7 +58,7 @@ function collapseChildren( code = code.slice(node.startIndex); let removedChild = false; while ( - countTokens(code.trim()) > maxChunkSize && + (await countTokensAsync(code.trim())) > maxChunkSize && collapsedChildren.length > 0 ) { removedChild = true; @@ -106,11 +106,11 @@ export const FUNCTION_DECLARATION_NODE_TYPEs = [ "method_declaration", ]; -function constructClassDefinitionChunk( +async function constructClassDefinitionChunk( node: SyntaxNode, code: string, maxChunkSize: number, -): string { +): Promise { return collapseChildren( node, code, @@ -121,11 +121,11 @@ function constructClassDefinitionChunk( ); } -function constructFunctionDefinitionChunk( +async function constructFunctionDefinitionChunk( node: SyntaxNode, code: string, maxChunkSize: number, -): string { +): Promise { const bodyNode = node.children[node.children.length - 1]; const funcText = code.slice(node.startIndex, bodyNode.startIndex) + @@ -153,7 +153,7 @@ const collapsedNodeConstructors: { node: SyntaxNode, code: string, maxChunkSize: number, - ) => string; + ) => Promise; } = { // Classes, structs, etc class_definition: constructClassDefinitionChunk, @@ -165,37 +165,50 @@ const collapsedNodeConstructors: { function_item: constructFunctionDefinitionChunk, }; -function* getSmartCollapsedChunks( +async function maybeYieldChunk( node: SyntaxNode, code: string, maxChunkSize: number, root = true, -): Generator { +): Promise { // Keep entire text if not over size - if ( - (root || node.type in collapsedNodeConstructors) && - countTokens(node.text) < maxChunkSize - ) { - yield { - content: node.text, - startLine: node.startPosition.row, - endLine: node.endPosition.row, - }; + if (root || node.type in collapsedNodeConstructors) { + const tokenCount = await countTokensAsync(node.text); + if (tokenCount < maxChunkSize) { + return { + content: node.text, + startLine: node.startPosition.row, + endLine: node.endPosition.row, + }; + } + } + return undefined; +} + +async function* getSmartCollapsedChunks( + node: SyntaxNode, + code: string, + maxChunkSize: number, + root = true, +): AsyncGenerator { + const chunk = await maybeYieldChunk(node, code, maxChunkSize, root); + if (chunk) { + yield chunk; return; } - // If a collapsed form is defined, use that if (node.type in collapsedNodeConstructors) { yield { - content: collapsedNodeConstructors[node.type](node, code, maxChunkSize), + content: await collapsedNodeConstructors[node.type](node, code, maxChunkSize), startLine: node.startPosition.row, endLine: node.endPosition.row, }; } // Recurse (because even if collapsed version was shown, want to show the children in full somewhere) - for (const child of node.children) { - yield* getSmartCollapsedChunks(child, code, maxChunkSize, false); + const generators = node.children.map((child) => getSmartCollapsedChunks(child, code, maxChunkSize, false)); + for (const generator of generators) { + yield* generator; } } diff --git a/core/indexing/chunk/markdown.ts b/core/indexing/chunk/markdown.ts index ad4594dde..b79ccec8c 100644 --- a/core/indexing/chunk/markdown.ts +++ b/core/indexing/chunk/markdown.ts @@ -78,7 +78,7 @@ export async function* markdownChunker( if (hLevel > 4) { const header = findHeader(content.split("\n")); - for (const chunk of basicChunker(content, maxChunkSize)) { + for await (const chunk of basicChunker(content, maxChunkSize)) { yield { ...chunk, otherMetadata: { diff --git a/core/indexing/docs/DocsService.ts b/core/indexing/docs/DocsService.ts index a76de2cf1..8d2854b9e 100644 --- a/core/indexing/docs/DocsService.ts +++ b/core/indexing/docs/DocsService.ts @@ -3,15 +3,16 @@ import sqlite3 from "sqlite3"; import { Chunk, EmbeddingsProvider, + IdeInfo, IndexingProgressUpdate, SiteIndexingConfig, } from "../../index.js"; import { getDocsSqlitePath, getLanceDbPath } from "../../util/paths.js"; - import { Article, chunkArticle, pageToArticle } from "./article.js"; import { crawlPage } from "./crawl.js"; import { downloadFromS3, SiteIndexingResults } from "./preIndexed.js"; -import { default as configs } from "./preIndexedDocs.js"; +import preIndexedDocs from "./preIndexedDocs.js"; +import TransformersJsEmbeddingsProvider from "../embeddings/TransformersJsEmbeddingsProvider.js"; // Purposefully lowercase because lancedb converts interface LanceDbDocsRow { @@ -29,7 +30,10 @@ interface LanceDbDocsRow { export class DocsService { private static instance: DocsService; private static DOCS_TABLE_NAME = "docs"; + public static preIndexedDocsEmbeddingsProvider = + new TransformersJsEmbeddingsProvider(); private _sqliteTable: Database | undefined; + private docsIndexingQueue: Set = new Set(); public static getInstance(): DocsService { if (!DocsService.instance) { @@ -69,32 +73,35 @@ export class DocsService { nested = false, ): Promise { const lance = await this.getLanceDb(); - const db = await this.getSqliteTable(); + const tableNames = await lance.tableNames(); + const preIndexedDoc = preIndexedDocs[baseUrl]; + const isPreIndexedDoc = !!preIndexedDoc; + let shouldDownloadPreIndexedDoc = + !tableNames.includes(DocsService.DOCS_TABLE_NAME) && isPreIndexedDoc; - const downloadDocs = async () => { - const config = configs.find((config) => config.startUrl === baseUrl); - if (config) { - await this.downloadPreIndexedDocs(embeddingsProviderId, config.title); - return await this.retrieve( - baseUrl, - vector, - nRetrieve, - embeddingsProviderId, - true, - ); - } - return undefined; + const downloadAndRetrievePreIndexedDoc = async ( + preIndexedDoc: SiteIndexingConfig, + ) => { + await this.downloadAndAddPreIndexedDocs( + embeddingsProviderId, + preIndexedDoc.title, + ); + + return await this.retrieve( + baseUrl, + vector, + nRetrieve, + embeddingsProviderId, + true, + ); }; - const tableNames = await lance.tableNames(); - if (!tableNames.includes(DocsService.DOCS_TABLE_NAME)) { - const downloaded = await downloadDocs(); - if (downloaded) { - return downloaded; - } + if (shouldDownloadPreIndexedDoc) { + return await downloadAndRetrievePreIndexedDoc(preIndexedDoc!); } const table = await lance.openTable(DocsService.DOCS_TABLE_NAME); + let docs: LanceDbDocsRow[] = await table .search(vector) .limit(nRetrieve) @@ -103,11 +110,11 @@ export class DocsService { docs = docs.filter((doc) => doc.baseurl === baseUrl); - if ((!docs || docs.length === 0) && !nested) { - const downloaded = await downloadDocs(); - if (downloaded) { - return downloaded; - } + shouldDownloadPreIndexedDoc = + (!docs || docs.length === 0) && !nested && isPreIndexedDoc; + + if (shouldDownloadPreIndexedDoc) { + return await downloadAndRetrievePreIndexedDoc(preIndexedDoc!); } return docs.map((doc) => ({ @@ -183,7 +190,7 @@ export class DocsService { return !!doc; } - private async downloadPreIndexedDocs( + private async downloadAndAddPreIndexedDocs( embeddingsProviderId: string, title: string, ) { @@ -204,10 +211,16 @@ export class DocsService { async *indexAndAdd( siteIndexingConfig: SiteIndexingConfig, embeddingsProvider: EmbeddingsProvider, + reIndex: boolean = false, ): AsyncGenerator { - const startUrl = new URL(siteIndexingConfig.startUrl); + const startUrl = new URL(siteIndexingConfig.startUrl.toString()); - if (await this.has(siteIndexingConfig.startUrl.toString())) { + if (this.docsIndexingQueue.has(startUrl.toString())) { + console.log("Already in queue"); + return; + } + + if (!reIndex && (await this.has(startUrl.toString()))) { yield { progress: 1, desc: "Already indexed", @@ -216,6 +229,9 @@ export class DocsService { return; } + // Mark the site as currently being indexed + this.docsIndexingQueue.add(startUrl.toString()); + yield { progress: 0, desc: "Finding subpages", @@ -223,41 +239,56 @@ export class DocsService { }; const articles: Article[] = []; + let processedPages = 0; + let maxKnownPages = 1; // Crawl pages and retrieve info as articles for await (const page of crawlPage(startUrl, siteIndexingConfig.maxDepth)) { + processedPages++; const article = pageToArticle(page); if (!article) { continue; } articles.push(article); + // Use a heuristic approach for progress calculation + const progress = Math.min(processedPages / maxKnownPages, 1); + yield { - progress: 0, + progress, // Yield the heuristic progress desc: `Finding subpages (${page.path})`, status: "indexing", }; + + // Increase maxKnownPages to delay progress reaching 100% too soon + if (processedPages === maxKnownPages) { + maxKnownPages *= 2; + } } const chunks: Chunk[] = []; const embeddings: number[][] = []; // Create embeddings of retrieved articles - console.log("Creating Embeddings for ", articles.length, " articles"); - for (const article of articles) { + console.log(`Creating embeddings for ${articles.length} articles`); + + for (let i = 0; i < articles.length; i++) { + const article = articles[i]; yield { - progress: Math.max(1, Math.floor(100 / (articles.length + 1))), - desc: `${article.subpath}`, + progress: i / articles.length, + desc: `Creating Embeddings: ${article.subpath}`, status: "indexing", }; try { const subpathEmbeddings = await embeddingsProvider.embed( - chunkArticle(article).map((chunk) => { - chunks.push(chunk); + chunkArticle(article, embeddingsProvider.maxChunkSize).map( + (chunk) => { + chunks.push(chunk); - return chunk.content; - }), + return chunk.content; + }, + ), ); embeddings.push(...subpathEmbeddings); @@ -268,7 +299,20 @@ export class DocsService { // Add docs to databases console.log("Adding ", embeddings.length, " embeddings to db"); + yield { + progress: 0.5, + desc: `Adding ${embeddings.length} embeddings to db`, + status: "indexing", + }; + + // Clear old index if re-indexing. + if (reIndex) { + console.log("Deleting old embeddings"); + await this.delete(startUrl.toString()); + } + await this.add(siteIndexingConfig.title, startUrl, chunks, embeddings); + this.docsIndexingQueue.delete(startUrl.toString()); yield { progress: 1, @@ -276,4 +320,15 @@ export class DocsService { status: "done", }; } + + public isJetBrainsAndPreIndexedDocsProvider( + ideInfo: IdeInfo, + embeddingsProviderId: EmbeddingsProvider["id"], + ): boolean { + const isJetBrains = ideInfo.ideType === "jetbrains"; + const isPreIndexedDocsProvider = + embeddingsProviderId === DocsService.preIndexedDocsEmbeddingsProvider.id; + + return isJetBrains && isPreIndexedDocsProvider; + } } diff --git a/core/indexing/docs/article.ts b/core/indexing/docs/article.ts index 4bf903142..d1f6a94a7 100644 --- a/core/indexing/docs/article.ts +++ b/core/indexing/docs/article.ts @@ -1,7 +1,6 @@ import { Readability } from "@mozilla/readability"; import { JSDOM } from "jsdom"; import { Chunk } from "../../index.js"; -import { MAX_CHUNK_SIZE } from "../../llm/constants.js"; import { cleanFragment, cleanHeader } from "../chunk/markdown.js"; import { PageData } from "./crawl.js"; @@ -21,6 +20,7 @@ function breakdownArticleComponent( url: string, article: ArticleComponent, subpath: string, + max_chunk_size: number, ): Chunk[] { const chunks: Chunk[] = []; @@ -32,7 +32,7 @@ function breakdownArticleComponent( for (let i = 0; i < lines.length; i++) { const line = lines[i]; - if (content.length + line.length <= MAX_CHUNK_SIZE) { + if (content.length + line.length <= max_chunk_size) { content += `${line}\n`; endLine = i; } else { @@ -79,7 +79,10 @@ function breakdownArticleComponent( return chunks.filter((c) => c.content.trim().length > 20); } -export function chunkArticle(articleResult: Article): Chunk[] { +export function chunkArticle( + articleResult: Article, + maxChunkSize: number, +): Chunk[] { let chunks: Chunk[] = []; for (const article of articleResult.article_components) { @@ -87,6 +90,7 @@ export function chunkArticle(articleResult: Article): Chunk[] { articleResult.url, article, articleResult.subpath, + maxChunkSize, ); chunks = [...chunks, ...articleChunks]; } diff --git a/core/indexing/docs/crawl.ts b/core/indexing/docs/crawl.ts index 376c7f40c..838a92241 100644 --- a/core/indexing/docs/crawl.ts +++ b/core/indexing/docs/crawl.ts @@ -16,7 +16,7 @@ const IGNORE_PATHS_ENDING_IN = [ "changelog.html", ]; -const GITHUB_PATHS_TO_TRAVERSE = ["/blob/", "/tree/"]; +const markdownRegex = new RegExp(/\.(md|mdx)$/); async function getDefaultBranch(owner: string, repo: string): Promise { const octokit = new Octokit({ auth: undefined }); @@ -53,7 +53,10 @@ async function crawlGithubRepo(baseUrl: URL) { ); const paths = tree.data.tree - .filter((file: any) => file.type === "blob" && file.path?.endsWith(".md")) + .filter( + (file: any) => + file.type === "blob" && markdownRegex.test(file.path ?? ""), + ) .map((file: any) => baseUrl.pathname + "/tree/main/" + file.path); return paths; @@ -142,7 +145,10 @@ export async function* crawlPage( url: URL, maxDepth: number = 3, ): AsyncGenerator { - console.log("Starting crawl from: ", url, " - Max Depth: ", maxDepth); + console.log( + `Starting crawl from: ${url.toString()} - Max Depth: ${maxDepth}`, + ); + const { baseUrl, basePath } = splitUrl(url); let paths: { path: string; depth: number }[] = [{ path: basePath, depth: 0 }]; diff --git a/core/indexing/docs/preIndexedDocs.ts b/core/indexing/docs/preIndexedDocs.ts index 8277adec5..1cb34ba6f 100644 --- a/core/indexing/docs/preIndexedDocs.ts +++ b/core/indexing/docs/preIndexedDocs.ts @@ -1,301 +1,305 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { SiteIndexingConfig } from "../../index.js"; -const configs: SiteIndexingConfig[] = [ - { +const preIndexedDocs: Record< + SiteIndexingConfig["startUrl"], + SiteIndexingConfig +> = { + "https://jinja.palletsprojects.com/en/3.1.x/": { title: "Jinja", startUrl: "https://jinja.palletsprojects.com/en/3.1.x/", rootUrl: "https://jinja.palletsprojects.com/en/3.1.x/", faviconUrl: "https://jinja.palletsprojects.com/favicon.ico", }, - { + "https://react.dev/reference/": { title: "React", startUrl: "https://react.dev/reference/", rootUrl: "https://react.dev/reference/", faviconUrl: "https://react.dev/favicon.ico", }, - { + "https://posthog.com/docs": { title: "PostHog", startUrl: "https://posthog.com/docs", rootUrl: "https://posthog.com/docs", faviconUrl: "https://posthog.com/favicon.ico", }, - { + "https://expressjs.com/en/5x/api.html": { title: "Express", startUrl: "https://expressjs.com/en/5x/api.html", rootUrl: "https://expressjs.com/en/5x/", faviconUrl: "https://expressjs.com/favicon.ico", }, - { + "https://platform.openai.com/docs/": { title: "OpenAI", startUrl: "https://platform.openai.com/docs/", rootUrl: "https://platform.openai.com/docs/", faviconUrl: "https://platform.openai.com/favicon.ico", }, - { + "https://www.prisma.io/docs": { title: "Prisma", startUrl: "https://www.prisma.io/docs", rootUrl: "https://www.prisma.io/docs", faviconUrl: "https://www.prisma.io/favicon.ico", }, - { + "https://boto3.amazonaws.com/v1/documentation/api/latest/index.html": { title: "Boto3", startUrl: "https://boto3.amazonaws.com/v1/documentation/api/latest/index.html", rootUrl: "https://boto3.amazonaws.com/v1/documentation/api/latest/", faviconUrl: "https://boto3.amazonaws.com/favicon.ico", }, - { + "https://pytorch.org/docs/stable/": { title: "Pytorch", startUrl: "https://pytorch.org/docs/stable/", rootUrl: "https://pytorch.org/docs/stable/", faviconUrl: "https://pytorch.org/favicon.ico", }, - { + "https://redis.io/docs/": { title: "Redis", startUrl: "https://redis.io/docs/", rootUrl: "https://redis.io/docs/", faviconUrl: "https://redis.io/favicon.ico", }, - { + "https://axios-http.com/docs/intro": { title: "Axios", startUrl: "https://axios-http.com/docs/intro", rootUrl: "https://axios-http.com/docs", faviconUrl: "https://axios-http.com/favicon.ico", }, - { + "https://redwoodjs.com/docs/introduction": { title: "Redwood JS", startUrl: "https://redwoodjs.com/docs/introduction", rootUrl: "https://redwoodjs.com/docs", faviconUrl: "https://redwoodjs.com/favicon.ico", }, - { + "https://graphql.org/learn/": { title: "GraphQL", startUrl: "https://graphql.org/learn/", rootUrl: "https://graphql.org/learn/", faviconUrl: "https://graphql.org/favicon.ico", }, - { + "https://www.typescriptlang.org/docs/": { title: "Typescript", startUrl: "https://www.typescriptlang.org/docs/", rootUrl: "https://www.typescriptlang.org/docs/", faviconUrl: "https://www.typescriptlang.org/favicon.ico", }, - { + "https://jestjs.io/docs/getting-started": { title: "Jest", startUrl: "https://jestjs.io/docs/getting-started", rootUrl: "https://jestjs.io/docs", faviconUrl: "https://jestjs.io/favicon.ico", }, - { + "https://tailwindcss.com/docs/installation": { title: "Tailwind CSS", startUrl: "https://tailwindcss.com/docs/installation", rootUrl: "https://tailwindcss.com/docs", faviconUrl: "https://tailwindcss.com/favicon.ico", }, - { + "https://vuejs.org/guide/introduction.html": { title: "Vue.js", startUrl: "https://vuejs.org/guide/introduction.html", rootUrl: "https://vuejs.org", faviconUrl: "https://vuejs.org/favicon.ico", }, - { + "https://svelte.dev/docs/introduction": { title: "Svelte", startUrl: "https://svelte.dev/docs/introduction", rootUrl: "https://svelte.dev/docs", faviconUrl: "https://svelte.dev/favicon.ico", }, - { + "https://docs.github.com/en/actions": { title: "GitHub Actions", startUrl: "https://docs.github.com/en/actions", rootUrl: "https://docs.github.com/en/actions", faviconUrl: "https://docs.github.com/favicon.ico", }, - { + "https://nodejs.org/docs/latest/api/": { title: "NodeJS", startUrl: "https://nodejs.org/docs/latest/api/", rootUrl: "https://nodejs.org/docs/latest/api/", faviconUrl: "https://nodejs.org/favicon.ico", }, - { + "https://socket.io/docs/v4/": { title: "Socket.io", startUrl: "https://socket.io/docs/v4/", rootUrl: "https://socket.io/docs/v4/", faviconUrl: "https://socket.io/favicon.ico", }, - { + "https://docs.gradle.org/current/userguide/userguide.html": { title: "Gradle", startUrl: "https://docs.gradle.org/current/userguide/userguide.html", rootUrl: "https://docs.gradle.org/current", faviconUrl: "https://docs.gradle.org/favicon.ico", }, - { + "https://redux-toolkit.js.org/introduction/getting-started": { title: "Redux Toolkit", startUrl: "https://redux-toolkit.js.org/introduction/getting-started", rootUrl: "https://redux-toolkit.js.org", faviconUrl: "https://redux-toolkit.js.org/favicon.ico", }, - { + "https://docs.trychroma.com/": { title: "Chroma", startUrl: "https://docs.trychroma.com/", rootUrl: "https://docs.trychroma.com/", faviconUrl: "https://docs.trychroma.com/favicon.ico", }, - { + "https://www.sqlite.org/docs.html": { title: "SQLite", startUrl: "https://www.sqlite.org/docs.html", rootUrl: "https://www.sqlite.org", faviconUrl: "https://www.sqlite.org/favicon.ico", }, - { + "https://redux.js.org/introduction/getting-started": { title: "Redux", startUrl: "https://redux.js.org/introduction/getting-started", rootUrl: "https://redux.js.org", faviconUrl: "https://redux.js.org/favicon.ico", }, - { + "https://prettier.io/docs/en/": { title: "Prettier", startUrl: "https://prettier.io/docs/en/", rootUrl: "https://prettier.io/docs/en/", faviconUrl: "https://prettier.io/favicon.ico", }, - { + "https://code.visualstudio.com/api": { title: "VS Code Extension API", startUrl: "https://code.visualstudio.com/api", rootUrl: "https://code.visualstudio.com/api", faviconUrl: "https://code.visualstudio.com/favicon.ico", }, - { + "https://docs.continue.dev/intro": { title: "Continue", startUrl: "https://docs.continue.dev/intro", rootUrl: "https://docs.continue.dev", faviconUrl: "https://docs.continue.dev/favicon.ico", }, - { + "https://api.jquery.com/": { title: "jQuery", startUrl: "https://api.jquery.com/", rootUrl: "https://api.jquery.com/", faviconUrl: "https://api.jquery.com/favicon.ico", }, - { + "https://docs.python.org/3/": { title: "Python", startUrl: "https://docs.python.org/3/", rootUrl: "https://docs.python.org/3/", faviconUrl: "https://docs.python.org/favicon.ico", }, - { + "https://doc.rust-lang.org/book/": { title: "Rust", startUrl: "https://doc.rust-lang.org/book/", rootUrl: "https://doc.rust-lang.org/book/", faviconUrl: "https://doc.rust-lang.org/favicon.ico", }, - { + "https://plugins.jetbrains.com/docs/intellij/welcome.html": { title: "IntelliJ Platform SDK", startUrl: "https://plugins.jetbrains.com/docs/intellij/welcome.html", rootUrl: "https://plugins.jetbrains.com/docs/intellij", faviconUrl: "https://plugins.jetbrains.com/favicon.ico", }, - { + "https://docs.docker.com/": { title: "Docker", startUrl: "https://docs.docker.com/", rootUrl: "https://docs.docker.com/", faviconUrl: "https://docs.docker.com/favicon.ico", }, - { + "https://docs.npmjs.com/": { title: "NPM", startUrl: "https://docs.npmjs.com/", rootUrl: "https://docs.npmjs.com/", faviconUrl: "https://docs.npmjs.com/favicon.ico", }, - { + "https://tiptap.dev/docs/editor/introduction": { title: "TipTap", startUrl: "https://tiptap.dev/docs/editor/introduction", rootUrl: "https://tiptap.dev/docs", faviconUrl: "https://tiptap.dev/favicon.ico", }, - { + "https://esbuild.github.io/": { title: "esbuild", startUrl: "https://esbuild.github.io/", rootUrl: "https://esbuild.github.io/", faviconUrl: "https://esbuild.github.io/favicon.ico", }, - { + "https://tree-sitter.github.io/tree-sitter/": { title: "Tree Sitter", startUrl: "https://tree-sitter.github.io/tree-sitter/", rootUrl: "https://tree-sitter.github.io/tree-sitter/", faviconUrl: "https://tree-sitter.github.io/favicon.ico", }, - { + "https://docs.netlify.com/": { title: "Netlify", startUrl: "https://docs.netlify.com/", rootUrl: "https://docs.netlify.com/", faviconUrl: "https://docs.netlify.com/favicon.ico", }, - { + "https://replicate.com/docs": { title: "Replicate", startUrl: "https://replicate.com/docs", rootUrl: "https://replicate.com/docs", faviconUrl: "https://replicate.com/favicon.ico", }, - { + "https://www.w3schools.com/html/default.asp": { title: "HTML", startUrl: "https://www.w3schools.com/html/default.asp", rootUrl: "https://www.w3schools.com/html", faviconUrl: "https://www.w3schools.com/favicon.ico", }, - { + "https://www.w3schools.com/css/default.asp": { title: "CSS", startUrl: "https://www.w3schools.com/css/default.asp", rootUrl: "https://www.w3schools.com/css", faviconUrl: "https://www.w3schools.com/favicon.ico", }, - { + "https://python.langchain.com/docs/get_started/introduction": { title: "Langchain", startUrl: "https://python.langchain.com/docs/get_started/introduction", rootUrl: "https://python.langchain.com/docs", faviconUrl: "https://python.langchain.com/favicon.ico", }, - { + "https://developer.woocommerce.com/docs/": { title: "WooCommerce", startUrl: "https://developer.woocommerce.com/docs/", rootUrl: "https://developer.woocommerce.com/docs/", faviconUrl: "https://developer.woocommerce.com/favicon.ico", }, - { + "https://developer.wordpress.org/reference/": { title: "WordPress", startUrl: "https://developer.wordpress.org/reference/", rootUrl: "https://developer.wordpress.org/reference/", faviconUrl: "https://developer.wordpress.org/favicon.ico", }, - { + "https://doc.qt.io/qtforpython-6/quickstart.html": { title: "PySide6", startUrl: "https://doc.qt.io/qtforpython-6/quickstart.html", rootUrl: "https://doc.qt.io/qtforpython-6/api.html", faviconUrl: "https://doc.qt.io/favicon.ico", }, - { + "https://getbootstrap.com/docs/5.3/getting-started/introduction/": { title: "Bootstrap", startUrl: "https://getbootstrap.com/docs/5.3/getting-started/introduction/", rootUrl: "https://getbootstrap.com/docs/5.3/", faviconUrl: "https://getbootstrap.com/favicon.ico", }, - { + "https://alpinejs.dev/start-here": { title: "Alpine.js", startUrl: "https://alpinejs.dev/start-here", rootUrl: "https://alpinejs.dev/", faviconUrl: "https://alpinejs.dev/favicon.ico", }, - { + "https://learn.microsoft.com/en-us/dotnet/csharp/": { title: "C# Language Reference", startUrl: "https://learn.microsoft.com/en-us/dotnet/csharp/", rootUrl: "https://learn.microsoft.com/en-us/dotnet/csharp/", faviconUrl: "https://learn.microsoft.com/favicon.ico", }, - { + "https://docs.godotengine.org/en/latest/": { title: "Godot", startUrl: "https://docs.godotengine.org/en/latest/", rootUrl: "https://docs.godotengine.org/en/latest/", faviconUrl: "https://godotengine.org/favicon.ico", }, -]; +}; -export default configs; +export default preIndexedDocs; diff --git a/core/indexing/embeddings/BaseEmbeddingsProvider.ts b/core/indexing/embeddings/BaseEmbeddingsProvider.ts index cd67a001a..f4ea7af2e 100644 --- a/core/indexing/embeddings/BaseEmbeddingsProvider.ts +++ b/core/indexing/embeddings/BaseEmbeddingsProvider.ts @@ -1,9 +1,12 @@ import { EmbedOptions, EmbeddingsProvider, + EmbeddingsProviderName, FetchFunction, } from "../../index.js"; +import { MAX_CHUNK_SIZE } from "../../llm/constants.js"; + export interface IBaseEmbeddingsProvider extends EmbeddingsProvider { options: EmbedOptions; fetch: FetchFunction; @@ -15,6 +18,11 @@ abstract class BaseEmbeddingsProvider implements IBaseEmbeddingsProvider { static maxBatchSize: IBaseEmbeddingsProvider["maxBatchSize"]; static defaultOptions: IBaseEmbeddingsProvider["defaultOptions"]; + static providerName: EmbeddingsProviderName; + get providerName(): EmbeddingsProviderName { + return (this.constructor as typeof BaseEmbeddingsProvider).providerName; + } + options: IBaseEmbeddingsProvider["options"]; fetch: IBaseEmbeddingsProvider["fetch"]; id: IBaseEmbeddingsProvider["id"]; @@ -29,11 +37,22 @@ abstract class BaseEmbeddingsProvider implements IBaseEmbeddingsProvider { ...options, }; this.fetch = fetch; - this.id = `${this.constructor.name}::${this.options.model}`; + // Include the `max_chunk_size` if it is not the default, since we need to create other indices for different chunk_sizes + if (this.maxChunkSize !== MAX_CHUNK_SIZE) { + this.id = `${this.constructor.name}::${this.options.model}::${this.maxChunkSize}`; + } else { + this.id = `${this.constructor.name}::${this.options.model}`; + } } + defaultOptions?: EmbedOptions | undefined; + maxBatchSize?: number | undefined; abstract embed(chunks: string[]): Promise; + get maxChunkSize(): number { + return this.options.maxChunkSize ?? MAX_CHUNK_SIZE; + } + static getBatchedChunks(chunks: string[]): string[][] { if (!this.maxBatchSize) { console.warn( diff --git a/core/indexing/embeddings/CohereEmbeddingsProvider.ts b/core/indexing/embeddings/CohereEmbeddingsProvider.ts index 59dcf23a4..f1e760bb3 100644 --- a/core/indexing/embeddings/CohereEmbeddingsProvider.ts +++ b/core/indexing/embeddings/CohereEmbeddingsProvider.ts @@ -1,11 +1,13 @@ import { Response } from "node-fetch"; -import { EmbedOptions } from "../../index.js"; +import { EmbeddingsProviderName, EmbedOptions } from "../../index.js"; import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider.js"; class CohereEmbeddingsProvider extends BaseEmbeddingsProvider { static maxBatchSize = 96; + static providerName: EmbeddingsProviderName = "cohere"; + static defaultOptions: Partial | undefined = { apiBase: "https://api.cohere.ai/v1/", model: "embed-english-v3.0", diff --git a/core/indexing/embeddings/ContinueProxyEmbeddingsProvider.ts b/core/indexing/embeddings/ContinueProxyEmbeddingsProvider.ts new file mode 100644 index 000000000..377bd6be8 --- /dev/null +++ b/core/indexing/embeddings/ContinueProxyEmbeddingsProvider.ts @@ -0,0 +1,25 @@ +import { EmbeddingsProviderName, EmbedOptions } from "../.."; +import { CONTROL_PLANE_URL } from "../../control-plane/client"; +import OpenAIEmbeddingsProvider from "./OpenAIEmbeddingsProvider"; + +class ContinueProxyEmbeddingsProvider extends OpenAIEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "continue-proxy"; + static defaultOptions: Partial | undefined = { + apiBase: new URL("/model-proxy/v1", CONTROL_PLANE_URL).toString(), + }; + + private _workOsAccessToken: string | undefined = undefined; + + get workOsAccessToken(): string | undefined { + return this._workOsAccessToken; + } + + set workOsAccessToken(value: string | undefined) { + if (this._workOsAccessToken !== value) { + this._workOsAccessToken = value; + this.options.apiKey = value; + } + } +} + +export default ContinueProxyEmbeddingsProvider; diff --git a/core/indexing/embeddings/DeepInfraEmbeddingsProvider.ts b/core/indexing/embeddings/DeepInfraEmbeddingsProvider.ts index 32c482267..11444ab68 100644 --- a/core/indexing/embeddings/DeepInfraEmbeddingsProvider.ts +++ b/core/indexing/embeddings/DeepInfraEmbeddingsProvider.ts @@ -1,8 +1,9 @@ -import { EmbedOptions } from "../../index.js"; +import { EmbeddingsProviderName, EmbedOptions } from "../../index.js"; import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider.js"; class DeepInfraEmbeddingsProvider extends BaseEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "deepinfra"; static defaultOptions: Partial | undefined = { model: "sentence-transformers/all-MiniLM-L6-v2", }; diff --git a/core/indexing/embeddings/FreeTrialEmbeddingsProvider.ts b/core/indexing/embeddings/FreeTrialEmbeddingsProvider.ts index 6d356cef9..70cd3d8c7 100644 --- a/core/indexing/embeddings/FreeTrialEmbeddingsProvider.ts +++ b/core/indexing/embeddings/FreeTrialEmbeddingsProvider.ts @@ -1,11 +1,16 @@ import { Response } from "node-fetch"; import { getHeaders } from "../../continueServer/stubs/headers.js"; import { constants } from "../../deploy/constants.js"; -import { EmbedOptions, FetchFunction } from "../../index.js"; +import { + EmbeddingsProviderName, + EmbedOptions, + FetchFunction, +} from "../../index.js"; import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider.js"; class FreeTrialEmbeddingsProvider extends BaseEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "free-trial"; static maxBatchSize = 128; static defaultOptions: Partial | undefined = { diff --git a/core/indexing/embeddings/GeminiEmbeddingsProvider.ts b/core/indexing/embeddings/GeminiEmbeddingsProvider.ts index 3de46d5e7..45eb5137e 100644 --- a/core/indexing/embeddings/GeminiEmbeddingsProvider.ts +++ b/core/indexing/embeddings/GeminiEmbeddingsProvider.ts @@ -1,17 +1,17 @@ -import { Response } from "node-fetch"; -import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; -import BaseEmbeddingsProvider, { - IBaseEmbeddingsProvider, -} from "./BaseEmbeddingsProvider.js"; import { EmbedContentRequest, EmbedContentResponse, } from "@google/generative-ai"; +import { Response } from "node-fetch"; +import { EmbeddingsProviderName } from "../../index.js"; +import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; +import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider.js"; /** * [View the Gemini Text Embedding docs.](https://ai.google.dev/gemini-api/docs/models/gemini#text-embedding-and-embedding) */ class GeminiEmbeddingsProvider extends BaseEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "gemini"; static maxBatchSize = 2048; static defaultOptions = { diff --git a/core/indexing/embeddings/HuggingFaceTEIEmbeddingsProvider.ts b/core/indexing/embeddings/HuggingFaceTEIEmbeddingsProvider.ts index 3efaa74dd..7315f368d 100644 --- a/core/indexing/embeddings/HuggingFaceTEIEmbeddingsProvider.ts +++ b/core/indexing/embeddings/HuggingFaceTEIEmbeddingsProvider.ts @@ -1,10 +1,11 @@ -import fetch, { Response } from "node-fetch"; -import { EmbedOptions, FetchFunction } from "../.."; +import { Response } from "node-fetch"; +import { EmbeddingsProviderName, EmbedOptions, FetchFunction } from "../.."; import { withExponentialBackoff } from "../../util/withExponentialBackoff"; import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider"; class HuggingFaceTEIEmbeddingsProvider extends BaseEmbeddingsProvider { - private maxBatchSize = 32; + static providerName: EmbeddingsProviderName = "huggingface-tei"; + maxBatchSize = 32; static defaultOptions: Partial | undefined = { apiBase: "http://localhost:8080", @@ -17,7 +18,7 @@ class HuggingFaceTEIEmbeddingsProvider extends BaseEmbeddingsProvider { if (!this.options.apiBase?.endsWith("/")) { this.options.apiBase += "/"; } - this.doInfoRequest().then(response => { + this.doInfoRequest().then((response) => { this.options.model = response.model_id; this.maxBatchSize = response.max_client_batch_size; }); @@ -26,7 +27,9 @@ class HuggingFaceTEIEmbeddingsProvider extends BaseEmbeddingsProvider { async embed(chunks: string[]) { const promises = []; for (let i = 0; i < chunks.length; i += this.maxBatchSize) { - promises.push(this.doEmbedRequest(chunks.slice(i, i + this.maxBatchSize))); + promises.push( + this.doEmbedRequest(chunks.slice(i, i + this.maxBatchSize)), + ); } const results = await Promise.all(promises); return results.flat(); @@ -37,11 +40,11 @@ class HuggingFaceTEIEmbeddingsProvider extends BaseEmbeddingsProvider { this.fetch(new URL("embed", this.options.apiBase), { method: "POST", body: JSON.stringify({ - inputs: batch + inputs: batch, }), headers: { "Content-Type": "application/json", - } + }, }), ); if (!resp.ok) { @@ -75,9 +78,9 @@ class TEIEmbedError extends Error { } type TEIEmbedErrorResponse = { - error: string - error_type: string -} + error: string; + error_type: string; +}; type TEIInfoResponse = { model_id: string; @@ -86,7 +89,7 @@ type TEIInfoResponse = { model_type: { embedding: { pooling: string; - } + }; }; max_concurrent_requests: number; max_input_length: number; diff --git a/core/indexing/embeddings/OllamaEmbeddingsProvider.ts b/core/indexing/embeddings/OllamaEmbeddingsProvider.ts index d7fd6bbe0..58fa5f265 100644 --- a/core/indexing/embeddings/OllamaEmbeddingsProvider.ts +++ b/core/indexing/embeddings/OllamaEmbeddingsProvider.ts @@ -1,4 +1,8 @@ -import { EmbedOptions, FetchFunction } from "../../index.js"; +import { + EmbeddingsProviderName, + EmbedOptions, + FetchFunction, +} from "../../index.js"; import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; import BaseEmbeddingsProvider, { IBaseEmbeddingsProvider, @@ -10,12 +14,21 @@ async function embedOne( customFetch: FetchFunction, ) { const embedding = await withExponentialBackoff(async () => { - const resp = await customFetch(new URL("api/embeddings", options.apiBase), { + let apiBase = options.apiBase!; + + if (!apiBase.endsWith("/")) { + apiBase += "/"; + } + + const resp = await customFetch(new URL("api/embeddings", apiBase), { method: "POST", body: JSON.stringify({ model: options.model, prompt: chunk, }), + headers: { + "Content-Type": "application/json", + }, }); if (!resp.ok) { @@ -35,6 +48,7 @@ async function embedOne( } class OllamaEmbeddingsProvider extends BaseEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "ollama"; static defaultOptions: IBaseEmbeddingsProvider["defaultOptions"] = { apiBase: "http://localhost:11434/", model: "nomic-embed-text", diff --git a/core/indexing/embeddings/OpenAIEmbeddingsProvider.ts b/core/indexing/embeddings/OpenAIEmbeddingsProvider.ts index 01a85ee5e..fc6af4547 100644 --- a/core/indexing/embeddings/OpenAIEmbeddingsProvider.ts +++ b/core/indexing/embeddings/OpenAIEmbeddingsProvider.ts @@ -1,9 +1,10 @@ import { Response } from "node-fetch"; -import { EmbedOptions } from "../../index.js"; +import { EmbeddingsProviderName, EmbedOptions } from "../../index.js"; import { withExponentialBackoff } from "../../util/withExponentialBackoff.js"; import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider.js"; class OpenAIEmbeddingsProvider extends BaseEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "openai"; // https://platform.openai.com/docs/api-reference/embeddings/create is 2048 // but Voyage is 128 static maxBatchSize = 128; diff --git a/core/indexing/embeddings/TransformersJsEmbeddingsProvider.ts b/core/indexing/embeddings/TransformersJsEmbeddingsProvider.ts index 069c5efd2..c7b99dbab 100644 --- a/core/indexing/embeddings/TransformersJsEmbeddingsProvider.ts +++ b/core/indexing/embeddings/TransformersJsEmbeddingsProvider.ts @@ -1,4 +1,5 @@ import path from "path"; +import { EmbeddingsProviderName } from "../../index.js"; // @ts-ignore // prettier-ignore import { type PipelineType } from "../../vendor/modules/@xenova/transformers/src/transformers.js"; @@ -37,10 +38,14 @@ class EmbeddingsPipeline { } export class TransformersJsEmbeddingsProvider extends BaseEmbeddingsProvider { + static providerName: EmbeddingsProviderName = "transformers.js"; static maxGroupSize: number = 4; + static model: string = "all-MiniLM-L6-v2"; constructor() { - super({ model: "all-MiniLM-L6-v2" }, () => Promise.resolve(null)); + super({ model: TransformersJsEmbeddingsProvider.model }, () => + Promise.resolve(null), + ); } async embed(chunks: string[]) { diff --git a/core/indexing/embeddings/index.ts b/core/indexing/embeddings/index.ts index f3979dd98..f39dee4fa 100644 --- a/core/indexing/embeddings/index.ts +++ b/core/indexing/embeddings/index.ts @@ -1,12 +1,14 @@ import { EmbeddingsProviderName } from "../../index.js"; import BaseEmbeddingsProvider from "./BaseEmbeddingsProvider.js"; import CohereEmbeddingsProvider from "./CohereEmbeddingsProvider.js"; +import ContinueProxyEmbeddingsProvider from "./ContinueProxyEmbeddingsProvider.js"; +import DeepInfraEmbeddingsProvider from "./DeepInfraEmbeddingsProvider.js"; import FreeTrialEmbeddingsProvider from "./FreeTrialEmbeddingsProvider.js"; +import GeminiEmbeddingsProvider from "./GeminiEmbeddingsProvider.js"; import HuggingFaceTEIEmbeddingsProvider from "./HuggingFaceTEIEmbeddingsProvider.js"; import OllamaEmbeddingsProvider from "./OllamaEmbeddingsProvider.js"; import OpenAIEmbeddingsProvider from "./OpenAIEmbeddingsProvider.js"; import TransformersJsEmbeddingsProvider from "./TransformersJsEmbeddingsProvider.js"; -import GeminiEmbeddingsProvider from "./GeminiEmbeddingsProvider.js"; type EmbeddingsProviderConstructor = new ( ...args: any[] @@ -26,4 +28,6 @@ export const allEmbeddingsProviders: Record< // eslint-disable-next-line @typescript-eslint/naming-convention "huggingface-tei": HuggingFaceTEIEmbeddingsProvider, gemini: GeminiEmbeddingsProvider, + "continue-proxy": ContinueProxyEmbeddingsProvider, + deepinfra: DeepInfraEmbeddingsProvider, }; diff --git a/core/indexing/ignore.ts b/core/indexing/ignore.ts index c800f2786..35fd84aa1 100644 --- a/core/indexing/ignore.ts +++ b/core/indexing/ignore.ts @@ -64,11 +64,13 @@ export const DEFAULT_IGNORE_FILETYPES = [ ".gitkeep", ".continueignore", "config.json", + ".csv", // "*.prompt", // can be incredibly confusing for the LLM to have another set of instructions injected into the prompt ]; export const defaultIgnoreFile = ignore().add(DEFAULT_IGNORE_FILETYPES); export const DEFAULT_IGNORE_DIRS = [ ".git", + ".svn", ".vscode", ".idea", ".vs", diff --git a/core/indexing/refreshIndex.ts b/core/indexing/refreshIndex.ts index c67379960..db69c8725 100644 --- a/core/indexing/refreshIndex.ts +++ b/core/indexing/refreshIndex.ts @@ -44,6 +44,36 @@ export class SqliteDb { artifactId STRING NOT NULL )`, ); + // Delete duplicate rows from tag_catalog + await db.exec(` + DELETE FROM tag_catalog + WHERE id NOT IN ( + SELECT MIN(id) + FROM tag_catalog + GROUP BY dir, branch, artifactId, path, cacheKey + ) + `); + + // Delete duplicate rows from global_cache + await db.exec(` + DELETE FROM global_cache + WHERE id NOT IN ( + SELECT MIN(id) + FROM global_cache + GROUP BY cacheKey, dir, branch, artifactId + ) + `); + + // Add unique constraints if they don't exist + await db.exec( + `CREATE UNIQUE INDEX IF NOT EXISTS idx_tag_catalog_unique + ON tag_catalog(dir, branch, artifactId, path, cacheKey)`, + ); + + await db.exec( + `CREATE UNIQUE INDEX IF NOT EXISTS idx_global_cache_unique + ON global_cache(cacheKey, dir, branch, artifactId)`, + ); } private static indexSqlitePath = getIndexSqlitePath(); @@ -90,14 +120,24 @@ enum AddRemoveResultType { Remove = "remove", UpdateNewVersion = "updateNewVersion", UpdateOldVersion = "updateOldVersion", + UpdateLastUpdated = "updateLastUpdated", + Compute = "compute" } async function getAddRemoveForTag( tag: IndexTag, currentFiles: LastModifiedMap, readFile: (path: string) => Promise, -): Promise<[PathAndCacheKey[], PathAndCacheKey[], MarkCompleteCallback]> { +): Promise< + [ + PathAndCacheKey[], + PathAndCacheKey[], + PathAndCacheKey[], + MarkCompleteCallback, + ] +> { const newLastUpdatedTimestamp = Date.now(); + const files = { ...currentFiles }; const saved = await getSavedItemsForTag(tag); @@ -105,35 +145,41 @@ async function getAddRemoveForTag( const updateNewVersion: PathAndCacheKey[] = []; const updateOldVersion: PathAndCacheKey[] = []; const remove: PathAndCacheKey[] = []; + const updateLastUpdated: PathAndCacheKey[] = []; for (const item of saved) { const { lastUpdated, ...pathAndCacheKey } = item; - if (currentFiles[item.path] === undefined) { + if (files[item.path] === undefined) { // Was indexed, but no longer exists. Remove remove.push(pathAndCacheKey); } else { // Exists in old and new, so determine whether it was updated - if (lastUpdated < currentFiles[item.path]) { + if (lastUpdated < files[item.path]) { // Change was made after last update - updateNewVersion.push({ - path: pathAndCacheKey.path, - cacheKey: calculateHash(await readFile(pathAndCacheKey.path)), - }); - updateOldVersion.push(pathAndCacheKey); + const newHash = calculateHash(await readFile(pathAndCacheKey.path)); + if (pathAndCacheKey.cacheKey !== newHash) { + updateNewVersion.push({ + path: pathAndCacheKey.path, + cacheKey: newHash, + }); + updateOldVersion.push(pathAndCacheKey); + } else { + updateLastUpdated.push(pathAndCacheKey); + } } else { // Already updated, do nothing } // Remove so we can check leftovers afterward - delete currentFiles[item.path]; + delete files[item.path]; } } // Any leftover in current files need to be added add.push( ...(await Promise.all( - Object.keys(currentFiles).map(async (path) => { + Object.keys(files).map(async (path) => { const fileContents = await readFile(path); return { path, cacheKey: calculateHash(fileContents) }; }), @@ -143,18 +189,43 @@ async function getAddRemoveForTag( // Create the markComplete callback function const db = await SqliteDb.get(); const itemToAction: { - [key: string]: [PathAndCacheKey, AddRemoveResultType]; - } = {}; + [key in AddRemoveResultType]: PathAndCacheKey[]; + } = { + [AddRemoveResultType.Add]: [], + [AddRemoveResultType.Remove]: [], + [AddRemoveResultType.UpdateNewVersion]: [], + [AddRemoveResultType.UpdateOldVersion]: [], + [AddRemoveResultType.UpdateLastUpdated]: [], + [AddRemoveResultType.Compute]: [], + }; - async function markComplete(items: PathAndCacheKey[], _: IndexResultType) { - const actions = items.map( - (item) => - itemToAction[ - JSON.stringify({ path: item.path, cacheKey: item.cacheKey }) - ], - ); - for (const [{ path, cacheKey }, resultType] of actions) { - switch (resultType) { + async function markComplete( + items: PathAndCacheKey[], + resultType: IndexResultType, + ) { + const addRemoveResultType = + mapIndexResultTypeToAddRemoveResultType(resultType); + + const actionItems = itemToAction[addRemoveResultType]; + if (!actionItems) { + console.warn(`No action items found for result type: ${resultType}`); + return; + } + + for (const item of items) { + const { path, cacheKey } = item; + switch (addRemoveResultType) { + case AddRemoveResultType.Compute: + await db.run( + "REPLACE INTO tag_catalog (path, cacheKey, lastUpdated, dir, branch, artifactId) VALUES (?, ?, ?, ?, ?, ?)", + path, + cacheKey, + newLastUpdatedTimestamp, + tag.directory, + tag.branch, + tag.artifactId, + ); + break; case AddRemoveResultType.Add: await db.run( "INSERT INTO tag_catalog (path, cacheKey, lastUpdated, dir, branch, artifactId) VALUES (?, ?, ?, ?, ?, ?)", @@ -182,6 +253,7 @@ async function getAddRemoveForTag( tag.artifactId, ); break; + case AddRemoveResultType.UpdateLastUpdated: case AddRemoveResultType.UpdateNewVersion: await db.run( `UPDATE tag_catalog SET @@ -208,27 +280,22 @@ async function getAddRemoveForTag( } for (const item of updateNewVersion) { - itemToAction[JSON.stringify(item)] = [ - item, - AddRemoveResultType.UpdateNewVersion, - ]; + itemToAction[AddRemoveResultType.UpdateNewVersion].push(item); } for (const item of add) { - itemToAction[JSON.stringify(item)] = [item, AddRemoveResultType.Add]; + itemToAction[AddRemoveResultType.Add].push(item); } for (const item of updateOldVersion) { - itemToAction[JSON.stringify(item)] = [ - item, - AddRemoveResultType.UpdateOldVersion, - ]; + itemToAction[AddRemoveResultType.UpdateOldVersion].push(item); } for (const item of remove) { - itemToAction[JSON.stringify(item)] = [item, AddRemoveResultType.Remove]; + itemToAction[AddRemoveResultType.Remove].push(item); } return [ [...add, ...updateNewVersion], [...remove, ...updateOldVersion], + updateLastUpdated, markComplete, ]; } @@ -255,13 +322,31 @@ function calculateHash(fileContents: string): string { return hash.digest("hex"); } +function mapIndexResultTypeToAddRemoveResultType( + resultType: IndexResultType, +): AddRemoveResultType { + switch (resultType) { + case "updateLastUpdated": + return AddRemoveResultType.UpdateLastUpdated; + case "compute": + return AddRemoveResultType.Compute; + case "addTag": + return AddRemoveResultType.Add; + case "del": + case "removeTag": + return AddRemoveResultType.Remove; + default: + throw new Error(`Unexpected result type: ${resultType}`); + } +} + export async function getComputeDeleteAddRemove( tag: IndexTag, currentFiles: LastModifiedMap, readFile: (path: string) => Promise, repoName: string | undefined, -): Promise<[RefreshIndexResults, MarkCompleteCallback]> { - const [add, remove, markComplete] = await getAddRemoveForTag( +): Promise<[RefreshIndexResults, PathAndCacheKey[], MarkCompleteCallback]> { + const [add, remove, lastUpdated, markComplete] = await getAddRemoveForTag( tag, currentFiles, readFile, @@ -305,6 +390,7 @@ export async function getComputeDeleteAddRemove( return [ results, + lastUpdated, async (items, resultType) => { // Update tag catalog markComplete(items, resultType); @@ -347,15 +433,15 @@ export class GlobalCacheCodeBaseIndex implements CodebaseIndex { _: MarkCompleteCallback, repoName: string | undefined, ): AsyncGenerator { - const add = [...results.compute, ...results.addTag]; + const add = results.addTag; const remove = [...results.del, ...results.removeTag]; await Promise.all([ - ...add.map(({ cacheKey }) => { - return this.computeOrAddTag(cacheKey, tag); - }), ...remove.map(({ cacheKey }) => { return this.deleteOrRemoveTag(cacheKey, tag); }), + ...add.map(({ cacheKey }) => { + return this.computeOrAddTag(cacheKey, tag); + }), ]); yield { progress: 1, desc: "Done updating global cache", status: "done" }; } diff --git a/core/indexing/types.ts b/core/indexing/types.ts index d636564bd..f952ea8df 100644 --- a/core/indexing/types.ts +++ b/core/indexing/types.ts @@ -5,6 +5,7 @@ export enum IndexResultType { Delete = "del", AddTag = "addTag", RemoveTag = "removeTag", + UpdateLastUpdated = "updateLastUpdated" } export type MarkCompleteCallback = ( diff --git a/core/indexing/walkDir.ts b/core/indexing/walkDir.ts index 98636b857..1c320f181 100644 --- a/core/indexing/walkDir.ts +++ b/core/indexing/walkDir.ts @@ -1,17 +1,15 @@ -import { EventEmitter } from "events"; import { Minimatch } from "minimatch"; import path from "node:path"; -import { FileType, IDE } from ".."; -import { DEFAULT_IGNORE_DIRS, DEFAULT_IGNORE_FILETYPES } from "./ignore"; +import { FileType, IDE } from "../index.d.js"; +import { + DEFAULT_IGNORE_DIRS, + DEFAULT_IGNORE_FILETYPES, + defaultIgnoreDir, + defaultIgnoreFile, +} from "./ignore.js"; export interface WalkerOptions { - isSymbolicLink?: boolean; - path?: string; ignoreFiles?: string[]; - parent?: Walker | null; - includeEmpty?: boolean; - follow?: boolean; - exact?: boolean; onlyDirs?: boolean; returnRelativePaths?: boolean; additionalIgnoreRules?: string[]; @@ -19,315 +17,194 @@ export interface WalkerOptions { type Entry = [string, FileType]; -class Walker extends EventEmitter { - isSymbolicLink: boolean; - path: string; - basename: string; - ignoreFiles: string[]; - ignoreRules: { [key: string]: Minimatch[] }; - parent: Walker | null; - includeEmpty: boolean; - root: string; - follow: boolean; - result: Set; - entries: Entry[] | null; - sawError: boolean; - exact: boolean | undefined; - onlyDirs: boolean | undefined; +// helper struct used for the DFS walk +type WalkableEntry = { + relPath: string; + absPath: string; + type: FileType; + entry: Entry; +}; + +// helper struct used for the DFS walk +type WalkContext = { + walkableEntry: WalkableEntry; + ignoreFiles: IgnoreFile[]; +}; + +class IgnoreFile { + private _rules: Minimatch[]; + constructor( - opts: WalkerOptions = {}, - protected readonly ide: IDE, + public path: string, + public content: string, ) { - super(opts as any); - this.isSymbolicLink = opts.isSymbolicLink || false; - this.path = opts.path || process.cwd(); - this.basename = path.basename(this.path); - this.ignoreFiles = [...(opts.ignoreFiles || [".ignore"]), ".defaultignore"]; - this.ignoreRules = {}; - this.parent = opts.parent || null; - this.includeEmpty = !!opts.includeEmpty; - this.root = this.parent ? this.parent.root : this.path; - this.follow = !!opts.follow; - this.result = this.parent ? this.parent.result : new Set(); - this.entries = null; - this.sawError = false; - this.exact = opts.exact; - this.onlyDirs = opts.onlyDirs; - - if (opts.additionalIgnoreRules) { - this.addIgnoreRules(opts.additionalIgnoreRules); - } + this.path = path; + this.content = content; + this._rules = this.contentToRules(content); } - sort(a: string, b: string): number { - return a.localeCompare(b, "en"); + public get rules() { + return this._rules; } - emit(ev: string, data: any): boolean { - let ret = false; - if (!(this.sawError && ev === "error")) { - if (ev === "error") { - this.sawError = true; - } else if (ev === "done" && !this.parent) { - data = (Array.from(data) as any) - .map((e: string) => (/^@/.test(e) ? `./${e}` : e)) - .sort(this.sort); - this.result = new Set(data); - } - - if (ev === "error" && this.parent) { - ret = this.parent.emit("error", data); - } else { - ret = super.emit(ev, data); - } - } - return ret; - } - - start(): this { - this.ide - .listDir(this.path) - .then((entries) => { - this.onReaddir(entries); - }) - .catch((err) => { - this.emit("error", err); - }); - return this; - } - - isIgnoreFile(e: Entry): boolean { - const p = e[0]; - return p !== "." && p !== ".." && this.ignoreFiles.indexOf(p) !== -1; - } - - onReaddir(entries: Entry[]): void { - this.entries = entries; - if (entries.length === 0) { - if (this.includeEmpty) { - this.result.add(this.path.slice(this.root.length + 1)); - } - this.emit("done", this.result); - } else { - const hasIg = this.entries.some((e) => this.isIgnoreFile(e)); - - if (hasIg) { - this.addIgnoreFiles(); - } else { - this.filterEntries(); - } - } - } - - addIgnoreFiles(): void { - const newIg = this.entries!.filter((e) => this.isIgnoreFile(e)); - - let igCount = newIg.length; - const then = () => { - if (--igCount === 0) { - this.filterEntries(); - } - }; - - newIg.forEach((e) => this.addIgnoreFile(e, then)); - } - - addIgnoreFile(file: Entry, then: () => void): void { - const ig = path.resolve(this.path, file[0]); - this.ide - .readFile(ig) - .then((data) => { - this.onReadIgnoreFile(file, data, then); - }) - .catch((err) => { - this.emit("error", err); - }); - } - - onReadIgnoreFile(file: Entry, data: string, then: () => void): void { - const mmopt = { + private contentToRules(content: string): Minimatch[] { + const options = { matchBase: true, dot: true, flipNegate: true, nocase: true, }; - const rules = data + return content .split(/\r?\n/) - .filter((line) => !/^#|^$/.test(line.trim())) - .map((rule) => { - return new Minimatch(rule.trim(), mmopt); - }); + .map((l) => l.trim()) + .filter((l) => !/^#|^$/.test(l)) + .map((l) => new Minimatch(l, options)); + } +} - this.ignoreRules[file[0]] = rules; +class DFSWalker { + private readonly path: string; + private readonly ide: IDE; + private readonly options: WalkerOptions; + private readonly ignoreFileNames: Set; - then(); + constructor(path: string, ide: IDE, options: WalkerOptions) { + this.path = path; + this.ide = ide; + this.options = options; + this.ignoreFileNames = new Set(options.ignoreFiles); } - addIgnoreRules(rules: string[]) { - const mmopt = { - matchBase: true, - dot: true, - flipNegate: true, - nocase: true, + // walk is a depth-first search implementation + public async *walk(): AsyncGenerator { + const root: WalkContext = { + walkableEntry: { + relPath: "", + absPath: this.path, + type: 2 as FileType.Directory, + entry: ["", 2 as FileType.Directory], + }, + ignoreFiles: [], }; - const minimatchRules = rules - .filter((line) => !/^#|^$/.test(line.trim())) - .map((rule) => { - return new Minimatch(rule.trim(), mmopt); - }); - - this.ignoreRules[".defaultignore"] = minimatchRules; - } - - filterEntries(): void { - const filtered = this.entries!.map((entry) => { - const passFile = this.filterEntry(entry[0]); - const passDir = this.filterEntry(entry[0], true); - return passFile || passDir ? [entry, passFile, passDir] : false; - }).filter((e) => e) as [Entry, boolean, boolean][]; - let entryCount = filtered.length; - if (entryCount === 0) { - this.emit("done", this.result); - } else { - const then = () => { - if (--entryCount === 0) { - // Otherwise in onlyDirs mode, nothing would be returned - if (this.onlyDirs && this.path !== this.root) { - this.result.add(this.path.slice(this.root.length + 1)); - } - this.emit("done", this.result); + const stack = [root]; + for (let cur = stack.pop(); cur; cur = stack.pop()) { + const walkableEntries = await this.listDirForWalking(cur.walkableEntry); + const ignoreFiles = await this.getIgnoreFilesToApplyInDir( + cur.ignoreFiles, + walkableEntries, + ); + for (const w of walkableEntries) { + if (!this.shouldInclude(w, ignoreFiles)) { + continue; } + if (this.entryIsDirectory(w.entry)) { + stack.push({ + walkableEntry: w, + ignoreFiles: ignoreFiles, + }); + if (this.options.onlyDirs) { + // when onlyDirs is enabled the walker will only return directory names + yield w.relPath; + } + } else { + yield w.relPath; + } + } + } + } + + private async listDirForWalking( + walkableEntry: WalkableEntry, + ): Promise { + const entries = await this.ide.listDir(walkableEntry.absPath); + return entries.map((e) => { + return { + relPath: path.join(walkableEntry.relPath, e[0]), + absPath: path.join(walkableEntry.absPath, e[0]), + type: e[1], + entry: e, }; - filtered.forEach((filt) => { - const [entry, file, dir] = filt; - this.stat(entry, file, dir, then); - }); + }); + } + + private async getIgnoreFilesToApplyInDir( + parentIgnoreFiles: IgnoreFile[], + walkableEntries: WalkableEntry[], + ): Promise { + const ignoreFilesInDir = await this.loadIgnoreFiles(walkableEntries); + if (ignoreFilesInDir.length === 0) { + return parentIgnoreFiles; } + return Array.prototype.concat(parentIgnoreFiles, ignoreFilesInDir); } - entryIsDirectory(entry: Entry) { - const Directory = 2 as FileType.Directory; - return entry[1] === Directory; + private async loadIgnoreFiles( + entries: WalkableEntry[], + ): Promise { + const ignoreEntries = entries.filter((w) => this.isIgnoreFile(w.entry)); + const promises = ignoreEntries.map(async (w) => { + const content = await this.ide.readFile(w.absPath); + return new IgnoreFile(w.relPath, content); + }); + return Promise.all(promises); } - entryIsSymlink(entry: Entry) { - const Directory = 64 as FileType.SymbolicLink; - return entry[1] === Directory; + private isIgnoreFile(e: Entry): boolean { + const p = e[0]; + return this.ignoreFileNames.has(p); } - onstat(entry: Entry, file: boolean, dir: boolean, then: () => void): void { - const abs = this.path + "/" + entry[0]; - const isSymbolicLink = this.entryIsSymlink(entry); - if (!this.entryIsDirectory(entry)) { - if (file && !this.onlyDirs) { - this.result.add(abs.slice(this.root.length + 1)); - } - then(); - } else { - if (dir) { - this.walker( - entry[0], - { isSymbolicLink, exact: this.filterEntry(entry[0] + "/") }, - then, - ); - } else { - then(); - } + private shouldInclude( + walkableEntry: WalkableEntry, + ignoreFiles: IgnoreFile[], + ) { + if (this.entryIsSymlink(walkableEntry.entry)) { + // If called from the root, a symlink either links to a real file in this repository, + // and therefore will be walked OR it linksto something outside of the repository and + // we do not want to index it + return false; } - } - - stat(entry: Entry, file: boolean, dir: boolean, then: () => void): void { - this.onstat(entry, file, dir, then); - } - - walkerOpt(entry: string, opts: Partial): WalkerOptions { - return { - path: this.path + "/" + entry, - parent: this, - ignoreFiles: this.ignoreFiles, - follow: this.follow, - includeEmpty: this.includeEmpty, - onlyDirs: this.onlyDirs, - ...opts, - }; - } - - walker(entry: string, opts: Partial, then: () => void): void { - new Walker(this.walkerOpt(entry, opts), this.ide).on("done", then).start(); - } - - filterEntry( - entry: string, - partial?: boolean, - entryBasename?: string, - ): boolean { - let included = true; - - if (this.parent && this.parent.filterEntry) { - const parentEntry = this.basename + "/" + entry; - const parentBasename = entryBasename || entry; - included = this.parent.filterEntry(parentEntry, partial, parentBasename); - if (!included && !this.exact) { + let relPath = walkableEntry.relPath; + if (this.entryIsDirectory(walkableEntry.entry)) { + if (defaultIgnoreDir.ignores(walkableEntry.relPath)) { return false; } - } - - this.ignoreFiles.forEach((f) => { - if (this.ignoreRules[f]) { - this.ignoreRules[f].forEach((rule) => { - if (rule.negate !== included) { - const isRelativeRule = - entryBasename && - rule.globParts.some( - (part) => part.length <= (part.slice(-1)[0] ? 1 : 2), - ); - - const match = - rule.match("/" + entry) || - rule.match(entry) || - (!!partial && - (rule.match("/" + entry + "/") || - rule.match(entry + "/") || - (rule.negate && - (rule.match("/" + entry, true) || - rule.match(entry, true))) || - (isRelativeRule && - (rule.match("/" + entryBasename + "/") || - rule.match(entryBasename + "/") || - (rule.negate && - (rule.match("/" + entryBasename, true) || - rule.match(entryBasename, true))))))); - - if (match) { - included = rule.negate; - } - } - }); + relPath = `${relPath}/`; + } else { + if (this.options.onlyDirs) { + return false; } - }); - + if (defaultIgnoreFile.ignores(walkableEntry.relPath)) { + return false; + } + relPath = `/${relPath}`; + } + let included = true; + for (const ignoreFile of ignoreFiles) { + for (const r of ignoreFile.rules) { + if (r.negate === included) { + // no need to test when the file is already NOT to be included unless this is a negate rule and vice versa + continue; + } + if (r.match(relPath)) { + included = r.negate; + } + } + } return included; } -} -interface WalkCallback { - (err: Error | null, result?: string[]): void; -} + private entryIsDirectory(entry: Entry) { + return entry[1] === (2 as FileType.Directory); + } -async function walkDirWithCallback( - opts: WalkerOptions, - ide: IDE, - callback?: WalkCallback, -): Promise { - const p = new Promise((resolve, reject) => { - new Walker(opts, ide).on("done", resolve).on("error", reject).start(); - }); - return callback ? p.then((res) => callback(null, res), callback) : p; + private entryIsSymlink(entry: Entry) { + return entry[1] === (64 as FileType.SymbolicLink); + } } const defaultOptions: WalkerOptions = { ignoreFiles: [".gitignore", ".continueignore"], - onlyDirs: false, additionalIgnoreRules: [...DEFAULT_IGNORE_DIRS, ...DEFAULT_IGNORE_FILETYPES], }; @@ -336,40 +213,18 @@ export async function walkDir( ide: IDE, _options?: WalkerOptions, ): Promise { + let entries: string[] = []; const options = { ...defaultOptions, ..._options }; - return new Promise((resolve, reject) => { - walkDirWithCallback( - { - path, - ignoreFiles: options.ignoreFiles, - onlyDirs: options.onlyDirs, - follow: true, - includeEmpty: false, - additionalIgnoreRules: options.additionalIgnoreRules, - }, - ide, - async (err, result) => { - if (err) { - reject(err); - } else { - const relativePaths = result || []; - if (options?.returnRelativePaths) { - resolve(relativePaths); - } else { - const pathSep = await ide.pathSep(); - if (pathSep === "/") { - resolve(relativePaths.map((p) => path + pathSep + p)); - } else { - // Need to replace with windows path sep - resolve( - relativePaths.map( - (p) => path + pathSep + p.split("/").join(pathSep), - ), - ); - } - } - } - }, - ); - }); + const dfsWalker = new DFSWalker(path, ide, options); + let relativePaths: string[] = []; + for await (const e of dfsWalker.walk()) { + relativePaths.push(e); + } + const pathSep = await ide.pathSep(); + const prefix = options.returnRelativePaths ? "" : path + pathSep; + + if (pathSep === "/") { + return relativePaths.map((p) => prefix + p); + } + return relativePaths.map((p) => prefix + p.split("/").join(pathSep)); } diff --git a/core/llm/asyncEncoder.ts b/core/llm/asyncEncoder.ts new file mode 100644 index 000000000..722664ead --- /dev/null +++ b/core/llm/asyncEncoder.ts @@ -0,0 +1,47 @@ +import llamaTokenizer from "./llamaTokenizer.js"; +import { Tiktoken, encodingForModel as _encodingForModel } from "js-tiktoken"; +import workerpool from "workerpool"; +import * as path from "path"; + +export interface AsyncEncoder { + encode(text: string): Promise; + decode(tokens: number[]): string; +} + +export class LlamaAsyncEncoder implements AsyncEncoder { + private workerPool: workerpool.Pool; + + constructor() { + this.workerPool = workerpool.pool(path.join(__dirname, "/llamaTokenizerWorkerPool.mjs")); + } + + async encode(text: string): Promise { + return this.workerPool.exec("encode", [text]); + } + + decode(tokens: number[]): string { + return llamaTokenizer.decode(tokens); + } + + // TODO: this should be called somewhere before exit or potentially with a shutdown hook + public async close(): Promise { + await this.workerPool.terminate(); + } +} + +// this class does not yet do anything asynchronous +export class GPTAsyncEncoder implements AsyncEncoder { + private tiktokenEncoding: Tiktoken; + + constructor() { + this.tiktokenEncoding = _encodingForModel("gpt-4"); + } + + async encode(text: string): Promise { + return this.tiktokenEncoding.encode(text, "all", []); + } + + decode(tokens: number[]): string { + return this.tiktokenEncoding.decode(tokens); + } +} \ No newline at end of file diff --git a/core/llm/autodetect.ts b/core/llm/autodetect.ts index 6f09839c2..32ef68a3a 100644 --- a/core/llm/autodetect.ts +++ b/core/llm/autodetect.ts @@ -61,6 +61,7 @@ const MODEL_SUPPORTS_IMAGES: string[] = [ "llava", "gpt-4-turbo", "gpt-4o", + "gpt-4o-mini", "gpt-4-vision", "claude-3", "gemini-ultra", diff --git a/core/llm/constants.ts b/core/llm/constants.ts index 0d63c6f6a..a31dbbe3d 100644 --- a/core/llm/constants.ts +++ b/core/llm/constants.ts @@ -20,6 +20,7 @@ const CONTEXT_LENGTH_FOR_MODEL: { [name: string]: number } = { "gpt-4-32k": GPT_4_CTX_LEN, "gpt-4-turbo-preview": GPT_4_CTX_LEN, "gpt-4o": GPT_4_CTX_LEN, + "gpt-4o-mini": GPT_4_CTX_LEN, "gpt-4-vision": GPT_4_CTX_LEN, "gpt-4-0125-preview": GPT_4_CTX_LEN, "gpt-4-1106-preview": GPT_4_CTX_LEN, diff --git a/core/llm/countTokens.ts b/core/llm/countTokens.ts index f8cdc9b4a..5d042e3ca 100644 --- a/core/llm/countTokens.ts +++ b/core/llm/countTokens.ts @@ -1,29 +1,42 @@ import { Tiktoken, encodingForModel as _encodingForModel } from "js-tiktoken"; import { ChatMessage, MessageContent, MessagePart } from "../index.js"; +import { + AsyncEncoder, + GPTAsyncEncoder, + LlamaAsyncEncoder, +} from "./asyncEncoder.js"; import { autodetectTemplateType } from "./autodetect.js"; import { TOKEN_BUFFER_FOR_SAFETY } from "./constants.js"; +import { stripImages } from "./images.js"; import llamaTokenizer from "./llamaTokenizer.js"; - interface Encoding { encode: Tiktoken["encode"]; decode: Tiktoken["decode"]; } class LlamaEncoding implements Encoding { - encode( - text: string, - allowedSpecial?: string[] | "all" | undefined, - disallowedSpecial?: string[] | "all" | undefined, - ): number[] { + encode(text: string): number[] { return llamaTokenizer.encode(text); } + decode(tokens: number[]): string { return llamaTokenizer.decode(tokens); } } let gptEncoding: Encoding | null = null; +const gptAsyncEncoder = new GPTAsyncEncoder(); const llamaEncoding = new LlamaEncoding(); +const llamaAsyncEncoder = new LlamaAsyncEncoder(); + +function asyncEncoderForModel(modelName: string): AsyncEncoder { + const modelType = autodetectTemplateType(modelName); + if (!modelType || modelType === "none") { + return gptAsyncEncoder; + } + // Temporary due to issues packaging the worker files + return process.env.IS_BINARY ? gptAsyncEncoder : llamaAsyncEncoder; +} function encodingForModel(modelName: string): Encoding { const modelType = autodetectTemplateType(modelName); @@ -46,6 +59,24 @@ function countImageTokens(content: MessagePart): number { throw new Error("Non-image content type"); } +async function countTokensAsync( + content: MessageContent, + // defaults to llama2 because the tokenizer tends to produce more tokens + modelName = "llama2", +): Promise { + const encoding = asyncEncoderForModel(modelName); + if (Array.isArray(content)) { + const promises = content.map(async (part) => { + if (part.type === "imageUrl") { + return countImageTokens(part); + } + return (await encoding.encode(part.text ?? "")).length; + }); + return (await Promise.all(promises)).reduce((sum, val) => sum + val, 0); + } + return (await encoding.encode(content ?? "")).length; +} + function countTokens( content: MessageContent, // defaults to llama2 because the tokenizer tends to produce more tokens @@ -79,16 +110,6 @@ function flattenMessages(msgs: ChatMessage[]): ChatMessage[] { return flattened; } -export function stripImages(content: MessageContent): string { - if (Array.isArray(content)) { - return content - .filter((part) => part.type === "text") - .map((part) => part.text) - .join("\n"); - } - return content; -} - function countChatMessageTokens( modelName: string, chatMessage: ChatMessage, @@ -360,6 +381,7 @@ function compileChatMessages( export { compileChatMessages, countTokens, + countTokensAsync, pruneLinesFromBottom, pruneLinesFromTop, pruneRawPromptFromTop, diff --git a/core/llm/images.ts b/core/llm/images.ts new file mode 100644 index 000000000..912ae48ca --- /dev/null +++ b/core/llm/images.ts @@ -0,0 +1,11 @@ +import { MessageContent } from "../index.js"; + +export function stripImages(content: MessageContent): string { + if (Array.isArray(content)) { + return content + .filter((part) => part.type === "text") + .map((part) => part.text) + .join("\n"); + } + return content; + } \ No newline at end of file diff --git a/core/llm/index.ts b/core/llm/index.ts index 728bdeef4..950c514fb 100644 --- a/core/llm/index.ts +++ b/core/llm/index.ts @@ -1,3 +1,4 @@ +import { findLlmInfo } from "@continuedev/llm-info"; import Handlebars from "handlebars"; import { ChatMessage, @@ -35,9 +36,9 @@ import { compileChatMessages, countTokens, pruneRawPromptFromTop, - stripImages, } from "./countTokens.js"; import CompletionOptionsForModels from "./templates/options.js"; +import { stripImages } from "./images.js"; export abstract class BaseLLM implements ILLM { static providerName: ModelProvider; @@ -114,14 +115,17 @@ export abstract class BaseLLM implements ILLM { ..._options, }; + this.model = options.model; + const llmInfo = findLlmInfo(this.model); + const templateType = options.template ?? autodetectTemplateType(options.model); this.title = options.title; this.uniqueId = options.uniqueId ?? "None"; - this.model = options.model; this.systemMessage = options.systemMessage; - this.contextLength = options.contextLength ?? DEFAULT_CONTEXT_LENGTH; + this.contextLength = + options.contextLength ?? llmInfo?.contextLength ?? DEFAULT_CONTEXT_LENGTH; this.completionOptions = { ...options.completionOptions, model: options.model || "gpt-4", @@ -235,12 +239,16 @@ ${prompt}`; ) { let promptTokens = this.countTokens(prompt); let generatedTokens = this.countTokens(completion); - Telemetry.capture("tokens_generated", { - model: model, - provider: this.providerName, - promptTokens: promptTokens, - generatedTokens: generatedTokens, - }); + Telemetry.capture( + "tokens_generated", + { + model: model, + provider: this.providerName, + promptTokens: promptTokens, + generatedTokens: generatedTokens, + }, + true, + ); DevDataSqliteDb.logTokensGenerated( model, this.providerName, diff --git a/core/llm/llamaTokenizer.mjs b/core/llm/llamaTokenizer.mjs new file mode 100644 index 000000000..0e861ecb9 --- /dev/null +++ b/core/llm/llamaTokenizer.mjs @@ -0,0 +1,486 @@ +/** + * MIT LICENSE + * + * Copyright 2023 belladore.ai + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the β€œSoftware”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +const base64decode = function(encodedString) { + return atob(encodedString) +} + +const utf8ByteToHex = (c) => { + const hexValue = c.toString(16).toUpperCase().padStart(2, '0'); + return `<0x${hexValue}>`; +} + +const hexToUtf8Byte = (hex) => { + const strippedHex = hex.replace(/<0x|>/g, '') + return parseInt(strippedHex, 16) +} + +class PriorityQueue { + // PriorityQueue implementation is copied from https://stackoverflow.com/a/42919752 with minor refactoring + constructor(comparator = (a, b) => a > b) { + this._heap = []; + this._comparator = comparator; + } + size() { + return this._heap.length; + } + isEmpty() { + return this.size() == 0; + } + peek() { + return this._heap[0]; + } + push(...values) { + values.forEach(value => { + this._heap.push(value); + this._siftUp(); + }); + return this.size(); + } + pop() { + const poppedValue = this.peek(); + const bottom = this.size() - 1; + if (bottom > 0) { + this._swap(0, bottom); + } + this._heap.pop(); + this._siftDown(); + return poppedValue; + } + replace(value) { + const replacedValue = this.peek(); + this._heap[0] = value; + this._siftDown(); + return replacedValue; + } + _parent(i) { + return ((i + 1) >>> 1) - 1; + } + _left(i) { + return (i << 1) + 1; + } + _right(i) { + return (i + 1) << 1; + } + _greater(i, j) { + return this._comparator(this._heap[i], this._heap[j]); + } + _swap(i, j) { + [this._heap[i], this._heap[j]] = [this._heap[j], this._heap[i]]; + } + _siftUp() { + let node = this.size() - 1; + while (node > 0 && this._greater(node, this._parent(node))) { + this._swap(node, this._parent(node)); + node = this._parent(node); + } + } + _siftDown() { + let node = 0; + while ( + (this._left(node) < this.size() && this._greater(this._left(node), node)) || + (this._right(node) < this.size() && this._greater(this._right(node), node)) + ) { + let maxChild = (this._right(node) < this.size() && this._greater(this._right(node), this._left(node))) ? this._right(node) : this._left(node); + this._swap(node, maxChild); + node = maxChild; + } + } +} + +export class LlamaTokenizer { + + vocabById; + vocabByString; + merges; + + utf8Encoder = new TextEncoder(); + utf8Decoder = new TextDecoder('utf-8'); + + constructor(vocab_base64, merges_binary) { + // Array where index represents tokenId, value represents tokenString + this.vocabById = this.decodeVocabulary(vocab_base64 || llama_vocab_base64); + // Map where key represents tokenString, value represents tokenId + this.vocabByString = new Map(); + this.vocabById.forEach((tokenString, tokenId) => { + this.vocabByString.set(tokenString, tokenId); + }); + // Map where key identifies token pair, value represents merge priority + this.merges = this.decompressMerges(merges_binary || llama_merges_binary); + } + + getMergeIdentifierString(firstTokenId, secondTokenId) { + return this.vocabById[firstTokenId] + " " + this.vocabById[secondTokenId] + } + + decompressMerges(merges_binary) { + // Base64 decode binary. + const byteArrayString = base64decode(merges_binary) + + // Convert byteArrayString to byteArray. + const byteArray = new Uint8Array(byteArrayString.length); + for (let i = 0; i < byteArrayString.length; i++) { + byteArray[i] = byteArrayString.charCodeAt(i); + } + + // Each byte-pair represents a tokenId. + // Convert byte-pairs to tokenIds (integers between 0 and 32000). + const tokenIds = []; + for (let i = 0; i < byteArray.length; i += 2) { + const byte1 = byteArray[i]; + const byte2 = byteArray[i + 1]; + const tokenId = byte1 + (byte2 << 8); + tokenIds.push(tokenId); + } + + // Each pair of tokenIds represents a merge. + const merges = new Map() + for (let i=0; i". + * + * This helper function returns the vocabulary as an array that contains Strings representing tokens: + * + * "" // Special token: unknown token + * "" // Special token: beginning of string + * "" // Special token: end of string + * "<0x00>" // Byte-level token representing the 0-byte + * "<0x01>" // Byte-level token ... + * "<0x02>" // Byte-level token ... + * ... // More byte-level tokens + * "<0x0A>" // Byte-level token representing '\n' (line break). This is one of the few byte-level tokens that appear to be actually needed in practice. + * ... // More byte-level tokens + * "<0xFF>" // Byte-level token ... + * "▁▁" // Token representing 2 consecutive spaces. + * "▁t" // Token representing the space character followed by the "t" character. + * "er" // Token representing the "e" character followed by the "r" character. Most tokens look like this. + * ... // 32000 tokens + */ + decodeVocabulary(vocab_base64) { + const byteArray = Uint8Array.from(base64decode(vocab_base64), c => c.charCodeAt(0)); + const textDecoder = new TextDecoder('utf-8'); + return textDecoder.decode(byteArray).split("\n"); + } + + mapCharactersToTokenIds(prompt, add_bos_token, add_preceding_space) { + const tokenIds = [] + // Special "beginning of string" token. + if (add_bos_token) { + tokenIds.push(1) + } + // Special "preceding space" added to beginning of prompt. + if (add_preceding_space) { + prompt = " " + prompt + } + // Special: spaces are represented as thick underscore ▁ (id 29871) + const promptAltered = (prompt).replaceAll(" ", this.vocabById[29871]) + // We need to use Array.from to iterate over characters in order to support UTF-8 multipoint characters + const charArray = Array.from(promptAltered) + // Transform each character to its corresponding token + for (let i=0; i= 0)) { + // This is not supposed to happen because the LLaMA vocabulary has a token corresponding to each byte, + // but if this happens regardless, let's follow the protocol and tokenize to token instead of crashing. + console.log('Encountered unknown character ' + c + " (partial UTF-8 byte " + bytes[j] + " + hex + " + utf8ByteToHex(bytes[j]) + ")") + tokenIds[tokenIds.length-1] = 0 + } + } + } + } + return tokenIds + } + + encode(prompt, add_bos_token=true, add_preceding_space=true, log_performance=false) { + + let startTime = null + if (log_performance) { + startTime = performance.now() + } + + if (!this.vocabById || !this.vocabByString || !this.merges) { + console.log('Tokenizer not initialized properly!') + return + } + if (prompt.length === 0) { + return [] + } + // Initially each character is transformed to a tokenId, later there will be merges of these. + const tokenIds = this.mapCharactersToTokenIds(prompt, add_bos_token, add_preceding_space) + + // Set up priority queue to efficiently iterate merge possibilities in priority order + const mergeQueue = new PriorityQueue((a, b) => { + return a.mergePrio < b.mergePrio + }) + + const addToMergeQueue = (leftNode) => { + const mergeIdentifierString = this.getMergeIdentifierString(leftNode.tokenId, leftNode.next.tokenId) + // Merge priority is primarily determined by the location of the merge in the "merges" data, + // secondarily determined by the relative position of the node in the linked list + // (We want to perform equal merges from left to right) + const mergePrio = this.merges.get(mergeIdentifierString) + leftNode.origPos / prompt.length + if (mergePrio) { + // If mergePrio not found in merges, that means this merge is not possible according to vocabulary. + leftNode.mergePrio = mergePrio + leftNode.mergeToString = mergeIdentifierString.replace(" ", "") + mergeQueue.push(leftNode) + } + } + + // Fill merge queue from initial merge possibilities and construct linked list + let firstTokenNode = { + origPos: 0, + tokenId: tokenIds[0], + prev: null, + next: null, + } + let prevTokenNode = firstTokenNode + for (let i=1; i")) { + // Special case + const utf8byte = hexToUtf8Byte(tokenString) + utf8byteVals.push(utf8byte) + } else { + // Typical case + const utf8bytes = this.utf8Encoder.encode(tokenString) + utf8bytes.forEach(utf8Byte => utf8byteVals.push(utf8Byte)) + } + } + const uint8Array = new Uint8Array(utf8byteVals) + const decodedString = this.utf8Decoder.decode(uint8Array) + const spacesFixed = decodedString.replaceAll(this.vocabById[29871], " ") + // Note that preceding space must be removed here at string level, not earlier at token level, because multiple consecutive spaces are represented as single token. + return add_preceding_space ? spacesFixed.slice(1) : spacesFixed + } + + defaultTests(tokenizer) { + + function isEqual(arr1, arr2) { + return arr1.length === arr2.length && arr1.every(function(value, index) { return value === arr2[index]}) + } + + function testCase(inputString, expectedTokenIds) { + const actualTokens = tokenizer.encode(inputString, true, true, true) + if (!isEqual(actualTokens, expectedTokenIds)) { + throw `Test failed. LLaMA Tokenizer Encoder returned unexpected result: expected tokenize(${inputString}) === ${expectedTokenIds}, actual was: ${actualTokens}` + } + if (inputString !== tokenizer.decode(actualTokens)) { + throw `Test failed. LLaMA Tokenizer Decoder returned unexpected result: expected decode(${actualTokens}) === ${inputString}, actual was: ${decode(actualTokens)}` + } + } + + // Simple test case + testCase("grabbed", [1, 2646, 1327, 287]) + + // Naive implementation produces inconsistent tokenization for " grabbed", making this a good test case + testCase(" grabbed", [1, 29871, 2646, 1327, 287]) + + // Naive implementation uses incorrect merge order for multiple consecutive space merges, making this a good test case + testCase(" grabbed", [1, 9651, 2646, 1327, 287]) + + // Linebreaks and tabs are handled as fallback to byte tokens + testCase("\n", [1, 29871, 13]) + testCase(" \n", [1, 259, 13]) + testCase(" tabs out here", [1, 29871, 12, 21175, 12, 12, 12, 12, 449, 1244]) + + // Equal prio merges are performed left-to-right (fixed in 1.1.1) + testCase("ax\n####\nboo", [1, 4853, 13, 4136, 13, 833, 29877]) + + // UTF-8 multipoint character that should be found in vocabulary + testCase('镇', [1, 29871, 30411]) + + // UTF-8 multipoint character that should NOT be found in vocabulary, fallback to MULTIPLE byte tokens + testCase('πŸ¦™', [1, 29871, 243, 162, 169, 156]) + + // Consecutive UTF-8 multipoint characters that are NOT found in a vocabulary and use DIFFERENT number of bytes + testCase('πŸ¦™κ™Š', [1, 29871, 243, 162, 169, 156, 237, 156, 141]) + testCase('κ™ŠπŸ¦™', [1, 29871, 237, 156, 141, 243, 162, 169, 156]) + + // Larger text input with various special characters sprinkled in + testCase("The llama (/ˈlɑːmΙ™/; πŸ¦™Spanish pronunciation: [ˈʎama]) (Lama glama) is a domesticated South American camelid, widely used as a meat and pack animal by Andean cultures since the Pre-Columbian era. Llamas are social animals and live with others as a herd. Their wool is soft and contains only a small amount of lanolin.[2] Llamas can learn simple tasks after a few repetitions. When using a pack, they can carry about 25 to 30% of their body weight for 8 to 13 km (5–8 miles).[3] The name llama (in the past also spelled \"lama\" or \"glama\") was adopted by European settlers from native Peruvians.[4] The ancestors of llamas are thought to have originated from the Great Plains of North America about 40 million years ago, and subsequently migrated to South America about three million years ago during the Great American Interchange. By the end of the last ice age (10,000–12,000 years ago), camelids were extinct in North America.[3] As of 2007, there were over seven million llamas and alpacas in South America and over 158,000 llamas and 100,000κ™ŠπŸ¦™ alpacas, descended from progenitors imported late in the 20th century, in the United States and Canada.[5] In Aymara mythology, llamas are important beings. The Heavenly Llama is said to drink water from the ocean and urinates as it rains.[6] According to Aymara eschatology, llamas will return to the water springs and lagoons where they come from at the end of time.[6]", + [1, 450, 11148, 3304, 20374, 30176, 29880, 30426, 30215, 29885, + 30184, 29914, 29936, 29871, 243, 162, 169, 156, 15495, 728, + 11504, 11173, 362, 29901, 518, 30176, 31743, 3304, 2314, 313, + 29931, 3304, 3144, 3304, 29897, 338, 263, 21849, 630, 4275, + 3082, 3949, 295, 333, 29892, 17644, 1304, 408, 263, 27654, + 322, 4870, 13019, 491, 1126, 29872, 273, 4185, 1973, 1951, + 278, 4721, 29899, 1625, 3774, 713, 3152, 29889, 365, 5288, + 294, 526, 5264, 15006, 322, 5735, 411, 4045, 408, 263, + 902, 29881, 29889, 11275, 281, 1507, 338, 4964, 322, 3743, + 871, 263, 2319, 5253, 310, 10906, 22878, 7226, 29906, 29962, + 365, 5288, 294, 508, 5110, 2560, 9595, 1156, 263, 2846, + 21159, 2187, 29889, 1932, 773, 263, 4870, 29892, 896, 508, + 8677, 1048, 29871, 29906, 29945, 304, 29871, 29941, 29900, 29995, + 310, 1009, 3573, 7688, 363, 29871, 29947, 304, 29871, 29896, + 29941, 2383, 313, 29945, 29994, 29947, 7800, 467, 29961, 29941, + 29962, 450, 1024, 11148, 3304, 313, 262, 278, 4940, 884, + 805, 14356, 376, 29880, 3304, 29908, 470, 376, 3820, 3304, + 1159, 471, 16356, 491, 7824, 3604, 9306, 515, 7531, 25493, + 1403, 550, 7226, 29946, 29962, 450, 19525, 943, 310, 11829, + 294, 526, 2714, 304, 505, 3978, 630, 515, 278, 7027, + 13494, 1144, 310, 4644, 6813, 1048, 29871, 29946, 29900, 7284, + 2440, 8020, 29892, 322, 17602, 9725, 630, 304, 4275, 6813, + 1048, 2211, 7284, 2440, 8020, 2645, 278, 7027, 3082, 4124, + 3167, 29889, 2648, 278, 1095, 310, 278, 1833, 14890, 5046, + 313, 29896, 29900, 29892, 29900, 29900, 29900, 29994, 29896, 29906, + 29892, 29900, 29900, 29900, 2440, 8020, 511, 3949, 295, 4841, + 892, 1294, 5562, 297, 4644, 6813, 7226, 29941, 29962, 1094, + 310, 29871, 29906, 29900, 29900, 29955, 29892, 727, 892, 975, + 9881, 7284, 11829, 294, 322, 394, 29886, 562, 294, 297, + 4275, 6813, 322, 975, 29871, 29896, 29945, 29947, 29892, 29900, + 29900, 29900, 11829, 294, 322, 29871, 29896, 29900, 29900, 29892, + 29900, 29900, 29900, 237, 156, 141, 243, 162, 169, 156, + 394, 29886, 562, 294, 29892, 5153, 2760, 515, 410, 1885, + 17259, 19673, 5683, 297, 278, 29871, 29906, 29900, 386, 6462, + 29892, 297, 278, 3303, 3900, 322, 7400, 7226, 29945, 29962, + 512, 319, 962, 2518, 22082, 3002, 29892, 11829, 294, 526, + 4100, 367, 886, 29889, 450, 22977, 368, 365, 29880, 3304, + 338, 1497, 304, 13748, 4094, 515, 278, 23474, 322, 5065, + 262, 1078, 408, 372, 1153, 1144, 7226, 29953, 29962, 7579, + 304, 319, 962, 2518, 831, 13496, 3002, 29892, 11829, 294, + 674, 736, 304, 278, 4094, 7689, 886, 322, 301, 4425, + 787, 988, 896, 2041, 515, 472, 278, 1095, 310, 931, + 7226, 29953, 29962]) + + console.log('LLaMA Tokenizer tests passed successfully.') + return true + } + + runTests(tests=this.defaultTests) { + tests(this); + } + +} + +const llama_vocab_base64 = "PHVuaz4KPHM+Cjwvcz4KPDB4MDA+CjwweDAxPgo8MHgwMj4KPDB4MDM+CjwweDA0Pgo8MHgwNT4KPDB4MDY+CjwweDA3Pgo8MHgwOD4KPDB4MDk+CjwweDBBPgo8MHgwQj4KPDB4MEM+CjwweDBEPgo8MHgwRT4KPDB4MEY+CjwweDEwPgo8MHgxMT4KPDB4MTI+CjwweDEzPgo8MHgxND4KPDB4MTU+CjwweDE2Pgo8MHgxNz4KPDB4MTg+CjwweDE5Pgo8MHgxQT4KPDB4MUI+CjwweDFDPgo8MHgxRD4KPDB4MUU+CjwweDFGPgo8MHgyMD4KPDB4MjE+CjwweDIyPgo8MHgyMz4KPDB4MjQ+CjwweDI1Pgo8MHgyNj4KPDB4Mjc+CjwweDI4Pgo8MHgyOT4KPDB4MkE+CjwweDJCPgo8MHgyQz4KPDB4MkQ+CjwweDJFPgo8MHgyRj4KPDB4MzA+CjwweDMxPgo8MHgzMj4KPDB4MzM+CjwweDM0Pgo8MHgzNT4KPDB4MzY+CjwweDM3Pgo8MHgzOD4KPDB4Mzk+CjwweDNBPgo8MHgzQj4KPDB4M0M+CjwweDNEPgo8MHgzRT4KPDB4M0Y+CjwweDQwPgo8MHg0MT4KPDB4NDI+CjwweDQzPgo8MHg0ND4KPDB4NDU+CjwweDQ2Pgo8MHg0Nz4KPDB4NDg+CjwweDQ5Pgo8MHg0QT4KPDB4NEI+CjwweDRDPgo8MHg0RD4KPDB4NEU+CjwweDRGPgo8MHg1MD4KPDB4NTE+CjwweDUyPgo8MHg1Mz4KPDB4NTQ+CjwweDU1Pgo8MHg1Nj4KPDB4NTc+CjwweDU4Pgo8MHg1OT4KPDB4NUE+CjwweDVCPgo8MHg1Qz4KPDB4NUQ+CjwweDVFPgo8MHg1Rj4KPDB4NjA+CjwweDYxPgo8MHg2Mj4KPDB4NjM+CjwweDY0Pgo8MHg2NT4KPDB4NjY+CjwweDY3Pgo8MHg2OD4KPDB4Njk+CjwweDZBPgo8MHg2Qj4KPDB4NkM+CjwweDZEPgo8MHg2RT4KPDB4NkY+CjwweDcwPgo8MHg3MT4KPDB4NzI+CjwweDczPgo8MHg3ND4KPDB4NzU+CjwweDc2Pgo8MHg3Nz4KPDB4Nzg+CjwweDc5Pgo8MHg3QT4KPDB4N0I+CjwweDdDPgo8MHg3RD4KPDB4N0U+CjwweDdGPgo8MHg4MD4KPDB4ODE+CjwweDgyPgo8MHg4Mz4KPDB4ODQ+CjwweDg1Pgo8MHg4Nj4KPDB4ODc+CjwweDg4Pgo8MHg4OT4KPDB4OEE+CjwweDhCPgo8MHg4Qz4KPDB4OEQ+CjwweDhFPgo8MHg4Rj4KPDB4OTA+CjwweDkxPgo8MHg5Mj4KPDB4OTM+CjwweDk0Pgo8MHg5NT4KPDB4OTY+CjwweDk3Pgo8MHg5OD4KPDB4OTk+CjwweDlBPgo8MHg5Qj4KPDB4OUM+CjwweDlEPgo8MHg5RT4KPDB4OUY+CjwweEEwPgo8MHhBMT4KPDB4QTI+CjwweEEzPgo8MHhBND4KPDB4QTU+CjwweEE2Pgo8MHhBNz4KPDB4QTg+CjwweEE5Pgo8MHhBQT4KPDB4QUI+CjwweEFDPgo8MHhBRD4KPDB4QUU+CjwweEFGPgo8MHhCMD4KPDB4QjE+CjwweEIyPgo8MHhCMz4KPDB4QjQ+CjwweEI1Pgo8MHhCNj4KPDB4Qjc+CjwweEI4Pgo8MHhCOT4KPDB4QkE+CjwweEJCPgo8MHhCQz4KPDB4QkQ+CjwweEJFPgo8MHhCRj4KPDB4QzA+CjwweEMxPgo8MHhDMj4KPDB4QzM+CjwweEM0Pgo8MHhDNT4KPDB4QzY+CjwweEM3Pgo8MHhDOD4KPDB4Qzk+CjwweENBPgo8MHhDQj4KPDB4Q0M+CjwweENEPgo8MHhDRT4KPDB4Q0Y+CjwweEQwPgo8MHhEMT4KPDB4RDI+CjwweEQzPgo8MHhEND4KPDB4RDU+CjwweEQ2Pgo8MHhENz4KPDB4RDg+CjwweEQ5Pgo8MHhEQT4KPDB4REI+CjwweERDPgo8MHhERD4KPDB4REU+CjwweERGPgo8MHhFMD4KPDB4RTE+CjwweEUyPgo8MHhFMz4KPDB4RTQ+CjwweEU1Pgo8MHhFNj4KPDB4RTc+CjwweEU4Pgo8MHhFOT4KPDB4RUE+CjwweEVCPgo8MHhFQz4KPDB4RUQ+CjwweEVFPgo8MHhFRj4KPDB4RjA+CjwweEYxPgo8MHhGMj4KPDB4RjM+CjwweEY0Pgo8MHhGNT4KPDB4RjY+CjwweEY3Pgo8MHhGOD4KPDB4Rjk+CjwweEZBPgo8MHhGQj4KPDB4RkM+CjwweEZEPgo8MHhGRT4KPDB4RkY+CuKWgeKWgQriloF0CmVyCmluCuKWgWEKZW4Kb24K4paBdGgKZXMK4paB4paB4paB4paBCuKWgXMK4paBZAphdApvcgphbgriloFjCmlzCnJlCml0CuKWgXRoZQphcgpsZQriloF3CuKWgXAKb3UKYWwK4paBZgriloFtCmVkCuKWgW8K4paBYgpvbQppb24KaW5nCmljCmFzCmVsCmVudAriloFpbgriloFoCm5kCmV0CuKWgWwK4paBbgpzdAriloF0bwpjaAriloFJCnJvCuKWgeKWgeKWgeKWgeKWgeKWgeKWgeKWgQppbAriloFvZgpkZQpjdAriloEoCmFtCuKWgUMK4paBZGUK4paBUwriloF1CuKWgUEK4paBXAriloFlCuKWgWFuZAriloFUCm9sCuKWgXYKaW0Kb3QKYWQKdXQK4paBZwplbQp1cgppZAriloEqCmlnCnJhCuKWgXJlCuKWgWlzCnF1Cm93CuKWgU0KZXN0CuKWgXkKc2UKdmUKY2UKaWUKdW4K4paBUAriloFCCmFnCnVsCuKWgT0KaGUKZW5kCm9kZQp0ZXIKbWVudApvcwriloFECmlmCmF0aW9uCuKWgWZvcgriloFyCuKWgUwK4paBeW91CuKWgWJlCmx5CnZlcgphYgp0ZQriloFpdAriloFvbgpyaQp1cwriloEiCuKWgXdoCuKWgWNvbgriloFICuKWgXN0CmlyCuKWgUUK4paBRgpjawriloFhbgp0aAplZwpheQppdGgK4paBUgppc3QKYW5kCuKWgXRoYXQK4paBYWwK4paBJAriloEjCm9kCnVtCuKWgVcKaHQKY29kZQriloFHCmF0ZQplc3MK4paBTgplcmUKcHAK4paBYXMK4paBc2UK4paBcHJvCuKWgXdpdGgKcGUK4paBawplcnMKcHQKKTsKbG8K4paB4paB4paB4paB4paBCuKWgWNvbQphbWUK4paBYAriloFDb20KaWEKYW50CuKWgWxhCuKWgXsK4paBZW4KY3Rpb24K4paBZXgKbGQKdWIK4paBagpsYQp1ZQriloFKCmljaAriloFkbwriloFPCuKWgXF1Cml2Cm9ydAphcnQK4paBdW4K4paBIyMK4paBdGhpcwprZQriloFoYQriloEtCm91dAriloFUaGUK4paBbm90CuKWgW5lCmlsbAriloFsZQpjaQpyb20KaW5lCi8vCm9wCmVnaW4K4paBQ29tbWVudAriloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloEKYmVnaW4K0YHRggphc3MKaXoKKS4Kb2cK4paB0L8K4paBb3IK4paBd2FzCuKWgWF0Cm91cgriloFpCmFpbgriloFLCtC90LAK4paBVgpnZQriloFzdQphcAphZ2UKb3VsZApuZQphdgp4dApvcmUKaWxlCi0tCuKWgdCyCuKWgWJ5CmxpCmF0aArRgNCwCmJlcgphY2gKYWxsCuKWgVRoCnVsdAriloF9CuKWgVUK4paBdXMK4paBegp1c3QK4paBaGF2ZQpsaWMK0L3QuAriloFjYW4KdHIKY29tCiksCuKWgUluCmluZAplbGwK4paBZnJvbQrQvtCyCnRvCuKWgVsKYWJsZQpvc3QK4paBY2gKZWN0CmlnaHQKaW50CuKWgScK4paBYXJlCuKWgWltCuKWgXNoCuKWgTwK4paBQW4K4paB0YEKYXRhCmlyZQriloF0cgpjb24Kb3JkCml0eQphcmQK4paB4paB4paB4paB4paB4paBCuKWgWhlCuKWgWJ1dApvYwo9IgriloFwcgp1cmUKcGVyCmFjawpvcmsKb25nCmFucwrQutC+CnBsZQriloFkZXMKb2sKb3JtCndlcgphawpwcgphc2UK4paBZWwKcGgKYWMK4paBdW5kCuKWgWFyCuKWgWlmCnVkCnBzCml0ZQpibGUK0L3QvgpmZXIKcGwKaXZlCmFuZwplbnMK0YDQvgriloFzbwpzbwphc3QKKCkKc3dlcgpydQppZXMK4paBOgphdQpvdgrRgNC1CtCz0L4K4paBZGVyCuKWgW15CuKWgXdlCuKWgW1lCm50CuKWgWFkCnVybgriloF5b3VyCjovLwphcmUK4paBYWxsCmZmCmlvCmVzdGlvbgppbWUK4paBZXIKbGFzcwriloHQuAriloF3aGljaApvbWUKb250CuKWgXBhcgriloFtYQriloFZCiIsCuKWgdC+CmZ0CmlhbApjYwpvdW5kCuKWgWxpCuKWgXJlcwpldGgKamVjdAriloFhcHAK4paBU3QKaWNlCuKWgWFtCmFjdAriloFkZWwKZ3IKYXRlZAppZXIK4paB4paB4paB4paB4paB4paB4paB4paB4paB4paB4paB4paBCuKWgWFiCuKWgWV0CmFsbHkKLi4KcG9ydAppawriloFwZXIK4paBY29udArRgNC4CtC60LAKc2VyCtC70LgKbGwKaWV3CmlnbgpfewpwdXQKb25lCnVuY3Rpb24K4paBZGkKYXJ5Cml0aW9uCm1hCtC10L0KZ2V0CuKWgWxvCuKWgXZhbAriloFRCnJhbgriloHQtAplbmNlCuKWgXdvcmsK4paB0L3QsAppcAppdGVtCnlwZQriloEmCuKWgWhpcwriloF1c2UKZGVyCuKWgUFuc3dlcgriloF3aWxsCml6ZQrRgtCwCmxvdwriloFDaAriloFnZXQKaWRlCm91cwppbmsKcHRpb24K0LvQsAp0dXJuCnVuZwplYwp1Zwpmb3JtCnJlcwpodHQKb3VnCtC70YwK4paBbm8KY2wK4paBcm8K4paBb25lCnR0CmNyaQpkdQriloF1cArRgtC+CigiCuKWgW9iCndlCm9yeQriloFlc3QKZXJ5CmllbApzdHIKb2IK4paBcXVlCmlhbgriloFvdXQK4paBcGwK4paBbmV3CtC60LgK4paBKwpyeQpvdGgKdGhlcgriloF2YXIK4paBd291bGQK4paBc2VyCnRlcm4KdGV4dAriloF0aGVyZQppc2gKcm9yCtGC0LUK4paBc2V0CuKWgUAK4paB0L/QvgriloF0ZQpleAriloFyZXR1cm4KYWlsCuKWgWFueQriloFJdAriloFmdW5jdGlvbgp7XAonLArDqXMKYWxlCtCw0L0K4paBd2hlbgppYgriloFnbwphbmNlCuKWgWhhZAriloFRdQriloFjb21wCtC70LUK4paB0LcKbWF0aAriloFoYXMK4paB0LwK4paBcHJlCmVuZXIK4paBcGFydAplbGYK4paBZGllCuKWgWxpa2UKcmF5Cmlyc3QK4paBZGlzCuKWgW1hbgpyaXQK4paBdGhlbgriloFjbGFzcwpwcm8K4paBcG8K4paBdXNpbmcKZWIK4paBY29kZQpvd24K4paBc29tZQpjZXMK4paBJFwK0LXRgApsZWN0CuKWgWF1CmlzY2gK4paBY29sCuKWgeKAkwp1cApvbnMK4paBYWRkCmlsZAppc3MKdmFsCm91bnQKbGVzCnZlbnQK4paB4paB4paB4paB4paB4paB4paB4paB4paB4paB4paB4paB4paBCuKWgVoKSW4Kcm93CmVhcgphdGlvbnMKYWgKcXVlCnVibGljCmFuawriloFzcAriloFXaAotLS0tCnNrCmV3CmFncwrRgtC4CmFubgriloHigJQKZXJ0CmFjZQpzY2gK4paBbmVlZAriloHDoAppZW4Kb3VnaArQvdC1CuKWgWRlZgppagplcm4K4paBd2hhdAriloFBcgp3bwptbAo8LwriloFSZQriloFlcwriloFpbnN0CmJvCmF6CuKWgSMjIwriloHQsQplcm0K4paBQWwKbGVkCtC00LAKdGVuCnNldArQu9C+CuKWgWNvbW0Kc2gK0LLQsAriloEvCuKWgWRhdGEK4paBLy8KXSgK4paBc3RyCm9zZQriloFVbgp2ZW4KU3QKLi4uCuKWgdChCnlzdAriloHCqwppY2sKaXgKcGFyCuKWgdGDCuKWgXdhbnQKbmcKb3RlCuKWgWdyCuKWgWR1CuKWgS4KdW5kCuKWgW9ubHkK4paBc2EKZWx5CnZlcnMK4paBZW50CikpCignCuKWgW1vZAphdmEKdG9uCuKWgXNob3VsZAplbWVudAriloFmb3JtCuKWgWFsc28K4paBc2MKaW5ncwriloFZb3UKw7NuCuKWgWtuCigpOwriloF8CuKWgXdlcmUKc3MK4paBUXVlc3Rpb24KaXNlCuKWgXRoZXkK4paBRGUKb25kCuKWgXNvbAriloFmb2wK4paBbW9yZQriloFoZXIK4paBXwriloHDqQphdGNoCmZ0ZXIK4paBY3JlCmxvY2sKdHJpbmcK4paBVGhpcwp6ZQphZG8KdWxsCmdlcgpiZQriloFvdGhlcgriloFUYWdzCnV0aW9uCmljdAriloFob3cK4paBeAriloFTZQriloFjaGUKY3JpcHQK4paBanVzdAriloFwb3MKYW5nZQppZmljCnJlZQp9fQriloF0aW1lCmFwcArQvdGLCuKWgWZpbGUKYXJrCmljYWwK4paBZmlyc3QK4paBaW50CuKWgdCSCuKWgUhlCnRhCnVtZW50Cm9ycwpsZW1lbnQKcmFjCuKWgWFnCuKWgWRvZXMKeW4KcmVhZAp1YWwK4paBTGUKeXMK4paBZW0K4paBbnVtCnZlbArQtNC4Cm92ZXIK4paBZGlmCmV0aG9kCuKWgUlmCuKWgXNwZQp5bQriloF0aGVtCuKWgWludG8K4paB4paB4paB4paB4paB4paB4paB4paB4paB4paBCuKWgWxlcwriloFpdHMKZXNlCmllbGQK4paBcHVibGljCuKWgdCfCuKWgWRlbgp5c3RlbQpvZgriloFvdmVyCi0+CuKWgWZpbApuYW1lCmluYWwK4paBaWwKYW1wbGUK4paBd2F5CmljYQrQstC+CmNlc3MKaXR0CnVjaAriloF3aGVyZQrQvNC4Cm9yZwpodHRwcwriloF2bwppZW50Cm92ZQriloF2YWx1ZQplbmcK4paBTGEKXnsKcmVmCmllZApFUgriloFzdGF0CmZpZwptZQriloF2b24K4paBaW50ZXIKcm9pZAphdGVyCuKWgXRoZWlyCuKWgWJldAriloFlaW4KfVwKIj4K4paBc3ViCuKWgW9wCuKWgWRvbgp0eQriloF0cnkK4paBUHJvCuKWgXRyYQriloFzYW1lCmVwCuKWgXR3bwriloFuYW1lCm9sZApsZXQK4paBc2ltCnNwCuKWgWF2CmJyZQpibGVtCmV5CuKWgWNvdWxkCuKWgWNvcgriloFhY2MKYXlzCmNyZQp1cnIKc2kK4paBY29uc3QKdWVzCn0kClZpZXcK4paBYWN0CuKWgWJvCuKWgdC60L4K4paBc29tCuKWgWFib3V0CmxhbmQKbWVyCuKWgWxpc3QKY2FsCuKWgWltcG9ydApjb2wK4paBbmEKbmEKOjoK4paBd2hvCuKWgWVycm9yCuKWgVgKYXRvcgpleHQK4paBYmVlbgrDqXIK4paBcnVuCnBvcwriloFjbAoqKgriloHQmgp1bGFyCmF1c2UK4paBcmVnCuKWgWtub3cK4paBc2VlCuKWgWhpbQpuaW5nCuKWgdC30LAKYXRlcwpmb3JlCmlvbnMK4paBaGVsCnV0ZQriloFyZW0K4paB0LPQvgriloFNYXIK0YDRgwp2aWNlCmlyZWN0Cm5lcgriloF1bmRlcgpyaWIKaHIK0YfQtQriloFBcwriloFlbmQKZW1iZXIK4paB0LAK4paBYXR0CmluYQpzb24K4paBZm9sbG93CuKWgVNjaApwZWN0CuKWgXJlbAriloFTbwriloFsb29rCmFiZWwK4paBcHJvYmxlbQriloF2YW4Kc3Ryb25nCmNvCnBvbgpjYQphZGEKIjoKY29uZAphbWIKfSwKcXVlc3QK4paBYXV0CuKWgXJlc3VsdAriloFtYXkKUmUKaHR0cAopOgriloFBbmQKcmVkCuKWgUhvdwpwbwrRgdC60L4KYXR0Cm91cApjZWQK4paBdHlwZQriloF0aGFuCuKWgWNvbnMKdWYK0YbQuAriloFxdWVzdGlvbgpyYXBoCmlnaAriloHQnAriloFodHQKaW5zCmRlbgriloFkYQriloF2ZXIKb2gK4paBPT4Kcml2CnVkZQriloFGb3IK4paBcmEKZnJhYwrQvNCwCuKWgWFmdGVyCn17CuKWgW1ldGhvZAoiKQphbXAKYXNoCuKWgXJlYwriloFkaWZmZXIKT04KYXgKYW1lbnQKb3VyY2UKQ29uCml0cwpOYW1lCm1hbgriloFiZWMKY2hlCuKWgUVuCmFqCuKWgWdlbmVyCklOCuKWgWlkCmFnZXMK4paBbG9jCmZvCmJyCuKWgXNoZQpQcm8K4paBdW5hCuKWgdC6CmV0YQpsb2cKb2xvZwriloFzdXIKYXJnCuKWgS0tCmt0CihcCm1pbgriloFsaW5lCuKWgXZhcmkK0YHRjwppY3MK0L3Rjwp2ZXJ5CmFkZAriloFvYmplY3QKSWQK4paBQnV0CuKWgWNhc2UK4paBbWFrZQriloFjYWwK4paBcGFzcwrRgdGMCmVzc2lvbgpuZXQKLiIK4paB0LMKw6RyCtC00LUKbm8KYXRpbmcKYXRvCmxpbmUK0LLQuAriloFFeAriloFhc3MK4paBdmVycwrQu9GPCuKWgWVkCnVtbgpvdGhlcgrRgdGC0LAKYXRpdmUKU3RyaW5nCuKWgWxvcwp3bgriloFhbnN3ZXIK4paBbGV0CuKWgXBlCmVudHMK4paBZmUKaW5jZQpuaQppZGVyCm93cwriloF0ZXN0CuKWgWhlcmUKcm9sbAriloFjYWxsCnJ1Y3QK4paBcG9sCmFpdAriloFiYWNrCmhvCkV4CnJlc3MKU1QKcmllZApkYXRlCtC10YIK4paBZGlkCnRpbmcK4paBRWwK4paBZGVtCikkCtC+0LLQsAp1cnJlbnQKbGFjZQpyaWdodApyZW4K0L/QvgriloFlYWNoCmN5CmJsb2NrCmRhdGEK4paBJQriloFhYwriloE9PQrDvHIK4paBcG9yCmFzawphcmNoCmFtZXMK4paBQ29uCtGH0LAK4paBb2ZmCuKWgWZpbmQKY29udAriloFub3cKd29yawphdGlvbmFsCmRkCmNpw7NuCuKWgdCQCmF1bHQKTGlzdAriloFleHQKdXJzCmFrZQp1bGUK4paBcG9pbnQKQVQKYXV0CuKWgXRyYW5zCuKWgWNvCuKWgXJlYWQK4paBdXNlZArRgdC60LgKYXJpCkxFCmV0ZXIKb3VuCmV2ZXIKc2VsZgppbmVkCmlkdGgKdXgKanMK4paBc3VjaAriloFJcwrDqWUKZnVsCuKWgWRpc3QK4paBYnUKaXRlbWl6ZQpDb250CmplCtGB0LgK4paBcHJvdgpiYgp3YXJkCmVzZW50CmVyc29uCmFua3MKd2gKbm90CuKWgVdlCmthCnJvcAphdHVyCmFscwriloFiZWwKw7ZyCmZyCuKWgWV4YW1wbGUK4paBaW5jbAphbWlsCuKWgdGA0LAK4paB4oCcCuKWgXN0cmluZwriloF0aGluawpUaAriloF0ZW0KYXZlCuKWgUZyYW4K4paBbnVtYmVyCuKWgXNpCmltZXMKdGVtCm15Cmxlcgpsb2FkCj09CuKWgWhhbmQKemEK4paBYmVjYXVzZQriloFzY2gKdm8KdGhpcwpJRArDo28K4paBc3RhcnQK4paBd2FyCuKWgWhlbHAKdHMK4paBY2hhcgriloFwaAriloFtaW4KdGlsCnJpdGUKLS0tLS0tLS0KZWxzCuKWgW1pdAplZGlhCtC60YMK4paBU2gKYW55Cl07CuKWgdCRCmlxdWUKZGEKZWYKZGV4CuKWgXByb2R1CuKWgdCdCmdyYW0K4paBT3IK4paBZ3JlCnF1b3RlCmxlZwpvcm4K4paBaW5kCuKWgXBvc3QK4paBZGVwCl0sCnZpCuKWgXVzZXIK4paBPgpsaWNrCuKWgXZlcnkKZXRoaW5nCuKWgWFycmF5CuKWgWd1CuKWgWR1cgpgLgrRgtGMCmxpY2F0aW9uCtGB0YLQuAplawppY28K4paBZGF0CtC+0YAKaHRtbAppb25lCuKWgWRpZmZlcmVudAriloFjaGVjawriloFmcgriloFFcgriloF0ZXh0CtC90ZYKaWNodApzdGFjawpFTgpyYWcK4paBZXZlcnkKQXIK4paBYmVmb3JlCmFsc2UK4paBZmluCuKWgWTDqQriloF0aGVzZQriloFkZXQKVmFsCmNlcHRpb24K4paBYW5kcm9pZApibG9ja3F1b3RlCuKWgWplCmZpbGUKYXRzCuKWgdC00L4KZXNzYWdlCuKWgWFnYWluCmF3CkNoCndlZW4K4paB0JQKZm9yCmNpYWwKcGxheQpwcmUKaWRhCuKWgVBhcgpueQpyYWN0CuKWgXN1cHAKYXNlZApsZWN0aW9uCuKWgWRhbnMKYWlyCnJvbAriloF0aHIKRGF0YQpsaWNoCuKWgdC/0YDQvgriloFsb25nCuKWgXNlY29uZAp1YWxseQppbmVzCuKWgWZvdW5kCmVuZ3RoCnlwCmVhZAriloFsb2cKdWkKbmV3CuKWgdCgCmdvCmF1cwpvZHkK4paBc29uCtC80LUKZXJvCnZlZApzdWIK4paBcmlnaHQKdmlldwriloFmb2xsb3dpbmcKJykKIik7CuKWgXNhaWQK0LbQtQrRh9C4CtGC0YMKb3R0CtGB0LUKYXJzCiQuCmdnCuKWgWJyCm9vbAp5bGUKdXNlCuKWgXNob3cKbGVhc2UKY2lhCuKWgWRpcmVjdApkb2MK0LDRgAptcwriloFnaXYK4paBZXhwCnFsCtC00YMK0LLQtQriloFCZQpDb20KaXRlcgpSRQptcAptZW4K4paBUm8KTUEK4paBQ29sCmlzdGVyCuKWgXdlbGwK4paBPC8KYXlvdXQKYXR1cmUKaXZlcnMKenkK4paB0L3QtQriloFtZXQKdW5lCnl0aApUeXBlCuKWgWVsZW1lbnQK4paBbGluawptb2QK4paBYmV0d2VlbgpjZXB0CnF1aXJlCuKWgXRocm91Z2gK4paBd2hpbGUK4paBT24KdGhlCsOtYQriloFzb21ldGhpbmcKdm9sCuKWgW1vc3QKc2MKdXNzCuKWgWNhcgriloFzbQriloHRgNC+CmFubwpsZWZ0CnZhCuKWgXRydWUKKCQKZW1zCuKWgW11Y2gKw6FzCuKWgU5ldwriloFwcm9wZXIKZXJhCml0ZWQK4paBZG9jCmljZXMKVGhlCuKWgT8K0YHRgtC+CmZsCuKWgXNwZWMKZW5kZXIKd2F5CuKWgXNlbGYK4paBZXZlbgrRltCyCuKWgdGB0LUK0L3QuNGPCuKWgVByCuKWgWtlCmVtYgriloF0YWJsZQriloFlcXUKbGllbnQKdGQKcGFydAriloFwcmludAriloF1bmUKaWZ5CuKWgS0+CmVuZQriloFtb24K4paBZGVjCuKWgXN0aWxsCuKWgdC+0LEK4paBVHIK4paB0YQKaWZlCmlzbQpieQpyYXcKaW9yCuKWgW1lZApvcmxkCuKWgWNvbXBsZQp3dwriloFhcnQKcm9uCuKWgdCTCuKWgU15CuKWgWFscwpyZWN0CuKWgWF1ZgriloFkb3duCmF0aGVyCkNvbApUZXh0CmJhY2sKJCwK4paBeWVhcgrQvNC+CnBpCuKWgUdyCnJlYW0K4paBcmVwCmJmCnd3dwriloF3dXIK4paBb3JnCmludGVyCuKWgURpZQriloFiZWluZwoiLgpsYWJlbAriloFjZW50CmphdmEKYmFyCmFudGUKYW5hCl9fCuKWgXNvbHV0aW9uCuKWgdCeCuKWgWZsCuKWgWNyZWF0ZQppY2kKc3RlCnl0aG9uCnVudAphc29uCmZlcmVuY2UKU0UK4paBbm9uCmFuZQriloFpbnMKYWRlcgpfe1wKUmVzCuKWgW1haW4K0L/QuAriloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloEK4paBVGhlcmUK4paBcG91cgpSTwpgLApsaXNoCmJqZWN0CmNjZXNzCuKWgW9yaWcK4paB4paB4paBCmlzY2hlbgpvd2VyCuKWgWhldAp1YwriloFlbHNlCsK7LgriloHQvtGCCmVxdQpzaWJsZQp0ZXN0CnN0YW5kCsOpbgpldHMKR0UKaWRlbnQK4paB0LUK4paB0L/RgNC4Ci4sCuKWgWRhcwpvY2sKLCIK4paBdm9sCuKWgWZvCuKWgXBhcmEK4paB0KIK4paBQ2FyCnJhbAriloFTcAp2YXIK4paBcGxheQpvdXNlCuKWgdGC0LAKaWNhbGx5CuKWgWNvbnRhaW4KcG9uc2UK4paBU3RyaW5nCsOhbgriloFib3RoCmtlbgpBUgrQtdGA0LUK4paBSWwK4paBaXNzCuKWgW9wZW4K4paBKQriloFXaGF0CmZlCnJpdmF0ZQpyZWcK4paBd2l0aG91dAriloF6dQp2aXMKZmxvdwriloFodHRwCmFiYXNlCuKWgXdvcmQK4paBY2hhbmdlCuKWgXdvcmtzCuKWgWdlCuKWgSEK4paBZWVuCml0bGUK4paBZXZlbnQKd29yZAphbmRvClNCCnJlbQriloFmaWVsZAp2aW5nClNlcgriloFvdXIK4paBcXVpCuKWgW9wZXIK4paBaXN0CmRlZgriloFtYWRlCtC90LjQtQpweAriloFtZW4Kcm0KYWlzCmNlbnQKbGlzdApUbwriloFUbwpqYQp2ZXJ0CuKWgW1hcgp2YWx1ZQriloHigJ4KIjsK4paBYXVzCuKWgUJyCm9sZQriloFtdWx0Cm91Z2h0CuKWgW1hdAriloF2aWV3CmZpbAriloHRgdC+CtCz0LAK4paBdm9pZAriloFnb29kCtCx0L4KQ1QK4paBbWFueQpiZW4K4paB0LLQvgriloHQutCwCuKWgXN5c3RlbQppbm8K4paBYW5vdGhlcgriloFyZXN0CnVzZXIKaWxpdHkKYWkK4paBbWlnaHQKdXN0b20K4paBb3JkZXIK4paBVmVyClNTCn0pCuKWgWVmZgrQtNC+CmV0dAriloFzaWduCtC80YMKSVQKc3RyaW5nCmVsbGUK4paBc2luZwpjdWwK4paBdHJ5aW5nCuKWgWJlZwriloFwYWdlCtGF0L4K4paBQ2FuCuKWgVNlcgorKwriloFtdXN0CuKWgXZhbHVlcwriloFrZXkKaWJsZQpdLgppcmQK4paBcHJvZ3JhbQpyb2xsZXIK4paBY29ubmUK4paBc2F5CuKWgXBhcmFtCmFjaGUKdmVsb3AK4paBc2VsZWN0CuKWgWZhbWlsCuKWgWxhc3QK4paBVGhhbmtzCuKWgXBvcAp9LgplcQriloFkb2VzbgpbJwriloF0ZXJtCuKWgXLDqQriloFkb2N1bWVudArQv9CwCtC70YMKYXRlZwouKQpsaW5nCmlvbmFsCmFibGVzCuKWgXRhawp1dHRvbgriloFhcmcKdHlwZQriloFzdXJlCuKWgXJlYWwK4paBd2ViCuKWgWN1cnJlbnQK4paBUGwKY2hvCm1lbnRzCuKWgUpvaApvdHMK4paBZXhpc3QK0L3RgwriloFmw7xyCuKWgdC40LcKZG8K0L3QvtCz0L4K4paBbGFzCuKWgW51bGwK4paBaW5mb3JtCuKWgdCbCuKWgXZlcnNpb24K4paBY2hhbmcKYWdlcgriloFDb21tCtC70ZYKdXNoCuKWgUdlCuKWgWhpZ2gK4paBaW5wdXQKb2dsZQpyb3MKYm94CmdlbgriloFzdGUK4paBbG9jYWwKSW0K4paBcHJvY2Vzcwp0ZXJuYWwKaXplZArQs9C4CsOpdAriloFJbmQK4paBb2NoCmx0CuKWgWNvbHVtbgriloF0cmllZAriloFjb21tYW5kCuKWgWJlc3QKYXN0ZXIK0LfQsAriloFwcmltCuKWgW1vZGVsCuKWgdGWCuKWgXRob3NlCml0aWVzCsOocmUK4paB0YDQtQrRmNC1CtGI0LgKcXVlcwriloFBbQriloFvd24KbGluCtC30LgKVmFsdWUKdGhpbmcK4paBLAriloFUZQriloFzdHVkCuKWgXVtCuKWgXNlcnZlcgppbGxlCuKWgXB1dAphdGl2Cmd5CtC+0LLQuApyYWYK0L7QstC+CuKWgXd1cmRlCuKWgVdoZW4K4paBZGl2CmFudHMK4paBdGVyCuKWgXBhcnRpYwriloHRggriloFEbwriloFObwpzZXJ0CmlkbwptYXRoY2FsCmFkZQriloFJSQpsZWFyCm9ncmFwaAplbnNlCuKWgXJvdwpudW0K4paBcG9zc2libGUK4paBc2luY2UK4paBQm8KY3Rpb25zCuKWgUltCk9SCtGG0ZYK4paBaWRlCm1hcAriloFjb3JyZWN0CnZlcwpwaHAK4paBb3V0cHV0CuKWgVBoCkFMCmFyZWQKXFwK4paBaW1hZ2UKZXNjaArQttC4CuKWgWNvbmYKcG9yCnF1ZXJ5CnVyZXMKaXVtCmVuZHMK4paBQWIKU0JOCtGW0LQKZXRoZXIKcHRpb25zCml0dQpsaWIKbnMKa2kK4paBd29ya2luZwriloFjb21vCuKWgVRoZW4KTUwKa2V5CmNsYXNzCm9wbGUKaXR0bGUK4paBbWF0Y2gKd2F5cwptYXRoYmIK4paBcmVxdWlyZQphbHQK4paBdmlzCuKWgWJsCuKWgWNhbGxlZApJdGVtCnVyYQp2ZWMKZW1lCuKWgWRlbGxhCmVtYnJlCnVyZwpTZQriloFyZXF1ZXN0CmlzY2hlCuKWgXBvcnQK4paBaW5zdGVhZAo9XAriloHQowpob3IKZW50ZQp1bWUKZXJkCtGB0LAK4paBd2h5CnJpc3QK4paBcGVyc29uCuKWgS4uLgriloFwcml2YXRlCuKWgXRvdApwaGEKaWZ0Cml0YQpsb2MK4paBb2xkCtC+0L0K4paBbmVsCiddCnRpCmlldApjaXRlCnBsZW1lbnQK4paBYWJvdmUKa3MKcmVhZHkK4paBY29tZQpzZWN0aW9uCuKWgVBvbAriloF3cml0CuKWgWh0dHBzCuKWgSQkCuKWgcK7CuKWgWJ1aWxkCml0bwriloFjb25zaWRlcgphZnQKQXBwCixcCmluZG93cwpjb21tCuKWgTsKZ3JvdW5kCuKWgXBsYWNlCkJ5CuKWgXByb2plY3QKT2JqZWN0CuKWgXJlcHIKZW5jZXMKaW5kb3cKenQK4paBZmlsZXMKY3oKaXZpdHkK4paBaW5pdAriloFwcm9iCuKWgXNrCm9ydGgKaW1lbnQKb3VibGUKYXRhbAppcmMK4paBw6gK4paBYnJlCmlzdGEKaW5wdXQK4paB0JgK0L3QvtC5CnN1bQpwYXRoCuKWgWNvdXIK4paBdG9vCuKWgUFkCuKWgUd1CuKWgWZhbHNlCuKWgWZ1bgriloHRgdGCCm9vZArDqHMK4paBZW5jCmJvbApybAphcmdldApvcmRlcgriloFtZWFuCtC/0LUKaWdlbgriloHQv9GA0LUKd2lkdGgKOw0KaXRvcgriloFzdGF0ZQriloFncmVhdAplbm4KYmluCkVyCk1vZApvegriloF3b24K4paBZmFjdAriloFqYXZhCuKWgVVuaXZlcnMK4paBY2FwCmlzdG9yCn0oCmt1Cml0aGVyCmFsZXMK4paBb3UKcm9zcwriloF0YWtlCnJpeApsb2IK4paBZWluZQphc2VzCuKWgWFjY2VzcwppdMOpCmlzdHIKaXphdGlvbgriloFhcHBybwpiYWxsCuKWgW1hawp9XgriloFDb25zCnByZXNzCnNlcnYKKCkuCmFmCuKWgXJlZgopXAriloFjb250aW4Kc3UKaXZlcgriloFjb25kCuKWgWV4cGVjdAriloFjaGFyYWN0CmJlcnQKZWx0CnRlcnMKc2NyaXB0CuKWgUVkCmFwdAonKTsKcHJpbnQK4paBc2l6ZQriloFzaWNoCmZhY2UKZW5kZW4K4paBQW1lcgppZmllZArDs3cK4paBU3UKdGVzCm1lZAriloFSZWcKc29sZQriloFpbmNsdWQKaW5pCmluY2kK4paBcGxhCuKWgWxlZnQKZGYKUGFyCuKWgUFsbAriloFvY2MK4paBQXQK4paBY3IKUXUK4paBZ2l2ZW4K4paBU3lzdGVtCmljYW4K4paBZmluYWwKaXRpb25zCuKWgdCx0YsK4paBcGVyZm9ybQpBTgriloFNZQp1cm8K4paBVGhhdArQs9GA0LAK4paB0J/QvgriloHQstC4CmFibHkK4paBcHJlc2VudApkdWN0CnJpYwriloFFbmcKdHJ5CuKWgWxhcgpibAppZGQK4paBw6RyCm9yYQpMTApvc3MK4paBSVNCTgriloF0aHJlZQpqbwpuw60KcmMK4paBZmFyCuKWgU5vdAriloFsaXR0bGUKZGlzCmF0aQpmdW5jdGlvbgriloFhYmxlCmxlc3MK0YHQvgriloFwYXRoCuKWgXByZXMKbG9zZQpQSQriloFpc3N1ZQphY2thZ2UKdGltZQppZ2UKYW1zCuKWgUNsCmFpbHMKYWxrCmlpCtGI0LUKcGVuClFMCuKWgWVhcwpSTApjZWwK4paBc2wK4paBYXNrCuKWgW5vbQriloF0b3AKaWRlcwppbmRleArDqW0K4paBaGFwcApveApjZAriloFiZXR0ZXIK4paBbG9hZAphZG9zCnplbgriloFjZQriloFmYQriloFKb2huCklNQQriloFCYXIKb3ZlcmZsb3cK4paB0LTQtQpuZXNzCmNlcgriloFIZXJlCnJldAriloFzegphbWJkYQpvcHkKdXJsCnB5CnJ0CuKWgXVuZGVyc3RhbmQKYcWCCmhlcgojIwriloFjaGlsZAriloFleGVjCuKWgWFwcGxpY2F0aW9uCuKWgXN0cnVjdAriloHRjwpGaWxlCuKWgWNlcnQKaXNvbgriloF2YXJpYWJsZQpERQpycwriloFyZWFsbHkKUG9ydApiYQriloFCZXIK4paBaW50ZQriloFzdGF0aWMK4paBY29uZmlnCuKWgVNoZQplc3Rpb25zCuKWgXBsdXMK4paBaGFiCm9wZQriloFtdXMK4paBY291bnQKTUUK4paBc3VwcG9ydAriloFwZW9wbGUK4paBYmVoCuKWgWFscmVhZHkKVHIK4paBZG9uZQpkZW0Kc2l6ZQphbHBoYQriloFkaXNjCl0pCuKWgU1hbgriloFtaWwK4paBc3RhbmQK4paBZ3JvdXAK4paBc21hbGwK4paBbWFnCtGB0YLRjAriloFkZWZhdWx0CuKWgXNpbmdsZQpsaW5rCmNsdWRlCuKWgWVhcgppbGFyCioqKioK4paBZml4CmxleQriloFwYXMK0L3QuNC5Cmlzc2lvbgriloFpbXBsZW1lbnQKaXRjaAriloHQs9C+0LTQsAriloFhbHdheXMK4paBSmFoCnByaW5nCsOnw6NvCnBsYXRlCuKWgWRlc2NyaQriloFoZWFkCmluaXQKb2dyYWYK4paBcXVlcnkKaXZlZAriloFpbmcKcHR5CmhhCuKWgW1vdgriloHRjQpldHRlCmlseQriloFnb3QKaWxlZAppY3JvCuKWgXdyCtGA0Y8K4paBbmV2ZXIKb3JlcwriloFiYXMKaW9zCmxhY2sKYWludAp2aW91cwriloFnaXZlCmlkYWQKRW4K0L3Ri9C5CnRhYmxlCuKWgdCd0LAK4paBcGF0CtGC0L7RgAphbmd1CmxveQriloFzZWcKYXJyYXkK4paBRmwK4paBaW5kZXgK4paBc3cKSU1BR0UK4paBa20K0LHQuApDbGFzcwplbmEK0LzQtdC9CmNvbXAKYXR1cwpyYXAK4paBTGlzdApFcnJvcgriloF0eXAK4paB0LzQsApjcwonOgpqaQriloFIb3dldmVyCuKWgdGC0LUK4paBYmVsb3cK4paBQXBwCtGJ0LUKfV8KYnVtCnZpcgrDqWVzCuKWgXJlY29yZAp0YWluCmxlbQppdGFsCuKWgWltcAplZ28K4paBb2QK4paBcmVjZQptaXQKZmZpYwpzdGFja292ZXJmbG93CmlldmUK4paB0JcK4paBbm92CtGG0LUK4paBSW50ZXJuCmJ1CuKWgXN1Z2cK4paBbG9vcApyaWRlCuKWgSQoCuKWgXN1cGVyCnJpZArQvdGL0YUK4paBUGVyCuKWgWRvbQo9Jwp1dHNjaApsZW4K4paBd3JpdGUK4paBaW52Cm91dGgK4paBSGVyCuKWgXllYXJzCuKWgW9yaWdpbmFsCmVnYQriloFTdGUK4paBc2VlbXMKw6lnCuKWgW5leHQKZWRlcgriloFOZQphdmFzCmlmaWNhdGlvbgpFeGNlcHRpb24K4paBRGVyCuKWgXZlCmF0aWMKaGF0CmJyYXJ5CnJldHVybgp1cmNoCmlzaW9uCm1pCm9pbnQK4paBZGF5CmljdGlvbgrDoWwK4paBw6lzCuKWgXRob3VnaAphY3Rpb24Kw610CnVuZ2VuCm91cnMK4paBc2NyaXB0CuKWgWluZm9ybWF0aW9uCuKWgW11bHRpCuKWgVxcCnN0ZXIK0LrQtQpBQwpjaWVzCuKWgWRpc3BsYXkKb21hbgpUaW1lCml1cwopKTsKdHJlCuKWgWxpbQphdGVseQrDqWQKaXN0ZQriloHRgdCwCnBvc3QKdWVsCmltZwriloHRhwrRgdC60LAKZWxkCnBwZXIKdWxhCuKWgWdlbmVyYWwKQWwKRm9ybQriloF1cG9uCnpvCmFtZW50ZQriloFwcm9tCuKWgcO8CmxleAriloF0dXJuCuKWgdC80LUKZW50aW9uCtC70LXQvQriloFhZgppY2xlCtGB0YLQsgriloFGaWwK4paB0KQKYXZhc2NyaXB0Ck1hbgphcmEKd2FyZQphbGlnbgphbmdsZQriloFTYwp1bmljCuKWgWZyYW4KVW4KemkKbWV0CkFkZAriloFwdWIK0LrQvtCyCuKWgWdlbgriloFwb2QK4paBc3VtCuKWgWhhdmluZwriloFhdmVjCnNsCuKWgWZpZwriloFSZXMKRGF0ZQp1bGVzCndpdGgK0YHQutC40LkKZ3UKRVQK4paBYnJvCnJpZQphcHMKZW5kaW5nCm1haWwKb29rCuKWgXN1Y2Nlc3MKYmVyZwriloFkZWIKZWx0YQooKWAKZW50aWFsCmZyYW1lCktleQppbm4K4paBc2ltcGxlCml2YWwK4paBY2FyZQriloFXZWIKIikuCj48LwriloFkYXRhYmFzZQriloFOb3cKSW5kCuKWgdC80L4KY2h0CmJhbgpyYW0KZXF1YXRpb24Kc2tpCmllZgpsaW0KR2V0CuKWgXRyZQphdGVuCmJlZAriloFKZQriloFyZXN1bHRzCtC70Y4K0YLQtdC70YwKZGIK4paBYml0CmJvZHkKQXJyYXkKbXUKcHJlc3Npb24K4paB0YHRgtCwCm9ueQppZmYK4paBYmFyCuKWgUFyY2gKYmVycwopewriloFNb24K4paBZG9pbmcK4paBcHJvZgriloFpbnN0YWxsCuKWgXBvc2l0aW9uCmVtYQriloF9KTsKUGF0aAphbGkK4paBJiYKbGV2CuKWgWNhbm5vdAriloFNYXkKaW5zdAotXAriloFjb3VuCuKWgWFuZwriloFhcHBlYXIKY29yCmNpw7MKaWRlZApxdWVzdGlvbnMKYXR0ZXIK4paBUGEKc2VsZWN0CuKWgXByaW5jaQpFdmVudAriloFzaWRlCuKWgW1lbQriloFKYW4KYXJpbwriloF3aXRoaW4K4paBVmFsCm9kZXMKaWRkbGUKdXJhdGlvbgpicmEK4paBZGF0ZQpbXQriloFlbnRyZQppbGkKUG9ydGFpbApkb2NzCtGB0LrQvtC5CkVsZW1lbnQK4paBbWVzc2FnZQriloFuYWNoCuKWgWR1cmluZwriloFncmEKZXR3b3JrCuKWgUJ5CuKWgXRlbGwKZXRlCn5cCuKWgWJpcwriloFwdQriloFyZWQK4paBdGhpbmcK4paBc29ydAp4aW0KaXJlcwpVc2VyCmlvZAriloFFc3QKb3NlZApvdXRlCuKWgUxlcwriloFzZW50CnJpYnV0ZQp1dGVzCmlzdG9yeQriloFzZXJ2aWNlCic7CmZpZWxkCuKWgUlOCmVuc2lvbgpyZWwK4paBZ29pbmcKd2ViCkNvbnRleHQK4paBbGF0ZXIKdWsKbGF5b3V0Cm9uYQrDoXQKLS0tLS0tLS0tLS0tLS0tLQriloFleGFjdAphbmRvbQriloFzaWUKSUkK4paBVGhleQptZW50ZQppYmxpCuKWgWZpbmUKVVQK4paBZGV2ZWxvcAriloFFaW4Kc29mdApvZmYKU2V0CuKWgWF6CmV0ZXJzCmlsZGVyCnBsZXMK4paBc3BlY2lmaWMK4paBb20KZXJyb3IKZW50bHkK4paBZmlsbQp1Y2sKYWlucwphY2nDs24KZ2VzCtC20LAK4paBdGhpbmdzClNoCuKWgXRob3VnaHQK4paBYWRkZWQKZGVwCtGB0LrQvtCz0L4K4paBTGkKaWxzCnluYwriloHRgtC+CnJpZXMK4paBY3UKY2hlbgpJT04K4paBRGVzCnVsdGFkbwppcnQK4paBYmFzZWQK4paBbW8K4paBZGVzdApwbmcKcmVlbgriloFydW5uaW5nCmFtbWEKb3VkCuKWgXJlZmVyCmlvdXMK4paBSnVsCuKWgXNlYXJjaAphbGQKZWRlCuKWgXdyb25nCkFuCuKWgXVudGlsCnNpdGUKYXllcgriloFvbmNlCmFycgriloFhZ2FpbnN0Cj09PT0K4paBc291cmNlCmFybgphcGkK4paBcmVwcmVzZW50CuKWgWFmZgriloFzZWluCuKWgWFsbG93Cm9ybWFsCmVuZGVkCuKWgWNvbnRyb2wKbWF0aGJmCmNvbWUKY3VyCmVuZG8Kd2EK4paBdXBkYXRlCuKWgWluc2lkZQriloFyZWFzb24Kb21lbgriloHQstGLCkRlCuKWgdGY0LUKc3cK4paBc2V2ZXIKT2YK4paBaW5zdGFuY2UK4paBbWVyCuKWgWVmZmVjdApjb2xvcgp1Z3VzdAppbHQKZGVzCml0egp1bGF0aW9uCm5pZQriloFXb3JsZAriloFzaW1pbGFyCnltYm9sCmhpbmcK4paBbWFyawpTdGF0ZQriloFjb250ZW50CuKWgW1lYW5zCmFtZWQK4paBRW5kCk5ECmNvdW50CuKWgUluc3QKcGVydHkKY3RvcgriloF7XAriloFMZXQK4paBIT0K4paBZ2V0dGluZwp1dGgKdW1iZXIK4paBQ29uc3VsdGFkbwpzY2hhZnQKbGV0ZQriloFXaWxsCuKWgUVtCmhlYWQK4paBbGVnCtC90L7QvApPcgphcm0KcG9uZAriloFDaHJpc3QK4paBYXJvdW5kCuKWgWNsZWFyCuKWgWhyZWYK4paBU2VlCicpLgriloFjcmVhdGVkCuKWgWJ1dHRvbgppbmluZwriloFjbGljawppYW0KcGxpdApGb3IK4paBcG9saXQK4paBc2VlbQriloFsaWZlCtC90L7QsgriloFpbnRlcm4K0YnQuApzZWwKc29jaQriloFzdG9yCmNsZQplYXJjaAphbmRyb2lkCn1eewriloFlaXRoZXIK4paBZmV3CuKWgWluaXRpYWwKbGVuZ3RoCnJpYQpzcWwKd2lrCuKWgcOpdAp1ZXIK4paBdmFsaWQKQW5kCmluY2x1ZGUKdXJ5CuKWgXN1cwppcmVkCuKWgUFmdGVyCuKWgWR1ZQriloFiZWkKb3VyY2VzCuKWgU5vdgpBY3QK4paBQ29udAriloFicmVhawplc3RlZAriloFhY3R1YWxseQplbHNlCnRtbApyZXIKb25lcwriloFkZXNpZ24K4paBcHJvcGVydHkKcGhpCmFsaXR5Cm9jaAppc3RzCuKWgcK3CnVkaW8KQUIKYWxhCmlvbmVzCtGE0LgKZmluZApBcwriloFjdXN0b20K4paBYW5uCkVTCk9UCmxhbWJkYQriloFpZGVudAriloFvcmdhbgriloFDZW50CuKWgUNoYXIK4paBb3MK4paBaGFyZArRgNC+0LIK4paBLz4Ka28K4paBZXhwZXIK4paBc2VwYXIKeWwKb3VybgriloFkZXYK4paBYXVjaAriloFibG9jawpib29rCuKWgW1hcAppbGxhCuKWgWNvbXB1dAriloFzcGFjZQpyZXN1bHQKKX0K4paBZWNobwpjb25maWcKaGkK4paBbGFyZ2UK4paBd2lkdGgK4paBR28KbWF0CuKWgWRpZmYK4paBa2luZAphbmNlcwp5bmFtCuKWgWNvbG9yCkludApzb2wK4paBcGkK4paBY2hhcmFjdGVyCm9tZW50CuKWgXJlc3BvbnNlCmlnbWEKd2FyZHMKYXJyb3cK0YHRgwp0aWVzCuKWgcO8YmVyCkltYWdlCnlkCuKWgdC/0LXRgNC1CuKWgW5vZGUK4paBaXRlbQphY2hpbmUKaW1hCuKWgXZhCuKWgWFwcHJvYWNoCuKWgXdlcgriloHRh9C1Ck9uCm9sbG93CtC+0L3QsApjdGVkCnVyZWQKQ29udHJvbGxlcgpsaWVkCuKWgWpvCuKWgWRhbAp1bmsK4paBw64Kc3RhcnQKb2xhCuKWgWNvbXBvbgpJQwpiaXQK4paBYmFzZQrQv9GDCuKWgWlkZWEK4paBZGlyZQriloFyYWQKZ3JvdXAK4paBV2l0aApzZXJ2ZXIKc2lkZQpzaW5nCuKWgWRpZXMK4paBbmVhcgriloF2b29yCuKWgWFyZ3VtZW50CuKWgX0sCuKWgWxhbmQK4paBbmFtZXMK4paBb3B0aW9uCml0aHViCnBwZWQKYXVnCuKWgWxpbmtzCuKWgWZ1bGwK4paBc2l0dQriloFjb25zb2xlCuKWgWV0YwphdXgK4paBQ29yCmljcm9zb2Z0CuKWgWNhbWUKbG9jYWwK4paBa25vd24K4paBbXVsdGlwbGUKYW5ndWFnZQriloF0b3RhbApvbG9neQrDpHQK4paB0KUK4paBZnJlCuKWgXRlbgppZGVvCuKWgWJlcwp0cnVlClF1ZXJ5Cm9tbQriloFBcnQK4paBa2VlcAriloFVbml2ZXJzaXR5CnJlYXRlCnBwb3J0CuKWgXB5dGhvbgp0cmEKZWN0b3IK0YDRlgpvcGgK4paBY29uYwriloFmb3VyCnZpcm9uCuKWgXZpYQo/IgppbWFnZQpvbGwK0L3Ri9C1CuKWgWNvbnRleHQK4paBc2VtCi5fCuKWgWVuZwptYXIKQUQK4paBbW9yCuKWgUNhbAriloFjZWxsCmltYWwKQVRFCuKWgWluZgrDtm4KdWZmZXIKc3EKLi4uLgriloF6dXIKV2l0aArRgNCw0L0KY2huCuKWgWRvb3IKY29udGVudAriloFtaXNzCuKWgXNpbXAKw6FyCmlyYQriloFoYXQKVGVzdAriloFjZXJ0YWluCk5TCuKWgWNobwriloFhZHYKd2hlcmUK4paBbG9va2luZwriloF0aW1lcwrQvdC40YUKdXRvCuKWgcOJCmNhbgpob3N0CuKWgSgqCmxvYXQK4paBbmljaHQKRmllbGQKYnVyZwpjb25zdAphZGVzCuKWgU11cwriloFub3RoaW5nCuKWgWluY3JlCuKWgU1pbgriloFwb3dlcgriloFBbWVyaWNhbgpsbgp2YWxpZAp1bmdzCuKWgU5hdGlvbmFsCuKWgVNhbgriloFZb3JrClJlcXVlc3QKY2hhcgriloFaZQpidXR0b24K4paBYWxnClNPTgriloFhcAp1ZmYKYWJpbGl0eQrQtdC8CuKWgWFueXRoaW5nCmVsYQooKSkK0LHQsAphbXBpb24K4paBcG90CuKWgWZ1dAphaWxhYmxlCuKWgXByb3AKIl0K4paBbGVzcwpsYWcK4paBQXVndXN0Ckl0CuKWgXBsZWFzZQriloFzdHlsZQriloFBbHNvCmJ0CuKWgXByb2JhYmx5CuKWgU9uZQriloFwb3NzClVJCnVpdAriloFXZXN0CmhuCitcCkJ1dHRvbgpqc29uCmVycgpyYW1lCmRvbQppbG9uCmFsZgriloFjbGllbnQK4paBY29udGludQp4bWwKcGVjCmFkb3IKbHMK4paBaG93ZXZlcgriloFBbnkKw6RuZAptYXRocm0K4paBdXJsCuKWgWJvb2sK4paBZ2wKaXZlcwpnaQriloF0cm8K4paBVVMKcG9pbnQKb3BlbgriloFjdXIK4paBZXJhCuKWgXBhcnRpY3VsYXIK4paBSFQKb290CmVsbG8KbG9iYWwK4paBYWN0aW9uCuKWgUludAriloFpbmNsdWRlCuKWgWVsZW1lbnRzCtC90LDRjwphcmRzCuKWgUJsCuKWgWh1bQpmcm9tCmNoYW5nZQriloFmdW5jdGlvbnMKaGVuClNlcnZpY2UK4paBaGVpZ2h0CuKWgUxhbmQKaWFzCmdzCmnDs24K0LvQvtCyCm5vZGUKLuKAnQpoYW5kCuKWgdCx0YMK4paBYW1iCuKWgUx1CuKWgXRocm93CuKWgW1vdAriloFBY3QK4paBd29ybGQKX1wKYmFzZQriloFDbwriloFhcmNoCuKWgSMjIyMKZ2VkCnByaWwKb2xkZXIKTW9kZWwK4paBc2V2ZXJhbApsaWUKY2hlY2sKXXsKY29ucwriloFUcmEKaGVjawriloFsZWFzdApkb3duCmVicnUKRGVmCnBhcmFtCmlzY2hlcgriloFjYXMKQ0gK4paBYWRkcmVzcwriloHRgNCw0LcKdWZlbgp1cm9wZQrQtdC5CuKWgWJvdW5kCkNPCuKWgUFuZwriloFNYQpJbmRleApjb3JlCm91Y2gKYXRhYmFzZQpyaWJ1dGlvbgpkb2N1bWVudApMZQp9X3sKdmVybgriloFzdGF0ZW1lbnQK4paBQnJpdApvbm8KcHNpbG9uCuKWgWxldmVsCuKWgXByb2R1Y3QKSVMK4paBY291cnNlCuKWgU1yCj4NCuKWgWJhY2tncm91bmQK4paBcmV0CmVyaW5nCm1vc3QK0YHRjNC60L4K4paBdGhyZWFkCml0aW9uYWwKaXRlcwpQbAriloFkb3MKZ2EKZGF5CuKWgUdlbmVyCuKWgXR3CkFkCiI+PAriloEoJAriloFtb21lbnQKdGl0bGUKY3JlYXRlCnZlcnNpb24KTWFuYWdlcgriloFmdXIKcHBpbmcKaWpuCtC+0YEK4paBcmF0aGVyCnB0ZW1iZXIKT1MK4paBc2l0ZQriloFjYXVzCmFuaQriloFob21lCtC80ZYK4paBc2hvcnQKcGEK4paBbGVhZAppc2hlZApjaW5nCm9yZGluZwriloFwcm90ZQrRgdC70LUKTEVDVAriloFkaWRuCnBvc2l0aW9uCiIsIgooKSwKdHJhbnMK4paBbG90CuKWgdC+0LQKQVMK4paBc2F0CuKWgXBvaW50cwpnaXRodWIKc3R5bGUK4paB0LPQvtC00YMK4paBRGlzCnBvbmVudApvbWV0CnplcgpVTEwK4paBcGEKQVAKYWNlcwriloFVbml0ZWQKYW1hCmV0eQpDb2xvcgriloFlbm91Z2gKVVMK4paBbGVuZ3RoCigpKTsKXntcCmZ0eQpCb3gKYXB0ZXIK4paBY29tcGxldArQvdC40LoKbWF4Cm9iamVjdAooewppbWd1cgppdGl2ZQp1bmNoCuKWgVN1YgplbmRlCtCz0YMKYXRlZ29yeQrRgtGLCmlhbm8K4paBdXBkCuKWgUF1c3QKfXtcCnRvcApsYXMKcGlzCmluZXNzCuKWgXsNCuKWgdCVCkdyCuKWgUFTCuKWgdCy0LUKdGhlcnMK4paBZGVmaW5lZAphemlvbmUK4paBb2ZmaWMK4paBYXV0b20Kw7xuCuKWgWJyb3cK4paBc2VydgriloFyZW1vdmUKaXJvCuKWgUJpYmxpCkVECuKWgXdob2xlCuKWgdGICuKWgUphdmEK4paBenVtCnVhCnBtCmRldgrQutGA0LAKb2xkcwriloFXYXIKw6RuCnBhc3MKdXoKWyIK4paBdHJpCmlzZWQK0YXQsAriloFtZW1vcnkK4paBUG9ydApvcGVyClVwCuKWgVRoYW5rCuKWgU1pY2gKeWNoCmJvYXJkCtCx0YMKSW5zdAriloFiZWdpbgppbmF0aW9uCuKWgU1vZApfLAriloFEZW4Kb3B0aW9uCuKWgWNvbnN0cnVjdAriloFKdXN0Ck1hcApydW4K4paBcmVzcGVjdApoYW0K0LzQsNC9CmltZWRpYQriloFhcHBseQpjcmlwdGlvbgptYWluCuKWgdCa0LAKb2lkCkNvZGUKfTsKSW5mbwriloFmb3JtYXQKTG9nCuKWgdGB0YMK4paBbGF0CnV0b3IK4paBcmVmZXJlbmNlCuKWgWNhbGN1bApvbm4KTG8KaW5mdHkK4paBYWxvbmcK4paBxI0K4paBdGFzawriloFldgp0aGV0YQpyYXMKam9yCuKWgdCx0L4K4paBcHJpbmNpcApNeQriloFlaW5lcgriloFFcwpvbWIKcXVhZApeey0KdW1wCuKWgXRpbGwK0LTRlgriloFsb29rcwriloFvawrRhtCwCm51CkZpbAriloFzb250CuKWgU1lZAphZ3VlCuKWgWNvc3QK4paBU2ltCuKWgWNvbW1lbnQK4paBKFwKZWdlbgriloFwYXJhbWV0ZXIK4paBRnJhbmNlCnJlcAriloFUSAriloF5ZXQK4paBYXdheQriloFjaXJjCuKWgUFQSQplbXAK0LLRlgpMYXlvdXQK4paBbGluZXMK4paBUGFydAplbXB0CuKWgUJpCuKWgW1pbmQKa3kKZ2luZwriloFyZXBvcnQK4paBQWRkCtGA0L7QtAriloFyYW5nZQpjaWFzCmxpcAriloFLYXIK4paBQ29tbW9ucwpnZXJ1ZmVuCmFmZgpzZWMK4paBaHRtbApsaWcK4paBd2luZG93CmluaXRpb24KY2lzCuKWgXV0CmVsbgriloFhdXgK4paBbmVnCkhhbmQK4paBKTsK4paBYW5hbAriloFmcmkK4paB0YHQuApldGNoCm1kCnBhZ2UK4paBbGlicmFyeQriloE6PQpST00KWW91CnNwYWNlCuKWgWR1cmNoCuKWgWhvc3QKYXZlbgriloFGaWxlCmFsbGUK0YLQuNCyCuKWgXBhcArRgdGC0LLQvgptYXJrCuKWgW1haXMKZXJtYW4KU2l6ZQrQtdC6CuKWgdCc0LAK4paBaXNuCuKWgWNvcHkKc3RlbgpyaXZlcgriloF3ZW50CuKWgWphdmFzY3JpcHQK4paBc2FtCuKWgWZyYW1lCuKWgXZpCuKWgXByZXZpb3VzCnJvZHUK4paBbWV0aG9kcwriloFuZWNlc3MKTkEKY2tldAriloFvcHQKTG9jCmhvdwriloHDrm4Kc2hpcAriloFpdHNlbGYK4paBUGxlYXNlCmllbmUK0LLQtdGACuKWgTw8CuKWgW1pbGwK4paBdHJhZApwYWNlCuKWgUhhcgppdGVuCndpc2UKd3JpdGUK0YbQuNC4CtGA0YsKTGluZQpvbG8K4paBYWNjZXB0CmhlaWdodAriloFlbGVjdAplbGxhCuKWgXDDpQpTZWxlY3QK4paB0LvQuAriloFcPAooKAriloFJRApvcHMK0LLQsNC9CmnDswpUUArCuywKbmVjdGlvbgpwYXJlbnQK4paBTWFnClRhYmxlCk92ZXIK4paBbmV0d29yawrRgdC/0L4K4paBYXNzaWduCmlnZ2VyCmlybQopYApvdHRvbQpiZXRhCuKWgWRlbGwK4paBYm9keQriloHQtNCwCuKWgVlvdXIK4paBZnVlCuKWgXBhY2thZ2UK4paBbGlnaHQK4paBKioKTVAK4paBY291Cnllcwo6XAriloHQpwriloFtZW50aW9uCmVuc2NoCuKWgWRlZwriloFjb252ZXJ0CuKWgURhdgphZHQKUmVzdWx0CnRob3VnaAriloFidXMKeHkK4paBc2VlbgpBbGwKcHVibGljCml2ZWx5CuKWgVJlYwriloFIaXMKc2ltCuKWgWbDtnIK4paBaGlzdG9yCuKWgXNldHQKcmF0CmFibGVkCuKWgcK7LApnb29nbGUKV2ViCsOpbAriloF0aXRsZQriloFKYW51CtGY0LAK4paBdG9vawppZGVuCnN6CuKWgUdldAriloFvYmplY3RzCuKWgWNvbW1vbgriloFjaGFuZ2VzCuKWgUxvbmQK4paBZXh0ZXJuCuKWgWp1CklzCuKWgWF2YWlsYWJsZQp0cmkK4paBbcOhcwpvc2EKQmUK4paBRGF0YQp1cmFsCuKWgWhvbQriloFhY2NvdW50Cm9vCuKWgXBlcm0KcmVzcG9uZAp5dAriloFzZW5kCuKWgXJldHVybnMKaXZpZAriloFleHBsYQrDrW4K4paBbm9yCklmCuKWgUZyb20K4paBdGFyZ2V0CmZlY3QK0LXQvdGCCuKWgXVpdAriloFKbwriloF2YXJpYWJsZXMK4paBc2VyaWVzCuKWgWZ1bmMK4paBaGltc2VsZgriloHRh9CwCmFudGkK4paBYWNoCmlhbG9nCuKWgXN0ZAphZQriloFmb290CuKWgXVudGVyCmdyZXNzCk5vdApyYWQKZsOpcgriloF1dGlsCm9yZW0K4paBc291Cm9wdAriloFvZwriloF1bWEKaXRhcgriloFPawrDvGNrCnNxcnQK4paBYW50CuKWgXdlcmRlbgrDpXIKfSk7CuKWgVBhcmlzCuKWgWV4Y2VwdGlvbgriloFkZXRlcm0K4paBVm9sCuKWgVNhbQriloFlc3MKbGllcwppb25pCm9kaW5nCmlkZ2V0CuKWgXByaQriloF3aGV0aGVyCuKWgdC/0L7QtAriloFudW1iZXJzCuKWgX4KZXZlbnQK4paBc2hvd3MKYXR1cmVzCuKWgWhvdXNlCuKWgWZhY2UK4paBc2nEmQp2aXJvbm1lbnQKdmFuCuKWgWluY2x1ZGluZwriloE8LQp0aW1lcwpub3cK4paBcHVyCmlmaWVyCuKWgWVtcAriloFjbGEKbW9uCuKWgURhcwphZHkK4paB0LLRltC0CuKWgdGGCmFib3IKT1NUCuKWgWJhbmQK4paBw7oK4paBZXhhY3RseQppZXJ0CmF2aWcK4paBcmVkdQriloFTRQpsaXNoZWQKQnUKTWVzc2FnZQpjZWxsCmZ1bGx5CuKWgXN2CuKWgW1ha2VzCnBvbAriloFyZXF1aXJlZApmZXJyZXIK4paBcGVycwriloFtaQpGSQriloFQYXVsCuKWgVVJCuKWgUJlbAppbmMK4paBY29udGFpbnMKT3V0CmFzdXJlCnB1Cm90bwriloFnYW1lCnpuCuKWgVdoeQpvcml0aApiaWcK0LrQuNC5CnNpZ21hCuKWgXF1aXRlCuKWgWplZApyZWMK4paBU1FMCtCx0LUK4paBTWFydAp5YQriloFzY2hvb2wK4paBc2ltcGx5CuKWgXZvcgriloFkb3VibGUK0YDQsNCyCuKWgVN0cgppZW0K4paBYWxidW0K4paBcmVzb2wK4paBZGVpCuKWgVdpawriloFhdwp1bWIKb2xzCuKWgSovCuKWgXplCuKWgWFuaW0KLz4KcmlzCnJlc2gKTm8KaXF1ZXMKY3VycmVudAriloFwZXJpb2QK4paBQXByaWwK4paBc3RvcmUKJywnCuKWgVNldAo9ewphY2hlZAriloFNYWwK4paBUGFsCmFudGVzCmF0ZXJpYWwK4paBd29ya2VkCmxlcQpvcmVmZXJyZXIK4paBaGFwcGVuCuKWgWJveApuZXkK4paBY2xvc2UK4paBZ3JhbgriloFsaWUK4paBaXIK4paBZXhwZWN0ZWQK4paB0LTQu9GPCmNsaWNrCsiZaQriloFwYXJ0ZQpvZ24K4paBRm9ybQriloFtZW1iCuKWgXBsYW4K4paBdGVhbQpdWwriloFjb21tdW4Kb3JyeQplbmN5CmdsCmluYXJ5CmNkb3QKXlwK4paBRmlyc3QKYW5kZXIK4paBRGVjCnJlcXVlc3QK0YHRgtCy0LAK4paBc3RydWN0dXJlCuKWgXx8CuKWgUNvbXAKYWN0b3J5CuKWgU1pbAriloFTb21lClN0cmVhbQriloFhc3N1bQp1ZW4K4paBd29yZHMK4paBU2VwdGVtYmVyCuKWgdCa0L4K4paBZGF5cwpvcmllcwrRgdGC0LDQsgpzbQp2aW4KcGFydGlhbAriloFwYXJlbnQKb2oK0L3QuNC4CiEiCnVnaW4K4paBV2luZG93cwpFZAo6fQriloFxCuKWgWJlbgppYW5hCuKWgWxhYmVsCnN0YXRlCnV0ZWQK4paBKCkK4paB0YHQstC+CuKWgWVkaXQKdXJpbmcK4paBTlMK4paBSmFocgriloFwcm92aWRlCkhlCuKWgVllcwphbmVsCmVuYW1lCuKWgURvbgppc2sKZ3JhCmVsaWoK4paBcm9vdAoqLwriloFGcmUK4paBTW9yCnVzZWQKcmFuZ2UK4paBdGFtYgriloFtb2R1bGUK4paBZGlyZWN0b3J5Cm91bmRzCkFjdGl2aXR5CuKWgW11CmluZm8K4paBZnJlZQpvcmdlCnRhYgopPQpsYW5nCuKWgdC+0YEK4paBRlJPTQriloFlbnRlcgriloFiZWNhbWUKaWRhZQrRhdC4CuKWgVN0YXRlcwp2ZXJzZQriloFleHBsCnludApVTgplZQplbmRlbnQK4paBbWFraW5nCuKWgSIkCnVuaQpxdWVuY2UK4paBbHVpCkhUCuKWgXVzZXMKemllCm5pYQpDb250ZW50CuKWgUNvdW50CuKWgXN0YW5kYXJkCkVOVAriloHQutC+0L0KZm9ydAphZGFzCtC30YMKU3lzdGVtCuKWgVN3CuKWgWV2ZXIKTE8K4paBY29ycmVzcG9uZAriloFQbwphcmdpbgrQutGCCtGW0LkK4paBcmVtYWluCmNpbwriloFhY3R1YWwK0YHRgtGDCuKWgXNpbmQK4paBUGUK4paBY2hhbmdlZAriloFOb3RlCnNraWUK4paBZmFtaWx5Cml0w6AKY29zCnR4dAprZXIKY2VlZAriloFhcnIK4paBY2FtCml6ZXIK4paBRGFuCmhlbAppY3VsdApIUAppbGVyCuKWgVNhbAriloFjb25uZWN0aW9uCnVzaW9uCmtuClJJCuKWgXZvbQpMaXN0ZW5lcgriloHDtgriloFkaW0K4paBcHJlc3MK4paBZXNjCuKWgVRyeQphdGFsb2cK4paBdGhhbmtzCkRPCuKWgXdyaXR0ZW4KZGlyCnJldwriloFmaXJlCuKWgU5hY2gK4paBw6EKZW5jCuKWgW9yaWdpbgriloFOb3ZlbWJlcgriloF9OwpDb3VudAriloHQl9CwCuKWgWdyYXBoCuKWgW1pcwriloFFeHRlcm5hbAriloHiloHiloHiloHiloHiloHiloHiloHiloEK4paBb3B0aW9ucwriloFVUkwK4paBcGhwCuKWgWludGVncgpDb25maWcK4paBVGV4dAppbm5lcgriloFjcml0CizigJ0K4paBdG9nCiQkCm5vZgriloFzZXMKw7xocgriloFTaW5jZQpEZXMKdWJlCuKWgXNlY3Rpb24K4paBZ2kKZm9yZAriloFBc3MKYWluZXIKdHRwCuKWgWJlaGF2CnBvcnRzCmRyYXcKVGhpcwpyYW5jaAppbmRpbmcK4paBZXN0YWIK4paBb2J0YWluCnJpY2gKbGljaXQK0LXQsgriloFxdWFsCuKWgXphCuKWgWhhcgriloFmYWMKYWFyCmpldAppY2xlcwriloFBdXMK4paBaG9yCuKWgXJlbW92CuKWgXdpZQpDbGllbnQK4paBbmF0dXIKaGlwClN1YgriloFyYW5kb20KREYK4paBYXJlYQp0YWcKUHIK4paBSXRhbAriloFyb2t1Cm5vZm9sbG93Cip9CuKWgW90aGVycwriloFsaW1pdAriloFzaWwK4paBc2F2CuKWgW9mdGVuCuKWgXJlbmRlcgpEQgriloFNYwriloF6aWpuCtC20LXQvQriloF0YWcKbWluZwpsaWNoZW4KcGFjawriloFBZwriloFzZW5zZQpwZwpNZXRob2QKYWdlZArDoWcKxYJhCuKWgWludGVyZXN0CuKWgWFzc29jaQp2b2x1dGlvbgriloFlbXB0eQppY2hlCuKWgWdybwriloF0eXBlcwriloFTaWUKSW50ZXIK4paBbm9yZWZlcnJlcgriloFnaXZlcwpoYWwK4paBc2F2ZQriloFmb250CnJ1Y3Rpb24KU2NyaXB0CuKWgWFsbGEK4paBc2F5cwriloFmdQphcGUK4paBbGFuZ3VhZ2UKaWdlcgriloFLaW5nCmJvcgp1dgriloFzaGFsbAriloFFdXJvcGUK4paBZWluZW0K4paBd2F0ZXIK4paBZ292ZXJuCmFuegphdG9ycwriloFtb250aAp5ZQriloFpbXBvcnRhbnQKYXR6CmZpcnN0CuKWgVRyYW5zCuKWgU1hZAriloFicmEKaWthCuKWgVNhaW50Cm9yaWEKa3JlCmVtZW50cwriloFCZW4KbGF2CuKWgWFkbWluCuKWgUhlbgpyaWwK4paBU20KY2F0CuKWgVJlZmVyCuKWgdCoCuKWgXByYWN0CuKWgVBhdAriloFHcmUK4paBeW91bmcK4paBSW50ZXIKb21hCnRlZ2VyCmliaWxpdHkK4paBcGFyYW1ldGVycwriloFldmVyeXRoaW5nCmRhdAp1cm9wCm9sZWFuCuKWgXJldHVybmVkCuKWgUNsYXNzCmFjeQojIyMjCuKWgXDFmQriloFmb2xkZXIK4paBa29uCuKWgWd1ZXNzCmd0Cmplbgphbm5lbAppY29uCuKWgWNvbWIKcmljdAriloFoaWoK4paBYXV0aG9yCnNlZQpoZXJlCnN0cmEK4paBZW50aXJlCuKWgWRpcmVjdGx5CnJhZnQKaGVldAplc3RlcgriloHQvNC4CuKWgW1hc3MKdW50dQriloF1c2VycwpjaGkKUEUK4paBY29tcG9uZW50CkNsaWNrCkF0dAriloFzb2JyZQphbmRzCuKWgUhvbAriloFTYW50Cm9yaQriloFzdWEKc3RkCmVudGljCkNDCuKWgWZpbHRlcgpTUUwK4paBR29kCkF0CuKWgdC80YMK4paBcGVyZm9ybWFuY2UKZGVsdGEKYW5kZQphbWVyCtC00YsK4paBY3VsdAriloFOb3IKYnV0CuKWgWxpawoqKioqKioqKgrRgdGC0LLQtdC9CuKWgWNvbW1lCuKWgWRyCmltZXIKb3JkaW4K4paBY29uZGl0aW9uCmVzdGUKKFsKRkYK0YLRjNGB0Y8KaW1vCnJhYgrRltC70YwK4paBaGFsZgplYWNoCkRpcwriloFyb3dzCuKWgWhvbgriloF0b2dldGhlcgriloHImWkKbWVkaQphZ24KYWxsZWQK4paBdmlsbApJTkcKaWRkZW4K4paBZHJhdwp5bnRheAriloFhdHRlbXB0ClVSTApwb3NlCuKWgWluZGljCtC90LjQutCwCuKWgUVuZ2xpc2gK4paBZMOpYwriloFuZWVkcwriloFub3JtYWwKdXJ0CuKWgdC90L4KfX1cCmxhc3QK4paBRmluCuKWgUZlYnJ1CmlsYQriloFjb3VudHJ5CuKWgWZpZWxkcwriloFtYXgKbMOpcwpvd2llCuKWgWRldXgK4paBYnVpbHQK4paBTWFpbgriloFjYW1wCml2bwppdmEKaWN5Cnppb25lCk5vZGUK4paBOikK4paBYW1vbmcK4paBT2IK4paBY2FzZXMKaGFwcwpzZXJzCmFydGVyCsWbY2kK4paBaXRlcgriloFuYW1lZApleGVjCuKWgXNlYXNvbgp0b3QKPT4KZ3JhcGgK4paBbmlsCmFjaW9uYWwK4paBTlVMTAriloFzcGVjaWFsCtGB0YLQtQpjc3MK4paBXCgKdnMKYWVsCuKWgWNpdHkKb3ZhCuKWgWFydGljbGUK4paBU291dGgKQWN0aW9uCsOnYQpzcHJpbmcKaXR1ZGUK4paBY29tcGxleAriloHRh9GC0L4KYnVpbGQKZ2FtbWEK4paBRW50CmllcnMKJy4KY2FyCmFwYWNoZQppbmdlbgpJbnB1dAo64oCJCuKWgWR5bmFtCmFsbHMKc2hvdwp8XAriloF3aXJkCkJhcgphbHRoCm1vZGVsClRyYW5zClJvdwphYmUK4paBbGliCm51bGwKcmFnbWVudAriloFTdGF0ZQriloFsYXcKRnJhbWUK4paBTG8KZ2ViCn0kLgriloFuZWVkZWQK4paBY29udHIKYXJpZXMK4paBc2NyZWVuCnlyCm1tCuKWgXNob3duCuKWgWJhZAriloFjYXN0CuKWgVRlc3QK4paBQXVmCuKWgXF1YW50CmlnYQriloFyZW4K4paBTWFjCuKWgXRyYW5zZm9ybQriloFkaWZmZXJlbmNlCuKWgXRpdApURQriloFzdGVwCuKWgWNhcHQK4paBY29sbGVjdGlvbgppY3Rpb25hcnkK4paBVG9tCnJpZXIK4paBbW92ZQpjb3BlCm9yZHMK4paBZnVydGhlcgriloFjb2x1bW5zCuKWgUxpbgriloFmaXhlZAriloFjaGlsZHJlbgpNUwptbwp1bmEK4paBaW5kaXZpZAp0dHkKYXN0ZQpzcmMKbWF0Y2gKd2kK4paB0YUK4paB0LTQuAriloFvcmQKaXZpbmcK4paBQnJvCuKWgWFsbW9zdAriloFQcmVzCnJlY2kKYXJpbmcK4paBLy8vCtC10YLRgdGPCuKWgXNpZwpsaWdodAriloFSZWQK4paBc3VnZ2VzdApvbGYK4paBw6l0w6kKaXNhdGlvbgrQt9C90LAKTmV3CtGB0YLQsNC9CkxBCnVuaWNpcAriloFmaWd1cmUKbXQKaWFsZQriloFjYXRjaApkZWZhdWx0CuKWgXRlbGUK4paBbWF0dGVyCmNhc3QK4paBUmljaAriloFoYW5kbGUKdmFsdQokLQrQvtCxCuKWgWpzb24KQ3JlYXRlCuKWgWV4YW0K0LDQu9GMCtGO0YIKb3JlZAppZG9zCmFwcGVuZAriloFBcnJheQrQutGBCn1bCnJpdmUK4paBY2x1YgptYW5uCuKWgWVzdGUKZXN0YQriloFHaQriloFKYXAK4paBTmFtZQpDb2x1bW4Kb3Vwcwppc21vCuKWgUNpdHkK4paBY2xhc3NlcwriloFpbmZsCmhsCtGA0L7QvAriloFhZGRpbmcK4paBZmFpbAp4eArDtWVzClNjCnV0aWwK4paBbG9jYXRpb24KbGVnZQphZ28K4paBcHJvcGVydGllcwphYmlsCnZhcwp9JCwKaXR0ZWQKw7NkCuKWgURlbQriloFhc2tlZAriloF0YWIKU291cmNlCuKWgWVycm9ycwpvZ3JhcGhpZQriloHQttC4CuKWgW1hbApzdHJhY3QK4paBZHJvCnJhawriloFub3RlCuKWgXNldHRpbmcK4paBZmVtCuKWgXNhdwppYXIKSEVSCtC10YEK4paBcHJlZAriloFPdXQK4paBaXRlbXMK0LvQsNC9CuKWgXdlcmQKZXJzaW9uCmxpYQriloFzaW4KaWNodGUK4paBZmVlbAriloHQv9GA0LAK4paBb2RlcgpVRQpvY3VtZW50CuKWgW1vZGUK4paBTmEK0LTQtdC9Cm1lcwpmcmFtZXdvcmsK4paBYXV0bwrQvdGL0LwKdWJ5CuKWgXRlbXBsYXRlCuKWgW1lc3MKaWVkZXIK4paBcmVsYXRlZApva2VuCuKWgWZvbGxvd3MKc2VhcmNoCmFtaQriloF3YWl0CmlncgriloFsb3cK0YHQutC40YUK0YHQutCw0Y8K4paBTWFyawriloFpbGwKYW1lbnRvClw8CuKWgWRmCm9zaXRpb24K4paB0JLQuAppc2YK4paBRGV1dHNjaAphaGwKd2FyCml0ZWN0CuKWgXNhbAplbGVuCkJ5SWQK4paBZ3J1CnN2CuKWgXBhc3NlZAriloFhw7EKU2NoCuKWgXNvbHZlCndlaXNlCmF0b3MK4paBbWVnCuKWgW1lbWJlcgplcm5hbWUK4paBY29ubmVjdAppcHMK4paBcm91bmQK4paBXQpuZXMK4paBZGlyCuKWgUxvbmRvbgpkeQpGQQriloFyZWNlaXZlZApyZWV0CuKWgUxvZwriloFTY2hvb2wKYW5nbwriloFUaGVzZQriloFNb250CuKWgWVuZXIKbGFkCuKWgWRlZmluZQpzaWduCuKWgWNsZQpmaWd1cmUK4paBVmlldwp0ZXh0YmYKJFwK0LfRiwpudW1iZXIK4paBZGluCmVsbGVyCm9yaXRobQpmYWxzZQpmb2wKZmZpY2llbnQK4paBSFRNTApsaWNoZQriloFNbwriloFpbnRyb2R1CmV4cAriloFzdHJvbmcK4paBdGh1cwovKQriloFlbGUK4paB0YLQsNC6CuKWgdC/0LAK4paBZG9udAriloFjYXVzZQpOdW1iZXIK4paBaW1hZ2VzCuKWgXNhbXBsZQriloFzY2kKbGlrZQriloFMb3UKZGl2CmFuYwriloFmcm9udApuZW4K4paBbWlzc2luZwphcmlhCnByZXMK4paB0L/RgNC10LQKREkKZmlsdGVyCuKWgU1pdApVUgriloFvcHAK4paBc3FsCuKWgdGA0L7QutGDCmVyZW4KZW1hdArDrXMK4paBSmVhbgrDqWMK4paBY2kKZW5uZQphdGZvcm0K4paBdGFrZW4K4paBT2YK4paB0L3QsNGB0LUK4paBZXJyCk9QCkZyb20KRGVmYXVsdAriloFHZW5lcmFsCndpa2kK4paBZ3JhbmQK4paBZWluZW4KUmVnCkhhbmRsZXIKY29ub20KYW5nZXIK4paB0LHRi9C7CuKWgUxvcwriloFleHByZXNzaW9uCtGI0LAKeWFsCuKWgSQoJwriloFzd2l0Y2gK4paBdmVjdG9yCuKWgVRob20K4paBdmlydApsZWFzZWQK4paBY292ZXIK4paBcmVzcApha28KcmVuY2gKb3RhCkNlbGwKYW5nZWQK4paBKz0KbGFjCnNrYQpuZXh0CuKWgUludGVybmF0aW9uYWwK4paBV2lsCuKWgW9udAppYnIKdXN0cgriloFibGFjawriloFzZWxlY3RlZApjaGVyCuKWgWxpdGVyCnJvb3QK0LvRgdGPCuKWgUxpZmUK4paBaW5zZXJ0CuKWgW1hdHJpeAppc2VzCildCuKWgXBlbApPdmVycmlkZQpyeXB0CuKWgWZvcm1lcgriloFGaWxtCuKWgU5vcnRoCmNsaWVudAriloFuaWdodArRhdC+0LTQuAriloFBdXN0cmFsCuKWgVJldApyaG8K4paB0L/QtdGACmlwZWRpYQriloFleHByZXNzCuKWgXRoaXJkCuKWgW1ham9yCuKWgWdyYWQKb3dlCuKWgWJlbGlldmUKb3VybmFsCuKWgXN0YXR1cwp1bmMK4paBZG91CuKWgUpTT04KdWlzCuKWgXBvcHVsYXRpb24KZW56CuKWgVdpbGxpYW0Kc2YK4paBT2JqZWN0CuKWgWNpbgriloFEaQpjdXJpdHkK4paBT3BlbgriloHQu9C1CmxhcgphZGRpbmcK4paBa29tCn0oXAriloFraWwKdW1lcgoiLz4K4paBZmVhdHVyZQriloFBcmUKY2tzCuKWgUludGVybmV0CuKWgWloCuKWgXN0YXJ0ZWQK4paBZWFybHkK4paBYmVnYW4KVEgKcHl0aG9uCmFzcAriloFGcgriloFjbG9zCmlzdGljCuKWgW11c2ljCuKWgWRpZwriloFpdGFsCuKWgURhdmlkCuKWgXdlYnNpdGUK4paBY29udHJvbGxlcgriloFNZXIKY29udGV4dApwcm9kdWN0Cm9zcAriloHiloHiloHiloHiloHiloHiloEK4paBanVuCnJvd24K4paBQXoKIjoiCuKWgWFhbgriloFEYXRlCm11bHQK4paBYnJvd3NlcgrRgNC10LQKd2hpY2gKUkEKcXVhcmUK4paBUnVzcwriloFzb29uCuKWgVByZQp0YXUK4paBd2VlawriloHQsdCwCuKWgW9jdAriloF0b3duCnJveQriloFlbHMKYmxpYwp1bmRsZQriloFIaXN0b3IK4paBZm9pCuKWgW1vZGVscwrQt9C+Cm9ueW0KUGFyYW0K4paBTWV0CmdlbmVyCmrEhQriloFlc3BlCkNFCuKWgWRldmljZQplbGxvdwriloFkZWJ1ZwrDqXJpZQp1c2luZwrQsNC90LMK4paBKikKdWRpCuKWgU1pc3MK0LrQvtC8CnBvc2VkCuKWgXp3ZQrRltC9CuKWgVJvYmVydAriloFPY3QKbG9wCmphcgriloFhdmVyCuKWgWhhYml0CuKWgTo6CsOkbmcKU3RhcnQK4paBcG93CuKWgXNyYwriloFwYXR0ZXJuCuKWgdCtCuKWgWJpCm90ZXMK4paBX18K4paBc2VucwriloFhdm9pZApleGFtcGxlCnV0dApMYWJlbAp0ZXgKYm9vdAplc3RvCuKWgU1hcmNoCuKWgWVhc3kKaWN0dXJlCkdyb3VwCuKWgWZhdGhlcgriloF1cGRhdGVkCuKWgVZvCuKWgUlJSQpvbWVnYQriloFhbGxlClJlYwp5ZwrQt9C1CuKWgURpbQpuZWN0CuKWgVRvcgriloFkZXV0c2NoCuKWgXdoaXRlCuKWgW5hdGlvbmFsCnBwZQriloFhaXIK4paBcGFzc3dvcmQKZGV0CuKWgWJpZwriloFVc2UKY2FsbAriloFleHRyYQpXZQphbmlhCuKWgWhvbGQKQ29udHJvbAriloFDTwriloHQvNGWCml0aQriloFLZQplbnUK4paBUGFyawrRgtC+0LwK4paBYXV0aAriloFjZW50ZXIKUGgK0YLQvtCyCmlkaW5nCuKWgWFjcm9zcwriloFzb25nCuKWgXBoeXMK4paBbnVtZXIK0YnQsAriloFBbGV4CuKWgXByb2JsZW1zCuKWgUVycm9yCmZvcm1hdAriloFBY2MK4paBc2l4CuKWgWRiCuKWgUNhc3QKb21zCnByb2plY3QK4paBdmVydApjcmV0CuKWgWhlYWRlcgriloFzdHJlYW0KaWRzCuKWgXRvcgriloFzZXB0CuKWgWVzdGltCuKWgWRlY2wK4paBZ2F2ZQriloFwbGF5ZXIKeXNpcwriloHQtNGA0YMKYW1tCtGJ0L4K4paBKCIK4paBYXgKUHJvcGVydHkKdXNyCuKWgXNvbWVvbmUK4paBaW1wcm8KYWRlbgpyb3RlCuKWgdCc0LgKaWgKKyspCuKWgXZpZGVvCuKWgWV4aXN0cwrQutC70LAK4paBY29tcGxldGUK4paBc2Vzc2lvbgriloFjb25zdGFudAppY29zCuKWgXBhY2sKcm9tZQplZ3IKQXBwbGljYXRpb24K4paBeWVzCuKWgWVsbGUK4paBZW1haWwKb3JmCmNhc2UK4paBcG9pbnRlcgriloFyZWdhcmQKc2VuCnN0YXR1cwriloFtZXMK4paBZGVsbGUKaW5ndG9uCuKWgUJhcwopXgpkZXZlbG9wCuKWgWZvcmNlCuKWgWNoYXJhY3RlcnMK4paBY3Jvc3MK4paBZGVhdGgK4paBdGFrZXMKw6lyaQppZ25lCtGH0LXQvQpVUAouOgpUaHJlYWQKanUKaW55CuKWgWRldGFpbHMK4paBeG1sCnRhaXQKb3V0cHV0Cm1lc3NhZ2UKJycK4paBQnJpdGlzaAp2aWxsZQriloFEaXYK4paBVXNlcgpjbQrRh9C90L4KY29sdW1uCmVxcmVmCsOzcgpvbm9tCuKWgVBvc3QKZWxsZW4KQWIKdWx0w6kK4paBcGVyZmVjdAooKXsKdmlzaW9uCmFjdGl2ZQpsaWVyCnJpagpzZAriloFrw7YK4paBbmllCuKWgXJlbGlnCuKWgW90CuKWgW1hY2hpbmUK4paBaGVsZAopJC4KPT09PT09PT0KY2tlcgrQstGLCmJvcm4K4paBcGFzdArRgNC40Y8K4paBRHIK4paBcmVndWxhcgriloFwcm92aWRlZApURVIK4paBdW5pdmVycwriloFnZXRzCuKWgW51CuKWgS8qCm9iZXIKZmluCuKWgW5lbGxhCuKWgWJlY29tZQriloFgYAriloFoaXN0b3J5CuKWgVNvbAriloFSYWQK4paBdGVybXMK4paBZXZlbnRzCmx5bXAKKSkpCtGA0L7QstCwCuKWgWFic29sCuKWgXNvZnQKbGlua3MK4paBaG9wZQriloFzdWJqZWN0CiIpLAriloFjcmVhdGluZwriloF9DQriloFTawriloFmbG93CuKWgdCg0LAK4paBYXNzZXJ0CnpldAriloFGcmFuawpzYQriloFkaXN0cmlidXRpb24KY3UKYmFuZAppenoK4paBam9iCmluZXIKc3RydWN0CsOhawpUTwphdWYK4paBZXh0ZW5kcwriloFHcmEKZGlzcGxheQriloFzaWduaWZpYwpvbmV5CnNvdXJjZQptaWNyb3NvZnQKaW5kZXIK4paBcXVpY2sK4paBd29uZGVyCkluc3RhbmNlCmVsbGVzCsOobWUK4paBY29tcGFueQp1w58KLn0K4paBc2VwYXJhdGUKVU0KSEVSRQriloF3cml0aW5nCml0dXRpb24K4paBR2VzY2gK0LzRjwriloFKYW1lcwriloFERQriloFTcGUKcHJvY2VzcwpTdHIK4paBc3ltCuKWgWFvCuKWgXd5CuKWgWFueW9uZQriloFVcAp1c2V1bQphcm9uCuKWgWRlZmluaXRpb24K4paBYCQK4paBZmF2CnJpYnV0ZXMK4paBUsOpCm9ncmFmaWEKZWxlbWVudApjYXAKcGF0CuKWgUJyYQopKAriloFhY2NvcmRpbmcK0LPQtQriloFwaWUKZWxpCn0iCuKWgWFjdGl2CuKWgXN0b3AKcGF0Y2gK0YLRlgriloFKb3NlCkVuZAriloFwcnplCuKWgWFnZQppdG9yeQriloFQSFAKYWdlbWVudAriloFgLgriloFwcmV0dHkK4paBcmVjb21tCuKWgXN1ZAriloFyZXF1CuKWgdC+0LHQu9CwCmF0aXZlcwriloFIaWdoCsOhegpvdWwKcmVzdAriloFUZXIKdW5kZXIKdGhlcm4KY2VudGVyCuKWgXVyCmxhdAriloFpbnRlcmZhY2UK4paB0LjQvQriloF3aG9zZQppY2FzCmFtZW4KRmlsdGVyCuKWgXN0YXRpb24KUGFnZQriloFhcm0K4paBZXllcwriloHRgNCw0LkK4paBc2V1Cm9saQp3aW4KbGlrCmdleApjaGFuCmlkZW5jZQphcmdzCmFraW5nCuKWgUdvb2dsZQriloFTdHVkCuKWgWhvCtGC0L7RgNGLClN1CuKWgWF1dG9tYXQKw6ptZQriloFjeQpsb3IK4paBc3RhY2sK4paBU0VMRUNUCkFGCuKWgT4+CuKWgWNvbXBldAriloFwYWlyCuKWgWluZ2zDqXMKUmVzcG9uc2UK4paBRmlnCmdyYWQK4paBZG9jdW1lbnRhdGlvbgriloFjYW50CuKWgWFwcHJlY2kKw6VuCuKWgWxlYXJuCuKWgWluZGVwCuKWgXBhbApwYWNrYWdlCmFyZXMK4paBQmVybGluCtCx0LvQuApyZWljaArRkdC9CuKWgXNhdGlzZgriloFyZWdpb24K4paBZnJpZW5kCuKWgUdlb3JnZQriloHQktC+CuKWgSIiCuKWgWRlc2RlCkZhY3RvcnkK4paBQ291bnR5Cm91dgriloHigJgK4paBaW5zdGFsbGVkCuKWgXdhbnRlZAriloFQeXRob24K4paBaW50ZXJwcmUK4paBaW5jbHVkZWQK4paBKCgK4paBYWx0ZXJuCmlzdG8KZ24K4paBYm9yZGVyCnBkZgriloFkdXAK4paBZG93bmxvYWQKanVzdAriloFtZW1iZXJzCmNoaWxkCuKWgXBheQriloFjZXIK4paBbG9va2VkCuKWgWNvcnJlY3RseQphdXRoCuKWgdGB0YLQsNC9CuKWgWVzcAriloFkZXNjCmViZW4K4paBcXVlc3Rpb25zCm1hbAriloFhYmdlcnVmZW4K4paBQmFuZAriloFbXQpCYXNlCuKWgXJpcwriloFmb3J0CuKWgUlkCuKWgXZhcmlvdXMK4paBTGVhZ3VlCuKWgUhhbmQK4paBVHlwZQppcmwK4paBRmUKacOpbgppdHRlcgriloFmYXN0CnN0YQriloFleGNlcHQKaWN6CuKWgUZyZW5jaAriloFlbnZpcm9ubWVudAriloFjb25zZQrRg9GACtC+0LPQvgriloFuZWNlc3NhcnkKdGFyZ2V0CuKWgXJlYWRpbmcKaG9tZQp6ZWljaAriloFlcXVhbAriloFwacO5CuKWgXByZW0K4paBZGlmZmljdWx0CuKWgXVuaXQK4paBcmVwbGFjZQriloFoZWFydAriloF0YWxrCkFNCuKWgVJFCuKWgVBlcnNvbgplbmRlbmN5CuKWgWltbQriloFodW1hbgpkbgriloFLaXIK4paBQXV0Cmtub3duCuKWgWZyZXF1CnN5c3RlbQrQu9Cw0LIK4paBU3oK4paBR2FsCtC90L7QtQpzZWx2ZXMKcmlnaHRhcnJvdwriloHQodCwCj0iQAriloFidWlsZGluZwppbXBvcnQK4paBZmFtCuKWgWRlbGV0ZQphaXJlCm1hcnkK4paBZnVuZAriloFwYXJ0aWNpcAriloFzeW4Kc2luCuKWgWxvd2VyCuKWgXplcm8K4paBc2VjCuKWgWZyYQpQb2ludAriloFmYWlsZWQKaWVudG8KY3VwCuKWgXNsb3cK4paBbmF0aW9uCsOkaHIK4paBaW5mbwriloFQdWJsaWMK4paBZGVjbGEK4paB0KLQsAriloFzb2xkCuKWgVJlbQriloFQaGlsCtGB0YLRgNCwCuKWgW1laHIK4paBV29yawriloFOb3JkCuKWgWZhaXQK4paBZ2V3CnByaW50bG4Kb2JpbGUK4paBS29uCuKWgWFzc3VtZQpsYW5kcwriloFhbW91bnQK4paBUHJlc3MKw71jaAriloFtYXhpbQriloFDaGFtcGlvbgpsaWJyYXJ5CmHDsQriloFXYWwKQ29tbQpdXQriloF6dwriloFzb2NpYWwKTEkK4paBVW50ZXIKdm9yCkRlbHRhCmVtYWlsCnJhaW50Cm9uaQriloFhbHQK4paBbsOpCtGG0LjRjwpvZ3JhcGh5CuKWgW1lbnRpb25lZAriloE8PQriloFjZXR0ZQriloFjdXJyZW50bHkKdmFyZQppemluZwriloFEZWYKaWNvbArDvG5kCuKWgWNvbmZpZ3VyYXRpb24KZXN0aWcKSUlJCmxhbQppw6hyZQriloFFYXIK4paBdHUKRW50CuKWgVVzaW5nCuKWgdC60L7QvApjaWUK4paBcHJvb2YK4paBaW52b2wK4paBSGlzdG9yeQo+PAriloFBTkQKYXZ5CuKWgXJlbGF0aW9ucwokewriloFjb21lcwriloFkaXJlY3Rpb24K4paBSnVuZQriloFXYXkKQ29tcG9uZW50CmVjaAriloFQZXRlcgpzZwriloFzdHJhCnVjdAriloFpbXBsZW1lbnRhdGlvbgphdHRsZQriloFjegpwbG90CuKWgXBsYXllZAoiPjwvCuKWgWZpdmUK4paBY29sbAriloFDaGFybGVzClRyYQriloFzdW8KZmlsZXMKZW50ZXMKcmVzcG9uc2UKSG93CuKWgVNvY2kK4paBaWduCuKWgWxlZAriloFHZXJtYW4KdWRvCuKWgUR1CuKWgXRpbQpvdW50ZXIK4paBYXR0YWNrCnVyaQriloHQsNGACmVzc2UKaXZpbAriloFKdQriloF2ZWwKbWF0cml4CuKWgU1hdApnaW8K4paBWmVpdApWRVIKaGFzCkNvbm5lY3Rpb24K4paBaWhyCuKWgWF0dHJpYnV0ZQriloFkaXNjdXNzCuKWgWRvbWFpbgpiaW5kCuKWgVNlYwpyaWsKY2xvc2UKZ2luCuKWgWxvdmUKYW50bwpnZW50CmFiYQpqYW5nbwpiaQriloFvYnNlcgppdHRpbmcK4paB0YDRgwp9PQphZ2VuCkJDCnNvbWUK4paBQnUK4paBc29jaQriloFpbmRpdmlkdWFsCuKWgWRlYWwK4paBb3V0c2lkZQpyaW8KRXhlYwphbmRpZAriloFidXNpbmVzcwriloF0ZW1wb3IK4paBVHVyCuKWgSghCnJpdGVyCuKWgWdvb2dsZQpdOgppdHRlCnhpCuKWgdCf0LAKaG9sCtC90YwKcmluZwriloFzdWwK0L3QvtGB0YLQuApfLgpnYXIKVGFzawriloFDaGVjawriloFtb2Rlcm4K4paBd2luCnVzdGVyCmhhbgpmb3JtYXRpb24Kdm9pZAriloHRhNC4CuKWgXVzZWZ1bAriloFFbmdsYW5kCmxvcwpldGltZQpldXIK4paBdW5pcXVlCuKWgdC60LDQugp5aW5nCm9iagp1aWQK4paBd2luZG93cwriloFkaXN0YW5jZQriloFub21icmUK0ZbRjwpvY3VzCmFobgppZXJ0ZQriloFkYXIKU0kKbG9uZwphc3RhCml2ZW4K4paBdG9sZAriloFHcnUKZm9vCuKWgWNhbGxpbmcKaWVtYnJlCuKWgWZ1dHVyZQpwcsOocwpsZWVwCmF2aWdhdGlvbgpQT1NUCuKWgWRlc2NyaWJlZAriloFub2NoCnVuaXQKYWxsZW4K4paBYnJhbmNoCmZhCuKWgWZpbGwK4paBb2JqCuKWgXRyZWUK4paBd3VyZGVuCuKWgUxpdGVyCnJvdApzcGxpdAplbWVpbgptb2R1bGUKQ0EK4paBb3BlcmF0b3IK4paBd3JvdGUK4paBSmFjawpvbG9naWUK4paBQW50CtGC0LXRgApzdHJlYW0K4paBUXVlCmVwc2lsb24Kbm9uCnN0ZWluCuKWgXNpbXBsCnB1YgriloFKdWx5CuKWgW5hdHVyZQriloFEYXRhYmFzZQrDs2wK0L3QuNC8CuKWgVZJCsOqdHJlCmlsZXMK4paBd2VsCicpLAriloFtdXQKbG9jYXRpb24K4paBdGhlcmVmb3JlCmVsbGkK4paB0IYKbsOpCuKWgdCw0LIKbGVkZ2UK4paBY29udmVyCsOtbQriloFYVgp2aWRlcgriloFKYW51YXJ5CuKWgXVzdWFsbHkK4paBcmVsZWFzZWQK4paBTWkKSGVhZAppbGxlcgriloFqYW4K4paBbGV0dGVyCnByb2R1CnJkCuKWgUNhbQosJwriloHQpgriloFwdXNoCnVwZGF0ZQriloFtYXliZQpIdHRwCkAiCtC80LXRgApzZXJ2aWNlCnBhcnNlCuKWgWRhc3MKw6puCikiCm1vcmUKLyoK4paBbWFzCuKWgWxpa2VseQriloFtYXRlcmlhbAriloFbWwriloFsb25nZXIKYmFsCuKWgUFyY2hpdgppZ3QK4paBZWd5CmlkZ2UKaWd1CmNvbmYK4paBaW5jCmNvbnN1bHTDqQriloFtYWkKV29yawriloHQs9GA0LAK4paBT2N0b2JlcgriloFnbG9iYWwK4paBc2VsCuKWgW11bmljaXAK4paBdmlvbAriloFEb2VzCuKWgVxbCtGB0LrQvtC8CuKWgWNvbXBvcwrQsdGA0Y8K0LLRjwriloFyZXNwb25zCuKWgWNvbnNpZGVyZWQK4paBSmFwYW4KcGVzCm9zdG8K4paBbWlsaXQKU1AK0YHRiwphdHRyCmNpbAppcmVjdG9yeQphdmluZwriloFEZWwK4paBcHJldmVudAppZGFkZQpnaXQKaWZvcm0Kb3V0ZXIKaW5jdApsZXZlbAphdGV2ZXIK4paBcmVwZQriloFleGMK0LTQsNGAClN0eWxlCuKWgVRob21hcwplbGluZQriloHQtgp1bnRpbWUK4paBbGFyZwpUcnVlCi4qCmNyZWVuCnlsZXMK4paBdHJhbnNsCuKWgdCh0L4KZW5zaW9ucwrDpGwKaXNzZQriloF2b2x0CmNpYWxseQpuaWsKLl0K4paBU3RhZHQK0LzRiwpmaWxsCmxvdgriloEiLwpTcAriloFBaXIKQ2FsbAriloFudXIKQ2hlY2sKaWVuY2UKZWZpbmVkCuKWgdCy0YDQtQrFgm8KZHoK4paB0L7RgAppa2VyCm93YQrQvtCy0LjRhwpyw6kKT0wK4paBbGluZWFyCuKWgWV4cG9ydAphaHIKaWNpYWwKUmVwCuKWgW5hdHVyYWwK4paBY29wCuKWgX0pCsOnw7Vlcwp6egpXaGF0CuKWgUhvdXNlClJlZgppbmdlcgriloF0YWtpbmcKbsSbCuKWgUVpbnoK4paBZGFtCuKWgWlzc3VlcwpCdWlsZGVyCmVkaXQK4paBcHJ6CnBhc3N3b3JkCkdlbmVyCnJpbQriloFwYXJ0cwotLS0KaWdpbmFsCuKWgVNjaQriloFtb3RoZXIKcmVhCuKWgWNvbnRhaW5lcgrQtNGPCuKWgUlQCuKWgW5vbmUK4paBZm9sbG93ZWQK4paBcGxlCuKWgW1lYXN1cmUK4paBdG91dApFeHQK4paBVFYK4paBZXhwbGFpbgriloFwYXBlcgrRgdGC0ZYKd3MKV2lrCuKWgW1tCuKWgU5vcm0K4paBU2VydmVyCmZvbnQKZWNhdXNlClRSCuKWgdCx0LgKTGEK4paBZW5zCuKWgXJldHIK4paBU2lsCuKWgXNlcXVlbmNlCmFyYwpJVgp6w6EK4paBQW5kcm9pZAriloFTdXBlcgriloFyb3oKb3ZpZQpPbQriloFXZWxsCm1ha2UKb3JwaAriloFKZXIK4paBUm9zCnJlZmVyZW5jZQriloFmZWF0dXJlcwriloFHZXIK4paBTGVnCuKWgWxhdGUK4paBYWRkaXRpb25hbAriloFmbG8K4paB0LXQs9C+CuKWgWFsZ29yaXRobQpCQQprYXIKSVAKXSk7CuKWgWFwcGVhcnMKeXcK4paBdGVtcAriloFhdXNzaQptZXRob2QK4paBcGV0CnN0cmFwCmFybmluZwriloFjdXQK4paBU2EK4paBdHJhY2sK4paBZW1wbG95CuKWgWluZGUKcmF2CuKWgWdlbmVyYXRlCmJlcwphcnRzClN0YXR1cwp1Z2UKYWxpcwriloFvdmVycmlkZQriloFmaQriloFsb3N0Cm90ZWQK4paBcm9vbQriloFjYWxscwriloFjb25zaXN0CtGA0LXQvQriloF2aWxsYWdlCmRpc3QK4paBdGVjaG4KZW56YQriloHRgNC+0LcK4paBQ2F0YWxvZwriloFiZWNvbQpyb3dzCuKWgU5lbApjb21wbGUK4paBcHJlbWkK4paBcm90CuKWgVdlYmxpbmtzCuKWgWZvb3RiYWxsCuKWgWNvbXBhcgriloFsaXZlCtC60LjRhQriloFlcXVpdmFsCmNhcGUK4paBR2VuCm5kZXIK4paBVmlzCuKWgWJlaGluZApnZXJzCnZva2UK4paBbWVkaWEKRVgKdGhhdAriloFzb25vCuKWgW15c3FsCmV2CuKWgXJ1bGUK0LTQvtCyCmFjYwriloFXSEVSRQrQtdC90LUKR3JpZAriloFqdWwK4paBbW9ydAriloFnZW5lcmF0ZWQKZW5jaWEKYWN0ZXIKY2x1ZAriloFzY2VuCuKWgWNsb3NlZAriloFNaWNoYWVsCuKWgW1vdW50CikkLAriloFkcm9wCuKWgWNvbWJpbgp0b2NvbAriloFnb2VzCuKWgWdlYgpNRAriloFBbnRvbgriloEkKCIKVGVtCuKWgWNhCuKWgWluc3RydQplZHMK4paBdG9vbApteXMK4paBcm91dGUKIikpCtC/0YDQtQriloFmbG9hdAriloFzZXJ2aWNlcwriloHRh9C4CtC60ZYKZW1ibHkKYWtlcgriloFTb24K4paBTWF0aAphc3NlCm91c2x5CmxpY2F0aW9ucwriloFydQriloHRidC+CuKWgUNvbnN0CuKWgWltbWVkaQpGTwpvcm8K4paBcHJvZHVjdGlvbgpyZWkK4paBanF1ZXJ5CmFubnQK4paBV2hpbGUK4paBc24K4paB0LPQvtC00LgKRm9ybWF0CuKWgXN0YXIK4paBU2VuCuKWgWtvCk5BTUUK4paBcHLDqXMKY2hhCndoYXQKb21pbgplbmRhbnQKaHkK4paBb2JzZXJ2CuKWgXByZWZlcgrRg9C9CuKWgWNvbnN0cnVjdG9yCmJzCuKWgW1hYwriloFCcmUK4paBSW5zdGl0CuKWgXN0b3J5CuKWgXN5bWJvbAplbGVzCsOfZQphc2luZwriloF3ZXN0CmlhbnMK4paBbWFzdGVyCtC10LcK4paBd2F5cwpibQriloFwaWNrCuKWgWRlcGFydApCYWNrCmVuawpsaXBzZQriloFtYXRoCuKWgUZyYW5jaXMK4paBRGVjZW1iZXIKZnMKcnVtCuKWgWRldmVsb3BtZW50CkxUCmVybmVsCuKWgVRydWUK4paBTW9yZQpyYW5nbGUK4paBY29uZGl0aW9ucwpPcHRpb25zCuKWgWdsaQriloFvcGVyYXRpb24Kw6lrCmFjaHQKaWdodHMK4paBbWlzdAphbmRhCuKWgWVuZXJneQriloHQttC1CuKWgXdvbWVuCmFrdAriloFDSApnZWJyYQriloFtZWV0Cml1CndlbGwKw7ZsCuKWgWdvdmVybm1lbnQK4paBSm9zCmllZwriloFzeW50YXgKZml4CuKWgVBldApqcXVlcnkK4paBY2FyZAriloFwcmluY2lwYWwK4paBZHJ1CuKWgXRlcnJpdAriloHQv9C+0LIK4paBU1MK0YDQuNC4CnRyZXMKYWduZQpseWluZwp0aWxkZQpiZXJuCmVudGVyClBlcgriloFzb21ldApMb2FkCmxpY2UK4paBc291cwriloFMb3VpcwriloFsb2dpYwriloFPdGhlcgriloFjaXIKw6l2CmNocm9uCuKWgWhhbgriloFtYXJnaW4KV2luZG93CsOocmVzCm55Y2gKcHVzaApib2xkcwriloFsYXlvdXQK4paBW2AKQ2hhcgriloFDYXAKYm9sZHN5bWJvbAriloFSb21hbgriloFNYXgKOigK4paBQ29kZQppc2luZwriloFzdGF0ZXMK4paBZXhpc3RpbmcKc3VwcG9ydAriloFyZXNlYXJjaApsaWNhdGUKdmFyaQriloFiaWoK4paBYXBwZQriloFoYXBwZW5zClwiCuKWgWNvbmNlcm4Kd2VzdAriloFzYXlpbmcKcGlkCuKWgXJlY29nbgriloFIZXQKQ2hpbGQK4paBY3MKXCwK4paBY2xlYW4KbGVjdGlvbnMKYWNjZXNzCtCy0YMK0L/RgNC+CmFjaXR5CuKWgU9mZgriloFlYXNpbHkKw6hxdWUK4paBamFrbwriloFpegriloFIYQriloFEZXQK4paBZm9ybWEKc2NoZQpzd2VycwriloFvZmZlcgpxdWlyZWQKVXNlcnMK4paBc3Vic3QKPigK4paBZ3JvdW5kCnVubgpyb2QKc3BlCnVyc29yCuKWgWxlYXZlCmVyawriloF0YWwK4paBYm90dG9tCklPCuKWgXBvcHVsYXIKaWdvCuKWgVRpbWUKdmFsdWVzCuKWgUxvYwriloFDbHViCuKWgWFuY2hlCmlhxYIK0ZbRlwpPbWVnYQriloFsb2NhdGVkClVybAriloFFc3AK0LvRiwrRhtGMCnVsYXRlCuKWgWpvaW4KYXZlcwp2ZXQKbGlvCnJlbW92ZQriloF0b2tlbgriloFvcHRpbQriloFjbGFpbQpvbG9naWNhbAriloFjc3MK4paBYWx0aG91Z2gK4paBcHJpdgriloFCYQrDvGwKZW50aWNhdGlvbgriloF2ZW4KU2VydmVyCuKWgUNvbmcKTkVUCkNPTgpkdApwZXJ0aWVzCuKWgWVwaXMKd2lraXBlZGlhCuKWgWVuZ2luZQriloFmZXIKZ2V0RWxlbWVudAriloFDbGEKxZnDrQriloFyb20KdmFyZXBzaWxvbgriloFwcmltZQppc3RyeQpwZWN0ZWQKb3JhZ2UK4paBdG91Y2gK4paBWycK4paBZGFuCkVtCmFjaW9uZXMKQ2FuCuKWgXdob20K4paBYmVoYXZpb3IK4paBc3RyaW5ncwriloFFdXJvcAriloFSb20KY2lyYwriloFwdW4K4paBcmVnaXN0ZXIKYnVudHUKcmFpbgpPYgpUQQriloFzb21ldGltZXMK4paBbWVudAriloFpbnRlZ2VyCuKWgUphYwpsZWdhdGUKb3RoaW5nCuKWgXNvdW5kCmxhY2VzCuKWgdCR0LAKcmIKZGkK0LvQtdC90LjRjwriloF0aGVtc2VsdmVzCuKWgUJsYWNrCuKWgXNldHRpbmdzCuKWgW5vcm0K4paBcnVucwriloFOT1QKS0UK4paBcGVyaGFwcwriloHQrwriloFtb2wK4paBYW5zCmF0cmUK4paBRGllcwpUb2tlbgphbmllCuKWgWFsbG93ZWQKUmFuZ2UK4paBR3JvCnZpYQp1dG9yaWFsCmVuc29yCmVzdGl2YWwKKTsNCtC60YDQsNGXCuKWgXR1cm5lZApzY29wZQriloFiaWVuCj0kCuKWgWV4dGVuc2lvbgphdG9yZQriloHQoNC+CuKWgXNwZWNpZnkKZWR1CkRhdG9zCuKWgXN0b3JlZAriloFwYXJzZQriloFhbnN3ZXJzCmlsbHMK4paBaGVhcmQKbHUK4paBVEhFCuKWgWfDqW4K4paBZnVsCmV6CuKWgVByZW0KdGhlbgpkcArRgdGM0LrQvtCz0L4K4paBU2kKw6dvCkVkaXQK0LrRltCyCuKWgdCb0LgK4paBU2luZwriloFjYXRlZwpFcXUK4paBZ3VlcgpXaWR0aAriloFDaHJpc3RpYW4Kc3RhdApXcml0ZQriloF3b21hbgp3b29kClZpcwrRgNCw0LcK4paBJCRcCm9kZXIK4paBYm9vbAriloFpbnRlcm5hdGlvbmFsCtC90L7RgdGC0YwK4paBUmljaGFyZAriloFhZGRpdGlvbgriloFNdXNpYwriloFhYmVyCnTDswriloFoaWVyCnVnaAriloFwb2IK4paBdGFibGVzCkRvCuKWgWhpZ2hlcgpwc2kKcsOhCuKWgWFjdGl2ZQriloFUYWJsZQrRmtC1CuKWgWRlc2NyaXB0aW9uCuKWgXNlZW1lZArDrXN0CuKWgW15c2VsZgriloFtZW51CmRlbAriloHFvgplbGUKQXV0CuKWgdCz0YDRgwptdXQKb29uCmFzYwpidWcK4paBbW92ZWQKQ0wK4paBZGF0YXMKU08K0L7Qu9C+CuKWgUdlb3JnCuKWgXJlYWNoCjoiCuKWgWV2YWx1CuKWgUhlbAriloFSaXZlcgriloHQkNGACi8vLy8K4paBc2V0cwriloFPbHltcApBZGFwdGVyCi4nCm92ZXJuCuKWgUxvcmQKIS0tCmpwZwppbWVudG8K4paBUHJvZgriloFhY2hpZXZlCn06CuKWgWluY29yCuKWgW9uZGVyCmVuZ2wKQUJMRQriloFNYXJ5CuKWgXdhcmVuCmxhZ2UKRGVjCtCw0L3Qs9C7CmVuY2lhcwrQu9C10LkK4paBTWFjaGluZQriloHQkNC9CnVkYQriloHFmwriloFYWApvbmx5CtC70LXQvdC40LUK4paBdGFtYmnDqW4KbmVqCuKWgXJlbGF0aXZlCuKWgWhvdXJzCuKWgWluZGVlZAp1bmRvCmluZ3UKYXJlYQriloFDcmVhdGUKYmVpdAriloFyZW1vdmVkCm1hc3RlcgpoYXVzCuKWgUJlcm4K4paBc3BlZWQK4paBQmF5CuKWgUF0dAriloFOb25lCmFwcGxpY2F0aW9uCsO8ZAriloFmaXQK4paBTWFyaWEK4paBbm9yZAriloFzcGxpdAriloFzdHJ1CuKWgW9mZmljaWFsCuKWgWV4ZWN1dGUKb3V2ZQp7ewriloFBcAriloHQutGDCklMCuKWgV4KZGltCuKWgXNldHVwCtGB0LoK4paBc2hhcmUK4paBbWludXRlcwpnbGUKb2NvCnN0ZWxsCuKWgUNvdW4K4paBdGVtcGVyCmtlaXQK0YHRjNC60LjQuQphbwriloFMb25nCigmCtC60LDQvQriloFkZW5zCkJ1dApYWApEQVRFCmdhbgouKS4K4paBZW50cnkKaW5zdGFsbAriloHQt9C90LAK4paBU29tCkNvbW1hbmQKw59lbgriloFzdGFydGluZwriloFzdG8KSUcK4paBbWluaW0K4paBZXhwbGljaXQK4paBYnl0ZXMK4paBcGFydHkKdG9iZXIK4paBR3JhbmQK4paBVm9yCuKWgWxldXIKRG9jdW1lbnQKZXJjCmVuc2l2ZQpDUAplbnYK4paBYXJndW1lbnRzCuKWgUdyYW4KYXJpbHkK4paBbGluCnRuCigtCmdlcQriloFGYW1pbAriloHQkdC+CuKWgXRvdXIK4paBbmF2CuKWgXByb3Blcmx5CuKWgU1ycwriloFNZWwK4paBc2NhbGUKYXN0aWMKZHMK4paBU2lyCuKWgUNodXJjaAp9XntcCnlvdQovLgpTbwriloFicm91Z2h0CuKWgXJvbGUK4paBU3VyCuKWgWZvbmQK4paBZ2VzCsW8ZQpldGVuCuKWgcOpdGFpdApTRVIK4paB0LrQvtGC0L7RgNGLCuKWgWVxdWF0aW9uCmFzcHgK4paBQWZyCuKWgWRpdAplbXB0eQphbGVtZW50CndyYXAK4paBQmV0CuKWgWNvbGxlY3QK4paBZ2l0CuKWgXZpZQriloEuLgrRgNC+0LkK4paBPD8K4paBZWR1YwprbAplbnNpcwriloFPUgriloFIaQriloFDb3VyCtCx0YsKY2VydAriloFHZXMKZXNzb3IKTWFpbgriloHQu9GOCmNhZGUKZG90CmF1Z2gKaGliCuKWgWF1dG9tYXRpY2FsbHkK4paBc3BpcgpwcmVzZW50CuKWgUZlYnJ1YXJ5CuKWgUVsbGUKY3VzdG9tCuKWgXByb2dldAriloFhZG1pbmlzdHIKQUEK4paBYm9ybgriloFDb2xsZWdlCmF0aG9sCmApCmllcnJlCuKWgXJhbgriloFwcm9mZXNzaW9uCm9nZW4KfV97XAriloFhY3Rpdml0eQriloFzY3JvbGwK4paBcHJvdmUKaWJyYXJ5CmVyaWVzClJlYWQKeWVhcgriloFsYW5nCkRldAriloFrbmV3CuKWgXByb3RlY3RlZAriloF3b3IK4paBZWZmaWMK4paBcsOpZwriloF0aGVvcnkK4paBcHVibGlzaGVkCnJlYWwK4paBVG91cgriloFkdXJhbnRlCsOkcwriloFwb3NpdGl2ZQriloFmb3J3YXJkCuKWgVJlbAp7IgpwYXJrCuKWgVVtCuKWgWVlcgplbnRhCuKWgWltYWcK0L3QvtGXCnBpZWwK4paBalF1ZXJ5CmlzbWUKY2huaQpvcmdhbgriloFhcmdzCm9pcgpoZWltCnJpYW4KZWxlc3MKdXNlcwrQtNC40L0KaWNpw7NuCuKWgWluZHVzdAriloF3aXNoCsOhbnkKb2NhCuKWgWFuZ3VsYXIKaWV2ZWQK4paBb2NjdXIKU0VMRUNUCm9uaWEKYWRtaW4K4paBQmVzdAriloHRjdGC0L4K0L7Qs9GA0LAK4paBbG9zcwriloFiYWwK4paB0KDQvtGBCuKWgWNhcmVlcgriloHQv9C1CklYCuKWgWZhbGwK4paBUm9iCuKWgU9QCmVuZWQKZ3JhcGhpY3MK4paBY29taW5nClVwZGF0ZQriloFkaWVkCmVkZW4K4paBYWJzCuKWgWlubmVyCuKWgXRyYXYK0YHRgtC+0Y8KesSFCsOpcAriloFHcm91cAriloFjZWwK4paBc3R1ZmYK4paBc2l0dWF0aW9uCuKWgSR7CmFjbGUK4paBcHVycG9zZQriloFGaXJlCuKWgU9oCuKWgVNlY29uZAriloF1cGxvYWQKb3N0YcWCCtGO0YnQuApBdXRoCuKWgXNob3dpbmcK4paBY29tcGxldGVseQphdmVsCmJkCuKWgXByb2NlZAriloHDlgpjb250cm9sCuKWgXRoYW5rCnVuZHJlZAriloF0b20K4paBZXhhbXBsZXMK4paBcmVtZW1iZXIK4paB0YDQsNCx0L4K4paBcG9zc2liCuKWgWRldGVjdAriloFwb29yCuKWgU9wCuKWgWNlbnR1cnkKdXR0ZXIK4paBbG9naW4KdW5zdApPdXRwdXQK4paBb3RoZXJ3aXNlCmxhbgrRgtGD0YAK4paB0YHQvtCyCuKWgWdyb3VwcwpyaXAK4paBc2hlbGwK4paBZGlzdHJpY3QK4paBcmVjb3JkcwriloFzacOoCmZvcnR1bgplbnR5CuKWgVRyZQriloFjaGFuZ2luZwrRgdC70LXQtAphdWdodAriloFkZWVwCnN1YnNldAphZ3kKZW5kYXIKamF4Ck9NCkVsCmltYXRlCmFyZG8K4paBcGxvdAriloF2aXNpdAriloFidWcK4paB0LLRgdC1CuKWgW9wZW5lZAriloFyZXBsYQriloFIZW5yeQriloFwcApiYXMK4paBZGFyawriloFNYXJ0aW4K4paBcmVzb3VyY2UKaWxpbmcK4paBd2F0Y2gKcmVwbGFjZQriloFyZWxlYXNlCkxvY2F0aW9uCuKWgWxlYXJuaW5nCm1lbnUK4paBYWxsb3dzCtGK0YAKTGVuZ3RoCuKWgXdoYXRldmVyCuKWgXBhZ2VzCuKWgWNvbXBpbGVyCuKWgdGC0LDQutC20LUK4paBUGFuCmNvbW1hbmQK4paBcm9hZAriloF1bmxlc3MKYD8K4paBZGlzY292ZXIK4paB0L7QvQp9XQpib3VyCuKWgUNvdWxkCuKWgXJlZ2V4CuKWgXBzCkNECtC40LcK4paBd2lmZQphbWVudGkK4paBZmFpcgriloFEQgriloFDdXAKZW5lbgphamF4Cm90aMOocXVlCuKWgXNlaW5lcgppY2tlcgrDoW0KZXhjaGFuZ2UKb2xlcwpJRgriloHQlNC+Cm9obgriloFncm93CuKWgVRodXMKc3BlYwriloFoYXR0ZQojLAphbGxlbAriloFyYXRlCuKWgWNlbnRyYWwK4paBVmFuCmlmb3JuClJ1bgriloFzdHVkeQriloFYTUwK4paBQ2hlCuKWgWJlYXV0Cm1pZAriloFhZHZhbmNlClZlcgrRgtGPCuKWgWhhbmRzCuKWgWxheQriloHFoQriloFPUwriloF7fQpQcmUK4paBSGFsbAppbXAK4paBc3VuCuKWgXN0ZXBzCuKWgWp1ZApxdWkK4paBYm9vdAriloElPgriloHQktCwCm5vc3QK4paBbmVtCuKWgXBlbgpPcGVuCuKWgWNodXJjaArQutC+0L0K4paBYXZlcmFnZQriloFjb21tZW50cwriloFjb3JyZXNwb25kaW5nCmxldmFudAriloFiZWQK4paBbWVhbmluZwpWZXJzaW9uCkxpbmsKYmVsCuKWgWV4dHJhY3QKxZvEhwriloFJVgriloFJcgriloFjb21wdXRlcgriloFhZmZlY3QK4paB0KHRgtCwCkFYCnNvcnQK4paBc3BlY2llcwriloFPcGVyCuKWgWhhc2gKY2hlcwriloFFaW56ZWxuCuKWgWtleXMK4paBbWFyem8K4paBaW50ZXJwcmV0Cmhvb2QK4paBY29vcmRpbgrDtnMKcmFnZQpldHoKaXphCtC00LXRgArDvHQKXioK4paBbW9kaWZ5CuKWgXRlcm1pbgriloFjcmVkCnpvbgrQvdGD0Y4K4paBbWllCuKWgScnCuKWgU1vcwriloFjb25uZWN0ZWQKTk8K4paBY29tcGlsZQriloEiXAriloFjYXQKZmlkZGxlCnV0YQpBY2Nlc3MK4paBU3RvCuKWgUJ1cgriloFub3J0aApHYW1tYQriloFhbGxvYwpJbml0CuKWgUxpbmsKaWFsaXplCkltcGwKb3VwZQpyb3ByaQriloFHb2xkCuKWgXNvbG8K4paBRGlzdAosLQpuYXYK4paBYWxlcnQKZXNpcwriloFPcwovLy8K4paBZmViCuKWgS0tPgpmb290CuKWgUZyaWVkCuKWgUVpbnplbG5hY2gK4paBcmV2CnplaXQK4paBU3RhdAriloFTZWcK4paBYmxvCndpY2sKRUwKY2FwdGlvbgpoZWFkZXIK4paBcHJlc2lkZW50CuKWgW11bHRpcAriloFFaW56ZWxuYWNod2Vpc2UK4paBc2VpbmUKP+KAnQpGdW5jdGlvbgriloFTdGFuZAriloFGdW5jdGlvbgriloE/PgriloFCaWxsCuKWgXNwZWN0CuKWgXJlZGlyZWN0CnJ1cHQK4paBd2FsawrQstGI0LgKc3ByaW5nZnJhbWV3b3JrCnBsYWNlCsOpaG8KRW50aXR5CuKWgVNlcnZpY2UKaW50ZQriloF0cmFpbmluZwriloEoYArRhNC+0YAK4paB0LrRgNCwCmF1cgriloFmZXRjaAriloHigKAK4paBbcOqbWUK4paBKCcKYXRpdmVseQriloFleGVjdXQKw6RjaAriloFDYXRhbG9ndWUKYmFzZWQKQXR0cmlidXRlCuKWgXNwcmluZwpwaG9uZQrRgtGA0LAK4paB0L/QuArRgtC10YDQsAriloFgXAriloFPZApPbmUKc2VuZApib24K4paBwrAKTU8K4paBYXNraW5nCuKWgW/DuQriloFpbmfDpXIK4paBdGVzdGluZwriloHRhNCwCuKWgUJvb2sKaW1tCuKWgXByb2dyZXNzCmJybwpGaXJzdAriloFwaG90CuKWgU9OClRlbXBsYXRlCmRldmVsb3Blcgphbm5vdAriloE+PQptaXNzaW9uCuKWgWt0w7MKcGMKYmFjaAp6ZW50CnVlZAriloFvbmVzCtGY0LgK4paBcm91dAriloHQmtC4ClBvc3QK0YbRltGXCuKWgVZpcgpuZWsKYWdpbmcK4paB0L7Qugppem9udAriloFhZ29zdG8K4paBY2hvb3NlCuKWgQ0K4paBc3lzdGVtcwpsb3NzCmllbnRlCuKWgUNyZQriloFjb250cmEKdW1zCuKWgWJlZ2lubmluZwplbXkKaXN0aWNzCuKWgXNlcnZlZApEb3duCm9wdGlvbnMK4paBR292ZXJuCuKWgUJZCuKWgWplc3QKdMOpCuKWgWNvbnRpbnVlCnBlcnMK4paBZWFzaWVyCuKWgWNvcwplc3NvCj4+Ck5ldAriloFCb3IK4paBQ3IK4paBdHJhbnNmZXIK4paBQ1NTCuKWgWZpbm5zCuKWgdGF0L4KdXNlcm5hbWUK4paBY29uc3RydQriloFwYWluCuKWgVRlbQriloFzcGVjaWZpZWQK4paBYnJpdArRgdC60LjQtQppcmsKcmFwcGVyCuKWgWNvdW50ZXIK4paBWyIKb2RlZArQtNCw0L0KcHJvcGVydHkKaGFyZAppc3RyaWN0CikvCuKWgVBvdXIK4paBV2hlcmUK4paBPT09CuKWgXNvd2llCuKWgdCf0YDQvgriloFkZXNzCuKWgXRyYXMK4paB0YPRh9CwCuKWgU92ZXIKbm90ZQriloFBbWVyaWNhCmNwCuKWgWdyYW5kZQpNZQopLQpNb2RlCuKWgXBhc3NpbmcK4paBZ2l2aW5nCkNsCn0vCk1lbnUKISEKYW5ndWxhcgriloFsYXVuY2gKdmFycGhpCuKWgUpvaGFubgriloFmb3JlYWNoCnLDswpzZXF1CmlmaQpBbQphcnAK4paBYnVmZmVyCuKWgW5pCuKWgW1peAriloFNdXNldW0K4paBbWVhbnQKYXNpCuKWgWthbgrQv9GA0LDQsgpDb21wCmlzdG9pcmUKaWZ1bApqZXIKaXNzaW9ucwpSZXNvdXJjZQriloHQstC+0LcK4paBU1QK4paBc29sdXRpb25zCuKWgWJlbG9uZwriloFBc3NvY2kKY2YK4paBTcOkcgriloFncmlkCk11bHQK4paBcmVxdWlyZXMKa2sK4paBdGVhY2gKZW1laW5kZQriloFzcXVhcmUK4paB0LrQvtC80LDQvQriloFFdmVudAriloFydWxlcwriloFidXIK4paBZWluZwriloFNYWkK4paBbmFtCuKWgXNsw6QKaMO2cgriloF0aXAK4paBTGl0ZXJhdHVyCuKWgXNjb3BlCm92ZXJsaW5lCuKWgWV4aXQKKT8KYmV0CuKWgXZpY3QKT2ZmCuKWgWFwcHJveGltCuKWgUdlYgprdG9wCmhlaXQK4paB0K4KdGVtcGxhdGUK0YDQvtC9CuKWgXVubwpTZXJ2CuKWgWZyYW1ld29yawpvcGVyYXRvcgriloFnZW5lcmFsbHkK4paBaHVuZHJlZAriloFkaXZlcnMKb3ZpCuKWgXLDqXMKYWJzCuKWgWdhbArDp2FpcwriloFmZWV0CuKWgXZpcnR1YWwKY3p5CtGB0LrRgwouLwpodQphbmN5CuKWgXJlY29tbWVuZAriloHQv9GW0LQK4paBbW9uZXkK4paBdmVyc2lvbnMK4paBaGVscHMK4paBSG9yCkl0ZW1zCmxvb2sKY29ubmVjdAphbmdlcwpWaWV3Q29udHJvbGxlcgplbGlqawriloFvY2N1cAriloFlZGl0b3IKYXV0bwrDtmcK4paBc2Vjb25kcwriloFvYnZpb3VzCnZtCmFrZXMK4paBZ2VnZW4K4paBdGlsCmplY3Rpb24K0LvQtdC90L3RjwriloFvcGVyYXRpb25zCuKWgUVhc3QKb2d5CuKWgVBvbGl0CnV0ZW4K4paBSm9zZXBoCiJgCuKWgUNvbXBhbnkK4paBY2FsbGJhY2sK4paBc2VuCmNjacOzbgriloFhc3NvY2lhdGVkCuKWgWNvbnRhaW5pbmcK4paBcHJhY3RpY2UKZWxpamtlCm9rZQrDqXJhCnVucwphbnRhCnZleQp6dQriloFCZXMK4paBRmxvcgptZW0KeWN6CuKWgWFyY2hpdGVjdAriloFhbm5pCuKWgWNvbnRhY3QKWVBFCuKWgUNhcwriloHQv9C+0LvRgwpvdm8K4paBYnJpbmcK4paBY29uY2VwdAriloFqcwriloFSZWZlcmVuY2lhcwplbWJsZQriloHQvQriloFzdXBwb3J0ZWQKQmlnCuKWgUhhbnMKZXJ2CuKWgU1hagriloFhcnJpdgriloFIYXZlCuKWgXByb2JhYmlsaXR5CuKWgVBvcAriloFQYXNzCnRva2VuClByb3ZpZGVyCuKWgVJhClJlYWRlcgpvb3RoCmxhcAriloFhc3Npc3QKYWRvdwriloF0ZXN0cwrRgdGB0LgK4paBa2luZwpsYW5nbGUK4paBU3VtCk9JTgriloFzZWN1cml0eQpuaXMKLi4vCuKWgWJhc2ljCnVuaXR5CmA6CuKWgdC60L7RgtC+CmtvdwriloFCaWJsaW90aMOocXVlCmFzaW9uCmFsbwppZmVzdAriloFub3ZlbWJyZQriloFwZXUK4paB0JYKZW5zY2hhZnQKY2x1cwrRmNGDCkhlaWdodArDum4K4paBdHVyCuKWgWlkZWFzCuKWgWNlcwpmcmFrCuKWgXByZW1pZXIKaXRhdGlvbgriloFzw6kKSFRNTAriloFSb3lhbArRgdGM0LrQvtGXCuKWgWJ5dGUKUFMK4paBc2VndQppbmVuCuKWgUdyZWF0CuKWgdCa0YMK4paBZXh0ZXJuYWwKVGl0bGUKVG9wClByb2Nlc3MKaXTDpHQK4paBYC8K4paBc2VjcmV0CnBvc2l0b3J5CuKWgXBvdGVudGlhbAriloFCdWQKbmFtZXMKYXNvbnMKc3RhY2tleGNoYW5nZQpiYWNrZ3JvdW5kCtC/0LXRgArRgdC+0LIKYWZ0ZXIK4paBcGVybwriloFzb2Z0d2FyZQriloFzZWQK4paBYXJyYXlzCnRtcAriloFhc3AKc2NhbGUK4paBTGF0CmFuYWwK4paBZ2VtClBVCuKWgUFsdHJpClRoYXQK4paB0J3QuAppZmFjdApBZGRyZXNzCuKWgXNvdXRoCuKWgWZvcm11bGEK4paBQ29sbGVnCuKWgdGW0L0Ka3Rpb24K4paBc2FjClNICmFqbwpldGMKdmMKYF0oCuKWgUR1cgriloHQnNC1CuKWgVNtaXRoCml0ZW1zCkNLCmVsbwriloFwbHVnaW4K4paBc2VyaWUKaWVubmUK4paB0LjQu9C4Ck1hcgriloFJbWFnZQpnb3QKYW5kYXMK4paBbWF0Y2hlcwriloF3b3J0aAriloFEZWIK4paBY2FjaGUK4paBZmVsdAplcnNjaAppemVzCk9wZXIK4paBSmFocmUK4paBY29tbXVuZQp0aHJlYWQK4paBbnkKZGVjCm91dwriloFzdXJmYWNlCuKWgVBvcgriloFTdHJlZXQK0L/RgNC4CuKWgWNhbmRpZAriloFSZXR1cm4K4paBS29tCmdydQriloHRgtC4CltcCuKWgWRlcGVuZHMK4paBaW5mbHUK4paBdG93YXJkcwphaW5lZAriloFyYW5rCuKWgUphbnVhcgriloFjb21wb25lbnRzCmdlc3QKZ2V0RWxlbWVudEJ5SWQK4paBY2hlY2tlZAphaXJzCmpvaW4K4paBZGVhZAriloFoaXQKw6lueQriloFlcXVpdmFsZW50CuKWgdCf0YDQtQriloFhcHByb3ByaQpQYXNzCuKWgXByaW1lcgplbmdsaXNjaAriloFhcHBhcgriloFEdXJpbmcK4paBa25vd2xlZGdlCuKWgXRyaWdnZXIK4paBY29yZQriloFPbAriloFQcm9kdQriloFGZXJuCuKWgdC90LDRh9CwClRlCuKWgU1vdAplcnZlCtGC0LLQvgriloFtaWQK4paBZmluYWxseQphaXJlcwriloFlc3BlY2lhbGx5CuKWgXR1dAriloFyZWNlaXZlCmFkcmUK4paBbmVpZ2gKa3RldAppbGRlCuKWgXJhZGlvCuKWgWRyaXZlcgrQu9C40YHRjAplbmRlbmNpZXMK4paBSUUK4paBc2F2ZWQKZmZlY3QK4paBV2F5YmFjawppYXQK4paBcGFkZGluZwp3aW5kb3cK0YLQuNGH0LUK4paBbXVyCmFjdG9yCuKWgUhhbgrQvtC90LDQu9GMCuKWgWdhcgriloFmYW1pbGplbgrDs3MK4paBbmF0aW9uYWxlCuKWgXByw6kKZGVkCm9uYWwK4paBUHJlc2lkZW50CuKWgVwsCuKWgXBsYWNlZAplcm5pCuKWgXNpZ25hbApuYWIKaG0KTW9uCuKWgXZzClNDCuKWgXByb2dldHRpCuKWgcOcCuKWgWZvcm1zCuKWgW1lc3NhZ2VzCmluZgp1c2VycwpHRVQK4paBZGVscwpDb2xsZWN0aW9uCuKWgUdvb2QK4paBTWF5YmUK4paBY29tcHIK4paBbGFyZ2VyCmdyZXMKYXBlcgriloHQn9GA0LgKdW5kZXMK4paBc2VhCuKWgVNwcmluZwp1bG8K4paBbWVjaGFuCuKWgXNhbnMKR0IKVmFsaWQK4paBY29tbXVuaWMK4paBcHJhCnZpZXIK4paB0KHQtQriloFhaW4K0YLRg9GA0LAKa29tCnNraWVnbwrQutC+0LLQvgphZGF0YQriloHQoNC1CuKWgWJvb2xlYW4Kc2V0cwriloFlZmZvcnQKLlsK4paBem9zdGHFggpQQQriloFWaWN0ClNECm93YcWCCuKWgWVtYgriloFwcmltYQriloFob3VyCnN1YnNlY3Rpb24K4paBRm9ydAptYXRoZnJhawppZ2luCkdMCikrCmZpCuKWgWFuY2kK4paBcGFuClwpCuKWgWx1ZwriloFkZXBsb3kKZG9tYWluCuKWgXNsaWdodApKU09OCuKWgW1vcm5pbmcK4paBaGkK4paBY29tcGFyZQppamUK4paBYmx1ZQriloFBYwriloFtaWRkbGUKYW5kZW4K4paBc2hhcmVkCuKWgUNhbXAK4paBw4EKb3VuZGVkCnV3CmllcnVuZwpTdGFjawriloFlaW5lcwriloFEYQpsaWoKZW50aQriloHQuQpVdGlsCuKWgWV4cGVyaWVuY2UK4paBYXdhaXQKdWxzCuKWgXJlcXVlc3RzCuKWgWltcG9zCuKWgWNvbnN0cmFpbnQKQ2hhbmdlCmVtcGgK0LHQtdGACuKWgUFub3RoZXIKQ3VzdG9tCuKWgXNpZ25pZmljYW50CmNyCuKWgW1pbGxpb24KcmVlawriloFkYWxsYQriloFHZXJtCm90YWwKYXRldXIKYnRuCuKWgXRoaW5raW5nCuKWgWludGVydmFsCm9ubmUK4paBbGl2CigpOgriloHQktC1Cm9lCuKWgUV2Cm1ldGEK4paBYnJvYWQKUmVtCmFwcGx5CuKWgWNvdXBsZQriloF0ZWNobmkKaWRhZGVzCuKWgWdvYWwK4paBQ0QKaGFiCuKWgWV4cGxhbgphbm5lcgriloFCZWNhdXNlCmJsb2cKaW5jbHVkZWdyYXBoaWNzCuKWgXZvaWNlCuKWgU1hcAp2ZW50aW9uClNlc3Npb24K4paBTGllbnMK4paBc29yCmNhdGVnb3J5CmFzaGluZ3RvbgriloFNw6Ryegpwb3AKaWxsZXQK4paBendlaQriloFMaWUKTnVsbAphZGRyZXNzCuKWgWZhY3RvcgriloFsaWduZQriloFIVFRQCuKWgXN1ZgriloFwZXJzb25hbApjaXAK4paBRGFyCuKWgWFkbQrQutC+0LkK4paBRXh0CuKWgWdvZAphYQpSaWdodArDqXTDqQriloFkeW5hbWljCuKWgW1haW50YWluCnRvcgojIyMjIyMjIwriloFGcmEK4paBY2hvaWNlCuKWgdGB0YLQvgrQodCgCuKWgUZlZGVyCnN0b24K4paBZmxhZwpraXQKTW9kdWxlCuKWgdGB0L/QvgriloFTdHJhCmlja3MK4paBaGF2ZW4K4paBTWFzcwriloFFbXAK4paBUGkK4paBUGVuClJlY3QK4paBS3IKaXRhdAplbGVyCtGP0LHRgNGPCml0ZXQK4paBU3RhcnQK4paBcHJvZHVjZWQK4paB0L/QvtC7CihfCuKWgWRlbGV0CuKWgWhvdAriloFHZXNjaGljaHRlCn5+CuKWgW1vbnRocwriloF0b2QK4paB0L3QuArDunMKdGVtcAriloFEZXoKeXBlcwriloFjdWkKb21tdW4KYWN0aW9ucwriloFlaWdlbgriloFpbW1lZGlhdGVseQpQTAriloHQk9C+CuKWgUJhbArRmdC1CnVsdWkK4paBb25saW5lCuKWgWHDsW9zCuKWgW5hbWVzcGFjZQriloFtb25kCuKWgUJhc2UK4paBQ2FuYWRhCmV0enQKfS0K4paBZGVmaW4K4paBZG91YnQK4paBaW52ZXN0aWcKdmlld3MK4paBTGluZQriloFzdGFnZQpldHRpbmdzCnVicmUKZmxvYXQK4paBUGxheQriloFMYXMKcHRyCuKWgWJlY29tZXMKZXN0YW1wCuKWgWluZGVwZW5kZW50CuKWgWFuYWx5c2lzCuKWgUxvb2sKbGFpbgriloHRgNCw0YEKUmVmZXJlbmNlCuKWgXNvcnJ5CuKWgXN1cHBvc2VkCsO7dAriloFkZWdyZWUKdXR6Ck1NCuKWgWRlc2lyZWQKxYJ5CuKWgWxlbgriloFhbG9uZQpzaWduZWQK4paBU3RhClBlcnNvbgriloFhcHBsaWVkCuKWgUJhY2sK4paBbWFycwpQYXJ0CuKWgURpZAriloFleHRlcm5lcwriloFucApvbmdvCuKWgWVzdGEKQmxvY2sK4paBcG91CmFkb3JlcwriloFTdHVkaW8KLiQK4paBcmVhY2hlZApib3QK4paBSnVuaQp0b25zCml0ZWwK4paBR2FyCuKWgWFydGljbGVzCuKWgURpc3RyaWN0CuKWgXRyb3VibGUKbGlkZQriloFGb3VuZArDoWQK4paBZXF1aXAK4paBaW50ZXJuYWwKJ10sCuKWgWFzeW5jClVCCmdlbAriloFhaQplbnN1cmUK4paBYXBwZWFyZWQK4paBJF8K4paBbWF4aW11bQriloHQodC4CtGA0YwK4paBYW5ub3VuCtC70LDRgdGMCuKWgWNtCtCz0LDQvQphdXB0CuKWgWxhdHRlcgriloFwbGF0Zm9ybQriloFkcmEK4paBY2FwaXRhbAriloFzb2x2ZWQKcml6CmVkaWMK4paBTXVyCuKWgVRvcArRgtGB0Y8KUGFuZWwKcnVsZQpldGljCuKWgVJlbgriloFXaWtpbWVkaWEK4paBVE8Kc2Vjb25kCmlzbAriloFoeQriloFuaWV0CuKWgWxvYWRlZApkaWcK4paBbWF5bwpbOgpBY2MK4paBYmVrCtC90LjRjgpsb2dpbgp0eAriloFGdXIK4paBU2FudGEKYXp6CuKWgWNvbmR1Y3QK4paBSW5kaWEKT3JkZXIKaXJ0aAp0dwp9KwriloF3aWVkZXIK4paBRWR1CkFWCuKWgWBgYAriloFtYW51YWxseQriloFSZWFkCmZvcnR1bmF0ZWx5CuKWgVJ1bgriloFBd2FyZAriloFGb290CiopCnBhcmFtcwrQv9GWCuKWgW5hdGl2ZQpyaWZ0CuKWgcOkCkFUSAriloF5b3Vyc2VsZgriloFwcmlvcgriloFjaXQKw6RoCuKWgXRyZWF0CuKWgW1lYXMKcmlidXRlZAriloFjbGFyCmNhcmQKUk9SCmlsbGVzCuKWgWxheWVyCmF1ZXIK4paBcmF0CmJlcm5hdGUK4paBc3RhdG8K4paBQ2hpbmEK4paBJCgnIwriloFuYWFyCnppcAriloEke1wK4paBYXBwcmVjaWF0ZWQK4paB0LjQvNC1CsW8eQriloFwcnplegriloFJbmRpYW4K4paBVG9kCuKWgVNvdXJjZQriloHQtNGA0YPQs9C4CmludGVybmFsCmlvbmFsZQpQcm9kdWN0CuKWgU1lbgriloF1cHBlcgriloFFdmVyeQp9LFwK4paBcHJpbnRmCuKWgWNvbnRpbnVlZAriloFub2RlcwrQu9C60LgK4paBbmljZQptb2R1bGVzCmVpZ24K4paBTWV4CuKWgUFjY29yZGluZwriloF1bmRlZmluZWQK4paBYmluYXJ5CmN1dApDdXJyZW50CmVkeQp9fXsKYmxlcwriloHQstC+0LkKc2NyaQplcW4KQ2hhbmdlZAriloFrw7Z6CuKWgXJlbW90ZQrQstC70Y8K4paBcXVlbAriloFhbGlnbgriloHQv9Cw0YAKU1YKeWVyCuKWgUNhbGlmb3JuCuKWgXBsYWNlcwriloFwcmltYXJ5CuKWgWNvbnYK4paBSnVsaQriloF2aXN1YWwK4paBU2VsZWN0CmF0b3J5Cj0oCmlzZXIK4paBaW50ZW50CnN1cgpjb250YWluZXIKaWNlZAriloFib2FyZAphc3RyCm9taWFsCtCy0LXRggrQt9Cy0LAK4paBY3J1CuKWgU9rdG9iZXIKc2F2ZQriloFncmVhdGVyCuKWgWlubgriloFwaWN0dXJlCuKWgdCi0L4K4paBb2J0YWluZWQKV2lraW1lZGlhCsO6YmxpYwriloFsb3JzCuKWgW1vbnQKb2JyZQriloFjaXZpbAriloFjb25zdHJ1Y3Rpb24K4paBV2VsdAriloFVbmRlcgp1bmRlcnQK4paBZWRnZQriloFMaXN0ZQpjc3YK4paBZXhwZXJpbWVudApsb2NhbGhvc3QK4paBRWRpdApncmVnCm92w6EK0ZnQsAptc2cK4paBR3JlZW4KRGlhbG9nCklkZW50CuKWgUpTCl57KAriloFzbMOka3RldApfX19fClByb2plY3QK4paBYmVza3JlCuKWgWJlcgriloF3b3VsZG4K4paBcmVhY3QKSGVsCnp3CuKWgVdhc2hpbmd0b24Kb3JpZQp0YXNrCuKWgWNhdGVnb3J5CuKWgWFydGlzdAphbm5vCuKWgW9vawphbW1lbgriloFNaW5pc3RlcgriloFkZWNsYXIK4paBS2V5CiwuCuKWgW1hY2gK4paBd3cKaXNlbgpGcmFuCuKWgdCg0L7RgdGB0LgK0LHQvtGACtGC0YDQuAriloFyb2NrCnF1aXMKbW9zCtC/0LXRgNCwCuKWgWVzdGVybmkK4paBZ29sZApXaW5kb3dzCiUlCuKWgXBhcnRpYWwK4paBd2VpZ2h0CuKWgXNwcgp9KS4K4paBZnJhbsOnYWlzCmZ1bgriloF0aG91cwpob2xkZXIK4paBZ29uZQriloHEjAriloFyZW5kCkRBCuKWgWFuc3dlcmVkCuKWgUZhbHNlCkJ1ZmZlcgriloFkYXVnaAouLS0K4paBU2hvdwriloFyZWN0CuKWgUtyZQpkcgpvc29waAriloF5aWVsZAp1cml0eQp0b1N0cmluZwphdmFsClBvbAriloFsb2NrCmltYXRpb24KYW50aWMKTG9jYWwK4paBYmVza3JldnMKaXTDqXMKZ3JpZArRg9GCCuKWgV97CtGB0ZYKRklMRQriloHQutC8CuKWgXNwZWFrCnN1bW1hcnkKcHJvcApqYXZhc2NyaXB0CnprCml6b250YWwK4paBdHJvaXMK4paBUm9kCnByaXNlCtGA0L7QstC+CuKWgW9kZAriloFnZXN0CuKWgXByb2R1Y2UK4paBd2FhcgriloFBdgpyaWJ1CtCy0LDQvdC90Y8K4paBZmluaXNoZWQK4paBYWRhcHQK4paBU2FyCnRleHRpdAriloFDZQriloFGYQpvc2VuCuKWgWRlcml2CuKWgXNoaXAK4paBb3BpbgriloFFdmVuCmdlc2NoCuKWgXN1cHBvc2UK4paBRmVyCtGB0LrQvtC1CuKWgXdvcmRlbgpzZXkKaGxpbmUK4paBVW5pb24K4paBLyoqCuKWgXZlegriloFDb2xsZWdhbWVudGkK4paBU29jaWV0eQriloFlY29ub20KxaHDrQpvaQriloFvcmllbnQK4paBVGVpbApyZW50CtC70LXQutGBCuKWgXNvbGlkCuKWgWNhcnQKKioqKioqKioqKioqKioqKgriloFjYWIK4paBTWVzc2FnZQpkb3RzCuKWgcOpZwriloF0d2UKYWdhCuKWgW5hegriloFNaWNyb3NvZnQK4paBdW5kZXJhcnRlcgpwcGVuCuKWgXJlY2VudAriloFuZXQK4paBcmVzb3VyY2VzClN0ZQouXAriloFTTwrQu9C+0LwK4paBY2VsZQriloFsaWMK4paBYmVuZWYKbGRvdHMK4paBc2VyaWFsCkludGVnZXIKY2xlcwriloFtaWxlcwriloFBbGUK4paBZW50ZXJlZAriloFUd28Kd2llCuKWgWluY2x1ZGVzCuKWgUVhY2gKZWxsaW5nCnF1ZXIK4paBRG9tCnBmCldTCuKWgXN0cmFpZ2h0CuKWgVN0YW4K4paBbm9zCsOtY3VsCmF0cm8K4paBQ2VudGVyCkZUCuKWgUluZ2EKaWxvCuKWgXd3dwpqc2ZpZGRsZQpuaWMK4paBRXVyb3BlYW4K4paBY29tbWVyCuKWgWdpcmwKdG90YWwK4paBU3RhcgriloFzdWdnZXN0ZWQKcGFsCuKWgXp3aXNjaGVuCtC/0LjRgdCwCklNCuKWgWhhbmRsZXIK4paBUHJvZ3JhbQp4c2wKw6FseQpCVQosLS0K4paBdmlkCuKWgWVzdGFibGlzaGVkCuKWgVNwaWVsCm9tZXRyeQp1bmVzCuKWgXNpdAriloFpbmhlcgriloFwdWlzCuKWgcOqdHJlCuKWgU1vc3QKSGVhZGVyCmluc2VydAriloFzaXN0CuKWgWZhdm9yCmRlc3QK4paBZW50aXR5CkNhbAriloFUaGVyZWZvcmUKREQKOzsK4paBRGV6ZW1iZXIK4paBUmgKaW1lbnRzCuKWgXJldHVybmluZwpzdG8K4paBVmFsdWUK4paBbGliZXIK4paBUmVzdWx0CuKWgWJpbmQKdm9pcgriloFUaW0K4paBTW92aWUKd2VnCmtldAriloHQuNGB0YLQvgriloFmcmllbmRzCuKWgWZuCuKWgcOpbAriloEmPQphcmRlbgpmZmljaWFsCuKWgWNvbW11bml0eQriloFhcGkKQXJncwppZXJlbgriloFkYW5uCm9tb3JwaAphZHIKbG9vcAp1bWFuCuKWgXZvdXMKYnN0CnN1Ym1pdApcfArRgtC40L0KQ29udGFpbmVyCmFza2V0Cj8pClNlYwriloFkcml2ZQpBc3MK4paBc3dlCuKWgWFtZXIK4paBbWluZQriloFIYW0K4paBYXZhaXQK4paBSG9uCuKWgWFwcsOocwriloFNYW5uCtGB0YzQutCwCuKWgWluY3JlYXNlCuKWgXR5CnNreQriloFhY2N1cgphcnRpY2xlCndlaWdodAriloFzZXgK4paBbGlzdGFkZQovKioK4paBZXN0w6EKfX0kCmFyZ28KZGVmaW5lCuKWgdGB0L7RgdGC0LDQsgpzZXNzaW9uCmFkcwrRgdGC0LLQuAriloFMYXcK4paBZGlhbG9nCuKWgWR1cGxpY2F0ZQriloHDqXAK4paBdm9jCmZyaQriloFncmVlbgriloFoaWRkZW4K4paBSXNsYW5kCuKWgWRpYWcKb3dlagpteXNxbAp0ZWlsCnLDpAppa2FuCuKWgUpvc8OpCmFsZWQKUnVudGltZQriloF0cmFpbgriloFEaXZpc2lvbgrQvdC40YYK4paBU3BhbgrQvdC40LzQsAopPVwK0YLQsNC9CuKWgXN0YXkK4paBZm9vCuKWgWFjY29tCuKWgWhlcnMK4paB0L3QsNGDCuKWgU3DvG4KaWRlb3MKc3RhdGljCuKWgXJlYWR5Cl1gCuKWgXZpc2libGUK4paBSG9wZQp1bGF0ZWQK4paBQ3VsdArRgdGC0YDQvgpDbwriloFzbWFsbGVyCmF0dXJhCuKWgXBlcmZlY3RseQpyZXEK4paBcHJvcG9zZWQK4paBZGVnbGkKU2VhcmNoCuKWgWljaApNYXgK4paBdm9sdW1lCmV4ZWN1dGUKZ3JlCuKWgXNwb3J0CnVkYWQKUFQK4paBUmVjb3JkcwriloFjb29rCuKWgWV4cGFuZArQsdGWCuKWgWFsdHJpCnBwZXQKYXJzZQriloF3ZXQK4paBQm9iCuKWgUZDCuKWgUFzc29jaWF0aW9uCnVqZQriloFmZWwK4paB0YHQu9GDCuKWgUJpZwovXApHZQp3aGlsZQp7KAriloFzdWZmaWNpZW50ClBvc2l0aW9uCuKWgXVuZGVyc3RhbmRpbmcK4paBbnVlCuKWgXJhegriloF5ZQpoZW0KTnVtCuKWgVByb2plY3QK4paBSXRzCuKWgWhhc3RhCmVuc28K4paBd2lyZQpSZXQKdWoKcHJvb2YK4paBcmVsZXZhbnQK4paBcGFydGlyCuKWgWFnbwppZmljYXRlCuKWgWRvbWluCuKWgWJveQriloFwbGFudAriloFlbmNvZGluZwriloF0aHJvd3MK4paBUm9jawp6b25lCmdhbmcKd2lkZ2V0CuKWgWludGVyZXN0aW5nCkRFUgriloFkZW1vbgriloFvZmZpY2UKYW10CsOkdGVyCuKWgVdoaXRlCuKWgXZlcnNjaAriloFkaWVzZXIK4paBTW91bnQK4paBc3R1ZGVudHMK4paBUHViCuKWgdCU0LUKaWphCuKWgUN5CuKWgUNhbGlmb3JuaWEK4paBYWJyaWwKw6RsbAriloHRh9C10LwKVFYK4paBbcOpcwriloFkZWNsYXJlZAriloHRjgrFkWwKYXBwYQriloHQkdC1CmVjaG8KbnVtZXIK4paBcG9zdGVkCuKWgdCy0LXRgAriloHQs9C+0LTQuNC90LUK4paBd2VhawriloFSZXB1YmxpYwriloFjaGFtcGlvbgplbnN1cmVtYXRoCnlvdXIK4paBT2JlcgriloFDZW50cmFsCmlzYQrQsNC90LQKeXkK4paBZnVsbHkK4paBU0QK4paBTGludXgK4paBU2NvdHQKcGFydG1lbnQKa29uCuKWgWNvbnRyYWN0CuKWgU9GCuKWgWFsZQriloFBbm4K4paB0L3QsNC0CmxhaAriloFOZXh0Cm9yZW4K4paBZGlzawriloFlZwphdHUK0LvQvtCz0LgK4paBZ2FtZXMKTGVmdAriloFsdQriloFmaW5pdGUK4paB0LrQuAriloFjcmFzaApwaGVyCmV4ZQpBVElPTgriloFicm90aGVyCkVuZwp0YXQK4paBSW50ZWdlcgrQvdC+0LzRgwriloFjb2xvbgppcXUKKSkuCml2aQriloFNZXRob2QKYXJ0ZW4KVW5pCnZlY3RvcgriloF3b29kCtGA0YIK4paB0JvQtQriloFzacOoY2xlCuKWgWdlbnQKfQ0K4paBY29udGVudHMK4paBY29tcGFuCkdvCuKWgWpvdQp1ZW50CkFzeW5jCnByaW50ZgriloFNb2RlbAriloFrZXB0CkFTRQriloFwcm92aWRlcwriloFBYmdlcnVmZW4K4paBR2FsbAriloFBbGYKU0EK4paBTWVtCuKWgWt0ZXIK4paBQnJ1CkFuZHJvaWQKKDoK4paB0KPQutGA0LDRlwpOZQpNaW4KYXRyCuKWgUhhbApkZWxldGUKb2RvCuKWgW7Do28Kw6huZQriloFjYWxjdWxhdGUKSnNvbgprZXlzCtC90LXQuQriloFoZW5jZQriloFvdwriloFMaWIKZW5vCuKWgUxvdmUKb3NpCndpZGUK4paBc2NvcmUKZnVsbArQstC+0LQK4paBZGV0ZXJtaW5lCuKWgXNwYWNlcwrQu9C+0LLQsAriloFwZXV0CsOpcmFsCsOzxYIK4paBYXBwb2ludAriloFUdwo8PwriloFPcmRlcgriloFob3AKcmFuZG9tCmNhY2hlCuKWgWRlc3Ryb3kK4paBcmFjZQpUYWcK4paBcmlkCuKWgW5lZ2F0aXZlCkNhcgplbnNpb25hbApkawriloFjcm8K4paBVEhFTgriloEkLgplbnNrCk5FCkhPCuKWgWtsZQpvc3BpdGFsCmt0ZQpmw6lyZW5jZXMKdWRlcwpJUgpvdGlvbgriloFSZWFsCuKWgUZlYnJ1YXIK0LjQvQriloFPbGQK0LrQvtCz0L4KbGVpY2gK4paB0YAKw61hbgriloHQs9CwCmNpZGUKbGFiCuKWgXB1bGwK4paBJy8KTG9uZwosJAriloFhcHByb3ByaWF0ZQriloHQsdGL0LvQsApmw7xocgriloFNZWRpYQriloFtYW5uZXIK4paB0JPQtQpkZXNjcmlwdGlvbgpCZWFuCuKWgUxhcgonXTsK4paBcmVsYXRpb24K4paBU29ycnkKaGFyCmNwcAriloFLbwriloFleGVjdXRpb24KaW5vcwriloFidWwKZ3JhZGUK4paBTXUK4paBcGlsCndyaXQKaWZpY2F0aW9ucwppbmVzZQriloFQaGlsaQpkeAriloFsZWFkaW5nCuKWgUpvdXJuYWwKb3ZlZAriloFjb250cm8K0L3QvtCy0LAKWWVzCuKWgWNoYW5uZWwKKSksCmlzdGVuCmFrYQpUb1N0cmluZwptYXMK4paBZXR0CuKWgWZvcmNlcwp1bGF0aW9ucwriloFDYWxsCuKWgWV4cGxhbmF0aW9uCm9yaW5nCkFUQQpjaHRlcgp3aGVuClZDCuKWgUphaHJoCkNhc2UK4paBY29tbWFuZHMK4paBcmljaApidXMKRmUKbWJveAriloFyZWNvbgrDsW8K4paBc2hhcGUKb3d5CmVudHJ5Cml0YWJsZQriloFlbGVjdGlvbgrRlNGC0YzRgdGPCuKWgXByZXAKdsOhCuKWgWluZmluCmxvdAriloFib29rcwriloFVU0EK0LvQuNC9CuKWgXBvbQriloFuYXMK4paBdGFncwriloFleGVjdXRlZAphaWxsZQpsdW5nCuKWgUphdmFTY3JpcHQK4paBYmFsbAriloFhaW5zaQriloFQcmkKeyQK4paBVU4K4paBUmFtCuKWgWhlYXIK4paBVWJ1bnR1Cj4oKTsK4paBcHVyZQriloFlbWJlZAphw6fDo28KY29udHJvbGxlcgriloFtYXJyaWVkCuKWgUZvbApmYW1pbAriloFwcmVjCuKWgXJlY3VycwpwYWQKaXN0cmF0aW9uCuKWgXJlc3BlY3RpdmVseQpbJAphdXRvcgriloFncmF2CmllcmEKYXppb25pCuKWgUJ1bAriloFBdXN0cmFsaWEKbW9uZAriloFUcm8K4paBRWxlCnBhY2thZ2VzCm1zZG4K4paBQWxzCuKWgXByenkKQVJUCuKWgWNoYXJnZQriloFhcHBsaWNhdGlvbnMKVW5pdAphcmVuCuKWgXN1ZGRlbgpvbWV0ZXIK4paBZG90CmFjamkK0LrRgtC+0YAKaW1pbgplbmluZwriloFkb25kZQriloFIbwp0cmVlCm1iCuKWgWRyYWcKYWplCuKWgWludmFsaWQK4paBZmluaXNoCmxhaW0K4paBZmVlZAriloFOYXAKcm9vbQppbWFnZXMK4paB0YHQsNC5CuKWgXN1Y2MKaWZmZXIK4paBYcOxbwriloFjdWFsCtC80LXRgNC4CkRSCuKWgUJpbGRlcgrQsdGA0LAKcmFpdApwYW4K0LXQvdGMCuKWgWRpc3RpbmN0CuKWgUtuCsO2bmlnCmFuY2VkCuKWgWxvYWRpbmcK4paBVGVjaG4K4paBU2VsCm11cwriloFyYWlsCuKWgXN0dWRlbnQK4paBbm90aWNlCuKWgXNsYQriloHQlNCwCuKWgWd1YXJkCuKWgURheQrQstCw0LvQuApPcHRpb24KYWlzb24KaXBwCuKWgUp1bgriloFmZWxsCuKWgWFic29sdXRlCtC+0LLQtQpkZWJ1ZwriloFTdWQK0L/Riwp1Z2lucwriloF2aWV3cwpsYXkK4paBc3VycgriloFzdG9vZAriloHQstGWCnNlbGVjdGVkCtCz0ZYK4paBYXR0cmlidXRlcwpmaW5hbAplbmRhCuKWgUJvbgpuZXJzCuKWgVdlcgpidXIKaXR0ZWwK4paBbW92aW5nCuKWgVBsYW4KaXNjaGVzCkphdmEK4paBYmFzaXMK4paBQnVzCuKWgUF1CuKWgUlsbAriloHQstGA0LXQvNGPCuKWgdGG0LXQvdGCCmhhbmRsZQrRgdGC0YPQvwriloFGYXIK4paBb3JhegpvY3IK4paBc2VpdApvbmRlcgrQtNC+0LwKOi8KY2hvcgriloFUb3duCuKWgWRlZmluaXQKcmVhY3QK4paBcGllY2UK4paBS2FybApDSQriloFBcHBsaWNhdGlvbgp1bnRlcgriloFmb3JtZWQK4paB0L/RgwpCbwriloFEYW5pZWwK4paB0L/Qu9CwCkJvZHkKfSkkCuKWgdCx0YvQu9C4CuKWgWVhcnRoCtCz0LvQsApUaGVyZQriloHRgdGC0YDQsAriloF2aWxsZQriloFjZW50cmUKKQ0K4paBaGVscGZ1bAriloErKwriloFDRwppemlvbmUK4paBR2FtZQriloFXaGljaAriloFwaXAK4paBUG9ydHVnCkRTCuKWgWRlc2NyaWJlCuKWgWNoZWNraW5nCuKWgW1hbmFnZXIKQk8K4paBQnVuZGVzCmJ1Y2gK4paBZGVjaWRlZAriloFKYWhyaHVuZGVydAriloFmaWYKZWZmaWNpZW50CmFuY2kKYnJhcmllcwriloFmYWlscwriloFrZXJuZWwK4paBR2wK4paBTmFjaW9uYWwK4paBcHJvY2VlZAriloFmdWVyCuKWgWxpdmluZwriloFzdWNjZXNzZnVsbHkK4paBZmFzdGVyCuKWgWNvbnRyZQriloFwcmlzb24KT1JUCmhlbHAK4paBYXV0b3IKxYJhdwphasSFCuKWgUFybQriloFwcm92aW4K4paBbmFhbQovIwpzZWQK4paBZ2VzY2gK4paB0LzQsNGACmVzawp0ZXJtCuKWgVRleAppcmluZwriloF0b29scwpQREYK4paBdWx0Cmlzc2Vuc2NoYWZ0CuKWgWNvdWxkbgpkaW5nCkRlcAp7LQriloFwcmVkaWN0CmFudGFnZQriloFMaWtlCuKWgdCR0LgKdG9vbHMKZXN0cmEK4paBa2kK4paBSmltCnN0YXIK4paBcmVtYXJrCsOzZwpuYWJsYQriloFBbHRob3VnaAptb2RlCkhvc3QK4paBc3RyYW5nZQpOb25lCmJsYWNrCuKWgUZlc3RpdmFsCuKWgUlTCmFuemEK4paBKC0KaWNrZXQK0LrQvtC70LAK4paBSmVzCuKWgWZsZXgK4paBw4AK4paBTmV0d29yawriloFFWAriloFlbmVybwoh4oCdCuKWgU9ydAriloFhbG9ycwriloFPcmlnaW5hbAriloF6bwrQvdGL0LzQuAriloFzcGwKRHJhdwp5b25kCuKUgOKUgAriloFPdAriloFkcmFtCuKWgWRpdmlzaW9uCuKWgWVmZmljaWVudAriloHQk9CwCuKWgXZpZXIKbmFrCkxTCuKWgXNwaXJpdAp6ZWljaG5ldAriloFkaWNpCmNsZWFyCmNvcHkKeWFyCuKWgdGA0L7RhtGWCnVzcXUK4paBbm91cwriloFibGV2CtC20LTQtQpBcmcK4paBcGVyZm9ybWVkCuKWgU1ha2UK4paBQ2Fyb2wKZXR0bwriloFTYW5kCuKWgURpc2MKRW5jCnJlcm8KaGFzaAriloFmb2N1cwriloFhdHRlbnRpb24K4paBYWdyZQriloFkaXZpcwriloHQsdGL0LvQvgriloFlagriloFtYXJjaAriloFwaGFzZQrDrWFzCuKWgXBoaWwK4paBUGFwCuKWgXJpdmVyCuKWgWNhdXNlZApwbHVnaW4K4paBVGVhbQp1bGVyCuKWgSQoIiMKaWVqCklTQk4KbmFtCuKWgWZpZ2h0CnZpZAriloFMdWQKU2VsZWN0ZWQKOkAiCuKWgVBvZAriloFhbm7DqWVzCmFyaW9zCuKWgWRldXRzY2hlcgriloFOQQriloHQuNGOCuKWgWRpY3Rpb25hcnkK4paB0JvQsAriloFUcmkKw6huCuKWgXBvbGl0aWNhbApyaWRnZQphdHRlbgriloFjaXJjbGUK4paBdHJhbnNwb3J0CmVtYXMKRkMK4paBcmVwbGFjZWQK4paBQXVkCmlza2EKQ29uZmlndXJhdGlvbgriloFzb29ydAriloHQndC1CuKWgXNlcXUKUFJPCuKWgWJ1ZAriloF7ewpsaWXDnwriloFNYXMKZGVycwp1c2FtbWVuCmVzYQriloFMeQrQstGA0L4KbWFjCuKWgdC40YHQv9C+CuKWgXN1Ywp1eQriloFpbGx1c3RyCuKWgXByaW1lcmEKaWxhdGlvbgriloFzdG9yYWdlCuKWgXBhcmFtcwprYXoK4paBdGVybWluYWwK0YDQsNC70YwK4paBaG9sZHMK0LvQvtGB0YwK4paBbmFkCuKAnS4K4paBb2N0dWJyZQpidWwK4paBaHVzClVMVAriloHDqWdhbGVtZW50CuKWgU1pbGwKxYJhZAriloFjb250aWVuZQoiPwriloE+Pj4KUXVlCsKgwqAK4paBcGxhaW4KYXRpdmEKb2NrZXIKTmFtZXMK4paBSnVkCuKWgWFncmVlCuKWgUdlbWVpbmRlCmxhcmUK0LrQsNC30LAK4paBc3RhcnRzCuKWgXByaWNlClRhcmdldApjdXMK4paBSW5zdGVhZAouOwriloFhbHRlcm5hdGl2ZQriloHQstC70LAKSUUK4paBb3JnYW5pegppbnUK4paBY29tcGxldGVkCuKWgWNhcnJ5CmF0b20K4paBZGVwZW5kaW5nCuKWgU91cgriloFpbnNwCuKWgSZcCmFpbHkKaXJlY3Rpb24K0YTQsAriloFkZWZlClRBQwriloFkZXNpZ25lZAriloF2b2lyCmJyZWFrCuKWgXBhcnRpZQriloFKYWhyZW4K4paBc3R1ZGlvCuKWgWpvdXIK4paBTm90ZXMKZmlyZQpob3VzZQpzdWNjZXNzCuKWgUp1YW4KSlMK4paBQ3VzdG9tCuKWgWJlc2NoCuKWgXN0YXRlZApib290c3RyYXAKw7Z0dApvenrDoQriloFDT04KaGF2CuKWgXNsZWVwCmVkYQpob3QKw6FuZAriloFTeQriloF0ZW1wcwphbWFyCuKWgXNjYWwK4paBYXN0CuKWgW9wZW5pbmcKY2xpcHNlCuKWgXByb2dyYW1taW5nCuKWgWxldHRlcnMK4paBcHJvZmlsZQpuYWgK4paBYmV5b25kCuKWgUZ1cnRoZXIKZmFjZXMK4paBY2hhcnQK0LfQtNCwCmFpZ24K0L3RltC5CuKWgVJvbArQvtCy0LDQvdC+CnRlcmlvcgp3ZWQK4paBaGVyc2VsZgriloFuZwphbmd1YWdlcwp9PVwKeW5hbWljCuKWgWp1ZwriloFFeGFtcGxlCuKWgSjigKAK4paBcGxheWluZwriloF1c2FnZQriloFtYW5hZ2VkCuKWgU5hdHVyCtGC0LXRgNC4CuKWgUV0CmVyaWEK4paBZGF1Z2h0ZXIK0L3QuNC10LwKRnJhZ21lbnQK4paBaG9sCkZsCtC+0LPRgNCw0YTQuAriloFpaG4Kw7xoCmluc3RhbmNlCuKWgWNvbXVuCuKWgXRydXRoCuKWgdGB0LDQvNC+CuKWgWltcGxlbWVudGVkCuKWgWFueXdheQriloFDcm8K0YTQtQpHQwp1YnVudHUKdHlwZXMKw6pzCi5+XApmb2xkCuKWgWpvaW5lZAo/PwriloFtw6kK4paBd2lsZArQutC70Y4Kcm93c2VyCuKWgUhvbWUKc2tpZWoK4paBSk9JTgriloFqdWluCmhvZgriloFkYXRhc2V0CtC20LTRgwonKSkK4paBbWllanMKQVBJCuKWgWVkaXRlZApvb2xzCuKWgXNlZWluZwppamQK4paBcHJvY2VkdXJlCuKWgUJyYXMK4paBc2lnbmVkCuKWgWV4dGVybm9zCuKWgWRpc2FwcAriloFEaXJlY3QKY3ljCuKWgWNvbnN1bHQKw7ZyZApXaWRnZXQKY2lvdXMKc2VjdAriloHQlNC4CuKWgXdpbmQK4paBQXJjaGl2YWRvCmFtbArRgdGBCldoCmtiZAriloFBcm15CuKWgXN1ZmZlcgphcnRpZmFjdAriloFyZXNvbHZlCuKWgVNwb3J0CuKWgdGG0LUKaWRhcwriloF0YXgKaWRpCuKWgWFjdGlvbnMK0L/RgNCwCnB1w6lzCuKWgW5hagpGYWxzZQriloFjaGFuY2UK4paB0YLQsNC60L4Kw6RkCuKWgWRvbAriloFlbnYK4paBYmFzaWNhbGx5CuKWgUNvdW5jaWwKenRlCuKWgWRpc3BsYXllZApuaWwKY29tcGxldGUK4paBTGVtCmlhbmNlCuKWgdC+0YHQvdC+0LIK4paBZGVwZW5kCnBsb20KZW5zdXMKdXRzCuKWgUhvdApiaXRyCuKWgXZhbGlkYXRpb24KYWJiCuKWgdGC0YDQtQprbQp6ZArDtmZmCldFCuKWgWludGVyZXN0ZWQK4paBeyIKYXJvCuKWgWNvcnJlbAriloFkZWRpYwriloFsaXN0cwriloFCaWJsaW9ncmFmaWEK4paBZWFybGllcgpwcm9ncmFtCuKWgXByZW1pw6hyZQpmcm9udApUYWIK0YHRgtCy0YMKZHJvcAriloFmZWFyCuKWgUVubGFjZXMK4paBQ2FwdAriloFyZWFsaXoK4paBaGFsCuKWgWluc3RhbmNlcwriloFzdXNwCmlsbGluZwolOwp7fQp8fAriloFwYXJ0aXRpb24K4paBQnVpbGQK4paBd28K4paB0J/QtdGACuKWgWRpcmVjdG9yCuKWgVNpbgrRgtC40Y8KcnNnCm91dmVyCuKWgW5lYXJseQpvZGEK0LrRgtC40LIK4paBc2lyCklNRQriloFqYW52aWVyCuKWgVdpbgpCdWlsZAppZXVycwpJTkUKZG91YmxlCkxhc3QK4paBcG9saWN5CnN0b3JlCuKWgW9ic2VydmVkCuKWgWZhbWlsaWUKbmljYQpyZXkK0LfRjAriloFZZWFyCuKWgWRldmVsb3BlZAriloFJbnN0aXR1dGUK4paBcmVwbHkKQ29tcGxlCmljaWFuCuKWgUd1ZXIK4paBZGFsbAriloFkZXNwCuKWgUZvb3RiYWxsCkVtcHR5CmNrZW4KdW5kYQriloFVcgriloFpZwriloFBdGwKYXV0aG9yCuKWgUJvbAp6aWcKbmF0CsWhdApzZWN1cml0eQpvbmljCuKWgXBlcwppdGFuCuKWgUV4dGVybgpqYW4KVkFMCuKWgdC40LwKYm9sZAriloHQstCwCuKWgdCc0L4K4paBZGlzcHV0CuKWgXRyaWNrCuKWgXBlZAopXnsKaW50bwpTaW0K4paBcGFyYWxsZWwKZm94Cm5vcm1hbAppbmVudArQv9C10LTQuApob2xkCk9LCuKWgWNoZW0K4paBdHdpY2UK4paBdXNlcm5hbWUKacSNCuKWgXJlcHJlc2VudGF0aW9uCuKWgWpvdXJuYWwK4paBOi0K4paBYmF0dApcJQriloFjZXJ0YWlubHkK4paBRXhjZXB0aW9uCmVwcwpzaG90CmF0ZWd5ClNob3cK4paBQ2FybApyaWcK4paBcmVwb3J0ZWQKYm90dG9tClRGCuKWgUZyYW5jaXNjbwpuYXAK4paBQ2hhbXBpb25zaGlwCuKWgWNvdXJ0CuKWgXNvdXJjZXMKaW91cgriloFjb25zZXJ2CmRpY3QK4paB0KDRgwpJQgriloFWZQriloHihJYK4paBRVIKIikpOwriloFQb2ludAphemluZQriloFpbnRlcm5ldArQtNC90LAK4paBY2FycmllZAriloFGaWVsZApheGlzCuKWgVN1bgriloFhdmUK0L/QuNGBCtGP0L0KYXN5CuKWgWp1bGlvCuKWgWRlcHVpcwriloFzdWdnZXN0aW9uCltbCuKWgUFyY2hpdmUKxJlwCuKWgVByYQpyZWgK4paBZGVtb25zdHIK0YTRlgpjbWQK4paBd2FzbgriloFwaG9uZQp1cGxvYWQKYXlhCtGC0L7RgNCwCmxpbmVzCuKWgWluZHUK4paBdm90CuKWgWVzcGEK4paBYmluCuKWgdC/0L7RgdC70LUKcGxhbgriloFqdW5pbwpvcmlhbApmcmVlCnN0ZXJyZWljaAriloHQtNGDCuKWgWxpbmtlZAriloFlbmFibGUKUEMK4paBZGVuc2l0eQriloFFZ3kKeW8KZW5kcmUK4paB0YHRigriloFpdGFsaWFubwriloFBUgriloFQZXJzCmbDqXLDqXMK4paB0YHQutC70LAKVmFyCuKWgU9uY2UKUmVkCmJ1ZmZlcgriloFFbnRlcgriloHFoAppbWllbnRvClN0b3JlCuKWgWhlYWx0aAp2YXQKSVNUCk9oCuKWgWt3CuKWgXJpdgriloFzb21ld2hlcmUKb2dyYWZpZQpwcml2YXRlCtC60YLQuAriloFkZWxheQriloFIdHRwCmpvYgpyYWVsCmVtcG9yCuKWgWRpY2llbWJyZQrDqnRlCtGG0YMK4paBY29tbWl0Cm9zbwpWYWx1ZXMK4paBaGVhZGVycwp0cmFuc2Zvcm0K4paBcHJvY2Vzc2luZwpyw6UK4paBQWgK4paBTm9kZQotLS0tLS0tLS0tLS0K4paBZmFpcmUK4paBaHVuClBsYXllcgriloFyZXZpZXcK0LPQtNCwCuKWgWxpbWl0ZWQK4paBUHJvcGVydHkK4paBc2VydmUKcmlhZ2UK4paBTWFzdGVyCuKWgWthbm4KY3JldGUKcGhlcmUK0ZHRgAriloFjaGllZgriloFzY2VuZQpraW4K4paBdW5pZm9ybQriloFmZWJyZXJvCiJ9CmlsbG8KSVRFCm91dmVsCnVzZXBhY2thZ2UKZW50aAriloFxdWlja2x5CkxhbWJkYQp4ZXMK4paBY2VsbHMKcm9nCmFtaW4K4paB0JzQsNGACuKWgW1heW9yCnBsYXllcgorKzsK4paB0J3QsNGB0LUK4paBc2FmZQriloF2ZWxvYwriloHQvtCx0YDQsApEYXRhYmFzZQpuZWgKVmVydAriloFmbGUK4paB0YTQvtGACuKWgWZvcmVpZ24KQWJzdHJhY3QK4paBbWFnbgriloFtb2RpZmllZAriloFtaWxpdGFyeQriloFtb25kZQriloFBY3Rpb24K4paBYmFuawpTZXJpYWwK4paBY29udGludW91cwriloFnZWwK4paBcGh5c2ljYWwK4paBaW50cm9kdWNlZAp1dHVyZQpyaWNrCuKWgXByZXNlbnRlZAriloFQcm92CuKWgUJvdGgKUG9zCnN1cGVyCiYjCuKWgWZpbmRpbmcKbmVsCnVuZGUK4paBZnLDpW4Kc2tpbQriloFIaWxsCmZuCuKWgUNhbmFkCuKWgWludGVuZGVkCm96esOhZsOpcsOpcwriloFqdWlsbGV0CuKWgVdhcnMK4paBc3VjY2Vzc2Z1bAriloFjaGFyZwppZWxlCm9tZXRoaW5nCm9rdQpmZXRjaAriloF9fQpiYW5rCm9wZXJhdG9ybmFtZQriloFDb2xvcgriloFDYXJkCnR1CuKWgSIsCndpZAriloFnZXAKWE1MCj09PT09PT09PT09PT09PT0K4paBVmlyZ2luCsOkaHJlbmQKbGljYXRlZApEaXIKemVybwriloFLYWwK4paBUGFydHkK4paBw6UKcHJpY2UKZG9uCuKWgXdhcm5pbmcK4paBQmFkCuKWgVN1cHAK4paBTGlnYQriloFQaWVycmUKUmVjb3JkCnVsYXRvcgriloFSb21lCuKWgXRoZW9yZW0K4paBZW50aXJlbHkK0YHQutC40LwKaGV0CuKWgWRvcG8KTmV4dAptbHVuZwp3aWcK4paBQXRoCuKWgVNvdQpsaWNoZXIK4paBc3Vkbwplc3RzCtGF0ZbQsgriloFzZXB0aWVtYnJlCuKWgW1pY3JvCuKWgXRyb3AKZml0CkNvcmUK4paBUmFkaW8K4paBT3JnYW4K4paBUG93ZXIKQ0YK4paBTGFzdAriloFvcHBvcwriloFvZmZzZXQK4paBcmVnaWEK4paBbWluaW11bQriloFoZWxwZWQKYW5kb24KaWZ5aW5nCnJ1aXQKZW5zY2hhcHAK4paBYmVyZQpWTQriloFBd2FyZHMK4paBYWdyCnlub21pYWwKZW5jZWQK4paBZGV2aWNlcwriloFib3QK4paBZmlybQriloF3cml0ZXIK4paBcmluZwouLQppc3Rlcwpsw6QK4paBbWVsCmVudGF0aW9uCuKWgVNjaHcK4paBbm9tZQriloFwb2JsYQriloF3b2oK4paBdWwKZW50bwrRi9GFCuKWgXJlc2lzdAriloFyZW1haW5zCuKWgUNhCmHDsWEK4paBQ291cnQKdXRhYmxlCmVudGlhbGx5CuKWgXRyYXQK4paBVmlzdWFsCuKWgXJlc3RyaWN0CuKWgXByZXZpb3VzbHkKY2F0aW9uCuKWgdC+0YHQvgriloFNeVNRTApmw7ZyCmNhbGEK4paBY3VsdHVyZQpsaXZlCuKWgWFjY2VwdGVkCkRpZAriloFob3VzCuKWgXNlbGVjdGlvbgriloFkZWNyZQptYXJnaW4KdXJiCuKWgUluYwriloFNYW55CmlidAriloFzdWNjZWVkCkJpbmRpbmcKY8OtCuKWgVJvZwriloFzaG91bGRuCmNsb3VkCuKWgWR6CtCy0LDQsgriloFwaXgKc21hbGwK4paBcHJvamVjdHMK4paBT0sK4paBbGF0ZXN0CuKWgXJlZmVyZW5jZXMKUHJvZ3JhbQriloFlcnN0CuKWgdGP0LoK4paBa2FtCuKWgUNhbWIKZWxsdArDtmQKbm9uZQriloFqdXNxdQpraW5nCuKWgVBlZAphc3NlcnQKQ1MKcml0bwplc3NhCtC70YzQutC+CuKWgVZvbgriloFFZHdhcmQK4paBaW1wb3NzaWJsZQpucAp3b3JkcwppZWx0CuKWgVBhZ2UKbGVycwriloFwaWVyCuKWgdC+0LHQu9Cw0YHRgtC4Cml0dGVlCuKWgShbCuKWgXRydXN0Ck5HCnJlZHUKPDwKcmlhbAriloFwcm9kdWN0cwriloFFcm4KcmnDqHJlCtCz0L7QsgriloFSZWljaAriloFSb2FkCuKWgW5lc3RlZApEaXNwbGF5CuKWgXN0cmVuZ3RoCm9ncmFmw61hCuKWgWFubm91bmNlZAriloFTY2llbmNlCuKWgdGA0LDQudC+ClBhcmFtZXRlcgriloFUYXNrCnVtZW50cwriloFhZG9wdAriloFPbmx5CtGO0YLRjAriloFjbGkK4paBbGVtCnN0b29kCuKWgUZJCsOqbmNpYXMKcG9uZW50cwpdJApjb21tZW50CuKWgXlhCnNob3VsZAppa2UKdGltCmVsbGlnCuKWgXNlbmRpbmcK4paBYWpheAriloFub3ZpZW1icmUKdW1lcwriloF3ZWl0ZXIK4paBRGFucwpvcHAK4paBc2VwdGVtYnJlCm90aW1lcwp6xZEK4paBZXAKdmVyZQriloFvaAo6PQriloFTb25nCuKAnSwK4paBdml2CuKWgXF1ZXJpZXMK4paBdsOhCuKWgWTDqWNlbWJyZQriloF1bmFibGUK4paBZXJoCuKWgWAtCuKWgUxlZQriloFlcnN0ZW4Kw7R0CtGB0YLQstC1ClRTCuKWgWZyYWdtZW50CuKWgXdpZGUK4paBc3VmZgriloFkdXQK4paBVmVyZQrRltGBCmFkaW5nCmllZ28KaWNhZ28K4paBQXJnZW50Cm9yZXIKZW5uZXMK4paBTGViCmxpbnV4CmFjaW5nCuKWgWJyb2tlbgp0cArDrW8KYWJldGgKaXN0YXMKZ2V3CmnDqG1lCmNhcwriloFwcmVjZWQK4paBRGFsCuKWgWNvbXBhcmVkCmVxdWl2CmlsbHkKdGVlbgriloFDb25zb2xlCuKWgXN0cmljdAppdGFpcmUK4paBRUQKZW50aWFscwriloFwZXJtYW4K4paBdG91cwriloFnZW1lCuKWgWV4dHJlbQriloHQvtC60YDRgwprZwriloFoZWF2eQriloFhdnJpbAriloFhbnRpCuKWgW9jdG9icmUKdXRmCmhlbG0KYW1wbGVzCuKWgShfCmFrZW4K4paBZGVhcgriloFvcGluaW9uCuKWgWZpc2gK4paBQWxleGFuZGVyCml3CtC40LwKY2FkZW0K4paBcmVmbGVjdAriloHQtNGACuKWgXRyaWIKY29tbW9uCuKWgWNsZWFybHkK4paBc2FmCj0iQCsK4paB0JzQvtGBCtGB0LjRgtC1CmVxbmFycmF5Cm51bmcK4paBcmVsYXRpb25zaGlwCuKWgVNlbQriloFraWxsZWQKdGVkCnVubwriloHQu9GWCuKWgXdpZAphbm5pbmcK4paBcGFuZWwK4paBTGViZW4K4paBcnVieQphbnNpb24K4paBYXJlbgp0YWJ1bGFyCmFsZXQKfSQkCuKWgUxha2UK4paBc3VpdGUK4paBbWlub3IKSG96esOhZsOpcsOpcwriloF4bWxucwpESVIKZHJpdmVyCmludHMK4paBdmljCkFORApwcmltCtGB0YvQu9C60LgK4paBT3gKVEMKcml2aWFsCmF0aWUK4paBZWlnaHQK4paBY29uZmxpYwphbmdlbAriloFCZWdyCuKWgWV4cGxpY2l0bHkK0Y7RgtGB0Y8K4paBRGV2CnJlbmRlcgriloFyZXByb2R1CuKWgWNyw6kKR3UKTUIK4paBa8O2bgriloFyZW1haW5lZAriloFrbArRhdC+0LIK4paBYnlsClBoaQriloFkZXRhaWwKamF2CuKWgW1vdXNlCkJhcwppxJkKYXNzZXIKaHMK4paBc2hpZnQK4paBw7psdApyYW5kCuKWgWJ0bgpyYXoK4paBcHVsCuKWgXN0YXRlbWVudHMKZmlsZW5hbWUK4paBcHJvbXB0CsOpbMOpCmlregriloFTdXMK4paBZGVidXQKU3RhdApmb3JtcwriloFIZWluCnN0YWR0CmVubmlzCtC/0L7QuwphcmFudGUK0YbRltC5CuKWgXF1ZXVlCuKWgXJlY2kK4paBc3RhCnluY2hyb24KY2VudGVyaW5nClNvbWUKR3JhcGgK4paBdGVzdGVkCuKWgUt1bnN0CtC+0LwK4paBTm90aGluZwppZXUK4oCcLgpCdW5kbGUK4paBb2ZpY2lhbAphbGxvdwriloFSZWFjdAriloFMaWJyYXJ5CmJsdWUK4paBdmVydwriloFwYXJlCuKWgUZyaWVkcmljaAriloFhd2FyZQpFeHAK4paBZWZmZWN0cwriloHQs9C+0YDQvgpsb3BlZGlhCuKWgVZlbgpyYWxlCuKWgUZpbmFsCuKWgXByb3BvcwpsYWNlbWVudAprdGVuCuKWgW5vdmVsCm9ydGVyCuKWgUdlcm1hbnkK4paBZGphbmdvCuKWgXRyYW5zaXRpb24K4paBaGFwcGVuZWQK4paBYmVhdXRpZnVsCuKWgW5laXRoZXIK4paBbGlicmFyaWVzCuKWgWhpZGUKYWxnCuKWgWFzcGVjdAriloFmb3JnZXQKY2FkZW15Cm9udGUKcmVmaXgK4paBY2xvdWQKbmVkCmNkb3RzCnJlZ2lzdGVyCm55bQouKToK4paBSmV3CuKWgXRyw6hzCtC90LjRh9C1CuKWgURvcgriloFwcm9jCuKWgWdhbgriloHRlAriloFTYXYKdsOtClNldHRpbmdzCuKWgVZhcmkK4paBY291cnMKUm8K4paBY29uagriloFyZWFzb25zCuKWgXJlYWRlcgrQu9C10LrRgdCw0L3QtAppY2F0ZQp9KSwK4paBdGFza3MK4paBUmF5CuKWgXJpYwpLZQpvbmllCnJmCilbCuKWgXN1YnNlcXUK4paBVHVybgriloFWSUFGCm1hdGhzZgpIRQriloFkZWNsYXJlCuKWgXByb3RvY29sCuKWgVBDCtGG0LjQvtC9ClZpZXdCeUlkCuKWgWFuaW1hdGlvbgriloFjb25mdXNlZArQstC40YcK4paBZW5hYmxlZApvd28Kw6FzdArDtnQK4paBbWFuZAriloFSYWlsCmZpZWxkcwriloFLYXAK4paBYWxnZWJyYQriloHQodGDCmbDqXJlbmNlCuKWgUN1cnJlbnQK0YHQvdC+CuKWgUxpbQpQYXJhbXMK4paBQW50b25pbwriloF0dgpsYXRlCmlmZXIKRW50cnkK4paBU2VydgriloFtdXNpY2FsCuKWgXRyYWNlCuKWgXNjaWVudApmaWMK4paBZm9yZ290CnZpZGVvCuKWgW9sZGVyClRyZWUK4paBdW5zCtC90LjQutC4CuKWgUV1cm9wYQriloFad2UK4paB0LHQtQriloF2ZWMK0LbRgwriloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloEKTWF0Y2gKc3BhbgriloFibGFuawriloFzcMOkdGVyCuKWgVR5CuKWgWRpY3QKw7FhCuKWgWNvbmZpcm0K4paBdsO9CtC30LDQvQpSZWwKZmlsbQriloFSb3QK4paBSHkK0LrQsNGFCuKWgWRlbWFuZAriloFtaW5pc3QK4paBTWFkcmlkCuKWgXVzdWFsCnNwaWVsCmVyb3MK4paBdHV0b3JpYWwK4paB0KHRgdGL0LvQutC4CnN5cwrRhtC40LDQu9GMCuKWgXNwcmVhZAriloFjb252ZXJzCuKWgXJvbGwKYXJ0aWZhY3RJZAriloFOdW1iZXIK4paBc3ltbWV0CuKWgU11bHQKZXhwZWN0ZWQK4paBYXhpcwriloFtYXRjaGluZwriloFmb29kCmdyb3VwSWQKTWFwcAriloHRgdCy0Y8K4paBdmVuZApGb3VuZApvdHRvCkNhdApjcml0CmlzdGVudAriloFkcmVpCuKWgWVuZGVkCuKWgVRlbGUKY29tcG9uZW50CuKWgWludm9sdmVkCuKWgUVzdGFkb3MK4paBZGFuZ2VyCuKWgWNoYWluCuKWgVByb20KaG9tCuKWgXBvbMOtdApjb3AK4paBbmFwCnJpZgpwbGVtZW50cwriloF2ZW50CmFubmEKYW50ZWQKZGF0ZWQKYW50aAriloF0aHJlYWRzCtC30L7QstCwCuKWgdGB0YLQsNC90L7QsgriloFlZXJzdApidWYKaGVpZAriloFSdQriloFQcmltCuKWgW1pZ3IK4paBVW5pZG9zCuKWgWFyYml0cgriloFyb21hbgpvdW50cnkKdWx0dXIK4paBS8O2bmlnCuKWgWFubm90CmFjaGluZwriloFIYXVwdAp1bWluCuKWgWhlbQpja2V0cwpiYXUKZWN0aW9uCmVmdAriloFwYWNrYWdlcwriloFLdXIKdGh1cgriloFwYXlzCmxpYW1lbnQK4paB0JHRgwriloFjYWRhCnBvaW50cwpvY2tldAriloF2ZXJiCtC70LXQtQriloFzdWJtaXQK4paBc2FuCnJ1YnkK4paBZWFzdAprb3YK4paBVmVybGFnCuKWgXNwb3QKcHBvCkVhY2gKamVrdAriloFCaW9ncmFwaGllCuKWgW5ld3MK4paBcGHDrXMKdWZhY3QK4paBZGlhCtC60L7QstCwCuKWgWFjY29tcGwK4paBw4l0CmlsaXRpZXMK4paBaWhtCmludm9rZQriloFhcHBlbmQKLiksCuKWgWxhYgphbmdpbmcKaXN0YW4KcmVzb2wK4paBU2VjdGlvbgpQYXJlbnQKbW96Ck1hdApzdHlsZXMKdW5kZW4K4oCcLAppcnRzY2hhZnQK0LrQuNC8CuKWgUZpbmFsbHkKcGhlbgriloFQYWMK4paBQXJyYXlMaXN0CuKWgXJlY292ZXIK4paBZWR1Y2F0aW9uCm1vZGVscwpwZWQK4paBaGFwcHkK0YfRgwriloFndWVycmEKbWVkaWEKT0YK4paBZW5zdXJlCk1hcmsKZGF0YWJhc2UKb2dnbGUK4paBcHVibGlzaApPVwriloFCYXUKPy4K4paB0YfQsNGB0YLQuAriloFyZXBvc2l0b3J5CuKWgU1hdHQKaGlnaApvdmVuCuKWgWdlcgriloF1bmtub3duCkFtZXIK4paBQnJvd24KQUxMCuKWgXJlc3VsdGluZwriloFib3IK4paBcG9ldArQvdC40LzQuApFbWFpbApGb250CuKWgWhpc3QK4paBdG9kYXkK4paBQmVyZwriloFidXR0b25zCtGC0LDQuwriloFzbmkK4paB0YfQtdC70L7QsgpDcmUK4paBdW5pb24K4paBemljaAppc2hvcAriloFxdWFuZG8KUG8KQ1RJT04K4paBQ29zdArRgdGD0LTQsNGACmVydmVkCk5vdGUKRXF1YWwK0LvQuNGPCtCx0YPRgAriloFhYnN0cmFjdApzdG9wCuKWgWFkdmljZQriloFpY29uCuKWgXRyYXZlbApCUwp2ZW5zCuKWgWJhdGNoCmxpcXVlCnNoZWV0CuKWgWlocmUKZW1vbgpiZXJ0bwriloFhc3NpZ25lZArRjNGOClBob25lCuKWgWF3YXJkCuKWgWZ1bmN0aW9uYWxpdHkKYWxsYQriloFEYW0K4paBY2l1ZGFkCuKWgWNsdXN0ZXIKRGVzY3JpcHRpb24K4paBc2hlZXQK4paBQXVzdHJhbGlhbgriloHCuy4K4paBIjwK4paBd29uZGVyaW5nCmFpbmUK4paBcmVwcmVzZW50ZWQKa2FwcGEKbmIK4paBc3kK4paBS8O2Cj0iIwriloFzZXZlbgpEaXJlY3RvcnkK4paBc2lzdGVyCnBsYXRlcwriloFsdWNrCuKWgXJlbWFpbmluZwriloFWaWxsCndlcmsKYW5uaQpldHRpCmZ1bmMK4paBYmFuCmltcwptaXNzCmFncmFwaArQtdC60YHQuAriloFSZWYKbml0dAriloFHYWIK4paBYW5kZXJlCuKWgWplZG9jaApyZXN1bHRzCiFcCuKWgWxpc3RlZAriloFsb3JvCuKWgWtub3dzCtC20L3QvgpSYWQK4paBc29ja2V0Cm11bHRpCuKWgdGA0ZYKcmFpbHMK4paBdGFyCuKWgWdlbnRsZQpzZXR0CnNlcnZpY2VzCmJvdW5kCmlna2VpdAphamEK4paBY21kCmFnZ2VyCuKWgWJhCuKWgUJlbGcK4paBS2xlCuKWgXdvcmR0CuKWgWZvc3QK4paBZGltZW5zaW9uCkFuZwp1bWluZwpPYmoK0L3QtdC9CuKWgU1hcmllCmV4aXN0cwrRgtGA0L4K4paB0LHQvtC70YwKZW1lbnRlCuKWgUpvbgpTRVJUCuKWgWhpZ2hlc3QKYWtpCuKWgXRyZXMK4paBY2lyY3VtCuKWgURvd24Kb21tZW4KdXJlcgriloFjYXVzZXMKdmVudWUKaXNzYW5jZQriloFpbmZsdWVuY2UK4paBZmF0CtGA0LXQtNC4Cn1cXAriloFlbnRyCuKWgVNpZ24K4paB0LrQu9CwCuKWgWJpbmRpbmcKZXNzZW4K4paB0KTRgNCw0L0K4paBTG9jYWwK4paB0Y/QstC70Y8KYXBwcm8K4paBZGVwZW5kZW5jaWVzCuKWgXRhbGtpbmcK4paBenVyw7xjawpjb25uZWN0aW9uCkFjdGl2ZQpiYmUKaXJscwriloFJbmYKd2QK4paB0LjRgQpyb2FkCuKWgWNvbnZlbgrEm3QK0LLQtdC3CuKWgWVudHJpZXMKZXNjCuKWgWJpdHMKYXNzbwpXUgpzaGlwcwriloFkw6lzCmVzcApNYWtlCuKWgWZhbWlsaWFyCkFydAriloFhcm15CmN0cgrDqXJpYwpxdWV1ZQriloFcewp1ZWxhCmFtaWVudG8K0YjQuNGFCuKWgSIiIgpjb250cgrQu9C70LUKRlMK4paBbWFya2V0CsOlbmcKY2l0ZXAKSWxsCnJhbmsK4paBc2VuZGVyCuKWgWJlaW0K0YDQsNC6CuKWgWNvbXBhdAriloFvY2N1cnMK4paBZGllc2UK0YHRgtC40YLRgwphd2EK4paBaU9TCuKWgUNoaW5lc2UK4paBVFIK4paBS2VuCuKWgVVuZQriloFjcmVhdGVzCuKWgXNob3dlZAriloHDqXYKb2xvZ2lhCuKWgXByb3Rlc3QK4paBUGYK4paBc3F1YWQKKyssCsOhdgriloFlc3NlcmUK0LfRjwprb2wK4paBc2xpZ2h0bHkKYWRkcgrDom4K4paBcmVkdWNlCuKWgVwoXAriloFEZXAK4paBZ2VuZXJpYwpMb2FkZXIKyJtpCuKWgdC/0L7RgQriloFvY2Nhc2lvbgriloFMYWR5CmVudGl0eQriloFhdmFudAriloFQYXMKYWdnaW8KXHsK0L/QsNC0CmF0aG9saWMKUGFzc3dvcmQK4paBcmVzcG9uZAriloFOb24KQUcKbmVnCuKWgdGD0YEKYmxvYgpja2UK4paBQ29uc2lkZXIK4paBQ2FyZQppa2kK4paBQ2hpY2FnbwppbmRlbgriloFDb3AKXSsKw7ZtCsOpdnJpZXIK0LrQu9C+CmFsZW4K4paBbWFqCnJhY3kKb3J0ZQppZW50cwplbGxzCmFjdGl2aXR5CuKWgXJ1bnRpbWUKTlVMTAriloFwb3NzaWJseQriloFzdHJpCml6aQriloFtaXIK4paBVmVyc2lvbgpwcmltZQriloF0d2VudHkK4paBTWFoCuKWgXNvdW5kcwrRiNC10L0KY2x1c2lvbgphY3oK4paBZGV0ZXJtaW5lZAriloFSZXAK4paBTGFuZGVzCuKWgXdhbGwKaWdpCuKWgXJlc2V0CtGI0L4KeWFuCk1ldAplaQriloFhcHBlYXJhbmNlCuKWgWZvaXMK4paBbmVsbAplc2kK0ZHRggpsb29yCuKWgVVsCuKWgXJlc29sdXRpb24K4paBZm90CuKWgXRocm91Z2hvdXQK4paBcmkKTGV2ZWwKcG9vbAriloFpZGVudGl0eQriloFqYW51CuKWgWltcGVyCuKWgcO2dmVyCn1gCuKWgWluZmVyCuKWgWRhdGVzCuKWgVN0YW5kYXJkCmZvcmNlCm9ja2V5CnRlcmEK4paBZGlzdGluZ3UK4paBcHJlc2VuY2UKbGljYQriloFsZWF2aW5nCml0dW5nCsOpYgriloFlc3RhYmxpc2gK4paBbWFhcgphZGkK4paBTmV3cwphem9uCmZvbGcK4paBSGVuY2UK4paBWWUK4paBZmFiCuKWgWbDvGhyCml0bWFwCuKWgVZlcnMKcm92ClNpZ24KZGV2aWNlClNpZ21hCuKWgXdldGVuc2NoYXBwCuKWgVBzClBBVEgK4paBdG9ybgp2ZXN0CtGB0YLQvtCyCmFjY291bnQK4paBbGFyZ2VzdAriloFwZXJjZW50CuKWgVdvbWVuCuKWgWltZwp0b29sCuKWgXJvY2UK4paBYXkKaW5ldAriloFhb8O7dAriloFwb2x5bm9taWFsCuKWgWludGVncmFsCuKWgWFyZWFzCn0nCuKWgWh5cApsb3llZQrRgtCw0LvRjAriloFwcm94eQriloFXeQriloHQnNC10LrRgdC4CuKWgWVzY2FwZQpvbGFyCuKWgW1pc3Rha2UKKX17CuKWgVBvdAriloFwcm9jZXNzZXMKIj4NCmhhbHRlbgp6emEKYW1vCtC60YDQtQriloFXb29kCsO4cgriloHRgdC10YAKb2NpYQp0d28KcHJvZmlsZQriloFBc3QKZW1icm8K4paBYXJtcwppbmFzCmlubmVuCuKWgW1zZwpJTlQK4paBYmF0dGVyCmlnbm1lbnQK4paBdnkKSHJzZwriloFHcnVuZApyb2MKc2VnCuKWgWRlY29yCuKWgWV2ZW50dWFsbHkKPiwK4paBcGFnCmFudGVuCuKWgXN0cnVnZwp9XlwKZGF0ZW4K4paBcmVsYQrQv9C+0LIK4paB0LrQvtGA0L4K4paBQm9zCuKWgWxhYm9yCuKWgVNlY3JldAp1Z2VuCuKWgWphcAriloFodXNiYW5kCuKWgUFsYnVtCuKWgWV0d2EK4paB0L/RgNC+0LjQtwpyaWNodApyYWNoCmJhdAriloFwcmVwYXIK4paBU3RvY2sK4paBbGFjawrRhdGW0LQK4paBaG9neQriloFDaHJvbWUK4paBQWRtaW4K4paBY29tcGFyaXNvbgriloFpbmNyZWFzaW5nCtC90LMKaW1pCkRiCuKWgWdlZgp1Y2h0CsOpc2UKZ2VuY2UK4paBQ29yZQriloFpbmNvcnJlY3QK4paBYXNzdW1pbmcKb3Vyc2UKaWVyb24K4paBVGhlb3JlbQriloFjYXNhCmplcwriloHQtNC10YDQtQriloFgIgpMRArDpMOfCkRlYgriloFzdWl2CuKWgUJhbmsKbGlicwriloFMZW9uCuKWgXF1YXJ0CuKWgXByb2Zlc3Npb25hbAriloF0aWVuZQriloFhY2NvbXAK0YHRgtC10YAK4paBVUsKTk4K4paBbMOtCtGG0Y8Ka2VsCuKWgeKAogriloFkaXNlCm9udG8K4paBbcOhCmlmcwpiaWxkCuKWgWNvbXB1dGUK4paBw6lkCmrEmQriloFNw6kK4paBbGFuZ3VhZ2VzCuKWgVRpbWVzCmNlbgriloHQsNCy0YLQvgrDvW0KZW5legriloF1cHAK4paBbcOpZAriloFjdWFuZG8K0L7QtApJbnRlbnQKZWVyZAriloFUYWwKb2Zmc2V0CuKWgWhhYmVuCnJlbWUK4paBU3RhY2sK4paBZHJpCuKWgXNlaW5lbQriloFmw6l2cmllcgriloFjb21iaW5hdGlvbgriloFzb2xsCuKWgW1vdmVtZW50ClNwZWMK0LrRgNGLCnJldGNoCk9mZnNldApSb290CtCQ0YAKd2FydAriloFGb2xsb3cK4paBU29jaWFsCtC90LjQutC+0LIK4paB4oaSCkRvbgriloFoYXJtCmFncgpuZWdvCnJlc291cmNlCuKWgUx1YwriloFzZWluZW4K4paBRGVwYXJ0bWVudAriloFVcGRhdGUK4paBVGV4YXMK4paBcmV2ZQriloFQb3MK4paBc2hvdApvdGhlCuKWgXJlcGVhdGVkCuKWgXJlY2VudGx5CsOhYmFuCmFrcwrQv9Cw0L0K4paBY2hhCm9obAriloF0ZW5kCuKWgdC00LLQvgpjaHRzCsOnYWlzZQpwbGluZwphbGJ1bQplagriloFgWwptYXBzCuKWgXVuaXRzCuKWgTwhLS0K4paB0LPQtQriloFJbmZvcm1hdGlvbgppa29uCuKWgXRhbgriloFkb2NrZXIK4paBU3RhZAriloFhdWRpbwppa28K4paBY29vcmRpbmF0ZXMKeHMK4paBcmVwbGllZAriloEpLAriloFHb3Zlcm5tZW50CuKWgUFjYWRlbXkKVU5UCuKWgdGC0YDQuApCbAriloFhbmMK0YjRgwriloHRgtCw0LrQvtC2CuKWgWluZmluaXRlClJDCuKWgWdhCuKWgWFkanVzdAriloFtZXJnZQo7YAriloFwb3N0ZXIK4paBSmFwYW5lc2UKIl07CuKWgWV4aGliCuKWgW9yZGVyZWQKaWN0dXJlcwrRgNC+0YEK4paBc8OpcmllCmxldHMK4paBaXAKU2VsZWN0b3IK4paBZXhpc3RlbmNlClJlY2UKbGlnYQpkb3dubG9hZAriloFsZW1tYQppZXYKdWRlbnQKc2tvCuKWgUFyYWIKaXRhdGUKYnl0ZQrQvtGCCmlrdArQvdCw0YLQsAriloFBZgooQAriloFtYWQKb2RiCuKWgWVsaW1pbgriloFzcGVudApFbnRlcgriloFNaXRnCldoZW4K4paBZMOpcGFydApNSQriloFmZWxsb3cK4paBdGhvdXNhbmQK4paBQ3UKa3RvcgpDYWNoZQriloF0YW1iw6ltCuKWgWV4dGVuZGVkCtCy0LXRgdGCCmF0ZXJzCuKWgUxpYwp0b3R5cGUK4paBR2EK4paBYmxvb2QK4paBbWFwcGluZwriloFub21pbgriloFtYW5pZmVzdAriloFwZW5zCuKWgXJpdAriloFmaWxlbmFtZQriloFmaWxsZWQKdsOkCuKWgXJhaXNlZAriloFtb2JpbGUKa8OpCuKWgVJpZ2h0CuKWgWdlaMO2cgriloF0ZW1wZXJhdHVyZQriloFzb21laG93CuKWgVNwYW5pc2gK4paBa29tbXVuCuKWgWNob3NlbgriloFob3JzZQo7XAriloFvcmlnaW5hbGx5Ckhhc2gK4paBY2l0dAriloFlbmNvcmUK4paBV29sZgriloFuw7oK4paBWW91bmcKVmFyaQriloFTY2h3ZQriloFjYXB0dXJlCuKWgUphbmUKSW50ZXJmYWNlCm93eWNoCuKWgURldXRzY2hsYW5kCuKWgUtvbAriloFib3VuZGFyeQriloFHTkQKTm93CmtlaHIKKCoKPS0K4paBV2VsCuKWgUNhdAphbW1lbnQKQUdFCuKWgXJpZ2h0cwpTY3JvbGwK4paBaGFwcGVuaW5nCuKWgUJsYQriloFzY2llbmNlCmF3cwriloFiZWhhdmlvdXIK4paBaW1wbGllcwriloFRdWVlbgpvdmFuCnBheQrRmtCwCmFyZXQKZXJzaGlwCuKWgUxhbmcK4paB0LPQvtC0CuKWgXJlY29yZGVkCnplbQriloFUaHJlYWQK4paBdG9kbwpvZ28K4paBc2NlbmFyaW8K4paBY29uY2VudArRgNC10LcKU3RvcmFnZQriloFkaXJpZwriloFTZXJpZXMK4paBZ2FzClNFVArDqGNlCnJhdGUKSFRUUAriloFrYXAKRW1wClVURgrDoW7DrQrRgdGC0LDQstC4CndpbmRvd3MKw6lyYXRpb24KYXBlZAriloFzaXN0ZW1hCuKWgXN1cnYK4paBV2VzdGVybgriloFnw6kK4paBU3VjaApXcml0ZXIK4paBY2FudmFzCuKWgWd1YXJhbnRlCnNjcm9sbAphdmVkCkl0YWwK4paBRWxlY3QKXSgjCuKWgUhlcm0K4paBQ29tbWFuZAriloFDaGlsZAriloFwZAp1dGNoClNxbAoqLgriloFUYWcK4paBVGEK4paBbWFpbApzY3JlZW4Kc2NyCnppYWwK4paBRsO8cgriloFzdWdnZXN0aW9ucwpjaGVzdGVyCil8CnBlcnNvbgp6ZWwK4paBd2FpdGluZwriloHRgdC70LUKRkwK4paBQWxiZXJ0CuKWgUhpagriloHRgtC10YAKZXdyaXRlCuKWgXNlbnRlbmNlCuKWgWxpbnV4CtC10LTQtQrDqm5jaWEK4paBSXRhbGlhbgrRh9C60LAKRmlsZXMK4paBbm90aWNlZApiaW5nCuKWgVJlc2VhcmNoCuKWgWFsdGVyCmhlZWwKXDxeCuKWgVByb2Nlc3MK4paBYmF0dGxlCtC80L7QsgriloFBZnJpY2EK4paBQW5uZQriloFnZWxkCn0lCuKWgWRvY3MKVHlwZXMK4paBcmV0cmlldmUK4paBT2ZmaWNpYWwK4paBdHJhYgrRhtGLCuKWgUlucHV0CnN0ZXAK4paBbGF1Z2gK4paB0KXQsAriloFwZWxhCk1lZGlhCnJvdWdoCtCz0LDQvdC4CuKWgVNob3VsZAriloFDb250ZW50CtC70LXQvApvc2gK4paBc29tZXdoYXQK4paBQ2VyCkJhY2tncm91bmQKc3RydQriloFpbmxpbmUK4paBTmVkZXIK4paBbW9kdWxlcwriloFCdWNoCsWEc2tpCndpZGV0CuKWgXpuCnBvc2VzCuKWgWdyYWR1CuKWgWFxdQpQUgriloFwdXR0aW5nCuKWgdC/0L7Qu9C4CuKWgXB1cmNoCuKWgXNtb290aArRgNC40LkKZW5naW5lCuKWgWxpdmVkCkFjY291bnQKRGV0YWlscwriloF0ZWxscwriloFPdXRwdXQKSGVyZQriloFGb3VuZGF0aW9uClRleHRWaWV3CuKWgWRlY2lzaW9uCuKWgWRlcGVuZGVuY3kKb2NhdGlvbgpvdmFsCmZlbGQK4paB0L/RgNC+0LIK4paBZW5kcwriloFpb3MK4paBZXhjZWwKYWd1CuKWgWVsZWcK4paBRWxlbWVudApRdWV1ZQriloFmw7YK0LLQtdGA0YHQuNGC0LUK4paBZXhwZXJpZW4K4paBZGlyZWN0ZWQK4paBY2FtYgriloHQlNC2CuKWgWZvbGcK4paBY29uY2UK4paBRmFiCuKWgVZpCuKWgWFkdmFudGFnZQriloFCZWkKcHJvZAriloFYSVgK4paBRmFjZQriloF2aXIK4paBUnVzc2lhbgriloFzcGFuCmVuw60K4paBem9uZQriloFhdHRhY2gK4paB0LHQtdC3CuKWgW1hbmFnZW1lbnQKQWMK4paB0L7QvwpvbmNlCmhhbHQKdXNvClNwZQriloFyYXcKw6lybwppZGVsCmxhdwpTaGVldAriloFtaXNzaW9uCuKWgWNhbWVyYQriloFob25vcgriloFhcHBvaW50ZWQK4paBUm9tYQpsaW5lYXIKUm93cwpmZXJlbmNlcwriloFJTwriloFjb3ZlcmVkCnJhagrRgdGC0LLQvtCy0LAK4paBU3ltCuKWgXRpZAppc2MK4paBUnVkCuKWgWVuY3VlbnQK4paBZmFpbHVyZQrDvHNzCuKWgXNxdQriloFwYWludAriloFzZXJpb3VzCuKWgWN1cnNvcgp0cmFzCuKWgWRpc2N1c3Npb24K4paBY3JpZWQKZXJpZQriloFEZXZlbG9wCuKWgXJld3JpdGUK4paBZ8OpbsOpcmFsCndhaXQK4paBSGFycnkKw61yCuKWgWdlcHVibGljCuKWgdC40LMK0ZbQsQrRj9GCCuKWgdCY0LcK4paBZXF1YXRpb25zCuKWgXBsYW5lCuKWgWFjcXUK4paBYW5nbGUK4paBdHJlZXMK4paB0JrQvtC9ClZECnBlcnQK4paBZG9jdW1lbnRzCmNiCuKWgWltcGxlbWVudHMK0YHRgtCw0L3QvtCyCuKWgVdhbHRlcgrQt9GL0LLQsAriloHRgdC/0LUK4paBY2hhcApwbGV4CuKWgW1hZ25ldAriloFnZXB1YmxpY2VlcmQK4paBaGlnaGx5CuKWgWxldXJzCuKWgWRyZXNzCuKWgXJlc3RhcnQKUmVuZGVyCkNhbGxiYWNrCmlzbwriloFjb25zdGl0dQriloFFbmRlClpFCuKWgUFuZ2VsZXMK4paBZGVyaXZlZAo9InsKXVwK4paBQ2hhbmdlCuKWgUhhdXMK4paBc3RhZAriloFSZXF1ZXN0Cm9tbwriloFBY3RpdmUKdXJlbgriloF0b3VybgriloFwYXJ0aWN1bGFybHkKU2VydmxldAphYmMKd2lkZXRpbGRlCmFuZHJhCkhlbHBlcgpSdWxlCuKWgXBsdXNpZXVycwriloF3YXZlCm5lcQriloHQotC1CmZyZQpza8OpCuKWgWFsYwriloFsb2dzCkdTCuKWgU1vbAriloFwZXJtaXNzaW9uCuKWgXNvdWwK4paBd2FudHMK4paBZ3VpZGUK4paBdmllbmUK4paBV2lsaGVsbQriloFldmlkZW5jZQoifSwKcm9wb2wK4paBYXV0aGVudGljYXRpb24K4paBb2NjdXJyZWQK4paBSUYKbm9jCklBCuKWgUJhbgriloHQutCw0YAK4paBYmxlCuKWgXNlZ21lbnQK4paBcGxheWVycwppc2kK4paBc3R1Y2sK4paBUHkKQW55CmhvdQriloFmb3JtYXR0CuKWgXBlYWNlCuKWgdCa0LDRgApldGVzCmRmcmFjCig/CuKWgVNpdGUK4paBTGl2ZQriloFVcwriloFjbGltCuKWgUFsaQrRgNC10LkK4paBUHJpbmNlCuKWgW9ibGlnCmllYgriloFBbHQK4paBcHJvcwpyYWNsZQriloFDZXR0ZQprZXMKesO2cwpvdXZlbGxlCi8vLy8vLy8vCmFieQrDqXJlCnJhbmUK4paBcG93ZXJzCuKWgVBhdGgK4paBV29yZAriloF0cmFuc2FjdGlvbgriloFjYXVzaW5nCmVsbHNjaGFmdArDonQK4paBQ1BVCuKWgWRlcHRoClNUUgriloFDb25mCuKWgXJhcmUK4paBQWsK4paBYm9uCuKWgUNhcmxvcwriloFzcGVjaWZpY2FsbHkKcmljcwpLRVkK4paBc3RhcnMKw6lyaWNhCuKWgdCb0YMK4paBY29uZmlndXJlCuKWgWFnZW50CuKWgWV4cGxhaW5lZAriloFjb2VmZmljaWVudArQtNGMCid9CuKWgXZpZGEK4paBU3luCuKWgdC90LDQt9Cy0LAK4paBT3B0aW9uCuKWgXJvYgriloHQutC70YMKOlsKYW50bHkKZGVwZW5kZW5jeQriloFDdXIK4paBZnJhbmNlcwriloFpZGVhbApTdwriloHQs9GA0YPQvwriloFDYXB0YWluCuKWgXRvZG9zCkpvCuKWgXBlbG8KP10oCuKWgWZhaXRoCtC+0LLQvtC5CuKWgWZyZXNoCuKWgXByb3ByaQpUaW1lb3V0CuKWgXZlaApjb250ZW50cwriloFEb2N1bWVudApjb2xsZWN0aW9uCuKWgWthcgpydWNrCllvdXIKdW1hCuKWgW1hdGhlbWF0CkVuYWJsZWQK0L/Rg9Cx0LvQuAriloFFbmdpbmUK4paBTcO8bmNoZW4K4paB0L/QvtGB0LUK4paBZm9uCmFyY2hpdmUK4paBZnJlcXVlbmN5Cn0rXArDonRlCuKWgWtvcgriloHQmtGA0LAKU2luZwptb250aAriloFIYXcK4paBc3lzCmVybWUK4paBV291bGQK4paBaW1wYWN0CnVycmVuY3kKbGljaHQK4paBYXB0CmllcmUK4paBbW90aW9uCtCh0KHQoAriloFJbml0CuKWgW1zCuKWgU1TCnNoaWZ0CuKWgWF1dHJlcwriloFiYXNoCmhpZGRlbgpvcmlvCuKWgWNlbGVicgriloFMaWJlcgpldG8K4paBZG92ZQriloFwYXRocwriloFpbmoKQ2F0ZWdvcnkK4paBY3J5CuKWgW1hcmtlZArRg9C00L4KYXNoaW9uCsOkbHQK4paBbGFuCuKWgXRlYW1zCuKWgWt2CmlhbXMKYWJhbgriloFUQUJMRQrQstCw0YAKUmVwb3MK4paBQmVsbAriloFwdWJibGljCuKWgWNvdW50cmllcwriloFzcGluCuKWgWzDqWcK4paBS3JpZQriloFKb25lcwp3aGl0ZQpIdG1sClByZXNzCuKWgUJsdWUKT3BlcmF0aW9uCuKWgUFudGgK4paBcHNlCuKWgUZvbnQK4paBdGhlbWUK4paBYmxvY2tzCiQpCuKWgWdsYWQK4paBbWFuYWdlCm9yZGVuCm9zdGVuCmNvbGUK4paBU1AK4paBc2NoZW1hCnVyYXMK4paBd2hlbmV2ZXIK0KjQkArRgNC40YLQvgriloFkaXNjb3ZlcmVkCuKWgXByZWZpeApnbG9iYWwKcm9rZQp6ZXMKY2h0ZQriloFCZWZvcmUK0LzQtdC90LgK4paBRGlnCuKWgXJhcGlkCuKWgWxsZWcKZXF1YWxzCuKWgUhvY2gKZm9yYWxsCtCy0LDRgtC4CnVzegriloFhdHRhY2hlZApFeHByZXNzaW9uCuKWgXN0b2NrCsO8bGwKcGV0CmVzc2lvbnMKY29sbwriloFneQpCb29rCuKWgUphY29iCuKWgVByb2R1Y3QK4paBaW5wdXRzCtC80LjRgAriloFsZWFybmVkCsOzd24K4paBcG9saWNlCuKWgdC70LXRggriloFJdGVtCuKWgWV5ZQphaWVudAriloFTYW1tbHVuZwriloFMb3IK4paBcmVwcmVzCuKWgWZlc3QKQ29uZAriloFub3V2ZQriloFleHRlbmQK4paBRnJhbmNlcwriloFGaW5kCuKWgWRlemUKZXJuYQriloFoYWLDrWEKcHLDvAriloFtb3RvcgpiaWUKSGVsbG8K4paBcmVzaWQK4paBZmluYWxlCiUpCnsnCuKWgUhhcmQK4paBcGFpcnMK4paBRWxsCml2b3QKcmVlcwriloFGb3JjZQriloFldmVuaW5nCuKWgWRlc3B1w6lzCnJnCldoeQriloFjb25uCnNjaGVtYQrRhdC+0LQK4paB0LzQtdC20LTRgwriloFmbGFzaApza2lwCuKWgW1pbnV0ZQriloF2ZWQKYXlsb3IK4paBc2V1cwriloFNYWpvcgriloFmcmFuYwriloFyYWMKa3cKY3YKTmF0aXZlCuKWgUJ1dHRvbgrQvdC40YbQuApzZXR0aW5ncwriloFBY2Nlc3MK4paBcXVhbGl0eQpwcm9wcwpGbG9hdAriloFTY290CuKWgUFECuKWgWFsbGVtCiZcCnVzdHJhdGlvbgpwYXR0ZXJuCm1pcgriloFpbmNvcnBvcgpza2ljaAonPgpTdGFuZAriloF0ZWNobmlxdWUK4paBRXNzCuKWgU94Zm9yZAriloHQu9CwCnRpa3oK0LvQuNC5CkxvZ2luCuKWgW1pbmlzdGVyCuKWgWN1cmwKa2FuCuKWgW1hcHMKaW5kYQpyaWViCuKWgUVORAppZmllcwpjb25zb2xlCmJ1cnkK4paBTEUK4paBaW5kZXBlbmQK4paBdGEK4paBxZoKb25lbArDqXN6CuKWgUlzdAp1dGl2ZQrRkdC7CuKWgVJlZ2lvbgriloEoPQriloFjb21wYWN0CsOnb2lzCuKWgWxhYmVscwphdXRvcml0w6kK4paBc3RhbgriloFmcmFuw6dhaXNlCuKWgXJlbW92aW5nCnljCn18CuKWgUV4ZWMKKCRfCm1hZwpiZWZvcmUK4paBc3RvcHBlZArQvNC40LgK4paBcmVmcmVzaAp1bmt0CmljaW8KWG1sCuKWgVRhYgriloFmb3VuZGVkCuKWgWZhbApmeAriloFIaXN0b3JpYQriloFFYXJseQpEb20K4paBZGVjaWRlCuKWgXVuZGVyc3Rvb2QK4paBanVyCuKWgU5yCuKWgWNhcGFjCndhcwriloFlbmVteQriloFwcm9ncmFtcwriloFtYXNrCtGB0LrQtQriloFncm91cGUKY2FtCuKWgXdpZGdldApSRUFURQriloFzZXZhCuKWgUJhcmNlbAriloFwZXJkCuKWgdCc0YMKcmFuY2UKVFlQRQriloF7JwriloFiaWxsCuKWgSJfCidgCmJhaG4K4paBY29udGFpbmVkCkNsb3NlCnJ1ZwplZ3kK4paBc2lnaHQK4paBUHJvdmluCtC90Y4KYXJ6CtGJ0LXQvQriloFKb2UK4paBZGVsZXRlZAriloFBdXRvCuKWgW1ldGVyCkNHCtGK0LsK4paBcGVudAriloFiZXplaWNobmV0ClN1bQpkYmMK4paBUGxhdHoKZWN0b3JzCuKWgUxpdHRsZQpRVUUK0YbRltGPCtGC0LXQu9GPCm5pZ2h0CuKWgWxsCuKWgW1vc3RseQpVSUQK4paBYmV6CmRvYgrQutGB0LgKdGVybmUK4paBY29ybmVyCmF0eQriloFpbXByb3ZlCuKWgWludHIK4paBYEAKYXJvZAriloFpbnN0YWxsYXRpb24K4paBUmVmZXLDqm5jaWFzCmlnYW4K4paBY3JpdGljCmFkZWwK4paB0YHQtdC70L4KLA0KYXRvcmkK4paBRnJpCuKWgXLDqWbDqXJlbmNlcwriloFJbnRlbnQK4paBdGFudAp1bmNpCuKWgWxldmVscwplcmVzCuKWgWVtZXIKc2FmZQp0awriloFjaGFtCuKWgWdyZWF0bHkK4paBd2VpdAriloFjb2FjaAriloF0b3dhcmQKSG9tZQriloFCb29sZWFuCtGC0LXQuwriloFtb2NrCuKWgWFwcHJlY2lhdGUK4paBQ3Jvc3MK4paBVGFrZQpEUAriloFzaWRlcwriloFOb3JtZGF0ZW4K0LTQtdC5CnN0YWwK4paBY291dApibgriloFWZXJ0CuKWgWJpcmQK4paBZHluYW1pY2FsbHkK4paBRG9sCuKWgUJ1cmcK4paBZG9nCsOkdHQK4paBbnVjCkVDCkJ5dGVzCuKWgWFrCnJlbGFuZAriloFndWl0YXIK4paBcmVnYXJkaW5nCuKWgUZ1w58K4paB0LTQvtC7CmF1c3MK4paBamVqCmFjbwriloF1cGRhdGVzCtGA0YPQugooJy8K4paBY29sZAriloFHaXZlbgpoaW4K4paBZmVlbGluZwppZ2xpCmZhaArRgdGC0YDQtQpib29sCmluaXRpYWwK4paB0YHRgtCw0L3QvtCy0L3QuNC60LAK4paBQW5uYQriloFob3JzCuKWgWRvbGwK4paBY29uc3VtCnViZXIKc3RhbmRpbmcKYWN0aXYK0LfRlgpjaGVja2VkCuKWgXBlcm1pc3Npb25zCuKWgU1vbnRlCldyaXRlTGluZQpwbHVzCuKWgUVxdQriloHQuNGFCtGH0LrQuAp1bnF1ZQriloFMTwplYQpzYW1wbGUKaWVzegpvcmFsCuKWgdCY0L0Kb3N0b24K4paBU2ltb24KZmFzdAptawphc3NlbgriloFhcmNoaXRlY3R1cmUKZW5zZXMK4paBw4UK4paBdG9waWMK4paBZGlzYWJsZQriloFDcnUK4paBQ29udHJvbAriloFjcmVhdGlvbgriloFoeXBlcgppdHVkCtC20LXQvdC40Y8KYXJhbQriloHQs9C00LUKaWVuc3QKZWR1bGUK4paBQm90CuKWgdCe0YEK4paBVGhlaXIKYW5uZQpNaWNyb3NvZnQK4paBUE0KeWRybwplbnRsaWNoCuKWgUVpbmUKQ0hBUgo6JwpXZWxsCmxldG9uCuKWgXN1cHBvcnRzCiddKQptYW51YWwK4paBdmljZQphc2EKY2xvcwp2aXNlZAriloFwb2sKdHJhY2sK0L3QvtGB0YIKLi4uLi4uLi4K4paBJ1wKwrIuCuKWgW9yZGVycwpldHRhCuKWgWNvbnZlcnNpb24K4paBdHJhZGUKY2xpCuKWgdCY0YHRgtC+CuKWgWFrdAriloFzdWJzZXQK4paBYXVnCuKWgWxlYXZlcwpNYXRoCmFubmVkCmthbAriloHQktC10LvQuAriloFub2cK4paBZXRoCuKWgWhhaXIKYXJvdW5kCuKWgWphdmF4CtCy0L7QuQriloFDZW50cmUKw7bDnwp1dGkK4paBbmF2aWdhdGlvbgriloFQUwriloF3YQriloHQoNC+0YHRgdC40LgKdXNhCnpldGEK4paBUERGCuKWgW1pc21vCnByb3BlcnRpZXMKbWVpc3RlcgrQu9GM0YLQsApmb3J3YXJkCuKWgU9zdApraW5zCuKWgXNpZG8K0LfQvtCyCnRhZ3MK4paBYWN0b3IK4paBZmx5CkNSCmFnaW5pCuKWgWxldHQKZW5pCnRlY2gK4paBRW5jCm9yYWNsZQphbWlsdG9uCnplagpmZW4KdW1lcmF0ZQriloFxdWVzdG8KZGFydAriloFLb3JlCmFwaXMKZXBlcgpTY3JlZW4Kd2FsbAriloFpc2xhbmQKc2hlCuKWgWxpZ2dlcgrQstGB0Y8KZmFuZwriloF0YXJkCuKWgXBsYWF0cwriloHQv9C70L4K4paBT2ZmaWNlCuKWgVNFVAriloFjaXJjdWl0CmplZApTYXZlCtC70YzQvdC+ClNvY2tldAriloFJbmRleApBQ0sKaWRlcnMKZXJlcgriloHQodCo0JAK4paBbGFkeQriloFzY2hlbWUKaWVsbGUK4paBZXhlcmMKKX1cCkRhdGVUaW1lCmF0aGFuCuKWgVByb2Zlc3NvcgriloFtb2lucwriloFFeGNlbAriloFIYXkK4paBTXVzaWsK4paB0ZcKxJlkCuKWgSIuCuKWgdCx0YPQsgriloFpbnN0cnVtZW50CtC/0LDRgAriloHQsdC10YDQtQriloFwb2xpdGlxdWUK4paBdHJhZGl0aW9uCuKWgVZNCuKWgUFydHMK4paBQ2kKVXNlCuKWgWFnZ3JlZwriloF3ZWVrcwriloFvcHBvcnQKaXRpbmcK4paBdmVydGljYWwK4paBTmF6Ci4uLikKaXpvCuKWgWN5Y2xlCuKWgXRlbXBvCtGC0YDQtQriloFoYW5kbGluZwppc3RlbmNlCuKWgXBhc3RlCuKWgWVuam8KUk9VUAriloFvdXRlcgriloFzdXBwbHkKZW1hbgriloFhY2NpZGVudAriloFcXQriloHRgtC10YUKUG9vbApvdGluZwpvbnltb3VzCuKWgUdpb3YK4paBdWQK4paBLi8KRVJST1IKY29uc3RydWN0CnRleHR3aWR0aApxdWlwZQpjYXNlcwriloHQsNC0CuKWgVJvdwpIb2xkZXIKd2FuCmFybmEKTWVtCuKWgUNhbmFkaWFuCuKWgUNvbW1pc3Npb24Kc3VuCuKWgWFwcHMK4paBQmxvCuKWgWlocmVyCuKWgWZhbWlsbGUK4paBbcSbCuKWgXB5CtC40YEK4paB0YLQvtCz0L4K4paBQWdhaW4K4paBaWdub3JlCuKWgXRlbGV2aXNpb24KUGF0CmhpZGUK4paBUmV2CuKWgWJlYXIKcGh5CuKWgW5vaXNlCuKWgXdyYQphdGlvbmFsZQriloFjb2xsYWJvcgpib3JkZXIK4paBZWxlY3RlZAriloFzdXJwcgriloFhdm9pcgriloFhc3NlbWJseQriloHQvtCx0YnQtQriloFhcmJpdHJhcnkK4paBYnJpZWYK4paBLS0tCuKWgU1hdXIKZ3Jlc3Npb24KaWNpYQriloFsaWVndAriloFGaWd1cmUK4paBb250bwpSZXBvc2l0b3J5CuKWgWTDqWYK4paBZm9ydGgK4paBY2xpY2tlZApzZWl0ZQriloFub3RlcwpuYXRpdmUK4paBRURJVArRi9C1Ck1UCmFtZW50YWwK4paBcm9zZQriloFwdWVkZQpEZWxlZ2F0ZQp1YmEKbmVvCnhpcwriloFBcnRodXIKVVJFCmFtaW5nCkRldmljZQriloFkaWFtCnN0w6RuZAriloFwcm9uCm9pcwpjb21pbmcKUGFyYW1ldGVycwp1dnVkCuKWgWFiaWxpdHkK4paBbcOpdAriloFVbmZvcnR1bmF0ZWx5CmZkCkRpY3Rpb25hcnkKc29ja2V0CuKWgWNvbm9jCmNvbnRhaW5zCmVzc2VkCuKWgWdlbGRpZwrQvdC40YbQsAriloFwb2ludGVkCmVzdGkKbm9tCtC+0LPRgNCw0YTQuNGPCuKWgXJlcHJlc2VudHMK4paBbWFuaXAKd29ybGQK4paBcmVzb2x2ZWQKdGVncgriloFkb3J0CmFzdGVybgriloFjYW1wYWlnbgriloFwcmltbwriloE7OwriloFzbmlwcGV0CuKWgU5pawpUb3RhbAppc3NlbWVudApBQ0UK4paBdmVyaWZ5CmlmZmUKbGFnZW4KaWV1cgriloFjb252ZXJ0ZWQK4paBTWlsaXQK4paBQWxnCuKWgVJvbgriloFrb25uCmFwcGxlCuKWgWRpc3BvcwpzdGVsbHVuZwriloFyZXRhaW4K4paBbWVudHJlCuKWgW5ldXQK4paBTmlnaHQKY2jDqQphdHRpCuKWgW9icmEK4paBc3VwZXJpb3IK4paBQ29uZ3Jlc3MK0ZHQvAriloFjb2RlcwriloFBbWEK4paBRWFydGgK4paBb3Bwb3NpdGUK4paBcG9vbAriloFEdW4K0LbQtdC90LjQtQriloEiJHsKaW52CuKWgdGD0L3QuAriloFBbmRyZXcK0YLQtdC70LXQuQriloFiecWCClVuaXZlcnMK4paBQW5ndWxhcgphbmltCtC00L7QstCwCkJVRwp1dGVseQriloFkcmF3aW5nCuKWgWdhaW4K4paBZm91cnRoCuKWgVByb2JsZW0K4paBc3VkZGVubHkK4paBw4QKb25uYQriloFLb250CuKWgUJpbGRlcm4K4paBa29ubnRlCsW+ZQpUcmFjZQriloFzZWN1cmUK4paBa3TDs3J5CuKWgWVxCuKWgWZvcm1hbAphbWVyaWthbgriloFBbmFsCuKWgVJld3JpdGUK4paBRG91YmxlCmNyZWF0ZWQKTlUKTURiCmFwZXMKVW5pcwriloFlc3BlY2lhbAp9KVwKZWRvbQriloFjYXRlZ29yClJldHVybgriloFIYW1iCuKWgVJpbwriloFNaXIK4paBR2VtZQphYmlsaXRpZXMKdHJ6CnVzZXQKaWVycmEKbmV0d29yawriloFkb2N0b3IKZXVycwriloFsaXN0ZW4K0LTQtgriloFIw7YK4paBY29uc2lzdHMKYXNtCkNocgphbGFuZAriloHQuNGB0L/QvtC70YwK4paBbHVnYXIK4paBZGVmaW5pdGVseQptb3ZlCsO6YmxpY2EK4paBbMOkbgppc211cwriloHQtNGA0LbQsAriloFkdAriloFQZXJoYXBzCuKWgUJyYXNpbApKb2huCuKWgXByb21pc2UKxYJ1CnJlZW5zCuKWgXBzeWNoCuKWgVdobwrRgNGP0LQK4paBSU5UTwriloFQZW9wbGUK4paBV2lsbGlhbXMK4paBTWFyZwriloHQtNCw0L0KcmVjb3JkCuKWgUV1cm8K4paBVmlyZ2luaWEK4paBUmVzdAriloFDb3JuCn19LAriloFHcmlkCuKWgWluamVjdArQvdCw0L0K4paBY3JvdwriloFQaHlzCuKWgURPCuKWgSItCuKWgWluY3JlYXNlZAphY2hlcgpwZWF0CkxpbgriloFEdWIKcmljZXMKYWdub3N0CmRsCuKWgWN1cnZlCsO8ZwpyaWNlCmxhbmd1YWdlCkNsaWNrTGlzdGVuZXIK4paBbXVuaWNpcGFsCuKWgU9yaQriloFCaWxkCuKWgUNhYgriloFWYXIK4paBbm90ZWQK4paBw44K4paBc3VicwppYXRpb24KV09SCmluZ2x5CuKWgVJ1cwppZW5zCklORk8K0LrQstCwCmF0aXZvCmdlbmRlCuKWgUZyYW56CuKWgWlzb2wKZWRlcwpuaWVyCuKWgU5PCuKWgUhhcwpiZWFucwriloFwYW5kYXMKKCIlCtCy0ZbRggrRg9GC0LHQvgriloFnYXRoZXIK4paBbGVnYWwKaW5jbHVkCuKWgWNpcmN1bXN0CmNyaXB0b3IKcmlibGUK4paBU8O8ZAriloFhcHJvCkFwaQriloHQvdCw0LkK4paBQWZyaWNhbgpvd3NraQriloFKb2huc29uCmllawriloF2b3RlCuKWgUthbgriloFiaWJsaQriloFoYWFyCuKWgXZyCl0pLApzdWJzZXRlcQpQYXJzZXIKaWFuaQppc8OpCmlkZWEKT25seQriloHDoWwK4paBQ2F0YWwK4paBQ2FzZQpzZWgK4paBZW5jb3VudGVyCuKWgXJlZm9ybQrQvNC40L3QuAriloFTdHJlCmV4Y2VwdGlvbgriloFUYXIK0YLQsNGACnRybAriloHQkNC70LXQutGB0LDQvdC0CtC70LXQutGCCmVxdWFsCk9wCuKWgWxpZgriloHQudC+0LPQvgriloF2b2x0YWdlCnNoaXJlCuKWgUdyb8OfCtCy0L3RjwpuaW5ncwrQvdGG0LgK4paBbGFnCuKWgWFuZGVyZW4K4paBdmFjCuKWgW1hY3JvCj1bClRoZW4K4paBY29udHJvbHMKc2VxCm9sb2dpZXMK4paBc2VsZWN0b3IK4paB0KPQutGA0LDRl9C90LgK0YXRltCy0L7QstCw0L3QvgrRi9C5CmFsbGVuZ2UK4paBSU1EYgp1bW15CnllbgriloFiZXN0ZQriloFCb3gK4paBY2hhaXIK4paBU2FiCmVyZGUK4paBbmFzdAppdmFtZW50ZQriloHQvtCx0YoK4paBcmVxdWlyZW1lbnRzCuKWgW1lZXRpbmcK4paBZmluYW4K4paBQWRhbQriloF0ZWxldmlzCuKWgWJyaWdodAriloFHaXQKRUcK4paBR2lsCnLDqHMK4paBQ29uZAriloFmdAriloHQsdGD0LvQvgotKwpFTkQKZXJuZQriloFDb21wdXQK4paBaWxzCuKWgWdhbGwK4paBY3N2CsWCdWcK4paBc3VtbWVyCmdhbWUK4paBcG9zdHMK0JDRgNGF0ZbQstC+0LLQsNC90L4K4paBemlqCuKWgWRldGVybWluCuKWgWFiYW5kb24KY291bnRlcgriloFyZXF1aXJlbWVudAriloFUaXQKaXJ0dWFsCuKWgVZpZGVvcwriloFxdWlldAriloFUZXJtCuKWgXRpbWVvdXQKUHJpbnQK4paBaW52ZW50CmxhaXMK4paBbW9uaXRvcgpoYWxiCuKWgVdpbGQK4paBbGVhZGVyCuKWgdGB0LXQu9GMCuKWgXV0aWxpegriloFwYXJlbnRzCuKWgWZvcmNlZAriloFwcm92ZWQK4paBZWZmZWN0aXZlCuKWgWxsYW0K4paB0KHQv9C+Cm9yYgpnZ2kK4paBYXNzdW1wdGlvbgriloFzdWJtCuKWgdCy0ZbQuQppbGlhCuKWgXJldmVyc2UKJyIK4paBcXVvdGVzCuKWgXNpdGVzCmlndW5nCuKWgUFyZwpEb3VibGUK4paBc2NyZWVucwriloFjbGF1c2UK4paBYnVuZGxlCuKWgXBoaWxvc29waAriloFOdW0K4paBZ2xlaWNoCnVseQpkaXJlY3QKYXNrZXRiYWxsCm93YW55Clx9JAriloFyYWRpdXMK4paBU2VhcmNoClByb3BlcnRpZXMK4paBZWxldgriloFwcm9kCuKWgSIlCmlzacOzbgpEZWJ1ZwpTZWNvbmQKKCEK4paBQ2F0aG9saWMK0YDQvtCy0LDQvQpsZXoKUGEKcHNvbgriloFlcnN0ZQriloFGdQriloFsaXQK4paBU2Fpc29uCuKWgUhhc2gK4paBZXhlbQriloHQv9GA0LXQtNGB0YLQsNCyCikqCuKWgWV1CuKWgeKUggriloFnYWIKZXRhaWxlZApDb3B5CuKWgdC00LLQsApldmVuCktpbmQK4paBSmFja3NvbgrQsNC7CuKWgWNvbnNlYwpVU0VSCuKWgVRvawooLgriloEkfAriloFUYW1iCuKWgUxlbW1hCmhhbmcK4paBY29udHJpYnV0aW9uCnJvbGxlcnMK4paBc3R1ZGllcwriloFwb2kKZ2VtcwriloFVUAriloFXb2wKPiIK4paBZmxvb3IK4paBaW5pdGlhbGl6ZQriloFMZXcKemVrCmFydGUK4paBcG9zaXRpb25zCuKWgXBvcnRpb24KY292ZXIKd3AK0L7QstC+0LPQvgriloFwaWFubwriloFtZXRhbAriloFzYW1wbGVzCuKWgdCh0LDQvQp2YXJpYWJsZQriloHRgdGC0LDRgtGMCuKWgWludGVnZXJzCldoZXJlCmZhbWlseQriloFudW4K4paBaW5jcmVtZW50Cml4ZWQK4paBaGVlZnQKZnRlCuKWgXZpbAriloFvdHJvcwpNdWx0aW1lZGlhCuKWgUhlbnJpCmFkZWQK0LPQtdC9CuKWgWNhcGl0CuKWgdC00YDRg9Cz0LjRhQppc3AKSVRZCuKWgWNvbnN0cmFpbnRzCuKWgUtpcmNoZQpmb3VuZArRiNC40LkK4paBcGljCuKWgXRvdQpjcmVkCtGA0L7QsQriloFNZXNzCkpvYgriloFNYWlzCuKWgXN0eWxlcwpmYWxsCuKWgVVrCuKWgXN0cmVldApvY2Nlcgplc2VuCuKWgWNvbG9ycwpjZWFuCtGO0YnQtQpjb25uZQriloFyYXRpbwphbnRvbgriloFGZWwK4paBY3VzdG9tZXIK4paBUHJpeApyw6FzCnByZWQK4paBZWxlY3Ryb24Kc3ltCuKWgdCy0LXQu9C4CuKWgW92ZXJmbG93CuKWgSRbCuKWgVBPU1QK4paBQ2luCnNjaGVpZAooIi8K4paBc2VhcmNoaW5nCuKWgXB1cnBvc2VzCuKWgWFycml2ZWQK4paBcHVudAriloFsYWQKUHl0aG9uCuKWgWxlYWRzCuKWgXNhbmQK0L/QsNC00LAK4paBY29tbXVuZXMK4paBQ0hBUAriloFjYXNvCnJ6CuKWgWR3CmFjYQriloFDb2x1bWIKY2hpbGRyZW4Kw6p0CnNjaGVtYXMK4paBaW5zdHJ1Y3Rpb25zCuKWgS1cCuKWgUlzcmFlbApub8WbY2kK4paB0L7QsdGA0LDQtwriloHRgdC+0LLQtdGCCuKWgWltbWFnaW5pCuKWgUZyZWQK4paBR2xvYmFsCuKWgXRoaWNrCuKWgWZ1ZXJvbgriloF0aHJvd24K4paBY2xvY2sKZW5hYmxlCicnJwriloFTdW5kCuKWgWNvbnRlbXBvcgphbnN3ZXIK4paBbWFudWZhY3QK4paBaW8KcXF1YWQKT1VUCuKWgUxhYgriloFadwpsZWdhbAriloFWZWwK4paBcmFpc2UK4paBZGVsaXZlcgriloFWb2lyCuKWgWFzc3VtZWQKTGV0CmllcnRlbgriloFLb25nCuKWgUV4cAriloFKdWcK4paBZGVjbGFyYXRpb24K4paBRmlzaAptw6kK4paBc3BlZWNoCuKWgXRlbnQK4paBUm91dGUKX18oCuKWgXLDqWFsaXMK4paBRGVzaWduCnNldFRleHQK4paBU3RhdGlvbgphcmNoeQriloHQutCw0YLQvgriloFkZW50CuKWgUtsCmnDnwriloFyaXNrCuKWgUJyb2FkCuKWgXZlY3RvcnMK4paBU3BlYwriloFyb3V0ZXMKeW1uCuKWgUdyZWcK4paB0L/QvtC70YPRh9C4CmdpZQpPUk0K0LLQtdC00LUKd2FsdAriloFlZnRlcgpQdHIK4paBc3VidAriloFiaXJ0aAriloFkcmF3bgptZXNzCtC80LXRgNC40LrQsNC9ClZFCuKWgVB1dAriloFhc2MK4paBZmVkZXIK0YHQu9C4CuKWgVByaW4K4paBc3RpY2sKcmVzZXQKeWsKc3R1ZGlvCuKWgVN0aWxsCkNvbnN0CmFjacOzCuKWgVBvcnR1Z2FsCuKWgXNjcmlwdHMKdW5kaWFsCuKWgWxpdmVzCuKWgXN6ZXIK4paBZXN0YWRvCmZvbGRlcgriloFjb21tdW5pY2F0aW9uClJvdXRlCuKWgXN3aWZ0CtGC0LXQvQriloFraWxsCuKWgVBSCmpvaW50CuKWgW9iamVjdGl2ZQriloFjb21wbGljYXRlZAriloHDnGJlcgplc2gKcGljdHVyZQpyYWluZQpjb21wdXQK4paBcHJvcG9ydApvZ3MKw7xsdAriloFxdWFudHVtCtC60YDQuAriloFzb3AK4paBbG9vcHMK4paBUmVmZXJlbmNlCuKWgW5laQpJQ0UK4paBdmVybQriloFhZGoK4paBcGVyw7IK4paBdHJvdQppc2lvbnMK4paBQXBwbGUKc2VydmFibGUK4paBQm9zdG9uCm9yZXQKb2tzCuKWgWtnCmRlZmluZWQKcGxhdGZvcm0KY2xlcgpvZ3JhcGhpYwpyaXR0CuKWgWRpYwriloFNb25kCuKWgUlyZWxhbmQK4paBVW5hCuKWgWNvbW1lcmNpYWwK4paBUHUKRGkK4paB0LXRkQriloFwcmVjaXMK0L3QsNGA0L7QtAriloFxdWF0cmUKdXN0cmFsCuKWgWRhZwppZ3VlCuKWgWJ1cm4K4paBb2ZmaWNlcgriloHQkNCyCuKWgWhpZ2hsaWdodAriloFTdXBwb3NlCm9kaQpzZXJ2bGV0CuKWgUVuY3ljCuKWgVJhbmdlCtGC0LjQuQpQbGVhc2UK4paB0YDQvtC60ZbQsgpxdWFudAriloFmbGF0CuKWgVLDqWbDqXJlbmNlCtGB0LvQtdC00L7QstCwCnJvbGUK4paBZGllc2VuCn19KAriloFJbmR1c3QK4paBbsO6bWVyCuKWgSI7Cmx1cwrDtGxlCuKWgXptCmRlZwriloFyb3VnaApJbnYK4paBaHVyCuKWgVJlc3MKY2hzCuKWgXR1cm5zCm5lcm8KZnVuY3Rpb25zCtCw0LvQuAriloFoYWJpdGFudHMK0LDRggppc3N1ZXMK4paBaHVnZQpVdGlscwriloFTYXQK4paB0LPQvtGB0YPQtNCw0YAK4paBY29hc3QKc2hhcGUKTEMK4paBbG9nZ2luZwplbmRvcgriloFsaWVzCuKWgWRpZmVyCuKWgWNyaXRpY2FsClhUCtC80LjQvdCwCmFuc2sKUmVzdWx0cwprYwppdmVyc2UKRVhUCkFMU0UK4paBdsOhbApQaQpjb21waWxlCmhlbGxvCuKWgdGH0LXQvNC/0LgK4paBSXRhbGlhCtC60L7Qu9C+CuKWgWVkaXRpb24KZ3J1bmQK4paBZGF0YWZyYW1lCuKWgUZvbGxvd2luZwpyZWliCuKWgUplZmYK4paBY2l0dMOgCklUYWJsZQriloEkKFwK4paBcmVkdWNlZApvYmlsCuKWgWFueXdoZXJlCicoCuKWgXBocgriloFLaAriloFGcmFtZQriloFtYW51YWwK4paBY3JhCuKWgVZTCiU9Ckluc3RhbmNlU3RhdGUK4paB0LHRgNCwCuKWgURyYWcK4paBSGVycgriloHQs9GDCuKWgW3DunMKVG9vbAriloFQcml2YXRlCuKWgXN5bmNocm9uCmlyYXRpb24K4paB0L7QsdC+CuKWgXR5cGljYWxseQriloFpbXBsaWNpdApvcmllbnQK4paBdGltZXIK4paBa8O2bm5lbgppZXN0CnJhaWQK4paBZXhwcmVzc2lvbnMK4paBYWltCuKWgXN0cmUK4paBd3JhcAriloFCYXJ0CuKWgWJyb24K4paBa2V5Ym9hcmQKcG93CuKWgWdydXBvCuKWgdGA0LXQt9GDCuKWgXByb2Zlc3NvcgriloFIZWFkCtC90L7RjgptaW51cwriloFNaWNoZWwKTk9UCm1vcgpdfQp3aWRlaGF0CmFyaXMK0YLQtdGA0LDRgtGD0YDQsApkZWZuCmlzdHJ6CuKWgXRhbnRvCuKWgVBvdwriloFpbmRpY2F0ZQriloFXaW50ZXIKcmVzaG9sZArRgNGW0LIK4paBYCgK4paBb3duZXIK4paBZGlzcAriloHQutGA0LgK0LzQtdGCCtC80LXQvdGCCnJlcG9ydApyZXF1aXJlCuKWgXZveQriloFBUAriloFFc3Bhw7FhCuKWgVPDo28KasOkcgpOb24KTGlicmFyeQppY2h0ZW4K4paBc3RydWN0dXJlcwriloFtdXkKw6FyaW8K4paBY2VydGlmaWNhdGUK0YfQvdC+0LPQvgriloFwcm92aW5jZQpwYWdlcwpkYWwK4paBRnJlZGVyCtGM0LUKRXhlY3V0ZQriloFhbmNpZW50CuKWgWZpbG1zCuKWgUFsZnJlZApBdXRvCuKWgWF0b20K4paBZWxsCuKWgUhhcnIK0LnQvQriloEiIwriloFuYWNpb25hbAriloFuZWlnaGJvcgrRgdGC0YPQv9CwCuKWgXdpdApQb3AK4paBR3JlZWsK4paBcmVwZWF0CmJhZAriloFTQwriloFEYXRlVGltZQrRiNGC0LgK4paBV0gK4paB0L/RgNCw0LLQuAriloHQotC4CuKWgXNhaXNvbgriloFIYXJ0CmRpcmVjdG9yeQp1YW4Kbm9ybQriloFQaGlsaXBwCuKWgXN1c3BlY3QK4paBYW5ubwpiYwrRgdC70LAKJCgK4paBYmVmaW5kCm9jcwpsYXRlc3QKOyI+CuKWgWFmdGVyd2FyZHMKUFVUCuKWgWphCuKWgUhpbAp5egriloFCb3VyCuKWgWxhaWQK4paB0JTQttC1CnBpZQp3YXRjaAriloFFcQpjb250YWN0CmliZXIKY2hlY2tib3gK4paBZXNwYcOxCmFuc2UK4paB0YjQutC+CmVmZgp4eHgK4paBR0VUCuKWgWxvdgppdHV0ZQp6ZWNoCnRlcmUK4paBcHVycwprZW5zCmlhbnRlCuKWgUZyZWUK4paB0L7RgNCz0LDQvdC4CmtyZWlzCuKWgXs6CnNoYXJlZAriloFHcmFwaAriloFjb25uZWN0aW9ucwriloFET00K4paBQ2FydApzc29uCuKWgUhhbWlsdG9uCtGC0LXQu9C4CuKWgXJlc3RhdXIKUmVzb2wKRHJpdmVyCuKWgWVuZgpFRElUCuKWgXByZXYK4paBaWsK4paBc8SDCmrDtgriloHQodCh0KHQoAriloFjb2xvdXIKY2h0ZW4K4paBZXN0YWQKaW5vaXMK4paBY29uZmlyCuKWgXbDqQriloFDZXMK4paBTmV2ZXIKb21lcgrQttC00LAK0YHQu9GDCtGH0LXQvdC40Y8KZGxsCuKWgXlvdXRoCmVtZW4K4paBc3R1ZGllZAriloFLaWwKY2lvbgriloFuYXZpZwpyZXF1aXJlZApvcml0aG1zCmlsb3IK4paBRGV1dHNjaGVuCuKWgXBlcnNvbnMK4paBQmFyY2Vsb25hCuKWgWZvcm1hdGlvbgphYmVpCuKWgdC/0YDQvtGC0LjQsgpFbmdpbmUKT05FCm9ncsOhCkNhcApyaXIK4paBZ2F0ZQpvcmF0aW9uCm1hdmVuCuKWgWNvbWJpbmVkCuKWgWF0dHIK4paBaG9vawriloHQutC+0YLQvtGA0YvQuQriloFzZXJ2ZXJzCnVjdHVyZQrQttC10L3QvdGPCnR2CuKWgXJlcQpqYWwK4paBbG9jYWxseQp9fXtcCkJyCuKWgUhpZXIK0LzQvtGACuKWgWFwYXJ0CiJdLAriloElPiUK4paBenVzYW1tZW4K4paBaWRlbnRpZnkK4paBQWx0ZXJuCuKWgdCx0YDQvgriloHRhtC4CmdoCuKWgVRlbgpSUwrRhNC+0YDQvNCwCuKWgW5lbGxlCuKWgUhpbgpvdW5kaW5nCuKWgXJlcHLDqXMKYXBoCuKWgVtcCuKWgVNwb3J0cwrRgNCw0LsK4paBdGhyZQriloFwcmluCuKWgUVsaXoK4paBRm91cgriloFzb2NpZXR5ClRyYW5zYWN0aW9uCuKWgXZlZwriloFzY2hvb2xzCuKWgW92ZXJhbGwK4paBdGFpbArDvGJlcgriloFTb3YK4paB0KHQtdGACuKWgXJhcHAK4paBdHJhZmZpYwpxdWVzdGlvbgriloFlbnZpcm9uCmF0ZWllbgppY3VzCuKWgW5hcnJvdwriloFwcmF5CuKWgUJvdQriloFDbGllbnQKYWJsCuKWgUF1ZGlvZAriloFucG0K4paBQ29sdW1uCuKWgUdhbWVzCmF2ZXIKb255bWVzCuKWgdCf0L7RgdC70LUKbsSFCuKWgU51CuKWgURpY2sK4paBdGVuc29yCuKWgUAiCnbDqQpJY29uCuKWgdC/0L7QtNCwCuKWgUdvbgovKS4KaXN0cmEK4paBQXVkaW9kYXRlaWVuCkRlbGV0ZQp9fX0K4paBanVtcAriloHQntCxCuKWgXByaW5jaXBsZQriloHDiXRhdHMKb2tlZAriloHQktC70LAKSW50ZXJ2YWwK4paBc2F1CmVuY29kZQriloFwb24KY2F0Y2gK4paBdGllbQriloFHdXN0Ck1DCmxpbWl0cwriloFrZWVwaW5nCuKWgXNvbmdzCuKWgdCw0LLQs9GDCuKWgdGA0LDQudC+0L0K4paBbm90aWZpY2F0aW9uCuKWgW9mZmVyZWQKQ29yCuKWgXNodXQKZXJyb3JzCuKWgUVOCuKWgWxhdGFjaAriloFzZWxic3QK4paBY2hlY2tib3gK4paBY29vbAriloFmYWN0b3J5CuKWgXBhaWQKZGltZW5zaW9uYWwKbmllagpwdG9uCuKWgXBpbgpha2VkCuKWgXJlbGkK4paBVGF5bG9yCuKWgVNvbWV0aGluZwppbXVtCuKWgVZpbgriloFpdGVyYXRpb24KRmluZArQutC+0LLQuAriloFib3lzCuKWgVNpbXBsZQriloFDcmlzdAriloFXYXMKw6JuZAriloFWYQriloHRgtGA0LAK4paBZGVzdGluYXRpb24KbGltcAriloFLYXQKd29ydGgK4paBS29yCmnDp8Ojbwo9YAriloFmYWlybHkKZmFsbHMK4paBcmVqZWN0CuKWgWRyZWFtCmJlbGwK4paBdG91dGUK4paBJFx7CuKWgXN0b25lCuKWgXByb3RlY3QK4paBZXhjZWxsCuKWgU1leGljbwriloFkYXNoCuKWgWZhdWx0CnBtYXRyaXgKYWxsZXIK4paBZ3VlcnJlCm9yaWdpbgpoaWJlcm5hdGUKw61saWEK4paBUmVnaXN0ZXIKdW50bwriloFCYXQK4paBYm93CtGB0YzQutC40YUKZXTDoAriloFMdWlzCuKWgWZvdQriloFDYW1icmlkZ2UK4paBb3R0CnN1cApyZWFzCuKWgXBvaW50ZXJzCuKWgUJvYXJkCuKWgdGA0LgK4paBZHJpdgrQvdC40L0K4paBQ2lyYwriloF0aG91CkRpdgpzcGFyawpsYW1lbnQK4paBVkFMClNlbmQK4paBSXJpc2gKb3kK4paBVHUK4paBdHJpdmlhbApGb3JtcwriloFhc8OtCuKWgUltcGVyCuKWgXNpZ25hdHVyZQp1bm9zCuKWgU5lZwriloFjYW5jZWwK4paBSGVpbnJpY2gKZWVkCklsbHVzdHJhdGlvbgriloFzdWxsYQriloFxdWFydGVyCmFzegriloFibG9nCmZpY2EKd29uCnF1ZXQKXSkpCuKWgWdlbmVyYXRpb24K4paBY2F1Z2h0CuKWgWxhbmRzCuKWgUtpbmdkb20Kc2NoYWZ0ZW4Kcm9ucwphbm5lbHMK4paBU3BlY2lhbAp0dXRvcmlhbAp0aXAK4paBIiIsCuKWgUF6dXJlCuKWgWJvdW5kZWQKU20KdGFyCtCy0LXQvQriloHQt9C10LwK4paBbm90YXRpb24K4paBYXBhY2hlCuKWgWdhegppZXJubwphbmdlbgpwZWN0aXZlCuKWgWVsZWN0cmljCuKWgXNlbWkKTUFYCmVkZXJiCm9iamVjdHMK4paBZGlmZmVyZW5jZXMKaXN0ZWQKaHJlZgppY2lwCuKWgW51bXB5CuKWgdGE0YPRgtCx0L4KbG9hZGVyCuKWgWRpY2gK0ZnRgwriloFEw6kKSHoK4paBUGFyYW0KZG9jdW1lbnRhdGlvbgppcmNyYWZ0CkVNCuKWgWluc3RpdHV0aW9uCmNvbXBhdAriloHQsNC70YwK0YHQu9Cw0LIK4paBTmV0CtGG0LjQvtC90LDQu9GMCuKWgWJyb2FkY2FzdApkYXRldGltZQphc3luYwp2cmUKbWVhbgriloFDaGVtCuKWgWVzdGltYXRlCmljYW5hCuKWgWdyZXAKdGVrCsOkbQpvcmlnCuKWgVZpY3Rvcgp1dGVuYW50CmFuZ2EKcGluCuKWgXZlcnRleAriloFDSEFQVEVSCmNpdHkKdWdieQpncmVlbgriloFLZXIK4paBZGlmZsOpcgriloFuZWNlc3NhcmlseQpEQwpMaW5lYXIKYWxlbQriloFMYXRlcgriloFtZXRhCmplbQpyYWdlbgpNYXkK4paBTWl0Z2xpZWQK4paBc29ydGVkCnVzc2VuCuKWgXNwb2tlCuKWgWRpc2FibGVkCuKWgWFjY29tcGxpc2gK4paBUnVzc2lhCnRoZXJlCmVlcwriloFoYWxsCuKWgW1ldHJpYwphdHRyaWJ1dGUK0YLQvtCz0L4KYWJvdXQK4paBTGFtCmNoYW5uZWwK4paBZXBpc29kZQriloEkKCcuCuKWgW91Z2h0CuKWgUVzdGUKT2JqZWN0cwriloF2YWxpZGF0ZQriloFyaW0K4paBbnVtZXJvdXMK4paBSmF2YXNjcmlwdAriloFHTAriloFJdGFseQplZGVyYsO2cmQKb25hdG8KYm9va3MKc3RvbmUK0YXRgwriloFqZWwKaXJpCuKWgUFTUApHQQriloFzdGF0YQriloFiYXoKRGF5CnRobQpkaAriloFGaWxlcwpBbmRyb2lkUnVudGltZQriloFjaGVja3MKa3IK4paBdmVubmUKU0wKYXZpYQprYXp5CuKWgVRocmVlCkFkbWluCuKWgWNvbGxlZ2UKR2xvYmFsCnRpb24K4paBY3VyaW91cwpzaG9ydAriloFiYXNzCtC00LXQu9CwCuKWgdC00LXRjwpTY2hlbWEKJ1wKZGlmZgriloFDQQriloFDb3Jwb3IK4paBb3BlcmF0b3JzCm9tcsOlCuKWgWVkZ2VzCik7YAppbmRzCuKWgWdpbmcKJiYKfS1cCnJhbm8K4paBc8OjbwriloFhZGRzCmVsb3IK4paBdW5zaWduZWQK4paB0L/RgAriloFDb25maWcK4paBRXNjCuKWgWNob3NlCuKWgXBpZWNlcwriloFyZWdpb25zCkVzdAriloFCYXR0bGUK4paBZm9jCuKWgUxpZ2h0CnBhZGRpbmcKYWJlbgriloFldXJvcAppbGxvbgriloHQtdGB0YLRjAriloFib3JkCuKWgdC+0YLQvdC+CuKWgUhvbmcK4paBdnVsCnBsdWdpbnMK4paBJzwK4paBa3VyCnJlZ2lvbgriloFSZXB1YgppY2hlcgp9X1wK4paBbWVkYWwK4paBTW9yZW92ZXIKQkkKQXYKdXRlcgriloFzY2FuCuKWgU11bmljaXAK4paBY29udHJhc3QK4paBSWcK4paB0LPQvtGA0L7QtApyZWxhdGVkCmFsaW5nCuKWgdC80LDRggrDvG5zdAriloFDaHJpcwp3eQriloFBY3R1YWxseQriloFVbml2ZXJzaWRhZApFdmVudExpc3RlbmVyCuKWgXRlbXBvcmFkYQriloFhc3NpZ25tZW50CuKWgU1pa2UK4paBd8OkaHJlbmQK4paBxZt3aQriloHRgdGA0LXQtArQutCw0LTQtQriloFjYWxjdWxhdGVkCuKWgWVsbGVyCuKWgUFzaApyaWVsCuKWgWhhcmR3YXJlCuKWgWludGVucwooJy4KaWxsaQphZ29uCuKWgUd5CuKWgWhldXRlCuKWgXNsZQriloFsaXRlcmF0dXJlCnNlbQptYW5hZ2VyCuKWgUdyYW5kZQriloFtaXhlZAriloHQktC10YAKw61jw60K4paBc29pdAriloF3ZWxjb21lCtGH0LXQvdC40LUK4paBVW5pdmVyc2l0w6R0CuKWgWJ1aWxkZXIKc2ltcGxlCmljb2RlCsWZZQppbmRlbnQKb3BvCuKWgWFkdmFuY2VkCnRlbXBlcgplZGdlCuKWgWRhdGV0aW1lCuKWgWRvbmMK0LvQsNC90L3RjwriloF2ZXJkCtC00L3QvgppdG9zCuKWgWhlYXQKdmlzaWJsZQptZWwK4paBR2lvdmFubmkK4paBdmFyaWV0eQriloFyb3V0ZXIKVmVjdG9yCuKWgVdhbGsK4paBb2J2aW91c2x5CmhlaW4KRmluCklUYWJsZVZpZXcKWWVhcgriloFFY29ub20K4paBdmVsb2NpdHkK4paBQ2l2aWwK4paB0ZgKYWxlcnQKSWRlbnRpZmllcgrDqG5jaWEK4paBbm9ybWFsbHkK4paBRWd5cHQK4paBY3R4CuKWgVZlcmVpbgriloFIdQp1bHR1cmUK0L3QuNGC0LUKbMOpCuKWgVdpZW4K4paBUHJ6CkJ5dGUK4paBbmFoCmlzbXMK4paBUHVibGlzaAriloFIZXJ6CmljdWwKcGlzb2RlCtGH0ZYK4paBZGllc2VtCmvDtgpWaXNpYmxlCuKWgXJpZwpgKS4KUGFyc2UK4paBSmFjcXVlcwpOSQriloFnbGFzcwotLS0rCuKWgWluaXRpYWxseQriloFrcgpDQ04KcGxheXMK4paBc2lndQpGb2xkZXIKc3RvcmFnZQriloFcfAppdm9zCtGB0LrRg9GOCuKWgU1vaAriloFDb21taXR0ZWUK4paBS2ltCmV1CtGC0LXQvAriloFvcmlnaW5hbGUKaXJzCuKWgVJlYgppdHV0Cm5sCuKWgVBpZXIK4paBXTsK4paBRmFsCuKWgSIiOwptdmMK4paBZmVtYWxlCuKWgWJyaWRnZQriloF0w610Cmt0cgo+KQriloFzZWF0CuKWgXZlc3MK4paBVVNCCuKWgUFydGljbGVzCuKWgURlc2NyaXB0aW9uCuKWgW9jCuKWgWhvdXNlcwriloHQn9C10YIKbG9uCk5vdGlmaWNhdGlvbgriloFwcmVzc3VyZQriloHQutGD0LvRjAppZ25lZAriloFyZWxpZ2lvdXMKZmFuCmlnbGlhCuKWgWNsYXNzaWZpY2F0aW9uCm9nZXRoZXIK4paBU0RLCuKWgUh1bWFuCuKWgWNvbW1pc3Npb24K4paB0J7RgAriloFhbnRlcwpEVArDqHRlCnByw6lzCi8iCuKWgSjCqwriloFow7YK4paB0YfQsNGBCuKWgWphawppZW5lbgp1Z2cKV0EK4paBcGxhY2Vob2xkZXIKV2lsbAosLAriloFLYW0K4paBd2VuCuKWgVNjaHVsCsibaWUK4paBYXVkCuKWgXN1ZQriloFyZWZlcnJlZArQstCw0YIK4paBUGFyYQriloFibGEKVUVTCuKWgXN0YXRpc3QK4paB0YLRgwriloFXYXJzemEKZ3VlCuKWgUlkZQptYXRoc2NyCuKWgWxpZXUK4paBYm9kCuKWgXJ1cwriloFib2F0CnhzcGFjZQriloFtb2RhbArQu9C10LoKdG9waWMKbWFueQpza8O9CuKWgW9yZ2FuaXphdGlvbgriloHQs9C10L3QtQriloFXaWxzb24K4paBY29tZm9ydAppYmlsCjotCuKWgWFuaW1hbApSZXBvcnQK0LrQsNC80LgKam9uCuKWgWtlcgriloHQutC90LgKbW96aWxsYQpQcmljZQphbnRpbgplbWVudG8KbWF5CuKWgWx1bmcK4paBYmxvdwplZGV1dAriloF0eXBlZAriloFkZWNlbWJlcgriloEuLi4uCmxpYW5jZQriloF2aWVsCuKWgdCk0LgKcHJlc2EK4paB0L7RgdGW0LEK4paBTmFtCuKWgUdyZW4K0YHQuNC70LDQvdC90Y8KVklECnN0cmUKd2VpcwriloFwcm90ZWN0aW9uCnRhaWVudAriloFvZmZpY2VycwrRgtC90L4K4paBQnJpZwriloFpbnRlbGxpZwrRj9GFCklUSAriloFzZXBhcmF0ZWQK4paBTENDTgpuw61tCmNsb2NrCuKWgWFwYXJlCtGP0LLQuAriloFFbGl6YWJldGgK4paBV2F0ZXIKZ2ViaWV0CuKWgWNvbnZlbnQKZnVydAriloFiZWlkZW4KYmFzaAriloHRh9C10YDQtdC3CuKWgXViCuKWgVN0YXRpc3QK4paBbGltaXRzClZvbApjdHgK4paB0L3QvtCyCmd1aWRlCm1pYwppZXNhCuKWgWh1dnVkClJUCkZpZwriloFsZWN0CmNvbm4KaW1pdArQs9Cw0YAK4paBYmFqbwpzY3JpYmUKcmVnZXgK4paBQ2FzcwriloFwcm9wYWcKJyQK4paBcHJvZmVzCnVuaXF1ZQriloFTcWwKdW5pb24KcmlvcwpwaXAKLS0rCmthZGVtCmNvbHVtbnMK4paBdmFyeQriloFiZXJlaXRzCuKWgWRvaQriloFDb21tb24K4paBUm9iaW4K4paBw5cK4paBc2VpCuKWgXN5c3QK4paBdsOkCuKWgURlZmF1bHQK4paBdHltCnBlbAriloFiZWxpZXZlZAriloFwcm92aWRlcgriloFtaW5pbWFsCtGC0LDQu9C4CmFpbmVzCktpdAppemlvCmlzc2VuCnByZXNzZWQK4paBc3RhZwriloF1aW50CmtvcgriloHRgNCw0YHQv9C+CuKWgWluaGVyaXQK4paBY29tcGlsZWQK4paBZmVicnUK4paBdG1wCndvcmtzCtGH0L3QsApkcmF3YWJsZQriloFOYXYK4paBdGhvdWdodHMKcm91dGUK4paBY29uY2VydAriloFvcHRpb25hbAriloFicmFzCuKWgXByb3ZpZGluZwrRgdC+0LwKaWR4CmVtcGxvCuKWgdC60L7Qu9C4CuKWgUJlcmUK4paBRWxzCtGA0LXQvNC10L0K4paB0LTQtdC60LAKY291dApsYXllcgriloFnbG9iCmZvcmVhY2gK4paBRWR1Y2F0aW9uClBPCuKWgWltcHJvdgriloFjbGllbnRzCmdyb3VwcwriloFrb250CkRlbApyZXR0CuKWgXN1cAriloFtb2cKdGFuCuKWgWNvbXBsCmlydHkK4paBbm91dmVhdQpvc3oK4paBTmF2eQpiZXJlCm1hc2sKb3bDqQp6aWwKUEVSCuKWgXBvYmxhY2nDs24K4paBZGV0YWlsZWQK0LvQtdGCCuKWgWZhbWlsaWVzCmFiZXQK0LXQstC40YcKw6RuZGVyCuKWgcOlcgriloFwZW5kYW50CuKWgWJpbAriloFoaW50Cm9kZW4K4paBZXhwYW5zaW9uCuKWgXBvbnQKYXNhbnQK4paBS2luZAppamkK4paBQXV0aApsYWltZWQKcmVmbGVjdApdPQpieXRlcwpob3ZlcgriloHRhtC10YAKZ3JhZGxlCkFyY2gKYXBlc3QKw6FzYQpDYXJkCuKWgXRlbXBvcmFyeQriloFkw6lwYXJ0ZW1lbnQKY2xhc3NlcwrQttC40LLQsAriloHRhdGD0LTQvgriloFtb2xlClJZCkxQCuKWgXBlYwpyb2R1Y3Rpb24K4paBR3VhcmQK4paBUGFybGlhbWVudAriloFpbnN0YW50aQriloFub3RhbW1lbnQK4paBRG91ZwriloFNYXJzaAoufgriloFcIgriloF0aMOpCuKWgWxpYnJlCmRvZXMK4paBZMOpYnV0CuKWgVVuaXQK4paB0YHRgtGDCuKWgWxlYWd1ZQriloFxdWFsZQriloHRgdC+0YHRgtCw0LLQu9GPClNlY3VyaXR5CuKWgWFwcGFyZW50bHkK4paBdHJvb3BzCmljYW5vCuKWgU1CCmVuemUKbG9hZGluZwriloFkaXN0cmlidXRlZAp3cml0ZXIKcmVzb3VyY2VzCmjDtgp1dGlscwriloFwcmVwYXJlZApjaWVyCm9wb2wK4paBbMOkbmthcgpoZXMK0L3QstCwCuKWgW9wZW5zCmFnb2cKaW50ZXJmYWNlCuKWgUZ1bmQK4paBcGVudHJ1Cm7DrWNoCuKWgWNvbmZpZ3VyZWQK4paBV2Vic2l0ZQriloFsaXN0ZW5lcgppdmVsCm7EmQptaW5hCuKWgWludmVzdAriloHQvNGW0YEK4paBZGF2CuKWgXBhdGNoCnBpZWxlcgriloFFeHRlcm5hCnRmCuKWgWVyZWQK4paBQXNzZW1ibHkK4paBc291dAriloF2ZXJrCm1lcnMKdG9nZ2xlCuKWgXVwZGF0aW5nCuKWgUtlbnQKZWNhCkZBVUxUCuKWgXRpdHJlCuKWgUtlbm4K4paB0JzQuNGF0LAK0YHRgtC+0YAK4paBcG9kZQriloFTZWIK0YbQtdCyCkVZCuKWgXNpbHZlcgriloFjYXBhY2l0eQriloFjb21wbGV0aW9uCuKWgVBlZHJvCmZlbAp2YW5vCnpldWcK4paBaW50ZXJpb3IK4paBUmVzcG9uc2UKw6lkaWEK4paBV29ybGRDYXQK4paBY8SDCnF1ZWwKU29sCtGW0YHQu9GPCuKWgURvbWluCuKWgWN1bQpjZXAK4paBTXVzZQriloFNYXLDrWEK4paBZnVuY3Rpb25hbAriloFhZGFwdGVyCmNvbmZpZ3VyYXRpb24K4paBdGlwbwriloFCcnkKdnkKVUwK4paBdHJhdmVycwohKAriloFhYnNvbHV0ZWx5CtC70YLQsArRgtGC0Y8K4paBSVQK4paB0LLQvtC10L0KeWNsZQpiZXN0CuKWgWNvbnN0cnVjdGVkCuKWgdGE0LjQu9GMCmNpZG8KZXhpdApnYXJ0CuKWgXByb3ZpbmNpYQp2ZXoKY2lwbAriloFGYWNlYm9vawriloF5ZWxsb3cK4paBU3VtbWVyCuKWgXBvaW50aW5nCuKWgXBvc3NpYmlsaXR5CuKWgWxlZ2lzbAriloHQvNC+0LYKZGVybgrQutC+0L3QvgriloFtZWNoYW5pc20K4paBQmVybmFyZApleHByCtC70L7QstC4CuKWgWRpZ2l0cwriloFkZWxlZ2F0ZQpvZ3JhbQriloFEaWN0aW9uYXJ5CmlzeQriloFzcG8KLyQKY2x1ZGVkCuKWgU1WQwriloF0w6ltCuKWgXByaW50ZWQK4paBR290dAriloFPbQphbnNhcwriloFEdXJjaAriloFJZGVudApRVQpodG0K4paBU3VsCiddLgriloFkdXR5CuKWgUF1dGhvcgriloFuxJsKb3dlZ28KcHVzCmVtYmwKRXhlY3V0b3IKQkwK4paBTWVucwpkaXNwYXRjaAriloFNaWQKYXBwcwpUcmFuc2Zvcm0K4paBRGF0CuKWgWltcGwKb3V4CmhvbG0K4paBSW5zCuKWgUVtcGlyZQrRgNGD0L8K4paBQXBhY2hlClNJT04K4paBcGFzc2FnZQojIyMjIyMjIyMjIyMjIyMjCuKWgWV4cHJlc3NlZArQvdCw0LQK4paBb2wK4paBaGF2aWEK4paB0LHQvtC70LXQtQriloFlbmpveQpmb3JtYW5jZQriloFkaW1lbnNpb25zCuKWgdGH0LXRgApTZWUK4paBbW91dGgK4paBZ2F1CmllbmN5CuKWgUNhcm9saW5hCkRpc3QKcmFkaW8KbGltaXQKLz8K4paBQmFsbArQvdGW0YHRgtGMCk1lbWJlcgp3YXRlcgriloFtdXJkZXIK4paBc3RhbmRpbmcK4paBVklJCkNlbnRlcgpwcGEKdXJlYXUK4paBTGVpcAriloFvYmpldAriloFBY3Rpdml0eQplbWJlcnMKdnIK4paBY29uZHUKQ2VsbHMKaW51cwriloEnLAriloFhZnJhaWQK4paB0YXQsAriloFWaWMKdGVzdGluZwpUdWJlCuKWgXZhc3QKUE0KbmloClNTTgriloFDaGlsZQp5bHZhbgriloFCb3cK4paBcmVsaWdpb24Kb3BoZXIK4paBQ29sbAriloFkaWdpdGFsCnppb25pClNlY3Rpb24K4paB0YDQtdC30YPQu9GM0YLQsApGb290CmNvbnZlcnQK4paBcmVjZWl2aW5nCkNvbnRhY3QK4paBaGVybwpzYW0K4paBcG9zdGVyaW9yCm93aQpBbnQK4paBZmxhZ3MK4paBWmVhbGFuZAriloFib3VuZHMK4paBd2hlcmVhcwppbmZsClBsYXkK4paBZGVtbwriloFnaWJ0CuKWgWhvc3BpdGFsCuKWgXZvbHRhCtC70ZEK4paBZmFzaGlvbgriloFleGNlZWQKZWxlbml1bQpJdGVyCmtyaWUK4paBaW50ZWdyYXRpb24K4paBT3RoZXJ3aXNlCmFkdQpTaGUKb25kZQp1aW50CnJhZGl1cwriloFyYW0K4paBw6FsYnVtCuKWgdGC0YPRgAriloFkeQriloFPdHQK4paB0L/QtdGA0LgKcmV2CnJpb3IKw61kCmlyYXQK4paB0LLQutC70Y4K4paBaW1wb3J0YW50ZQriloFEdWtlCuKWgWNhdXNhCuKWgU1hdGhlbWF0CuKWgWRpcGxvbQriloFOaWNvbAriloFleGNsdXMK4paBZGVidWdnaW5nCuKWgUdoCm9yaWdpbmFsCmx5bgriloFQbGEKc3VpdGUKY2hhdAriloFlc3R1ZAp1ZWxsZQriloFwZXJ0CuKWgWltcG9ydGFuY2UK4paBYXBwcm9hY2hlcwriloFkbGEK4paB0L/RgNC+0YQKUHJlcwo8XApwcmVmaXgKU1NJT04K0YDQvtC00LgKY291bnRyeQppdHplcgriloHQutC+0YAK4paBc2luZ3VsYXIKZ292CtGA0LjQvQriloFGQQriloFtYXRyaWNlcwpvbGFyZQpuaWthCnBvd2VyCmxsYQriloFkZXNpcmUK4paBZmFtaWxpYQrQtNC+0YAK4paBZmFuCmdlbmVyYXRlZAriloFDb3MK4paBxbxlCuKWgURpZXNlCm1vdgriloFkZW5vdGUKIildCm91dmVybgphbWFuCuKWgWluc2VyCmlqawpvdHRhCmVyYWwK0LTQtdC70YwKKCktPgriloFwb2RlcgppZ2VzCuKWgU9ubGluZQriloF3ZWlyZAppYWMK4paBcXVlbHF1ZXMKw6hyZW50CuKWgXRlbAriloFMYXRpbgp2ZXJ0ZXIK0LvRj9GACtGA0L7QuAriloFwZGYK4paBa2V5d29yZApIYW5kbGUKQWZ0ZXIKcmVjZQriloFpZGVudGljYWwKc3R5bGVzaGVldAriloHRgdGC0LDQvdC+0LLQuAriloFrYQpjZW1lbnQK0YLQtdGCCuKWgWNoYXQK4paBTXVuCmHFgmEKQU5UCm9sw7NnCuKWgWZhbnQK4paBZm9yZXN0CuKWgdCy0LjQutC+CmN1c3MK4paBc2VocgpwYWcKb3RpYwriloHDoWxsCtC80LDRgtC4CuKWgSInCisiCkFuaW1hdGlvbgrRhdC+0LTQuNGCCmF6dQriloFwbGF5cwppemlvbmkK0LzQuNGH0LUK4paBYm9tYgriloFtZXJlbHkK4paBaG9sZGluZwriloF3ZW5uCuKWgW1lZGljCuKWgXNwZWFraW5nCm9uZ29kYgriloFDYW1wZQppbml0eQriloHRj9C90LLQsAooKWAuCmx1c3MK4paBSGlzdG9pcmUK4paBb3BlcmF0aW5nCkNoYW5uZWwK4paBYWNjdXJhY3kK4paBYm9zCuKWgWV2aWRlbnQK0YbQuNGOCmV2ZW50cwp0ZXh0cm0Kb3JlaWduCuKWgWlpCmhyZW4KbG93ZXIK4paB0YLQvtC8CuKWgUFib3V0CuKWgWFqCmVyaQrRgdGC0YPQv9C4CuKWgWRpZ2l0CuKWgVNwYWluCuKWgURhdGVuCuKWgWZvcm1lCuKWgdGI0YLQsAriloFCYWNoCm5vbnVtYmVyCuKWgXJlY29tbWVuZGVkCuKWgXJlYWRzCmhpc3RvaXJlCuKWgXNhbmcK4paBPz8K4paB0YHRgtCw0LsKc2NvcmUKZmFzCuKWgWN1YgriloFncmV3CuKWgWNlbnRybwriloFiZWthbm50CkV2ZW50cwpCRVIKaGV3CtGB0YHQsAriloFtYWpvcml0eQrDrnRyZQplbmNpCuKWgVF1ZXJ5CuKWgWt0w7NyZQppxIcK4paBY29tcGxleGl0eQriloFGcmFuw6dvaXMKY29uc3RyYWludArRg9GA0L3QsArilZDilZAK4paBaXRlcmF0ZQpsZXR0CnBlcm9yCuKWgU5lZGVybGFuZApzaGFyZQriloFpbmNsdQrDpG5nZXIK4paBTmljCtGH0L4KRnVsbAriloFyYXBwb3J0CmVjbGlwc2UK4paBaW5kdXN0cnkKaGVhZGVycwriloHQoNC4CmNoc2VsCuKWgXBvbGljCnNjaGllZAolLApPRAriloFKYWsKKHtcCmFsaWduZWQK4paBZnJlcXVlbnRseQriloFzdW9pCuKWgWVzc2VudGlhbGx5CuKWgVJpYwriloFyZXBvcnRzCuKWgWRlY2ltYWwKcmFyCuKWgUZvbwriloFLYQriloFEQwriloFzaW1wbGVyClBhbmUKP30KU29ydAriloFwb3NpdApjZG4Ka3R1cgriloFhd2sK0LfQtdGAClBGCnV1cgriloFSb3NzCuKWgW1hbnQKTmEKQ29ucwopKSkpCuKWgXRlY2huaXF1ZXMKaW1wbAriloFkcm9wcGVkCuKWgUxpc3RhCuKWgUJhc2ljYWxseQplbnRhbAriloFjZWx1aQriloFzdHJhdGVneQriloFXYWxlcwpuYW4K4paBZ21pbgriloFncsO2w58K4paBZWVyc3RlClRpbQpudGVuCnJlc3AK4paBc3RhYmxlCm5vdgpyb2IK0L3QvtGYCuKWgW1hcnJpYWdlCmdldFN0cmluZwpBdXRob3IK4paBR3JhZgriloFkaWFncmFtCmdpYQpOZXR3b3JrCuKWgWNvbXBvc2VkCuKWgW1pc3NlZAriloFNZWcK4paB0L/RgNCw0LLQvgriloFob21vbnltZXMK4paBQm9va3MK4paBZW5jb3UKcG9ydGUK4paBcm90YXRpb24K4paBZmlyCtGC0LXQu9GM0L3QvgriloFndW4K4paBQWZmCtC90L7QugriloFGdcOfYmFsbAriloFTdG9yeQriloFDaGFwCuKWgSkuCuKWgVNlaXQK0LzQvtC9CuKWgXTDqWzDqQriloFjb3BpZWQK4paBY29uc2lzdGVudAriloFkcmluawriloFDaGFtCuKWgW1hdHRlcnMK4paBcmVuZGVyZWQK4paBaHlwb3RoCsWTdXYK4paBbWVlcgriloFwYXJzaW5nCuKWgVBSTwpzZXJpZXMK4paBesOhCnN0cmHDn2UK4paBQm9vdAriloFyZXBvCndvcgriloFTdHJlYW0K4paBQU4K4paB0L/RltCyCuKWgVNNCuKWgUFybgriloHFvQriloFbXTsKUmVzb3VyY2VzCuKWgWVsYWJvcgriloFFdGgK4paBbGlzdGUK4paBcmVsYXRpdmVseQpjaGFudAo9IiIK4paBbGlmdApDTgpTZXJ2aWNlcwpNRU5UCuKWgdC40LPRgNCwCtCx0YDQtQriloFKb3JkCuKWgXRlYwrRiNC60LAK4paBU3VwCuKWgWluZmx1ZW4Kb25kcwpoYW5kbGVyCuKWgWJhbmRhCuKWgXZlcnRpY2VzCuKWgXphcAriloFjb3JkCmFsdGVyCnplbmlhCsOidGVhdQriloFrbm93aW5nCuKWgUFyZ2VudGluYQpBcmVhCtCw0L3QtQpmYwo9Ii8K4paBTWlrCmF0xIMKaWV1eAriloFkZXV0c2NoZW4K4paBdHJhZGl0aW9uYWwKZGVjb2RlCnZleAriloFzaXplb2YK4paBRnVuCuKWgXBhcnNlcgriloFGbG9yaWRhCuKWgWJ1aWxkaW5ncwriloFNYW51ZWwKcmlsZQriloFsb2dnZWQK4paBc3Ryb25nbHkK4paBcmV2b2wK0L3QtdC1CnhpY28K4paBRmFpcgpjYXJ0CuKWgVdvcnQK4paBSmVzdXMKZW1lcwpzY2hyaWZ0CklucHV0U3RyZWFtCndhZAriloFncmFuZGVzCuKWgW7Dum1lcm8K4paBT3R0bwppZW50ZXMK4paBZmFtb3VzCm9sb2duZQpKZQrQvdC40YgK4paBR3VlcnJhCmJhcmEK4paBY2FkCmVsdmUKYnJhY2UK4paBSnIKc3RhYmxlCkVDVApsZW1tYQptZWRpYXRlCuKWgXZpbgriloFtb251bWVudAriloFjdgriloF3aW50ZXIK4paBdHJhbnNmb3JtYXRpb24K4paBTmljawpzdHJvbm9tCuKWgWZyYWcK4paBaW50ZWwKcmFjdGlvbgriloFjb25zaWRlcmluZwriloFGbGUK4paB0LvQvgriloFBcHLDqHMK4paBQU0K4paBSHVtCuKWgW11bmRvCk5FUgriloFCZWxvdwriloHQs9C+0YDQvtC00LAKYXJ0ZXJzCi0tIgriloHQn9C1CsOudAriloF0eHQKYW5nZXJzCuKWgXRoeQpDTEEKaWJsZXMK4paBcmVxdWVzdGVkCuKWgUFsZXhhbmQK4paBZmFjdG9ycwriloFwcm9kdWNlcwpuaW5nZW4K4paB0YHQvtGB0YLQvtGPCuKWgW9wdGltaXphdGlvbgpjaG9kCj5gCuKWgVdpa2lwCm5vc3RpCuKWgWNvbXBldGl0aW9uCuKWgUhhbm4K4paBem9uYQpkYwpkZXNpZ24K4paBWnUK4paBZXNwZWMKZXF1YWxpdHkK4paBQWJiCuKWgWRldmVsb3BlcgriloEiXgriloFTaG9ydAriloFwbGFucwriloF2aXQKaXphYmxlCmJ1cmdoCmFnZW0K4paBUHJpbnQKw612CuKWgXN1aXRhYmxlCnBpY2tlcgpQcm9maWxlCmFuZHkK4paBcXVvdAriloFEdXJhbnRlCuKWgUZyYW5jaWEK4paBdGFydAriloFWZW5legriloFkaXNwYXRjaAriloFvYnNlcnZhdGlvbnMK4paBxbwKSW52YWxpZAriloFvY2N1cnIK0YLQutC4Ck1lbWVudG8K4paBU3lkCuKWgXRpZW1wbwriloFzdGFmZgriloFzZWN0aW9ucwriloFzc2gK4paBTkdDCsOrbAriloFlcnJlCuKWgWRpdmlkZWQK4paBV2l0aG91dAriloFkdXJhbnQK4paBamFhcgriloHiiJIK4paBc29sZGllcnMK0YPQvdC6CmxhcHNlCuKWgVZhbGxleQriloEoOgpyZXJhCuKWgWTDqXZlbAriloFww6lyaQriloFjYWxjdWxhdGlvbgriloFrZWluZQplcnRhaW4K4paB0YLQtdC70LUK0YDRg9C0CuKWgWN1bAriloFjbG90aAo7fQriloFwcnplZApNb250aApQaWNrZXIK4paBU1YKYXJpYW4K4paBUmV2aWV3CuKWgWhhbmcK4paB0L7QutGCCuKWgUZyb250Cm90bGluCuKWgXRyYW5zbGF0aW9uCuKWgW1vZG8K4paBc3RhdGlzdGljcwriloFOdWUK4paB0J3QuNC60L7Qu9CwCk5VTQriloFzaGlwcwriloFSZXBvcnQKe1sKRWZmZWN0CmllcmkK4paBcGFydGllcwpwbGEKcncK4paBV29ya3MK4paBaXJvbgriloFhdHRyYWN0CuKWgWNvcnQKbsOhCuKWgVN0ZXZlCuKWgWJlbmUK0YLQvtC9CsOtY3VsYQpUd28K4paB0LPQu9Cw0LIK4paBVmlkZW8K4paBcG93ZXJmdWwKYXVjaAptYW5kZQrDpGNoc3QKTGF0CuKWgXpuYQriloFmaWd1cmVzCuKWgWFsaWFzCm5leAriloFjYXRlZ29yaWVzCmNhbGxlZAriloFTaW1pbGFyCuKWgWdpcmxzCnBlegriloFqb2ludArRgNC+0LPQvgppa2VuCtGH0LjQvdCwCmFuY2lhCuKWgXRpamQK4paBUm9zZQriloFhbGdvcml0aG1zCuKWgXByaW50aW5nCm5lYQriloFleGVjdXRpbmcK4paBbGFtYmRhCuKWgXJlZ2lvbmFsCuKWgUNvcGEKRm9vCnBoeXMKem0K4paBTGF1cgriloFjYW5kaWRhdGUK4paBSmEKenltCkV4YW1wbGUK4paBc3BpZWwK4paB0LTQtdC5Cm5laG1lbgprZWl0ZW4K4paB0YHQtdC90YIKaW50ZW50Ci4oCuKWgdC/0LXRgNCy0YsKcHJvbQriloFuYXQK4paBaW1hZ2luZQpjYWxsYmFjawpjb21wb25lbnRzCndpdGhvdXQK4paBYXF1ZXN0ClN1cHBvcnQK4paBcmVzcG9uc2libGUK4paBamVnbwpsagp3aWxsCmxlYW4KZWxhbmQKb2xvZ8OtYQptYwpQcm94eQriloFvY3VwCuKWgdC90LDRhdC+0LTQuAriloFydWIK0L3RltCyCuKWgUZhbGwKYW1vcwriloFFcAplbnRyZQpmYWlsCldvcmxkCuKWgUVkaXRvcgriloFleHBvcwriloFmaW5kcwriloFDdWx0dXJlCkxFQVNFCuKWgW1vdmllCjw9Cm9tZXRyaWMKZWxpbmcKbnVtZXJhYmxlCm91cmQK4paBU2VhCuKWgWJpbGQK4paB0L7RgdGC0LAKYmxvCuKWgWxvc2UKYXRldXJzCm91cmVkCuKWgUJhdHQKKCk7DQriloFwb3oKcG9zdHMKcGVuZApjZXJ0YWluCtC90LjQutC+0LwKSnVzdAp3ZWJraXQKZGVtw6FzCn5+fn4K4paBaW5kaWNhdGVzCuKWgXBhcmsKcmlxdWUKdm9kCuKWgUNoYW1wCmZ0d2FyZQpPUFQKZGphbmdvCnJlbGVhc2UK4paBw4gKU1IK4paBcG9saXRpY2lhbgriloFyb2kKYXR1cmVuCuKWgURldXRzY2hlCnRhZ29uCuKWgU1vdgpvYmllcm5vCuKWgWRhw58KdXRoZXIKaW5kaQriloFXaWtpcGVkaWEK4paBYW5vcwriloFvYnNlcnZlCmVsbHkK4paBcmFpbHdheQphdG9uCuKWgWVudW0KaHVzCuKWgWluaGFiClBzaQpvaXJlCuKWgdCl0L4K4paBU3BhY2UK4paB0JDRgNGF0LgK4paBYW50ZXJpb3IK4paBxYEKaXNvbnMKSWwK4paBYW3DqXJpYwpsYXBzCuKWgUJCQwpRVUVTVApDb25zdHJhCm1vbnQKw6RmdAriloHDpHZlbgp1YmVybgo8IS0tCuKWgWNvZGluZwp0aGVvcnkKYXRoZWQK4paBQXJiZQriloHRiNC4CmZvckVhY2gKb21vcnBoaXNtCmRldGFpbHMKYWNoc2VuCmludGVncgpWb3IKVW5rbm93bgphY2VhZQppbnVlCmVzb21lCuKWgUZpcgpjaGFpbgriloFleHRyZW1lbHkKbXVsdGljb2wK4paBU3dpZnQK4paBYWRkcmVzc2VzCmhzcGFjZQriloFSb2dlcgriloFkZXNzZW4K4paBY29uc2VxdQp1YWxtZW50ZQriloFQcmVtaWVyCuKWgVJlY29yZAriloFCcm9uCmtpcgpzZXgKaW50ZXJuCuKWgWJlbmVmaXQKdW1lbgriloFiZWNvbWluZwriloFsaWcK4paBcG9wdWxhCm9zYwriloFjaXYK4paBZ3JlYXRlc3QK4paBcHJvY2VzCl0qCuKWgdC80LXRgdGC0L4K4paBJyQKaGVsbAooIlwK4paBbmluZQriloFGYWMKdWxwdApqb3VycwriloFDb3B5CuKWgWFjdGl2aXRpZXMK4paBRGVtb2NyCkVzClN1Y2Nlc3MK4paBRXN0YQppdHVsCmlzdGkK4paBQmVkCmphcwriloHRgtC10LwK4paBSHVuZwpHYW1lCuKWgWhlYXYKb25uw6llcwriloFicmFuY2hlcwpib3JnCuKWgXZsCuKWgXNsb3dseQpGYQpHb29nbGUKZW1pCuKWgWNpcmN1bXN0YW5jZXMK4paBJyUK4paBVW5kCuKWgVZpY3RvcmlhCuKWgVR5cApydXB0ZWQK4paBcmVsYXRpdgriloFzbG8K4paBcGFkcmUK4paBZGFpbHkK4paBb3J0aArRh9C90LjQuQriloFmcmFuesO2cwriloF0ZWlsCuKWgVNlY3VyaXR5Cm9yZG9uCuKWgXN3ZWV0ClNJWkUK4paBQ2VsCsOodHJlcwpvbW1lcwriloHRgdGWCuKWgWVmZm9ydHMKxIV6CuKWgW9obmUK4paBU291dGhlcm4K4paBYXBwcm94aW1hdGVseQrRhtC10L0KKCcjCuKWgXNhdmluZwpuYnNwCuKWgXRyYW5zbGF0ZQriloHDjm4KbWVtYmVyCuKWgWxhd3MK4paB0LbQtdC9CuKWgdGB0LjRgdGC0LUKdGMKPlwKZWx0ZQriloFlaGVtCuKWgWNvbnRyYWQK4paB0YDRg9GBCtGM0Y8K4paBTWlkZGxlCnF1aXAK4paBY2hlegpGaWVsZHMK4paBcGVybWl0CmlrZWwK4paBd2lyCuKWgXRyaWFsCuKWgXZlcnNjaGllZAriloHRhNC10LIK4paBbWFsZQriloHRj9C30YsK4paBbnllbApha3RlcgriloFkZW5vbWluCmNlcHRvcgriloFXYXQK4paBZmlubwriloFYVklJSQpyeXB0aW9uCmRlc2MKYXBhCtC70LXQvdCwCuKWgWtvbAriloHQhAriloFkZXBlbmRlbnQK4paBQ3JhCuKWgXN0b3JtCuKWgdCT0LXRgAriloFwaXBlCuKWgWF0dGVuZGVkCuKWgXZpdGEKdXppb25lCmN6YXMKb25kYQriloFib2xkCkNvbHVtbnMKaWNpw7MK4paBY3rEmQriloHQuNC30LLQtdGB0YIK4paBQ2xvdWQK4paBd2FybQriloHRgdGLCuKWgdGB0YLQtQriloFwcm9kdWNlcgriloFMdWR3aWcK4paBTm9ydGhlcm4KxYLEhQpOU1N0cmluZwriloFIYWQK4paB0JjQstCw0L0K4paBRWcK4paBSW1wCtGI0ZYK4paBQXVjaArRgtC+0LoK4paBSGl0CuKWgXF1aWVuCuKWgWRlcGFydG1lbnQK4paBZXJoaWVsdAriloF1aQriloFTcHIK0YHQtdGACm91cnQK4paBU3RlcGhlbgp0ZWFtCuKWgXppcAriloFCYW5nCuKWgWdyb3d0aAriloFqYW0K4paBS2FpcwpibWF0cml4CuKWgUFzaWEK4paBcsOpZ2lvbgo9LwriloFQYWNpZmljCuKWgWF1dGhvcml0eQriloEjWwrRgtCw0LzQuAriloFldmVyeW9uZQriloFhdHRlbmQK4paBdGltZXN0YW1wCuKWgXRyaWVzCuKWgWZmCtGI0LXQuQriloFkZXZlbG9waW5nCm9sdAp1cHMK4paBbW9tZW50bwriloFTYWluClRlcm0K4paBY2VsbGUKR1IKTW91c2UK4paB0YfQtdC70L7QstC10LoK4paBQ29sbGVjdGlvbgrDonRyZQriloFXcml0ZQriloFQb20KWy0KQ2FtCuKWgWxvY2F0aW9ucwriloFKc29uCmVsbGVkCnNlbGVjdG9yCnJlcGVhdApjdG9ycwpvdHRlCtCy0LjQt9C4CsOkbmRlCuKWgWFjaGlldmVkCuKWgW1haW5seQpfX19fX19fXwohKQriloHRj9Cy0LvRj9C10YLRgdGPCuKWgWNpdGllcwpzaW5nbGUK0LPRgNC1CuKWgVBhawriloFhbGxvd2luZwpmZXJyZWQK4paB0LDQv9GA0LUK0YXQvtC00Y8K4paBYnJvd3NlcnMK4paBZXNjcml0CuKWgW1vdW50YWluCuKWgW5ldHdvcmtzCmtpbmQKbGl2ZXIK4paBY2xvc2luZwriloFza2lwCsO6dAriloFkdXJhdGlvbgrDqXRhaXQK4paBc2NyCkJCCsOzcmlhCuKWgUt1bHR1cgriloFvdXRwdXRzCm11bHRpY29sdW1uCuKWgWJlbG9uZ3MKZmVhdHVyZQp1Y2t5CuKWgWp1bGkK4paB0YDQsNC50L7QvdCwCtC30LLQvgpmYWN0b3J5CkZ1bmMK4paBdXR0ZXIK4paBVE9ETwriloFvYnQKYXRlZ29yaWVzCuKWgWNvbWJpbmUK4paBV2FsbAriloF1bmRlcmx5aW5nCmFyb25vCuKWgVByb3RlCmPDs3cKc3RhbgriloFHZXcK4paBb3B0aW1hbAriloFBcmNoaXZsaW5rCuKWgVNjcmlwdAriloFkZXN0cm95ZWQK0YXQtQriloFGaXJlZm94CuKWgXNvbGUKTGF5ZXIK0YLQutGDCuKWgXN0b3JlcwriloFkaXNwbGF5cwppc2hpbmcK4paB0L7RgdGCCuKWgWluc3RhbnQK4paBZWzFkQriloFoYWJpdGFudGVzCuKWgUVpbndvCuKWgWFsaQriloFFUlJPUgriloFhaGVhZAriloFnb2FscwriloFtw6FyCuKWgXPEhQriloFtYXJ0CtC80LjQvdC40YHRgtGA0LAKRnIK4paBVmlsbGEK4paBTWFyYwpyb3B5CmFncmFtCmhhcGUK0LzQtdC5CuKWgUFMCuKWgWNvbm5leGVzCuKWgUVudHJlClN0ZXAK0LvRltCyCuKWgURlYXRoCuKWgXJpc2UK4paBZm9zCuKWgWxldgpnYWJlCuKWgWJyb2tlCnByb2R1Y3RzCuKWgW1lZGkK4paBZGlzcG9uClBhY2thZ2UKSW1hZ2VWaWV3CuKWgU5hZwp1asSFCldvcmQK4paBa29sZQrDn2VyCilgLgriloFyb2wK4paBw60K0YLQtdC5ClByb2dyZXNzCmJlYW4K4paBc2VtcHJlClN0YXRlbWVudApVUERBVEUK4paBbW9uZGlhbGUK4paBd3JhcHBlcgriloFDaGFydAriloFvbkNsaWNrCtGH0LXQvdC90Y8KTE9HCnNvbWV0aGluZwriloFJTlNFUlQK0YnQtdC90LjRjwp1ZXQKd2VycApyb3VuZAppY2hlbgriloFYVkkK0LfQvdC4CuKWgWF2ZXZhCuKWgVN0b3JlCuKWgXhzCnJhY2h0CnNjYXIK4paBb3BlcmEK4paBZGVncmVlcwriloFjaXRpegrDpHNpZGVudAriloFjbGFzc2ljYWwK4paBSmVyc2V5CuKWgWVyc2NoCuKWgXRyZWF0bWVudAriloHQvdCw0YHQtdGZ0LUK0L3QvdGPCuKWgWJvb3N0CmFtb3VudAriloHRgdC+0LfQtNCwCsOpcmlldXIK4paBdGVsbGluZwpIYXMK4paBaW5pdGkK4paB0J/QuApldmFsCuKWgU1hdGNoCuKWgWNvcnJlClBvaW50ZXIK4paBcGFzc2VzCmNvbXBhbnkK4paB0LDQvQphY2hlcwriloFzaWdsbwrQvdC10LwK4paBZXhjaGFuZ2UKY2l0bwriloFCYWIKRG9jCnplxZsK4paB0L3QsNGA0L7QtAriloFjb25mbGljdAriloFub3ZlbWJlcgplYXUKw7Z2CuKWgUh1YgriloFwb2NvCmVuc2EKc2NobGllw58KbGFzc2UKZGF0YXMK4paB0YHRgtC4CnVuaXZlcnMKZWtzCuKWgUNobwriloFjw7QK4paBKC4KZXduxJkK4paBQ2hpZWYK4paBY2hlZgriloHRg9C/0YDQsNCyCnVsaQriloEnJycKbmFwc2hvdAriloFyZWxhYwrDqWdlCnd0CndlbmQKb3NpbmcK4paBaGFjZXIK4paB0YTRgNCw0L0KYXV0cmVzCuKWgWZpbHMKZXJlZAriloHQn9C+0YHQuNC70LDQvdC90Y8K4paBdGhlcm0K0LXRgNC20LAKc3VjaAriloFpaHJlbgriloFlbmNvbnRyCuKWgWxvdHMKbG9nbwriloFXaQovKArRiNGa0LUKREFUQQriloFQbGF5ZXIK4paBTGVpcHppZwriloFyZWxhdGl2ZXMK0YDQtdCyCuKWgW5ld3NwCj8sCuKWgVN0dXR0CuKWgWR1YWwK4paBY29tcGFuaWVzCuKWgXphbQpwdXRhdGlvbgriloFpbmVxdWFsaXR5CuKWgXRyZW0KaGlwcwphbmNoCuKWgcW7CtCx0YPRgNCzCuKWgWNvcGllcwpkYXNoCtCy0L7RgApzcGllbGVyCuKWgVJldm9sdXRpb24KZXN0eQriloFqdW50bwriloFJbmRlZWQKb2thbApjdHJpbmUK4paBRm9yZAriloFDUkVBVEUK4paBd2FsbHMK4paBYXV0ZQpTVQp3aHkKcGxlbWVudGF0aW9uCnJvdXQKTWF0cml4CuKWgXNhZArQsNC90LAK4paBUGljCi7igJwK4paBQUMK4paBRmVzdAriloFkZXNrdG9wCuKWgVBheQpvbWV0aW1lcwriloFUYWsK0YDQsNCxCuKWgVNldmVyCuKWgW5vcnRoZXJuCmFudGVyCuKWgU1vZGVybgp3YWwKew0Kb25saW5lCsO2awriloFicml0YW5uCiRfCuKWgWphcgpUTAp4eHh4Cm1lcmdlCuKWgU5hbWVuCuKWgUtFWQriloFyZWZlcnMK4paBaGluCuKWgVZvbGtzCnN0ZWxsZXIKdmlhdGlvbgpvbmlvCmlnaHRlcgpDb21wYXQK4paBQ0UK4paBcHLDswriloFlbmN1ZW50cmEKdGhlb3JlbQriloFwdWJsaQriloFEZXZlbG9wbWVudArQvdC0CuKWgXJvcwriloFzaHIKc2VhdQriloFnZW5lcmF0aW5nCuKWgWRpZmZpY3VsdHkK4paBRXhwcmVzcwpBbGlnbm1lbnQKZGV1dHNjaAriloHQktC70LDQtNC4CuKWgXN1Z2dlc3RzCuKWgUZhbWlseQpiYmkKXSkuCnN0YXcK4paBcHJlc2lkZW50ZQriloFzdGVzc28KaW54CnNldHVwCuKWgWNvbmZvcm0K4paBZnJvCj1cIgriloFkw6UKaWNpb25lcwriloFldm9sdXRpb24KcHJvdGUK4paBcHJpbnRzCuKWgVBvbnQK4paBY29uZnVzaW9uCuKWgdCZCuKWgWRlbGxvCuKWgW1hbmlmCkRlZmluaXRpb24Kw6FyYQptYWxzCuKWgXNhbGUK4paBZHJvcGRvd24KQ2hhaW4KQW1lcmljYW4K4paBbWsK4paBQmV6CuKWgUZ1ZQriloFORQrQs9GA0LDRhNC4CmRvY2tlcgriloFeewpBc3NlcnQK4paBaG9yaXpvbnRhbAooQCIK4paB0LTQstGDCnByb3h5ClVyaQpnZW5jeQriloEiWwriloFRdAriloFOYW1lcwriloFldmFsdWF0ZQohLwriloFlaW5nZXMK4paBc3ludGgK4paBWW91VHViZQriloF0dXJuaW5nCuKWgUVyaWMK4paB0LHQu9C4CuKWgWtsdWIKcGxvcmVyCuKWgXNwb3J0cwriloFzaWEK0L7RiAriloFkYWkK4paBZXVyb3BlCmljaWFucwppbmdzb21yw6UK4paBZHJlCuKWgXdvcmthcm91bmQK4paBc3VpdAphbWJpZ3UK4paBcXVhbnRpdHkK4paBc2VndW5kbwpTeW1ib2wK4paBbW9yYWwKQ2hhcnQK4paBZGFtaXQK4paBYXR0ZW1wdHMK4paBZG9ubgpqb3MK4paBZXJlCuKWgWhvbW1lCnNpbXAKcnlwdGVkCuKWgWFjdHMKaW5uZXJIVE1MCuKWgXRvdXJuYW1lbnQK4paBc2t5ClRpbWVyCuKWgW1pbGxpb25zCl4rCmFnZW50CicpKTsK4paBb3N0CuKWgWdsYQriloHQv9C+0LzQvgriloFmw7xuCtGB0YLQstC+0LwKZXduxJl0cnoK4paBTcOpeGljbwriloFsdWIK4paBw4lkCmlmaWsK0YfQtdGB0LrQuNC5CuKWgWltbWVyCmVuc2VuCmFubnkKaW5saW5lCuKWgWdvdmVyCmF1YwriloFyZXByZQriloFoaXN0b3JpYQpBZwriloFwbHQK4paBUHJpbmNpCmltZXRlcgrFkXMKxaFlCuKWgVVFCkVxdWFscwpEaXNwYXRjaApsZWdlbgrQu9Cw0LfQuArRh9C90L7QuQriloFzdGVsbArFhHN0CuKWgWNyaQriloFJbmRlcArDqGRlCn1cKQriloF3eXN0CuKWgWZpZ3VyZWQKQVRDSArDqWJlbgpsYWNodAriloFzdWNjZWVkZWQKZ3J5CuKWgXByZXQK4paBU2FmCuKWgSIpOwplaAriloFvZmZpY2llbArQutGA0LDRl9C9CndpbmQK4paBc2NhdHRlcgriloFGb3gKaWNpb3VzCk1hbnkKdXBlcgriloFDb252ZXJ0CnN0ZXJkCuKWgVN0ZWluCuKWgdCe0YIKfV57KApiZXR3ZWVuCmhpcmUK4paBb25DcmVhdGUKOzwvCmJhYmx5ClNZCm1vdAriloFEaXJlCml0ZWN0dXJlCtGC0L7QuQriloFjb29yZGluYXRlCigiIwriloFzw7xkCk9CCuKWgW1vcnRlCuKWgXdlYXRoZXIK4paBaGVseQriloFwcml2aWxlClJFTEVBU0UKYXRlbAriloFyZWNvZ25pemVkCuKWgVRob3VnaArRgdGB0LjQuQptZW1vcnkK4paBY29tcGlsYXRpb24KYml0cwriloF3ZWQKfX1fewriloFHVUkK0L/QvdGPCuKWgXNvdXRoZXJuCuKWgWhheQpvdmnEhwpsYXVmCuKWgUVMCuKWgUZ1bGwK4paBSGFtYnVyZwriloFNaXR0ZWwKRFUKYXBwcm94CkhTCuKWgdC/0YDQvtGG0LUK4paBbWFnYXppbmUK4paBTWlnCuKWgWNsaWNraW5nCmVudHIK4paBYXV0cmUK4paBdMOpCuKWgWjDoQrRgdGC0YsK4paBTUEKYXBweQpzdHbDrQriloFzZWxvbgriloFnZWsK4paBU2wKZnJhc3RyCkxpYgriloHQlNGDCuKWgWZhY2luZwriloHRgdGC0LDRgAriloFEdXRjaAphdGFyCuKWgWtlZXBzCuKWgVBhdHJpY2sKaWxpbwriloF2aWcK0YLQstCwCuKWgUZlZGVyYWwK4paBcGFyYWdyYXBoCuKWgWludGVyYWN0aW9uCuKWgW9jY2FzCuKWgUlyYW4K4paBbWFjaGluZXMKKCgpCnVyaWVzCuKWgdGA0L7QtNC4CuKWgdCw0LzQtdGA0LjQutCw0L0KdXBwCuKWgWljZQriloFTYXkK4paBc2FpbAriloFCZWdpbgpmaWNvCm9nYQriloFkZXNhcgriloFkdgriloHRgNCw0LTQuApvaGVuCmVyZWkKw6FuYWsK4paBZGFhcgppZmllcnMK4paBdGhlZQriloFieWxhCtCy0LDQu9CwCmFuZHJvCuKWgdC80L7Qu9C+CuKWgXRvdGFsbHkKaW9tCuKWgWFlcgpuc3lsdmFuCuKWgWNvcnBzCuKWgXRyZWF0ZWQK4paBY29tdW5lCk1pY2gKdm9pY2UKcGdmCuKWgWFueAriloFQaGlsaXAK4paBZWsK4paBTWVuc2NoZW4K4paBZGVyZQriloFwZXJtZXQKTWFpbAriloFWw6kKZW50ZWQK4paBYnVuY2gK4paBUGlldAphdHRhY2gK4paBcG9ydGUK0LTQsNGCCuKWgUJyaXRhaW4KRW5jb2RpbmcK4paBYDwKU3BhY2UK4paBcmFwCuKWgXBvcHVsCmZsb29yCnNwZWNpZmljCmNsZWFuCuKWgWNvbnF1CmZiCuKWgWludHJvZHVjZQriloFFbnRpdHkK4paBZXJmb2xnCmF0b2wKaWVudG9zCtC60LjQv9C10LTQuAriloFVdAriloHQsdGA0LgKZWR1bGVyCuKWgWNvbmNlbnRyCuKWgWNoZXIK4paBdXBncmFkZQriloFwaWN0dXJlcwriloFGYW1pbGllCk11cwpMb29rCuKWgWVyYW4K4paBZ3JhbQriloFXbwpucG0K4paBU2FsdgriloFjZAriloHQktGLCndhaGwKdHJhaW4KY2hlbQriloFQaWwK4paBQ29ubmVjdArEjWUK4paBaGFzdAriloFNdWx0aQphdHRhCuKWgVNvdW5kCnNvbHV0ZQriloFxdW90ZQriloFvYnN0CmNjaW9uZXMKaWJseQriloFicmFuZAriloFjb252ZXJzYXRpb24K4paBdG91dGVzCuKWgVJ1YgppZW5pYQppcml0CuKWgdCQ0L3QtAplZHVsZWQK4paBVG90YWwKRGlnCmVyZW0K4paBc2tpCkRlc3QKWVkK0LXQtNC4CmFseQriloFiYWNrZW5kCnVsdXMK4paBZmVhdHVyZWQK4paBcGVyc29ubgriloFzY2hvbgp0cmFjZQriloFJREUKw6FqCuKWgWFuaW1hbHMK4paBc25vdwp1dmUKdWVydG8K4paBZHJldwriloFZZWFoCuKWgVN2ClwsXAriloFTZXJpZQriloFzZWNvbmRvCuKWgUxlYmVucwriloFhY2NvcmQK4paBQ2V0CmVyYWRlCuKWgWRlc3BpdGUK4paBQ2FybG8K4paBemV3bsSZdHJ6CuKWgWxpc3RhCm5pY28K4paBQ29ycG9yYXRpb24KdnNwYWNlCuKWgdCy0L7QudC90YsK4paBc3RhbmRzCuKWgXdvcnNlCuKWgXNpbXVsdAriloFwcmFjdGljYWwKQ09MCmNoYW5nZWQK4paB0JjRgdGC0L7RgNC40Y8K0LHRgNC4CmluZG8K4paBTGV3aXMK4paBcGF0dGVybnMKaWZpY2EK4paBc21hcnQK4paBY29uY2VybmVkCsibaWkK4paBSGVsbG8KcmVsbAriloFMZXgK4paB0LLRgtC+CuKWgWNvbmRpdGlvbmFsCm90dGVkCuKWgXNob290CuKWgVdlZAriloHQvNCw0YDRgtCwCmF1ZAriloFhbnRlCmllbnRyYXMK4paBcGFwZXJzCuKWgXBvcnR1ZwriloFNYW5hZ2VtZW50CuKWgWV4ZXJjaXNlCuKWgUJlZ3JpZmYKY29tbWl0CuKWgXJlbmRlcmluZwriloFjemFzCkRyb3AKZXJnCuKWgW11bAriloFUYW4KaWVybwriloFsb2NhbGUK4paBaW5hdWcKZHVtcArRhtC40LkK4paBc3ltYm9scwppbnRhCuKWgWF3YXJkZWQK4paBc3VzdAriloFTZW5kCtGX0LIKUmVzdAp6dGVuCtC70LjQvApyaXZhbApQT1JUCsO2bGtlcgppbWF0ZWx5CmlndGUK0YfQvdGL0YUK4paBdGVycmEKw7ZnbGljaAriloFIb20K4paBaGV4CmRvbmUKYW1wcwriloFjZXQKUFJFCsO2c3QK4paBZmVtbWUKU2VsZWN0aW9uCuKWgXphdwpzcHIK4paBaG9yc2VzCuKWgXNuYXAKVGV4dEJveAriloFFY2xpcHNlCnVsbGUKb3d5bQriloFjb21lcgpuZWNlc3MKY29vawplbmdlcgotLT4K4paBcMWZw60KcGFuZGFzCuKWgVBsdXMKeWxsCuKWgXRlcnJvcgriloFjcmltCuKWgXphawppc3N1ZQpwYW5lbApzdmcK4paBcmViCkN1c3RvbWVyCnN3aXRjaArQvtCx0YDQsAriloFDaGFtcGlvbnNoaXBzCmNsbwphdHRlCuKWgWFueW1vcmUK4paBZXhjZWxsZW50CuKWgW9wcG9ydHVuaXR5CuKWgUJhaG4K0YfQuNC9CmV0aW5nCuKWgWluY2lkZW50CnRvbQpQZXJzCmJiZW4K0YHRgtCy0LXQvdC90L7QuQrQuNGFCnJvdXRlcgriloFuZXdseQriloFzaWxlbmNlCuKWgUdOVQriloFSYWlscwriloFBbWIK4paBUXVhbAriloFTY2hhdXMK4paBU29obgriloFBTEwK4paBcm95YWwK4paBwqMKd2nEmQriloFlbnRmZXIK4paBUmVtb3ZlCuKWgWhhcmRseQpVc2luZwrQu9C+0LMK4paBSWNoCuKWgWRlcm5pCuKWgUNvbm5lY3Rpb24KZmlzaAriloFJbmZvcm0K4paBRW5lcgpyb2l0CkJiYgpWaWV3TW9kZWwKVmlkZW8KaWxleQriloHQvNC90L7Qs9C+CuKWgUdlbQriloFjb21wcmVoCmVudW1lcmF0ZQp1bGFzCuKWgUJhaAriloFZZXQKQlIK0YXRgNCwCuKWgWNvdW50eQriloFIaXN0CuKWgdCT0YMK4paB0IgK4paBbWFyaQriloFDbGFyCkJpdG1hcAriloFDegriloFtw6VuCuKWgW1lcmUK4paBbXVzaXF1ZQphbHNvCmRhdGVzCuKWgURWRAriloFnb2wKZm9ueQriloFDYXN0bGUK4paB0YTQsNC80LgK4paBYXJyYW5nCuKWgUJ1c2luZXNzCuKWgUthegriloFvc2MK4paBc2Vjb2xvCuKWgWFmZmVjdGVkCuKWgUhlYWx0aApyZWIKZWRpdG9yCuKWgW93bmVkCnRsCuKWgXbDrQrRh9C90LjRhQrQutCy0LgK4paBZGV2aWVudApNdXRhYmxlCuKWgXRlZ2VuClJlZ2lzdGVyCtGU0Y4K4paBY2FyYWN0ZXIK0LvQu9C4CuKWgW5vdXZlbGxlCm9rbwppY2h0ZXQK4paBZXZvbAriloFIYWIK4paBbWlsaXRhcgriloFwdXRzCmVuZGlmCuKWgURhdmlzCuKWgVNjb3RsYW5kCnJlZ3VsYXIK4paBQ29udGV4dAppc3BpZWwK4paBR2FsbGVyeQoiLA0K4paBYXJjCuKWgUlORk8K4paBY29kCtC00ZbQsgriloF2YXJjaGFyCuKWgXRvdWpvdXJzCmF0aWFsCuKWgWhhbm5vCuKWgdC/0YDQvtGE0LXRgQriloFsYXVuY2hlZAriloHQvdCw0YHQtdC70LXQvdC90Y8K4paBdG9uCmF1c2VkCuKWgdGW0LcK4paBdMO2CuKWgVB1cgriloFvbHltcApBUk4Kw7NtCuKWgWF1Z3VzdAriloFmdXJuCuKWgUNvbG9tYgriloFTdGFhdHMKaG9yYQriloHQvNC+0YAKY2FudmFzCuKWgWdyYXZlCuKWgWNvbXBvc2l0aW9uCmFjamEK4paB0LrQvtGC0L7RgNGL0LUK4paB0YfQvgpHZW5lcmFsCtCw0L3RlgriloFKb2hhbm5lcwrQutCw0YAK4paB0YfQsNGB0YIK4paB0JLQsNGB0LgKc3NoCuKWgXJlcGxhY2luZwriloE8PgrRhtGW0LIKbGF1cwplbnkKw6RobAriloFtYXJnCmNpZW5jZQriloFpbnN0cnVjdGlvbgriloHQutC+0ZjQuApFZGl0b3IK4paBZnVuZGFtZW50YWwKbXVuZAriloFleGNlcHRpb25zCuKWgXBsYXRlCuKWgUxpcwriloFkZXJlbgpwcmVwCuKWgWphbnVhcmkKU2NvcGUKeW5hc3QKcnYKb3JzegriloFUb255CuKWgdC00ZYK4paB0L7QtNC90LAK4paBc2FiCm90aQpqZWwK4paBZ2VuZXJhdG9yCuKWgScuCuKWgXNoYXJwCuKWgdGC0L7Qu9GM0LrQvgriloFhY2NvdW50cwriloHFvmUK4paBZm9yYW0K4paBZ291dmVybgpUSU1FCuKWgVNvdmlldAriloFHw6kK4paBZXhwZWQK4paBb3JkaW5hcnkK4paBQ29uc2VydgriloFjb21wbGEKdGVpCuKWgWNhcHRhaW4K4paBU2FtdWVsCuKWgURhcmsK4paB0LLRltC9CuKWgWRlbGlnaHQKcmVjaHQKZGlhCmVzc2VzCnVscArRiNC60LgKYmV6CuKWgWRldGVjdGlvbgriloFjb29raWUKYW50cnkKTXVsdGkKb2JhCuKWgWpveQriloFzYWZldHkKfF4KcG9kCmFkw6ltCuKWgUNocm9uCuKWgURqYW5nbwriloFlaGVtYWwKa2gKw6hsZQriloFwb2MKQm90dG9tCmxhdW5jaApuZW0K4paBR1JPVVAKbsOtaG8K4paBR2liCnNkawpCRQriloFHZW5lCuKWgVN0YWZmCuKWgXN1YnNlcXVlbnQKaWNpb24K4paBdmljdG9yeQriloFjYW5vbgppemFyCml6aWEK4paBbWF0ZQriloFsYXllcnMKc3VkbwpzY2h1bGUKcGVyaW1lbnQKw7xsZXQKQVJDSEFSCuKWgdGC0LXRgNGA0LjRgtC+CuKWgW1lYXN1cmVzCuKWgXpvdQpvcHNpcwrQvdCw0LzQuAp0Ym9keQriloFlc2UKc3RlcmRhbQriloFwaG90bwp5bmNocm9ub3VzCnNldG1pbnVzCuKWgWxvYWRzCuKWgXBsZWFzdXJlCuKWgW1laWxsZQp9XCwKcXVhbAriloFmYXZvdXIK4paBcm9kCkRlcgrRgNCw0LHQvgriloFwcmVzc2VkCnLEmQppZXZpbmcKbWF0ZXJpYWwKdmlydAriloFjYXBhYmxlCtGB0LvQvgp1c2hlZAriloHQv9C+0LHQtQp1c2V0dHMKdW5zaWduZWQKa8OzdwriloFvdgplZ2ViZW4K4paBYXBwbHlpbmcK4paBZ2FsYXgK4paBT3JhY2xlCuKWgVN0dXR0Z2FydApJbmZsCmFjaHVzZXR0cwriloFkZWVsCmxpcmUK4paBc3RhdHVuaXQK4paBUG9saXRpa2VyCuKWgWJlYXV0eQopPgriloFDb2x1bWJpYQriloF6ZXduxJl0cnpuZQriloHQv9GA0L7Qs9GA0LAK4paBZHgKY2tub3cK4paBZHViCnVuw6RjaHN0CmZpbmRWaWV3QnlJZAriloFNYW5kCsOhbGwKbmFpcmUK4paBZGVzdGluCmlzdGluZwphZ2dpCmNoYXJ0CuKWgWp1c3RpY2UKU2ltcGxlCuKWgXVuZm9ydHVuYXRlbHkK0ZbRgAriloFxdWVzdGEK4paBR292ZXJub3IK0Y/QsgriloFtw7pzaWNhCuKWgWVxdWlwbwriloFEZXN0CmVsZWN0ClN0YWNrVHJhY2UK0LfQvtC8CnByb2MKZW50aW4KYWRvcmEK4paB0JvRjgriloFyZWdpc3RlcmVkCkhMCmZhY2Vib29rCuKWgXN0b3JpbmcK4paBQ3VycmVudGx5CuKWgXF1YWRyClN0YW5kYXJkCnRyaW0KZWFycwpzZW5kZXIK4paBVmFzCuKWgWVkaWZpYwriloFCw7xyCuKWgUNvdW50cnkKdGhhCjsiCm5vcgriloFEb2N0b3IKcnVtZW50CkdlbgriloFCdWVuCnJhZGUK4paBa3VuCm5hdmlnYXRpb24KUGF5CuKWgWNhcHR1cmVkCuKWgXN0cnVjawp2ZW5pcgrDqW1lbnQK4paBVHJlZQriloF4eAriloFuYXJyCtC70YzQvdC+0LPQvgriloFpbnN0YWxsaW5nCuKWgWFzc29jaWF0aW9uCuKWgWluc2VydGVkCmVybmVyCnZhbGlkYXRlCuKWgWx1dAriloFnbG8K4paBdGVjaG5vbG9neQriloFQbGFjZQokPwriloF6dgrRgdC70ZYKRVAK4paBYXRtb3MKdWdvCsOpcnQK4paBV2VyawriloElfQp0ZWxlClNwYW4K4paBUmFqCuKWgVBlcnNvbmVuCuKWgUNhbnQK4paBY29tYmF0CuKWgW9ic2VydmF0aW9uCnBhcmFtZXRlcgriloFhZ3JlZWQKcHVyCuKWgXNoYWRvdwriloFnxYIKS2V5cwpDcmVkCm91cmkK4paBcGFsZQppY2vDqQriloFXZWVrCuKWgVByaW1lCj4uCkluaXRpYWwK4paB0L7QtNC40L0K4paBJycsCuKWgdGD0YfQuAriloFJbnYKY29sYQpjaWJsZQriloFUaGVhdHJlCuKWgWJlbQriloFzYXRpc2Z5CnhsCuKWgdGA0LDQt9Cy0LgK4paBcGl4ZWwKbMOhbgriloF0d2VlCsOnb24K0L3QtdC90LjRjwriloFBVArDqGdlCuKWgU1vcnQK4paBbXlzcQpmdGVuCuKWgdC/0LXRgQrDqW1hCuKWgVNlcnZpY2VzCmN1c3RvbWVyCuKWgUFXUwrRitGCCuKWgUFjaAolLgriloFjbGFyaWZ5CuKWgdGD0L3QuNCy0LXRgNGB0LjRgtC1Cnh0dXJlCnVtaQriloFzw6UK4paBUGVsCnNlcmlhbApVUkkK4paBcmcK4paB0YHQvtGB0YLQsApjaGVzdHJhCl0uWwp3ZW4K4paBTG9uZHJlcwriloFhbnlzCkRhdGFTb3VyY2UK4paB0YDQsNC50L7QvdC1CuKWgXJlaW4K4paBbWV0YWRhdGEKdW1ibGUKYXJiZWl0CmhuZXIKY2llbnQK4paBbm9ydGUK4paB0L7QvdCwCuKWgXNjb3JlZAriloFyYXkK4paB0YTQtdCy0YDQsAriloFwcm90YWdvbgriloFTYWMK4paBY29tbW9ubHkKTGluZWFyTGF5b3V0CuKWgWFwcGxpYwriloHQvNCw0Y8K0JfQsAriloFhY2Nlc3NpYmxlCmlld2VyCmZsYWcK4paBUsO8Y2sKw6R1CuKWgWVyYW5vCuKWgWF1dGhlbnRpYwriloFSeQriloHQvdC10YHQutC+CuKWgWVtYmFyZ28K4paBZHJ5CuKWgXJlYXNvbmFibGUK4paBTW9kdWxlCuKWgWFjY2VsZXIK4paBaW50ZXJ2aWV3CuKWgUNyZWVrCuKWgWFscGhhCnNlcmllClRoZXkK0Y7Rh9C4CuKWgUhvZgriloFDUgptb2RhbAriloFzZXF1ZW5jZXMKY2xvc2VkCil9JAriloHQp9C10YAK4paBT1JERVIKUmlnaHRhcnJvdwpoYXVzZW4KfX1fCuKWgXRhbWLDqQriloFtYWduZXRpYwriloFNY0MK4paBd2lubmluZwp1bmRlcmxpbmUK4paBQmlsbGJvYXJkCm5haW8K4paBbGlxdQpkaXNwbGF5c3R5bGUKdGltZW91dAriloFjb25zaWRlcmFibGUK4paBZWJlbgppZmZlcmVudAphbnUK4paB0KHQvtCyClsoCuKWgTotKQpsZWl0dW5nCmZvcm1lZAriloFNYW5hZ2VyCuKWgW9uY2xpY2sKVFkK0YLQsNGFCkNWCnJ1bnRpbWUKcG9xdWUK4paB0JvQvgpUZW1wCmxvYWRlZAriloEhPT0K4paBc2luZ2VyCmZhcgriloFDb21wbGUK4paBw5ZzdGVycmVpY2gKUG9saWN5CuKWgXdvcmtlcgpXcmFwcGVyCm9iaQriloFkaXNjdXNzZWQK4paBYnV5CuKWgdGP0L3QstCw0YDRjwriloFEaW4K4paBZ2VkCtGB0LrQvtGYCkV1cm9wZQriloF0YWxsCmhvcwrQu9Cw0LPQvgriloFCbG9jawriloFpZGVudGlmaWVkCkxpc3RWaWV3CuKWgWF0dGVtcHRpbmcK4paBdHlwaWNhbApwc3VtCm9zdGVyCuKWgdC20YPRgNC90LAKUGUKbWVyY2UK4paBdW5leHBlY3RlZApodWkKbGV0dGVyCuKWgW51ZXZvCuKWgdCw0LHQvgriloFWQUxVRVMK4paBSXoKRmxhZ3MK4paBVFJVRQppemFjacOzbgriloFncm93aW5nCmVzdHJlCuKWgXBvbHkK4paBU3RvbmUK4paBVklJSQriloFsb2NhbGhvc3QKw6RobHQK4paBZW1iZWRkZWQKamRiYwriloFjb252ZW50aW9uCuKWgXNjYWxhCtGB0L7QugriloFhbmFsb2cK4paBIisK0YbRjgpvY2MK4paBbGl0dApQTgriloHQsNC60YLQuNCyCmF0dHJpYnV0ZXMK4paBRmVyZAriloFhenVyZQrImXRpCsOxb3MKcGluZwriloF0ZWFjaGVyCn0mCmlwZQriloFOb2IK4paB0LjQvNCwCkJpbmQK4paBbWFnaWMK4paBVHJhbnNwb3J0Cml4ZWwK4paBY29tcHV0ZWQKYWduYQplcnN0CkhBCldhaXQK4paBYXV0aG9ycwriloE7KQpjbGFtCuKWgVBlbm5zeWx2YW4K4paBZHJ1ZwriloF2YWluCuKWgWVtcGxveWVkCuKWgWluZGl2aWR1YWxzCuKWgWFuZ2UKdXRhdAriloEkLQpjb3JyZWN0CuKWgWV4cGVyaW1lbnRzCkFyZ3VtZW50CuKWgUlCCuKWgXDDqHJlCuKWgUJyaWFuCmJlcmdlcgpNYWMKaWFzdApQZXJtCkNhc3QK4paBe307CuKWgVN0dWRlbnQK4paBc3RhdHQKYWxnZWJyYQriloFlcXVhbHMK4paBcHJvamV0CuKWgXByw6lzaWRlbnQKQWN0aXZpdHlUaHJlYWQK4paBZWluegplbmlhCnJlegplc3Npb25hbAriloHQsNCy0LPRg9GB0YLQsApvdmVycmlkZQpuZXdzCuKWgXBsYW5ldApubgriloFXaXMK0YLQstC10YAK4paBVmFsaWQK4paBR2VmCtCz0YDQsNC0CuKWgWVpZwphbnRvbQriloFNZWlzdGVyCmZsYWdzCmZmaWNpYWxlCtGI0LDRjwotLAphdGlvbmVuCm1vdXNlCnN0YW5kYXJkClNpbmdsZQriloFib2wKaXNpcwriloFmcnVpdApjb3Vyc2UKaXRhbnRzCuKWgcOpdGFpZW50ClRleHRGaWVsZAriloHRhNC+0L0K4paBYWlyY3JhZnQK4paBSVNTTgriloF3ZXN0ZXJuCuKWgXJlcHJlc2VudGluZwpFc3AK4paBRWxzZQriloFzaXplcwriloFzYXRpc2ZpZWQKb3RvcwpVRApGaW5hbArDs2oKw6h2ZQriloFSb3kKZmZlbgriloFzYWx0CuKWgUxhYmVsClNrCuKWgdC60YDQtQriloHQm9C40YLQtdGA0LDRgtGD0YDQsAriloHRgdC8CkF0dHJpYnV0ZXMKYXllCtGB0YzQugriloHQstGL0YHQvgotKQpvc2VzCmNhbGN1bAriloFDYW5ub3QKR2VuZXJpYwplbW8K4paBQXV0b3IK0LvRkdC9CtC70LDQs9CwCnZvdGUKbGljYXRlcwpydXMKw6lsaQpvcGYKYXRpcXVlCnNjYWxhCuKWgU9oaW8K4paBQnJpdGFubgriloFiZWYK4paB0JXQstGA0L4K4paBQ2FyZWVyCmlzw6llCsOzdApib3NlCuKWgdCR0LXRgAriloFDb250cm9sbGVyCnBvbGUK4paBYWxsZW4K4paBaGFjawriloFleHRlbnQK4paBY2FsY2kKTWVyCuKWgXN1bW1hcnkKTWFydAriloFoaXN0b3JpY2FsCmltYXQKYnVkCuKWgUZPUgpleHBvcnQKZWRpCk1hcHBpbmcK4paBQXkK4paBUnVieQriloFkZWZpbml0aW9ucwriloF7JAriloF5b3VycwpyaWFzClRvdWNoCuKWgUdhegriloFBdXRvbQriloHQuNGB0YLQvtGA0LgK4paBZGVsZW4K4paBS2luZGVyCn19JQriloFwZXJmb3JtaW5nCkZSCuKWgVNpZwriloFCcmFkCmJyYXMK4paBSmFyCnBrZwp3cgriloFQYXlzCk5DCuKWgW9wcG9zZWQKVHJ5CuKWgdCy0LXQt9C1CuKWgUJvZwriloF3cml0ZXMK4paBc3RvcmllcwriloFtYXRlcgriloFzdGFnaW9uZQriloFzdHkK4paBY29tcGF0aWJsZQpoZWFzdAriloFHdXkKZWdyw7xuZAriloFpZGVudGlmaWVyCuKWgWhlYWRzCtC/0L7Qt9C4CuKWgXN0dXAK4paBdGYK4paB0ZjQvtGICuKWgUh1Z2gK4paBY2FyZHMKb3Z5CuKWgVRvYXN0CmFsbGFzCuKWgXDDumJsaWMK4paBYXNzdW1lcwriloHRh9C10LzQv9C40L7QvdCwCnljbGVyCuKWgUp1bmlvcgriloFGaWNoCuKWgWVzdGltYXRlZAp6ZXJ3CmRpYWxvZwrRiNC40L0Kc2hlbGwK4paB0L3QuNGFCuKWgXBpdGNoCtC00L7QuwpvdXR1YmUK4paBU2FudGkKT25DbGlja0xpc3RlbmVyCuKWgU1hZ3lhcgriloF2dWUKacOjbwriloFgIwpjb2xsZWN0CuKWgVJvdQphbmFseXNpcwppc3Ryem9zdAriloFEaWdpdGFsCuKWgWNyaXN0CnJpZXJlCuKWgWNhbXBvClVzCuKWgWNpcmNhCuKWgUNvbXBvbmVudAriloFOU1N0cmluZwpwZAriloFwcmluY2UK4paBaW52b2tlCuKWgU1hcmluZQpBbGxvdwplc3RpYwrRgNC40YHRgtC4CmJvbmUK0YLRg9GA0YsK4paBcGFzc2lvbgrDoWNpw7MK4paBb3JuCtCy0LXQtAriloFpbnZhcmkK4paB0L3RlgpSZW1vdmUKZW5jaWVzCmlsaWIK4paBRGlyZWN0b3IKIiIK4paBQ29uc2UKZ29vZ2xlYXBpcwrDs2sK4paB0KPQutGA0LAK4paBSGF2aW5nCkRvbWFpbgppZXJ6CtC90L7Qu9C+0LPQuApDaG8KdW5kZWZpbmVkCmFsbG9jCuKWgXBpZWQK4paBZnJhY3Rpb24KYmlhCuKWgdC/0L7Qu9C+CnVnbm8KbWluaXN0ZXIK4paBcHJpbmNpcGFsZQriloFyZWZ1c2VkCmJyb3dzZXIKKiwK4paBSG9zcGl0YWwK4paBdW5pdmVyc2FsCuKWgUVybnN0CndobwriloFHYXJkCidfCmNvbmRlCuKWgVt7CnNvYgriloFDcml0CuKWgdC00LXQutCw0LHRgNGPCuKWgXB1bnRvCuKWgWVpbmdlc2V0enQK4paBdMO2cgriloFOaQriloF3b3JyeQriloFsZWdlbmQK4paB0LHRg9C70LgK4paBa29tbQpyaWprCmVmZmVjdApPcmkKUkVTCuKWgVBldGVycwriloFCYXJvbgriloFHb3QK4paBaG9uZXN0CsOkcmUKw6FzegriloFub2JsZQriloFjb25jbHVzaW9uCuKWgWZvcm1hdHRpbmcK4paBb3R0bwriloFkZWxlZwrQvNCxCnB0b3AK4paBc2VuZHMKdXJuYW1lCuKWgWZlc3RpdmFsCizigI4K0YDRg9GBCuKWgWRvY2gKc3ViamVjdAriloFjYXJlZnVsCnF1ZW50CuKWgUxvYWQKdGVtcGVyYXR1cmVuCuKWgXJ1ZQpNZW1vcnkKyJthCmlvbmEK4paBZGVudHJvCuKWgWJlZ2FubgriloFBcXUK4paBc2NpZW50aWZpYwprYcWECtC70L7QugplbGRlCuKWgVRob3NlCnF1aWVyCmFjdMOpcgriloFBdWZsYWdlCiknCuKWgWdyYWRpZW50CmludGVnZXIK4paBSW1wb3J0ClNLCuKWgVN0YXR1cwriloFleHBsbwpBRQpTaGVsbAriloFQYXVsbwouwrsKfTwvCmZsZXgK4paB0LrQvtC80L8Kb25kZW4KYWNjZXB0CuKWgW1pZWpzY2UKSHViCmFsbGVuZwpXTgriloFpbXBsZW1lbnRpbmcK4paB0LvRgwriloFjb25mdXNpbmcK4paBSW5zdGFsbAriloFyb3UK4paB0L/RgNC+0LXQugpBY2Nlc3NvcgrRmdCw0YjRmtC1Cm9kaW8K4paBYXBwbGllcwrRjtGJ0LjQuQriloFNdW5kaWFsCsOJdGF0CmlldG5hbQpodW0K4paB0YHQsdC+0YAKb3JkaW5hdGUKRnJhbmNlCuKWgXByZW5kCmVsdGVtcGVyYXR1cmVuCuKWgXRyYWJhagpBeGlzCuKWgdC80L3QvgpwcmltYXJ5CuKWgVNlaXRlCnBlcm1pc3Npb24K4paBb3JkZW4Kc2luY2UK4paBaWMK4paBQnJhemlsCuKWgWJhcmUK4paBTmFyCuKWgUp1cgriloFmcmVlZG9tCuKWgW1lZGljYWwKaXNjaG9mCuKWgdGB0L8KaWXFvAriloFib290c3RyYXAK4paB4oCmCuKWgWZhY2lsCmNvcmQK0LLQsNC90LUK4paBQWxsZW4KYXZpZAppbmdoYW0KemFzCuKWgWluc3BlY3QKaXR0ZW4Kb3N0aQp1aApjw6kK4paBIyMjIyMKY2l1cwpvbXkK4paBU2VpbmUKYnJlcwriloFnZW51cwpPdGhlcgriloFHb2xkZW4KbXVsCuKWgdCh0L/QvtGZ0LDRiNGa0LUK4paBZ2VubmFpbwriloFjYXJlZnVsbHkKYWFsCuKWgWFuYWx5dApuZXVyCuKWgXN0cmV0Y2gK4paBT2NjCm9sYXMK4paBZmlyZWJhc2UK4paBZXhwZWN0aW5nCmJhc2ljCmNvbmRpdGlvbgpwcm92CuKWgVdhc3NlcgriloFjb25jYXRlbgriloFldmlsCuKWgWNvZWZmaWNpZW50cwpXZXN0CmlyeQpwaGFzCuKWgUphbQpmb2lzCuKWgWNvbnNpZAriloFtYWludGVuCm5pbQplc3Nlcgplc3oKdW50YQp1ZXN0CuKWgWNyZWRlbnRpYWxzCl87CkRpbQrQv9GA0LXQtNC1CuKWgULDvApidWlsdAriloFBY2FkZW0K4paBYXVkaQriloF0dsOlCmluYW5kCuKWgVRoZWF0ZXIK4paBZ2VucmUKw6dvcwpncmVzcWwK4paBd2VhcAriloFSYWIK4paB4oCZCuKWgWFkdWx0CuKWgWTDqW0KYGAK4paBc3RhYmlsCuKWgWNvcnJlc3BvbmRzCuKWgUVhc3Rlcm4KdW5uZWwKV29ya2VyCuKWgWNvaArQu9C60LAK4paBTWFzc2FjaHVzZXR0cwpwaW8K4paBcG9ydHMKYWdnCuKWgURlYnVnCuKWgWJyZWF0aApNSU4KVmFyaWFibGUKYmF0Y2gK0YHRgdC1CuKWgXByZWcK4paBcm9sZXMKcGFzdGUK4paBcmVmZXJlbmNlZAphZHJhdArRh9GRCmJpbm9tCuKWgWRlZmluaW5nCuKWgUJ1ZGFwZXN0CuKWgdC00LLQuAriloF0YXVnaHQK4paBaG9sZQriloFxdWVsbGEKTXNnCmFza2EKc2NhbgriloFwcm9wb3NlCuKWgdCR0LjQvtCz0YDQsNGE0LjRjwp7e1wKdGV4dHQK4paBQWxiCuKWgVN5ZG5leQriloFiYWNrdXAK4paBY3JlZGl0CuKWgdGE0YDQsNC90YbRgwpzdGF0cwpcIjoK4paB0J/QtdGA0LUK4paBYWNjb3JkaW5nbHkK4paBTGVuCnpuYQriloFSZWdpb25hbAriloHQuNC30LTQsAriloFqw7oKaGlzdG9yCuKWgWVudGl0aWVzClN0YXIK0L7QvdC1CiddWycK4paBTm92YQpkaWUK4paBYCcK4paBb2J0ZW4KYW5zdAriloFSZWxpZwriloF0cmlnCuKWgdGA0LXQttC4CuKWgVBlcnNvbmFsCuKWgXRvbmUK4paBYWlkClZpc3VhbApTdWJtaXQK4paBbW92ZXMK4paBQnJpZGdlCuKWgUJveQriloFhY2N1cmF0ZQpvc3RhCmF0dG8K4paBZGVmZWF0ZWQK4paBZGF0YWIKZ2lueAriloFMaXYKbHl3b29kClRXCnJpdW0KaXBwZWQKRmFpbApSRVFVRVNUCuKWgWlnbm9yCuKWgXNpdHRpbmcK4paBbW9sdG8K4paBZW5kcG9pbnQKdWNpw7NuCuKWgWNvbGxlY3Rpb25zCuKWgdCi0YMKdGVtYnJlCuKWgW7DqWNlc3MK4paBaW50ZXJhY3QK4paBb3RyYXMK4paBY3VycgriloF0cmFja3MK4paBZmFtw61saWEK4paBbnVtZXJpY2FsCmxlZ3QKXS8K4paBTWFyaW8K4paBdG9ydApiZwpzc2wKdGV4dHR0CuKWgXNwYXJrCtC00LjQuAriloFwcm9iYWJsZQolJSUlCnBoaWEKXSxbCuKWgWJveGVzCuKWgWFjYWRlbQriloFTbG8Kw6R1ZGUK4paBd2l0bmVzcwriloFlZGl0aW5nCtC70LjQvdCwCuKWgWxvb2t1cAriloFCdWNrCtC00L3RjwriloFqb3VycworKyl7CuKWgWluZGljZXMK4paBZmxpZ2h0CuKWgWNvbXB1dGF0aW9uClBsdWdpbgriloFyZWFsaXplCmlzc2V0CuKWgWRlcml2YXRpdmUKbGluZXdpZHRoCmJ1bmQK4paBdGhvcgriloEuPQriloFzw60K4paBQ2xpY2sK4paBU2ViYXN0Cj4nCmhhdmlvcgpsZWkKdWxmCuKWgWdlb21ldHJ5CnByZXYKZW1wbAriloFMw6kKYW5zb24K4paBQWxpY2UKcHJvdG90eXBlClJFQUQKaWN1bGFyCuKWgdCx0ZYK4paBZGV1dHNjaGUK4paBUmVwcmVzZW50CnNpdGVzCuKWgU1lYW4K4paBZGlzcwriloFadXIK4paB0L/RgNC10LcKUEFSCuKWgScjCuKWgURyYQrRgdC+0L0K4paBc3RlaHQKbWFya3QK4paBZWFzZQpEcmF3aW5nCj0lClN0b3AK4paBc2VydmluZwriloF0YWvFvGUK4paBRE5TCuKWgWxpdGVyYWwKRGllCuKWgdCy0L7RgQriloFzZW5pb3IKYWNpb24K4paBdWJ1bnR1CuKWgUZyYW5rZnVydAriloFTdW5kYXkKw6FiCuKWgWpvdXJuZXkKaXNzYQpiZXJyeQriloFzZXAK4paBaW9uCndlcnQKb3JzesOhZwpzZXJ2ZQriloFNaWxhbm8K4paB0LLQtdC60LAK0YDQsNGFCuKWgdC40Y7Qu9GPCuKWgW1hbmVyYQriloFzdGF0aW9ucwriloFhZG9wdGVkCuKWgWFueWJvZHkKVkVSU0lPTgpGRQpkb3JmCi4uLiwK4paB0L7QsdGA0LDQt9C+0LLQsApMb2dnZXIK0YTQuNGG0LjQsNC70YwKV1JJVEUK4paBaGFtCuKWgUZ1dHVyZQpvdGVuCuKWgUFHCuKWgXRyYWluZWQK4paBTmljaAriloF1bml2ZXJzaXR5CuKWgU9seW1waWNzCuKWgWRvaXQK4paBY3VsdHVyYWwKQ29uZgriloFDb25mZXJlbmNlCm9ybm8K4paBTVAK4paBYm91CmNpbgpIaWdoCmFubnRlCuKWgWRpc3BsYXlpbmcK4paBY2hhcHRlcgriloFGcmF1ZW4K4paBcmVhbGl6ZWQK4paBYXR0ZW1wdGVkCuKWgXByZWZlcnJlZApEYXQK4paBdHJvdXZlCuKWgWludGVudGlvbgriloFOb3RpY2UKdGltZXN0YW1wCiooCuKWgdCo0LAKYW5hcwpjbGEKaXN6CnRibApBcnIK4paBaW52ZXJzZQriloF0ZXJyaWJsZQriloFvY2N1cGllZApKQVgKPC0K4paBUGhpbG9zb3BoCuKWgUNvcnBzCmJ1aWxkZXIK4paBYmVnaW5zCuKWgWNlbnN1cwou4oCZCuKWgXByb3ZlbgptZXRyaWMK4paBaW5jcmVhc2VzCndpY2gK4paBQUJDCnByb2plY3RzCuKWgVRob3IK4paBY29uZmlkZW5jZQriloF1ZmZpY2lhbGUKZWxtCuKWgWdhcmRlbgriloFyb2J1c3QK4paBY29zw6wKaWVkegriloFJc2xhbQriloFBZGRyZXNzCuKWgWRpdmlkZQriloFFdQpjYXRhbApkZXRhaWwKZXBlbmRhbnQKZmcK4paBYmV3CuKWgWZpcwriloFCTwriloF3c3AK4paBcGlwZWxpbmUKaGQK4paBU2Vzc2lvbgpsw6RuZAppdmVhdQplc3RyCuKWgXBhcnRpY2xlCuKWgWxhcmF2ZWwKcGljCuKWgW5hdQriloFmaW5zCuKWgVZpbAriloFmdXMK4paBcXVhc2kKb3BlcmF0aW9uCuKWgWFsbGVyCuKWgWFuYWx5CuKWgdCe0L0K4paBTWVzCuKWgdC+0L/QtdGA0LAK4paBaGFuZGxlZAriloFkZXByZWMKdHRvCuKWgUVrCuKWgXN0cmFuCuKWgWFuZ2xhaXMKanVyZQriloFTaWx2ZXIK4paBY2xvc2VseQplbmtpbnMKYW5vcwpzdGVkCuKWgdGB0LXQvdGC0Y/QsdGA0Y8KYnJhbmQK0L3RjNC+CuKWgXByw6lzZW50CnJvawptb3VudAriloFBbnRob255CuKWgUZ1cnRoZXJtb3JlCmluaGEK4paB0LDRgNGF0LgK4paB0YDQsNC30LvQuAriloHQvtC60YLRj9Cx0YDRjwriloFwaW50Cm7DvQpwdHMK4paBaXRhbGllbgriloHRgNC10LPQuArQu9C10LcK0LTQuNC90LAKYXRoZXJpbmUKSW50ZXJuYWwKUXVlc3Rpb24K4paBc2V0dGxlbWVudAriloHQktGB0LUK4paBZm9sZGVycwrQtNGA0LgK4paBdmFsb3IK4paBTWlsbGVyCuKWgUFzc2VydAriloFwYXRpZW50CuKWgU5pZWRlcgriloFFUAriloFBZ3IK4paBb25kZQriloFzY29wCnNlcXVlbmNlCuKWgVBMCuKWgXNlZWsKamF2YXNlCuKWgVZlY3RvcgriloFuw6EK4paBY2F0ZWdvcsOtYQpjbG9uZQpOUgphdmFpbGFibGUK4paBQmVzY2gK4paBZWNsaXBzZQp3aWNrbHVuZwpkZXBsb3kKZW5pZQriloEiKQrDpHN0CuKWgXN5bmMKQ09ERQriloHQp9C1CuKWgWZsb2F0aW5nCi9gCuKWgXJldGlyZWQKZGViCuKWgXBhcnRpY3VsCuKWgWNvbGxlY3RlZAriloFkb3dubG9hZGVkCm5pY2UK4paBQnVmZmVyCuKWgUFjY291bnQK4paBbWFnZ2lvCuKWgdGA0LXQtNCwCuKWgXNhbGVzCuKWgXN0YXR1bml0ZW5zZQriloFLaQriloFGZXJyCkxvY2sK4paBSXNhYmVsCmNsYXIK4paBcG92CmF0cmEK4paBRnJhdQriloFzb3J0aW5nCuKWgXBocmFzZQriloHQsNC/0YDQtdC70Y8K4paB0LTQtdGP0YLQtdC70YwK4paBQW5kcsOpCmRlZmluaXRpb24Kd3JpdGluZwrDqXLDqQrRidGDCuKWgU9yZAriloFydW0K4paBVHVyawriloFJdmFuCnRoZWxlc3MK4paB0LPQuAriloFzYWtlCuKWgUJhc2VkCmRlY2sKb3J1cwriloF0dXR0aQriloFibGFuCuKWgdCf0YMKRGV0YWlsCuKWgdCd0L4K4paBU2t5CuKWgXByw6hzCtC80L7QuQpjb2xuCtGH0LXRgdC60L7QuQpldGkK4paBYXJyb3cK4paBQ2hhCmNobWFyawrFk3VyCmZhYgrQutGD0LvRjApHcmlkVmlldwriloFCYWNrZ3JvdW5kCnNuCuKWgXNlZ3VpdG8K4paBbmljCmNvdQrRgtGW0LIK4paBYnp3CmFkZEV2ZW50TGlzdGVuZXIKc3luYwphenpvCmFic3RyYWN0CmFzc2V0cwriloFEcnUK0LfQtApvcmRuZXQK4paBYmlnZ2VyCuKWgWluaXRpYWxpemVkCtC60LDQtwpvZ2VuZQp2aW91c2x5CuKWgWd1aWQKc2NoZWlkdW5nCuKWgVplbnQK4paBZnJhbWVzCnJpZWJlbgriloFpc3N1ZWQK4paBZG93CuKWgWRlc2NyaWJlcwppbHN0CuKWgWNyaXRlcmlhCuKWgWdlbnRsZW1hbgpCYXNpYwpuZXoKRGV2Ck1vdmUK4paBZXN0YWJhCuKWgXNldHRlbWJyZQpjaXJjbGUK4paBZmFpcwriloFteXN0CuKWgWFyY2hpdgpkeW5hbWljCmrDoAppdGFzCuKWgdGP0LrQuNC5CuKWgWRvcgriloFBbWF6b24K4paBbmVjZXMK4paBTWFyY2VsCuKWgWVsbGEK0YDQvtC6CuKWgVBlbm5zeWx2YW5pYQpjdWxhcgpQYWNrCml0YWdlCuKWgUJ1cm4K4paBUk8K4paB0L7QvdC4Cn4kClRlWAphc3NpZ24K4paBYmVhdAppZGVuc2UKYWNlbnQKQWxlcnQK4paBc3RyYXRlZwriloFtw6VuYWRlbgpMT0MK4paBY2F0YWxvZwpwcmludFN0YWNrVHJhY2UKKCkpLgp1c3RlZAriloFGcmFtZXdvcmsKRUNLCuKWgWF0w6kKRnJhbWV3b3JrCuKWgWF0dGFja3MK4paBQmVydAriloHRgtGA0LDQvQo6JQphcnNpCm5vdGF0aW9uCuKWgWxvZ2ljYWwKd2VldAriloF2aXNpdGVkCmJydQriloFzdXJwcmlzZQpeXgppbmFsZQpyZW1vdGUKJ30sClN5bnRheAppYW5lCm9ubmVuCuKWgWJyZWFraW5nCnBhcnNlcgphcGsK4paBTWlndWVsCuKWgcKnCuKWgWFjdGluZwriloFnZWJydQpBdEluZGV4CtGO0YLRjNGB0Y8K4paBb2ZmZXJzCuKWgXByYWMK4paBZ3JhbnQKdGVybm9vbgriloFhY3F1aXJlZAriloFOeQriloFjb21tYQpuw61rCuKWgVN0ZXAKaW5uZXJzCuKWgVNBCuKWgXdhdApkYXlzCuKWgXJlY3RhbmdsZQpkYXIK4paBdHJhYwriloFJbmRvbmVzCuKWgWZlZWRiYWNrCuKWgWJyZWFrcwpwYXJ0aXRpb24KaWNhbnMK4paBTm90aWNlcwriloFpbXByb3ZlZApwaGFuCuKWgWRpZmZlcmVudGlhbApzY3JpcHRzCuKWgVhJSUkK4paBTGFib3IK4paBcHJlY2lzaW9uCuKWgXNlZWQKYnVuZGxlCmlkZW50cwpocmUK4paBRG91Z2xhcwp1bGQK4paBc2Vjb25kYXJ5CuKWgWJyaWcK4paBY29uZmlybWVkCuKWgWNsYWltcwpSb2xlCuKWgUpld2lzaAriloFwxZllZAriloFob3RlbAriloFjb21wdGUK4paBcmVjdXJzaXZlCl0oIykK4paBcm90YXRlCuKWgWNocm9tZQppbmVhCiU7DQriloFFbnZpcm9ubWVudApwbGF0egriloFTaW5nbGUK4paBc2V2ZW50CuKWgXBvc3RpbmcK4paBZGVhbGluZwpwYXJhbWV0ZXJzCtCz0YDQsNGECkF1dGhlbnRpY2F0aW9uCnRvdWNoCkF6CuKWgWdyYXkKZW5jaW5nCmJvbGRtYXRoCuKWgdGB0LDQudGC0LUK4paBWmEKYW5qZQriloFwb2xhcgriloHRg9C70LgKa2lsCuKWgWhvdmVyCuKWgVJFU1QK4paBQ29tZQpqYgriloFHZW9yZ2lhCuKWgUVzdGFkbwpPdXRwdXRTdHJlYW0K0ZvQuAriloFkdW1wCuKWgUFnZQriloFzd28KbW9iaWxlCm9jY3VwCtGI0LXQs9C+CuKWgWNvbnN0aXR1dGlvbgpnb29kCmFrdQriloHQsNC90LMKaWVjawriloFQc3ljaAriloFyb290cwriloF2ZXN0CuKWgdCz0L7QtNCw0YUK4paBUmVww7pibGljYQriloFwaWFuCmlncmF0aW9uCuKWgXByw6ljCuKWgWdlbmVyYXRlcwpMWQooYAriloE9fgrRiNC10L3QuNGPCuKWgVJhaAriloFjb25uZWN0aW5nCsW+w60K4paBZsWRCuKWgWFwcGVsCuKWgVJhaWx3YXkK0LPQu9C4CuKWgWTDqXZlbG9wcAriloFhcG8KZnJhbgriloFpbW1lZGlhdGUK0LLQvtCz0L4KUnVubmVyCsOkZwpTb21ldGhpbmcK4paBZ8OpbsOpcmEKRXZlbnRBcmdzCmluY3Rpb24KZ2x5CuKWgUR1ZQriloFwcm9zdAriloFyZWZlcnJpbmcK4paBam9nCuKWgWV4ZWN1dGFibGUK4paBRHJlYW0KYWNzCuKWgUNvbGUKYW1wZgriloFCaXMK4paB0LjRjtC90Y8KbGllZGVyCtGC0LXQugriloF2YgriloFtb20K4paBOigK4paBZGVybmllcgonPT4K4paB0Y3RgtC+0LPQvgriloFuZXVlCuKWgdCn0LAK4paBd2VpdGVyZQriloFhbGxlZwriloFyZWFsaXR5CuKWgWp1ZGdlCuKWgUJhbHQK4paBdGhpbgriloFHZWQKaWV2YWwKbXgK0YbRltC+0L3QsNC70YwK4paB0LLRi9C/0YMK4paBSVgK4paBYmxpbmQK4paBTW90b3IK4paB0YjQsAriloFhcHByb3hpbWF0aW9uCmRhbQriloFmb2cK0LrQvtGACuKWgVdyaXQK4paBbGluZwriloHQv9C40YHQsAriloFNYXJzCm90dGkKRW51bQriloFUcmliCuKWgW1lcmMKenVuZwp2YW5jZWQKY2ZnCtC90LDRhQpzY2hlbgoiXS4KYmVrCuKWgXN0ZXIKanAK4paBUmFwCuKWgXJlY29yZGluZwriloFwZWludAriloFsZXRzCsOkbmdlCj4iOwriloHQvNGW0YHRhtC1CuKWgWNhdmFsCuKWgUNTVgriloFlbnRzdGFuZAriloFoZWxwZXIKZW5kZXQK4paBR3JhbQriloFEaWVnbwriloFCaXNob3AKVEFHCuKWgWVjYwriloFFZW4K4paBQVYKQ2l0eQriloFHdWlkZQpoaW5kCnJpY2FsCuKWgdCe0YHQvdC+0LIKQnVzCuKWgXp1bsOkY2hzdAriloF0aWNrCuKWgUNvbG9uZWwKVGhhbmtzCuKWgWZlcm0K4paBZ3JhbnRlZAriloF0aHJlc2hvbGQKb21vcnBoaWMK4paBSHVuCmVuaXMK4paB0L/RgNCw0LIK4paB0Y/QutGWClBHCuKWgXdzCuKWgXRlY2huaWNhbAplc3RybwprbMOkcgp2YXJzCm9jcmF0CuKWgdC+0L/RiNGC0LgKb25zbwppYmEK4paBU2F2ZQriloFwcm9ncmFtYQriloHQstGKCuKWgWludsOlbgo+KCkK4paBbWVqb3IK4paB0YHQu9C+0LLQsAriloFyZXBsYWNlbWVudAriloFpbXByCuKWgUZyYW5jZXNjbwriloFIb3RlbAriloFVUERBVEUK4paB0LzRg9C30YsKdWdzCnZhcmQK4paBZmF6CmludG9uCuKWgWFydHMK4paBS3kK4paBSWxzCuKWgXNlcmEK4paBVm9sdW1lCuKWgWdpdWdubwriloFhc3ltCuKWgVBpcgriloFOQVMK4paBVGFtCsSbbApTZXF1CmttYWwK4paBRWlucwriloHQutC+0LzQv9CwCm9iZQpvb3IK4paBaGVhcApjdGwK4paBc2VwYXJhdGVseQpyZWFkZXIK4paBc2lnbmlmaWNhbnRseQriloFMYWcKbm90ZXMK4paBc2VsZQriloFkZWRpY2F0ZWQK4paBSG9zdApjaG9pY2UKd2luZwriloFUaXRlbAriloFiZWZpbmRldApsYXJnZQriloFjb250ZW4KSmF2YVNjcmlwdAriloFkZXNlcgriloFHb3Jkb24K0YHQv9C1CuKWgXBhdHJpCuKWgVJhbmRvbQriloFSZXR1cm5zCtGL0LwK0YDQvtC80LAK4paBU3R1ZGllcwpTbAriloFmcsO8ClRFWFQKaW5hdGUK4paBVG9sCuKWgWV2ZXJ5d2hlcmUKYXJ0YQriloFvcmJpdAriloFBaXJlcwriloFJc3MK4paBdGXFvAriloFkaXZlcnNlCuKWgW51bWVyaWMKbWF6CuKWgW1pc2UK4paBYmF0dGVyeQriloFBa2FkZW0K0L3QtdC90LjQtQriloFzaW11bHRhbmUK4paBRGVhZAriloFjbHVzdAriloFvdHJvCuKWgWNlcmNhCigpYCwKcm96CsSDdAriloFNTwpyaWZ0ZW4KaW1wb3J0YW50CuKWgWplaG8K4paBZmluZFZpZXdCeUlkCuKWgWNvbnNlcXVlbmNlCuKWgW1lYXN1cmVkCmlzaGVzCuKWgXN6ZQppZW5kbwriloFXYWhsCnN0cmlwCkFSRAriloFvcGFjaXR5CldPUkQK4paB0JLRlgriloFMb2NhdGlvbgpyYWkK0L/QtdC9CuKWgXJpZgphdXNzaWFuCkZpbGVOYW1lCuKWgWRpc2NvCmlsZW4K4paBdmFneQpsaWNpdHkKQm9yZGVyCuKWgVRyYWNrCtCx0L7QvApmYWN0Cm9rYQriloFnaW9yCuKWgVhWSUkK4paBZMOkcgpTaXRlCmHFgm8Kc2vDoQriloFwaXhlbHMKdml0eQpqUXVlcnkK4paBc2N1bHB0CuKWgWNhcmdvCuKWgWRpcmVjdGl2ZQriloF3YWwK4paBY29ubmEK4paBVGhyb3VnaAriloHRjdGC0L7QvApTdGF0aWMKb21zbml0dAriloFydW5kCuKWgWNsYWltZWQK0LfQvdGPCnNoYQriloFyYWcKY3JlbWVudAriloFmw7xuZgriloFyaXZhbApyaW4Kc2xhc2gK4paBdGhpcnR5CnNsZWVwCtC+0LvQvtCz0LgKU00KZ2F0ZQppemF0aW9ucwp2aWsK4paBYmxlc3MK4paBSWxsaW5vaXMK4paBVEUKdXRpbmcK4paBc29sdmluZwpHRVIK4paBWElWCuKWgUluZGlhbnMKZXhwcmVzcwriloFIZWlsCuKWgW11amVyCuKWgWludsOlbmFyZQonXSk7CuKWgWF1cgpib29zdApHTwriloFuaW4KdG9rCmdvZApvdGVyCikkJAriloFkZXNjZW5kCtGA0Y4K4paBTGFuZ3VhZ2UK4paBZGl2ZXIK4paBQXNzdW1pbmcK4paBZnJlcXVlbnQK0YfQvdGWCuKWgUJpb2dyYXBoeQosWwp1cm0K4paBd2Fsa2VkCuKWgWZlZGVyYWwK4paBTWljaGlnYW4K4paBZmFjdHMK4paBSW50ZWdyCkxFUwriloFBbGFuCuKWgWNvdXAKQmVyCuKWgXBhcnRpY2xlcwrRm9C1CkluZmxhdGVyCisoCkJvdW5kCuKWgVPDvApBdWRpbwpjaXRldAp5ZWN0CuKWgW5yCnhlCuKWgUJydW4K4paBXywKYXZvcgriloFkaXNjaXBsCmFsbQriloHQvdC+0Y/QsdGA0Y8K4paBU1NMCuKWgUthaXNlcgriloFyZWNoZXIKeWdvbgriloFyZWdhcmRsZXNzCuKWgWNvbmZpZ3VyCuKWgXVubmVjZXNzCuKWgUNsYXJrClBIUAriloFGQUxTRQriloFwYWQKJH0K4paBdmFsdQriloFkaXNlYXNlCuKWgW1haW9yCuKWgWhvbW1lcwriloFFZGl0aW9uCnNsYW50CuKWgWVuZGluZwriloFzZXR0bGVkCnVydXMKaGVkClBhdHRlcm4K4paB0LPQvtC00LjQvdCwCuKWgVBoaWxhZGVsCnRpa3pwaWN0dXJlCuKWgWNvYWwK4paBc2VkZQriloFzYXRpc2ZpZXMK4paBdHJpbQriloFiYXQK4paBYW3DqXJpY2FpbgriloFsdWdsaW8K4paB0L/QvtGH0LAKZmZmZgriloFUYXJnZXQKZ2VuZXJhdGUK4paBWmllCsibaWEK4paBZ2FyZAriloF3b3JrZXJzCuKWgUpvYgriloF1cmJhbgphaGxlbgriloFCdWlsZGluZwriloFuZXUK4paBY2hyb24K4paBRWFybApncm8KVVNFCuKWgVhJSQriloF3ZWFsdGgKaW5hZQriloHQkdGA0LAK4paBbGliZXJ0Cmlyb3MKOiQKbGVlCmlldmVzCuKWgUp1c3RpY2UK4paBb2lsCuKWgUF0aGxldAriloFjbG8KU2NhbGUK4paBbGlwcwriloFhcHJpbAriloFpbXByZXNzaW9uCuKWgXBlcmNlCuKWgdGD0YfQsNGB0YLQuAp2aWwKw6ljaAriloFlcXVhbGl0eQriloHQvNC10YIK4paBYW5ub3RhdGlvbgplcm5hbAriloFNYWNoCuKWgWludGl0dWwKcHJvYmxlbQrRjtGJ0LjRhQpvcGx1cwriloF0aG91c2FuZHMK4paBY2FsY3VsYXRpb25zCnVtcHMK4paBdHJpYW5nbGUKcGhhbAriloFEb3JmCuKWgWRvbGxhcnMK4paBZGVuZW4KbMOocwpvbGlkCuKWgVJlc3VsdHMK4paBU3RhZGl1bQriloFEZXNwCuKWgUVpc2VuCmltaXIK4paBc290dG8K4paBxI1pCmF0YWJsZQpvcnVtCuKWgWNvbnZlcmdlbmNlCuKWgWpldW5lCm9raW5nCuKWgdC20LjQstC+CmFpbmluZwpwb2ludGVyCmN1bG8K4paBanNvdQriloFncmFiCmFrdGUK4paBaG9waW5nCuKWgU1hawriloFzYWcKb3JpZ2luZQriloHQv9C+0YHQu9C10LQK4paBVmVnCuKWgXRoZW9yZXQK4paBVHJ1Cm5lbWVudAriloFmYWNlcwpIb3IKSm9pbgphcmVsCuKWgdC+0LrQvtC70L4KSG93ZXZlcgriloFjYXRhbApib3VyZwriloFteXNxbGkKYWNpb25zCuKWgUluaXRpYWwK4paBcmFpbgppdHVyZQriloFTY2llbmNlcwriloFLcmVpcwouX18K4paBY2lucQriloFBdcOfCml0aG1ldAppdG9ycwphbWF6b24K4paBZ2FwCuKWgWlnbm9yZWQKYWR2CtC60L7RlwriloHRh9Cw0YHRgtGMCuKWgWNvcnBvcgrRhtC10YAK4paBY3JpbWUKdW91cwriloHQvdCw0LvQsNC30LgKRGF0YUZyYW1lCtCy0L7QtNC4CklnbgriloFMaW5jb2xuCuKWgW1lbm9zCuKWgUx1ZnQK4paBTGluZAriloFDb29rCuKWgW1hdGVyaWFscwphcHBlZAppZ25vcmUK4paB0L7RgtC60YDRiwpmcmllZAriloFnb3V2ZXJuZW1lbnQK4paBZmlyZWQK4paBc2NyZWVuc2hvdArRgdC10L0K4paBWygK4paB0L7RgNCz0LDQvdC40LfQsApHcmFwaGljcwriloHQv9GA0L7RgtC4CuKWgXBoZW4KY3JhZnQK4paBYnJhaW4K4paBQ29tbwriloFFdmVyeXRoaW5nCmFuZXMKSUdOCuKWgW5lZGVyYsO2cmQK4paBRm9yZXN0CnphaGwK4paBQW1vbmcKUXQK4paBdG9nZwriloF2YXJpYW50CuKWgWhpbGwK0L/QuNGB0LgKY29sb24K4paBZGljZW1icmUK0LPQvtGACuKWgVdpbmQKw7xuc3RsZXIK4paBPVwKc2F2ZWQK4paBbmVqCnVudGUKdXR0bwriloFyZWNlbnMK4paBc2ljawriloFkZXNlbgpVU1QK4paBd29yc3QK4paBQW5nZWwKb2RveAriloFQcm92aW5jZQriloFNYXoK4paBYWdyZWVtZW50CuKWgUJhc3MK4paBc2VndW5kYQpvbmNlcwriloFMaW5raQriloFDTAriloFqw6EKaXRlbWVudAriloHDoXJlYQriloFzY2FsYXIK4paB0KDQtdGBCmF3dApzaWVtZQriloFqdW5pCuKWgdGF0YPQtNC+0LYKaWt1cwriloFsaWQKcHBlbAphdmkK4paBYmFsYW5jZQppcHBpbmcKY3Vzc2lvbgrRh9C10YHQutC40YUKKCIuCkFsc28K4paBd2hpcwpIT01FCuKWgWJyb3duCuKWgWTDrWEK4paBcHXDsgpwbG90bGliCuKWgUphaHJodW5kZXJ0cwpESwriloFhbmNob3IKLi4uXQriloFBdXN0cmlhCuKWgW1hcmNhCuKWgWdlegppb3VzbHkK4paBbGF6eQp4YQriloFDaGFubmVsCuKWgW5ldWVuCmRhcwriloFzZWFyY2hlZAriloFzdGFhdAriloHQotCw0LoK4paBSm9zZWYK4paBU2hlcgpwb2lzCuKWgWVuZW0K4paBYWNjZXNzaW5nCuKWgdC90LXQutC+CuKWgWZ1cm9ubwriloFwc2V1ZG8KPz4K4paBZXN0YWRvdW4K4paB0JLQuNC00LgK4paBbW90aXYK4paBcmVjYWxsCmlzc29uCsOzYgopLS0K4paBRXJ6CuKWgdGB0LDQstC10LcKRGlyZWN0CtGB0L7QsQriloFzaG8KdsO2bGtlcgpBcApnZW5zCtC90LjRiNGC0LLQvgriloFBbXN0ZXJkYW0KdXNrCtC/0LvQvgriloFzaW11bGF0aW9uCuKWgUJDCuKWgVdvagphdXRvbQpBbGV4CuKWgWVjb25vbWljCtCz0L7QvAppa2FpCuKWgWFsdHJlCuKWgSctCuKWgVdlZwpOb3RGb3VuZArQudGB0LrQvtC5CuKWgWNvbnZlcnRpbmcKcGhhYmV0CmF0cmljZQpib3VybmUKYWxvbQriloFjb21wYXJpbmcK4paBWm8K4paBZmxhCtCy0LDRjwriloFlbnRyYQriloFjaGFyc2V0CmRldmVsb3BlcnMKw61zdGljYQp9PgriloFKYXp6CuKWgUhvd2FyZArRiNGC0LAK4paBY2xvbmUKZG9vcgriloFQaW4KKioqCuKWgXNpbGVudAplY3ljbGUKaXNjZQriloFtdWQK4paBRGlzcGxheQriloFsaXAK4paB0LjRgdC/0L7Qu9GM0LfQvtCy0LAK4paBY2hhcmFjdGVyaXN0aWMK4paBc2IKZmlyZWJhc2UK4paBQmV3CkNhbGVuZGFyCuKWgXVzbwrDqHNlCuKWgVJhdAriloFlc3BlcgriloF0aHJvd2luZwriloFyb2R6CuKWgXlhcmRzCuKWgWdyYXNzCuKWgW1hcmtlcgriloFLb3MKVGhldGEK4paBb3JnYW5pcwprZXJuZWwK4paBcGVyc29uYXMKa2VlcAriloFleGNsYWltZWQKb3NsYXYK4paBRW50ZXJ0YWluCtC90LXRgAriloFpbndvbgriloFSYW5kCnJlZHVjZQpmYWMKZXhwcmVzc2lvbgp5agriloFkaWZmZXJlbnRpCmFnbGlhCuKWgXRlbXBsYXRlcwriloFtxbEK4paBcHJ2CuKWgW1vaXMK4paBZ2V3YW5uCuKWgdCx0YPQu9CwCmJpYmxpCmRlbW8K4paBQW5kZXJzb24K4paB0YDQtdC0CuKWgXBvcnF1ZQriloFQb2xvZ25lCuKWgXRyaXAK4paBZXhlbXBsZQriloFJbnRlcm5hY2lvbmFsCuKWgdC60LDQvgpJbnNlcnQKZ2VuZXJhbApTRVNTSU9OCmJlcmdhCmjDpGx0CnVuYXMK0LzQuNGA0LAK4paBeWllbGRzCm1hcHN0bwpzcG90CuKWgStcCtC70LvQsAriloFwcmVjaXNlbHkK4paB0YfQu9C10L0Kc2hhZG93CkFyZQp1bmFsCuKWgWRpc3BhcgriloF0w610dWxvCm5lc3QK4paBTG93CuKWgXByb3QK4paBQ29zdGEKbmFtZWQK4paBZ2FpbmVkCmxlc2lhCuKWgWFkbWluaXN0cmF0aW9uCkltcG9ydApicmFuY2gK4paBc3ltcGF0aAp2b2oK4paBRUMK4paBbXVuaWNpcGlvCuKWgWFuaW1hdGVkCuKWgWRpcmVjdG9yaWVzCuKWgXJvb2YKesSFZAppbWV0CnByb3RvCmJsYQo6XQpoYXZlCmF0ZW0K4paBbnMK4paBc2VjdG9yCnRocmVlCm93YW5lCndlcnMK0L7QstC40YUKcmVuY2UK4paBZXh0cgppZ3RlbgriloFvY2NpZGVudArIm8SDCuKWgWVhdAriloFoeWRybwp1YmVybmV0ZXMKW0AK4paBTW9vbgriloFTaG8K4paBZWxzZXdoZXJlCsO8bGxlcgpVcGxvYWQK0LvQsNC90LQK4paBRsO2cgp3aXNzZW5zY2hhZnQKS1MK4paBcGh5c2ljcwp0egriloHRgdC10YDQtdC0CuKWgUFyYmVpdAriloHQvNC10YHRggriloFHZWJpZXQK4paBaW5zZWN0CkFoCml6YWRvCuKWgXRlbXBsZQriloFhbm51YWwKc3RhZAriloFoYWJpdGF0CuKWgUFCCndvcnQK4paBcmVwb3MK4paBTmV1CuKWgSQoIi4KVm9ybGFnZQriloFyZXByZXplbnQKZXN0YW5kZW4KSW50ZXJuCi5gCuKWgWZhaWxpbmcK4paBTWF0ZXJpYWwK4paBZWZmZWN0aXZlbHkK0YLQtdC70LXQvAriloHQs9C70LAK4paBbmFobQriloFkaWZmZXJlbnRseQpleHRlbnNpb24K4paBVmVybQplbmFibGVkCmNvbmZpZ3VyZQpuaW8KY2lvbmVzCuKWgUJlYWNoCtGB0L7QvdCwCuKWgWNvcHlpbmcK4paB0YPQutGA0LDRl9C9CuKWgdC/0YDQuNC30L3QsAp6aApEZXNrdG9wCuKWgXNvc3QK4paBc3Vic2VxdWVudGx5CuKWgUxlaHIK4paBw7MKbMOkcgpvZG9yCnBob24KbmMKaXRlcmF0b3IK4paB0Y3RgtC4CuKWgWV1cm9ww6kK4paBVG9yb250bwrDs2RpZ28K4paBcG9zdG8KZmZlCuKWgWNyZXcK4paBU2Nod2FyClNhCnNxdWFyZQriloFiZXNpZGUK4paB0JzRlgriloFhdGgK4paBYWR2ZW50CmNqaQp3cml0dGVuCuKWgXJ1c3MKcm9zdApISQriloFkaWNlCmNjYQriloFkw6lwCnBseQpiaWdnCnppYcWCCsO8dHQK4paB0L7QtNC90L4KSkVDVArRgdGM0LrQvtC80YMKbm9zCm1vY2sKTGF1bmNoCnNhbWUK4paBam9icwriloF3aWRlbHkK4paBZGVmaW5lcwriloFQc2UK4paBbmVpZ2hib3VyCtGO0YnQuNC1CuKWgWNsb3NlcgriloHRgNCw0YHQv9C+0LvQvgriloFjbHVicwpmbHkK0YjQuNC8CuKWgXN1ZmZlcmVkCuKWgW5hcgriloFsYXZvcgpFeHRlbnNpb24KaXRpb25hbGx5CuKWgWdyYWNlCuKWgUNhbXBlb25hdG8K4paBQ2hyaXN0bWFzCm1pZGRsZQpvdGhlawplbGVtZW50cwriloFzb25kZXJuCuKWgXRhcmRlCuKWgXBlcm1hbmVudAriloFjb25jbHVkZQpTZWcK4paB0LDQutCw0LTQtQp9IiwK4paB0YTQtdCy0YDQsNC70Y8KxZllZAriloFJTApqdWQK4paBVVNTCuKWgU5hdHVyZQppZmZlcmVuY2UKU2VyaWFsaXplcgriloF0d2VsdmUKdGlkCtC80LjRjwrRh9C10YHQutC+0LPQvgriloFjYWxlbmRhcgpjb25jYXQK4paBaW50ZXJzZWN0aW9uCuKWgVBBCmF6dXJlCuKWgXNpdHXDqWUK4paBa2luZHMK4paBYXVzZ2UK4paBcnVyYWwKVGhlbWUK4paBdGFsZQpub2luZGVudApnb2luZwpyeAphZ2kKd3JhcHBlcgriloFDb2FzdAptYkgK4paB0L/QtdGA0LXQtApzcHJlCuKWgX1cCuKWgUxJCnpuYW0KaXRsZWQKU2FtcGxlCnVsaWFyCipcCuKWgXJlc2lzdGFuY2UKc3RvY2sKa2VkCuKWgUhFCuKWgXBvc3Nlc3Npb24K4paBUmluZwriloFtYWd5YXIKb3V0cwriloFTZWNyZXRhcnkKbmRlCuKWgVdhbGQKLSgK4paBSVNPCuKWgWFmdGVybm9vbgppb25lbgriloFzdG9wcwriloFjb25zdGFudHMKZ3VhcmQKYm93CuKWgWVycwriloFGaXJlYmFzZQriloFDbGVhcgriloFIb2x5CldpbgriloF0aXRsZXMK4paB0YLRgNCw0LIK4paBY29udHJpYgpow6RuZwriloFwaG90b2dyYXBoCuKWgURpc3RyaWJ1dGlvbgppZnRzCuKWgWF1bnF1ZQpjb21iCkFERAriloFwdWJsaWNhdGlvbgriloHRgdC70YPQtgriloHQutC90Y8K4paBYXlhbnQK4paBcmVzdG9yZQriloFiZWxpZWYK4paBdsOpZwriloFleHRlbnNpb25zCuKWgWRlY29tCtCy0YjQuNC5CldUCuKWgXBhcnRpCuKWgWdpb2MK4paB0LzQuNGA0LAK4paBaXNzdQpwaXBlCuKWgXByb3BzCuKWgXdpbGxpbmcK4paBbmVzdAphc28KcG90CuKWgWhhbmRsZXMK4paB0YTQvgriloFtb2RlcgriloFlYmVuZmFsbHMK4paBZmlnaHRpbmcKdW1ibgriloF0cmFuc3BhcmVudAriloFLcmlzdAriloFob21lcwriloF2b3lhZ2UKRmFpbGVkCuKWgUJpcmQK4paBSGVhcnQKQ291bnRlcgriloFTY290dGlzaArDoXRpY2EK4paBYXJiZWl0Cl57LVwK4paBU29yCuKWgWVuZ2FnZWQK4paBYXNpZGUK4paBRm91CuKWgXdpZWwK4paBcmVjb25zdApvdXNpbgriloFob3N0ZWQK4paBY2xhc3NlCuKWgWNvbnRlc3QKLi4uIgrQvNC+0LwK4paBYmVhbgpnZW0K4paBY29uc3VsdGF0bwriloFiaW8K4paBc3ViamVjdHMKYm9Cb3gK4paBU2NocmlmdAriloFkaW5uZXIKxINyCuKWgXLDs3duCuKWgSUlCmJhZ2UK4paBdmVyw7ZmZgriloFkZXRlY3RlZAppZW5uCnJvc2UK4paBVG9uCkNvbXBsZXRlCuKWgXByb3RvCmljaHRzClNUQVQKQ2hlY2tlZAriloFpbnRlbgriloFzbWlsZQriloFzdHJpcApuZXV0CicpOw0KZm91cgriloF0b2RhcwpDb250cm9scwriloF0aG9yb3VnaApydXAK4paB0LTRgNC20LDQstC4Cml0xIMKUHJvdG9jb2wK0JrQsAriloFleHBhbmRlZApleHRyYQpvcG9ydAriloHQodGC0LDQvdC+0LIKbGVhc2VzCuKWgW5vdGlvbgriloFndWVzdAriloFJc2xhbmRzCmlja2VkCuKWgURhdmUK4paBcmVmbGVjdGlvbgpsaXYKw6FsbsOtCuKWgXJldmVhbGVkCuKWgXNvZwriloFUYXgK4paBcGVyaW9kbwriloFXZWx0a3JpZQpjYXRhbGluYQpxdcOpCuKWgUZhdGhlcgriloFCaXIKZXhwZWN0CuKWgXJlZ3Jlc3Npb24KaW7DqQriloFkYWJlaQpwZXJtCtC80LXQvdC1CuKWgUFiZAriloFDRgphcmtzCnJlc29sdmUKd2VkZ2UK4paBaW5pdGlhbGl6YXRpb24K4paBVsOpYXNlCuKWgdC/0YDQuNC90Y8Kc3RtdAriloFpbmNvbWUKTVkK4paBb2RrYXp5CuKWgVNpZWhlCuKWgWJvZGllcwriloFzb2MKUmFuZG9tCuKWgXNlbnphCmFibG8K4paBcmVnYXJkZWQKb25DcmVhdGUK4paBTWFnYXppbmUK4paBUmFmCuKWgUJ1ZW5vcwrQuNC7CikpKTsKY2FwdApyZWRpcmVjdAriloFwZXRpdAriloFmYXJtCuKWgXLDtGxlCuKWgdGB0YLQsNGC0YzQuArCoMKgwqDCoApzdWJmaWd1cmUKw6hjZXMKemllbAriloHQvtC60L7QvQpFRQptZWUK4paBcGVydGVuCuKWgXJlcHLDqXNlbnQK4paBTEEKPycK4paB0YLRgNGDCuKWgXJhdGlvbmFsCm9zb2YK4paBa25lCuKWgWFydGlzdHMKRmxvdwriloHQkNC70YwKaXphcmQK4paBbnVtZXJvCmFjdGljCuKWgWRlc3RydWN0CuKWgdCf0YDQsApvbnNpZXVyCnF0CmFiZXN0YW5kZW4Kbm/Fm8SHCkNvbm5lY3QK4paBb3JhY2xlCuKWgVN0b2NraG9sbQpzaXplb2YK4paBZ2Vtw6TDnwpBQ1QK4paBZXhwZXJ0CnV0aW9ucwriloFoYWNpYQriloFsb2dnZXIK4paBZm9vbApyeXB0bwrDpnIK4paBY2lkYWRlCuKWgdGB0L7RgdGC0LDQstC1Cm9rZXIK4paBVHJhbnNmZXIK4paBZGVuaWVkClRyYWNrCuKWgXJhZGkKemVjCuKWgUhpc3RvcmljCuKWgUVpbndvaG5lcgrQutC+0Y4K4paB0YXRgNCwCuKWgUNhdGVnb3J5CuKWgURpc25leQriloFzd2FwCkJlZ2luCuKWgW1pZW50cmFzCuKWgWRhbmNlCuKWgXTDqnRlCuKWgWRyb2l0CmVydGEK4paBYmlyZHMK4paBY29udmluCnBhcmF0b3IK0LTRgNCwCuKWgUVTCuKWgVJlc3NvdXJjZXMKRUdJTgrDvGNrZQriloFDcnV6CmFibGluZwriloEiQAriloFtZXRyZXMK4paBQmVnCuKWgUdyw7xuZAriloFCb2gK4paBbWlsZQriloFUZWNobm9sb2d5CiIrCmFjY28K4paBc3MK4paBRmVkCuKWgUhlbmQKdXNjaAppdMOkCmZvbGsK4paBYWJzb3IKYW50YWwKb2RnZQriloFXSEVOCuKWgUV4dGVybsOtCuKWgVJlZ2ltZW50CuKWgWV2YWx1YXRpb24K4paBVGFpCuKWgXZvY2FscwriloFleHBlcmltZW50YWwKZW1iZWQK4paBTWlubgriloHQstC80LUKcHJlYwpldmVyeQriloFob29mCuKWgUZlcm5hbmRvCuKWgUJpYmxpb2dyYXBoaWUK4paBbmFnCmFtZXJpa2FuaXNjaGVyCuKWgW1hcmtzCuKWgVVUQwriloF1bmNlcnRhaW4K0LTQuNGPCm9saWEK4paBY3VwCuKWgWZpbGxlCuKWgWRvawp1c2VwcGUKZXN0ZXJkCuKWgUJyYW5kCuKWgVRoaXJkClBQCm5vZGVzCuKWgVBhZAriloFsb3ZlZApzd2luZwriloFzdXJwcmlzZWQKYXJkaQriloFHUgpdIgriloFlcXVhbGx5CmloZQpjYXJlCtC/0LjRgdC+0LoKbGlqawpyaW5uCuKWgVxbXAriloFzb25zCuKWgXTDpHQKaWNhbWVudGUK4paBbGlzdGluZwppZWxsZW1lbnQK4paBbnllbHZlbgriloFkcwriloFhZ3JpY3VsdAriloFIZXJtYW5uCuKWgWJlc2lkZXMKcHJvZ3Jlc3MK4paBcGVjdWxpYXIKZm9jdXMKY24KLSQK0YHRgtCy0LXQvdC90YvQuQpvdXJnCuKWgXd5bgriloFjb25kdWN0ZWQK4paB0KHRgtCw0L3QvtCy0L3QuNGI0YLQstC+CmNvbm5lY3RlZAriloFib3R0CuKWgdGB0LzQtdGACuKWgVBvegp1bmN0CmNvbmRhCuKWgdGB0LDQstC10LfQvdC+0ZgK4paBaGF2ZXQKbGlndApvcnRlZAriloFlbnRlcmluZwptdWx0aXAK4paBVGVtcGxlCuKWgVBsYW50CnR5cGVvZgriloFWbGFkCuKWgXF1ZWQK4paBcmVzdGUK4paB0LzQsNC5CuKWgVZlcnkKYW1iaWd1YXRpb24K4paBY2hhbGxlbmcK4paBcmVzcGVjdGl2ZQriloHRgtC+0YAKQ3RybAriloFhYnNlbmNlCmFydQrQstC+0LUK4paBZsO2cnN0CuKWgXNxCuKWgUVtcGVyb3IK4paBSWduCuKWgdGC0L7QstCwCjpgCmFkb29wCuKWgU1hZGFtZQriloFncnVwcG8Kc3R1ZAriloFleHRlcm5hcwriloHQkNC70LXQutGB0LDQvdC00YAK4paBZGlnbgriloHQttC40LLQtQpBbW91bnQK4paBY29ycmVsYXRlCuKWgUZhbnQK4paBcmFpbHMKZnAK0LzQuNC90LjRgdGC0YDQsNGC0LjQsgriloFib3VnaHQK4paBZmlsdGVycwriloFhbmNvcmEK4paBcGFydG5lcgriloFxdWFuZApzeW1ib2wKdWxhdGluZwriloF6ZAphd24K4paBR3JhbnQKYmVjYXVzZQpyYWJsZQpcfQrDrXN0aWNhcwriloHRg9GH0LUK4paBcMOpcmlvZGUK4paBc2tlCuKWgUFueXdheQriloFpbmRleGVzCuKWgWRpcmVjdGlvbnMK4paBUkFNCmNocm9tZQriloFhcG9zdAriloF3YXJuaW5ncwriloFBaXJwb3J0ClZJCmFiaWxlCuKWgWxvcmQKcHJvdmlkZXIK4paBSmkKb3N0cmVhbQriloFnZW1lZW50ZQp0YWJsZVZpZXcKRXh0cmEKY3Vyc29yCmVncm91bmQK4paBTW96CuKWgXJpYgriloFtb3JwaApsb2FkcwplbHNrCuKWgU1BWAriloFTYW50aWFnbwriloFIaW0KY29kZXMK4paBbGFuegriloFjb3VudHMKcmlubmluZ3NvbXLDpQrRidGRCuKWgXNww6kK4paBcGllcndzCuKWgVN2ZXIK4paBYWNrbm93CkJvb2xlYW4K4paB0YTQsNC80LjQu9C4CuKWgVNlbmF0ZQrRiNC+0LIKYWdlcnMK4paBTnVldmEKYmlsCmtpZW0K4paBTWV5CndpagriloFHbWJICnZhbGlkYXRpb24K4paBZW5zdWl0ZQppbmtpbmcK4paBY2FtcGlvbgriloFmaW5hbmNpYWwKaXpvbgpIZWFkZXJzCuKWgWRlcHJlY2F0ZWQK4paBZm9uY3Rpb24KUkVHCuKWgXZvbHVtZXMK4paBQ2hpCuKWgWVuY291bnRlcmVkCmxhawrRgNCw0Y8K4paBY29udGludWVzCuKWgX5bCnVlcnRlCuKWgVw7CuKWgURvawriloF3ZWlnaHRzCuKWgXJoCuKWgU5hcG9sZQriloFuYXR1cmFsbHkKc2t1CnBhcwriloFnZWdyw7xuZApldHIK4paBS3UKaWN0ZWQK4paBZmFicmljCuKWgUFTQwriloFFbnRlcnRhaW5tZW50CuKWgWVuZXJnCtC60LvQsNC0Cm9tb24KdGhlbWUK4paB0YXQsNGA0LDQugriloFkcmFmdAriloFjaGFubmVscwriloFkZXNlcnQK4paBdHJhdsOpcwriloFMb2NrCuKWgXNpZW5kbwrRhNC10LoKbcOqbWUK4paBcGFja2V0CuKWgU1vdW50YWluCuKWgUZhaHIKYnJhaW8K0L/QtdGA0LUK4paBZ2VuYW5udAriloFkZXBsb3ltZW50ClBhbArQvdC+0LMK0YHRgtGA0YMKUHJpbQpmw7xyCuKWgWRhbmdlcm91cwriloFzesOhbQpyZWNrCuKWgXBvcHVwCmlja3kKaW5hcgpjb3dvCtC90YbQuNC60LvQvgrDrXTDoXMK4paBcGx1Z2lucwriloFkcml2ZW4K0LvQtdCyCuKWgSIoCnR0YQriloHDmgriloFlYgriloEnJzsK4paBa25vY2sK4paB0L7RgdC90L7QstCwCuKWgW1haXNvbgrQs9C70Y8K4paBSG9ub3IKdGFpbApyaXR6CuKWgWd1eXMK4paBY29tYmluYXRpb25zCm9uZGVyZQriloFBbGQK4paBZmlkZGxlCtC00LDQsgp1cmQK4paBcHJvamVjdGlvbgriloFUYW1iacOpbgp2ZXJiCuKWgXRlcnJlCnJ1Z3UK4paBc2VwdGVtYmVyCuKWgTwhCmNvc3QK4paBbnV0CnslCuKWgXViaWMKYW1hcmluCtGC0LjQuAriloFwYXRyb24K4paBYW1lbHkK4paBZXN0bwriloFsaXN0b3AKZmFsCuKWgVByb3AK4paBT250CuKWgU1hZGUKVEVTVAriloFOZW0K4paBTmF0aW9ucwriloHQstGDCmluY2x1ZGluZwriloFzcGVjdHJ1bQriloFMYW4K4paBRXZlcgpQYXVsCnRtCkFwcGVuZApSZWxhdGl2ZQpkaXNhYmxlZApyZXR1cm5zCuKWgWZsb3dlcnMKaWt1CuKWgXxcCuKWgUpvcmRhbgriloFTbWFsbAriloFjaWMK4paBc2V4dWFsCmF1dHJlCtCy0LDQuwriloFyaXAKb3VzdAriloFQaGlsYWRlbHBoaWEK4paBdWsK4paBTW9uZ28KeG1sbnMK4paBc2hvcAriloFkZWJ1Z2dlcgriloF6YWoK4paBQmlsbHkK4paBbmllbQpvbGlzCuKWgdGA0L7RgdGB0LjQuQphZ25lcgriloFtYXZlbgriloFHdXN0YXYKQXVzCmNvbXBhcmUK4paBamV1CnVkZXIKaXNobWVudAriloHQtNC40LLQuNC30LgK4paBRmlubGFuZArQvdGD0YIKesOpcwriloFMaWdhw6fDtWVzCuKWgXF1ZWxsbwphbm5vdGF0aW9uCuKWgXRocmV3CuKWgVByb29mCuKWgUFyZWEKYXNoaQriloFGTwpqYW1pbgrQtNC10L3RggriloF1bnVzCmZyaWVuZAouIik7CuKWgXRyYWt0ZW4KZG9jdW1lbnRjbGFzcwphbmthCuKWgWFycml2ZQriloFkb25uZQpvbHkK4paBUmVpbgriloFmYWNlYm9vawppY2luYQpzbGljZQriloFuYWd5CuKWgWhlYmJlbgriloFJQwriloFCYWcK4paBY2lyY3VsCsOhY3QKbWl0dAriloFncmV5CuKWgWNhdgriloHQvtGB0L7QsdC4CuKWgXN5bW1ldHJpYwriloFTaWMK4paBbWVkaXVtCuKWgVVURgriloFEb3BvCsOtY2gKYmFyZQpkemllCuKWgWhlYXZlbgriloFjYW1wZQplc3RlcmRheQriloFXaXNzZW5zY2hhZnQK0L/QvtC70YwKZGlkCmFsZXIK4paBY2l0aXplbnMK4paBTWFyZ2FyZXQK4paBc291Z2h0CmNoYXJ0cwpDTEMKb2xseQp5c3oKd2FsZAriloFmZW4K4paBU2l4CuKWgVVycwriloHQvtGA0LPQsNC9CuKWgVRyYWQKY3VlCnNjaHV0egriloFwcmVjaXNlCuKWgVdpbmRvdwrRgtC40LUK0LvQvtCy0ZYKaXRvcmkKZGlzYW1iaWd1YXRpb24K4paB0YXQuAriloFOYXR1cmFsCmRhbgriloFjb25jcmV0ZQrRhtC40ZjQsAriloFzcGVsCuKWgUZhaWxlZArFm2NpZQriloFidWYKdWNhCmljaW9uYWwK4paBb3R0b2JyZQriloHRhNGWCuKWgXN1Ym1pdHRlZApsYXZlCuKWgVBsb3QK4paBY29sbGVnCmFkZW0K4paBY2hhcXVlCuKWgW5laWdoYm9yaG9vZAriloFjYWxjaWF0b3JlCkxvb3AK4paBR2FzdAriloHQutC+0LPQtNCwCuKWgWluZHVzdHJpYWwK4paBZmF0YWwK4paBQ2VydApsYXRpb24K4paB0J7QtNC90LAK4paBamFtYWlzCuKWgWFjY3VtCklkZW50aXR5CuKWgU1lZGFsCk1ldGFkYXRhCuKWgdC70Y7QtNGPCmJyaWRnZQpHb29kCuKWgdGH0YLQvtCx0YsK4paBY29tcG9zZXIK4paBYnJlYWQK4paBY2xvc3VyZQriloFsYXJnZWx5CkZCCuKWgdC+0LHQu9Cw0YHRgtGMCuKWgWF1dG9tYXRpYwphcsOtYQriloFzdWZmaWNpZW50bHkK4paBaXRhbGlhbmEK4paB0LrQsNGH0LUK4paBSsOzCmhpc3RvcnkK4paBSEQK4paBc2lndWllbnRlCm5lbGwK4paBR3JlZQriloFUaQriloF0cmFuc2ZlcnJlZArDqXF1aXBlCuKWgVBoaWxpcHBlCuKWgWVuY291cmFnCuKWgVZpZXRuYW0K4paBZ3JhcGhzCuKWgXN5bW1ldHJ5CmZyZWQKd2VlawriloFicm9uemUKcnlzCuKWgW5hbWVseQpvbmRlcnMKbGVtYWduZQpYWQpDb252ZXJ0Cn1dKApSZWdpb24KcGVjaWVzCuKWgXRleHR1cmUK4paBY2hyCtC90LXQs9C+CuKWgXNvbWVib2R5CmFxdQplcmFzCuKWgdCd0L7QstC+CuKWgWRlegphbml1Cm9rcmF0CuKWgWNvdmVycwriloFzaWduYWxzCtGS0LUK4paBSGViCuKWgUFudGkKSVZFCuKWgXJlc3MKTEVURQp5bmEK0L/Qu9CwCtC20LTQtdC90LjRjwriloFjaGFtcAriloF2aWxsYWdlcwpab25lCuKWgWlQaG9uZQriloFzb3V2ZW50CtGB0YzQutGWCuKWgWZlYmJyYWlvCsOpcmNpdG8K4paBWEkKb2thdAriloFtZW1icmVzCmp1bml0CuKWgURyYXcK4paB0L/RgNC+0LLQvgphdWRpbwplbmRsCuKWgU5hZAriloFtYWduaXR1ZGUKU3VyCmljaW5nCuKWgXVudwriloHQvtGC0YDQuAriloFCZXkK4paBVmlrCuKWgXBvbMOtdGljYQpwb3J0ZXIK4paBQmFyYmFyYQrDoWx0CmJpYgriloFhY2NvbXBhbgpWUAriloFlbmNvZGVkCuKWgVNvbWV0aW1lcwpiaXJkCuKWgVVsdAriloF0dW4KZ2V0VGV4dAriloFhcnJpdmFsCnNjcmlwdHN0eWxlCntgCuKWgXBlcnNwZWN0aXZlCkxJTkUKRm9ybWF0dGVyCuKWgWJvbQrQstGA0LAKREVCVUcKQm91bmRzCuKWgVRpdGxlCmzDswpEYW4K4paBZ2VuZQriloFCaXQK4paBcmVwcm9kdWNlCuKWgWdyYXBoaWNzCuKWgdGB0LXQvArRgNGRCuKWgdGA0LXQutC4CnVzYWxlbQrRgNC+0LYK4paBREVTCuKWgVNvZnR3YXJlCnVyYW5jZQppdGhtZXRpYwplbmVzcwppY2hpCkNvbnZlcnRlcgriloFnaXRodWIKZXJkaW5ncwpnbGlzZQrDoWNoCuKWgWJ1cmllZAriloF2aXNpb24KTWlzcwriloFzZWVzCuKWgXBlcnNvbm5lcwriloFJbnRlbAplbGlhCuKWgcSNbMOhbgriloFjaGkK4paBa2xhcwphdXTDqQriloFzdGFyawpjemUK4paBZHJpdmVycwp2bgohLAriloHQs9C+0LTRiwpIaQriloFleHBsYWlucwphcnRpY2xlcwriloF6dWcKUHJvbQo+PQriloFCZWF0CuKWgVNheAp2ZXJ0aWNhbArQutGC0L4K4paBcGxhbnRzCuKWgVLDqWbDqXJlbmNlcwriloFvZ25pCuKWgWN1cnMK4paBU0sK0L7QvdC4CuKWgWRlc3RhYwoiKTsNCuKWgVN1cmUK4paBcGFydGlkbwriloFGb2xnZQriloFNb29yZQriloF3egrRgdC60YPRgQpsdHJlCm9uZG8K4paBcG9zZQppbW9zCtCx0L7QuQrRhtC40L/QsApqdXMKLi4uLi4K4paBw6lwb2NhCuKWgXF1YW50bwriloFTdXBwb3J0Cmdlc2NoaWNodGUKU0VSVkVSCuKWgUdlb3JnZXMKZW51bQriloFoZXJtCuKWgW5lYm8K4paBQ2hyCmNoYXJhY3RlcgriloEqKioK4paBRm9yc2NoCmlhbWkK4paBwr8KY3ljaAriloFmaWZ0aApzZW50CuKWgWFuZGVyZW0K4paBcHJvcG9ydGlvbgriloFwcmVzdAriloFHaXJsCuKWgWRyYW1hCndhbmQK4paBTWFpbAriloFMdXgK4paBa3RlcsO9CuKWgUdlc2VsbHNjaGFmdAriloFIaW53ZWlzCm5pc3NlCuKWgW1vbmRvCkVxCuKWgXBlcsOtCuKWgWVhc3Rlcm4K4paBVUVGQQp1YWxlCuKWgWNvbnZleAriloHQv9C+0LvRjAriloFIZXkKemVuaWUKaW5pdGVseQriloFadXNhbW1lbgpTU0wKb2NhbAriloFjYW5hbAp2b3kK4paB0JrRgNC4CuKWgWvDtnrDtnR0CuKWgWNhcnMK4paBdmVyc2nDs24KRW52aXJvbm1lbnQKSGVyCuKWgXNlw7EK4paBc3BhdGlhbAp5bWkKRmlyZQriloF2ZWdldAriloFXaWUK4paBem5hagriloFkYW1hZ2UK4paBZW5kbApnaWYK4paBcXVhbGkK4paB0LrQvtGC0L7RgNGL0YUKZWxsYW4K4paBbWVucwriloFwbHVnCuKWgWFidW5kCkZJRwriloFzZgriloFjb25mbAriloHQvdCw0YHQtdC70LXQvdC40Y8K4paBcHJpbmNpcGxlcwriloFHYWJyaWVsCmliZQriloF7JQriloFwb2JsYWNpw7MK0L3RltGG0LjQv9CwCuKWgWV4dHJlbWUK4paBYXNzZQriloF2dQpNb2NrCuKWgXNwaWVsdGUK4paBQWVyCuKWgWRhdG9zCmVuZGVzCuKWgUdlbAriloFHb3IKQ2hyaXN0CmNob3MKUHJvY2Vzc29yCuKWgWluc3RydWN0CuKWgXBpY2tlZApuYWhtZQpmYWhyCuKWgWluZGljYXRlZAriloElLgriloF0cwriloFub3RhYmxlCuKWgXF1YWxpZmllZAriloHQkNC7CkJsYWNrCuKWgWNvdW5jaWwK4paBb3ZlcmhlYWQKYWNpCmFubsOpZQriloFpbml0V2l0aApiacOzCuKWgWludHJvZHVjdGlvbgriloFjb21wYW5pb24K4paBZXhwb24K4paBa8O2cgpvYnkKYnVybgpnbnUKdmlydHVhbAriloFpbnRlbGxlY3QK4paB0LTQtdGA0LbQsAonKwrQsdC70LUK4paBc3RyaWN0bHkK4paBcmVjb2duaXplCmhvdXIK4paBV3Jlc3QKZW5uZW4KJCkuCmZmZgriloFDZW50cm8K4paBUGl0dAriloFkemlhxYIK4paBY2VsYQriloFmcmFuY2VzZQrRgNCw0LzQuApzcGVjaWFsCuKWgUR1cAp0b2lyZQrQutCw0LvRjApDT1VOVAriloFCcm9vawriloHRgNGD0LrQvtCy0L4KcHVibGlxdWUK4paBc2Vjb25kYQriloFjb21wdAriloFibGFuZApCZWZvcmUK4paBUGFjawphbHR5CsO2ZGVyCuKWgWludGVydmFscwriloFEYXRlbmJhbmsKTW92aWUK4paBdHJhbnNtCuKWgXRhcAriloHQv9C+0YcKZm9uCmlhaQriloFmaWIK4paBd3lkCuKWgWh1bmcK4paBYWxpdmUKQ2xlYXIK4paBcHVzaGVkCuKWgXR1cGxlCmFjaGVuCtCz0L7QstC+CuKWgXJldmVycwriloFhdWdtZW50CuKWgWNoYWxsZW5nZQpsb3N0CuKWgWRldXhpw6htZQpzdHJ1Y3RvcgriloFtZWhyZXJlcgphdHVyYWwKU3BsaXQK0YHRgtC10LwK0YjQu9CwCilcXAriloFEb2cK4paBZGV2ZWxvcGVycwriloFub2QK4paB0YHRgtC+0YDQvgriloFOYU4K4paBcHJpZXN0CuKWgWV4aGEKVU5ECnBhaXIKYWxvbmUK4paBbW9vbgriloEjIS8K4paBZ3Vucwpyb2xhCtGH0LjRgtCwCuKWgUVuY3ljbG9wZWRpYQphdGlzCuKWgSciCnp5Y2gK4paBc3VwZXJmaWMK4paB0Y3QugrQtdC00LXRgNCwCmZlZWQKTEFZCkZpCnVua3MKaXNlY29uZAriloEnQAriloFBZGRpbmcK0YDQvtC1CuKWgXRhbmcK0YbQvgpodW5nCmJpcwpza8OpaG8K4paBYWR2ZXJ0CuKWgdC30LDQvdC40LzQsAp1enoKw6FnaW5hCuKWgVRlbApzaWcK4paBRXoK4paBZ3VhcmFudGVlCuKWgXRlYWNoaW5nCm90eQp0ZXJtaW4K4paBZGlzdHJpYnV0aW9ucwpGTEEK4paBR2l1c2VwcGUKcXVlcnlTZWxlY3RvcgriloEvXAriloFTcXVhZApnegpkZWxheQriloFzdXJyb3VuZGluZwriloFtYW51cwriloFIb3UKwrIsCuKWgWN1bHRpdgriloF0cm91YmxlcwriloFyYWlzb24KZXhwYW5kCuKWgWNvdgpudW5nZW4KKSl7CuKWgWdlZW4K4paBYXXDn2VyCuKWgdCb0ZYKxZlpCuKWgXNpdHVhdGlvbnMK4paBdGVsZXAK4paBSmVkCuKWgXRyYXZhaWwKbGlhcwpidWxsZXQK4paBc2VsZWN0aW5nCmF2aWVyCuKWgWVzc2VudGlhbAooLwp5eXl5CsWhdMSbCnVsdHkK4paBa3JhCuKWgXRhYnMK4paBZXhwZXJpZW5jZWQKYXppCuKWgURpcmVjdG9yeQriloFjcm9uCuKWgXNwZW5kCuKWgVJBCuKWgXNlbGVuaXVtCuKWgVRow6kKRWxlbWVudHMKY2lpCuKWgXBsYXQK4paBYXJjaGl2ZQriloFhc3Npc3RhbmNlCuKWgW5lY2sK4paBQXZlbnVlCuKWgXdoZWVsCuKWgWhhZGUKQ29tbW9uCuKWgURpYWxvZwriloFmb3JnCuKWgXN1cmVseQriloFob2NrZXkKa3TDswriloF0awriloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloHiloEK4paBQnJ1Y2UK4paBZW5vcm0KLOKAmQriloFDaHJpc3RvcGhlcgpqZXYK4paBcXVhZAriloFBSkFYCuKWgXJlbGllZgriloFtb2Rlcwpza2zDpHIK4paBVmlkCuKWgVNlcmlhbAriloF0b2tlbnMK4paBUG9sYW5kClxdCuKWgXZpZGUKcm9vbXMKb21hcwriloFCdXJlYXUKY3gK0L3QvtGB0YLRjNGOCuKWgXNpZ25zCtGI0LXQvdC40LUKbG9zc2VuCuKWgVF1ZWVucwriloFtZW1icmUK4paBbWV6CuKWgUJvb2wK4paBTmFqCuKWgU1lbW9yeQriloFLaGFuCuKWgWzDoAriloFIdWQK4paBZGlzbWlzcwppZ2h0aAriloFmcwpwcmV2ZW50CuKWgdC80LXQtNCwCuKWgVBvbGljZQriloHRgdC60L4KZmluaXRlCuKWgWFtaQriloFNdWNoCm93YW5pYQpPUlkKaW9ycwriloFQcmVtaW8K4paBdGV4dGJveApkbQriloFhZmluCuKWgURvbmFsZAriloFQcml2CuKWgWRlY2lkCuKWgU1hdXJpY2UKYWdhbgriloFCcml0YW5uaWNhCuKWgW9mdAriloFjb25zZWN1dGl2ZQoiPz4K0L7QstC40LkKc3R1ZGVudAriloFwZXF1ZQriloFkaWVzZXMK4paBcmV0b3VyCsOpdHIK4paB0YHQtdC3CuKWgWtyZQriloF2b3RlcwpydXB0aW9uCml6YWRhCuKWgVdpZWwK4paBR3JheQriloFMZW9wCnRlaWx1bmcKKFsnCuKWgXdoaXRlcwpmcmljYQphbmltYXRpb24KY3VybApsaW5ncwo9IiQKbG95ZAp0ZXh0c2MK0L7RgNGDCuKWgdGB0LXQu9CwCmVzaWFuCuKWgU1pc3Npb24K4paB0L3QtdC30LAK4paBdWx0aW1hdGVseQrQsdC+0LIKb2xlbgrRgdC60L7QvNGDCm5ldGUK4paBRGl0CuKWgWNvc3RydQpkZXBlbmRlbnQK4paBUmVzb3VyY2UK4paBaG9zdHMK4paBcmVhcgpEdXJhdGlvbgrQvdC40LrRltCyCtCc0LAK4paBcGxhbm5pbmcK4paBcHJlZGljdGlvbgriloFMeW4K4paBa2lyCuKWgUxlZ2lzbArQvNCw0YIK4paBU29jY2VyCuKWgXN1cnZleQriloFlc3RhZG91bmlkZW5zZQpvcmdlbgpqb3VyZAriloFhcHJpbGUK4paBaWRzCtGB0YzQutC1CuKWgWVtcGxveWVlCuKWgVNjaGF1c3BpZWxlcgrRgNGKCuKWgW11bHRpbWVkaWEK4paB0YHQstC+0Y4K4paBd2luZQriloFFVQppY8SDCuKWgVJoZWluCuKWgVBhbG1hcgpvdGVjYQriloFwcmVwYXJlCuKWgVRvdAriloFOdWxsCuKWgWtpbgppbmFscwriloFOZXd0b24K4paBdGJsCuKWgVNvbGQK4paBdmVyZgphdHVyaW5nCuKWgWxhcHRvcAriloHQodC+0LLQtdGCCnNlY3JldAriloFPbHltcGljCuKWgWZvb3RiYWxsZXIK4paBUnVkb2xmCuKWgWNvbmhlCnp5c2sK4paBZXZhbHVhdGVkCsK7KQpzaG9wCnJlcG9zaXRvcnkK4paBemFjaAriloFsb3NpbmcKZXR0ZXIK4paBV2lydHNjaGFmdArRgtCw0LoK4paBdW5uZWNlc3NhcnkK4paBUGhvdAphbnNrYQriloFOYXRpdmUKQ0NFCuKWgWZpZnR5CuKWgWVydwpyaAppc3NlbnQKfXsoCuKWgWxhbsOnCuKWgVhjb2RlCtCz0L7RgNC+0LQKY2lyCuKWgXBlbMOtY3VsYQriloFPc2NhcgriloFzaG9yZQriloFzdXBwbGllZApleGFtcGxlcwpNZXNzClZJQ0UK4paBZXhjbHVkZQriloFoZW4K4paB0LPRg9Cx0LXRgAriloFGcmFnbWVudAriloFCaXR0ZQriloFCZXNpZGVzCuKWgWhlcwriloFpaHJlbQriloFTZXJnZQriloFhcnRpZmljCj0iJHsK0LvQvtCy0L4KdXRldXIKdGFpcmUK0L/QsNGBCuKWgWVhc2llc3QK4paBZmFtaWdsaWEKTm9ybWFsCuKWgWRhbGxlCuKWgW5hdGlvbnMKcnAKdGhlYWQK4paB0L7QsdC70LDRgdGC0ZYK4paBRGVtb2NyYXRpYwriloHRh9C10LvQvtCy0LUK0LzQvtC2CuKWgdCz0LXRgAriloFzbWFsbGVzdAriloFQdWJsaXNoaW5nCuKWgVRzCuKWgWxhdWdoZWQKbGxlCuKWgUFtdAriloFJSVMKRk9STQpNYWcK0LTQvtC9CuKWgXN0b3JpYQriloFvcmdhbml6ZWQKxI1uw60K4paBb3gKbGluZ2VuCuKWgWx1ZWdvCmNjacOzCuKWgXJlbHkK4paBdHVzc2VuCmVydGVuCuKWgWhvbm91cgriloFDbGF1ZGUK4paBS29yZWEK4paBTWV0cm9wb2wKU3VwZXIKcmllbgrDqXJhdHVyZQphdHRybwriloHQsdGW0LvRjAriloFIZXJiZXJ0CuKWgWF1dGV1cnMK4paBZGFyYXVmCuKWgW1lbnRhbAriloFyYW5nCuKWgXPDs24K4paBU29waAopIiwKRGVzY3JpcHRvcgpwcmVwYXJlCuKWgUxhbmRrcmVpcwpIQwpjcm9zcwrQu9C40LfQsAriloFMb2dpbgpvbmVuCkZlYXR1cmUK4paBbXVzZXVtCnZlawriloFOZWxzb24K4paBcmVqbwriloHQutC+0LzQsNC90LTQuAriloFzdW1tYXIK4paB0YHQu9C10LTRgwrDpG1wCuKWgUdhcwrQstC+0LwKVkFMVUUKaW5nZQpwZXJpb2QKbGFzc2VuCsOhdmFsCuKWgWFsdG9nZXRoZXIKdW1waAppc3RybwrEhcW8CuKWgUtlZXAK4paBTWFyY28K4paBw6l0YW50CuKWgURyZQpnZW9tZXRyeQriloFLYXMKbWVzc2FnZXMKQ29vawriloFTaWRlCuKWgdC60L7QvNC4CtGB0YLRgNC4CuKWgWV4Y2VzcwriloFCaW9ncmFmaWEKWFhYWAriloFOaWUKdmVuZG9yCnhzZApNaWxsCnByb2Nlc3NpbmcK4paBTWlzc291cmkK4paBcGVybWV0dAriloFhcGFyCuKWgWNyb3dkCmZlcnQK4paBRG91CnLDrQriloFDQwriloFwYXltZW50CuKWgUhvbGx5d29vZAriloFWaXJ0dWFsCuKWgXNwb2tlbgriloF0cmFtCuKWgUNvbW11bml0eQriloFhZG1pbmlzdHJhdGl2ZQriloHQstC+0LvQvgpnaW9yCnZpc29yCuKWgdCj0LrRgNCw0LgKc3RhZ2UK4paBRm9ybWF0CuKWgWNvbnZlbmllbnQK0J3QsAriloFtZWRpYW4K4paB0LLRgNCwCuKWgdCf0YDQtdC80LAKZW5pZwriloFPcGVyYQpyw6lzCuKWgWZtdAriloFlZmZpY2llbmN5Cm1hbGUKTWFzdGVyClNlcmllcwriloFzeWQKZ2VuZXJpYwppbnRlcnZhbAriloFlZmVjdAriloFpbndvbmVycwrQu9C40LzQv9C4CmlyZW1lbnQKRXJyCsO2aAriloFseWluZwriloFTZXR0aW5ncwohPQplbWF0aWMKYXJndgriloFCYXNpYwriloFjb25zaWRlcmF0aW9uCuKWgWhhYmUKLSUK4paBbW91bnRhaW5zCuKWgXBlYWsK4paBZmFsbGVuCmVkZWQKbG9naWMK4paBbWF0Y2hlZAriloF0eXBpbmcKKX0sCuKWgWZhbmN5CuKWgWVsZWdhbnQK2KfZhAriloHRg9GH0LDRgdGCCuKWgVNhcmFoCuKWgVZlcmQK4paBdGVnbwpydWxlcwriloFtb3VudGVkCuKWgdGW0LwK0LXRgNGDCnN0b2ZmCmZhaHJlbgpkaXN0YW5jZQriloFMaWNlbnNlCuKWgUxFRlQK4paBd3AKL3sK4paBYW1hem9uCj4mCuKWgWVsc8WRCnF1YXJ0ZXJzCuKWgXNob2NrCm5pY2sK4paBQXJjaGl0ZQriloFTcXVhcmUK4paBcmF0ZXMKaW9yZQriloFOYXQK4paBQ2hhcmxvdApyZWljaGVuCuKWgXZhcmlhdGlvbgpvc2lzCmxpZmUKc2xpZGUKYWJpCnVraQpteXNxCuKWgXByaW1pdGl2ZQriloF1bml2ZXJzaXRhaXJlCkxFTkcKYWxlxbwKZWJvb2sKc3luCuKWgUdlZ2VuCuKWgUvDvAriloHQsNC70LUK4paBTHViCmNvbmN1cnJlbnQKaXp6YXRvCuKWgXN0dWIK4paBaWUK4paBJy4vCmNvZAriloFpbnRlcm5hY2lvbmFsCuKWgUdsYXMK4paBbWFyZQriloFOZWIK4paBR0IKa3dhcmdzCuKWgWF1bWVudApXSUQK4paB0YDQvtC0CnB1bmt0CuKWgUdyYWQKU04KQU1QCuKWgUJvcm4K4paBR3VlcnJlCtCz0L7RgtC+0LIK4paBbWVkaW8KTWVkCnN1cHAKYWN0dWFsCmRyb3Bkb3duCuKWgW9rdG9iZXIK4paBxZkK4paBY2lyY3VsYXIK4paBc2tpbgriloFlbXBoYXMK4paB0LPQvtC70L7QsgriloFwdWUK4paBaW5mb3JtYXRpb25zCuKWgVdvbGZnYW5nCuKWgXVzZWxlc3MK0LjRggriloFKb2FuCuKWgdCx0L7RgAriloFHbGFkCuKWgUtub3cKa8OpbnQKc3BlZWQK4paBS2V2aW4KdW5mdAriloFhcnF1CuKWgUNhc2EKKC4uLgriloFyYXBpZGx5CuKWgXByb2JsZQriloHQktC40LrQuNC/0LXQtNC4CsW+ZW4K4paBTmViZW4K4paBTWV0ZXIKQ2hpbGRyZW4KY2VtCmlnb3MKYWp1CuKWgVJldHJpZQriloFIZWxsCuKWgWdpZwriloFjb250cm92ZXJzCuKWgXpvb20K4paBY2VucwriloFhbGN1bmkK4paBSGVhZGVyCk1ldGEKUmVxdWlyZWQK4paB0LjQvdGB0YLQuNGC0YMK4paBc2t1cAriloFpbmdsZXMKw6lnbApiaWoK4paBdMOpcgriloFjb21wYWcK4paBY29tbWl0dGVkCuKWgXByb2Nlc3NlZApMb3dlcgriloFGb3JlaWduCuKWgXNlcQpzaGVldHMK4paBRmVtCmhvegppbmtzCuKWgWthbGwKdmFyaWFudAriloFsaWJybwriloFjbGlja3MK4paBZ29iaWVybm8KaWVnZWwK0LzQvtCz0L4KZ2VtZQriloF0b3dlcgriloFwYXJpc2gK4paBVENQCuKWgWxzCuKWgW5naW54Ck5hTgriloFEaXIK4paBQmVncmlmZmUKYXJpZQrDrW1wCmljaW9zCuKWgXNoYXJpbmcK4paBY2luw6ltYQpiZWMKUkVECuKWgUtyYQphYm9sCuKWgWZsdXgK4paBZXhwZW5zaXZlCuKWgdGB0YPRidC1CuKWgWBfCm9jegrQu9C40YHRggriloFhY3F1YWludAriloF3aXNlCuKWgXBvdXZvaXIK4paBZGV2YW50CuKWgW1vbWVudHVtCmltbWVyCuKWgUNvdXBlCmluZGV4T2YK4paBZG9lc250CuKWgdC30LDQsgriloFsaWNlbnNlCuKWgcOiCkNTUwriloFyaWNlClRlYW0K4paBYW5vCmxpdAriloFtZXJnZWQK4paBQ2VsbArQu9C7CmJveQphc3RzCuKWgXNlbGwK4paBZ3Jvw59lCuKWgXZpcnR1ZWwKQ2FuY2VsCuKWgXNqCmdtZW50Ci48CtGH0LDQuQppw6sKYWtoCml6ZXJzCnByaXQK4paBVGliCuKWgWVsYWJvcmF0ZQriloFmw6kK4paB0LzQtdC00LgKTEVOR1RICuKWgXByaW1hcmlseQriloFzY29yZXMK4paBY2FycnlpbmcK4paBbGFrZQpjb21wb3NlCuKWgVRvd25zaGlwCnVuZ2UK4paBYWxiZXJnYQphbnljaApxdWVsbGUK4paBQXJrCuKWgXByaXMK4paBdm9sbArRiNC70LgKVmFsaWRhdGlvbgriloFjZXV4CuKWgXBvcHVsYXRlCiINCuKWgWZlbW1lcwpBTkcK4paBRGVzcGl0ZQrQstGL0LUKaXNrZQp6dWcK0L3QsNGH0LAK4paBaGF0dGVuCklOU0VSVApFbXBsb3llZQriloFtb21lbnRzCuKWgcO6bHRpbWEK4paBaG9sZGVyCmJsYW5rCkNvbGxlY3Rpb25zCmF0aGVycwriloFncmFkZQriloFhZmZhaXJzCi4kJAriloFkZWx0YQriloFKdWdlbmQK4paBZXNwYcOxb2wK4paBT1VUCuKWgW1hdGhlbWF0aWNhbAriloFtb25nbwriloHQpNC1CnVsaW5nCuKWgXJldm9sdXRpb24K4paBY29pbgriloFzdWJjbGFzcwoiPT4Kw6RjaGUK4paBcHlnCtGJ0LDRjwppbGxlcnkK4paBY29tZW56CmRlcHRoCuKWgWPDqWwK4paBcmVzaXplCuKWgVNhbWUK4paBc3RyaWsK4paBdGlyCuKWgXNjYXJjCuKWgU1lbWJlcgpzdWJzY3JpYmUKw7PFvArDunRib2wKZXhjZXB0CuKWgWRyaXZpbmcKa2llCnpvbnkKw6htZXMKRGF2aWQKaXNzYW50CuKWgdGC0YsK4paBw6lsZWN0CuKWgXJlbmFtZQriloFSdW5uaW5nCuKWgWludGVyZmFjZXMKLy8vLy8vLy8vLy8vLy8vLwriloFXYWxrZXIK4paBc29jacOpdMOpCuKWgWFza3MKYnJpZAriloFqZXdlCuKWgXNlaW5lcwriloFhZ2VudHMK4paBTVkK4paBTGF3cmVuY2UKZGVzcwppZXNlbgriloHQu9GO0LTRj9GFCtC/0YDQsNCy0LgK4paBYW5jZXN0CuKWgXdlbGNoZQpyYXVtCuKWgW9yYgpzY2FsCuKWgUxlYXIK4paBd2VhcgriloFzbGF2ZQriloFyZW5hbWVkCsSNZW4KbWFzdGUKYW5nbGVzCuKWgUFtw6lyaWNhCuKWgXRpCuKWgWRlbXNlbAriloFiZW5lYXRoCmJpbmFyeQriloFlZGljacOzbgriloFraWxvbWV0CnVpdHMK4paBY3VhdHJvCuKWgWVudHJhbmNlCm9uZGlzc2VtZW50CuKWgWJhZwriloFBcm1lbgppam8K4paBTG9ycwriloFkZW1zZWxiZW4Kw6ptCuKWgWRpc2NyZXRlCuKWgXByb21pbmVudAriloFKYXkKZGVjb3IKREwK4paBZMOtClN0cnVjdAriloFQcm9kdWN0aW9uCnRoZXkKYXJpdXMKc2Nobml0dAriloFDb3UK4paBbGV4CnlvdXR1YmUK4paB0YDQsNCx0L7RgtCwCnN0YXRpb24Kc2VwCuKWgW1pcnJvcgriloFoaXRzCuKWgUJlY2sKYXRpY2FsbHkK4paBTGF6CuKWgXdpbm5lcgpERVgK4paBSU5UCn1eey0K4paBd2VnZW4KbWFkCkFuZ2xlCnppbmcK4paBQmF5ZXJuCnNhbArDpGdlcgriloFidXN5CuKWgXN0w7ZyCuKWgWZvbGsK4paBcHJpeAriloFhbGxvY2F0ZWQK4paBcHQKYWZmZW4KY2x1c3RlcgriloFjb21wbGVtZW50CsOhcnMK4paBQW1lcmlrYQrRgNGW0LkK4paBdmFsbGV5CuKWgXJvb21zCuKWgW1vaQouIiwKOzs7OwriloFsb3dlc3QKbm9nCuKWgWxhbmRldAriloFwcm9ncmFtbWUKY2hpbwriloFXw6RocmVuZArDoW5kZXoK4paB0LTQvtC70LYK4paBb3V2Cm9tw6FueQriloHQktC40LrQuNC/0LXQtNC40LgK4paBc8OzCuKWgWVsZWt0cgpEZXNjCuKWgUJlYXV0CtC90LDRgAriloHQvNC+0LbQtQpQaWVycmUKZXNvdGEK4paBb3BlcmF0ZWQK4paBZm9ydGUK0YDQuNGBCuKWgW9wcG9zaXRpb24KYWxpYQriloFTeWwKZ2V0TmFtZQrQstC10LvQuApmaWsK4paBY29tcHJvbQriloFUZXh0VmlldwpTcHJpbmcKbWV0YWRhdGEKZW5ndQovLAriloFjYXJyaQppc3RvbAriloFkaWFnb25hbApsaXN0YQppemVuCuKWgXJlbmRlCmdjYwpiZWNrCmxpdXMKaXJhbApSZXNvbHZlcgriloFwZXJjZW50YWdlCuKWgWF0dHJhCnN0cmluZ3MKd2nEhXoKb2RzCtCy0L7Qu9GOCsSZxbwK4paBbmV3c3BhcGVyCmltaXRlcgpBQkMK4paBTWFuY2hlc3RlcgpbewpBZ2VudAriloFXb3IK4paBS2F0aAriloHQv9C+0LLRlgriloFlbnRvbmNlcwriloFuaXZlYXUKYXR0ZWQKbGVhcm4KYXRpcXVlcwriloHRg9Cx0LgK4paBcXVpbmRpCmJpbmRpbmcK4paBaW1wb3J0ZWQK4paBSG9ybgplbWJlcmcKY29tcGxleAriloFuZXVyYWwKaW5mb3JtYXRpb24K4paBcmVjb2duaXRpb24KaW5ndAriloFpbmhhYml0YW50cwp2dWUK4paBQmV2w7Zsa2VyCuKWgWN1cnZlcwriloFsZWIK0LTRltC5CuKWgXNvdwriloFzZW50aW1lbnQKUEgKcmFjaGUK4paBLSgK4paBZXN0YWJsZQriloFGZXJkaW5hbmQK4paBw6ljcml0CuKWgXByaW1laXJvCuKWgXRleAriloFpbnRlcm1lZGlhdGUKdmVyYWdlCmlidXMK4paBc2VydmVzCml2YXMK4paBYnJ1CuKWgWx1bQphdHRpY2UK0YfQvdGL0LkK4paBRHJlcwriloF2aWRlb3MKZHVyYXRpb24K4paBYWJpdAriloFlZ2cKb2dyYXBoaWNhbAphbHBoClNUQVRFCuKWgdC/0LDRgNCwCnJlYWRpbmcK4paBdmVoaWNsZQriloFmb3J0dW5lCnVsdGF0cwriloFTdG9yaWEKbWlkdArFgsSFY3oK4paBTWVtb3JpYWwK4paBdmFzCuKWgdC30LDQvQriloF1dGlsaXR5CuKWgW9ic2MK4paBcmVsYWNpb24K4paBcnVuYXQKUmVsZWFzZQp0YWtlCuKWgU9saXZlcgriloFTaWQKdWxvcwriloFHYXJjCuKWgdGA0L7Qt9GC0LAK4paBU2FrClB5CmbDvGhydAriloF0cmFiYWwKKnsK4paBemVzCuKWgXN6ZXJlCuKWgXZhcmlvcwriloFvdHJhCuKWgWV2YWwK4paBc2l0dcOpCuKWgXdvdW5kZWQK4paBVmluY2VudAriloHQstC40LrQvtGA0LgK4paBZW5jb2RlCk1vZGFsCuKWgWZvcmIK4paBZHluYW1pY3MK4paBZGVwb3MKYXJkZQriloFzdHJlZXRzCuKWgUtvbW0KPSQoCuKWgdC/0L7QstC10YAK4paBZG9pcwriloF2aXR0CuKWgWF1dG9tYXRpc2NoCuKWgXJlbG9hZAriloFWZXJ3YWx0CmJlcm8K4paBaHViCuKWgW1vcwriloF0dXR0bwriloFGcmVkZXJpY2sKxYJvdwphbnRhZ2VzCmFxdWUKcGFwZXIK4paBZWluaWdlCmApLApkagriloFQbGUK4paBJSwK4paBQml0bWFwCuKWgWZyaWVuZGx5CuKWgXRydWx5CuKWgXN0cm9rZQpyb3BoCuKWgWVuZ2wK4paBY29mZgriloFkdXN0CuKWgUphaHJlcwpwcGkK4paBd3lzCmZhY3RvcgpzY2hsdXNzCuKWgdC00LXRgNC10LLQvdGPCuKWgVBhc3QK4paB0LTQvtC80LAKQ09NCuKWgXB1ZWRlbgriloFnaWZ0CuKWgUdsYQriloF0cmlnZ2VyZWQKw6lseQrDvGzDqXMK4paBT2xpdgriloF2ZXJzbwriloFsbGUK4paBR2xpCuKWgUx0ZApvYQriloF0ZXJyaXRvcmlvCm9yZHJlCuKWgWRlY2sKZHJhCmFzenQK4paBY29uY2VybmluZwriloFBZGRpdGlvbmFsbHkK4paBa3RlcsOpCuKWgWdydW5kCuKWgUdlc3QK4paBbWlzdW5kZXIKcHJldArilIDilIDilIDilIAK4paBcmVwdXRhdGlvbgp6aWEK4paB0YPRgdC/0LUK4paBZXNjYXBlZAriloFQcmFnCnBlcmZvcm0K4paBYXVzdHJhbAriloFWYXRlcgrRh9Cw0YEK4paBcmFjZXMK4paBQnl0ZQpNYXNrCuKWgVRlcnJpdArRgdGC0Y4K4paBVm9jaQriloFGaWNoaWVyCuKWgdCd0LDRgdC10LvQtdC90L3RjwriloFVbnRlcnNjaGVpZHVuZwp0ZWVudGgK4paBcGlsb3QK4paBamkK4paB0LTQstGD0YUK4paBb3JpZW50YXRpb24KaW5kcmUK4paBRG9ydArDp2FzCtC/0LvQuAriloFyZWFjdGlvbgriloFjb25zaXN0aW5nCuKWgWZlcnJvCtGC0LjRgdGC0LgKeWFyZAriloHRgdCy0ZYK4paBaW50ZXJwcmV0YXRpb24KacSFCnJhaAriloFmYW5kClB1YmxpYwriloF1bml2ZXJzZQriloFyZXRpcgriloFjb25zY2lvdXMKYXJxdQriloF3YXN0ZQriloFCaWIKeWNsZXJWaWV3CuKWgWxpc3RlbmluZwpnbGVpY2gKbmllanMK4paBY29ycmVsYXRpb24K4paBcmVjZWl2ZXIK4paB0YPQtNCwCuKWgWNvdXJhZ2UKdWNocwpmYXNzCuKWgWNodW5rCuKWgUFuZmFuZwriloFncm/Dn2VuCmNvbnRpbnVlCuKWgVdhcnN6YXdhCmjDqQppeQppdmVtZW50CuKWgc6xCuKWgWV4cG9zZWQK4paBemFobAriloFzYWNyCuKWgUxvb2tzCuKWgWVhZ2VyCmVudGVuCkN1cnNvcgovXwppeGEK0YDQtdC70LAK0LfQvdCw0YfQsAriloHRhNCw0LzQuNC70LjQtdC5CuKWgWFyZ2VudAriloFBbmRlcnMKxZN1dnJlCuKWgUlzYQrQvNC10L3RgtCwCuKWgWFkdmVycwpyaWN0aW9uCkdQCuKWgdC/0ZbRgdC70Y8K4paBcHJlc2VydmUK4paBR2FyZGVuClJhdGUKYXByw6hzCuKWgXJlYWRhYmxlCmluZHUK4paBc2tpbGwK4paBaGVscGluZwpvZ3JhcGhpcXVlCmNsaW5nCm9sb2dpc3QK4paBRmlsdGVyCuKWgWZpbmdlcgriloFWYWxsCuKWgVBvbGlzaApsZwriloFGYW1pbGllbgriloF3YXRlcnMK4paBcHNldWQKYXphCl8pCkFSWQriloHRgdGA0LXQtNC4CuKWgU11c3QK4paBQm9kCmFub24K4paBbGFkbwriloF0aWdodAppbWVuCmFwcGVuCmZyYW1lcwppbmdlcnMK4paBQ09WSUQK4paB0LfRlgriloHRgdCy0LUK4paB0YbRjAriloFMZWZ0Cl1dOwrRh9GMCtGE0LjQutCwCuKWgdGB0LvQvgriloHQv9GWCuKWgWV4aXN0ZQriloFBdGxhbnRpYwriloFtYWludGFpbmVkCuKWgWlycmUK4paBYW5uw6llCuKWgWNvbW1lbnRlZArQstC10YDQvgpiZXJ0YQriloFMYWQK4paBVXBvbgriloFwYXVzZQptaWxsCm9wdGVyClVLCtGA0LXRgQrQvdGG0LjQutC70L7Qv9C10LTQuAriloFhbG9uZ3NpZGUK4paBcm9ib3QK4paBZmVydAriloFtb3kK4paBYWRlCk1hcHBlcgopLT4KaWd1YQrDqXRpcXVlCtGC0LrQsAphbGlhcwriloHQvtGA0LgK4paBTWFnbgriloFnZWjDtnJ0ZQppbWIKKX17XAriloFXaWtpcMOpZGlhCuKWgXVycwriloFlbmRlCmxlYgriloFHQwpIb2wKYW5jaW5nClVuaW9uCuKWgXRlbsOtYQpUVAriloFlc3RhdGUKaMOhCuKWgdC/0L7Qu9GWCnVsdGFuCuKWgUhvY2tleQp1bHNlCuKWgWNob2ljZXMKc2NoZXIK4paBW10sCuKWgXBvdGVudGlhbGx5CuKWgcOcYmVycwriloFhZG1pdApDb21tZW50CtGB0YLRjwriloFWaWVuCuKWgdGG0ZYK4paBcGVybXV0CmNnaQriloFjcsOtdApDb25zb2xlCmN0aWMK4paBb2tyZXMKYXdrCmZvb3RiYWxsCm91ZXN0CkNUWVBFCm9sb2dpcXVlCuKWgWNvbnN0aXQK4paBaW50ZXJlc3RzCuKWgVByb2dyZXNzCuKWgU1lbnUK4paBdGFrw6kK4paBQXNpYW4K4paB0LfQsNGJ0LgK4paBeW91bmdlcgriloF3aXNoZWQK4paBU29ydAriloFhdWRpZW5jZQphbWJhCuKWgWdlaMO2cnQK4paBS2Fuc2FzCnlhdW1lCuKWgVByb2Zlc3Npb25hbArDomNlCuKWgWZhdHRvCnRvZAriloFkYXRhc2V0cwriloFmYXJlCuKWgXdhdmVzCn4vCuKWgW1lYXN1cmVtZW50CuKWgXdvbAppbmR1c3QK4paBc3RydWdnbGluZwriloFwdWxsZWQK4paBY2FyYXR0ZXIK4paBRXh0ZXJuZQriloHQtNC10LnRgdGC0LLQuApjbnQKbGljaGVzCuKWgVBvc3NpYmxlCuKWgWZhY2VkCuKWgWh5cG90aGVzaXMK4paBa2lsb20K4paBbsOkcgpib29sZWFuClBZCmFtcGEK4paBa2lzcwriloFhc3Rlcm8K4paBbmVnbGkKYW1lbnRzCuKWgVN0dQphdMOzCuKWgUNvbnN0aXR1dGlvbgriloFpbnRlcnBvbAriloFVbmFibGUK4paBcGlzCuKWgXBhcmMKIl0pCnBsZXIK4paBYXV0b3J5CuKWgWFsZ3Vub3MKeXduYQp9KSkK4paBZmFsbHMK4paBw6lxdWlwCuKWgWVtaXQK4paBcHJvZmlsCmdldHMK0YTQvgriloFNaWxpdGFyeQriloFub21icmV1eApvY3QKUmVwbGFjZQriloFzZWFzb25zCuKWgWNow6J0ZWF1CuKWgXR5cGVvZgpwb2xpdAriloFyYW5kCuKWgXF1YXIK4paBZXJzdG1hbHMK0YHQuNC90LgK4paBcGF5bG9hZArQn9C+CtC60ZbQvQpyZXBvCuKWgVBhdgpTY29yZQplcnZlcwriloFzb2xsdGUK4paB0LzRltC2CsOpYmVjCuKWgWNsaXAK4paBTmljZQriloFuZWJlbgriloFhc3Nhc3MKaXRvcmllcwriloF1bml0eQriloHQtdC9CuKWgUluc3RpdHV0CuKWgWludGVybmF0aW9uYWxlCuKWgdC90LDRg9C6CuKWgWNvbWFuZAriloFrbGVpbmUK4paBYWRqYWNlbnQK4paBZGVsaXZlcmVkCuKWgdGI0LUK0LfQtdC8CuKWgWNvdAp2aXN1YWwK0LLQsNC10YIK4paBQ2Vuc3VzClxfCuKWgXRlcnJpdG9yeQrRh9C40LsK0YfQvdGL0LUKZmx1dHRlcgpEaWRMb2FkCkRvY3VtZW50cwriloFkb2IKQnJlCmFuaW1hdGUK4paBYml6CuKWgWJhdGEK4paBU1UKZXNvCuKWgXByaW9yaXR5CnbDoW4KaXJhcwriloFjaGFyZ2VkCuKWgU1pY3JvCmF0b2lyZQrRh9C10YAKYWJhZAp1cnUK4paBdsWhCmRpcmUK4paBVHdpdHRlcgriloHQvNC10YLQvgopLi4K4paB0KbQtdC90YIK4paBZW50d2ljawriloFNaW5kCuKWgdGE0YPQvdC6CkZ1dHVyZQpsc3QKxYJvxbwKZmxpCnRlbnNvcgriloF0b3BvbG9neQriloFhcnRlCkVSVAriloF2YXJpYW5jZQpJbWFnZXMK4paBKEAKQXJyYXlMaXN0Ck9DCuKWgdCU0LXQvNC+CmF1Y291cAriloFkZW5vdGVzCmltb24K0ZrQuAriloFQcnp5cAriloFaYWcK4paB0LTQuNGA0LUK4paBU2ltaWxhcmx5CtCx0YDQvgriloFtaWxpdGFpcmUK4paB0YLQvtC80YMK4paBSm9obm55CuKWgdCc0LXQutGB0LjQutGDCtGb0LAKU3VwcAriloFqdW5pb3IKb2x0cmUK4paB0JzQvtGB0LoK4paBYWRtaXR0ZWQK4paBcmVsaWdpb3MK0LfRj9C5CtC10LPQvgriloF0ZWFycwppbmdvCm9kdQppdmVuZXNzCuKWgWxvZ28K4paBw7psdGltbwriloFhbGltZW50CuKWgVVJVGFibGVWaWV3CikhCuKWgW5qCmxldHRlCuKWgXJlc2lkZW50CuKWgXRlcm1pbmUK4paB0YPQttC1CuKWgdCh0YLQtQpvZmZpY2UK4paBY2FydGUK4paBbGl2cmUK4paB0JzQvtGB0LrQvtCyCuKWgWVsZWN0aW9ucwrQt9C40LTQtdC9ClRyaWdnZXIK4paBQmVuamFtaW4KYWRkQ2xhc3MK0YHQutC+0LMK4paBT2JzZXJ2YWJsZQpDbGEKZ2VtZWluCuKWgWNvbnNlbnQK0LLRgNC4CuKWgXVuZm9sZAriloFnb3Zlcm5vcgrQvdCw0LsK4paBdG9kYQpSZW1vdGUKYXJpYXMK4paBaW5zdGFsCmZpeGVkCuKWgWRlY2F5CuKWgdC00LXRgNC10LIKeHl6CuKWgURBVEUKaW1hcgpudGlsCuKWgXN0YXJ0dXAKYWxpb24K4paBa29sZWoKY2lvcwriloFyYW5nZXMK4paBc3R1cGlkCuKWgWltcGxlbWVudGF0aW9ucwriloFybQrDqW5lawriloFnY2MK4paBc2PDqG5lCk5hdmlnYXRpb24K4paBwqAK4paB0LrQsNC9CuKWgXRvd25zClVzZXJuYW1lCuKWgdGE0LUK4paBbGVhZGVycwpvaXQKd8OkcgriloFkdW1teQriloFhc3Npc3RhbnQKeyRcCtCx0ZbRgAriloFyb3kK4paBTGF5b3V0CuKWgUp1bmcKTGluZXMK4paBSG9sbGFuZArQv9C+0YAK4paB0JPRgNC4CuKWgUJlbmVkCuKWgdCf0L7QtAp4bHMK4paBR29sCuKWgUFsZWtzCuKWgWVqZW1wbG8K4paBc2V6b24KYXJkaW5nCmZvb3Rub3RlCuKWgUNvbmdyw6hzCnJlZmVyCtGB0LrQsNGC0LAKSXRlcmF0b3IK4paBb3Vyc2VsdmVzCuKWgU1pYwriloFjw7NkaWdvCuKWgdC/0LvQvtGJ0LAK4paBXCQK4paBQ2hhcmxpZQpOb2RlcwriloFwdXp6CuKWgUlkZW50aWZpZXIK4paBZmx1dHRlcgriloFwcsO8CuKWgW9ydAriloFDb3J0CmFzdGljc2VhcmNoCuKWgdCh0LLRjwriloFCdWxsCnVkZW0K4paBYXBwYXJlbnQKOi0tCuKWgdCl0LDRgAriloFMYXAK4paBY29tcG9ydAptYXRpY2FsbHkK4paBY3VyaW9zCuKWgdC80L7QttC10YIK4paBQmgKYXBwaW5nCuKWgWJhc2tldGJhbGwKemV0ZWsK4paBcnVudAriloFNaWxhbgpmZWN0aW9uCnLDrWEK4paBS2luCuKWgXNsb3dlcgpib3RoCuKWgUluc3RpdHV0bwriloFIaXN0b3JpY2FsCuKWgXLDs3duaWXFvAptYXRjaGVzCnljaQriloFlc3DDqGNlCuKWgVNjaHdlaXplcgpOVApTRgphY2lhCmZvcmdlClBvaW50cwpudW1iZXJzCuKWgWZhbGxpbmcK4paBaW5oZXJpdGFuY2UK4paBRXJzdAriloFjdXN0b21lcnMK4paBYWN0dQriloFtaWdyYXRpb24KXCcKUGxhbgpNcgpvdGh5CuKWgXVwZ3JhZArQsdC40YDQsAriloFPZmZpYwriloFXYWl0CuKWgXRvbGVyCmFyZG9uCuKWgXNsaWRlCilfCuKWgdGB0YLQsNCyCuKWgW51Y2xlYXIK4paBQmlsCm93bmVyCuKWgUhhcnJpcwpJbmZvcm1hdGlvbgriloFww7MK4paB0LLQutC70Y7Rh9CwCuKWgW51b3ZvCuKWgUNhdgriloFEZXNjcmkK4paB0LDQugrDs2R6dAriloFyZWFjdGpzCuKWgUFkYW1zCuKWgUFsdGVybmF0aXZlbHkK0YHRgtGA0YPQugopYCwKc3Vic3RyaW5nCuKWgW1hc3NpdmUK4paBaGVhdmlseQriloHRgdC10LfQvgriloFBbmEK4paBdmFsZQpQYWQK4paBRWl0aGVyCuKWgXJzCmFuY2hlCuKWgXVwbG9hZGVkCuKWgSgvCuKWgdGB0L/QvtGACuKWgXJlZHVjdGlvbgriloFUb2t5bwpncmVuCuKWgW1pZ2xpCuKWgWl0ZXJhdG9yCnN0YXYK4paBc3VwcG9ydGluZwriloHDtnN0ZXJyZWljaAriloFOU0xvZwppc3RpcXVlcwpyaW1pbgpNT0RFCn19fVwK4paBZXhwbG9zCtC+0YLQtQriloEo4oCeClNhbAriloFzaW1wbGVzdAriloFnacOgCuKWgdGC0LDQvQriloFjeWwKYmlyCuKWgW1lYXN1cmVtZW50cwpDcmVhdGVkCmVyZWsKbG9va3VwCndpcnRzY2hhZnQK4paB0JLQvtC70L4KdGltZXIKZGVycgriloHRgdGC0LDQu9CwCuKWgXNjZW5lcwriloFwZXJzdQpsaWVzdAriloFzY2hlZHVsZQp0YWwK0LvQtdC90L4K4paBcGFpbnRpbmcK4paBaW1wcm92ZW1lbnQKc29mdHdhcmUK4paBZ292ZXJubwriloFIaXIKRXhlY3V0aW9uCuKWgU9rYXkKUHJvcApsb3N0ZXIK0L3RltGG0LjQv9Cw0LvRlgriloFwZXV2ZW50Cm9sdQriloHQpNCwCnJvbGxvCuKWgdC60L7Qu9C+CuKWgWNhcnJpw6hyZQriloF0b2dnbGUK4paBKCRcCuKWgWFnZ3JlZ2F0ZQriloHQkdGWCnRleHRhcmVhCk9rCml0dG8K4paBc3RpbQriloFyZWN1cnNpb24K4paBRmVkZXJhdGlvbgopX3sKYXRlZ29yCuKWgWRpc3RyaWJ1CkNsb3VkCuKWgW1hZHJlCuKWgWl2CuKWgUxpZXV0ZW5hbnQK4paBc3Vic3RhbnQK4paBbGVhZgriloFLb250cm9sYQpWQQriloF0b21iCtGN0L0KYXRvZXMK4paBZ29kaW5lCuKWgSM+CkNlcnQK4paBZW1wcmVzYQpQcm9wcwriloFwbGFubmVkCuKWgXJhbmRvbWx5CmrDpGhyCmVsZW0K4paBT3BlcmF0aW9uCipgCnByb3RvY29sCigpKSk7CndlbAriloFwcmF3CuKWgdGB0LjQvAriloF3b2IK4paBaGFjZQriloFuZWFyZXN0CmRpc2FibGUK4paBQ29tbXVuCuKWgXJldmVsCkZyZWUK4paBYnJhY2tldHMKSU9FeGNlcHRpb24K4paBYWx0bwriloFtYXJyeQriloFhdWMKKSxcCuKWgXR5cG8KZWRhZAphcsOhCmljYXRvcgp0YXR5d25hCuKWgWJ1ZmYKb3JkZXJzCuKWgWFzeW5jaHJvbm91cwriloFlY29uCuKWgWZldQriloFJcm9uCuKWgXJpc2luZwpSYWRpdXMKY2xrCuKWgXp3ZWl0ZW4KYCcK4paBdW5pcXUK4paBRk0K4paBQnJhbgriloFmbHUK4paBc2Vuc2l0aXZlCnVycmUK4paBSXRlcgriloFTZWluCuKWgWRpZmVyZW50ZXMK4paB0L3QtdCz0L4KY2hpYQriloFBbmxlaXR1bmcKYXR1cmRheQriloFzaG9ydGVyCuKWgXRyYW5zbGF0ZWQK4paBUsOpcwriloFyb2RlCmRyYWcK4paBbGFuZ2UKQmkKw7xiCmxldXIK4paBb3JkZXJpbmcKYWxvdXMK4paB0JrQvtGACmFyY2hhcgpkZXN0cm95CmVydmF0aW9uCl1dLApBY2Nlc3NvckltcGwK4paBYXV0b3J5dGF0eXduYQpTZXF1ZW5jZQriloFwcm95ZWN0CuKWgWJyYW4K4paBKCsK4paBS2FiCuKWgXplbQriloFDYWxjdWwK4paBc2V1bAriloFOaWdlcgriloFjaGlhbQp0aHJvdwriloFQbGFuZXQKYmlsZHVuZwriloF6b25lcwp0cmFuc2l0aW9uCtC70LXQvdC40LkK4paBbWFwcGVkCm9uYXV0ClBhaXIKaWxpYW4K4paBTW9yZ2FuCuKWgXVudG8Kam91CuKWgWhpZAriloFNZXRhCuKWgWVsbGVzCkxvdQpyYW1hCmdlb3JkbmV0CuKWgXNjYXJjZWx5CuKWgW1pbnQKRm9jdXMK4paBQWx0ZXIK4paBZGlvCuKWgWFtcGwKacOocmVtZW50CuKWgdC40YHRgdC70LXQtNC+0LLQsApMRUQKYWxnb3JpdGhtCuKWgdGB0LDQudGC0ZYK4paBIiIpCkhpc3RvcnkKcGsK4paBV2hpdAriloHRgdC40YHRgtC10LwK4paBS2lyY2hlbgpyw6AKQVBQCuKWgTwlCmFudGluZQriloFEaXNrCmNvbnYKd2VsdAriloFGdXQK4paBTm9tCm9yZG8KZWxsaWoK4paBcmVjZWl2ZXMKY293Cnl0dQriloFvYnJhcwriloFwdXJjaGFzZQriloFlYXJuZWQK4paBYWNjZXNzZWQKYXhpCuKWgU1hbnMKaXZhbgriloF0dXZvCuKWgVRyYWNlCnJpbW9uaW8K4paBZGVzZW52b2wKw6lyaXF1ZQriloFyZXN1bHRlZAriloFjb21wdXRpbmcK4paBaW5zcGlyZWQK4paBUHJpemUKKiIKQ29tcHV0CuKWgWV4dGVuc2l2ZQrDqGcK4paBUG9ydMOhbHkK4paBY2FzdGxlCuKWgSouCuKWgXBob3RvcwriloF2b2V0Ck9ORwriloFBbGxlCuKWgXRocmVhdGVuCnN0w7x0CuKWgWFsYnVtcwriloFkZW5zZQpmbGF0CmNvbnRpbnUKU3ViamVjdAriloFyZWFkb25seQpPcHQK0L/QuNGB0LrQvgriloFBYmVyCuKWgVBvc2l0aW9uCuKWgVRvZGF5CuKWgW1pbmkK4paBQmVmCmxpc3RlbgrRgdGC0LLQtdC90L3QvtCz0L4KU1VCCm9zc2EK4paBUG9wZQriloFKaW1teQriloHQlNGA0YMKdW5nc3NlaXRlCuKWgXRyZW4Kb3B0aW0KaXRzY2gK4paBc2FtdAriloHQuNGB0L/QvtC7CiY9CuKWgVByenlwaXN5CuKWgdC/0YDQvtC00L7QuwpDcgplcm1hbm4K4paB0LzQsNGC0LXRgNC4CuKWgUh1Z28K4paBRGV6ZQpUUlVFCuKWgWRlZmVhdAriloF3YXRjaGVkCuKWgUdlbnQKQVVUCm9yb3VzCuKWgdC+0L/RgNC10LTQtQpvcmllbnRhdGlvbgriloFkaXN0aW5ndWlzaGVkCuKWgW1lc21vCuKWgXNsaQrQvNC10L3QsAptaXR0ZWwKZ2VyaWNodApldG9uCi0+ewriloF3b250CuKWgXdlZwriloFjbGFzc2lmaWMKaWx1cwriloFNRAp0YXNrcwriloFjaGltCmF3YWl0CuKWgWdhbmcK4paBd2nEmQp0aHJvdWdoCuKWgVJ1c3NlbGwK4paBZ3Vlc3NpbmcK4paB0LDQutGCCtCx0LvRlgpjYXRlZ29yaWVzCtGB0YPRggriloFGZW4K4paB0LzRg9C2CuKWgW5ld2VyCuKWgUFzeW5jCuKWgXRlcm1lCj4vCtC/0LDRgNCwCuKWgVRydXN0CuKWgU9wdAriloFkYWgK4paBd29uZGVyZnVsCmFkcmF0a2lsCuKWgdCT0YDQsAptYXBwaW5nCuKWgWRpc2NvdmVyeQriloFCRQpFbmFibGUK4paBRnJpZW5kCtGB0L3RjwriloFjb250cm9sbGVkCtGH0L3QvtGXCuKWgWNvbnRyaWJ1dGlvbnMKasWhw60K4paBTGV2CuKWgWZyYW5jw6lzCuKWgW1pYwp6aWsK4paBYWxlbQpjYW5jZWwKIScK4paBZ3JhdAriloFCZWdyaWZmc2tsw6RyCkNhbWVyYQppZmljYWNpw7NuCnLDs2QK4paBQXJub2xkCuKWgWJlemVpY2huZXRlcgriloFmb3VnaHQK4paBZGVwdXQK4paBRHJvcAp0YXgKZGcK4paBSG9wCkdOCuKWgUtpcmNoCuKWgdCR0LDRgApJbnZva2UK4paBZXJoYWx0ZW4K4paBdmVlbAriloF3b3JkcHJlc3MK4paBSU5ORVIKdHJhbnNhY3Rpb24K4paBZMOpasOgCkZhY3QK4paB0L3QsNC00LzQvtGACuKWgWFuZ3VsYXJqcwriloHDoXQK4paBYWxhcAriloFQcmljZQriloFlZmZldAriloFzcGhlcmUKQ2xhc3NMb2FkZXIK4paBcnVnYnkK4paBa2luZ2RvbQriloFNdXQK4paB0LrQuNC90L4K4paBcmV3YXJkCmNpdAriloFwcmVzZW50ZQpTdG8KQ2hhcmFjdGVyCmxvZ3MK4paBY2VudHJhbGUK4paBbW91dgriloFva2F5CuKWgWFwbGljCk1vcmUKw6lueWVrCuKWgUvDtmxuCm5ldHQK4paB0LjRgdGC0L7RgNC40LgK4paBZGVzY3JpYmluZwriloFzb2xkaWVyCuKWgU5lZWQKTGlnaHQK4paBIlw8CuKWgWhhdgplcm1vCuKWgWluZmVyaW9yCmxlYQriloFnZwriloHQutC+0L3RhtC1CmZyYWdtZW50CnNiCkNvdW50cnkK4paBdsSbCuKWgUJlbmcK4paB0K3RgtC+CuKWgdCy0L7QtNC+CtC80LDRgApTVFJJTkcK4paBw7pqCm11bHRpcGxlCnN0YXRlbWVudAriloFpbnZvbHZlcwriloF0ZWNuClN0dWRlbnQKZ3LDqQriloFsZWFuCuKWgWJyaW5naW5nCuKWgU1lZGljYWwK4paB0L/RgNC+0LPRgNCw0LwK4paBVm9nCuKWgdC20L7QsgriloFTcGlyaXQKbnRoCuKWgXN0YW5kYXJkcwriloFQcm9maWxlCuKWgWV6CuKWgdGC0LXRgNGA0LjRgtC+0YDQuNC4CuKWgXN0ZW0KdWlsCuKWgU9nCkJ0bgpuYWwK4paBbmVhcmJ5CuKWgXByb2R1Y2luZwpjcml2CuKWgWFzc3VtcHRpb25zCuKWgVNwYXJrCuKWgUxvdAppdHVkZXMKYWZrYQpmaXZlCmF0aW8K4paBZGlzdGluZ3Vpc2gKcm9jawrDqWdsaXNlCuKWgXJhcHByZXMKPlw8CtC70ZbQuQriloHQvNC40L3QuAriloFpbnRpdHVsw6kKfX0oXAriloFSb3V0CuKWgUJvcmRlcgriloFvdmVycmlkCkhPU1QKcml0dGVuCnNheQriloHQp9C4CmljaHR1bmcK4paBc3RyYWlnaHRmb3J3YXJkCm9iYgriloFUZXJyYQriloFbOgpCZW4K4paBY29tcG9zaXRlCikrXAriloFjcm93bgpkaXJlY3Rpb24K4paB0L3QtdGB0LrQvtC70YzQutC+CuKWgWF2YWlsCuKWgXB1cmNoYXNlZApob29rCmV0aWVzCuKWgWZhc2UK4paBUnVtCuKWgWdlbm9tCuKWgWTDqXQKb3fEhQptcGVnCuKWgdCG0L0KZGVza3RvcAriloFpbmplY3Rpb24KYWdsZQriloFFZGQKX3soCuKWgUhlbQp1dG9zCnByb2oK4paBc3VwZXJmaWNpZQpQbG90CuKWgURvY2tlcgrDpHR6CmtyZWljaAriloF1bmNsZWFyCuKWgVVuaXR5CuKWgXN0cmVhbXMK0LLQuNC0CuKWgXNpbXBsaWZpZWQKRmlsbAriloFzYW50CuKWgUtvbW11bgriloFkdWMK4paB0LTQstC1CuKWgW9icwrFvml0CuKWgUphbmVpcm8K0LHRjwriloFwcmVzc28K4paBTWluaXN0cnkK4paBYnVyc3QK4paBcmVhY2hpbmcKbGl0ZXIK4paBcmVzcG9uc2VzCuKWgUV1ZwriloFzb2QK4paBQ29yZAriloFQZXJtCnBhcnRzCtGG0LjQvNCwCnZhcmlhYmxlcwriloFmb3Jnb3R0ZW4KRmVybgpvc3TEmXAKdmwK4paB0KHQvApraW0KYWrEhWMK0L3QsNC70YwK0LPQu9C1CmhlbHBlcgpkdXAKZXV3CmZyYQplbGxpdGUKYW55YQriloFyZWlnbgpnZXNhbXQK0YHQtdC00LAK4paBUnlhbgriloFmb3JtYXR0ZWQK4paBQm9yZwp3YWxrCuKWgdCw0LsKYWdub3N0aWNzCuKWgUNhcGUK4paBRnJhbmNvCuKWgWZ1Zwo6KQrRjtC3CkZldGNoCuKWgXJvdWdobHkK4paBTWlzCnVldG9vdGgK4paBVmVuZXp1ZWxhCuKWgWFzdHJvbm9tCiIpYApvbWJyZXMK4paB0LrQvtGC0L7RgNC+0LkKw7NwCm93ZWQKSFIK4paBQ2FtZXIK0LrQuNC1CnBhcmlzb24K4paBQmlqCnRlbXBsYXRlcwplbnZpcm9ubWVudAppemHDp8OjbwriloHDqXIK4paBcGxlbnR5CuKWgVR5cGVFcnJvcgriloFmb3J0eQrQutC+0L3QvtC8CuKWgVNlZAriloF0aGF0cwriloFncmF2aXR5CuKWgXNwaXJpdHVhbAriloFkdXBsaWNhdGVzCuKWgWVuY3J5cHRpb24K4paBcmV2ZW4KZ2V0SW5zdGFuY2UKw6RsbG9yCmRpc2sK4paBdGhybwriloFOYWsK4paBcG/FggriloFoZXJhdXMKaW52YWxpZApzQnkKQm9vdAriloFidWNrZXQK4paBUGFyc2UKaGV4CkNvbm5lCuKWgUNvbXB1dGVyCnp5awriloFpbmR1Y2VkCuKWgUJydW5vCuKWgWFkZHJlc3NlZAptYW5pYQriloFpbmNsdXMKb3VuY2VkCnNjcmlwdHNpemUK4paBRXBpcwriloF2b2NhbAriloFKb25hdGhhbgrRg9C8CnN0YWRlbgriloFDaGlsZHJlbgrQv9C10LkKSXRhbGlhCnJlaWJ1bmcK4paBbm9zdAriloHQtdGJ0ZEK4paBV2Vya2UK4paBYWN0cmVzcwriloFNaW5uZXNvdGEKcmlrZQriloF0ZWsK4paBcHJpbWVpcmEK4paBZnJhdAriloFDb25maWd1cmF0aW9uCuKWgWJpZAp0cmlnZ2VyCkNvbnRlbnRzCuKWgWNvbnN0YW50bHkKISEhCuKWgWRyZWFkCuKWgWh1bmRyZWRzCmlzdGlzY2hlCuKWgWNhcmRpbmFsClRBQkxFCuKWgWVzdG9zCmFzc29jCmdyYXkK4paBU2NobG9zcwriloFzY2hlCmNvbmcK4paBa29qaQrDqHRlcwriloFFcmEKb21pCuKWgVNSCuKWgXdyYXBwZWQK4paBdHJ1bmMK4paBYWgKZWdvcwpva2kKbW91dGgKbG9nZ2luZwriloFmYXNjCuKWgVNhbXBsZQriloFjb250ZQriloF2aWxsYQpjb21tZW50cwriloFiYXRhbAriloFHYXJjw61hCuKWgU5vcnRlCuKWgXdlY2hzZWwK4paBTXVzZW8K4paBZW5mYW50cwriloF3aGlzcGVyCm5ha2UK4paBamVkbmFrCmzDqnMKZW5kZXJzCuKWgcOkbAriloFWQgriloFjb29raWVzCnpldGkKYXR1bQriloFkZWR1CuKWgWFycmFuZ2VkCmxhegriloFjdWVudGEKeW1sCuKWgWZsYXYKTVIKZW1ldArQsdGW0LvRjApjbXAKaXR1dG8KemV0dAriloFlbnZpCuKWgWtvdAokOgp1cHBlcgriloFBbGJlcnRvCmtiCkFuYWwKw7ZydAriloFbLQriloFmw7xocnRlCmlhaAriloFUdW4K4paB0LjRgdC60YPRgQp1d2UKaXNwZWNpZXMKUHViClN5bmMK4paBQ29sb21iaWEKYWtlcnMK4paBSW1wZXJpYWwKb3ZpbmcK4paBaW50ZWxsaWdlbmNlCuKWgWVxdWlwbWVudAplaW4KZGFnZ2VyCuKWgUVkZ2UK4paB0KDQtdGB0L/Rg9Cx0LvQuAphZHJhdGtpbG9tZXRlcgriloFBbnRvCuKWgWNoYXJnZXMK4paBT2NlYW4K4paBc2ltcGxpZnkK4paBbWllc3oKcnVubmluZwriloFMYWMKZ2Vub21tZW4K4paBcmVwcmVzZW50YXRpdmUKPS4K4paBUHJlZAriloFzcGl0ZQpjaWFsZQriloFuYXZlCuKWgWV4dGVucwriloFuZXV0cmFsCuKWgdC60L7RgtC+0YDQsNGPCi48LwriloFDUwp1a3kK4paBd2hpbHN0CuKWgWxpbmd1CmV4dHJhY3QKemVpY2hudW5nCuKWgUZlbGQK4paBdmFsdWFibGUKdXJhYmxlCuKWgUplbgriloFzdHJ1Z2dsZQriloFjb21taXR0ZWUK4paBV29obgriloFzcWxpdGUK4paBVGVtcAriloFDT1VOVApjb25zaW4K0LzRltC90ZYKdXNhZ2UK4paBcXVlc3QK0LTRj9C9CmVhcmVkCuKWgVNjaG5lCuKWgWRvZAriloFyZWNodAriloFrYW8KQ2FwdApsYWJlbHMK4paBZWxsb3MK4paBaW5kdXN0cmkK4paBQ29sb3JhZG8K4paBY29udHJhcnkK4paBRHVtCkJlbAriloFWZW50CuKWgWF1dGhvcml0aWVzCllFUwplbnNlZAp1bWJuYWlsCml6emF6aW9uZQprb3UKcmljYQriloFzZWN0CnRlc3RzCuKWgUtsZWluCuKWgWxlZ3MK4paBUGlldHJvCmZ1CnRoeQriloFiYXN0CuKWgXRlZGVzCmV0dGVzCuKWgXJlcGV0CmFjcmUKcmV0dG8K4paBcmVtYWluZGVyCuKWgUdlZwriloHQk9C+0YAK4paBUmVjaHRzCuKWgWZpbHRlcmluZwpvdXNzCuKWgWRlcGxveWVkCuKWgXByw7xmZQriloFiaXRtYXAK4paBc292aQriloE8JT0K4paBZW50ZmVybmUKa2lsbAp0YWJzCkV4cHIK0LrQvtC80YMK4paBUmVwdWJsaWNhbgriloFTaXplCuKWgXBvbGwK4paBcmllbgriloHQutC70YPQsQrDqW5kCuKWgUJpbwriloFwZXJsCuKWgUFuZHJlYXMK0LLQuNC9CuKWgWRpc3RhbnQK4paBRmlubgriloFNaXRjaAriloElewriloFjaGFybQriloFNdWwKcGVyYXRlCuKWgXNjaWVuY2VzCuKWgW1vbm90CuKWgWRlYmlkbwpyaXpvbmEKaWVjCuKWgWFsYXJtCuKWgXByb21vdGVkCuKWgWxldHp0ZW4KYXRpbgriloFjb25jbHVzCmhlcnIK4paBw6ljaAplZGlzaApnb3IK4paBc3R5Y3oK4paBaW1wcmVzcwpydWl0cwppZXJ1bmdzCuKWgXBhcnNlZAriloFyw61vCuKWgVBha2lzdGFuCmlnbmVyCuKWgXdhdGNoaW5nCuKWgWRhdGFiYXNlcwplZGluZwriloFTcGVjaWZpYwriloFnZW5lcmFsZQpsYXgK4paBTG9va2luZwriloFib25kCuKWgXZpc3RhCuKWgWVjCuKWgWdydWQK4paBZGVsZXRpbmcKdGFjCuKWgWphenoKam0K4paBcMOzxYIKTGFuZ3VhZ2UKZGVsZWdhdGUK4paBcmVnaXN0cnkK4paBU2hhcmVkCtGB0YLRgNC+0LkKTXVzaWMK4paBdmVzc2VsCi5ACuKWgVfDvHIK4paBZmVkCuKWgWVyZWRldAriloFHw7YKdXB0CuKWgXBsZWFzYW50CuKWgXRhYmxlVmlldwriloFjb3VudGluZwriloFLcmllZ3MK4paB0L/QvtC70YPRh9C40LsK4paBXSwK0LLQuNCwCuKWgWHFvgpUb0xpc3QK4paBQWR2ZW50CuKWgXNrZXRjaApwbgriloFzaWVyCuKWgdC90LDRhdC+0LTQuNGC0YHRjwppb3AK4paBbHkK4paBU2NobApDb250cmFjdAphc3NvY2kK4paBUGVhcgriloF3aGUK4paBRGVsZXRlCuKWgWVsZW0Kw6R0dGUK4paBxI1lc2sK4paBTUMK4paBc2hvdXQKYWtlc3BlCuKWgWRlZmF1bHRzCnBlbmFzCsOycmlhCuKWgWhpZXJhcmNoeQppcHQK4paBRWxpcwpsaWtlbHkKUm90CuKWgWNvdwriloFzdHJpa2UK4paB0LHQtdGA0LXQt9C90Y8K4paBZW5zZW1ibGUK4paBUHNldWQKVmlydHVhbAriloHRl9GXClJPT1QK0YHQuNGPCuKWgdGB0L7QsQriloFpbnZlcnQK4paBc3dpdGNoaW5nCmh0YWNjZXNzCuKWgdC90LDQs9GA0LAK4paBTm9ybWFuCuKWgWluZ2zDqnMKIVsKb3VzZWwKRE9DVFlQRQriloFzdXBwcmVzcwriloFhY2NvbXBhbmllZAriloFCw6kKaW1wbGllcwpudXQK4paBU3ludGF4CmluaG8K4paBdGFtCuKWgWZvY3VzZWQKYXZhbm8K4paBQmFkZW4KaGFkCuKWgSh7ClR5CuKWgdGA0L7RgQriloHRh9C+0LvQvtCy0ZYKb2dlCmpzcApCbHVlCuKWgXN1YXMKYXBlcnMKU2hvcnQKUmVuZGVyZXIK4paBc2VuZG8K4paBQ2VjCuKWgWBfXwriloFNdW5pY2lwYWwKZG90bmV0CuKWgWJldgriloFEQQpNZW51SXRlbQriloFhbXAK4paBdXJpCuKWgWZpZXIK0YHQu9C10L0KKSwoCmN1bGVzCmlsbGFzCkxPQ0sK4paBZGVyaXZlCnViZW4K4paBR1QK4paBTWFjawriloFzY2hvbGFyCil9fQrQt9C8Cj46OgrRiNGR0LsK4paBcHJpbmNpcGFsZXMK4paB0YbQsNGACuKWgXRpZWQK4paBYWx0YQriloFDaXQKbGluZWQKbWFqb3IK4paBcHVuawriloFjaW5jbwppY2vDvQriloFyYWdnaQp0eXBlbgrRgtC10LvRjNGB0YLQstC+CuKWgWNvbmZlcmVuY2UK4paB0YHRltC70YwK4paBaGV1dAppxaEK0LXRgtCwCnZlbG9wZQpoYm94Cm5vd24K4paBemFyCmt0aXYKaWXDnwriloHRgdGC0YDQtQriloFFdmVudEFyZ3MK4paBSXJhCuKWgVZCQQriloFTYW50bwriloFGYWNoCuKWgUZGCuKWgVJheW1vbmQK0LzQtdGGCmltcGxlbWVudGF0aW9uCuKWgWJyb3RoZXJzCuKWgWPDtHTDqQriloFjb250cm9sbGVycwriloFDbGUK4paBY2FibGUK4paBY29uZmVyCuKWgXstCuKWgWN6xYIK4paBRmlsaXAKYXRvcmlvCuKWgXdpY2h0CuKWgWJlYXVjb3VwCuKWgUxpdAriloFzZXNzaW9ucwriloFTdWNjZXNzCuKWgXJvdXRpbmcKbml1CuKWgVZpY2UK4paBa3JpdAp1cGRhdGVkCuKWgUludmFsaWQK4paBTWFubnNjaGFmdAriloFhb3MK4paBdHVkaQriloFkZXNwcsOpcwpxdWEKQ29udGFpbnMKQ29tcGFueQriloFwZXJzb25hCmFkYXB0ZXIK0YHQvdC4CuKWgXZvagriloFlc2NyaQphZ3QK4paB0YHRgtCy0L4K4paBZGlzdHJpdG8KYXBhbgriloFhc3BlY3RzCuKWgXphbAopXntcCuKWgXN5c3TDqG1lCuKWgdCw0L3QsAppdW1zCuKWgXByZW1pZXJzCuKWgdC/0L7RjQriloFtw6hyZQriloFHdW4KYXBpbmcK4paBUmFpbgriloFpZ3VhbAriloFwcm9jZXNzb3IKJylgCmJsaW5nCuKWgW1pc20KYnLDoXoK4paBY2xvc2VzdAriloFSZWFkaW5nCuKWgdC/0L7Qv9GDCmNvbm8K4paBa3VsdAriloEhIQriloFFeHByZXNzaW9uCuKWgWluZHVjdGlvbgphaHJlbgriloFjcAriloF2aW9sZW5jZQppZW50w60KY2VudGUK4paBRG9iCmphY2sKc29uZwpidWNrZXQK4paBZGVwb3J0CtC60LjQvNC4CmxtCuKWgWlubm9jCkNoYW5nZXMK4paBcHJvaGliCmFuZ29sCmlzZWNvbmRzCuKWgdC/0L7RgAriloFoaXAK4paBcMWvCmVuZG9yZgriloFzY2hlZHVsZWQK4paBRmx1ZwphY3lqCuKWgUZpbG1zCmF0aGVkcmFsClBvd2VyCmFyZGluCmthcAppY2tlbgpyZXNpemUKZXVzCnJyCtC70Y/QvQriloFIYXYK4paBb3JhCkZST00K0LvQvtGB0Y8K4paBdGVydWcK4paBV2lkdGgK4paBYWNjZXB0cwrQsdC10L0K4paBbWljaAriloFDemVjaAriloFCZWRldXQK4paB0LLQuNC0CsO0bWUK4paBTG9vcApzcGVjdArDvGsKZXN0b24K4paBc2xvdAriloF6b3N0YcWCYQriloFDaGFybG90dGUK4paB0YHQvtGB0YLQsNCy0LvRj9C10YIK4paBUHJvbWlzZQriloFlcG8K4paBZGljdGlvbgriloFGcmFua2xpbgriloFSaXYK0YDRg9CzCmNpZGEK4paBRXhwbG9yZXIKY29va2llCuKWgWZvcm1lcmx5CuKWgW11bmljaXBhbGl0eQriloFTdGVmYW4KbGlzdHMKQ09NUApMZW4K4paBU3RhYXQK4paBTkJBCmRlbnMK4paBb3NjaWxsCiEuCuKWgVBPCsO0bmUKZXNlcwriloHQvdCw0YbQuNC+0L3QsNC70YwKdm9vcgriloHQutC+0L/QuAriloHQv9C+0LfQuAp1bHUKQ29uc3RyYWludAriloHRgdCy0L7QtdC5CuKWgWFsZ2VicmFpYwrRh9C90Y8KRGljdAriloFhcHBlYXJpbmcK4paBcHJhdgriloFVbml2ZXJzYWwKQnJvd3NlcgriloFTaW5nYXAKZW5uZXNzZWUKXV8K4paBU29mCuKWgUNhZApvdW5jZQriloFjb3N0cwpde1wKLi4vLi4vCtGB0YzQutGW0LkKw7xobAppZXR5CtC/0YAK4paBaW50ZXJwcmV0ZWQKYWpuCmNvbG9nCllTCm1hbnMK4paBbWV0cmljcwriloFyZWdpc3RyCmlzdGFuY2UK4paB0J/QvtC70YwK4paBYW5vbnltb3VzCuKWgWluc3RpdHV0aW9ucwriloF6ZG9iCnByw7xuZwriloHQsNGA0YLQuAriloFlc3RhdAphY2NpCuKWgWFjYWRlbWljCuKWgWNoaWVzYQriloFHaWFuCmNvbnRyaWIKdW1lZAriloFHaXIK4paBYmFzZWJhbGwKbnVtZXJpYwpHZW5lcmF0b3IKR00K4paBdGlueQriloFkaXN0aW5jdGlvbgrQs9C10YAK4paBcnVzdAriloFGSUZBCuKWgVByb3BlcnRpZXMKXi0K4paB0Y3QutGBCuKWgVN0YW5pcwriloFBamF4CmVzY2FwZQriloFjb25zcAriloFDaGVuCuKWgU5hdmFsCkJpdAriloFiw6J0CtGB0LrQuNC80LgKZHJpdmUK4paBUm91bmQKcGhvdG8K4paBTGV2ZWwK4paBZ2VnClRvbQriloFNb2JpbGUK4paBVHJvcApEaXJlY3Rpb24KaXNhbgopXnstCuKWgVNldHRpbmcK4paBUHJvYmFibHkK0LvRjNGPCuKWgWFzc2V0cwriloFhdHRlCuKWgWJ1bGsKw6lzdAriloF3aW5nCm5pdXMK4paBd2lucwriloFsdWQKdXNoaW5nCuKWgWRldmVuCtC+0LPRgNCw0YQKYnVyZ2VyCuKWgWVtYmFyCkZpbHRlckNoYWluCuKWgXR1bQriloHDtnNzCuKWgW5vbW3DqQriloFwaXIK4paBbHVjCmRibwphZ3VlcwriloFhbGNhbgpvdXdlbgriloFTdGFubGV5CtGG0LjQsNC70LgK4paBZ3Jvd24K4paBcHJlc2VydmVkCuKWgXNvbGFyCuKWgdCd0LDRgdC10LvQtdC90LjQtQriloFwZXJmb3JtYW5jZXMK4paBQ293CuKWgWVuZ2luZWVyaW5nCuKWgXNjYWxpbmcKYXRvbWljCmVuZGFuY2UK4paBYWNlCsOkbmdlbgpBbmltCnBoYXNlCnpidXJnCk9sZAriloFzZXJ2YW50CuKWgWdlbWVpbnMK4paBT2JzZXJ2CnRyYW5zbGF0ZQriloFjb3ZlcmluZwriloFlc3TDoW4K4paBcHJvYmxlbWEK4paB0YPRgdGC0LDQvdC+0LIK4paBbGxldgriloFjemVydwrDqWFsCm1legpSRUUKRVJSCtGC0YPRgNC4CnNlZ3UK4paBcHJvZml0CuKWgW11bHRpcGxpY2F0aW9uCmtvbW1lbgriloFmYXV0CuKWgWNhbmRpZGF0ZXMK4paBVXJpCuKWgUxhdXJhCuKWgXNhcAriloHQstC40YHQuNC90LgK4paBQmV0d2VlbgpmYWRlCuKWgXJlc2VydmVkCuKWgWludm9sdmluZwriloFNYXJlCuKWgUNvbnRhaW5lcgriloHQvdCw0LfQvdCwCuKWgURFQlVHCuKWgWh1cnQK4paBUG9sc2tpCuKWgWx1eApDQgp3YWNoCuKWgdC/0LXRgNC40L7QtAriloFDYXRoZXJpbmUK4paBZ2Fuegp1Y2h0ZQriloFjb25zdW1lcgriloFjcm9zc2VkCm9yZGVyZWQKYXdheQp0ZWNobgriloFzdWJzY3JpCuKWgXNob3J0Y3V0CuKWgdC/0YDQvtC40LfQstC+0LQK4paBc2ltdWx0YW5lb3VzbHkK4paBcmF0aW5nCuKWgUtpbmdzCuKWgXJlbGF0aW9uc2hpcHMK4paBU2V4CuKWgVRvb2wKYWdoCmFjdGVycwpsb2dnZXIKaG9tbWUKZW5nZXJzCuKWgVJpCmVhcmFuY2UK4paBYXBwZWFyYW5jZXMKUmVhbAriloFwYXNzZQppY2xvcGVkaWEK0YfQutC+CnRlcnJlCuKWgU9udGFyaW8K4paB0L/QtdGA0LXQtNCwCmZvb3RlcgphcmNoaXZpCmlmaXoK4paBUHJvdGVzdAriloFMSU4KdW5uYWJsZQriloFjZW50dXJpZXMK4paBQmF5ZXIK0YbRltGOCtC+0LLQuNC9CuKWgUFuZHJlYQpzZWxlY3Rpb24K4paBY2FsbQriloFtb2RpZmljYXRpb24K4paBc2hvcnRseQppbmFpcmUK4paBZnVzaW9uCuKWgWZlZWxpbmdzClBLCuKWgVJvYmVydG8K0LPQvdC1ClNoYXJlZAriloFtZWhyZXJlCuKWgU5pZW0Kb21wCkVudgriloFBcnRpY2xlCuKWgVBvawriloFWQVJDSEFSCuKWgWRpbAriloFhZmZvcmQK4paBY29uZnJvbnQKb3dhbmllCuKWgW1pbmlzdHJlCmFkZXNoCuKWgVBvbHkK4paB0KDQsNGB0L/QvgriloFHcnVwcGUK4paBSGVsZW4K4paBY2MK4paBcG9ydHJhaXQKYmV3CuKWgWJldGEK4paBV2lyCuKWgUF1ZGlvCuKWgShcPApyaW9yaXR5CuKWgW5pdAriloHQv9GA0LXQtNGB0YLQsNCy0LgK4paBVmllCuKWgXfDvHIK4paBSG9sZAriloFTYWQK4paBVG9jaHRlcgriloFvbHRyZQriloFBY3RpdgriloFKYXNvbgriloF3aWVrdQriloFyZWdhcmRzCuKWgXRhc3RlCmFnbm9zdGljCtC70LDRgdGPCuKWgVNlbGYK4paBYXByCuKWgURlZXAKc2NvcApBY3RpdgriloF0eXBlZGVmCkNvbnRlbnRWaWV3CmNvbXBpbGVyCuKWgVJvdGgKeGMK0LfQuNC6CuKWgWxhcmdvCuKWgVJlbmEKaGVpdGVuCuKWgXBsYXRmb3Jtcwp1bGxhCuKWgWdsYW5jZQriloFtYXNjdWwK4paBbWV4CuKWgUpvcmdlCuKWgWZ1bmNpb24KY2hvb3NlCuKWgXJldmlld3MK4paBQWxiYW4K4paBR2xvCuKWgVNwZWNpZXMK4paBRmFtZQriloFSb2xsCuKWgVB1ZXJ0bwriloFcKQp5bW5hcwplbnZpcm9uCuKWgWlwaG9uZQriloFXcmVzdGxpbmcKYcWCeQriloFJbmRpYW5hClJhZGlvClZTCuKWgWluZGVwZW5kZW5jZQrRgtCw0LkK4paBZGVjb2RlCldoaXRlCuKWgWpvdXJuCsOtY3VsbwriloFCYXJiCuKWgUV2YW5nZWwK4paBQW5keQriloFXZWxjb21lCuKWgURldmljZQpnZWYK4paBcmVtZW1iZXJlZAriloF2YXJpYXRpb25zCuKWgUFkb2xmCml0YWluZQriloHQvdCw0LTQvNC+0YDRgdC60L7RmAriloFzdGVhbQriloFjb25jZXJucwriloFgfAriloHQsdC40L4K0YLQtdC70YzRgdGC0LLQsAriloFxdWF0dHJvCmV4dGVuZAriloF0cmFiYWpvCmVuYmVyZwriloFzY2VuYXJpb3MKw6JudAriloFrb21tdAriloFkb21lc3RpYwriloFCYXNrZXRiYWxsCuKWgUNvb3Blcgpzb2NrCtC00LXRgNC20LAKPXtcCuKWgWluaWNpCuKWgVBoaWxsCuKWgdCz0LXQvdC10YDQsNC7CmFyY2hpdmlhdG8K0YrQvQpSb2IK4paBdG9uZwriloFjaGFyYWN0ZXJpc3RpY3MK4paBYW1hegriloFNb2RlCuKWgWluYXVndXIKd2VocgpyYW50CmlvbmFsaQriloFNb3RoZXIKTWEKw6lxdQriloFLZWxseQpjaWxlCuKWgWJlc3RlaHQK4paBZXN0aW1hdGVzCnJ1Z3VheQriloFBbnMKTWFkCuKWgdC90LDQsgriloFkb25uw6llcwriloF0cm9waWNhbAriloFTZXZlcmFsCmVsdGVyCuKWgVBobwprZW0K4paBQ3VzdG9tZXIK4paB0YHQutC70LDQtNGWCuKWgWNvdXJzZXMKUGxhdGZvcm0KbmF2YmFyCmxlYXJuaW5nCuKWgVN3ZWRpc2gK4paBemFzdAriloFMaWcKbWFuYWdlbWVudAriloFsb2QKdWZmbGUKVGV4dHVyZQphcmdhCsOhdHVtCuKWgUREUgrQvdGW0ZcK4paBU29jacOpdMOpCuKWgWRvbWFpbnMK4paBcGVybWl0dGVkCuKWgWV4dGVybmUK4paBcXVlbHF1ZQp2dAp5bWFuCuKWgVdhcmQK4paBYWdsaQriloFhbmRyYQpTbmFwc2hvdAriloFtw6UK4paBeWVhaArQtNC10L3QsArEmXB1CmFza2VsbAriloFSw6lwdWJsaXF1ZQppbmplY3QK4paBJzsKw6RubgriloF6ZWxmCuKWgUVudHdpY2tsdW5nCsOhcmlhCm9ub215CuKWgXN2aWwKaWVzZQriloFjb25zZXIK4paBbmltCuKWgXLDqXN6CuKWgdCY0YLQsNC70LgK4paBcGFydGljaQriloFMaW9uCnNyCmFsd2F5cwriloHQktC70LDQtNC40LzQuNGACtGH0LXRgdC60LjQtQpbLAriloFEZWZpbml0aW9uCm5hbnQKb2VtCklkcwriloHQstC90LUK4paBWy4uLl0K4paB0L3QsNC/0YDQsNCyCuKWgUdPCuKWgcOlcnMK4paBdXTDoW4K4paBb3V0cm9zCuKWgXJlZ2nDs24K4paBTW9uZwriloFmaWxtZQriloF0cmlwbGUK4paBc3BvbnMKRGV2ZWxvcAriloFvdXRjb21lCuKWgUJpYmxlCuKWgdC40LzQtdC90LgKQ2FudmFzCtC/0YPRgtCwCmN1cnIKw6Fzb2sKKXtcCm5pbmdhcgpgOwriloFGbGFzaAo6IwptdXN0CmNwdQriloFmb3JtYXRzCkhhcgriloFlcGlzb2RpbwriloFSb3NhCuKWgWTDqHMKZW1pdApyaXRlcmlhCkFubm90YXRpb24KRmxhZwpnbWFpbAriloFOb3JtYWwKb2xsYXJ5CuKWgWZvc3MK4paBY29uY3VycmVudAriloFjcmFzaGVzCuKWgdCy0LjQtNC1CuKWgU1pbm9yCuKWgVNpdAriloFTTgriloFzY2FyCuKWgWZlbWluCuKWgXNwZWNpZmljYXRpb24Kc29hcAriloFvcGVyYXRlCuKWgXByaW5jaXBhbG1lbnRlCuKWgWF1c3QKaWJpbGUKaXRpbWUK0LvQtdC20LAKaWZyYW1lCuKWgWNvbmNlcHRzCuKWgXRhY2sK4paBdmlzcwriloFjYXJib24KdGVyeQriloFuYW1pbmcK4paBT3J0cwppZGVudGUK4paBQ2FwaXQK4paBZXhwcgriloHQvdCw0YHQtdGZ0YMK4paBU2VsZWN0ZWQK4paBaGludGVyCuKWgWlmcmFtZQriloF6YgppbmRleFBhdGgKY29sbAriloF3cnplxZsK4paBYWNodAriloFncmFkdWFsbHkK4paB0YfRgwrQt9C10LkKaGFmdAriloF0cmFuCuKWgWxhcXVlbGxlCnl0aWNzCklERQriloFweWdhbWUK4paBUGFja2FnZQriloFjbGFzc05hbWUKQmFsCnBlcmwK0YLQuNC90LAKT2NjCuKWgWluZnJhc3RyCuKWgUNoYW1waW9ucwriloFjbGFzc2ljCuKWgVJhdwriloFwYXJ0aWFsbHkK4paBVGVkCuKWgXN0b2xldApyYWluZWQKV0hFUkUK4paBdmFsbAriloFKdWxpYQp6YXQK4paBc3Vycm91bmRlZApTRUUK4paBd2Fsa2luZwpCYWQKRk9SCmNvbnRyZQriloFQYWxlc3QKw6F0aWNvCuKWgWVuZ2luZWVyCuKWgXBhcnRuZXJzCuKWgUpld3MKaWxlcnMK4paBY2VyZW0K4paBaW50ZXJhY3Rpb25zCmFjdQpzdHkK4paBUHJpbmNlc3MKc2hhcnAK4paBU2luZ2xlcwriloHRl9GFCmNoZXoKUmVjZWl2ZXIK4paBcGF0aWVudHMKc3RyaW5naWZ5CuKWgWNvbXBldGVkCmJleQokOwriloFCZApoYWRvb3AK4paBRGl2aXNpw7NuCsO2bGQK4paBcmVzdHJpY3RlZAriloFjb21tYW5kZXIK4paBSGlnaHdheQriloHEjGVzawriloFteXRoCtGH0LDQvQpyYWhhbQriloFlbnF1CuKWgXBvZwriloFjb211bmEK4paBcHJpbnRsbgriloHQutGA0YPQvwriloFkZXBvaXMK4paBc2VhdHMK4paBbmVpZ2hiCtGG0LjQvtC90LAKYWdpbmUK4paBY2xvdGhlcwriloFQcmlvcgpCcmFpbgpGRkZGCic6JwpmZWF0dXJlcwriloFmaWxlc3lzdGVtCuKWgXNpbmdsZXMK4paBTWVsYm91cm5lCuKWgWRlc3RydWN0aW9uCuKWgUx5b24K4paBSW5zZWwKTmF2CuKWgVJlcGxhY2UK4paBbMOpCldobwriloFFc3RhZAriloFkaW1lbnNpb25hbAriloHDtmZmCuKWgWdyYW5kcwrQtNC20LAKcGxhbmUK0L3QvtGB0YLRlgriloFPcmlnaW4KV0kKw6RubmVyCuKWgUNyeQpJVElPTgriloFmw7ZkZAriloFjdWx0dXJhCuKWgVJhbmsK4paBdnVlbAriloF6YWcK4paBTWF4aW0K0L7QvdGDCigpKSkKUmF3CmtpcmNoZQriloFhZGVtw6FzCuKWgXRpZQriloFTdHlsZQrRgdC60L7Qsgppc3RhbnQKb2xwaAriloFaw7xyCuKWgUluZm8KRE9NCnVzYwpuYWhtCuKWgdCk0LXQtNC10YDQsAriloFGb3QK4paBc3BlY2lmeWluZwriloF0aXRvbG8K4paBQm95cwppZWNoClBsYWNlCuKWgUhvZmYK4paBY2FjaGVkCtCy0LDQu9GMCmlzaGVyCnJvbGxpbmcKb3BlbnMK4paBaHIKLS0tLS0tCuKWgW1hZ2dpb3IK4paBdHJhbnNhY3Rpb25zCuKWgWNyaW1pbmFsCuKWgXJldHJlCuKWgUNhbXBiZWxsCikpOgriloFuZWQKUGFnZXIK4paBSGVybwooX18K4paBdW5jbGUK4paBcmVhY2hlcwphcnRvCuKWgWhlbGxvClByZWZlcmVuY2VzCuKWgdC30LDRgtC10LwKTmFtZWQK4paBcmVhZGVycwrRhdGWCmtlcm4K4paB0YPQv9C+CtC60LjQvQriloFsYXYK4paBbm9iCuKWgXNlY3JlCuKWgUxpc3RWaWV3CtCy0LDQvdC40Y8K4paBTWF5b3IKYm9yb3VnaAriloFmaWxvc29mCtC90LXQvdC90Y8K0YTRgNC4CuKWgXBhdHIKRk0K4paBYWNpZAriloFTYWx2YWRvcgriloFhYmIK4paBR3JhaGFtCnBvbGljeQpuZWdhdGl2ZQrFhHNraWVnbwriloFIZWltYXQK4paBZGF6dQriloFtZWx5CuKWgXJpZGUK4paBZHV0aWVzCm92ZXJ5CuKWgVByb3Bvc2l0aW9uCuKWgVBhb2xvCi8nCuKWgU1hdQppbWVudGkKU2FpbnQKZmF0aGVyCuKWgWVxdWlsaWIKcGhvbnkK4paBY2xhcwriloHQvtGC0LvQuAriloFCdWZmZXJlZApyZWsK4paBbWl0dAriloFIdXIK4paBSGFydmFyZAriloFkZW1vbnN0cmF0ZQp1YXJpbwriloFkb2xvcgriloFyZWplY3RlZAriloFNw7xsbGVyCuKWgW5hYwriloFCZWxsZQriloFnYXRoZXJlZApucgpmcmlrYQrDtmxsCuKWgWNoZW1pY2FsCm5pZwriloFjYWxjCuKWgURFRkFVTFQK4paBcGhpbG9zb3BoeQriloFMYXJhdmVsCuKWgWFsaWdubWVudApFVgplb3IK4paBZHppZQriloFtZXN0CuKWgUlvCkNSRQrQt9Cy0LgK4paBTWVkaWMK4paBbsOkCuKWgXphYgriloFTbG92CnV0bGljaAriloFhbXBsaXQK4paBRnJhbmtyZWljaAriloHQutGW0LvRjApJTkQKZXhlY3V0aW9uCuKWgUthcnJpZXJlCmRvc3TEmXAK4paBcsOpYWwKZW5nbwriloFzZXZlcmUK0LfQvNCwCuKWgdGC0YPRgNC90LgK4paBQ2FydGVyCuKWgVJvYmluc29uCmdldEVsZW1lbnRzQnkK4paBcHJvdG90eXBlCuKWgWphcG9uCmbDvGhydW5nCuKWgWNvbnNlZ3UK4paBc3R1ZGkK4paBbGlyZQriloFzY2hsaWXDnwriloFCdWZmCuKWgXJlZHVuZAriloFlcm4K4paBbXlzdGVyCuKWgXByb3ByaW8KYXRlZnVsCuKWgVBhcmVudAriloFsYWRpZXMKcmFjawrRgtC40LrQsAplbmJ1cmcK4paB0LrQsNGH0LXRgdGC0LLQtQriloFFRgriloFzdGFtCuKWgW51ZXZhCuKWgWZpbHRlcmVkCnJldGVuCuKWgUlhbgriloFNYXR0aGV3CmtpaAriloHFkQriloHQutC+0LzQv9C+0LfQuAriloFmb3JldmVyCm9pcmVzCjpcXAriloHDqXR1ZGVzCuKWgXNvdXAK4paBcGxlYXNlZAopfSgK4paBU3RvcApTZXR0ZXIK4paBSGVscAriloFiYXJzCuKWgUVSUgriloEoPwriloFwb2V0cnkK4paBVXRpbApBSwriloFmaWNrCuKWgUlNCuKWgXByb3VkCtC90L7RgdC4CuKWgW11ZXJ0ZQriloFQYWxtYXLDqHMK4paBTmFzCtGJ0LjRhQriloFxdWVyCuKWgWFwZW5hcwpdWycK4paBS29uc3QK0L/QvtC9CuKWgVNjaGlmZgriloFtcAriloHQsdC70LDQs9C+CmZyYW0K4paBaG91c2Vob2xkCuKWgXRyYWN0CmVuY29kaW5nCuKWgXVuZGVydAriloFBdWcK0L7QstCw0L0K4paBQXJ0ZW4K4paBaW52b2tlZAriloFkeW5hc3QK4paBZmxlZXQK0YfQtdGB0YLQstC+CuKWgU11cnJheQriloFndXQKZWxpaG9vZAriloFTU0gK0L7RgtCy0LXRggriloFwZXJzb25hbGx5CtC/0YDQuNGPCuKWgWZpbmFuY2kK4paBVGhvbXBzb24KYWx1CmlkZW50aXR5CuKWgUdyYWIKYWRkbGUKw4l0CuKWgVRvYgriloF2ZXJsb3IK4paBU2FpbnRlCuKWgWRvcAriloHQstC10YDQtQpfX18K4paBcHJvbW90aW9uCuKWgS09CuKWgdC+0YLQtNC1CuKWgWFtYmlndQpPUkRFUgriloFDb21tdW5pYwriloFpbXBseQpvbmVkCmNsdWRpbmcK4paBY29sbGlzaW9uCuKWgWZyYWdtZW50cwpzY3JpcHRpb24K4paBJ3sK0LvRj9GFCuKWgWhhbnMK0YPRgQp3aXJlCm5hbWVzcGFjZQriloFzd29yZApyZWZyZXNoCuKWgWt3YW0KenMKY29tbW9ucwriloFjb3NhCuKWgXJlZ2ltZQpncmVwCuKWgWRpb2MK4paBQ29udGFjdAriloFlc3RhcwriloFTdGV3YXJ0CuKWgXZpZWxlCtGC0L7QstCwCuKWgVJhbgphbm5lcwppZGF5CuKWgXNuYXBzaG90Cm9ycm93CuKWgXphxI0K4paB0YPRh9Cw0YHRgtC40LUK4paBcHJvbWlzZWQKQXNzZW1ibHkK4paBY2hhbXBpb25zaGlwCuKWgURlZmluZQriloFlcmVuCuKWgdC90L7QstC+CuKWgXRoaW5rcwpBZ2UK4paBZ2V2CnZhcmNoYXIKaXZpdMOgCmNvbXBvcwriloFNdXR0ZXIKQ09OVAphcm3DqWUKYWduZXQK4paBQnJvdwou4oCUCuKWgVRlbGV2aXNpb24K4paB0JTQu9GPCuKWgXZtCuKWgW9yZGluCuKWgdCc0LjRhdCw0LkK4paBYXByb3hpbQonKS0+CuKWgXpvbwppcHBpCuKWgXNpbm8K4paBUXXDqWJlYwpyYWdlcwrDpGNrCmVpbmcKYXJsbwpwaW9zCuKWgUNoYW4K4paBZWxsaQriloFpbmNvbnMKZ2VzdGVsbHQKcHBlcnMKSmVhbgphbnN0YWx0CuKWgURhbmNlCuKWgXRvZW4K4paBZGVjaXMK4paB0KDQtdC30YMK4paBb2ZmaWNpYWxseQrDpHR6ZQriloHQtNC+0YDQvgriloFlbnVtZXIK4paBdHJvaXNpw6htZQp0eXAKb2ZmcwrQsdC+0LvRjApvZG4K4paBWmFyCuKWgdC00YDRg9Cz0L4KcXVpYQriloFOaWNvbGFzCtC/0LjRgdGDCuKWgW1vYgpwYWNlcwrQvdGM0L7Qs9C+CkFsZwrDqXJvw68KRXJyb3JzCuKWgdCz0YDQtQriloHQttC10L3RidC4CmluY2gK4paBS29yZWFuCuKWgUFwb3N0CuKWgUxpdmVyCuKWgWVsZW1lbnRhcnkK4paBREkK0LLQuNGB0LgK4paBc29pbAriloFETEwK4paBcmlzcAriloFTaGFrZXNwZQriloFHYXVzc2lhbgriloFLdXJ0ClZlcnRleAplYm9sCm9yZ2FuaXNhdGlvbgrDpHJlbgriloFZRVMKQ1VSCuKWgdC90LDRh9Cw0LvRjAriloHQv9C+0YHRgtGA0L4K4paBTHVpZ2kK4paBY2FjaGluZwpwcmV2ZW50RGVmYXVsdAphbWQK4paBVml0CnN1YnN0CuKWgdGB0YLRgNC+0LgK4paBQ2FtcGlvbgpjaHIK0YTQtdGA0LUK4paB0KHQv9C40YHQvtC6Ck5GCuKWgWPDrW0K4paBaMOpCnJlYmJlCm9jeQpiZWxvdwriloFieWxvCuKWgdCj0LgK4paBXCh7XAriloFgOgpnaW9yZQpTYW4K4paBR2F0ZQriloHQstGBCuKWgW9saW1wCuKWgU1hdHJpeAriloFoZWFyaW5nCnJpaQp0ZnJhYwriloFhbGxlbWFuZAriloFWdWUK0LvQvQriloFjb21waWxpbmcK4paBRW5zCuKWgWludmVzdGlnYXRpb24K4paBQXgK4paBY2hhcnMK4paBdGFyZ2V0cwriloFsb3VkCnVzZW1lbnQK4paBTmV0aGVyCmNvbW1lcmNlCklHSFQKb2NvYQppZmVjeWNsZQriloFMZW8KcHJpdgriloFnb29kcwphZGFtZW50ZQpBdXN0cmFsCuKWgXJlYm9vdApHZXN0CuKWgXJlcHJlc2VudGF0aW9ucwpjZXUK4paBZG9jdHJpbmUKY2VycwriloFLcmFrCuKWgWFkdm9jCuKWgXNxdWFkcmEK4paBYXJiZWl0ZXRlCsO8c3QK4paBcGlsbApBbnN3ZXIK4paB0LrQstGW0YIK4paBV2EKdW1hbm4K4paBRHluYW0KRmFtaWwK4paBdGVubmlzCuKWgUVuZ2luZWVyaW5nCuKWgWNpcmNsZXMK4paBTWFyeWxhbmQK4paBYmVzdGEK4paBYmFzZXMK4paBem5hamR1CtC60YLQvtGA0LAK4paBYXJyZXN0CtC70LXRgAriloFHaWEK4paBcmVtYXJrYWJsZQriloHQvNC+0LPRgwriloFTdXByZW1lCuKWgWAlCmRvcgriloFhdWpvdXJkCuKWgXdpcwpXSURUSAriloFtaXNtYQriloFmbHVpZAriloFwZXRpdGUK4paBVG93ClJlZ2lzdHJ5CmVtZWQK4paBV2lzY29uc2luCuKWgVJhY2luZwriloFyZWdpc3RyYXRpb24KLyUKdGhpcmQK4paBbW9udW1lbnRzCtGH0LXQuQriloFqZXQK4paBVXJiYW4Kw6FsdmEK4paBbWlsaWV1CuKWgXBvc3Nlc3MK4paBZ2VybQpkZXBlbmRlbmNpZXMK4paBZW5lbWllcwriloFzYW1lbgriloFXZXJuZXIK4paBaGl6bwriloF0ZAriloF5ZXN0ZXJkYXkK4paB0JDQtAriloFoYXNuCmNlbGxhdGlvbgpvdsOhbsOtCmxpa2EKV2VlawriloFJbmcK4paBRW1haWwK4paBbcOodHJlcwriloFPQ0xDCuKWgWFtb25nc3QK4paBc3BsZW5kCmZ1cgphbnRpY3MK4paBWFhYCuKWgdCz0YDRg9C/0L/RiwpsYWNoCuKWgWNvdXNpbgriloFpbnZhcmlhbnQK0ZLRgwriloFCZWlzcGllbAriloFoYXJkZXIK4paBYmVsbAriloFvcmNoCnRiCkZvb3Rub3RlCnJlZ29uCk1hcnRpbgriloFpbmNvbgriloFhdHRhY2tlZApfey0K4paBVHJhcwpwYXJ0eQppdGVpdAriloFzYWludApyw6Fzb2sK4paBY29udGFpbmVycwpNbwriloFTbgpxdWFudGl0eQriloFyYXMK4paBQ2FuYWwKY2Npb24KdXZvCuKWgWlkeAp0eXBlbmFtZQriloFSdWdieQriloFTZWVtcwriloF0cmFuc21pdAriloFQcsOkc2lkZW50CtC30L3QtQriloFCYWtlcgppbnRoCuKWgXTDtmJiCnZlcmVpbgriloFlc3BlY2llCiwoCuKWgXTDqWMK4paBV0lUSAriloF1bm9zCuKWgXBvbGl0aWNzCmNyZWF0ZUVsZW1lbnQK4paBc3RhdHMK4paBVGVubmVzc2VlCuKWgUJlZGV1dHVuZwriloFTY3JlZW4K4paBU3RyYcOfZQphbnplCuKWgXBhcnRseQptYW51ZWwKb2xhdGlvbgpob3Jpem9udGFsCsOpcmlldXJlCmFtcGlvCuKWgdGB0YLRgNGD0LoKV2VpZ2h0CkxhbmQKcG9seQriloFEYWsK4paBQXNzdW1lCiIuJAriloFjYXNpCuKWgWdyb3NzCuKWgWVudGVydGFpbgriloFkw6ljYWRhCicuJAplbmNlcgriloFndWFyYW50ZWVkCl0kLgrQu9C40YHRjwriloFhY2NlcHRhYmxlCnJhaXNlCmlydXMKd2VpdAriloHQkNC90LAK4paBaGlsbHMKaXBhZ2UKQklUCuKWgW51Y2xlCuKWgXV0aWxpcwpDQUEKw6huZXMK4paBU2Nod2VpegriloFBQQpuaW5nZXIK4paBYmFuZHMK4paBdGVuZGVyCnNvbQpXYXJuaW5nCuKWgUJpc2Nob2YK4paBQXJjCuKWgVdvbWFuCuKWgXRyYW5zbWlzc2lvbgrRh9C90LgKaXN0cmUKQlkK4paBU0kK4paB0J/QsNGACuKWgX0pLgriloFwcmVzZW50YQriloFSZW7DqQriloFoYXBwaW5lc3MK4paBUHVuawpjb2xzCuKWgURlc2RlCtGA0ZHRhQriloHQvNC+0L3QsAriloFzY3JhdGNoCuKWgXRjcArDqnRlcwppdGF0ZWQK4paBZGlmZXJlbgpnZWgKbmFobWVuCtCf0LUKY2tpCuKWgVRlYXRybwriloFSZW1lbWJlcgriloFmcmlnaHQK4paBWWFtCndlc3Rlcm4KbGV0ZWQK4paB0LLRgdGC0YDQtQriloF0ZWxlcMO8bMOpcwrQt9C40L0K4paBUXVhbnQK4paBc3VwcmUKw6FqYQrQtNGW0Y8K4paBY2FycmVyYQprcmV0CnBhcmEK4paBU1VNCuKWgXBpdArFumR6CsOpbwrRgNC10L3QvdGPCuKWgUNob3IK4paBdm9peAriloFleGVjdXRpdmUK4paBYWxsZXJkaW5ncwpNYXliZQriloHQtNC10L3RjAriloFmbHlpbmcK4paBcGFybGlhbWVudArQttC00LDQvQriloFmcmFtCuKWgdC20L7QstGCCuKWgXVnbHkK4paB0LHRg9C00YMKaWdueQpcfF97CuKWgWJpdHRlcgpzY2UK4paBcG9sZQpWZXJsYWcK4paBdG90YWxpdMOpCuKWgWZvdW5kYXRpb24KanQK4paBc2xpY2UKaWZpcXVlCuKWgWludGVncmF0ZQpzdHJpagriloFhc3ltcHQK4paB0LXQvNGDCuKWgXBlcnR1cmIK4paBRmxvdwpqYm9zcwpSSUcK4paBQWxlc3MKWFhYCuKWgXN1bW0Kc3FsaXRlCuKWgWNoZWVyCnByb2IK4paBR1BVCnppxYIKKCopCuKWgWluZHVjdApSQVkKYmxhdHQKcXVlc3RhCm9ydQriloFJbnNpZGUK4paBTWNHCuKWgU5lcArQvNC/CuKWgWludmUK4paBQW5pbWFsCuKWgXNvYgrDrXRvdHQKbG95bWVudAriloFidW5kClN0YXRpb24K4paBQkVHSU4K4paBcGFydGllbGxlbWVudAppZ2cKZXN0b3JlCuKWgWNvaW5jCuKWgVNvbW1lcgriloFtZAriloFsb2NrZWQKbWF0aGNoYXIKYXJtYQpwZW50CmFyaXVtCuKWgWVhcnMK4paBU29uZ3MK4paBc2ltaWxhcmx5CuKWgWxpdGVyYWxseQriloFpbmNoZXMK4paBYWZmZWN0aW9uCmxwCuKWgWNvbmNsdWRlZAriloHQvNGD0L3RltGG0LjQv9Cw0LvRlgriloHQv9Cw0LzRjwplc3RhdXIK4paBSm9zaAriloFGcml0egpEQkMK0LTRkdC9CnBvc2EK4paBZ29sZGVuCuKWgXBjCuKWgWNvbXRlCuKWgVppZWwK4paBcHLDqXNlbnRlCm1hcmtzCmlnbmV1cgriloFEcml2ZQriloFuZWdsZWN0CuKWgXJvenAK4paBRml2ZQpzcGFjZXMK4paBTWVkaQriloFleGlzdGVkCuKWgWJ5xYJhCtC00LbQuAriloFmcmVudGUK0YLQvdC40LoKb2RkCuKWgWFuc3dlcmluZwpiaWFuCuKWgUV1Z2VuCuKWgVB1YmxpY2F0aW9ucwriloFEaWEKbMOhCuKWgSdfCuKWgXJlY3VwZXIK0L7QvNGDCuKWgUFwcGVuZApvYmFyCuKWgWVtcGxveWVlcwriloFjb21wZW5zCmVtZXRlcnkK4paB0Y3Qu9C10LrRggpNT04Kb2xpbgriloFoaXN0b3JpYwpoaXMKxIVkCm5tCuKWgUdvdGgK4paBc3RyZXNzCuKWgXBhcnRlY2lwCuKWgUF3CuKWgXNhcgriloFodQriloFtYXRwbG90bGliCuKWgU15c3QKKCk7YApzY2hlaW4KTG9uZ3JpZ2h0YXJyb3cK4paB0YDRjwriloFJc3JhClteCm5vdQriloFzeW5kCndvcmtpbmcK4paBTmF0aW9uCuKWgVBlbnQK4paBa2xhc3MK4paBYXBwbGljYWJsZQriloFEaWFtCuKWgWJyYXNpbGUK4paBcGFjCuKWgUhlaWdodApQdXQK4paBaW50cm8K4paBdW51c3VhbApuYXMK4paBR2Viw6R1ZGUK4paBYmVhbQriloFSZWN0CuKWgVByaW1lcmEK4paBaGF1dAriloF0cmFpdApwcsO8ZnQKaW5hY2nDs24K4paBY29uZmlndXJhdGlvbnMK4paBZ2lsdAriloF0ZXJyaXRvaXJlCmhlegriloFhbHRlCnJlbGF0aXZlCkV4Y2VsCuKWgVdyaWdodApHVgrQv9C+0LvQuApRdWFudAriloFnYXVnZQriloFtdWx0aXBseQpBU1MK0YHRgtCy0LXQvdC90L4K0LDQvdGDCuKWgWplZGVuCuKWgWxpdGVyYXJ5CuKWgURybwriloFhZHZpc2UKaXR6ZW4K4paBZGlzYWcKd2Vic2l0ZQriloHQtNGW0Y8K4paBb2JzZXJ2ZXIK4paBamFudcOhcgp2xJsKa3VwCuKWgVNlcwriloF3b2pldwriloFzdGFnZXMK4paB0LLRgNC10LzQtdC90LgKxYJ1xbwK0L3QvtGBCkRvd25sb2FkCmlwbwriloFncmFmCuKWgdGA0L7QsdC+CuKWgU5pa29sCuKWgWZpYwriloFqb2luaW5nCuKWgWRpdmVyc29zCuKWgUxJS0UK4paBRml0egriloFkaW1pbgriloFkaXN0cmliClNhbQprb3oK4paBYWxwaGFiZXQKb3NlcgpPVVIKdWthCtC60LDRjwriloFzdGVlbAriloFgLS0K4paBdGVuZXIKbWFya2VyCuKWgUhlYXZlbgpuZXdjb21tYW5kCuKWgXByaXNvbmVycwriloFLbmlnaHQK4paBcHJlc2VudHMK4paBcXVlc3RpCuKWgXRyYWlucwpvcGVyYQriloFMaW5lYXIK4paBTUUK4paBQnVjCkxlZwriloFhZ3VhCuKWgUdyaWZmCm9sZwpkc3QKLg0K4paBcGVyc29uZXMKTWFsCtCx0LXRgNC1CmZvbGdlCuKWgWFjYWIKY3R1CnB0aWMK4paBTmF2aWdhdGlvbgpSdXNzCtCz0LDQu9GMCuKWgUZ1bAriloHQvNCw0ZQK0YfQvdCw0Y8Kd25lcgpjb250cmEK4paBam91ZXVyCuKWgUplc3MK4paBcmVuZXcK4paBbGFwCuKWgWNhc3RpbmcKZ2FsCuKWgXTDqW1hdHUK4paB0L3QsNC30YvQstCwCtC30LDRhQrRh9C90LUKKS1cCuKWgdGH0LDRgdGC0L4KfSQtCuKWgWxpY3oK4paBZW1vdApoYXJtCuKWgW9jY2FzaW9uYWxseQriloFob3Jyb3IKZWFzdAriloFwcmludGVyCmFyYW4K4paBTWlzc2lzcwpmb2xsb3cK4paBQmFycnkK4paBaW52ZXN0aWdhdGUKZ293CuKWgUFtZXJpY2FucwpTaW5jZQriloHQstGW0LTQvgriloFyZXVuCm9zY2kK4paBQ2hhcHRlcgriloFiYXkK0YDQvtC80LUKZXRoZQrDqWRpZQpjb21vdAriloFtaWVqc2Nvd28K4paBc3R1ZGllcnRlCm91dmVydAriloHQutGD0YAK4paBREVTQwriloF0b3VjaGVkCuKWgUplcnJ5CnVlc2UK0LvQuNGJ0LUKYXV0aGVudGljYXRpb24K4paBY29sbGUKaGVhcnQK4paBcmVnaW1lbnQKY3JpYmVkCuKWgdCR0L7Qu9GMCuKWgdC/0YDQvtC40YEKY2VhZQriloFtYXNzZXMK4paBc2Nyb2xsaW5nCnVzdG8KU1cKb3ZhdAriloFncsOiY2UK4paB0JDRgNGF0LjQsgriloHQodC10LLQtdGACmF2YWl0CuKWgU1hcnNoYWxsCuKWgUhhc2hNYXAKYWNvbgrDvGNrZW4KW10pCuKWgWV2YW5nZWwKZXR6dW5nCnR0ZW1iZXJnCnN0ZXJzClRNCuKWgdC70LjRgtC10YDQsApxdW90ClByZWQK4paBd2VyawriloFoYWJlcgpsYXZhCnZvdXMK4paBTGF0ZQpjeWNsZQrRgtC40YDQvtCy0LAK4paB0L/RgNC+0LTRgwriloFwb3B1bGF0aW9ucwriloFZYW4KUHJlZml4CmFjdMOpcmlzdGlxdWVzCisnCigpYF0oCuKWgdCb0YwK0YTQuNC70YwK4paB0LbQuNC30L3QuApmdHAK4paB0LLRgdC10YUK4paBZ2R6aWUK4paBdmlkZWEKb2F1dGgK4paBcGlkCsWvbQriloFwZXNzbwriloF0cmFja2luZwppemluCuKWgU1vcnJpcwrRidC40LkK4paBUHJvdmluegriloFNaXR0ZQriloFhcnRpZmljaWFsCmJyw6F6a3kK4paB0LTQvtGB0YLQuAriloFyZXN0b3JlZAriloFjb21tdW5pY2F0ZQphZ2l0ClJlY29nbgriloFsb24K4paB0LfQsNC90Y8K4paBQXJndW1lbnQKZmx1c2gK0LzQsNC90LAKc2Vjb25kcwpVQwriloFSdXRoCuKWgXR1YgriloFCcmV0CuKWgVBlcmUK4paBcmVzcG9uc2liaWxpdHkKxYRjenkK4paBZW52aXJvbm1lbnRzCmtlZQriloFncm9vdAriloFwYWludGVkCuKWgcOJZGl0aW9ucwpjcHkKw6FydApsaWNoa2VpdAphcmRhCkJhdGNoCuKWgUxlb3BvbGQKcmVhc29uCm5vcmVmZXJyZXIKc2VucwriloFyb2NrcwriloFIaXRsZXIK0LvQsNGCCuKWgXF1b3RlZAriloHQutC+0LvQu9C1CuKWgdGD0YDQvtCyCmJhZwouIikK4paBTUwK4paBa29tdAriloFbXwriloFzcGVjdHJhbAplZG8K4paBaW5zaWVtZQriloFzdWZmZXJpbmcKc2xpZGVyCuKWgUtlbm5lZHkKb2xhdGUK4paBUGF0cmkK0LfQuNC4Ck9ICuKWgdGC0LXQsAriloHQv9GA0LDQstCwCtC80LDRhQpyZXdyaXRlCuKWgUVpbnNhdHoKZXh0ZXJuYWwKaG9sZHMK4paBUGxhY2VzCmF0eXBlCuKWgXZ1bG5lcgriloFhYmFuZG9uZWQKT3JpZ2luCuKWgW1heGltYWwKQUFBQQriloFCYXNlYmFsbAriloFDbG9zZQriloFwYWludGVyCuKWgWFzc2lnbmluZwpOQgpibGFzdAriloFLw7xuc3RsZXIKKV0oCmZhY2gK4paBQ29uc3RhbnRpbgpva2VzCuKWgW5vYm9keQriloFzdWJ0cmFjdAriloFmb3NzZQriloFjZXJ0aWZpYwriloFtdXNlCi8pLAriloFQcm9maWwK4paBcHJveGltCuKWgUplcnVzYWxlbQriloFzaW1wbGljaXR5CuKWgXdzegpOVU1CRVIKdXR0YXZpYQpVSVRhYmxlVmlldwppY2h0ZXIK0LbQsNC9CuKWgUxhdgppdGNoZW4K4paB0KfQtdC8ClR1CuKWgWdlb20K4paBenZ1a3kK4paBU3VydmV5CkFOQ0UK4paBZW5jcnlwdGVkCnByb2YK4paBZGFyZQriloFMb3JlbgrRgtCyCuKWgdCQ0LvQtdC6CuKWgWNvbXB1dGVycwriloFleHBlY3RhdGlvbgriloFzdWJzdGFudGlhbAriloHQlNC80LgK4paBYHsK4paB0LTRgNCwCnViYmxlCuKWgXBlcmZvcm1zCuKWgUtyaWVnCuKWgWluY29taW5nCuKWgUNsYXNzaWZpY2F0aW9uCldlYlZpZXcK4paBZXBpc29kZXMKYXBwZXIKw6R1ZmlnCuKWgWdpb3YK4paBRGVwYXJ0CtCx0L7RgNCwCmVkbHkKb3Nwb2QK4paBcHRyCuKWgWTDoXR1bQriloFlc3RpbWF0aW9uCmljb2xlCuKWgS0tLS0K4paBcHJpbmNlcwpIRUFECuKWgWRpZmZ1c2lvbgriloFkcmllCuKWgUFkYQrQvdC40YbQtQpuZ2lueApzaGFsCuKWgWZlYnJ1YXJpCuKWgVRhdApsb29raW5nCmt1bmQK4paBRGVhbgptb25nb2RiCtCy0YjQuNGFCuKWgUF1cgriloFGbG9yYQriloFTdHVkaW9zCtGG0LjRmNC1CmVpbApJbnN0YWxsCuKWgWZyYW5jaAriloFITVMK4paBcHJhY3RpY2VzCmxlagpkYWxlCuKWgXBvc3RlCuKWgUhlbHMK4paBcmVsaWFibGUKxbpkemllcgriloF2ZXJzZQplcm1laXN0ZXIK4paBcXVpdArDqXRpY28KaWxpcwplZG9yCuKWgUN1bHR1cmFsCtC00LbQtQriloFsaWtlZAriloFtb25nb2RiCuKWgUJyb2Fkd2F5CuKWgUlSCmVzenQKaG92CuKWgW3DrXN0CnJlaWNoZQriloFrQgrRgdGC0L7QvAriloFTUUxpdGUK4paBdG9ybmVvClwuCk9yZAriloFBZG1pbmlzdHJhdGlvbgriloHQt9C00LAK4paBSGludGVyCuKWgVZpYQpEZWNpbWFsCm9yaW91cwriloFuw6ljZXNzYWlyZQp3eAriloF0ZWoK4paBdGVtYQpPYnLDoXpreQrRgNC40YLQtQriloFidWlsZHMK4paBbGF0ZW4K4paB0LPQswpWaXNpYmlsaXR5CmzDpHUK4paBc2VjaHMK4paB0LvRg9GHCmNlcmEKQ291bGQK4paBdHJhamVjdAp9fV57CuKWgUphcG9uCmFub3RoZXIKSUsK4paBYmVsb25naW5nCuKWgWZhY2lsaXRpZXMK4paBRGFpbHkK4paBZGVjZQppbnRybwriloHRgdC70YPRh9CwCk5hbWVzcGFjZQriloFCYWsKbG9jYWxlClVHCj0kewriloFjb21wYcOxCmrEhWMK4paBYXJpdGhtZXRpYwpmb3J1bQriloFwb3J0YQpvbmsK4paBZ2VuZGVyCuKWgWV4cGVjdHMK0LHQutCwCuKWgW5hawriloFHcmFjZQriloFzdHJvCml2aWR1YWwK4paBQ09NCuKWgUZhcm0K4paBY2FudG9uCtGC0L7QvNGDCmphdmF4CtGB0LXQuQriloFicmllZmx5CkZhY2UKcm90YXRlCmNvbnN0YW50CuKWgWdhbGxlcnkKYXN0cm8KYWxsZXJ5CuKWgURKCmNoYXJnZQrRhdC+0LTQuNGC0YwKQ2VudApcIiwK4paBZG9ubmEKYXJjYQpsYWRlCnppbgriloFOZWQK4paBaG9zdGluZwppZG9yCml0YXRpdmUKaWdzCuKWgdC/0YDRjwriloF0aWNrZXQK4paBc3R1ZHlpbmcK4paBZGVzaWduZXIKbGFwc2VkCuKWgWxhYXQK4paBZGl4CuKWgWludGVncmF0ZWQK4paBaW5mb3JtZWQK4paBYmVoYXZlCuKWgWxhYm91cgplc3RlbGx0CmNhbGVuZGFyCuKWgWtpbGxpbmcK4paBdHdpdHRlcgppYWUK4paBaGlzdG9yaXF1ZQpERUZBVUxUCmlhxYJhCuKWgXRoZW9yZXRpY2FsCuKWgXVuZGVycwrQu9GP0LXRggphdGFuCuKWgXN1cm5hbWUK4paBaW50ZXJjZXB0CtCz0LvQsNGB0L3QvgriloHQvtC/0YjRgtC40L3QuAriloF0aXJlZAriloFCZXRoCuKWgdCw0LTQvNC40L3QuNGB0YLRgNCw0YLQuNCyCkxpCuKWgdCi0YPRgAriloFTY2FubmVyCuKWgVN0ZXJuCuKWgdCy0LzQtdGB0YLQtQriloFyZXBvcnRpbmcK4paBc3VsbArRhtC40LXQuQpiZXJ0cwpvZ29uYWwKxZFrCuKWgWlwc3VtCuKWgXNldWxlbWVudAriloFTZWl0ZW4Kd29yZHByZXNzCuKWgWZlYXR1cmluZwppc3Rpc2NoZW4KanViCuKWgcOpdHIK4paBdGVhCuKWgWFkYXB0ZWQK4paBc2NhbGVzCuKWgW5hbgpnZXRWYWx1ZQriloFCbHVlcwphY2xlcwriloFzdGF0aQriloFlbnRpdGxlZAriloFSYWxwaApncmF2aXR5CuKWgWVudHJlcHIKa3TDs2JlcgpsaW1hdApsaXMKRGVtbwpyZWxhdGlvbgriloFuZXAKcHJvd2FkCml0aXMK4paBcHVwCm5laG1lcgriloFkaXNhcHBvaW50CuKWgWV0d2FzCmFubm9uCuKWgWFwcHJvdmVkCuKWgWNsZXZlcgpMb2FkaW5nCuKWgXZlcnoKcmVzc2UK4paBaW5zcGlyCuKWgXNhbXBsaW5nCuKWgUJlawp9KSQuCuKWgdCz0YDQvtC80LAK4paBc3BlY2llCuKWgXJlcHViCuKWgWxvYWRlcgriloFlcmYK4paBc2hvdWxkZXIKcmFpcwriloHQvNCw0YLQtQriloFNb250aApTY2VuZQriloFibG9ja2luZwriloFvY2VhbgpnZWJlbgriloFLaWxvbWV0ZXIK4paBYmVkZXV0CuKWgU1peApmbXQK4paBTm9yd2VnCuKWgUlEcwpwYXJhbGxlbAriloFhbnRpY2lwCuKWgXJldmlzCtGF0LDQvQriloHRgdCy0LXRggpDQVNFCuKWgWbDvGhydAriloFhdG9taWMK4paBZGFya25lc3MK4paBRnXDn2JhbGxzcGllbGVyCuKWgdCW0LgKcXVpc2l0aW9uCuKWgVNpZWcKQ2lyYwriloFjaWVudMOtCm5lbGxlClNIQQriloF1cmIK4paBa3NpCmxlcXNsYW50CuKWgdGE0YDQvtC9CuKWgWRlZmVjdAriloFyw6EK4paBc3Ryb25nZXIK4paBcMWCCuKWgWNvbW11bml0aWVzCtC90LjQvdCwCmVuYXMKaWVubmVudAriloFzYWZlbHkK4paB0YLRjwriloFiZW5jaG1hcmsK4paBQnJhdW4KbWV0aG9kcwphcmd1bWVudAp2b3MKb2JveArRgNC+0LLQuAriloFyZWNoZXJjaGUKbW4K4paBYnJpbmdzCm1hY2hpbmUKQ0VTUwpob3N0cwriloFOWQpBdXRvdwriloHRgdC+0LLRgNC10LzQtdC9CuKWgUdhcnkK4paBc2Vuc29yCuKWgWRvY3VtZW50ZWQK4paBcHJlbmRyZQriloFwZWVyCmVuaXgKaGFpCmFyYmUK0YbQtdC90YIKXygK4paBVVJJCtC10LLQsAriloFSZWdpZQriloFNb251bWVudAriloFvbmRlcndlcnAKQmFnCnRpdAriloFzdGlyCuKWgW5lcnYK0YHRgtC+0YDRltGPCuKWgXNvdgriloF3cml0ZXJzCuKWgXNvcnRzCmFic29sdXRlCuKWgWRpZmZpY3VsdGllcwriloFwYXJsYW1lbnQK4paBSUVudW1lcmFibGUK4paBZGlzc29sCuKWgUNIRUNLCmFyaW5hCmluYnVyZ2gKRE0K4paBZWluZAriloFidWRnZXQK4paBY2VydGFpbnMK4paBZsO2cnN0YQphbmphCuKWgdCz0L7QtNC+0LIK4paB0YLQtdC6CuKWgUR1Y2gKZ3VpCuKWgVRlYW1zCuKWgdC80L3QvtCz0LgKTWFyaWUKSW50ZWdyClRocmVhZFBvb2wKcnVzdArDrWsKJSIKZW5mCnNwbAriloFiZWd1bgpsb3UK4paBUmV3cml0ZVJ1bGUKdHVwbGUKYW5lb3VzCuKWgW1hcmluZQphdHRhbgppa2FsCuKWgWdyYWR1YXRlZAppbGzDqQriloHQv9GA0L7QstC1CuKWgdCg0L7QtwonLA0K4paBUGZhcnIK4paBbml2ZWwK4paB0L/RgNCw0YbRjgptdXNpYwriloFzZXRUaW1lb3V0CkVSUwriloFFcmlrCnBpdAriloHQpdGA0L4K4paBcGnFggriloFwZXJpCtC00L7Qugp1c3p0CuKWgUJlYXIKQ2xhc3NOYW1lCuKWgVBhcmxhbWVudAriloFhaXgK4paBaW52aXRlZAriloFQQVRICnh0ZXIK4paBUmFjZQriloFoZWNobwriloFUb3dlcgriloF1dGYKYWN0bHkK4paB0LHRg9C00LUK4paBYW5nbGVzCtC90Y/RjwpvdXZlbGxlcwriloFjbGltYXRlCuKWgXNpbmdpbmcK4paBbmF2aWdhdGUKPic7CmFkb3dzCuKWgWxldGEK4paBU2l0egriloFwYXJ0aXRpb25zCuKWgWRvY2sK4paBxbx5CuKWgWFsbG9jYXRlCuKWgWJlbmVmaXRzCuKWgW5pZWRlcgp4cGF0aAptZWNrCsOkbGxlCuKWgWNvdXBsaW5nCtC20LjQuwpGb3JLZXkKYXJnZW50CmNsb3UK4paBaW5zdHJ1bWVudHMK4paBZW50aHVzCuKWgW3DqWcK4paB0J/QsNCyCuKWgVJhY2gKLS0tLS0K4paBQVBJcwriloFWaWVyCkNtZAppdG9yZQriloFDdWJhCuKWgWTDoXR1bW1hbAriloFlbWJlZGRpbmcKc3RkaW8K4paBR2lsYmVydAriloFnZXByw7xmdAriloFzdGF0aW5nCuKWgXRyaWdnZXJzCis9CuKWgXNww6ljaWFsCuKWgWRlbGliZXIK0LzQuNC9ClByb2R1CuKWgVN0YXRpCuKWgXp1cwprdGlvbmVuCkRpc3BhdGNoZXIKaWRhbAriloFMUApvcHRlcmEK4paBZXN0YXIK4paB0LfQvdCw0YfQuArRgdC80L4Kb3VzZXMKZW5nb25vCuKWgVdQRgpwdWJsaXNoCuKWgXRlb3IKZWxpZgriloFlcmcK4paBc2VwYXJhdGlvbgpQYW4K4paBT3JjaGVzdHJhClBldGVyCmJvdW5kcwriloFTaGFrZXNwZWFyZQriloFjYW50YW50ZQriloFkZW1pCuKWgVBvcHVsYXIK0YTRgAphcnJpbmcK0YbQuNC9CuKWgdCY0YEKdm9uCuKWgXN1YnN0aXR1dGlvbgriloFsw61uZWEKXH0kLgpjb21vCuKWgdCy0LDQtgp3YWdlbgriloFyYXJlbHkK4paBcGVyaW9kcwpnbG9iCuKWgUZyaWQK4paBVGVycgriloFSZWxlYXNlCkJyYWluegriloHQs9GA0LDRhApESVMKY29tcGF0aWJsZQriloFwb8SNCkxJTgriloFLw6RsbG9yCuKWgUFyaXpvbmEKcHB5ClNlcQriloFBaW4K4paBVG91cm4KYnJvdwriloFLw7ZyCuKWgWFzaApvZ2VuZW91cwriloFkaWFsZWN0CuKWgdC90LDRgdC10ZnQsApteXNxbGkK0YbQvtCyCuKWgWZsb3IK4paB0YTQu9C+CklBQgriloFXaXRoaW4KXigK4paBYm9pcwriloF0YW5rCuKWgWFmZmlsaQriloFoaWpvCuKWgUthdGUK4paBVmVybAriloFNaWFtaQriloF0eXBlc2NyaXB0CtGa0YMK4paBVmVybgriloHQstC40YHQvgppZW1hbm4K4paBY292ZXJhZ2UKYnJpZQriloFTdGFydGluZwpudW1weQriloFKZW5raW5zCuKWgWvDqXQK4paBZ3J1cAriloFTY2llbnQK4paBaW50ZXJydXB0CuKWgWJsb2IKdWdlbAriloFPcnRoCmFiYW1hCuKWgUJhcHQKb3duaWsK4paB0LHRi9GC0YwK4paBSnVsaXVzCuKWgdCf0YDQtdC3CuKWgXN1YnN0aXR1dGUKc3VwcG9ydGVkCmNoeQplZ3l6ZXRlawriloFQZXJmb3JtYW5jZQpsZXNzbHkKQ29uc3RydWN0b3IK4paBZXh0ZW5kaW5nCuKWgU11c2xpbQpPdmVyZmxvdwriloFKZW5uCuKWgXByb2R1egrQvNGW0ZcK4paBcGHDrXNlcwriloFldXgK4paBZmF0ZQpvbG9nZQrRg9C6CuKWgXdvYmVpCuKWgVNhY2hzZW4K4paB0YHQsNC50YIKTW9kZWxzCuKWgUZhc3QKYmVzb25kZXJlCuKWgUZSCuKWgWFjb24K4paBRGVua21hbAriloFhbmNoCuKWgXDDumJsaWNvCuKWgVRhcwriloFjYW5kCuKWgXBhxbpkemllcgriloHQnNC+0L0K4paBdmVyc3VzCnJ1dApHVAriloFpbnNlcnRpbmcK4paBY2FuYWQK0ZTQvAriloFNZXRybwriloFIZXJ6b2cKSWdub3JlCuKWgWRlY3JlYXNlCuKWgdC/0YPQvQriloFGaXNjaGVyCuKWgU1hbGwK4paBbsO2cmQKaW9zdHJlYW0K4paBTHV4ZW1iCnBheWxvYWQK4paBWmVpdHVuZwriloFtb2RpZnlpbmcK4paBQ2hlcgriloFMdWNpCm54CuKWgWxvb3NlCuKWgXRvcGljcwriloF2YXJpZWQK4paBcGcKYWplcwp1bW0KVmlld3MK4paBQmVhdQpNQVAKaXBlbGluZQriloFJbnRlcmVzdAphcml0aAriloFzZWfDum4K4paBR2VtZWlucwriloFBdHRyaWJ1dGUKY29tbXVuaXR5CuKWgdGG0LXQvdGC0YAK4paBa2lsb21ldGVyCuKWgcOpY29ub20KbGFyYXRpb24K4paB0LrRigriloFjYXJyaWFnZQriloFMYW5lCuKWgdC90LXQvtCxCmt1cgriloFBRgpJTlRFUgopKSQK4paBYmVpZGUKZGVzdGluYXRpb24K4paBZm9udHMKYXBwZW5kQ2hpbGQK4paBTUFSCuKWgWdheQptaWwKbGVzaArDqHQK4paBV2FuZwriloFZZWFycwriloFTeW1ib2wKTGl2ZQpxdWVuY3kK4paBVXNlcnMK4paBVW5pY29kZQriloFTYXUK4paBdG9ucwriloHQndGWCuKWgdC60YDQsNGXCkFYSQriloFQaWNrCkFJCuKWgWhhdGgK4paBYWluZGEK4paBcGFwYQriloFDZW5zbwriloFCYWxkCuKWgdCd0LDRgdC10ZnQtQriloFzaW11bGF0aW9ucwriloFqYXJlbgriloFpbmhlcml0ZWQK4paB0YLQvtC5CuKWgWZlZWxzCnJlc3Npb24K4paBb2t0w7NiZXIKYmlkCsOhc2kK4paBbXVzcwp2ZW50b3J5CuKWgW1laXN0CuKWgWJvcmUK4paBc2xpZGVyCtC00LXQu9C4Clw7CuKWgWV4dHJhY3RlZArQutGD0YAKRWRnZQriloFwZXJmCuKWgUJyaWdhZGUK4paB0LPRgNCw0LQKaWVuaWUK4paBTm9yZGVuCuKWgWNhbmNlcgoiLwpDdXIK4paB0KHQtdGA0LUK4paBbGlxdWlkCnN0cnVjdHVyZQriloFjaG9vc2luZwriloFQZXJsClNpZGUKw7xzCtGA0LjRgtC+0YAK4paBa29zdAriloFwYWNrZXRzCuKWgdC60L7RgtC+0YDQvtCz0L4K4paBQ29tdW4K4paBZmluZ2VycwpvZ3LDoWZpY2EKPjoK4paBY2hhbXBpb25uYXQK4paBYmxpZWIK4paBU2l0dQriloFzdWljCmFuZGlzCkZyZQriloFDb25jCuKWgXJlcHVibGljCuKWgWFybWVkCuKWgWhlbGwK4paBaMO2ZwpyYWdtYQriloFlbnNlCuKWgWFjcmVzCuKWgdCS0ZbQtAriloFSZWZvcm0KTWFpbkFjdGl2aXR5CmtlZXBlcgplcmIK4paBbW9uYXN0ZXIKc3Vic3Vic2VjdGlvbgriloHQlNC40LIK4paBY3JlYXR1cmUK4paBaW5kaWNhdGluZwriloF1cmxzCuKWgWtlaW4K0L7QsdGA0LDQtwpwaWNrCuKWgUFkbWlyCuKWgW9sZGVzdAriloFtdXoK4paBY29udHJhZGljdGlvbgriloFwcm9iYWJpbAppbGxpYW50CuKWgXBhdgriloFwYXBlbAp1YnMK4paB0LbQtdC90LAKQU1MCuKWgXJlY2lwCuKWgUNPTAphZGRlZAriloFjbHVlCuKWgVVrcmFpbmUK4paBamVsZW50CtGH0LXQvdGMCuKWgW1hdGhlbWF0aWNzCkFjY2VwdAriloHRgdC+0YIK4paB0YHQtdCy0LXRgAriloFpc29sYXRlZAriloHQv9C+0Y8Kd8O8cgpSb3V0ZXIKQ0FUCnJnYgriloFMb3YKbXV0YWJsZQriloFXZXMK4paBSXRhbGllbgpEcmFnCmVuaXVtCmF0dGluZwp0Y3AK4paBZXJmb2xndGUK4paBQmVpdArQs9Cw0YLQvgriloFTeXN0ZW1zCuKWgXJlc2VydmUKZXJlZQriloHQn9Cw0YDQuAriloHQt9Cw0LvQuAriloFyZW50CuKWgXN1bnQK4paBR2lybHMK4paBRXJuZXN0CuKWgWZpdHMK4paBb3Bwb24K4paB0LbQuNCy0LXQu9C+CuKWgWF2YWllbnQK4paBRmxvcmVuY2UK4paB0YfQuNGB0LvQtQriloFlbmdpbmVzCkR5bmFtaWMK4paBc3R5Y3puaWEK4paBYmlhcwriloFFeGNoYW5nZQrQtNC40LkK4paBaGlzdG9yaXF1ZXMK4paBSMOkCmhvZAriloF3xYIKc2NoYXAK4paBbGFjCuKWgUZvaQriloFkd2VsbAriloFVbnRlcm5laG1lbgpVUk4K4paBa2lsb21ldHJlcwriloHQntC00L3QsNC60L4K0LrQu9C4CuKWgVNyaQpHcm91cHMKbWluZApvc2xvdgpmZXJuCmVndQphYmVsZWQKRmlkZGxlCuKWgUNlbnR1cnkKLy0K4paBSmVneXpldGVrCkhlbgplbnNlbWJsZQriloFHdXQKX3t7XAriloFyYW5raW5nCiskCtCw0LvQsAriloEjewppbWllbnRvcwphY2hpbQpyaWRlcwriloFLbGF1cwriloFpbnRlbmQK4paBS2VudHVja3kKY2lwZQriloFEaWVuc3QK4paBc2l0dWF0ZWQK4paBcMOzxboK4paBc2NyaXQKY2xpcArQvdC10YIKdGFibGVzCuKWgU5pZWQK4paBTWNLCuKWgXBvd3N0CuKWgWt1bm5lbgriloFFdmFucwrQttC00YsK0LLQsNGC0YwKdWNoYXIK4paBcmVzaWRlbnRzCmlhawriloFSZXNvbAriloF2ZWNlcwriloFzYXRpc2Z5aW5nCklORgriloHRgdC40L0K4paBY3Jvc3NpbmcKaWJlbgriloHRiNC40YDQvgpwdG8KSUxMCuKWgdGA0L7Qu9GMCuKWgWFrdGl2CuKWgdC+0LHRgNCw0YnQtdC90LjRjwpXaWtpc3BlY2llcwriloFIw7ZoZQpjcm8K4pWQ4pWQ4pWQ4pWQCmFsdHJhCuKWgUZJTEUK4paBdXBzCuKWgWFsbG9jYXRpb24KTWljaGFlbAriloFhY2tub3dsZWQKTGludXgK4paBbWV0cm9zCnR0ZQphZmVuCuKWgXhjb2RlCuKWgdGC0YDQsNC00LgKc3BlY2llcwriloFpbmp1cnkK4paB0YHQsNC80YsK4paBbGF0dGljZQpNYXRlcmlhbAphbmRlbmJ1cmcK4paBaHV2dWRzdGFkZW4Kc3RvcnkK4paBdmFyeWluZwriloFrw7Z2ZXQK4paB0KDQvtGB0YHQuNC50YHQutC+0LkKaXJzZQriloFkcnVtClByZXNzZWQKTGFyCuKWgUFndQriloF3ZWlsCuKWgWNvbW1lbmNlCuKWgVNlZ8O6bgpHZXN0dXJlClNoYXBlCuKWgVZvcnMK4paBc3VjY8OocwriloFjb3JyZWN0ZWQKS2FyCuKWgWNydWVsCuKWgXBvbGl0aWNvCuKWgVNjaHJpZnRzdGVsbGVyCuKWgXJpc3VsdApldHUKYXJjaGl2CuKWgWfDqW5lcm8K4paBTMO8CuKWgXRyaXVtcGgKT1JTCkx1CuKWgXBlcnNvbm5lbAriloFIaWxscwphc3NldApkb21pbgpSZWNlaXZlCuKWgU9hawriloFLbm8K4paBVGhlb3J5CmlyaWUKb3dhbgriloFlc3RhdmEK4paBZXhlY3V0ZXMK0LnRggrDs3BlegrQv9C+0LvQvgrDqXRpY2EK4paB0L3QsNC30LLQsNC90LjQtQriloFjb252ZXJnZXMK4paBbm90cmUK4paBcG9wdWxhdGVkCuKWgW1vdmVtZW50cwriloFzdGF0aXN0aWNhbAriloFad2VpdGVuCnF1aW4K4paBaW1wb3J0YW50ZXMK4paBa2xlaW4K4paBU2VndW5kYQpzY2hsaWXDn2VuZApGYWlsdXJlCm5hcgpkYWcK4paBcnVvbG8K4paBZmljdGlvbgriloHQuNGB0L/QvtC70YzQt9GDCuKWgWNyaXNpcwriloFHZXR0aW5nCiwlCuKWgdCw0YDQvNC40LgK4paBY2FtcHVzCuKWgWZvb3RlcgriloFkw61hcwrQsdCw0L0K4paBbGliZXJ0eQriloFnaAriloFjaGFtYmVyCuKWgWRpc3RyaWN0cwriloFleGNpdGVkCuKWgWNhbmNpw7NuCnRlcm8K4paBV29ya2luZwriloFjesSZxZtjaQrQu9GM0L3Ri9C5CuKWgWZvcnVtCuKWgUVoZQriloHQutCw0YLQsAppdGF0aW9ucwpUb29scwphY2hpdgriloFjcmVzCmFzdG8K4paBcmV2ZXIK4paBbmF6aW9uYWxlCuKWgWRvb3JzCuKWgU5hbmN5CuKWgWlzbGFuZHMKSW1wCuKWgUNoYWlyCuKWgXZvcm0Kc2VpbgriloHQtNC+0LrRgwplcnNldAriloF0w6R0aWcK4paBS3JpdAriloHQv9GPCuKWgWNvbnNlcnZhdGlvbgriloFQYXJ0aWRvCm1pbmlwYWdlClZhbGlkYXRvcgriloFyZWNvdmVyeQriloFOQVNBCuKWgWJyZWFzdAppbHR5CmFuYWx5CmVsaW5lcwriloFTYXR1cmRheQplbWFyawpjZWoKWmVybwriloFUdXJuZXIKc2VjdXJlCkV4aXN0cwriloFSaWNrCmV2YWx1CmN0cmwK4paBY29tcHJlc3Npb24K4paBQ1VSTAp0ZXh0Y29sb3IKKVwsCmxvbmdyaWdodGFycm93CuKWgUZlcm5zZWgKaWNoYQriloFsb2kK4paB0J7RgtC1CuKWgWNhdmUK4paBZG96ZW4K4paBZXhwbGFpbmluZwriloFpbm5vdgriloFOaWNob2xhcwriloFkaWFtZXRlcgriloFNYXJpYW4K4paBZmlyZXMK4paBYXJ0aWZhY3QK4paBUGFya2VyCuKWgUJ1bmQK4paBdmVydGUK4paBdGFsZW50CuKWgUx1Y2FzCnJldmVyc2UK4paBZm9sZ2VuZGVuCuKWgVNhaApqZWN0aW9ucwriloFpbnZlY2UK4paBY29zdGl0dQriloFzc2wKfX1eCuKWgXZpb2xlbnQK4paBc3BvcwpSb3V0CmpkawriloHQt9Cw0LzQtQriloFmdXJlbnQKYW5kYWwKSG9tCuKWgVNlbmlvcgriloFwb3VuZHMK4paBRGlzY29ncwriloHQt9C1Cid9WwriloFOYXBvbGVvbgpvcmRpbmF0ZXMKw6BuCuKWgWt1cnoK4paBdmVyZQriloFyZXVzZQriloHQk9C10L0K4paBU3lzdAriloFkaXNhcHBlYXJlZAriloFXYXRjaApiaWJsaW90aGVrCuKWgdC60L7RgNC/0YMK4paBQ3MK4paBfWAK4paBcsO2cgriloHQtNC10LvQsApWQgriloFjYWxjdWx1cwrRgNC+0LTQsAriloFqdWRnbWVudAphdGlsZQriloFsb25ndWUK4paBSHVzCkphYwp9fSkKUklQVApJQUJvdAriloFhcMOzcwriloFhc3RvbgpXZWJhY2hpdgriloFVUkxzCuKWgWNvYXQK4paB0Y3QutC+0L3QvgriloFsZWFyCmV4dGVuc2lvbnMK4paBQ2xhc3NpYwpUSQriloFUYWdlCuKWgWzDoQriloFzZW1iCuKWgWTDqXZlbG9wcGVtZW50CklTVFMK4paBc29sdmVzCixcLAriloHRh9C10LzQv9GWCm9yZGluYXJ5CuKWgUJhdgriloFtdWNob3MKU2VsZgriloHQnNCw0LkK4paBRGlldAriloFuZWNlc3NpdHkK0LLRltC0CuKWgW1hbm8K4paB0KHRgAriloFjYXJyZQriloFDYW1lcmEK4paBTmFyb2QK4paBUGhvbmUK4paBcG9seW0KaW1vcmUKaXNFbXB0eQriloFIb3VzdG9uCuKWgVJlY2UK4paBcHJlc2VudGF0aW9uCtC90LjRhtC40L/QsAriloFEYgriloFjb25maWRlbnQK4paBfXsK4paBYnVsbGV0CuKWgXt9LApBTkdFCuKWgU5vdHJlCmNoaW4K4paBRHJhZ29uCmVyY2EKaWFsaQriloFhc3NldAriloFtdWl0bwriloFkZWVwbHkK4paBcmVzdHJpY3Rpb24K4paBY29tbWVyY2UK4paBQm9tYgpjYXVnaHQKcXEK4paBQXJhZwriloHQvdC10LzQtdGGCuKWgUFuYWx5c2lzCuKWgcSNbMOhbmt1CuKWgWJhYnkK4paBZWNodGVyCuKWgdC+0LTQvdC+0LPQvgrQttC10L3QsAriloF3aGl0ZXNwYWNlCsOndQpMSVNUCmZyaXF1ZQriloF2YXJpYXMK4paBV2l0CuKWgUxpY2VuY2lhCkV4aXQK4paBc2llcnAK4paBYXNzZW1iCuKWgXNwbGl0dGluZwriloFwYWxhY2UK4paBYmxvY2tlZAriloFib3VuZGFyaWVzCuKWgWl0ZXJhdGlvbnMK4paBUm90dGVuCuKWgVZlcmtlaHIK4paBd2VlcgpUZXN0cwppZnRpbmcK4paBcmVndWwK4paBcGVyc2lzdAriloFTb2x1dGlvbgpwYgriloFjb2xsYXBzZQriloFhcnJlc3RlZAriloFwcmVkaWNhdGUK4paBWm9uZQriloFpbmdlbgp6w6FsZXoK4paBYmFua3MKcGxhbnQK4paBTmVsbGEK4paB0LHQsNC9CuKWgVNub3cK4paBS3JldXoKw61jaW8K4paBZW50ZXJzCuKWgWV4cG9zZQrEjWkK0YjQuNC1ClF1YWwK4paBbGFuZHNjYXBlCuKWgdC/0L7QtNCw0YbQuNC80LAKbWFpCnN0YWcK0L7QstCw0L3QuNC5CkRFRgpbXXsK4paBZGVybmnDqHJlCmljdXQK4paBWG1sCuKWgXN1Ymdyb3VwCuKWgVBvbHNjZQriloFXYXJuaW5nCuKWgXZlaGljbGVzCmlvdAriloFkbGwKcm9udAriloFMb3Vpc2UK4paBYXJhCuKWgVNjYWxhCuKWgWNhbm9uaWNhbAriloFwbGFjaW5nCkVSWQriloFKYWcK4paBdmlydXMKZW11CuKWgX0pOw0K4paB0LzQvAriloFUcnlpbmcK4paBTGV4aWtvbgphYm9yZAriloFleHBlZGl0aW9uCuKWgWRlbWFuZGVkClp5ZwpsZWluCuKWgXZlcndlbmRldArRgNC40L3QsAp3b2wK4paBcGl2b3QK4paB0L7QtNC90LDQutC+CuKWgXByb3ByaWV0CuKWgWF3YXJkcwp0b3V0CuKWgWFzc2ltCuKWgVN0b3JtCkxpbWl0CmVsaW4Kd2VhbHRoCnVlegriloFyYXBwcmVzZW50CuKWgXJlc3RhCuKWgWdlZ3LDvG5kZXQK4paBam91cm5hbGlzdAppc2llCuKWgWZhY2lsaXR5CmlsbGVkCnVsawriloFQSwpBbmNob3IK4paBXykKVkYKTEFCCuKWgW7DpQpvZG9zCuKWgWJpbGxpb24KdmlydGkK4paBSmV1eArRjtC30LAKdG9tY2F0CuKWgWNoYXJ0cwriloFCdW5kbGUK4paBbHN0CuKWgWV4ZXIK4paBZmVtYWxlcwriloFvYmxpZ2VkCuKWgWFieQpyb2xsZWQKZHJpCuKWgVNjaGUK4paBdmVzc2VscwpJTUFSWQriloFyZWFzb25pbmcK4paB0L/RgNC+0YLQtQpGSUxFUwp2ZXJrCm9zb3MK4paB0LrQvtC80LzRgwrQtNGW0ZcK4paBZGQK4paB0YHQvtC+0YLQstC10YIK4paBSU9FeGNlcHRpb24Kc2vDvWNoCuKWgUNMSQriloHRmtC1CkNNClRECuKWgXBvc3NpYmlsaXRpZXMK4paBQ29tcG9zCmhhbGYK4paBd2VicGFnZQriloFzd2luZwriloF6YXMK4paBY3ljbApsZWlkCmlzdGljYQriloFJbnNlcnQK4paBU3dlZGVuCuKWgXdhbnRpbmcK4paB2KfZhAriloFlZXV3CuKWgUFkbWluaXN0cgriloFXYXJyZW4K4paBYnMK4paBcGFtCmFudXMKRHJhCmV4cGwK4paBS2FudAriloFBdXN0aW4K4paBY3NhawriloF0aGVhdHJlCuKWgWNvbXBhdGliaWxpdHkK0LzQsNGC0LjRh9C1CnNldFN0YXRlCtCx0Y4KfXt8CuKWgUR5CuKWgVp3aXNjaGVuCkFsdApDTEFSRQpzdGVwcwriloFMYWdlCuKWgU1pdHQK4paBRHVibGluCuKWgdGA0LDQsdC+0YLRiwpkZWVwCuKWgWZsb3dzCuKWgVBhbGFjZQp1bml4CnJlZnMKdW1hcgphc2V0CmNvdgriloFwaW5nCuKWgVNhZmFyaQpmbHVnCmNyZWVucwp7IwriloHRgNC10LAKYWRvcnMK4paBYW1vcgp1Y2UKZGVtaWMK4paBTmV0aGVybGFuZHMK4paBY2x1c3RlcnMK4paBZW5mb3IKbWFyaW5lCuKWgWJ1Z3MKaXp6YXRhCuKWgXNjcmEKTGVzCnF1aWNrCuKWgXR1cm5vCl8qCtC10YDQsApHZW5lcmF0ZWQKPlsK4paBZXN0cmUKb3JkZQriloF2ZXJnCtGA0L7QtwriloFwYXUKaW5jbHVkZXMKYXNzYQphZGVycwriloHQk9C10YDQvNCwCuKWgWVzdGF2ZW4K4paBZWFybGllc3QK4paBcmVzdWx0YWRvCm11bgriloFwbG90cwpkaW4Kc29ydGVkCuKWgXByZWZlcmVuY2UKcmnDswrRgtGD0YDQtQriloFMaWd1ZQriloHQt9Cw0LLQtdGACnBocgriloFwb2NrZXQK4paBcGFybAriloFsYWsK4paBcG93aWUK4paBYWx0cmVzCiR9OwpwbGFpbgriloFDcmVkCml0emEKcGVycApHcmVlbgriloFkZXZvdGVkCnByb2R1Y3Rpb24Kd29ya2VyCmVsc2VuCuKWgXZlcm4K4paBbcOhcmNpdXMK4paBQ29uZmVkZXIK4paBTGl2ZXJwb29sCuKWgdC80YPQt9C4CuKWgWVtYWlscwriloFkaXN0YW5jZXMK4paBc2VnbWVudHMK4paBYW50aAriloF3cmVzdAriloFob29nCuKWgWNpbmVtYQpycm9yCuKWgWdlYm9yZW4K4paBw6ljCk1hcmtlcgriloFDb21wZXQK4paB0LvQuNGB0YLQvgphbGxvd2VkCnZvbHVtZQpFc3BhZ25lClplCuKWgWZpeGVzCuKWgXJvbmQK4paBYXJyYW5nZW1lbnQKL34KLl0oCuKWgUZvcnLDoXNvawriloF3ZWl0ZXJlbgpleGNlbAriloHQt9C80ZYK4paBbW9kZXJuZQpFbmdsaXNoCuKWgVRyYW5zZmVybWFya3QK4paBYmVhcmluZwriloFjbGVhcmVkCuKWgdGB0LDQvAriloFkaXZzCsSHaQriloHRjdGC0L7QuQriloHQk9C10L7RgApzY2VuZQriloFhZ2VzCkdFTgpyw6RuCuKWgVRvdWwK4paBQWJzCmrDoXQK4paBbWVkaWFudGUK4paBZW1wcmVzCuKWgUVtcGxveWVlCuKWgXBvbHlub21pYWxzCuKWgW9wdGltaXplCuKWgdCy0YvRgdGC0YPQv9CwCmZhcmUK0LLQtdC5CnhmCnF1ZXoK4paBYm90YW4K4paBZGVmZW5kCuKWgVF1YXJ0Ck1vbnQKdmIKdGljawpXRAptaW5lCuKWgW1vZGlmaWMKbm90aWZpY2F0aW9uCuKWgWRlbm4K4paBYWxnbwriloFTcG8K4paBbWlzdHJ6b3N0Ci86CuKWgWFwcmVzZW50CuKWgdC/0YDQvtC0ClZvbHVtZQpza8SFCnByb3RlY3RlZAriloFUdXJraXNoCmF6eQriloFwb3V2CuKWgXBlcsOtb2RvCnNrb2cK4paBZW50cm9weQp6ZWQK0YLQvtGA0LgK4paBbGlqCmJvYXJkcwriloHRgdGC0LDRgtGDCkJvb2wK4paBcG9saXR5CkAiLAriloHRgNGW0LoKbsOpZQriloFadWcK4paBVW5pdGkKw6ltZXQKYXRpZW5jZQpkaW1lbgriloFTdGV2ZW4KSGEKQUNUSU9OCuKWgXdhbmQK4paBTmF2YXIK4paB0YHRltGH0L3RjwpXYXRjaAriloFTdHVhcnQK4paBemRlCuKWgdC60L7QvdGC0YDQvgpkYXRhc2V0CnnDswriloFCdXNoCuKWgdGB0LXQsdGPCuKWgXdvcnRoeQriloFCbGUK4paBcHJvcG9yCuKWgVZpbGxhZ2UK4paBcnkK4paBdm9pdAriloHQutC+0L/QuNGPCuKWgXpwCuKWgWN1cmEK4paBSHRtbAriloFEaWVzZXIK4paBRGF5cwpvbm5lcwriloFhbnRpZ3UK4paBU3RhYXRlbgriloFmYWludApvbmdzCuKWgcO2c3QKUmVkaXJlY3QK0LXQu9GMCmF0b3JpYWwK4paBYm90aGVyCkVkaXRUZXh0CuKWgUdpdWwK4paB0LfQsNCy0L4K4paBcHVlYmxvCuKWgU1pc3Npc3NpcHBpCmphawriloF3aW5ncwpvbmMKw612ZWwKaWVuY2lhCmVudGxpY2h0CuKWgUJUVwpvcm5hbAriloHQmtC+0YDQvgriloHQvtC00L3QuNC8CuKWgXNhbHYK4paBZmluZGVuCmdlbwriloHQsNCy0LjQsAphdHR1bmcKdml2CuKWgUx1dGhlcgriloHQvtCx0YnQuAriloFSb2xsZQriloFBYnJhaGFtCuKWgWNlbnRlcmVkCuKWgXNsYXNoCmlzYXQKZW1hbm4KT3MK0L/QsNGA0YLQsAriloFQYWJsbwriloFjb2xsYWJvcmF0aW9uCnBhdGhzCsOpZGl0aW9uCuKWgXZpZXdlZAriloFjb25zaXN0ZWQK4paBcmVjb3ZlcmVkCuKWgU1leGljYW4K4paBRml4CuKWgXNwZWxsClNwZWNpYWwK4paB0KHRggplc3NldXIK4paB0KPQutGA0LDQuNC90YsKZm9ybWVyCuKWgcWbdwriloF6ZXJvcwriloFTdHJhw59lbgriloFvcmdhbmlzYXRpb24Kw7xzc2VuCuKWgVNpZXJyYQriloFTZWFzb24K4paBdm9sb250CkJlYW5GYWN0b3J5CuKWgdC/0L7QvNC+0YkK4paBcHJlc3NpbmcK4paBZXF1aXZhbGVuY2UK4paBY2F0dAppY2l0eQriloFhY2NvbXBsaXNoZWQK4paBeW8K4paBc2ljCuKWgWltcG9ydHMK4paBYWNjb21tb2QK4paBUG9ydG8K4paB0Y/QutCwCuKWgWxvYW4K0YLQuNC60LgK4paBY2hlY2tvdXQK4paBYXNzZXNzCuKWgVBvcHVsYXRpb24KdXJlbnQKY2xvanVyZQriloFTYW50b3MK4paBaW5mb3Jtw6FjacOzClBPUwriloFnYXJlCuKWgWtpY2sK4paBcmFkaWNhbAriloFQZWFjZQriloFzdHJlYW1pbmcKY2FtcAp6xIV0CtCz0L7QstC+0YAK4paBUmVnaWVydW5nCuKWgXByb2NlZWRlZApmbQrQu9C10L3RiwriloFlYXJuZXN0CuKWgVBhcmFkCnJlcXVlc3RzCuKWgVJhdW0KxaHEjQriloFwb2xpY2llcwriloFUaWcK4paBc2l0dAriloFFbmVyZ3kK4paBcHVyZWx5CuKWgUhhdXQK4paBU3BlZWQKYmlvCuKWgW9yYW5nZQriloFiaWdnZXN0CuKWgWJyaXRhbm5pcXVlCuKWgU5vdGFibGUKdnUK0LvQtdC90LjQuArQsdC40L0K4paBTmFzaArRidC10L3QuNC1CuKWgWNpZWwKYWTDqW1pZQriloHQs9GA0YPQtNC90Y8K4paBam91ZQriloF2b3RlZApyaWNvCuKWgdCz0L7RgAriloHQutC+0LzQsNC90LTRgwppdGl2aXR5CuKWgdGJ0LUK4paBZGVmaW5pdGUKdXJvcGEKISIpOwpEZWZhdWx0cwriloHQvdC10LrQvtGC0L7RgNGLCsOpZMOpcmF0aW9uCuKWgXNpbGx5CuKWgXRhbGtlZApyZXUK4paBTG9tYgriloFzdGF0dWUK0LrRgtCwCtGO0YAKdW1hYmx5CuKWgdCz0L7RgNC+0LTQtQriloFSdW50aW1lCuKWgWRpYWduCuKWgXJldHJvCuKWgVN2ZXJpZ2UK4paBaW5pY2lhbAppZW56YQriloFmaWdsaW8K4paBem9nCuKWgXJleQriloFSdW5kCtGC0L3Ri9C5CuKWgWNlYXNlZAplcm5vCuKWgWVzYQriloF0cm91dgriloFHZW1laW5kZW4K4paBY29tZXJjaWFsCnNrYXAKZW5hcmlvCuKWgWp1cmlzClRCCtC90LDQu9CwCuKWgXZpagpWTwriloFjbGluCmrDtnIK0YHQsNC9Cm93YcWCYQpyaWJ1Y2nDs24K4paBdXJzcHLDvG5nCuKWgWNvbmRlbQriloFTdGFnZQriloFtaXhpbmcK4paB0YDRltC3CuKWgWZhbnMKaMOhegpzb2NpYWwKemFuCuKWgdGB0LLQvtC5CkNvb2tpZQriloFSb2xhbmQKYXppb25hbGUK4paBU2xvdmVuCuKWgUZpY2hlCuKWgVPDqQpow6QK4paBb2ZmaWNpYWxzCuKWgcOubnQKSW50ZXJjZXB0b3IKVGFibGVzCuKWgWRhdm9uCmluaXRpYWxpemUKXT0iCuKWgUJvZHkK4paBVXBwZXIK4paBQ29sbGVjdAriloFaw7xyaWNoCkhvcml6b250YWwKVHlwCuKWgXBvbMOtdGljbwriloFSZXdyaXRlQ29uZAriloFob3BlZAriloFhbnhpb3VzCkxpdGVyCmphaHIK4paBYXNzZW1ibGUK4paBY3J5cHQKbGFob21hCkFTSAriloHQkdGA0LgK4paBQ2ljCnR3aXR0ZXIKaHlwZXIK4paBVGVsbArRltC70YzQutC4CtCy0L7QsdC+CuKWgWJhemllCuKWgWNvbnRlbXBvcmFyeQriloFQYXJhbWV0ZXIKc3R3YQriloFiZWtlbmQKY29jawpwcmV2aW91cwplbnNrYQriloFjYWxsZXIKXV0pCuKWgVJhegriloFTZWxvbgriloFwcm9wb3NhbAriloFiw70K4paBU2llZAriloFBcmJlaXRzCuKWgXByaWRlCuKWgXNsb3BlCmlkw6kKZ3JhZGllbnQK4paB0JTQttC10YDQtdC70LAK4paBU0gK4paB0YDQsNC30YDQsNCx0L4KaXZlcnNpdHkK0YHQv9C+0LTQsNGAClx7XAriloHRgdGC0LDQu9C4CuKWgUVpbnplbAriloFyZ2JhCuKWgUFuaW0K4paBYWxsZXMK0LHQsNGACmVydGUK4paBcsOpYWxpc8OpCkluc3RpdHV0CuKWgW1hcmt1cAriloF2YXJzCuKWgWdhbQriloHQktCw0YHQuNC70YwKaXp6YQriloFDb2IK4paBTWV0YWwK4paBbGVhawriloFMYW5jClN3aXRjaApEZWxheQphdHV1cgriloHRh9C10YLRiwriloHQsNC90LPQu9C40LkK4paBbGVnYWN5CuKWgWRlc2Fycm9sbAriloF0b3BvbG9naWNhbAriloFqZXdlaWxzCuKWgU5lZGVybGFuZHNlCuKWgWF0bW9zcGhlcmUKdXJiYW4K4paBc2xvdgriloFsYXd5ZXIKcGVjaWFsbHkK4paBYWx0ZXJuYXRlCuKWgXBhcmFtZXQK4paBZXN0YWJsaXNobWVudAriloF3b29kcwpQRAriloHQvdCw0LgK4paBbWFuZwriloF3ZWNoc2VsdGUK0YHRjNC60YMKLj0K4paBZmlmdGVlbgpTVU0K4paBRnJvCuKWgUxFRApvd2FubwrRgdGC0LLQuNC1CuKWgURvbm7DqWVzCnRvbArFvHluCmNyZWYK0YHRgtCy0LjQuApob3JuCuKWgdGB0L7QvtCxCuKWgdC+0LHQvtGA0L4K4paBQ29tcGxldGUK4oCcKQriloFraW5kbHkK4paBQ2hhbWJlcgpzw6lnCldICuKWgWFtYmllbnQK0LrRgNC+CuKWgWNoZXZhbAriloHQvdCw0L/QuNGB0LAKZmx1CuKWgU9mZml6Cm1hdGUKbmF0dXJhbApzZXBhcgplbXByZQpWaWV3SG9sZGVyCmZ3CuKWgWxldGVjaAriloF0cmFpbGluZwphdHJpCuKWgUfDswriloFCb25uCuKWgXVubGlrZWx5ClJBTQplbnN0ClN0YXRzCuKWgdC/0L7Qu9C40YLQuNGH0LUKKS0tKAriloF0cm9tCiEuLi4K4paBTWVhbndoaWxlCtGB0YLQsNC90LAK4paBUmVpbm8K4paBQXJpc3QKJH19JQriloFzb2xlbQpjbG9zdXJlCmlnbmF0aW9uCsWCb2QK4paBZGl2b3IK4paB0LzQtdC20LTRg9C90LDRgNC+0LQKPSI8PwriloFtb2x0CuKWgXNraWxscwriloFDaXIK4paBRGVzcHXDqXMK4paBbHVuCuKWgWNvcm9uCuKWgUNvbWljcwrRgdGC0L7RgNC4CuKWgUl0ZW1zCuKWgVRoaW5rCtC40LPRgNCwCuKWgWdyb3dzCnBvcnRhbAriloFuaWNoCuKWgXJlc3RyaWN0aW9ucwriloFMYXUK0YjQtdC90L3RjwriloFTb3ppYWwK4paB0LrRlgptYW5hCuKWgWxpZXV0ZW5hbnQKQXR0cgp1bWVyaWMK4paBZHJpdmVzCmFzaXMK0LHQsNC5Ck5MClp5Z290ZQpwaHlzaWNzCuKWgWludGVybmFsbHkK0LLQsNC10YLRgdGPCkhpZGRlbgriloHQlNCw0YLQsAriloF1bnNhZmUK4paBUm9jCuKWgWluc3RhbnRpYXRlCnVkbmkK4paBUm9vbQriloHQn9GA0LXQtAriloFtYWphCmFjaG1lbnQKdXVpZApQcm9qZWN0cwpHcmUK4paB0LLQt9GPCuKWgUJsb29kCmljaWxlCuKWgU5vdXZlbGxlCkRvZXMK4paBbmlldXdlCsOhbGUKYW5ncwp3ZWFrCuKWgWFhbnRhbAriloHQldCyCuKWgURyZXNkZW4K4paBTG9zdArQutCw0YLQsAriloFpbnZvbHZlCuKWgWRlY2xhcmluZwriloFQb2xpdGljYWwKw6lyZXoKa29wCm5vdGlmeQriloFDdXJ0CuKWgXNjaGxpZcOfbGljaApnaGFuCtGG0LXQvdCwCuKWgWt3aWV0CsO8Z2VsCuKWgVNvYgriloFzdWJzdHIK4paBZWxsZW4KaW9uYXJpbwplbnNvbgpXSU4K0YHQv9C+0YDRggplbWVyCm5vbWUK4paBc21pbGVkCuKWgVNjaG1pZHQK4paBc21va2UK4paBVG9rZW4K4paBdmFndWUK4paBcHJvdmlzaW9uCnlhbWwK0L3QuNGC0LXQu9GMCm9uaWFsCsOpcG9xdWUK4paBTkMK4paBTkZMCnRlY2sK4paBYWxsbwriloFwcsOpY8OpZApjZW50cmFsCuKWgW1hamQK4paBY2hyb20K4paBWnVtCnZlcnNvCuKWgXZlcnNjaGllZGVuZW4K4paB0YHRgtCw0YDQvgriloFxdWVsbGUK4paBcsOpcApST1cK4paBaWhuZW4K4paBc2Vuc2libGUKfCQK4paBc2NodwriloFCUgriloFPcHRpb25zCuKWgXRlbnMK4paBY29ucXVpc3QK4paBbGllw58Kb3ZpcwriloHQvNGW0YHRgtCwCuKWgWVsYQpyaWZpY2UK4paBbG9rCuKWgVF1ZWVuc2xhbmQKQmluYXJ5CuKWgVJhaG1lbgriloFhYm9sCuKWgcSNw6FzdAriloFFZGluYnVyZ2gKaW5kZQriloFjYWxjdWxhdGluZwriloFPcmVnb24K4paBbGVnaXQK4paBTmFjaGRlbQphdGhvbgpQcml2YXRlCmlsbGF1bWUK4paBb2JzZXJ2YWJsZQpsZWFucwriloFyZW1hcmtlZAriloFoYWx0CtC90LjRhtGLCuKWgXN0YW1wCuKWgUFkdgpMb3VpcwppbW1pbmcKZ3J1cHBlCuKWgVBvbGljeQriloF2cmlqCmZ0cmFnCuKWgW9mZmljZXMK4paBcGFydGljaXBhdGVkCuKWgWVzY29sCuKWgSI8LwriloFub21icmV1c2VzCuKWgWRpdmlkCuKWgWFkdmlzCtC70YLQsNGC0LgK4paBPT0+Ck9yaWVudGF0aW9uCmNpZApDYXJ0CuKWgW11cm0K4paBYXNzZXoK4paBbGlua2luZwpidWlsZGluZwriloFyZWNvbm5hCuKWgXNob29rCm1hbmFnZWQKbGFuZGEK4paBTGXDs24K4paBY3LDqWF0aW9uCtC00L7QuQpvY2l0eQriloF3aWoK4paBd2llxZsKeHRhcnQK4paBTW92ZQpsdW5nZW4K0YHRgtCy0YPQtdGCCm9ybmV5Cm9wdGlvbmFsCm1hY3JvCkNvbmRpdGlvbgriloFzcXVhcmVzCuKWgW1pc3Rha2VuCsOhbnQK4paBUmlzCuKWgXNlbnRlbmNlcwplcmVhCuKWgW1pagpVbmQK4paBbm9tYnIKekEK4paBSW5kZXBlbmRlbnQK4paBcHJldmlldwppbWFzCuKWgW1hbGVzCmluZW50YWwKVGhhbmsK4paBcG9wb2wK4paBcG92ZXIK4paBZ3Jhc3AK4paBaW1wZWQK4paBY2FtcGlvbmF0bwriloFXZWkK4paBdGl0bGVkCuKWgUFkZW3DoXMK4paBUGFzc3dvcmQK4paBUGFtClVJTEQK4paB0LvQuNC/0L3Rjwp3ZXJiCi4uLi4uLi4uLi4uLi4uLi4K4paBUsOtbwriloF0ZWV0aApicAriloFTVwp1bGFpcmUK4paBc2VpemVkCuKWgVN0ZWYKw7psCuKWgXZpegppb255CuKWgWp1bnQK4paBa3RlcsOhCuKWgXdyemXFm25pYQo8PgriloFzdXJnCuKWgXR1dHRlCuKWgUhvYgrQv9C+0LLRltC0CuKWgXdvaGwK4paBdHJhZwriloFDcm93bgriloF0cm92YQrRgdGC0L7QstGDCuKWgVZpZW5uYQplc2VoZW4K4paBbWV0cm9wb2wK4paBcmVmbGVjdGVkCtGC0LXRgtCwCuKWgXRyYWR1YwriloFCYXN0CuKWgWVyc2NoaWVuCndvb3JkCigpIgp0YWxldAriloFyb2FkcwrQstC10LTQtdC90LjRjwrDvGhydW5nCuKWgWNvZ24K4paBVmFsbGUK4paBbGFuZGluZwriloFSZWdleAriloFJb3dhCmR6aWHFggriloFlcnJlaWNodGUKYXVtCuKWgWZvdW5kZXIKYXBvbGlzCkNvbXBpbGVyCuKWgWtvcAriloFtYXJjCuKWgdGC0LXRgNC40YLQvtGACikpYAriloFsZWkKZ2VvbgriloF3ZWFwb25zCuKWgWhvcm4K4paBZWxpZgriloFDYXBpdGFsCsSHZQriloFmb3JhbGwK4paB0Y3RgtCwCnByZXZpZXcK4paBRE5BCuKWgXNpZApvcmNoCuKWgVJhcwriloFhcmFiCkJlc3QK4paB0YHRh9C40YLQsAriloFMw7NwZXoKYW7Dp2EK4paBZnVua2MK4paBdGllbmVuCjsmCm11c2V1bQriloFFcnIK4paBcmVzb3J0Ck5vdgriloFrYWwKTVcK0YjRjAphbmNob3IK4paB0YDQvtC80LDQvQpsZWFkaW5nCuKWgW1hbnRlbgriloFTaWx2YQpkYWRlCuKWgWRlc2lnbmF0ZWQK4paBcmV2aXN0YQpPY3QKcGVyY2VudAriloHRg9C90ZYKaWRlbnRpZmllcgptYXNzCkBACnVsc2lvbgpnZXJtZWlzdGVyCuKWgXByZWRpY3RlZAriloHRgdCy0LgK0LbQvdC+0LkK4paBRXJnZWIK4paBY3VzdAriloFyZW1vdmVzCmNoYXJnCtC/0YDQuNC80LXRgAriloFmb3JtaW5nCmFzbWEKc3Rkb3V0CkZ1bgp5bWUKdGVyZWQKdXJzaXZlCmlnaGVkCuKWgdGB0LvQtdC0CnZlcmJhbmQK4paBTE9HCnJhbXMKw6lvbgplbmRyYQriloFCZXJlaWNoCuKWgXRlbXBvcmFsCuKWgWxhbmd1ZQriloFJbm4K4paBbW9yZW92ZXIK4paBdHV0b3JpYWxzCk1pZGRsZQriloHRgdC+0LLQtdGC0YHQutC40LkK4paBbWFpbnRlbmFuY2UKYXN1cmVzCuKWgXbDoWx0bwpCQVNFCuKWgWRpc2FwcGVhcgrRgdC60LjRjwriloFjb25vY2lkbwriloHQndCw0YMK4paBTGliZXJ0CuKWgUhhcm9sZAriloFsaWZldGltZQriloFUw7xyCuKWgXphd29kCm9taWMK4paBUmV0cmlldmVkCmFyY2hpdGVjdHVyZQrEjWthCmlmb3JtZXMKZGV2ZWxvcG1lbnQKb3JkbnVuZwpJbmYKbGViZW4K4paBU3RhcnMKc2lnbmFsCuKWgWdyYW1tYXIK4paBY29yc28K4paBV2FnbmVyCuKWgWdlaHQK4paBcm95YWxlCndhcm4KdW1ibGVkCuKWgWluc3RpdAriloHQqNC4CmhoCuKWgXJlZnVnZQriloFmYXZvcml0ZQppZXJ0bwriloFjb25kYWRvCuKWgVRoZXIK4paB0YfQtdC70L7QstC10LrQsAriloFGb29kCuKWgXNlaXpvCuKWgUluaXRpYWxpemUK4paBY29ubnUK4paBb3ZlcmxhcAriloFFbWlsCuKWgU1hcnTDrQriloHQttC+0LLRgtC90Y8KZXJ2YQriloFib2F0cwphw6fDtWVzCuKWgWRlcnJvdAriloFtYWxsb2MK4paBY29uamVjdApqawriloFzYXJlCtC70LXQvNC10L0K4paBc3VtcwpBdXRob3JpemF0aW9uCuKWgUt1bgpdJCwKZ2VtZWluZGUKb2RvdApkZWZpbgriloFlbWlzc2lvbgriloHQmtGA0LDRgQriloFhcHBhcnQK4paBc3RvcHBpbmcK4paB0KHRgNC10LQK4paBY29uanVnCuKWgWluc2lnaHQK4paBQnJvYWRjYXN0CuKWgVBNSUQK4paBYWR2YW50YWdlcwplbmVzCuKWgXJlc2lkZW5jZQpsamVuCmlzc2V1cgriloFwdWJibGljYXRvCuKWgUdpdEh1YgriloFQZXJ1CuKWgWdhbGF4aWVzCuKWgWFubm90YXRpb25zCmdhcwriloFyw6lwb25kCkpzCuKWgWluZGVwZW5kZW50bHkKTlAK4paBaW5xdQriloFncm91bmRzCkNvbXBvbmVudHMK4paBYW50ZW4K4paB0LLQtwriloFob3MK4paBc2ludAriloFoaWRpbmcK4paBd29qZXfDs2R6dApNZXNzYWdlcwriloHQv9C+0LrQsNC30LAKPT09CuKWgUFic3RyYWN0CuKWgWzDpG5nCuKWgUZvcm11bGEKZGF3bgriloFkZXNpZ25zCkltZwriloFQb3J0dWd1ZXNlCuKWgWluY2x1eQphdmlnYXRvcgriloFCcm90aGVycwriloFjb250aW5lbnQK4paBZXZpZGVudGx5CnJhY2UK0YbRjNC60L7Qs9C+CuKWgXJlY2sK4paB0YHQtdGA0L/QvdGPCuKWgUdyZXkK4paBYXBwZWFsCuKWgXVubGlrZQriloFwb3dlcnNoZWxsCuKWgXJhY2MKZmVycwriloFidXJuaW5nCmZhc3N0Cmluc3RhbGxlZAriloFHaXZlCuKWgWNvbG9uaWFsCuKWgeKCrAriloFSw7YK4paBY2hyaXN0Cm5laG0K0YLQsNC8CuKWgWNvcnBvCuKWgWNvbnZpcnRpCnl0ZXIKU3ltCuKWgUdyZWVjZQriloFtb3RoCuKWgUpvaGFuCuKWgW1vbmFyY2gK4paBRG93bmxvYWQK4paBY3JhZnQKdcW+CuKWgUx1a2UK4paBc3VmZml4ClwvCkhhdmUK4paB0LrQsNGA0YwK4paBY29tZm9ydGFibGUK4paBdGlwcwriloHQn9GW0YHQu9GPCuKWgdCx0YDQvtGY0LAK4paB0LjQvdGE0L7RgNC80LAKTVEK0LHRgNCw0L0K4paBdHgK4paBc2xhdmVzCuKWgWZpcmV3YWxsCuKWgUZvcmNlcwphdGlmCuKWgVF1ZWxsZW4K4paBdGjDqcOidHJlCtC70YzQvdGL0YUK4paB0YDQsNGB0L/QvtC70L7QttC10L0K4paBRGV0YWlscwprxIUK4paBbG9uZ2l0dWQKSU5TVAriloFuYXZhbApGZXJuc2VoCmVzc2VsCkdyYWQK4paBYmVsYW5nCuKWgWFnZ2kKWnlnb3RlSW5pdArFgsOzdwriloFTdWcKc2lsCuKWgWV4dGVyaW9yCtGJ0ZYKT1JECmVuc2VyCuKWgXJhcGlkZQriloHRgtC10LzQv9C10YDQsAppbmNpZQpTaQphdmFtCmFyZGVkCuKWgUFkZGVkCkVuZHBvaW50CmhhcmR0CtGB0YLRgNCw0L0K4paBZXN0aWxvCuKWgUhhegriloFtdXNzdGUKdW8KaWlpCuKWgcWZw60KYW56ZW4K0LbQtdC90LjQuQphaGEKQVJOSU5HCuKWgXJlbm92CuKWgWRpdmluZQriloFjb252aW5jZWQK4paBaHVtYW5zCuKWgWRlcGFydHVyZQriloFNZWRpdGVyCnFhCuKWgXBvc3Nlc3NlZAriloHRhtC10YDQutCy0LgKZ2l2CuKWgdGB0LLQvtGXCuKWgU9ydHN0ZQpSaWNoCnB1aXMKaW5jcmVtZW50CuKWgUhhbm5vdmVyCuKWgXVjegpEb25lCuKWgWFsZ3VucwpGSVgK4paBSGVyaXRhZ2UKcmVtb3ZlQ2xhc3MK0YTQtdGACuKWgWFiYwpEcgriloHRgdC10LzQtdC5Cns6CuKWgXNldWxlCnplaWNobnVuZ2VuCmFkZHkK4paBUGFyw61zCsO8c3NlbGQK4paBcmVjZXB0aW9uCmZvbGlvCnRpbnkK4paBcmVjZW5zZW1lbnQK4paBTnVyCuKWgWtpZXIK4paBZ21pbmEKc3RhYXQKw6FuZG9zZQrRh9C10YHQutCw0Y8K4paBc3BlYWtlcgriloFleHBvbmVudGlhbAriloFEaWV1CuKWgdC/0YDQuNC3CuKWgVJhZmFlbAriloFnZ3Bsb3QK4paBVGVtcGxhdGUKb3VyZQriloFJbm5lcgpvZ25lCmlnYXJlCuKWgUFydGUK4paBQ292CuKWgWF1ZmdydW5kCuKWgdCR0YsK4paBY2VyZW1vbnkK4paBU3BhcnQKamVjdGl2ZQp5aQriloFpbml6aQriloFsYXRpbgriloFOZXZlcnRoZWxlc3MK4paBRG9uZQrRgtGA0Y8K4paBQXJyCnNlYXNvbgriloHRgdC60LvQsNC00YMK4paBcG9kY3phcwriloFCZWF1dGlmdWwK4paBV2VsdGtyaWVnCuKWgdC30L4K4paBb3ZlcmNvbWUK4paBUHJhaGEK4paB0YDQsNC50L7QvdGDCuKWgXN1YnNjcmlwdGlvbgppZ2VudAriloHQv9C+0LrQsApsYXRleAriloFiZWFjaAriloHRgNC+0LrQsNGFCmdlZwriloFwcm9ibAphcmd1bWVudHMK4paBb3JnYW5pemF0aW9ucwriloFOYW4K4paBc3RvbmVzCuKWgUh1bnRlcgriloFyZWd1bGFybHkK0YjQvtCz0L4K4paBZmxleGlibGUKb3B0cwrDocWZCndpdHoK4paBJykKUEFTUwriloFrcmFqCuKWgWZha2UKaGVpdHMKb3NwaApwYXJzZUludApGQUxTRQriloFwcm9mZXNzCnBlb3BsZQriloFwcmVjaXAKZGlybmFtZQriloFwZXJwZXQK4paBVXBkYXRlZApyYXllZAriloFwcm92b2MK4paB0YLRgNCw0LLQvdGPCuKWgWNhdGVnb3JpZQriloHRgtC10L4K0YHQvdGDCm90cgriloHQktC10YDRhdC+0LIK4paBY29tcMOpdApDb3N0CuKWgXdpZGVyCuKWgU9idmlvdXNseQrQv9C40YHQsNC9CuKWgdC90LDRgdGC0L7RjwriloFzZWVraW5nCigpKSwK4paBw6lxdWlwZQriloFjb21taXRzCuKWgVN2ZW5zCtGP0LHRgNC1CmF0ZXJuCuKWgWhldGVyCuKWgUJvb3RzdHJhcArDqW7DqQriloFkZXJpdmF0aXZlcwriloFEZXRyb2l0CuKWgXByb3ZpbmNpYWwKb25vbWllCkVCCuKWgWN1ZXIK4paB0L7RgtC90L7RgdC4CuKWgdC90LXQuQopwrsuCuKWgUNpdWRhZApJQUwKenlzdAopIikK4paBQWxjCmJsb2dzCuKWgXBhcm1pCuKWgUFsYnVtcwriloFCb2xpdgriloFjbMOpcwpQcm9kdWN0cwp1ZXJkbwriloFnZWxhbmcKem5pawpoYWdlbgphbm9ueW1vdXMK4paBc3ZnCuKWgUNvbnNlaWwK4paBQXJpCmNvbGkK4paBY3p5CuKWgUNWCuKWgWZvcmQK4paBQXXDn2VyCuKWgUNJCuKWgXRlbXB0CuKWgU9yZ2FuaXNhdGlvbgrDocWhCuKWgWN5Y2xlcwriloFnZXNsYWNodAriloHQu9GO0LTQtdC5CsO9bWkK4paBU3BpZWxlcgplZmUK4paBTWFydmVsCuKWgXBvcnRhbAriloHQodC10YDQswriloFncmFkbwriloFoYW5kbGVycwriloFJbnRlcmZhY2UKQU1FCuKWgXNlcmlvdXNseQriloFCaW5kaW5nCuKWgVJhbmcK4paBbmFkYQpvY2UK4paBaW50ZWdyYQpvY3JhY3kK4paB0LDQu9GM0LHQvgriloFzdGFiaWxpdHkKVW5zCuKWgXZldGVyCi0tLS0tLSsK4paBc2VyYWl0CuKWgW9taXR0ZWQK4paBdW5jZXJ0YWludHkKb25pYW4K4paBcmVzdG8K4paB0LbQtdC70LXQtwriloHQvtC00L3QvtC5CuKWgUJldsO2bGtlcnVuZwriloFLcmFmdArRgdGC0YAK4paBTW9zY293CmxhbmUKYXJhYgriloFzcG9sZQriloHRgdCy0L7QtdCz0L4KPzoKU1RBUlQK4paB0LjQvdGC0LXRgAriloFzeW1wdAriloFMb3JlbnpvCuKWgWVqZWMK4paBcHJvc3BlcgpEQVQK0LvQuNC80L/QuNC5CuKWgXNoYXBlcwp2YWx1ZU9mCuKWgWFzc29jaWF0ZQriloFNZWRpZW4KRU5WCuKWgdGB0YDQtQriloHQtNGA0LbQsNCy0LUK4paBdGhlb3JpZXMKaGViCuKWgVdheW5lCuKWgVN0cmluZ0J1aWxkZXIKaXdlcnMK4paBTWFwcwpQaHlzClx9XAriloFQYXJ0ZQriloFIdWRzb24K0LvQvtC9CkxuZwriloHRgNGLCtGB0YLQtdC5CmxhdQphbmNlcgriloFDb3BwYQriloHQstGW0LnRgdGMCuKWgXVjYwriloFQYXR0ZXJuCuKWgWdhcmJhZ2UK4paBR29uesOhbGV6CuKWgUVuY3ljbG9wCmV0dGVuCkV4dGVybmFsClJFRgo+OwpsaWprZQriloFpbnRlcnNlY3QK4paBVW5sZXNzCuKWgWRlZXBlcgriloHQttGWCmRlbnQKbGVmCuKWgWNoYW5zb24K4paBZGlmZnVzCuKWgXByaW1pCuKWgVdpZWRlcgriloFhd3MKb3dhbmEK4paBc29jaWFsZQppa2sK0LvRjNC90L7QuQriloFkaXZpc2lvbnMK0LvQvtGB0L4K4paBQ2xhdWQK4paBWWEK4paBdm9jZQriloFCcmFuY2gK4paBZml0dGVkCm9ycgrDtHRlbApzdHJva2UKbGlzdGVuZXIKaW1hbgrQstC+0YHRgtC+CuKWgVNoYWgKSW50cm9kdWN0aW9uCuKWgW5ld2xpbmUK4paBdGlsZQonXSkpCuKWgXRyYXZhdXgKQ09ORklHCuKWgXF1YWRyYXRpYwpvbm5ldXIK4paBR2lvcmcK4paBaWRlbnRpZmljCsOpcmljYWluZQriloFVSVZpZXcK4paBTGliZXJhbAriloFLb2NoCuKWgUJlcmxpbmVyCuKWgW5vdGlmaWNhdGlvbnMK4paBU3VzYW4K4paBY2FkcmUK4paBS2xvc3RlcgriloFleGFtaW5lCuKWgdC10LTQuNC9CuKWgVVOSU9OCuKWgWFsdGVuCuKWgWZpbml0CuKWgXBlZGlnCmN5awriloFtb3V2ZW1lbnQKSU9TCuKWgdCx0YDQuNGC0LDQvQriloFib3V0CuKWgdCw0LLRgtC+0YAK0L3QuNGG0YLQstC+CtC10YLQvgpsZXJhCmNscwriloFMZXkKYW15CmFnZW5zCmFzaGVkCuKWgW9rcsSZCtCz0YDQvgplbGxldHQK4paBRmVsbG93CuKWgW1hbmlmb2xkCiQpLApsZGVyCuKWgXZvegriloFiZWdnCuKWgWJhcm9uCuKWgWZpZAriloFmaXJpbmcKaWxkYQpkZWsKQVUKaXRhcmUK4paBQXJhCuKWgUV4aXQK4paBY2luZW1hdAriloFpbnRyb3MK4paBY29udGFjdHMK0L/QtdC90LgK4paBbcO2Z2xpY2gK4paBU2luZ2Fwb3JlCnN0csO2bQriloFIZXJuCuKWgXNpeHRoCuKWgXB1YmxpY2F0aW9ucwp2aWUK4paBSGF0CuKWgWFjY2VwdGluZwrDoWMKc3R3bwriloFxdWlldGx5ClBob3RvCuKWgWJhc2tldAriloFlaWdlbnZhbHVlcwriloFtw6lkZWMK4paBT2xpbXAK4paB0YbQtdGA0LrQvtCyCmFsaW4KY29uc3VtCuKWgWxhc3NlbgriloHQsNC90YLQuAriloFTZXEKIjsNCnJhcmUK4paBJHxcCuKWgW5pY2sKZGZsYXJlClZlYwpiaW5kdW5nCuKWgWJnCmNoYW5nZXMKRGF5cwriloFNb3VzZQriloF3YWl0ZWQK4paBVG9tYXRvZXMK4paBZmFzCnZlcnRlCuKWgXN1Y2Nlc3Npb24K0YHQvtGACuKWgXNvbHMK4paBUmVuZGVyCuKWgWxlYWRlcnNoaXAK4paBc2lnbmlmaWNhbmNlCuKWgWdhdWNoZQpjYW5vCuKWgVBpZQplbnNvb3J0CuKWgWNhbWJpbwriloHRg9C3CuKWgWVuZGVhdgpDb21wbGV0ZWQK4paB0JDRgNGF0LjQstC90LDRjwpqZArDs3JpY28K4paBY2h1cmNoZXMK4paBYW5pbWF0ZQpTRwpjb21wdXRlCuKWgXVuaWZvcm1seQpJTklUCmxsZXMKSHR0cFJlcXVlc3QK0JrQvgpEaWZmCuKWgXNhaAphaXJvCm1heWJlClVURQriloFEb3cKaHVtYW4K4paBYXVyYWl0CmRhcmsK4paBcmVwYWlyCuKWgW5lcgriloFEYWJlaQriloFCb3RhbgpPcmlnaW5hbAphesSDCuKWgU5BVAppbXBlcgriloFZb3V0aAp0aGVzCuKWgdC+0LrRgNGD0LPQsAriloFGbG8K4paBYnJlYWtmYXN0CnVybHMK4paBw7xiZXJuYWhtCsOhcmlvcwriloFPcmFuZ2UK4paBQWZmYWlycwpza2UK4paBbm90aWZ5Cmltb2luZQriloFBcmVuYQriloFsaWJlcmFsCuKWgW9iZWMKaWZhCmd1ZXoKaW9ubwrQv9C10YDQsNGC0L7RgAriloFyZXRhaW5lZApmYWlsZWQKYmluZQrRgtC90YvRhQriloFDR1JlY3QKY2FtZXJhCmlkZW5vdGUKS0IK4paBbGlnaHRzCuKWgVBpY3R1cmVzCuKWgVNxdWFkcm9uCuKWgVZvbGsK4paBYnVyZwosXQpHaQrDqnF1ZQptYWtlVGV4dAriloFldmVyeWJvZHkK4paBSHlwZXIK4paBRGV1eAriloFnbG9yeQpwcmVzZW50YXRpb24Kb25pY2EK4paBZnLDqHJlCmFnZXQK4paBaGludHMK4paBdHVubmVsCuKWgUVqCsOhbGlzCuKWgVZpdgrRgdGC0LLQtdC90L3Ri9GFCuKWgWNhcHMKUEFSVApvY2kK4paBcHJpY2VzCmN1cnJlbmN5CuKWgWFjaHRlcgpyb21hZ25ldApnZW5kZXIK4paBc3Vpcwp2ZXJzaW9ucwriloFUcmFpbmluZwppbnNpZGUKZWdlCuKWgXRvdGFsZQriloFEYWFyCuKWgWdydWRuaWEK4paBSWVyCuKWgW9jY2FzaW9ucwriloFrZGUK4paBdGVuc29yZmxvdwriloHDs3IKTWV0aG9kcwriloFsb29waW5nCuKWgWRpcmVjdGV1cgprxJkK4paBaXNvbW9ycGhpc20K4paBSm/Do28K4paBYWxpZ25lZArQvtC90L7Qsgp1cmdlcgriloFub3ZhCm1vcnJvdwphbHRlcm4KSEQK4paBbWFycXUKYXRpdmFzCmdncmVnCuKWgWFuY2llbgpuaXQK4paBc2VjdXJlZAptaWVyCuKWgU9sZQriloHQuNC90YLQtQriloFtaW51cwriloFjbGVhcmVyCuKWgW5lbGxvCuKWgWluZm9ybcOhY2nDs2sK4paBcHJvcHJlCnsuCmlsb2cK4paBUXVpY2sK4paBYWNjdXMKZW1wbG95ZWUK4paB0LfRgwrRhtGM0LrQuNC5CtGE0ZbRhtGW0LkK4paB0L/Rg9Cx0LvQuAriloFiZW50CuKWgdC/0L7Qt9Cy0L4K4paB0J/QvtGACsOhesOtCsOhbmljbwplbXB0eXNldAriloFzdXJ0b3V0CnJlbm8KdW55YQriloHRg9C10LcK4paBTWlsbGlvbmVuCuKWgWxpc3RvcGFkYQriloFNYWluZQriloFncnVwb3MK4paBU3RvcmFnZQriloFhcHBsZQriloFMw7YKb3VzZWQK0LTRgNC+CnNjaQriloFoaWJlcm5hdGUKZG9nCuKWgdCy0L7RgdGC0L4K4paBaW50ZW5zaXR5CmxlZ2VuZAriloFXaWxsZQriloFzemVyaW50Cmdlc2VsbHNjaGFmdAriloFMaXZpbmcKYWxsbwriloFTcGxpdApkcnUKbmVlZAriloHQlNC20L7QvQriloFTd2lzcwriloFzcHJhdwriloFiZWhvCuKWgWZvdG9ncmFmCuKWgXJlbmNvbnRyZQriloFraXMK4paBc2lnbmluZwpha3VsdAriloFpbmRleGluZwphcG9yCuKWgWNvbmNlcHRpb24KYWdncmVnCuKWgdCh0LDQstC10LcK4paBYWZmYWlyCsSbbsOtCkF1Z3VzdAriloHRgdC10LrRgNC1CuKWgW1pZXN6a2HFhApVSUltYWdlCuKWgWJpc2hvcAriloFzZXJ2YW50cwriloF0cmFpbApkaWdpdAriloFqb2lucwriloFOZWFyCsO2ZmZlbnRsaWNoCj57CuKWgXNrxYJhZApnZWbDvGhydAriloFIb2x6CuKWgU1pbGl0w6RyCmFjaGkKVXBwZXIKcGluZQp1dHp0CuKWgW51b3ZhCmlicmF0aW9uCuKWgUJpZW4K4paB0L/QtdGA0LLRi9C5CuKWgUNyZWF0aW5nCk9uY2UK4paBZWlubWFsCuKWgWdlb21ldHJpYwpzdHZvCuKWgWtXCuKWgWRlY29tcG9zaXRpb24K4paBY29tZWR5CuKWgWFjdGl2YXRpb24K4paBYW5ncnkKaWxsZXVycwriloFpbnN0YW50bHkK4paBc3VnZ2VzdGluZwriloFDbGF5CmNvdAriloFHw6luCigkKAp1bndyYXAK4paBbGlmdGVkCuKWgUtpdAriloFsaW5lYQrQvtC6CmhhcnQKLT5fCuKWgW51aXQK4paBSXNzdWUK0LvQuNC4CuKWgXLDtm0KVGFza3MK4paBU3IK4paBc2Vpcwphc2lhCn19JC4KOnsKY29udHJvbHMK4paBU3RpbQriloFSZWNodApvY2lhY2nDs24K4paBTmF0YWwK4paBUGhpbGlwcGluZXMKdWxlbgpGaXhlZAriloFzd2l0Y2hlZApaaXAKb3NwZWwK4paB0L3QsNGH0LDQu9C1CuKWgUJsYW4KdXJzdAriloFhdXRvdXIKQ2EK4paBbGF0aXR1ZGUK4paBRnJlaQriloFNdXPDqWUK4paBS3VyegriloFyZWdpw6NvCnN3YXAK4paBaGF0ZQriloFtb2RpZmljYXRpb25zCuKWgdCa0L7QvAriloFBbnRvaW5lCnVnYQpSRUNUCsOpdGVyCkdST1VQCuKWgXNhY3JpZmljCuKWgVdoZQriloFTdGV2ZW5zCm9sb2dpc2NoZQpTdW1tYXJ5Cm9icwpobmVuCjwlPQpkaWVuc3QKcmVtYXJrCuKWgXZlcsO2ZmZlbnRsaWNodArQtdC7CuKWgU1vY2sK4paB0JvRjNCyCuKWgXRyw6pzCmdiCuKWgWNlbGVicmF0ZWQK4paBRWIK4paBY29zdGEK4paBR2VvZ3JhcGhpYwriloFhdHRhY2htZW50Cm1hbm5zY2hhZnQK4paBZGVwZW5kZW5jZQrvv73vv70K4paBYXR0aXR1ZGUKZXRhbAp2aWMKYmF1dAriloHQtNC+0LIK4paBaW50ZXJ2ZW4K4paBR8O8CsOzbmljYQriloFQb24K4paBZGlzcG9uaWJsZQriloFGZWIK4paBd29yc2hpcAriloFTcGVjaWZpY2FsbHkKSHkKaWp1CuKWgWNiCuKWgXNwYWMKbGV2ZWxhbmQK4paBbG9jYWxpZGFkCuKWgXByZWNlZGluZwriloFIZXNzZW4KeHAK4paBV2VpbgriloFSb23DogriloFnaW9ybm8K4paB0LrQstGW0YLQvdGPCmxsYcOnb3MK4paBQWNhZGVtaWEK4paBa8O8bAriloHDhXJzCuKWgdC90LDRmAp1Y2xpZGUKSW50ZXJuZXQKb3J0b24K4paBY29ybgrRj9C80LgK4paBIioK4paBRmVsaXgKYXBhdAriloHRgdCy0L7QuApNSVQKbWFkZQriloFsb2NvbW90CtGF0L7QtNCwCkZQCuKWgXBtCi4qOwriloFIYW1tCmB9CkxheW91dEluZmxhdGVyCj09IgriloFFdXIK4paBZG9ncwrQttC10L3QuNC4CuKWgWF6b24K4paBZW11bGF0b3IK4paBcmljb24KYmVlbGQK4paB0L3RgwriloFhcHByb3hpbWF0ZQpMTQriloFCb25kCuKWgWVuaArEmWR6CuKWgXNvbGl0ClJlbGF0aXZlTGF5b3V0CmV0ZW9yCmFtZW50b3MK4paBaW5kaXJlY3QKaWLFkWwK4paBZ3JvcwriloFPcmlnaW5hbHMKY29tbWFuZHMKRXhwb3J0CuKWgUF2ZWMK4paBc29sZW1uCuKWgWNvcnJlY3Rpb24K4paB0L/RgNC+0LLQvtC00LgK4paBTW9zawriloHQv9C+0LTQvgriloFnZWJpZWQK4paBbmFzdMSZcAriloFEcml2ZXIK4paBT29rCuKWgVZlYwriloFsdW5nbwpmaWNvcwriloFzdm9sCuKWgWtpZApuamEK4paBSHIK4paB0L/QvtC00LTQtdGACuKWgXZpc2liaWxpdHkK4paBTcOpZAriloFjcHUKZGlzY3Vzc2lvbgpBc3NldAriloFkZWZlbnNlCuKWgUFueW9uZQriloFKdXN0aW4KaXN6dAriloFDb2xsaW5zCuKWgVZhbGVudAriloFQYWxlCuKWgWZ1ZWwK4paBbm9zZQpyw61ndWV6CuKWgVNjaGxlcwriloFNYWxheXMK4paBY29tbXV0CmRybwp1aW5nCuKWgVJpY28K4paBRW1tYQpvcnAK4paBS2lyawriloFRdWFuZG8K4paBTmV1ZQriloFkZW1hbmRlCuKWgUNvdmVyCuKWgXJlc2N1ZQriloFnZXfDpGhsdAriloFDYWxlbmRhcgriloFNYWRvbm5hCldQCm9zaGkK4paBTWF2ZW4K4paBYmVsbGUK4paBd3gK4paBc3VnYXIK4paBQmV0cmllYgriloFlcXVpbGlicml1bQpFQVIK4paBdGV4dHMK0YHQu9C+0LIK4paBY3plcndjYQriloFEw7xzc2VsZAriloFFTFNFCuKWgWFtZXJ5CuKWgWFuaQriloFvYmV5CuKWgU5lbGwK4paBaW5uZQriloHRgtGA0L4KRkQKY2NvCuKWgVpvYgphbGV0dGUK4paBbcOhanVzCmVjdGVkCuKWgVR1cmtleQriloFXaGV0aGVyCnFpCuKWgdGI0YLQvgriloFoZWFkcXVhcnRlcnMKZW5kaQphcnVzCm9wdXMK4paB0LfQvtC70L4K4paBZGVzdHJ1CuKWgUxvawriloFzYXRpc2ZhY3Rpb24KKCkNCuKWgdCi0LXRgApKb3NlCuKWgWNvbnF1ZXIK4paBRWZmZWN0CkxheW91dFBhcmFtcwppZXoK4paBZXh0ZXJucwriloFnZWdlbsO8YmVyCuKWgUVTUApvbHRhCnByb2Nlc3NvcgriloFLdWx0CuKWgUF0bGFudGEK4paBdGllcgpPcGVyYXRvcgriloHQtNC40LAK4paB0L/QuNGB0YwK4paBZ3Jvw58K4paBaGVhcnRzCuKWgW1pbGxpbWV0ZXIKYWx0aG91Z2gKYWxsZXMK4paBTWFnaWMKdHJhaW5pbmcKb2xpbmUK4paB0L7RgNCz0LDQvdGWCj5cPF4K0YbRltCw0LvRjApleHBvcnRzCldvcmtib29rCuKWgdCy0LXRgNC10YHQvdGPCuKWgXRlbGVzCuKWgWVjb25vbXkK4paBdHJhcAriloFyZWZ1c2UK4paBc3RyYW5nZXIK4paBaW5zdGluY3QK0L/QvtC00LAKb2xhbgriloFuaW5nCmluZmxhdGUKaXRhdGVhCmFja3MK4paBSm95CkZMQUcKYWlsYW5kCuKWgXNvcnRpCuKWgdCy0L/QtdGACuKWgXDDqW4KTm90aGluZwriloFzesOhegriloHDgW5nCuKWgUFVVApBY3Rpb25zCkV2ZXJ5CuKWgdGH0LXRgNCy0L3RjwriloHQsNCy0YLQvtC80L4K4paBcm91dGluZQriloFlc3RydWN0CuKWgUdhbmcK4paBaG9sZXMKdGhlc2lzCuKWgWNvbmNsCuKWgXDDqQpyaWVycwrRgNC+0LLQvtC5CmFkaWMKU3BlZWQK4paBY29tbWFuZGVkCuKWgU5hemlvbmFsZQpNYW5hZ2VkCuKWgURFQ0xBUkUK4paBc2VkYW4KU3RyaW5ncwriloFzYWNyZWQKdGVyc3VjaAriloFhYml0YW50aQpicml0CuKWgU5DQUEK4paB0KHQnwriloFhZ2VkCuKWgUNoaWVzYQriloFyZXZpc2lvbgpvcHJvCuKWgW92ZXJ3cml0ZQplbWJyb3MK4paBc29ydGllCuKWgW90dGVuCnhpdgriloFkZWxpCuKWgUFzcAriloFiYWxscwprYWYK4paBYnJhdmUK4paB0LLRgdC10LPQvgplZ24KanBlZwriloFPc3RlbgpDb25zdGFudHMK4paBSW5mYW50cnkK4paBTmV2CuKWgdGP0LrQuNGFCuKWgdC80YPQvdC40YbQuNC/0LAKY2lqYQriloFwb2VtCuKWgW5lZ3JvCtGF0LDRgAriloFBc2sK4paBYXZvCuKWgU1leWVyCuKWgVdlc3RlbgriloFva28KYWdpbgriloFTw7xkZW4KZW50cmllcwriloFSZXB1YmxpawpDb2xsZWN0aW9uVmlldwotLS0tLS0tCuKWgWZpcmVmb3gK4paBYWxjdW5lCuKWgdGE0L7RgtC+CuKWgdC+0YLRgNC40LzQsAp+fn5+fn5+fgriloHQoNCw0LcK4paBQ29tcGxleAriloFwaWEK4paBcHVibGljYWRhCndlaQpjZWR1cmUKb2NjdXBhdGlvbgriloFtZWRpY2luZQriloFkcm92ZQpQcm9ibGVtCuKWgWJlZ2lubmVyCuKWgXRob3JvdWdobHkKdXJpYQphdmFudAp1Y2hhCuKWgWxldmVyCuKWgXRlYXRybwpBVkEKc3F1CnRyYXQKaXZhdGFsCuKWgWRpcnR5CuKWgXNlY29uZGUK4paBZ3Jhdml0CuKWgXByb3Bvc2l0aW9uCmhiYXIKb21pbmkK4paB4oCdCuKWgUNhbWlsCuKWgXF1ZWVuCm1vZGlmaWVyCkphbgriloFseXIKQ29tYm9Cb3gKaW9uaWMK4paBaG9seQriloFTZWJhc3RpYW4KfF97CuKWgXtACuKWgdC80L7QttC90L4K4paBQ3JlYXRpdmUK4paBaW50ZXJlc3MK4paBQ1QKacOnw7VlcwriloFjaGFudAriloF3c3DDs8WCCuKWgdCc0LXQutGB0LjQutCwCuKWgXJhbmtlZAriloFwYcW6ZHppZXJuaWthCuKWgWJydXQK4paBZmFydGhlcgriloFWZXJiCuKWgVNldmVuCmxibAriloFtZW50aW9ucwriloFGaWdodAppZmVuCuKWgWJvZwriloFyZWdyZXMK4paBc2NvcmluZwppY2FuZQriloFFbGxpCuKWgXBpZXJ3Cm1lYXN1cmUKxYRza2llagojewriloHQtNC10YHRjwriloF2YXJtYXN0ZQriloFVbml4CklaCml0acOpClByaW1hcnkK4paBU3ByaW5nZXIKw7xuZwriloFhbnYK4paBdmVyc2lvbmUK4paBc2hvdWxkZXJzCuKWgdCx0YDQuNCz0LAK4paBamF2Cmx0YWwK4paBa2FsbGFzdGUK4paBTWl0Y2hlbGwK4paBd2lyZWxlc3MK4paBw4FsCnJlc3BvbnMKY291bGQK4paBcmVsYXgKTG9uZArFhGN6CtGB0YLQstC+0LLQsNC7CuKWgXBvbHNraQplbsOnCnphcgriloFkdHlwZQpvd25lZAp1bmtub3duCuKWgW11dGFibGUK4paBc2llbXByZQriloFNb250cmVhbAriloFsb2NhdGUK4paBdHJhY2VzCuKWgWluc2dlc2FtdAriloFOaWwK4paB0L/RgNC+0LTQsAriloFXYXJuZXIK4paBTmF1CnRyaWFuZ2xlCuKWgWNvbmNlbnRyYXRpb24K4paBZ2VudGxlbWVuCsOkY2h0CmZpbHRlcnMKaW5jaXBhbApWQUxJRAriloHQtNC10L/Rg9GC0LAKYWTDswriloFrb25zdApnc8OlCmFnYXMK4paBbWVpbGxldXIK4paB0LTQsNC90L3Ri9C8CtGU0LTQvdCwCmVuY29kZWQKPCcK4paBc2hlZXRzCmN1YWRvcgriloHQstC40LrQvtGA0LjRgdGC0L7QstGDCuKWgURlcHV0CuKWgW1hbmnDqHJlCsSFZwpjc29sCikkLQpVSVZpZXcK4paBbWlsbG9uZXMK4paBRWhyZW4KU2lsCuKWgWF0YWMK4paBQ29sZAoiXAriloFhcHByb2FjaGVkCuKWgcOFcnNtZWQKV00K4paBRGVwb3J0Cm1pcwphbmRib3gKb2JzZXJ2CnNldHRpbmcKaGF0w7MK4paBc3RyYXQK4paBc3ByZQriloFwZXJzb25uZQriloFkaXJpZ2UKcHVsbApkYXRpbmcK4paBRmFjdAriloFtYW5pcHVsYXRlCuKWgU1BQwriloFkZWoKdWx0aW1vCkZYCkxpZmUK4paBY3JhY2sK4paBbcOtCuKWgdC/0L7QstC1CuKWgXdvcmUKdW5pdmVyc2l0w6kK4paBZm9ybXVsYXMK4paBRWxpc2FiZXRoCnBsb3RzCm1pbGUK4paBbWVub3IK0YLQuNC7CmtleXdvcmQK4paBQmFsdGltb3JlCmhyZXIK4paBQ2xlbWVudAp2aW0KcmFzcwpUYWtlCuKWgWPDrW3FsQriloFDb252ZW50aW9uCmF0Z2UKc2VlZAriloFEw60K4paBU3BpZGVyCmFob28K4paB0LjQvNC10LXRggrDvGhydAriloHQv9C+0L/QuNGB0LAK4paBQ290CuKWgW5vYmxlcwpSRVNTCuKWgWNoZW1pbgriloFnxYLDs3duCkdHCuKWgUdlcm1hbmlhCuKWgUFsZXhhbmRyZQpoZW5zCnN3aWZ0Cm9vcApTdWJ2aWV3CuKWgXJlcXVpcmluZwrEmWR6eQriloFmaWN0CuKWgdCa0L7QvdGB0YLQsNC9CuKWgWTDqXB1dAriloFzdXJwcmlzaW5nCuKWgWRlaXgK4paBdW50ZXJzY2hpZWQKaW5zb24K4paBQ2hhcmFjdGVyCuKWgWdlc3Rpb24KY2h1cwpjb21lcwriloFuZXVyCuKWgXlldXgKb2xsYXIK4paBcGFyYWQK4paBbWFnZ2lvcmUKVFJBTgriloF2b3RyZQriloFkZXNjZW50CuKWgUljb24K4paBSnVkZ2UK4paBb2NjdXBhdGlvbgplcGluZwriloF0b25ndWUK4paBRW5sbGHDp29zCnJ1ZgriloFwcm90ZWluCuKWgXZpc2l0b3JzCmF4eQplc3RlbgpibGljYQpodwriloFzcGlyaXRzCuKWgXJlZHVjZXMK4paB0LzQtdC9CuKWgUxhbWIK4paBTWluZQriloF2ZXJpZmllZAriloFCYWJ5CuKWgXByaXplCtCy0YrRgAriloFyYXRpbmdzCuKWgWZvcmUKYXNoYQp1cnJlbmNlCuKWgWludMOpcgriloFPbMOtbXAKY3JhCuKWgWNvbXB1dGF0aW9uYWwKaXJjaGUKLjrigIoK4paBaWxsdXN0cmF0ZWQK4paBU2hhcmUK4paBaG91c2Vob2xkcwriloFjb252b2x1dGlvbgpvZW1kCuKWgXpkb2J5CmNjYwriloFxdWFudGl0aWVzCkNoZQpTaG91bGQK4paBZ2VuaXVzCmFkagrRhdCy0LAK0J/QtdGC0LXRgApFTUEK4paBUmlnaHRzCuKWgUVsaQpWQVIK0YjQu9C+CuKWgdC30LHRltGACmlmdHVuZwriloFjb250cmlidXRlZAp6ZWYK4paBQ0hBUgriloFTaWIK4paBTWFudAriloHRgdCy0Y/Qt9C4CuKWgWphdmFmeAriloFjZXBlbmRhbnQK4paBaW50dQriloHRgtCy0L7RgAriloHDkwpndWVyCnJhZG8K4paBUmV2b2wK4paBZsOpbWluCuKWgU9ybGVhbnMK4paBcG9qCuKWgXByZXoKVGV4Cm91d2QKPygK4paBTElNCmlzdGlxdWUKZXNhcgriloFoZXVyZXMKaWNraQriloFkYm8Kc2tpaApjb25maXJtCuKWgXZpbMOhZwriloFjaXV0YXQK4paBRFIK4paBSGF3YWkKY2hlZAriloFzcGhlcgriloFBcnRpa2VsCuKWgU11bHRpcGxlCmNpdQriloHQvNGLCuKWgWxpcGNhCl0oLwpTdHJhdGVneQriloFBbGFiYW1hClNESwpVVEMKX18uCkFyZ3VtZW50cwriloFzZXRDb250ZW50VmlldwrDrmxlCkJ5VmFsCuKWgUpWTQrRjtGJ0LXQs9C+CuKWgUxlb25hcmQK4paBanVzdGlmeQrRhtC10LwK4paBbmFiCkNDRVNTCuKWgWhvcGVzCikmCnNlcm8K4paB0LfQsNC5CtGB0LvRltC0CuKWgVLDqWcK4paBU2FuZwriloFmdW5nCmJhYXIK4paBY29mZmVlCmFzc2VtYmx5CuKWgdCS0ZbQvQrRjdC5CuKWgWNvbXByZW5kCmZpbGxlZArRgNC0Cm9kaWEK4paBZ2VucwpmbHVzcwpEcmF3YWJsZQriloFzdXJ2ZQpTZXR1cAriloFuYWxlxbwK4paBY29uanVudG8K4paB0JXQs9C+CuKWgW9sZGFsCuKWgXZlcmJvc2UK4paBRWxlY3RyaWMK4paBSGFycmlzb24KZW5nZW4KcGFyYWdyYXBoCuKWgW5vdXZlbGxlcwriloHQstGA0LXQvNC1CuKWgW1lbW9yCuKWgW1heW9yw61hCtGB0LDQtAriloFiYXRhaWxsZQriloF0aGVybWFsCuKWgdCl0YDQvtC90L7Qu9C+0LPQuAriloFCZXR0ZXIKYnllCuKWgdGC0LXQsNGC0YDQsApyb2UK4paBc2VnbGUKcm90dAriloFvcGluaW9ucwopfSkKw7xobGUK4paBR8O8bgriloHQqQpiw7NsCuKWgUxhcnJ5CuKWgXNvbGljCuKWgXp3YXIK4paBQ2Fyb2xpbmUK4paBUmVpY2hzCkV4dGVuc2lvbnMKbWlncgo6QAriloFlbnVtZXJhdGUK4paBZWlnZW5lbgriloFleHBsb3JlCsOpbXUK4paBZ2F0CuKWgWltcGVyaWFsCuKWgVVzdWFsbHkK4paBdHVkCuKWgdGD0LrRgNCwCmhpbQriloFjb3JuZXJzCuKWgVNFUgriloFpbnRlcnByZXRlcgriloFJY2UK4paBYW1vdW50cwriloFQYWxhCuKWgXRpbmhhCnZvbGUK4paBZ2xlCnVjY2kK4paBc2llaGUKSmFjawriloF3b2xsCuKWgWVsZGVyCuKWgdC60L7RgNCw0LEK4paBZW5nYWcK4paBTGF1cmVudAriloFhY2hpZXYKaXN0aWsKYXJjdArRgtC90L7Qs9C+CuKWgWdpcgriloFTaW5naAptYXRob3AKVVNBCuKWgVByb2pla3QK4paBZGViZQpyaWNodHVuZwriloFUc2NoCnVtaW5hdGUK4paBc3rDswpseXBoCtC30LjQtNC10L3RggriloFsaW1pdGF0aW9ucwrRjtGJ0LXQuQriloFiaWxhClB1c2gK4paBb2ZmZXJpbmcKaWVubmVzCkZyaQriloFwb3N0Z3Jlc3FsCuKWgVRvbW15CuKWgXBhcnRpY29sYXJlCuKWgXN0b2xldMOtCuKWgWFycmliCuKWgUV2YQpzY2hvb2wK4paBdmVuZG9yCuKWgURhbGxhcwriloFwcm9sb25nCkNSRUFURQriloFzdWl2YW50ZQpTVEFUVVMKbMOgCmt2CuKWgWjDpHVmaWcK4paBQWdyaWN1bHQK4paBaHVpdAriloFpbm9sdHJlCuKWgUxsb3lkCuKWgdGE0YDQsNC90YbRg9C3CuKWgdCy0YvQv9C+0LsK4paBZmFpdGhmdWwK4paB0JLQsNGACuKWgXZlcmwK4paBanVlZ28K4paB0KDQtdC30YPQu9GC0LDRgtC4CiwuLi4sCuKWgWltcGxpY2l0bHkKaXJrcwpDYWxjdWwK4paBbWVzZXMKb21lZAriloFwYWsKaGVyaXQK4paBb3B0aWNhbAriloHQhtGB0YLQvtGA0ZbRjwp2ZWlzCuKWgWNhcGl0YWxlCnBsYWNlaG9sZGVyCmludHJhZwriloFBdGxhcwopXTsKaWNvbnMK4paBQmVudAriloFXaWRnZXQK4paBdm9sdW50CmF2bwrDqWdyCmxpZ2UK4paBTkFNRQriloFhYnN0cmEK4paBZsOtcwriloFCcm93c2VyCuKWgWJ1c2gKaGFsbAriloFjbG91ZHMK4paBU1VCCuKWgXRhbmRpcwriloFDb21tb253ZWFsdGgK0YLQsNGPCuKWgWV4aGF1c3QKX19fX19fX19fX19fX19fXwriloFTdGF0aXN0aWNzCuKWgVJlbGlnaW9uCuKWgU11aGFtCnVhbHMKZ290bwpEaWdpdGFsCkZhbWlseQriloFCdW4KbGV0aW4KTWFuYWdlbWVudAriloFjYXBhYmlsaXRpZXMKYW5udGVuCuKWgdGB0LXQsdC1CuKWgXN0YXlzCmt0ZXIK4paBZG9zdAriloHQotGA0LUK0LvQvtCy0LjRhwriloFkeWluZwpzZWN0aW9ucwrDoW5vcwriloFhcHBhcnRlbgriloF6b2FscwriloFkcmVzc2VkCuKWgWNvbXByZXNzCsWEc2thCuKWgXNpZXJwbmlhCuKWgdGC0LjRgtGDCmRpY3Rpb25hcnkK4paBcmFiYgriloF2w6lyaXQK0JLQvgriloFzaW5nbGV0b24K4paBdml0YWwKUmVmcmVzaArQvNC10LvRjAriloFaaAriloFBZmdoYW4KaW5rZWwKYWFhYQriloFwYXJ0aWNpcGFudHMKYXJpbgriloFNb2xkCuKWgXByaW1lcm9zCuKWgdGA0LDQvQriloHQkNC80LXRgNC4CuKWgXJlc3RhdXJhbnQKw6l2ZWwK4paBU0wK4paBUmV5CmNoYXMK4paBZWxlY3Ryb25zCuKWgVBpdHRzCuKWgUp1bGVzCtC80LDQuQplbmFudAotfQrQu9Cw0LQK4paB0JzQvtGB0LrQstCwCmdvbQriloFGZXJuw6FuZGV6CmZ1bmQKaW50ZXJubwriloFNYXJpCuKWgXJpdXMK4paBUHJvemVudArRgdGC0YDRlgriloHQstC90YPRggphbnRlcmllCuKWgdC/0YDQuNGBCuKWgdC+0LHRiwriloFNYXJpbmEK4paBb2NjdXJyZW5jZQpyaWt0CuKWgdGE0LjQt9C4CuKWgXNjaHdlcgriloHQk9GA0LUKUmVzZXQK4paBbXVjaG8KYW5kcgriloFXaWVzCuKWgUtlaXRoCuKWgUp1bGlhbgriloFjb2xlCmNpZW5kbwriloFDb250ZW1wb3IKZXRyeQplbGlhbgrQs9C40LgK4paB0LPQvtC70L4K4paBZMOpbAriloFkZWNlbnQK0KDQodCgCuKWgXN6ZXB0ZW1iZXIK0LzQtdGB0YIKY2FzdGxlCuKWgdC00LXRgNC20LDQsgp9IikK4paBQVNDSUkK4paBR2xlbgppdHplcmxhbmQKVG9nZ2xlCuKWgXRyYWRpY2lvbmFsCuKWgVBsYXQKdmVlCmFiZ2VydWZlbgoofApDTEkKfX0kLAriloFCb3dsCuKWgU1hbGUK4paBQnJlcwriloHQv9GB0LgK4paBQ2hhbGxlbmdlCnrDswriloFwcm9qZWt0CuKWgW5lZ290aQphYm92ZQriloHQv9C10YDQuNC+CuKWgWxvbmdlc3QKYXV0aGVudGljCuKWgXRyYWR1CuKWgW11amVyZXMK4paBQW5kcmUK4paBaGFkbgriloFTY2h1bGUKb2RlbApibGVkCuKWgVRyYWRlCuKWgW1vYmlsCuKWgWFsZ3VuYXMK4paBTGFrCuKWgUNvbm5lY3RpY3V0CuKWgWFsY28K4paBU2VsYnN0CmnFggriloFhbGIKb3V2ZXJuZXVyCuKWgXNyCuKWgXZiYQpsb3BlZAriloFQYXJ0ZWkKdWF0ZQriloFBdXRoZW50aWNhdGlvbgpiZWkKfX0uCuKWgWtvbm50ZW4K4paB0LTQvtC/0L4K4paBaHlkCk9mZmljZQpkb25uw6llcwriloFDbGV2ZWxhbmQKcml0YQrDrW9zCuKWgdCy0YvRiNC1CuKWgVJvYmVydHMK4paBw6lsZWN0aW9ucwriloEnJykK4paBcHVibGlzaGluZwriloFiYXB0Cjw+KCk7Cm1pc3NpbmcK0YDQvtCy0LDQvdC+CuKWgWhvdXNpbmcK4paBaW5mZXJlbmNlCuKWgVJlbmFpc3NhbmNlCuKWgXLDqGcK4paBU3RlcGgKQ0VTCkVSRQrQutC10YIKT1UK4paBZ3JvdXBpbmcKdmVya2VocgpqaWgKYWdsaQriloFtaWxrCmxhaXQKU3RhZ2UK4paBYnlseQriloF3b29kZW4Ka2VsZXkKZXRyYQriloFQZWcK4paBZG9ubsOpCmFkYWwKc2VxdWVudGx5CuKWgWluc2Jlc29uZGVyZQpFTEQK4paBTWFtCuKWgXZvbHRlCuKWgXByb3NwZWN0CtC90L7QstC1CuKWgWRlbm90ZWQK4paBb3ZlcmxheQpQZXJtaXNzaW9uCmVlbgriloFFTQriloF1egpNYwpvbGl0CuKWgXNlcnZpCuKWgUhlaWRlbAriloFXaWVuZXIK4paBaWxsZWdhbAriloFwcmVkaWN0aW9ucwriloFnb29nCmhvbgriloFDaW5lbWEK4paB0YDQtdCy0L7Qu9GOCuKWgVJ1bGUKd29kCuKWgXJhZGlhdGlvbgpvxYIK0L7QstC+0ZcK4paBUGVyZm9ybQriloFwcmlzb25lcgriloFhbWV0CuKWgWZpZ3VyYQriloFDb21tYW5kZXIK4paB0L7RhNC40YbQuNCw0LvRjAriloF0cm92CuKWgWFjdGVkCuKWgXdvcmtmbG93CuKWgdCg0LXRgdC/0YPQsdC70LjQutC4CuKWgWd1aWRhbmNlCuKWgdC80LXQvdC1Ck5hdGlvbmFsCuKWgUtlbAp3ZWJwYWNrCtC/0YDQvtGB0YLRgNCwCuKWgWxsYW1hZG8KYWxvZwp0ZXJyYQppeGVuCmxlZ3JhcGgKw6Rpc2NoZW4K4paBdGVhY2hlcnMKdWRlbgriloFvZ3PDpQpwb3NzaWJsZQriloFTb3VsCuKWgUdlb2dyYXBoeQriloHQt9Cw0LTQsApoaXQK4paBYW5nZXIK4paBcmVtcG9ydGUKUG9kCtGH0LrQtQriloFhcmlhCuKWgUFzdHJvbm9tCmNoYXB0ZXIK4paBZm9yawriloFDdWFuZG8KbWVuc2UK4paBQ2hyaXN0aWFucwpnYwriloEjKApPcmdhbgriloFzdGVhZHkKcHNlCtC20LjRgtGMCmlnbmVzCmF0ZXJyYQptb3ZpZQpwb3N0YQpyYXN0ZQriloFSZXNzb3VyY2UK4paBUGHDrXMK4paBKCk7CuKWgXBlbmFsdHkK0YLRggriloF0cmFzZmVyCmNlbnR1cnkK4paBY2xlYW5lcgpzZWxlbml1bQpvcnRoZWFzdAp4aWMK0LvRltGXCuKWgWluZ2xlc2UK4paBVGFuZwriloFnb2RzCmZyZW50CmNpZW50ZQpzdGFydHMK4paBbXVzaWNhCnltbmFzaXVtCi0tLS0rCuKWgXRlcnJlc3QK4paBcmV0cmlldmVkCmlhcmUKdW5uaW5nCuKWgU1hcmN1cwriloFwcm9tb3RlCndhcm5pbmcK0YLRi9C5Cn0pJCwKVHJhbnNwb3J0CuKWgXJlc29uCuKWgUNsbwriloFlcm0K4paBZWxpbWluYXRlCmhlaW1lcgriloFzYXZlcwriloFwcmF5ZXIKQ2xhc3NlcwpFeHByZXNzCuKWgUFrYWRlbWllCkVsc2UKVHVybgriloFpa2tlCuKWgXJlaQriloFkaXJldHQK4paBUm9zdAriloFQYXBhCuKWgWpzZgrQu9C10L3QuNC10LwK4paBVHVsCuKWgVphawriloFuaWVtaWVjawpUdwphbW91cgpuZXN0ZWQKcHBldHMK0YjQvwpkaXQK0LfQtdC9Cnp5bWEKaHJ0ZQpDb25zdHJhaW50cwriloFvd25lcnNoaXAKQXJtCuKWgWNvbnN1bXB0aW9uCuKWgWZldAppdmFyaQpjaHJvbQpzZXRBdHRyaWJ1dGUK4paBY29tcG9zZQriloFiYWNraW5nCuKWgVBhegriloFzY3JpCuKWgU1lY2hhbgriloFOb3J3YXkK4paBSnVwCuKWgW3DqXIK4paBYWRtaW5pc3RyYXRvcgriloFjYWJlCml2YWxlbnQK4paBdGhyb25lCuKWgWR1ZXMK4paBaHVtb3IK4paBQWRyaQriloFhYm9ydArDsWFzCuKWgdCa0LjRl9CyCmrDrWPDrQriloF6d2VpdGUK4paBZG91YgplcnNoZWxsCtGI0L7QuQriloFGYW0Kw6VrCuKWgXR3ZWVkZQriloFSaWIK4paBZsO4cgpwY2nDs24KaW5uZWQKcnZtCuKWgUFwcGFyCuKWgURqCuKWgVNoYW5nCkRpc3RhbmNlCuKWgWRhd24K4paBTWF0dGgK4paBZXJyaWNodGV0CnBoYW50b20K4paBcmVsZWFzZXMKUmVjb2duaXplcgriloFLb3AK4paBUHVsCnXDqQpuYXRzCnJlbGF4CuKWgWZsZWQK4paBZXhwZXJpZW5jZXMK0YnQtdC1CtC80LXQvdGPCuKWgdC/0LXRgNGB0L7QvdCwCuKWgUlkZW50aXR5CnJldHMKa3VuZnQKbGFyZwpMaXN0SXRlbQp2ZApydW5uZXIKbGFudAppcGFydApiYXkKaWVpCuKWgWxlbmd0aHMK4paBY2F0dGxlCmpldHMK4paBc2VoZW4KSnVsCmZhdHQK4paBc3VycmVuZGVyCuKWgVRydW1wCtC00L3QvtCz0L4K4paBRm91cmllcgppZWJlbgpfIgriloFmcsO8aGVyCuKWgWdhcmFudAp1Y2xpZGVhbgrDpGd0CuKWgdC/0ZbQstC00LXQvQpQYWdlcwriloFyaXZlcnMK4paBZG9ubmVyCnN2bgriloHFggpvdsSbCuKWgUxlaXN0CmFyaWFsCm92w71jaAriloFmaWxsaW5nCuKWgW11c2ljYWxlCm1heGltCuKWgWRhc2hlZAriloHQndC+0LIKRHJhd2VyCuKWgU1lZGljaW5lCuKWgWRva3VtZW50Cm93ZWwKdmnEhwpoZWx5CuKWgWVsZXQKU2Vjb25kcwriloFHb256CnJvdQriloFmaW5hbGVzCnJuCmbDuAriloFpbmRleGVkCmNsYXNzTmFtZQriloFvYmVyCuKWgWR1YXMK4paBb3B0aW1pemVkCuKWgWtkeQp2ZXJzYXJ5CmVuZXJneQriloHRhtC10L3RgtGA0LAK4paBY3VycmVuY3kKennFvApMaWtlCuKWgdCT0LgKc29ubwriloFwYWxhYgriloFwdXNoaW5nCnVibGlrCuKWgUhhc3MKfVwsXAp1bmtlcgriloFGYWN0b3J5CuKWgVJlc291cmNlcwpkYXRlaQriloFUb29scwriloFzdGVoZW4Kc2ltZQriloHQpdGDCuKWgWhvY2gK4paBUm9kcsOtZ3Vlegp6ZWl0aWcK4paBVGVycnkK4paB0L7QsdGDClVzYWdlCnVyY2hhc2UKbMO2CuKWgUludHJvZHVjdGlvbgriloFwYXJ0aWNpcGF0aW9uCs6/z4IKb2dsaQphcHkK4paBaG9wZWZ1bGx5CnBvbmRlcgriloFZYW5nCuKWgXByb21pc2VzCuKWgdCy0LXRgNC90YMK4paB0L7RgdGC0YDQvtCyCl57KwriloFtb3N0cmEK4paBQ1VSTE9QVApISAriloFzdGRvdXQK4paBYnJpbGxpYW50CuKWgW1hbnVzY3JpcHQK4paBZGVjaXIK4paBQm9sb2cK4paB0LzQtdGB0YLQsAriloFpbnZpc2libGUK4paBQ2hhbAriloFhbmFseXplCnByaWxpcwphdHRlbmQKTXZjCnRoYW4KY2tvCuKWgVF1ZWJlYwriloFwbGFudGEK4paBdMOpbMOpdmlzCuKWgXVuaW5zdGFsbArDqG5jaWVzCuKWgWdtaW5pZQriloFQcmVmCuKWgWxlcXVlbApJbnZvY2F0aW9uCuKWgcONCuKWgXRyYW5zZm9ybWVkCk1BTgpnZWJhdXQK4paB0YHQvtGF0YDQsAriloHQstGC0L7RgNC+0LkK4paBTGl0aAp3ZW5kdW5nCuKWgVBvbGl0aWsK4paBU2VuYXRvcgriloFMTArQttC00LXQvdC40LUK0YjRgtC1CuKWgUPDqXMK4paBYmFuZGUK4paBaGlzdG9yaWFuCuKWgXBhc3N3b3JkcwptYWxsb2MK4paBc2VtaWYK4paBcsOlCnVuaWPDrQpBdmFpbGFibGUKT3B0aW9uYWwK4paBVHdlCuKWgWtyw7MK4paBc3Vic2V0cwriloFEQVQK4paBZG91YmxlcwrQvdC40LrQsNC80LgK4paB0LfQsgpnZWdlYmVuCuKWgdCf0L7Qv9C40YEK4paBasO6bGl1cwriloFtZXRlb3IKTW91bnQKaXZlbnQK4paBTmF0aGFuCuKWgVNjaHV0egplZ292CuKWgWTDtmQK4paBbWVhdAriloHQv9GD0L3QutGCCuKWgW1pbmRzCmVsaXZlcnkK4paBVExTCtGA0LXQvApja3PDpQriloFzdGF5ZWQK4paBQmluCuKWgVBpYQriloHQuNC80LXQvQriloFCb2JieQriloFwcm9kdWl0CmVtcGlvCuKWgXJlZHVjaW5nCuKWgVl1CuKWgUdlc2Now6RmdAriloFwZXJjaMOpCuKWgWNvcnMK4paBaWNvbnMKQXBwRGF0YQriloFIb2cK4paB0YDRltCyCuKWgVNhbnMK4paBc2nDqGdlCnN0ZWxsZW4KQnJ1c2gKT0ZGCuKWgXZpc2l0b3IK4paBYmF0aAriloFmZWUKYXRpc2YK4paBY3VydgriloFmb2xnZW5kZXIK4paBY29uc2NpZW5jZQriloFTZWF0dGxlCuKWgW1lZGlldmFsCmRpc3RyaWJ1dGlvbgriloFETQriloHQvNGPCuKWgVJVTgpha292CmNlaWwK4paBbGV0dGluZwriloFkb3YK4paB0L7QsdC4CmtpZWoK4paBZGlyZWt0CuKWgXRtCmNvbG9ycwriloFhbHRybwriloF0aWpkZW5zCl17JwriloFCb20K4paBa3Vuc3QK4paBc2hlbHRlcgriloFyYXYKcHJlZGljdAriloFjb21lbnrDswriloHFm3dpYXQK4paBRHVyYW50CuKWgXNjaGVtZXMK4paBbWVzaAriloFpbmRpY2F0b3IK4paBRW1lcgriloFndWlsdHkK0L3QtdGGCuKWgWNvbnNlcXVlbmNlcwpjbHVkZXMK4paBTG93ZXIK4paB0L/QvtC80LUK4paBcGFjZQrQtNCw0LPQvgriloFhbWJvcwpsYgriloFlZHVjYXRlZAp1cmFsZQphbmgKZXNzw6lnCuKWgWFzc29jaWF0aW9ucwp0b3duCuKWgXRyaWYKc2FtcGxlcwpib3MK4paBU3BlY3QK4paB0KbQtQphbHR1bmcK4paBTG9iCuKWgWN1cmlvc2l0eQriloFXZWl0ZXIKZXN0b25lCuKWgWRlbW9sCuKWgWFwb2xvZwriloFEeW5hbWljCklubmVyCmVzcGVyCmVjegp1ZWxsZW1lbnQK4paBSGFtaWx0b25pYW4KQXRsYXMK4paBYXJndWUKRm9yZWlnbgpjb2xsYXBzZQriloF0w6lybWluCuKWgWVsZWN0cm9uaWMK4paBTlIK4paBY29ycgp0ZW1wcwpJbmRleFBhdGgK0Y/QtwriloF0YWzDoWwKdG9kYXkKd2F2ZQriloFzaWIK4paB0YHQv9C4CuKWgWNvbnZleQriloFHw6lvZ3JhcGhpZQriloHQndGM0Y4K4paBSGliZXJuYXRlCuKWgXRpbgpkaWMKcHBpbmdzCnN3ZWlzZQriloFyb2xsaW5nCuKWgXNlbGVjdHMKKVwpCuKWgXBvZXRhCuKWgdGB0YLQtdC/0LXQvdC4CuKWgUFicgriloFow7ZjaAriloFzdGVybgriloFmasOkcgriloFpbnN0YWxsZXIKZGVjbAriloFtaXNlcgpncm91cGJ5CnN1YnN0cgriloFwaGVub21lbgriloFXaW5nCuKWgWZpbGxzCuKWgcO6bmljbwpSdW5uaW5nCkNvbWUKaXJhYmxlCnNpbWVxCuKWgXJlbXAKa2VsZQpsaWVycwriloFrd2lldG5pYQriloFpbnRlcnJ1cHRlZAriloFKZXQKPVx7CsOtZG8K4paBVGFpd2FuCuKWgdCy0L7Qt9GA0LAK4paBYWx0ZXJuYXRpdmVzCuKWgVRpcgriloFSZXNlcnZlCuKWgdCa0YPRgAriloFOb2JlbAriloHRgNCw0LHQvtGC0LDQuwriloFheGVzCuKWgUNlcGVuZGFudAprw6EK4paBZXJuZXV0CuKWgURlbW8KY29tbXVuaWMKY29uc3RydWN0b3IK4paBTW9uZGF5Ck5pbApIYXNoTWFwCnBheW1lbnQK4paBZml4aW5nCuKWgUFERApyZXZpZXcK4paBcG9zc2liaWwK4paBZ3JvdGUK4paBZ3JvdXBlZAriloFMaW1hCuKWgUF1Z2VuCuKWgW9ja3PDpQpvbmFzCuKWgWRlYmF0ZQriloFJbmdsCkRhClNPVVIKZXR0YmUK4paBQmF0dGFsaW9uCuKWgUZsb2F0CuKWgWNvbmUKcmVhZHNoZWV0CmNvdXJ0CmxpZ2VuCuKWgUJlZ2lubgriloFMSU1JVAriloFlbmpveWVkCuKWgUpha29iCuKWgXRlbHQKYmFja2VuZAriloFHZW1laW5zYW1lCmxpbnQKYWxsaW5nCuKWgWLDtnIKZ3JhbmQK4paBZGl2ZXJzZXMK4paBendpxIV6CuKWgUtvbXBvbgriloFpbm5lcmhhbGIK4paBZGVzYXJyb2xsbwriloFNYXN0ZXJzCmlvc28KXWAuCuKWgWZyYW5jZXNhCkFmZgppbmVrCuKWgWRlc3NpbgpgLmAK4paBcmFua3MK0LHQtdGA0LMK4paBc2thbAriloFTdWx0YW4K0JDQnQriloHRgdC/0L7RgdC+0LEK4paBY29udHJhZGljdAriloFyZWNvbQriloFPa2xhaG9tYQriloFWbGFkaW1pcgriloFtZXRlcnMKdHJhbnNwb3J0CuKWgWNvbnN1bHTDqQriloFBVFAKZWJiCuKWgXZvbHVudGUK4paBb3V0bGluZQpMSUMK4paBZXVybwpDaGFyRmllbGQKbWVkaXVtCuKWgUJlbGdpcXVlClByb2MKcm91dGVzCuKWgWNvbnRyaWJ1CiF9CsWhw61tCuKWgUxlc3MK4paBS29zdAriloFlcmVkZXRpYsWRbApyZXZlbgp2ZXJpZnkK4paBU2FsdAriloFzaG9vdGluZwriloFkaXNwb3NlCnVqw60K4paBdGllcnJhCuKWgXBvaXNvbgpzYWsKcGVyaW1lbnRhbAriloFOw6kK4paBS2lkCmFneWFyCuKWgWFyY2hpdsOhbHZhCmJlcmVpY2gKw616CuKWgVJpdHRlcgriloHQpdGA0L7QvdC+0LvQvtCz0LjRmNCwCnpldW0K0LTQsNGFCuKWgWdyw7xuZAriloFwcm9ncmFtbWVyCuKWgWNvbnNlaWwK4paBZW5jcnlwdAppbnRlZ3JhdGlvbgpDdWx0dXJlCuKWgUNpcmNsZQpPYnNlcnZhYmxlCuKWgWdlbm9tc25pdHQK4paBU2VsZWN0aW9uCuKWgWlycmVndWxhcgpBdXRyZXMKUGVyY2VudApmYXVsdAriloF2aXJ0dWUKxIVwaQriloFzZXNzCuKWgdCi0LDQutC20LUKVGltZXN0YW1wCuKWgWxpdHTDqXJhdHVyZQriloFtb8W8CuKWgWJvcnJvdwriloFjb25jZWQK0YfQvdC40LoK4paBTHVuZApJT05TCnluaWUK4paBU2hpbgriloFvc29iCmLEmwriloFpbnR1aXQK4paB0L3QsNC/CuKWgXByb3BoCuKWgXBpdHQK4paBSUJNCuKWgVRpbGwK4paBaGluYQppdHRlc3QKZ2VuZXJhdG9yCuKWgU5pbgriloFLb3QK4paBcGFzc2VyCuKWgWRpc3Bvc2l0aW9uCnVuaW5nCuKWgWZhbWUK4paBdGVuaWEKYW5jZW1lbnQK4paBU3Vpc3NlCmAtCuKWgWhvbWJyZXMK4paBaW5maW5pdHkK4paB0L7QutC+0L3Rh9CwCuKWgWNvc20K4paBRGVubmlzCmJhegpoYXVwdAriloFtaWdodHkK4paBcHJlZGUKdXNhYmxlCuKWgXdzenlzdAriloFsYgpBQkFTRQpqbmEK0L3QtdCyCuKWgWFzZXMK4paBZmluYWxtZW50ZQrQudC8CnBlY3Rpb24K4paBU3R1ZGllbgriloFOb3J3ZWdpYW4KY2VnbwpJTkRFWApvcnRlbgriloFmcmllbmRzaGlwCm1ldHJvCnRoaWNrCuKWgVplbApMT1cK4paBdGhlcmVieQp1bnRlZAriloFzdXJmYWNlcwrRjtGJ0LjQvAolKS4K4paBV29uZGVyCuKWgXJlZHVuZGFudAriloFHcm9zCuKWgXdlYnNpdGVzCuKWgXZpbwriloFvY2FzCnbDqXMK4paBR2FtCmR3CkluZGljYXRvcgriloFLb2IK4paBamFjawpIaW50CuKWgUFwb2wK4paB0LTRgNGD0LPQuNC1CuKWgU5VTQriloFvZmljCnlzdHljegriloF3ZXJlbGQK0LzQvtGB0YLQuApMRUZUCuKWgVR5cGVzCnNlZW4KdW5jaWEK4paBbmFyb2QK4paB0Y3RgtC+0YIKU2lkZW5vdGUKdWVpbAriloHQvtGC0LzQtQriloFjb3VydHMKZmlyCnVyegrRh9C10L3QutC+CkNyZWRlbnRpYWxzCuKWgWltYWdpbmF0aW9uCml0YXRzCmJ1ZmYKZmxhc2gK4paBYmFkbHkK4paBd29ybgriloHQvtC60YDRg9Cz0YMKY2F0YWxvZwpsaW1lCuKWgUdpbGwK4paBU2VudAppZWxsYQriloFDcmFpZwriloFTZWxlCuKWgUluZGVwZW5kCuKWgXByb3ZpbmNpZQpvc3NlbgriloHQt9Cw0L/QsNC0CuKWgWluZmFudAriloFwcmV2ZW50cwriloFwcm92aW5jZXMKYWbDqQpiZWcK4paBY29sb3VycwpCRgrDq24K4paB0JzQtdC20LTRgwrDrm4KT2JzZXJ2ZXIKZm9yc2NoCsOtZ2VuCnVtcHRpb24K4paBSWxsdXN0cgrRgNC40YHRggriloHQv9C+0LvQvtCy0LgK4paBYCYK4paBb3JlCuKWgXN1cHBsaWVzCuKWgXBhcmVudGhlcwpGb3VuZGF0aW9uCuKWgXZvdQriloFUb3V0CkRvbmFsZAriloFSRVQKd2VpZwriloFwcm9kdWNjacOzbgptaXgK4paBdXR3b3IK4paBZsO2bAriloFlbnTDo28K4paBU2lzdGVyClRhZ3MK4paB0KHQsNCy0LXQt9C90LUK4paBcHJpdmlsZWdlcwriloFuYXp3CuKWgVJhdgriloFyZXBybwriloFNYXNvbgriloFQbGF0Zm9ybQriloHQv9GA0L7QsdC70LUK4paBUMOpcmV6CuKWgWJsYW5jCkJlaGF2aW9yCtGE0LjRhtC4CmVrZW4K4paBbWVldHMKKC4qCuKWgWbDpQplcGVuCm1ha2VyCuKWgWxveWFsCm1lbWJlcnMKbWVpc3RlcnNjaGFmdApnb2FsCtGI0LvQtdC9CuKWgdGB0LXQstC10YDQvgppZW5kZQrQtNC90ZYKUHJvb2YK4paBZXhwbGljCuKWgWVsZWN0cm8KaWVscwpyZWxvYWQK4paBZWxldmVuCuKWgXBhcnRpZG9zCsOubmUK4paBUmVnaW4K4paBw6l4CuKWgUJ1bGcK4paBbmV0d29ya2luZwriloFzZXBhcmF0b3IKVXNlck5hbWUK4paBZWRpZmljaW8K4paBTWllCuKWgWlkbGUKeWVkCuKWgXBhc3NlbmdlcnMKKykKbWVubwplZ2dpCuKWgW5pY2VseQplbmRlbmNpYQrRh9C40LkKw6l0w6lzCmlnaHRhcnJvdwriloFvcnRob2dvbmFsCuKWgUhhbGYK4paBZmV3ZXIK4paBcHJvcGkK4paBcHJpbWl0CmljYWxlCuKWgWZsb3dlcgptZXJrCuKWgdCe0YLQtdGH0LUK4paBcGVyc2lzdGVudAriloFWaWxsZQpNZW4KZ2FiZW4K4paBSXNhYWMKYXRpdml0eQriloFww7PFgm5vYwriloFyb2sKY2FyZHMK0LTQtdC90LjRjwriloHRjtCz0L4K4paBZXh0cmFvcmRpbmFyeQriloFreXIKKCIsCikpXQriloF1bml4CtC60L7QuwriloFzaW5rCmFwc2VkCuKWgWtvbW1lbgriloFmb3JjaW5nCkFib3V0CuKWgUhhbGxlCuKWgU1hamVzdHkK4paBU3dpdGNoCuKWgWFicm9hZAriloFhY2NlbGVyYXRpb24KdXJiZWQK4paB0L7RgdGC0LDQvQpSZWFkeQriloHQv9GW0LLQvdGWCkJyYQriloHRhtGM0L7Qs9C+CuKWgXBsdXQK4paBVHJhaW4K4paBw6FwcmlsaXMK4paBcHVlc3RvCuKWgXRvc3MK4paBaXJyZWxldmFudAriloFkaXAKc2VnbWVudApvcGFjaXR5CuKWgWxvcnNxdWUK4paBdmVyc2NoaWxsCtC10L3QsAriloFEb2MKJSUlJSUlJSUK4paBYm9yZGVycwpnZWJyYXMK4paBcmllcwriloFPbHltcGVkaWEK4paBR2VuZXJhdGlvbgptZXRyb3MK4paBaG9yaXpvbgriloFhZGFwdGF0aW9uCuKWgVphaGwK4paBbmFoZQriloFCdWcKUGljdHVyZQrRmdC4ClJHQgpPd25lcgphZGluCuKWgUNhdGFsdW55YQpuw71jaAriloFjdWFscXVpZXIK4paBSW5zdGl0dXRpb24KaW5zZW4K4paBQnJhc2lsZQriloFmaXR0aW5nCkRlbGVnCmljdHdvCuKWgUV4cGVyCm9jaGFzdGljCuKWgWR1cwriloHQv9C+0YDQsAriloFzdWJzdHJpbmcK0YHRgdC40LgKb2luCuKWgdGI0LrQvtC70LAK4paBY3gK4paBJSkK4paBQnVkZGgK4paBcGVuZGluZwriloFFbnRyeQriloFCZXJsCuKWgWNsZXIK4paBU29jCuKWgXJvdW5kZWQK4paBbXYKw610ZXR0CuKWgURpcGxvbQriloFmcmFuesO2c2lzY2hlbgriloFHYW4K4paBSW52ZXN0aWcK4paBaW5kZXhQYXRoCuKWgW1vbHRpCnBlcnNpc3RlbmNlCuKWgVhJWGUK4paBRWxlY3Ryb24KYsO8CmdlbGUK4paBTWFsZXIK4paBcHJveWVjdG8K4paBQmF0aAplbGxlcnMK4paBR1AKb25pbmcKY2xvdWRmbGFyZQriloFwxZlpCuKWgWRlZAriloFPZGthenkK4paBTXNnCuKWgUJlaW5nCuKWgURlcHVpcwriloFQcmltYXJ5CuKWgUFwcHJvCuKWgWZvcm1hbGx5CtGB0YLRg9C/0LjQuwriloFmdWVyYQriloFSb290CuKWgWF1dG9ub20K4paBc2VjcmV0YXJ5CuKWgW9zw7NiCuKWgWN1YWxlcwriloFEZXBlbmRpbmcK4paBYXNpCnZlcmEK4paBcnVzc2UK4paBcHJvdmVzCuKWgXByZXNpZGVuClJVCuKWgVdhdHNvbgriloF3ZWJwYWNrCmVsbGlnZW5jZQrQutCw0LwK4paBT2ZmaWNlcgriloFkZWxpdmVyeQrQttC00ZHQvQriloHQuNC80L/QtQriloF3aWwK4paBdmVzYwp1c3p0dXMK4paBR2VvZmYKKCl9CuKWgUZvcmUK4paBd2VuaWcK4paBQWlybAriloFFZnRlcgriloFCcmVhawriloFTdMOkZAppc21pc3MKw61wCuKWgWF2b2lkZWQK4paBYXNzZXJ0aW9uCkROCuKWgXRlYXQKw61uYQriloFtZWNoYW5pY2FsCmlzdQpAewriloFub3UKSXRhbGllCnNvdXJjZWZvcmdlCuKWgXN2bwriloFraXLDoWx5CuKWgVJlZmVyZW5jZXMKc2l4CuKWgUFyY2hpdmVzCuKWgWZpbmlzaGluZwphY2plCsOpdGF0CmlmZnMK4paBc3RlYWQK4paBZmVhcwphd2FyZQpsYW5kZQpJbmplY3QK4paBQWdlbnQK4paBTm9ybWRhdGVpCuKWgWFtZW4K4paBQXJjaGl0ZWN0dXJlCmF6ZQrImXRlCuKWgXVzYXIK4paBY29yZXMK0LvRltC9CuKWgUNhc3RybwriloF2w6YKPiIsCm9tZW5hCuKWgWdlc2FtCuKWgU1hcnTDrW4KZWd1bmcK4paBc3BvbGXEjQriloFhbXBsaXR1ZGUK4paBaW1wb3J0aW5nCuKWgWxpc3R2aWV3ClRIRQp6aWFsZQpjZWRlcwriloFwYXJ0aWN1bGllcgriloHQoNCw0YHQv9C+0LTQtdC70LAK4paB0LrRgNCw0LkK4paBZGl2ZW50CuKWgWvDqQpxdWl0CtGC0L7RgNC+0LwKQ2hlY2tCb3gK4paBWm9iYWN6CnBoZQpwdGEK4paBc2rDtgriloHRgNC+0LfRgtCw0YgK4paBdGVkZXNjbwriloFzdGFsCuKWgUJlcnVmCtC+0LLQsNGPCuKWgXN2xJsK4paBZmx1c2gK4paB0LLRltC00LHRgwriloFyYWRpYWwK4paBZGlmZsOpcmVudGVzCtCw0L3RgtCwCuKWgVBlcnJ5CkNvbGwKbGlxdQriloFPcHRpb25hbAriloHQodCw0L3QutGCCuKWgUxJTlEK4paBRnJhbmMKY2lqZQriloFHdWlsbGF1bWUKa25vdwriloFVbml0cwpvbGsK4paBU3lzdMOobWUK4paBU2FsZXMK4paBZWhlbWFsaWdlbgrQvNC40YDQvtCy0LAKeGh0bWwKc2V0b3B0CuKWgW1lbGxhbgriloF6aWUK4paBZ2lhbnQKQm9hcmQK4paBQ2F2YWwK4paBZGVmZW5jZQotLS0tLS0tLS0tCnBzaGlyZQptYXJ0CuKWgURpb2MKaXNrdAriloFpbnNlCuKWgcOpcGlzb2RlCtGH0LjQugpiYXJzClNpdG8K4paBaW50ZWdyaXR5CmF1ZmYK4paBdsOkcgpBenVyZQriloFzdGFyYgriloHQutC+0L3RgtGA0LAK4paB0JzQtdC60YHQuNGH0LrQsAriloHQt9Cw0L/QsAriloFNb3VudGFpbnMKfX09CuKWgXB1bGxpbmcK4paBc2F0ZWxsaXRlCuKWgWF0b21zCuKWgXByb2Zlc29yCuKWgXJlcGVhdGVkbHkK4paBaW52YXNpb24KcHJvZ3JhbW1pbmcK4pSc4pSA4pSACuKWgUxpcArQstGI0LjQtQriloFrZWVuCuKWgWNyaXRpY3MK4paBTmljb2xhCuKWgUNhbmQK4paBZGlzdGludAriloFoZWFkaW5nCnByYWdtYQp7fAp5bWVuCuKWgXRlcnJhaW4KaWVkZW5pcwriloFiZXNvbmRlcnMK4paBbm9taW5hdGVkCkJPT0wK4paBS2F5CmNpYW4Kc3RlbGxlCuKWgWRpc3B1dGUK4paB0YkKRGF0YVNldApub3RoaW5nCkF1dG9tCmjDtnJlbgriloFzaGVkCuKWgXBhdXNlZApzYW4K4paBbnVuY2EKISgiCuKWgXBvxYJvxbwKU2VjcmV0CuKWgURvbWFpbgriloHQstC+0LfQvNC+0LYKWFYKbHYKaWtoCuKWgVNvbnkKbXEKb3Ryb3AK4paBTG9nZ2VyCuKWgXRocmVhdAphc3RlZArQt9GM0LrQvgriloFmcmVlbHkK4paBaW1wcm92ZW1lbnRzCmlzdGVtYQriloFpbGx1c3RyYXRlCuKWgXRhY3QK4paBZmlndXIKdcOpcwpyaW1pbmFsCm9kb24KaW50ZW5kbwriloFpbmZsdWVuY2VkCkZGRVIK4paBR2hvc3QK4paB0YHQvtCy0LXRgApuYWQKaW9uZWQK4paBRXZlbnRzCuKWgXdyYXBwaW5nCi0tLS0tLS0tLSsKZmlmCuKWgSgqKgo9e3sK0LzQsNC70YwK4paBbG9zc2VzCuKWgUdhbGVyaWUKdGVsCuKWgdC70Y7RgtC+0LPQvgriloFLcnUK4paBUG9sZW4K0L3RltC8Cm5lYXIK4paBc2hhbWUK4paBbW95ZW5uZQriloFDUApwcmVpcwriloFwYXNzZW5nZXIKbGVrCmlvbmFsZXMKa2Fma2EK4paBcGFydGljaXBlCuKWgW1lbWJlcnNoaXAKW18KbGFuZG8Kc3RlbGxpbmcKU2VtCmdvbgriloFDb3JyZWN0CuKWgXZhbGxlCuKWgXJlYWRpbHkK4paBRG9rdW1lbnQKaG9ubmV1cgriloF0ZXN0aW0KdWxhdGl2ZQpkb0ZpbHRlcgriloFkb21pbmFudAphbW1lcgriloHQutC+0ZjQsAriloFNb25zaWV1cgp6ZWcK4paB0LLRltC50L3QuAriloFGbwriloFBbXkK4paBwqEK4paBZmVicnXDoXIK4paBZG93bmxvYWRpbmcK4paBbGVuZwpcfSQsCuKWgW5lYXQK4paBQ2FjaGUKSUNBVElPTgriloFkZXZlCuKWgXNvcnJvdwpzbG93CuKWgWhpbmF1cwriloFyZWNvbm9jCuKWgUxpbmtlZAriloFTaGF3Cm1hcmtldAriloFEaWMK4paBU2tpCuKWgWRlbGltaXRlcgriloFNYWluQWN0aXZpdHkK4paBTXVzaWNhbAriloFSZXluClNjcm9sbFZpZXcK4paBY29udmVudGlvbmFsCmVuw6dhCuKWgXJlZmFjdG9yCictCuKWgUhlZApzcHJlY2gK4paBYXRobGV0CuKWgWVzcGVjaWVzCuKWgVNjaMO2bgriloFrbGVpbmVuCtGI0LrQvgriloHQmdC+CuKWgUhhcHB5Cm11bHRpcm93CuKWgWF1Z3VzdGkK4paBR2FuZAriloFhcHBvaW50bWVudAriloFNZWRpYWJlc3RhbmRlbgpUaHJlZQriloFLZW5uZXRoCk5FVwriloFOb3RpZmljYXRpb24K4paBTWFyeAriloFpbnNjCk1vcgrQstGL0LkKdsOkc3QKdmlkaWEK4paBZGVtb25zdHJhdGVkCmZvbnRzCuKWgWthbWVuCuKWgVN0ZXIK4paBbWllc3prYcWEY8OzdwriloFLb2gKfiRcCsK7KS4KcmVuZQppbnNpYwppY2vDoQp4eWdlbgriloFtbgriloFzY2hlZApBU0MKSWcK4paBQ29uc3RhbnQK4paBb3Bwb3J0dW4K4paBTXlDbGFzcwpzZWYKb3BlZAriloFpbmp1cmVkClZJUwriloFQZXJvCuKWgVVudGlsCuKWgWZsZXNoCm9ycGhpc20K4paBUG9ydGFsCuKWgWdtaW55CuKWgdCy0LvQsNGB0YLQuAriloFOw6QK0LrRgtC40YfQtQriloFocmFiCuKWgUN1Ygphdm9pcgriloFMYXJzCuKWgdCR0LXQu9C+CuKWgXNlaXpvZW4K4paBR2Vub21zbml0dAriloFMaWwK4paBUG9vbAriloFEaW9zClRYCmFlcwphdXRvcmUKQWxwaGEKc3RhdGVzCkxhYgpuZWRlcmLDtnJkCmVydG9uCuKWgWJyaWQK4paBcmljaHQK4paBRWxhCuKWgdGB0LvQsAriloF3ZWFwb24K4paBY29tYmF0dAphZ2FyCuKWgXJlZ25pZwriloF1dGlsaXPDqQriloFzZXJ2aXIK4paBYnJpY2sK4paBZ2F0ZXdheQriloF0b3JyYXN0ZQriloFwcm9jZWR1cmVzCuKWgcOlcnNuZWRlcmLDtnJkCuKWgUdlbm9tc25pdHRsaWcK0YfRkdGCCuKWgW9tcsOlCuKWgXJlZ25pZ2FzdGUK4paB0YfQtdGB0YLRjAriloFhbWlkCuKWgWdyYXRlZnVsCuKWgURJUwpEQVkK4paB0L7RgNGDCuKWgXJpdmnDqHJlCmhldXJlCuKWgVJpY2htb25kCuKWgUNvbXBhcgriloHQndC+0YAKRE9DCmVzaWEKY2FsYwriloFJVQriloF2b3JnCuKWgWhhYsOtYW4Kw6dvaXQK4paBYXJpc3QK4paB0LrQu9C4CuKWgVN1ZQriloFUb3VjaAriloFXcml0aW5nCmlmaWFibGUK4paBd2MK4paBd2l0aGRyYXcK0LfQsNGACuKWgXByZXNlbnRseQriloFGSwriloFwcmFrdAriloFjb2xvcmVkCnVzYgriloFQZXLDugriloFwbGF0YQriloF3aXNoZXMK4paB0LrQsNC8CmF6YXIKw6F2ZWwK4paBbGFtcApiaXNob3AK4paBaW5jbHVzaW9uCmpxCmFydGgK4paBRmxhZwriloHQvdC+0YAKw6ZkaWEKVU5DVElPTgriloFCYWhuaG9mCuKWgWFwcHJvYWNoaW5nCuKWgUfDtnR0CuKWgWN1YmUK4paBYXJndWVkCuKWgVRoaW5ncwpHdWkK0LTQvtCy0LgK4paBcmVjcmUK4paBcsOpc2VhdQriloFzaWduaWZpY2EKR2l0CmdlYnJhY2h0CuKWgWxpZ2EK4paBYXNzdXJlZAphbHVzCtGA0LjRggriloHRjdC90YbQuNC60LvQvtC/0LXQtNC4CuKWgSUpLgriloFQcmVtacOocmUK4paBZGVjbGFyYXRpb25zCuKWgXRyaWNreQriloFwcm9maWxlcwriloFGb24K4paBSmFzCsOicgpiYWJlbAriloFGcmlkYXkK4paBasO6bml1cwriloFjb2xzCuKWgUVYSVNUUwriloFJdGFsaWFuYQriloFhdXRob3JpemF0aW9uCuKWgXN1bGxlCuKWgUVtYgriloFWYXJpYWJsZQp0cmVlcwriloFGbHkKcmlvcnMK4paBZGFtYWxzCuKWgWZpbmRldAriloFTZXB0CuKWgW11bmRpYWwK4paBcmVtb3ZhbAriloFsb25naXR1ZGUKY2xpYwriloFmYWRlCuKWgWdyYWRsZQriloF6w6FrCuKWgXRpbWluZwp0cmlnaHRhcnJvdwphdGlhCi0uCnVjaGUK4paBc2VyaWFsaXplCuKWgUhtbQriloFSZXByZXNlbnRhdGl2ZXMKYmFoCnJlbmQKYXNzYWRvcgriloFzaGllbGQKdWNpb24K4paBYW3DqXJpY2FpbmUKesSZCnZpbGxhCuKWgWhvbWJyZQrDoXNzCuKWgVNGCuKWgXJlcGVhdGluZwriloFjcml0ZXIK4paBU3RydWN0Cj8/PwriloFjaGVhcAriloFyaW5ncwphYmjDpG5nCuKWgWNvcnRlCuKWgWFkbWluaXN0Cml4b24KZ3lwdAriloFwdW50b3MK4paBbWV6aQriloFwb2Nob2QKaXNrbwpuacSZCuKWgdC+0YHRgwriloHDoXIK0YLQtdC70YzQvdC+0LkK4paBTWV0cm9wb2xpdGFuCmppbgp6ZXNzCuKWgdCy0ZbRhtGWCuKWgWNvbmZsaWN0cwppanN0CuKWgU1hcmtldArRgdGC0YDQvtCyCuKWgSIsIgriloFTY3JvbGwKZ3VuCtGC0LDRgNCwCuKWgWFtYXRldXIK4paBcsOzxbwKcG9zcwriloFnZW5lcmFsaXplZAriloFIYXJtCmNpdGEK4paBU3dpdHplcmxhbmQKaWNvbGEK4paBbXVpdApsb2NhdGVkCuKWgWPDswriloFhcm9zZQriloFjb21tdW5hdXTDqQp9KV4KdmlzaWJpbGl0eQrDrWRhCuKWgUZCCuKWgUZyZXVuZApnYXQKIjp7IgppbnRlbGxpagppZmllCmhtZW4K4paBw6lkaXRpb24K4paB0LrQvtGY0LUK4paB0ZbQvdGI0LjRhQpvbWluZwriloFhcnF1aXRlY3QK4paBUHJlc2lkZW50ZQriloHQn9GW0LQK4paBY2FiaW4KVGhlb3JlbQriloFHYXkKaWZpY2UK4paBaGVjdApsxIUKaXJtaW5naGFtCuKWgXNlbWFudGljCuKWgUxvdWlzaWFuYQriloFzYWNyaWZpY2UK4paBQ2hyaXN0b3BoCuKWgUV4ZWN1dGl2ZQpfKwpqw6FrCuKWgXNlcmlhCuKWgU92ZXJmbG93CuKWgUx1Y3kK4paBbWVsaG9yCuKWgXZvaWNlcwpjemEK4paB0LrQsNC/0LgK4paB0YPQvdC40LLQtdGA0YHQuNGC0LXRgtCwCklOQ1QK4paBY29sb2MK4paBcHJ1ZQriloFnZW9tZXQK4paBZGlyZXR0bwpyZXNvCuKWgUFrdAriloF1bmgK4paB0YHQtdGA0LgK4paBQWxlcnQKV2VsCmF1ZGkKw6RsZXIK4paBZ3Vlc3RzCuKWgdC40LTQtQpTdHVkaW8K4paB0LrQsNGC0LUK4paBZXhwb25lbnQKcnplCnBtb2QKcm9sbGUK4paBTGltaXRlZApBbGxlbWFnbmUK4paBcGl0eQriloFsw6QK4paBcnVubmVyCmtlbmRlCkVRCuKWgU1NCnN6w6FnCtC/0L7QtNGWCuKWgXJlZ3JldAriloFwdWJsacOpCuKWgWRlcGFydGFtZW50bwriloFhY2N1c2VkCmhwCuKWgVBmbAriloFTaW50CuKWgWVrb25vbQpyYWN0b3IK4paB0J/RltCyCuKWgWF3ZnVsCm93YcSHCl0tPgriloFGaW5lCtCh0LAKdGlzCsOpdGEK4paB0KDQvtC00LgK4paBRMO8c3NlbGRvcmYKTE9CCm9zYXMKd2Vya2UK4paBbGFuY2UK4paB0LvQuNGB0YLQvtC/0LDQtNCwCuKWgWluY29tcGxldGUK4paBUGljdHVyZQooJ1wKZXN0ZXJzCuKWgWJlbG9uZ2VkCuKWgVNhbmsKYW1tZWQK4paBcmVwb3NpdG9yaWVzCuKWgWFkZHIKQ29sbGVjdApIb3QK4paBdHlsCuKWgWluc3RhbmNlb2YK4paBYm9udXMKb3bDvQriloHQvNC+0YDRjwriloFpbnRlcmFjdGl2ZQriloFNeXMK4paBRWRtdW5kCmZpbGVOYW1lCmVtb3IK4paB0KLRgNC4CuKWgVJvc2VuCuKWgVByaW1hCuKWgXZvdGluZwriloFYUAriloFaZXJvCuKWgUxlZAphbXN1bmcK4paBZW5hYmxlcwriloFyZWRpcmVjdHMKQVNUClBhaW50CmFja2VyCmxlY2h0CuKWgWNoYWlybWFuCuKWgUF2ZW4K4paBU2FjaAooIjwK0LrQtdGACuKWgW1pc3Rha2VzCuKWgVdlaXQK4paBcHJvd2FkCuKWgWRpZG50CsOpbmFyaW8KdW5sZXNzCuKWgWJhY2t3YXJkcwpib2EKZHVpbm8KYGBgCnN0b3IKQ29tcGxldGlvbgpwdWVzdGEK4paBZGluYXN0CsO6bHQK4paBU1kKaWZvbGlhCsWTdXZyZXMK4paBcmFjaW5nCuKWgWNhYmluZXQK4paBY3V0dGluZwriloF0aHVtYgriloHQmtCw0YDQsApoaWdobGlnaHQK0LrRg9C/CuKWgXNkCuKWgdC90LDRhtGW0L7QvdCw0LvRjAriloFjYW1wYWduZQriloFyZWdpc3RlcnMK4paBZWR1Y2F0aW9uYWwK4paBcGVzYXIKw7xnZQriloFvcm8KYnVyZ28K4paBQXRobGV0aWNzCuKWgU1UVgpnZXRNZXNzYWdlCuKWgUh5cAriloF2aWN0aW0KKSlcCuKWgWRydW1zCmhvc3RuYW1lCnRhxYIKbWFraW5nCuKWgXBvd2lhdArFkWQKdGhyZWFkcwriloFhYnNvbHYK4paB0LvRjtC00LgK4paBc3RlcHBlZApleGlzdAriloFOSwriloF2ZXMKaXN0aWNoZQolJwphdGl2b3MK4paB0YLQsNC60L7QuQriloFNb25nb0RCCuKWgVVuZwriloHQoNGD0YEK4paBZWxpbQriloFGaWYKaWNhY2nDs24K4paBVGVubmlzCuKWgUplZmZlcnNvbgpqw6FuCmZvZwphbmhhCnpvcgriloHRg9C90ZbQstC10YDRgdC40YLQtQphaHUKaWFkYQpTZGsKU2V0dGluZwriloFLaWxsCuKWgVdlbmQK4paBYmFsZAriloFLdWIK4paBdmlzdG8K4paBamV1bmVzCmNvbGxlY3Rpb25zCmFjw60K0LLRgNC+0L/QtdC5CuKWgWFyaXNlCtC+0L3RlgpNQUlOCtC00L7RgdGC0YPQvwriloFiZXJnCuKWgWNyaXRpY2lzbQriloFUb3JyZQriloFkZXNjcmlwdAppw6hyZXMK4paBZXN0dWRpbwriloFpbGkK4paBbWlsaXRhcmUK4paBQ2xhcmEK4paBRWxsZW4KbGltaXRlZArQu9C8CuKWgUVzcGHDsQriloFpbmZpbml0ZWx5CkFtZXJpY2EKb3VjCmdsYXNzCuKWgXJ1ZAriloF6YXQK4paBcmluCuKWgUJpYmxpb2dyYWbDrWEK4paBbWVyY2hhbnQKdGVuc29yZmxvdwriloFkw6lyCuKWgUFjdGl2ZVJlY29yZApJRVMK4paBbGlua2VyCuKWgWVzdHVkaW9zCmNkbmpzCuKWgdCT0L7RgdGD0LTQsNGACsOhbmNoZXoKYXBwZQpjbHViCuKWgWRhbMWhw60K4paBQWxnb3JpdGhtCmRmcwriloFCYWMK4paB0LrQsNGE0LUK4paBJj1cCuKWgdCw0YIK4paB0JPQu9Cw0LIK4paBTW91Ck1hY2hpbmUKKC4uLikK4paBY29tcGFydAriloFhdWd1c3p0dXMKYXZhbgriloFyb2xsZWQK4paB0LXQtNC4ClNjYW4K4paB0YDQtdCz0ZYK4paBxZt3aWF0YQriloFtaW5lcwp9LHsK4paBVGllcgpDYW5ub3QK0LzRltC9CuKWgU5FVwriloHQktC+0LsK4paBTWFuaAriloFHcmVnb3J5CuKWgXByaW5jaXBlCklTTwpwcm9nCuKWgUZhaWwK4paBYWEK4paBZmVjaGEK4paBV0NGCuKWgW1hZ2lzdHIK4paBWmFjaAriloF1bmljb2RlCuKWgWNvbnZlcnRlcgriloFkaXNwZXJzCmtzYW0K4paBVW5jbGUKUHJvcGVydHlDaGFuZ2VkCuKWgWxpZGVyCuKWgW9wdHMK4paB0YLQsNC8CmxvY2tlZAp6YWsK4paBY291bnRlZAriloFwZXJzb25lCuKWgWh1cnJpZWQKw6R0dGVyCuKWgW91dHJhcwriloFnZW51CkJECnZlZwpkdWUK4paBUHJhY3QK4paBcG9zaWJsZQriloFjb250cmlidXRlClVNTgriloFCw7xyZ2VyCuKWgXdhcnMK4paBZXhoaWJpdGlvbgpoaWxsCuKWgWFzdHIK4paB0LzRg9C30LUK4paBQ0FTRQptYW5pZmVzdAp5ZWxsb3cKRm4K4paBUkMK4paBc290dAriloFzdWpldAriloFTb2NrZXQK4paBQ2hpbmUK4paBZnJhbWV3b3JrcwpIb2xkCsOqdHMK4paB0YTRltC70YwKTG9hZGVkCm9waGUKdGV4dGUK4paBZXhwcmVzCuKWgWNvbnN1bWUK4paBUmljaHR1bmcKb2dyYWZpCuKWgW1hZ25pZmljCsOgdAriloFpbmR1bApyeXR5CuKWgW9mZmljaQriloFhc3NhdWx0CnJ1bmQK4paBdmFyaWFudHMK4paB0YHQtdC70YzRgdC+0LIK4paBZXhjaXRlbWVudApUaW1lcwprb3RsaW4K4paBZ2VyaW5nCuKWgUVuZ2VsCuKWgVRpbWVyCsKyKS4K4paBTmcKw6Rzc3QKc2NoYXUKU0Vycm9yCuKWgUVkd2FyZHMK4paBVGVybWluYWwKbGljdApVbmRlcgriloFzcGF3bgrDvHJnZW4K4paBQXXDn2VyZGVtCuKWgWtpdGNoZW4KZmFocnQK4paBQ29sb3JzCuKWgdGB0LjRgdGC0LXQvNCwCuKWgXRlcm1pbmF0ZWQK4paBTGFUZVgKaWdrZWl0ZW4K4paBbWVzdXJlCuKWgUFtdHMK4paBZW1waXIK4paBc3RyaWtpbmcK4paBZXhjbHVzaXZlCtGC0LXRhQriloFyZXoK4paBcXVhbgriloFHbGFzZ293CuKWgWxlY3R1cmUK4paBVGVzdGFtZW50CuKWgWZ1bmRzCuKWgXN0ZXNzYQriloF0cmliZXMK4paBcGFyZm9pcwriloF0cmViYWxsCm5pdHoKYm92ZQriloHQt9Cw0YHQu9GDCuKWgWFic2VudAriloFMYXVmClNtaXRoCuKWgdCd0LjQutC+0LvQsNC5CuKWgWV1cm9ww6llbm5lCmxyCuKWgXByb2dyYW1tYQriloFtaWRzdAriloFkYXVnaHRlcnMKU3luCm9iZW4Kw6JuxIMKaWRhbgriloF0aGVyCm9kb3JlCnNkbAriloFRdWludAriloFjYXNvcwriloFaYW0K4paB0YHRgtGA0LDQvdGLCuKWgXNwcml0ZQrQutCw0LsK4paBbmFzYwriloHRgdC+0YLRgNGD0LQK4paBdHJhdmEK4paB0YXQvtC30Y/QuQriloFVcnVndWF5CuKWgXNwYXJzZQriloHQv9C+0LvQtQriloFteXN0ZXJ5CuKWgU1hbmcKcmVnaXN0cgriloFDR0Zsb2F0CuKWgXN1Ym1pc3Npb24K0LLQsNC90LAK4paBIjoK4paBVHJhY2ViYWNrCuKWgVBpdAriloFFaHIK4paB0YHRgNCwCuKWgUdyYXBoaWNzClVwZGF0ZWQK4paBc3ZlbnNrCuKWgXNwYWNpbmcKdHJpdHQK4paBR3VpbmVhCuKWgUZyYW7Dp2EKQXNzb2NpCuKWgVRvdsOhCnN0YWIK4paBTGVhcm5pbmcK4paBQnJpZ2h0CsWbYwriloFpZMWRCn19X3tcCuKWgWRyb2l0ZQriloFyYWlzaW5nCmdldHRpbmcKeXRobQpvbnltZQrFvHMK4paBYmxhaApUYWdOYW1lClZlcnRpY2FsCuKWgWFwZXIKcG9zdGdyZXNxbAriloFIYW5kbGUKemV3CuKWgXNrdWxsZQriloFvcGVyZQpsYXllcnMK4paBcG9zc29ubwriloFyZWxhdGUKxIVjCuKWgU1paArDomdlCuKWgcWad2kKaXNzZXMK4paBc2VydmxldApMb3MK4paBQWR2YW5jZWQKYXRpY2EK4paBY2VkCuKWgWVsZW1lbnRvcwrRgNC+0L3QsAppa3MKYXJmCmFyaWF0Ck1vYmlsZQphZ3VhCuKWgXRpbXAK4paBQ29taXTDqQriloFjb21iaW5pbmcKd29obAriloFTdHVkeQpjb29yZGluYXRlCuKWgXJlY29tbWVuZGF0aW9uCuKWgXRyYW5zZm9ybWF0aW9ucwp1bnRpbApib3VuZGVkCuKWgdC40LfRgwpoYW5jZWQK4paB0LLQvtC/0YDQvgriloFQcsOpcwriloFjb29yZAp4dHkK4paBJCwK4paBY2hhbXBpb25zCkRlbgpNaWwKKCcsCuKWgVByZWlzCuKWgWVpZ2gK4paBbWFya2VycwriloFnZXdlc2VuCsOkdHRlbgriloFwaW9uZQptdgriloHRmNGDCnplaWNobmlzCmhvZmYKTmV3cwriloFTdGFuaXPFgmF3CuKWgUJyYW5kZW5idXJnCuKWgUZldWVyCj0mCtC20LXRggriloFOZWlsCuKWgXdpcmsK4paBc29jaWV0w6AK4paBc3BhcmUK4paBY2l2aWxlCnNwcmFjaAriloFkaXNzZQriloFnYXRlcwriloFhbm9tCuKWgdCk0LXQtNC10YDQsNGG0LjQuAriloF0aWIK4paBZsO6dGJvbAriloFXaWtpcGVkCmlhdGUKRnJvbnQK4paBY3JhdwriloFSYWsK4paB0LfQstGDCnN0cmVldAriloFBZ2VuY3kK0LLQsNC70L4K4paB0KDQsNGBCuKWgW1rZGlyCmFjasSZCuKWgXNoYXJlcwpTdG9yeQriloFyZW1hcmtzCuKWgWtleXdvcmRzCkJvYgriloF0b2UK4paBVml0dAriloFyaHMKUk9QCm9yaXMKL0AK0YHQuNC4CuKWgXRyYXZlcnNlCuKWgXJlZmVyZW5jaW5nCnByw6RzaWRlbnQKcm9uZwonKToKYXRpZXMKQVcKT3V0bGV0CuKWgcOpdm9sCmlrZXMK4paBZW52aXJvbm1lbnRhbAppY3VtCuKWgUxpZWQK4paBd2FybgriloFCdXRsZXIK4paBJSksCuKWgVplaXRzY2hyaWZ0CuKWgU1vbnRyCtCy0LDQttCwCuKWgU1lcmN1cgpqZWt0ZQptZXRlcgpkdWNhdGlvbgriloFhdHRyaWJ1dGVkCiokCuKWgXVuZgriloFWZXJ0cmFnCnppZW4K4paB0KDQvtCxCmxpY2VzCnBwbHkKYW5zZW4K4paBemVpdAriloFpbW1lbnNlCuKWgWx1dGVnbwriloFCdWxnYXIK4paBbWllbWJyb3MK4paB0J3QsNGG0LjQvtC90LDQu9GMCuKWgUFsbG93CuKWgWFuZ2zDqHMK0LTQstC4CuKWgVRveQrRgtGD0LAK4paBeWFyZAooJQppc3NlcgriloFnb2xmCuKWgVVrcmFpbgriloFob3NwCkluY2x1ZGUK4paBTGlzYQriloFjc2FsCuKWgU1pcmEKcmVjb2duCuKWgdCa0LUK4paBaGl0dGluZwrQutC+0L3QvtC80ZYK4paBVG91cm5hbWVudApMT0FECuKWgUd1YXJkaWFuCuKWgWRhaGVyCuKWgXRpbWV6b25lCuKWgXRvbWNhdAriloFzdWNjZXNzb3IK4paBVm9pZAriloFjb21lw6cK4paBY29udmVydHMKw6RjaHMKb3NleAp4ZWxsZXMKYXNlcgriloHDiXMK4paBbW91CuKWgXVuZwriloFvcmlnZW4K4paBQ3JvdwriloFFcmQK4paBc2llYmVuCmx1YQriloFCQgpSRU5UCuKWgXBpxYJrYXIK4paBbWFycXVlCuKWgUxhYm91cgp2aWRlcnMK4paBZXhlbXBsClNvdW5kCuKWgVdhc3MKYXJyaXNvbgriloHRgtC10YfQtdC90LjQtQriloFPZmljaW5hCuKWgURhdwriloFLYXVmCsOpbnQKw6lzxZEK4paBPSIK4paBa2F0CmRpY3Rpb24K4paBVm9sbAriloFoaWdod2F5CkphbWVzCnpldWdlCuKWgW1vZGVsbwpUaHJvdwriloFGb3J1bQooIkAK4paBZW5mZXIK4paB0YHQv9C10YbQuNCw0LvRjApOdW1iZXJzCuKWgUJpbmFyeQriloFNYXJ0w61uZXoK4paBU3RhdG8K4paBZmVzdGl2CuKWgWthdG9sCuKWgdCQ0LEK4paBbGltaXRhdGlvbgriloFTVFIK4paB0J7RhNC40YbQuNCw0LvRjAppcGVzCuKWgUlzbgriloFydWxlZAriloFjw60KZ2ViZXIK4paBbGF2b3JvCuKWgXBhcmVudGhlc2VzCtC+0LcK4paBw6lxdWlwZXMK4paBZWZmaWNpZW50bHkK4paBUGVyaW9kCuKWgVJlZ2FyZGluZwpsZWFmCuKWgXNpbWlsYXJpdHkK4paBZ2VzdHVyZQpkYXRhYgriloF0ZXJtaW5hdGUK4paBc2VtYW50aWNzCuKWgUFsbwriloFjaWcK4paBT3BlbkdMCuKWgWhldXRpZ2VuCnhhbWwK4paBZnJlcXVlbmNpZXMKKX0uCuKWgXRocmVhdGVuZWQK0YLQuNC6CuKWgWNhbGNpbwriloFSaWVtYW5uCnNsdWcK4paBRmluYWxlCkxSCuKWgURlcmJ5CuKWgdC+0YnQtQriloFkZXZpYXRpb24Kw6RjaGVuCuKWgUNyaXMK0L3QvtCy0L4K4paB0YHRgtC+0LvRlgriloFyZWxldgriloFzcGxlbmRpZAriloHRg9GH0ZEKZXJ2aW5nCmdhYmxlCuKWgWfDqW7DqXJhbGUKcG9tCuKWgUNoZWVycwriloFpbXByaXNvbgriloFpbmRlbnQK4paBYW5hbHl6CuKWgXJldmVydArDqXJlcgriloFwaGFzZXMKRmlyc3ROYW1lCuKWgW1pZwriloFkaXN0dXJiCuKWgW1peHR1cmUK4paBKXsKaW50dXJlCuKWgVRyaWVkCuKWgXNvb25lcgriloFwZWxzCuKWgcOpdGFibApldHJvCml0aWUK4paBcXVhcnRpZXIK4paB0LPQvtCy0L4K4paBdsOhcm9zCnVmZQpoZXRlbgrRhdC+0LwK4paBc29hcAp1dG9ycwriloFkdWNoCnN5bnRheAriloF0cmliZQriloFjaGFudGUKVHJpCuKWgU1hdGUKcXVhbGl0eQp1b2xhCj0iLgpjaGsK4paB0LLRgdGWCuKWgXByemVjaQriloFNZXRlb3IK4paBc2NhdHRlcmVkClBsdXMKdHJhZAriloFzdGFja292ZXJmbG93CuKWgXJldHJhCuKWgcOpZGl0aW9ucwriloFzYWluCmNyaWJlCmlnbm9uCnVja2VyCuKWgdC80LDQu9C+CuKWgXRlbmlyCuKWgWV4cG9ydHMK4paBYXV4aWxpCuKWgV1dCuKWgUNCUwp1bmlmb3JtCuKWgXBlcmlvZGljCmFncmFudAriloFlbXBsZQpXaWwK4paBZnJlcwriloFzdHJ1dHQK4paB0YHQstGW0YIK4paBYmV0cmUK4paB0L7QsdGK0LXQugrRgtC40YHRjwriloFiaXNoZXIKYmF1bQppc2hpCuKWgUdhemV0dGUKYmFja2dyb3VuZENvbG9yCmpsCuKWgWZpZWwK4paB0L/RgNC10LzQsAriloFwcm90YWdvbmlzdGEK4paBTXVoYW1tYWQK4paBc2ltdWxhdGUK4paBSG9vawpmZXN0CuKWgdGB0LLQvtC40YUKU2VuZGVyCuKWgWxpc3RlbmVkCtC20ZYKamVzdAprb3JkCkNob2ljZQriloFob29mZApyZWR1Y2libGUKaHBwCuKWgVd1CsWhaQriloFNYXJzZQriloFzb2lyCndlc3RlbgplbW9zCuKWgUR1YwriloFhbWVyaWsKfH17CuKWgUd1bAriloFTcHJhY2hlCuKWgW1pc21hdGNoClNjYWwKUGl4ZWwKRUYK4paBU2VwCuKWgXBvd2llY2llCnVyawriloFOYXBvbGkK4paBbmVpZ2hib3VyaG9vZArRgdGC0L7Rj9C9CuKWgXNlYXJjaGVzCnlydXMK0L/QtdGCCkhlbHAKcG9udAriloFPcmllbnQK4paBQWxmb25zbwriloFtb25pdG9yaW5nCmlhbwrDqWTDqQriloFDw6lzYXIK0YjQtdC1ClNoaWZ0CnN1aXQKY29kZWQK0L3QvtGC0L4K4paBUGFydGkK4paBbGFzY2kK4paBYXdlc29tZQp1c3RhCuKWgdCh0L7QstC1CuKWgUZsYW5kCm9vbQriloFkZXZpCmVuZ2Vsc2sKZW5kdW0K4paBUGFzY2FsCuKWgUJpbmQK4paBc2lndWllbnRlcwpKQgriloFQZXRlcnNidXJnCuKWgWluY29ycmVjdGx5CuKWgUJhc2gK4paBcGVsb3MK4paBemVzcG8KTlNVUkwK4paBcMWZZWsK4paBQ3JpbWUKbmFjaAriloF0aHJ1c3QK4paBQ3VsdHVyYQpXRgriloFTb2xvCuKWgWludmFzCuKWgWluZGl2aWR1YWxseQppYm0K4paBZXRhcGEK4paBaGFuZGVkCuKWgXdoZXJldmVyCuKWgWludGVycG9sYXRpb24K4paBbXVzw6llCuKWgUNOTgppZGlhCsWEc3R3CuKWgXByemV3CnVnaGluZwriloFhY3RvcnMK4paBT3JpZW50YWwK4paBY29udmVuaWVuY2UK4paBbWlhc3RhCmJyYWlucwriloHQvNC10YHRjwriloFpbmZhdHRpCuKWgUFsbE1vdmllCuKWgWNyaXRpcXVlCuKWgXN1Y2Nlc3NvCmFuY291dmVyCuKWgWbDoQrRitC70LPQsNGACuKWgXdpc2RvbQriloFQaG9lbml4CmhvbGUK4paBaW5mb3JtYWNpw7NuCuKWgUFpcmxpbmVzCi7Cqwptb3J0CnVzZXJJZAriloEqLw0K4paBQ29uZ28K4paBImAKY29ycgriloFwcm9ibGVtYXMK4paBYmliCuKWgXDDs8W6bmllagriloFmaWxlTmFtZQp6b3R0Cm1hY2h0CuKWgVVscmljaApDeQplbmRwb2ludAriloFzaGVlcAriloFpYm4KRmVlZAriloFzeW1wYXRoeQriloFJYgriloF0ZXJyaXRvcmlhbApyYXRpbmcK0LTQsNC80LgK4paBZHN0CtGD0Y4KYWhvCuKWgXN1ZwplbWlhCuKWgXRlZAriloFBcGkK4paBUmljYQriloFNUgrFhHNraW0K4paBVm9vcgriloFkZXZpbAriloHQpNC+CuKWgU7DpHIK4paBLi4uKQriloF2b2lzCuKWgWFiYnJlCuKWgU3DpG5uZXIKeGltbwriloFpbnRlbGxlY3R1YWwK4paBdGFsZXMKc2ltaWxhcgpuZXVtCuKWgU9yaWcK4paBcG9zdGFsCuKWgWh2b3IK4paBaWRlbnRpZmljYXRpb24K4paB0J7QtAp1ZXN0bwriloEuLi8K4paBYmlyCuKWgdCb0L7QvQriloFlc2VtcGlvCuKWgUVpbmcKRXhwYW5kCuKWgVBSSU1BUlkK4paBSmluCuKWgXbFoWFrCm91cnNlcwriloFCZXR0eQriloFXTQriloFmbGFzawpobGVuCuKWgUFkZWwKbGFyYXZlbAriloHQtNC10YIK0YHRjNC60L7RjgriloFNdW5kbwppY3puCmlmacOpCuKWgdCc0L7RgAriloHQtNGA0LXQsgpEYXRlRm9ybWF0CtGB0YzQutC40LwK4paBZGF0ZWQK0LrQvtC70LgK4paB0YDQtdC30YPQu9GM0YLQsNGC0LUKXCkuCuKWgWRlbGF5ZWQKc291bmQK4paB0JzQsNC6CuKWgSIuLi4K4paBYmlubmVuCuKWgdGE0LDQutGD0LvRjAriloFwb2x5Z29uCuKWgWVnZ3MKQXRJbmRleFBhdGgK0LzQtdC90YLQsNC70YwK4paBaW5jcmVkCmNodW5rCndlYmRyaXZlcgriloHRgdCy0L7QsdC+CuKWgW1pxJlkenkKUmVjZWl2ZWQK4paBTW9uZGUK4paBSlF1ZXJ5CkJ1dHQK4paBUERPCuKWgWZvcmVjCuKWgWRpc2NpcGxpbmUKY2hldgrQvdCw0YIK4paBcmVkaXMK4paBaHVudGluZwriloFhbGsK4paBcHJvb2ZzClBSSQriloFjaGlwCsOpc2llCuKWgUhPCuKWgXJ1Zwp6b3MK4paBc29ydGUK4paBemVpZ3QK4paBUGh5c2ljcwpsZWd0ZQriloFwcm9wb3J0aW9uYWwK4paBdG9vbGJhcgp2ZW1lbnQKbm90aW4K4paBcHJ2bsOtCmJsYWgK4paBcHLDqXNlbmNlCuKWgWxsb2MK4paBbMOtZGVyCuKWgUFjY2VwdAriloFBbHdheXMK4paBInsK4paBZGl2ZXJzaQppa29yClBlcmlvZArQttGR0L0K4paBQWxsaWFuY2UK4paBcmVsYXkKQnJvCmrDtm4K4paBQmF1ZAriloFCaWFuCicpWwrRh9C40LIK4paBUG9zcwriloFNaXRnbGllZGVyCuKWgW5ldgpEYW5pZWwK4paBdGVuZHMK4paBY29tcGFnbmllCuKWgWxpdnJlcwpsdWIK4paBCmUKdAphCmkKbgpvCnIKcwpsCmQKaApjCnUKbQpwCmcKZgouCmIKeQosCncKdgprCjEKKQooCi0KMAo6CkkKUwrQvgpcCjIKQwoiCkEK0LAKVAp7Cn0KLwonCngK0LgKXwrQtQp6CtC9Cj0KRQpNClAKagrRgApECjkKKgpMCtGCCkIKUgrRgQo7CiMKJApxCk4KMwrQsgpGCtC7CjUKNAo4CsOpCk8KSArQugpgCjYKRwo3ClcK0LQKPgrQvArRgwpbCl0KVgrQvwpVCjwKSgpLCtCzCtGPCtGWCtC3Cj8KKwrQsQrDoQrQuQrRjApZCsOzCtGHCtGLCsOtClEKXgrDpAomCtGFCnwKWAohCkAKw7wK4oCTCiUK0YYKw7YK0LYKWgrDqArDoArRiArigJQKDQrRjgrFggrCuwrQoQrCqwrigJkK0YQK0JIK0J8K0JoK4oCcCtGYCtCcCtCQCsOnCsOlCtGJCn4KxJkK4oCdCsSFCsSNCtCgCtGXCtCdCsO6CtCRCtCUCsOjCsOfCsSDCsSbCsOqCtCeCsWhCtCTCtCiCsW8CtGRCsW+CsWbCsOxCsWZCsWRCuKAngrQmwrRjQrDvQrQowrQmArRigrRlArDogrDrgrDsgrQlwrQpArDiQrEhwrCtwrImQrFhArImwrQpQrDtArQlQrDuQrFrwrCsArQqArRmQrQpwrDuArDpgrRmgrigIkKwqAK0K0Kw6sKw7UKw68K4oCYCuKAoArCsgrFsQrQhgrilIAK0KYK0ZsKw5YKw7sK0K8Kw6wK4oCmCsWNCtCWCtCuCsOBCsyBCsOcCsK6CsWTCsSBCsSMCsW6Cs6xCuKUggrYpwrDgArilZAKxaAK0ZIK4oSWCuKAigrigKIK4oiSCuKGkgrDlwrOvwrigoIKw4QKw44KxZoKxJEKw4UKxLEK4oCOCsWrCs69CtCZCsKqCs65Cs+ECtmECuKAsgrvv70Kw4gKzrsK77u/CsW9Cs+CCsWICs+BCuKCgQrQhArEqwrOtQrCpwrFgQrQiArCowrYsQrFuwrCvwrZhQrigLMKw5oK2YYK2YoKz4MKwrQK4oCLCs68CsKzCsWfCs+ACtmICtivCs66CuKCgwrDjQrLiArYqArDkwrDgwrCoQrigqwKxaUKzrcKyZkK44O8CtCpCs6yCuKUnArDsArSkQrCrQrPhQrCuQrigoQK2KoK15kKzrMK2LMK44GuCsSfCs60CtuMCuODswrZhwrXlQrPiQrOrwrilogKzrgK55qECsKpCsOCCuKGkQrvvIwKy5AKzqwK4oCVCti5CsOHCuKCgArCsQrDmArEjwrFmArFkgrCvQrilJQKz4wK4oCaCsSTCuKChQrDhgrImArJmwrXlArXqArPhgrigoYKxJcK2K0K2YEK2KkKxLAK4oCCCuKGkArilZEKyZQK4omkCtecCsSQCtWhCsWMCteQCuC1jQrjgrkK2LQK5aSnCuODqwrRnwrjgqQK4p+pCuKArwrCtQriiIgK2YIK4p+oCuOAggrSkArgpL4K2KwKyr8K4YOQCs6tCs+HCuS4rQrXkQrhg5gK4oKICuODiArOrgrjg6kK0I8K2YMK4oKHCteeCteqCuS4gArOoArguLIK44O7Cs6jCs6RCs6UCtepCtiyCuCljQrguKMK44GECsq7CtCKCuKCiQrKvArjg6oK4oCQCuOCrwriiJ4K4oGECs+NCsWeCuOCogrOlQrJqgrkuroKzpoK4oiACuCksArjg4MK4pa6CuWtkArCrArYrgril4QK2Y4K16IK5pelCuOBlwrhuKUK16AK5bGxCuOAgQrQhwrjgosK5paHCsORCuODiQrXkwrVtgrQggrOkwrDvgrCkgrCrgraqQrCkwrimq0K5pysCuKElQrguJkK0Z0KzLYK4LitCtGeCuOBqwrmlbAK4YOUCuWbvQrOqQrjgIAKx44K2LUKwpQKzpwK4oCDCuOBqArigaAK44GfCti3CtaACuOCvwrDvwrjgaoK2KMK44K3CuaWsArvuZUKyoMKxL4K44OtCuKBtArgr40K4oeSCsWjCu+8mgrImgrgtJUK4omlCuC0vwrjg54K44KTCuG5owrjgrgK5pivCuydtArii4UK55SwCuOCkgrpgZMK4LiHCsKoCtmACuC5gArmnZEKw4oK150K4oC6CueUqArPjgrlpKkK77yJCuC8iwrplYcK44GLCuS4jQrOpArlraYKxrAK5pyJCtW4Cu+8iArjg6wK2q8K4oCPCuODlQrgpKgK4LiBCsmRCuOBmQrXlwrkuIoK4oCMCuKIpwrhua0K16cKzr4KwqQK4KS/CuS8mgrgtKgK44KrCsWzCuOBvgrgtYEKzaEK4KSVCuCmvgrlsI8K158K6KGMCuOBrwrKgQrFkArDngrjgooK44KtCs6bCuGDoArkuIkK44GMCuOCswrOtgrluIIK546LCuKEnQrFuQrjgYYK44GmCuWMugrgtL4KwoIK5bm0CtekCtWrCsW/CuKAuQrgpKQKxY8K4oCRCsyDCsSGCtmJCuOAjArjgI0K4YOhCsSACuCkrgrnlJ8K4omgCtCJCuCkuArihpQKzp8K4LinCuGDmgrmiJAK5a6aCuC4pQrCtgrXmwrjgacK1rwK4LihCuS4qgrlkowK16EK5ZyoCs6SCuC4tArOmQrigbUK4LixCsmhCuKUgQrjgokK44KqCsK8CtWlCuODkArWuArFiwrFrQrjgrAK4oG2CtCsCuKBsArmlrkK4LiaCsKXCumrmArhu4cKzp0K0aMK44KjCuWcsArmnIgKw5QK4oSiCuOCpgrjgY0K5YWsCuG6oQrhg50Kyb4K4LmICuWHugrms5UKzpgK4LiqCuWQjQrguKIK4LSkCs6mCuKGkwrjgowK15IK0IEKxqEK5LiLCtOZCs+ICuKUvArjg6MK4oiaCsKlCuekvgrhuYcK44GVCtmQCuOBjwrgpYcK0KsK4byQCuODhgrkuLoK5LmhCuW3nQrjg4oK5LmLCuWtlwrjg6AK4KWACua1twrjg5YK4omICu+8gQrZvgrCrwrhvIAKwoMK44GTCtawCuadsQrmmI4K4b22CuaXtgrguJcKyagK44OHCu+4jwrKigrjgqgK5Y2XCuilvwrgpLIK44OhCuODlwrlubMK5byPCuG/lgrSmwrgpLUK2LoKw5IK5a62CsqSCuOCtQriiaEK44OACuC4lQriiIMK4oK5CuCkqgrnrKwK4LSwCti2CuKWhArln44K44OfCsmQCsKmCue+jgrku7YK4YOcCsOQCta3CuODiwrpg6gKxYYKx5AK15gK4KSvCuOBggrCvgrhuqMK44GhCuODpQrDtwrlpbMK56WeCuKZpgrCogrku6UK4LmJCuCmsArlpKoK4KeNCuODgQrVtQrliY0K6YeRCtaCCumHjgrljJcK4LirCuKAsArjgaMK5YqgCuWOnwrKsgrnva4K5a6JCuOCrArmiJEK4bikCuC0rwrkuqwK4paACuGDmwrhg5UKyr4K4oioCta0CuWPrwrlj5YK5Y6/CuS6jArilpIK55CGCuiHqgrkv6EK5LujCuC4tQrXpgrhgLoK4KSmCuKBuArMrwrjgYoK6KaBCuG/pgrgrpUK4buFCuClgQrGkgrKsArljJYK4pyTCuC0qgrsnZgK64ukCuacqArZjwrMgArLjArgpLkK44ORCuawtArhur8K4LiUCuOCugrigbkK5bO2CuKAjQrjgoIK5q2jCuKWoArYogrguJ4K5YaFCsOMCseUCuKUrArkvZwK5ZCICuG9uArjgb8K4pa8CuG/tgriipkK772eCuG7iwrZkgrlm54K5LqGCuaJgArkuosK6KGoCuC4swrliIYK4oG3CtKvCsKACuWFpQrlhagK2KUK6YeMCs6nCuCkggrjg48K4LiECuKBuwrjg6IK6YOOCuaNrgril48K5beeCuKIqQrogIUK6YCaCumDvQrihKQK4pmtCuKVjArjgaQK4biNCuaxnwrXlgrDnQrTqQrguYwK5YiwCuCuvwrKggrlr7kK7IqkCuS9vwrgpr8K44KICuG8iArDjwriiJgK7IKsCuCmqArkuJYKyZUK1a8K4YOjCuC0nwrhg5EK4KWLCuC0tQrmnpwK5Y2BCuC4uArol6QK5p2lCumdogrjgZEKxJUK44OTCui/mQrsp4AK4LSCCuihlwrnn7MK6IO9CuepugrVvwrYpgrmraYKyrkKz5UK5ZCOCuC4sArlhYMKypQK66asCuq4sArmsrMK55S6CuiKsQrhvZAK57G7CuKWkQrniakKzpcKwrgK4K+BCuGDlwrYqwrgtYYK4pWgCuKKhgrjgIsK44OECueJiArliqgK5aaCCuecnwrJsgrlj7cK2LAK7KCVCuaelwrmm7gK5rCRCuWPowrZkQrnpLoK4LSuCuyVhArlm74K4oiqCuaIpgrmnY4K4LSyCuOAigrlhYkK55m9CuW/gwrgrqQK4KScCuiuvgrhvbcK6LevCuCklwriiKUK7ZWcCuacgArQiwrmiYsK1b0K77yfCuWeiwrhuqcK44K7CuW7ugrjgqcK5Li7CuyLnArrjIAK4b+GCuKAoQrpm4YK4YOTCuebrgrOoQrjgqEK5bqmCumVtwrmmJ8K44OOCuG7mQrqsIAK5LqUCtqGCuuhnArjg6cK6YeNCuS6jgrlj5EK5Y+yCti4CuC4igrjgYgK5ZyLCsStCuCuqgrsnbgK5L2gCumnhQrigJIK4pmlCuWkmgrEpwrSmgrhu5MK5aOrCuWbmwrilLQK4K6uCuWPuArgp4cK4b2wCuKIggrilawK5qyhCsS9CuKftgrnq4sK54K5CumfswrioIAK5ZmoCu2VmArkupUK5a2YCta5CuW9kwrDiwrimIUK5a+6CuaApwrkuZ8K44KBCuOBoArkvY0K4LSZCtuBCuWAvArlj6QK4YOSCuCmrArpmaIK4LWHCuKWtgrgrrAK55WMCuiqngrgtLgK7IiYCseSCuaEmwrinJQK5pmCCuG7jQrgtLEK1bQK44KxCuS4nArlkIwK7KO8CuS/nQrDlQrhu5EK4bywCumdkgrjgrQK5L2TCua4hQrnm7gK4LiICtihCuaDhQrwnZWcCuCmlQrhuKsK4budCuWwhgrml48K64+ZCs6lCuKUjArjg5wK5a6uCuOAjwrgpq4K44COCsS8CuCktgrguJsK1LEK4KSsCuyekArmlL8K4K6+CumXtArvrIEK5p2+CuG5gwrlp4sK5oGvCuWwkQrmlZkK6I63CuWIlwrlvIAK4YOiCuODrwrhg5kK56eRCuaYpQrmsrsK5ZCJCuC9pgrguKgKyZIK5Y+wCuODjQrhgLgKxKkK5belCuG9sQrnn6UK5YWrCuWgtArnlLsK55m+CuKYhgroqJgK5b6XCuOCvQrmsI8K4YCsCuyXkArgprIK4bmbCuWFswrEoQrhvbMK4oiRCuODmQrmoIcK64uICuG9tArWtQrlpJYK4pmgCuOCjwrplpMK4LigCuagoQrliLYK4LmBCuWKmwrploAK5aW9CtKTCsOZCuKEkwrWtgrripQK4pSQCuKIlwrmjIcK6ImyCui/lArppqwK6K+3CuKJqwrpoqgK4b25CuaOpQrshJwK4oazCuOBmwrlv5cKzLIK6a2UCtKjCuabtArnqIsK6rmACumDoQrgvbwKxakK4LSaCuWIqQrnnIwK5ZGoCuOBnQrjgoQK6LC3CummmQrima8K44GYCtiMCuacnwriiIUK4pSYCuWInQrnpo8K54mHCuOCtgrli5UK5Y+CCuyEsQrGjwrilaYK7Ja0CuGDrgrnvqkK4KSaCuixoQrlip8K4pmCCuuPhArqs6AK6L+HCtW+CueahwrnibkK4bqtCumVvwroi7EK4bqlCuC0owrQqgrgprgK5YW2CuCmpArmtYEK6ZmkCuydvArgp4EK4Z+SCuawuArnm7QK7IOBCuWNgwrhuq8K6aSoCsWkCuacnQrgrp8KyaMK5Y2VCsqACuagvArlvrcK7KCECuKYugrjg5QK5q2MCui/mwrpmZAK5aSrCu2KuAriiqIK5ZySCumHjwrlnJ8K5pS+CueggQrnrYkK57O7CuKIvAroj68K4oa1CuyGjArluLgK5ZCmCuimiwrmupAK14EK5a6eCuWNmgrrnbwK7JuQCuuztAriipUK6KejCuOAnArnlLcK4KamCuODnQrjgo0K64KYCuC9ggrnhKEKw5sKzKUK0rEK5p+lCsyjCuKVlwrilakK5p2hCuCmrwrhvYEK5b6MCuS7lgrnvZEK4K6yCuKJgwrtmZQK25UK6Zi/CuGAsQrmiLcK4oirCuq1rArgvaIK4YCZCuKWuArVrAril4sK5ZG9CuWwsQrpvo0K5ZCbCuWkjwrCgQroqIAK5YWICuKenArhg6gK4YOrCuCovgrgrrUK44GpCuODkgrguYQK4K6pCuOBsArjgq4K1aMK4byECuODpArlhbgK5bqcCsyECuyLoArnu4QK5pS5CuG9sgrljY4K5LiOCuiwgwrilZ0K44O0CuGDpQrnlLEK5L+uCuWtuArimaMK5raICuespgrKjArrtoAK4bubCuKAvgrilrIK5b2VCuC0swrsl7AK7J2ECuOBsgrsmIEK4pSkCuW3sgrpmb0K4YCECuq1rQrlrrkK5pyqCuWulwrhtIcK44GzCuyepQrpvpkK4LeKCuaPkArEnQrlha0K5b2iCuygnArVgArkvIoKz7UK4LiCCsWwCuOCgwrngasK4bmiCuS9kAriiqUKzKoK4bupCuKWoQrnu5MK5LmdCumbhArVqQrhnrYK6ICMCuC9lgrsmrAK5bygCuCknwrgpLcK5ZCRCuG/pQrpgIkK6rO1CuOCsgrKkArku4EK5aCCCteaCuGArwrhvJQK4LSFCuG7gQrgvZEK7ISgCuyYpArkuYUKwpwK5LmJCuCkhQrilZQK5pegCuKAqArsnYAKyrcK6YKjCue3mgrliqEK5Z+6CuWxngrphY0K66+4Cui7jQrguYIK5rSlCuWujArnoJQK5rOoCuWksQrlupQK4YCACuKVmgrlj4sK56ugCs6oCuaxggrgpKMK6rK9CuKArArgpK0K5LusCuaooQrpnIAK4K6aCumbuwrgpqoK1aQK44G4CuatpArlpJwK5oiWCuapiwrmoLkKxKoK546JCuC4uQrhuYUK5LqkCuWTgQroia8K4L2ECuOCqQrliJkK6ZaLCs6WCuusuArooqsK7KGwCuagqgrorrAK5pyDCue7jwrgpYIK44KHCui9rArltI4K66eICuKMmArmr5QK6YCgCtyQCuC4twrmsqEK546wCuS4gwrOhgrllYYK4K+ICuacugrpmLMKxIkK6KeSCuermQrVogrtlbQK5Y+KCuCkpwrooZMK6K6kCsKRCuWImwrnt6gK1bIK4bipCuS8nQrlsqEK4KShCuODmwrmuK8K5Lu7CueZuwrgvbIK4LmHCuW4gwrnqbYK5bidCuyXrArsgrAK4YCUCuKXpgrlr4YK5Y+YCuW6jwrimYAK4oijCuiuoQrmm7IKxIIK4b27CsqLCuS8oArjgJEK5YyFCuaEjwrljrsK5rKZCuK4rgrjgJAK5YaZCui2hQrgrq8K5LuKCuKUiArmo64K4LeSCuKKlwrruYQK1bAK4bioCserCum7hAriiJkK65OcCvCfjI0K5pmvCua5lgrWhArhgK0K4oG/CsyCCuODmgrkvZUK5a6HCuW8tQror60K6ICBCuS+iwrhuawK6YmECuWFiwrimIkKwpkKybkK4byxCuK0sArnhLYK66W8CsenCuWgsQrmnI0KxI4K5oOzCuKAlgrjg6YK5a6fCui9vQrsmpQK4oSaCuazogrpqawK54q2Cue6vwrsnKAK5rSLCuS4hwrsp4QK4KacCua3uwrnkIMK5qmfCuaUrwrmmL4K5ouJCuG9kQrpgIEK6ZqKCuC4mArlpIQK5birCuKKggrlg48K4Ka8Cum7kgrWgQrCnQrhu6cK5Y+qCui1twrmrrUK4YCQCuWNgArpgbgK7LKcCualrQrnrpcK5bm/CuGemgrop4YK56eLCuWboArrhYQK25IK6L6TCsyxCtWECuKIhgrlurcK7IS4CuaAnQrmrbsK6IGWCuuvvArvvI0K5aS0CuC1vAriiIkK6LuKCuKUgwrilocK5oyJCuKNtQrlpKIK5rGJCuS7jgrgp4AK6aKYCsuGCuG8oQrlsZUK55yBCuC9tArokYkK7Zi4CuCosArntKAK6ZaiCuq3uArvvJsK4LaxCumhtQrlhbEK5a6/CuaAgQrgvZMK5oqACuS5kArmjqcK56e7CuW9sQrhu6UK44KGCuOBlArgs40K566hCuC1vgrilaMK5oi4CuKHlArlh70K4bqTCuWwvgrlnLoK5LuLCu+/vArogrIK4La7CuaziQrgtb0K6K+0CuaNogrlv4UK57SACuC9mArgvboK4bujCuC1uwrlrp0K5rCXCumXqArku6QK5bemCua8ogroi6UK5bGLCuWxgArmiZMK55m6CumXrgrmgYsK5YW1CuWIpQrgqr4K1Y0K36wK4KaXCuW5tgrgpJYK4b21CuiKggrKkQrXpQrhuKoK4oSCCuW8lQrnu58K5pm6CsypCuCliArnlLUK7ZiECuKchQrotaQK5patCuOBrQrnp7AK4Ka2Cui6qwrpppYK5LuYCuKFkwrgqLgK6YCjCuGDlgrlrpgK5oyBCuWliArlvqEK6KaqCuq1sArlupMK56eACuWdgArlrogK5rS7CuC9owrjgbUK6JePCuGenwrnq7kK6I2JCue1kArgt48K5piMCuaouQrgrrMK66y0CuCmuQrjgrwKzIgK1bcK5YudCui2swrhgJsK7JyECsSvCuG8uAroiKoK6ZmzCuS4mgrlr4wK6ZuqCuCkhgrlho0K7JWICum7mArrsJUK7JqpCuKcvwrmpb0K5rKiCue+hQrElgrKjgrlv6AK6ZSZCuuLqArrqbQKxLcK5qGlCumbsgror6UK4bmvCuWyqQrrgqgK4bu5CuS4kwrliIcK5bqXCuacsQrXowrjgZoK5bm4CuavjQrJqwrjgIUK4oi3CuS4sgrlh7sK4byYCuiorQriiqQK4oKXCue2kwrqsJUK4YCVCuClpArRkArhvrYK4p6WCuW6pwrslKgK44G2CsWiCuS6kQrlkYoK5aSJCuivlQrpmoYK6rCcCtW6CuWIpArliokKy5wKy6AK57yWCuC4kwrhu68K6L6+CsSaCtydCuGAvArhuLcK5Y+zCuuTpArFnQrTjwrgsY0K4LSOCuCusQrlpI0K55yLCuipsQrlnYIK5bCUCuihmwrVpgrssKgK5Li4CuagtwrprLwK4KS8Cu2VmQrllpwK5pavCumKgArrp4wKzp4K4YOqCue+pArov5EK5aGUCs+KCuCuqArjgoAK56GuCue0ogriiIcK6Z2eCuacmwrina8K5biMCuG7swrnlLIK6LaKCumzpQrpursK6ZuFCuaLswrhnoAK5rqqCua1iwror50K5rGgCuiPnArpo58K7YSwCuCovwrmuKEK6YCfCtq+CuCysArpmYgK5YGlCuCniwrgtpoK4b26CuWGmwrluoQK57qiCsSmCuirlgrFuArOiArhu7EK5a2dCumgrQrpo5sKy5oK4paTCtmLCuKArQrkuYgK6YGUCtGrCuW3tArmtJ4K6LK0CumhuQrgtKYKybUKzI0K0qEK56eNCui/kArsi50K4L6xCuG4swrlvaYK4qWkCuS5pgrmnoQK57GzCui/ngrmk40K6KOFCuqzvArjgZAK5Y+NCsyMCuS7rgrlkZgK5pitCuC0tgrlhbQK5a6iCuWIoArgtrgK4LeACuGDngrEiwrgtLcK4YCeCuG1iQrlsYUK7YOACvCdk50K4KSlCuePvgrLhwrsooUK5YqpCuWUkArngKwK4Z6TCuW+rgrvvJEKxKAK44G7CuiIngrrgrQK7KSRCsSSCuWvvArmlYgK67CpCuG4jwrmt7EK5qKFCuaWmQrsm5QK5q+PCua0sgrtmowK6Iy2Cui0pQrgtJ4K4buDCuODqArkupsK5Y+MCuWYiQrrqqgK67CUCuC4qQrpgLIK7J2MCuC4jQrkuIEK5pWFCuioiArpgaAK6rWQCuyerArlgJkK5oi/CuuqhQrkuKQK4YOkCuaJjQrtlakK5q2iCueVqgrJrwrlpYcK5oCqCuiBlArsl60K5rOwCuuwsQrhvYAK44GSCuOBuQrovrkK6L+YCum7gwrsmZUK5pS2CuW8mArnu5k=" + +const llama_merges_binary = "r3SxdLB0tnSzdLR0r3SydLB0tHS1dLR0BAG6dK90ggGwdLd0r3S3dK90uXSydLF0tXS2dLJ0tHSvdLt0s3S3dLZ0sHSzdLF0BAFiAQoBsHSvdBAGsnS2dLh0sHSvdMV0r3S+dLV0vHSydLh0r3TAdK90vXSwdLl0r3S1dK90wnS1dL10WQK0dLN0CQEGAb90s3RhA7N0u3SydLd0sHS4dAgBsXSwdFEC2gG0dK90BgGvdLp0tHS5dLB0sXSvdLh0r3S0dLd0sXQEAbV0r3QFArt0unSvdM50tnS1dLN0uHQgAcB0r3TOA7l0sHS7dLF0r3TKdLJ0vXSvdNN0DgGwdK90NwGvdM90r3S8dK901XSvdNF0r3SwdAcBKwGBAbl0r3SIAa9013S1dLh0r3TGdLN0vXS1dLF0snS5dLx0sXSvdL90sHS9dLx0tnSzdLl0r3TqdLN0v3S2dLJ0bAGwdK90FAHaAbd0r3QTAfN0vHS1dMV0r3TkdAsBsXSwdC8Br3TDdLd0sHTGdLB0u3SwdLN0sHS8dLR0r3TldK907XSydL90vHS4dK904nS6dLB0CAG5dLB0KwGNAbB0tXQ3AXMBtnSxdAUB7ANRAvcFsXS9dCgBtXS3dK906HSzdMB0DwEjAasICQFTUbR0snTVMR0BEAGlBrZ0r3SuBa90tnSvdOt0VwEbAeBgvHSvdJUYIQGwdK90kwO4dMN0WQG2dMZ0BQGydMJ0sXSwdNoBsXSvdBUBIAG0dK90CQG2dLN0vHS3dK901HQZAbp0r3Q0BRIBCQEWBbR0r3QXAq90/nQNAbF0r3QvAbN0tnSvdON0r3T3dLt0x3QHAbR0r3QRAbF0unSwdL90snTDdBUBunSzdIIBr3TudBMBsXSzdC8BEQG5dLJ0KwEEAZcJCgEPAa90cxYHAbh0r3QcAa908nSvdPF0tXS5dLx0vXSvdAR1unSxdFcENwFUS7B0u3RkAa90AnUPAbB0snRzAQsBt3SwdH0Dr3T0dAUBsHSwdBQBvnS+dAcBt3SvdCYBDQGwdK90WAEaATMBIAK1dK90AwMZAYUBFTC6dK907Qm+dLB0r3THdAUBt3SwdPAIvnSxdMl08HS4dLV0EgEiARYFvXSvdP4BOgGwdLJ07AOvdAB1OwEiAXUMvXSvdPMFs3SydBEBsXSydFECLQGydK90sQGvdNh0QQG0dK90CAE4ASMBu3TVMUEB3HSvdN8CuHS5dLx0wnSvdOZ0uHSydLx0sHSvdA91JQG6dLN0MQEOAbV0r3RLB690/XQPD7x0r3RTAbN0xnQQAbF0tXThCBcBsXSydOEIPgG0dK90XAGMAfF0r3TlCAQBYFkKARMBr3RWBcd0sHQqAbJ0r3QuCa90y3QbAbF0tXRJAUMBYgHyAbB0r3QoBi4BRwG2ArF0r3Q1BS4BsHSvdOQBNQG4dLN0hQItAbB0r3QYAbt0s3QzAb10tnQiAQYBsHSzdOQB2nTadLV0vnSDAQYBsHTvFKYBZgFUBygBr3QhTpMD7xScbQYBwnTMAe907HQmAbd0snR9A7N04HTJdMF0tXS/dK90DHUgAbZ0r3QQARkBJgE8LLd0r3ReKwcBsXSvdA8BGwG2dLV0TAGvdLN0Age0dLJ0BgGvdBB14XTWdK90C3W/dLB0DQG8dK90YgiydL50XwGwdLJ03wEbAa4BwxO5dLV0UkG0dLB0snTGdNx0sXQQAbB0tXQUATUBsHSzdBgBy3TLdK909nQhAcN0r3RJBrh0s3QPAbp0snSCAed01nSTA7Z0wnQFATICunSydDEBHAG4dLJ0hQJDAbp0r3RFBWABsXS8dGgHr3TZdK90DXU+Abd0r3R3Aa904HR3AbF0vHQvASoBRwW/AVkBI1GwdK90fETsAbt0uHQlAeF03XQSAREBkRa0dK90/AuxdLZ0VwS9dLt0IgHJdMR0MgG0dK90HQMGAbl0s3QrAScBuHSwdIUCHQHIAZAFIgFPOb10r3ReDNB09nSxdLV0r3QJdXIBGAG+MLB0snQ5AmcBsXS1dC8BEgG6dK90MQGvArF0sHQ4AU8BkAF1BLF0BgGxdLN0UQKvdNt0BwEUATQCsHSvdFYC2gG9dK90RgENAbp0r3RNA690DnU/AbR0r3S4Cq9073QPAbJ0snStA30BsHSzdBQBBAG2dK90/QFXBLR0u3QJARABuXS1dHsVFQHDdLN0+QMXAbl0snR7FSoBsHSvdGIBIQFJASkFsXSvdFsQtXS7dOJ01HQaAbZ0r3QuAkwBsHS8dBQBnAG2dL50BQEyAsd0snSAARABx3QJAb90tXRhAxEBt3SydL8H/3TQdDwCsHS+dBgBDgELATwBt3SvdN8KtXTHdBABvXS1dN4GwQK2dMV0BQGydMd0vnS2dCYBsHSydFgBQQG4dK90JwG+dLp0snS7dD4BKwG7Abl0r3RmAwcBtnSvdBcB2gHAdK90aQG8dLl0vnS3dBUBsHSzdHMBnAiwdMJ0GAHhdNB0vQa2dMB0BQG+dLh0uAGwdLN0WQERAb90snRhAwgBt3SwdL8H53TQdA0BtXSvdEICt3S1dCYBsXSydC8BynTJdNYKBQG3dCwCtnS8dFsBt3SzdAsBr3TNdLJ0vHS1dMZ053TfdBF10HQOAQUBPAG2dK90oAIeAcN0r3RNBRkBsHSvdMECHgGwdK907AO0dLF0BwG5dK90SAFMAbR0vHSTa1cB2QFuAbZ04GBMAa90gh/jINp0zXTKARcBsHSydBQBBwGFAooBuHSvdPEBwHTAdLN0tXQLAdUxVgEjAQEtCQFGAbB0s3TsA0EBtnSvdAUBsQF9AwUNt3S4dNEBr3TddHkBtAGvdGwSIgGwdLV07AMJAbF0tXRRAhoBFwHkDLZ0r3ReAx4BsnSvdI8Cr3QbddR0xHSvdNB0wHSxdKcBuHSzdBwBu3S7dBsBKwEdBbl0tXRmAy0Bs3SvdOwBUQG3dGwBCwGvdLICLAG6dLB0ggEsBTgB5nQKAgcBlwEXDL50r3SkAz0BsXSvdFcDJQGwdLN0WgEHAb10r3Q6ATICsXSydDgBDgEnATwBuHSvdAAYv3S2dA8BHwGTAbl0snTmJFsBtnSzdAUBBwHCdK90cgFBAbF0r3QsARwBcAHxAcN0wXTBdGkE4QizB7F0vnS5AbN0x3QaAQUB1AS2dK90IgISAWECegGxdBYFUQKvdAUF53TddP901nRYAbZ0t3QFAfh03XS4dLh0WwHFdLN0KQNPAbR0s3QSFN502HSiDrF0vnRJAQkBsHS1dOQBXAGsATUS1TGBRiMBDgGzdK90oxcXAcN0snTPAhUBIwHMEgkBs3TVMb10snTfdOF03wGxdL90LAEtAbV0r3ShAUUBHAGDC7h0r3QXA690IHVQAbR0tnQRAa90BXUIAVoBiQ+wdBkBJALdGMd0r3QHBTgb1nSvdN0Bs3S+dBUBSwE4Ar10s3RMBcYFsHTDdJwBr3QjdSoBEwFTHLd0r3RgWT4BWAH2AbB0r3TlBTcBtnS5dAUBEgJFAnVVLAKvdBZYGQHFAYRuuHSvdNs20gGwdLN0jwPsdNZ0oQHFdLh0VAE7Abp0r3SrBUoBLAHJBrF0r3SRAk0BsHSzdDcBGwG3dLV0dwEGAcd0nwEjAb501TH4dNZ0ySOTa7F0UwJcAb90vHRhA7B0u3S8dL90nQTeBq4FvXTAdCsCFAG3dLZ0CwGQAbF0unS6AhsBv3S1dLAC+HQadS4BtXSvdMEEu3S4dGwBtXSvdDMBIAHkAXUBsHSvdIoCsXSxdHMcs3S7dHYBuXS8dD4BvnSvdBID7HTQdMp01HQgAcJ0r3THAsV0sHQQAcN0tXTPAkEBLwE/A7F0r3RWAQUBw3SwdM8CWwG4dLN0JwEvAbZ0t3T9AbV0wnS3AbB0Dw+yAa90IgOnAbR0s3QRASABSQFLCLF0r3TBARoBuHSvdDwCLgEpA8QBxXSvdMoF/3TddK90FnW2dMN0RwG6dLV0ggGCAQUBEAa2dLF05AhFARcBgwu2dK90qwYZAeMBryJSQQ0BBQGZAbZ0r3SDAmUBtHRzAZNrsXQ4A3MB5gGoErF0sXQmBAQBNhAKAZYBFgEUASRysHSvdKcxEwG6dLN0TQMzAbZ0tnQQAex033QNASwBmQGxdK90SgOvdCh11QHQdK909AQEAbB0r3RzAbB03HRRAa0CqAxTAq90mQkCB7h0snQ1AQcBtAWBAcN0r3RoBTIBsXSvdCgMHQGLAioIrAFFDtUxr3SsCNh00XTbdMR0/HS3dBwBsHSydBgB1nThdBkBYQx5AQgBElO0dK90QCCzdMJ0SgG1dK90zAURAVoB1BGwdCoBSAG/Abl0r3RAU5QCvHSvdIYIEgHwVKMBvnQWBfYFr3RUCfh033SvdBR1jwKCAWoLunS9dO0BKgEmAb8Bt3SvdOUUr3QHdRoBFAEgArB0r3SxBQgBBQFABrZ0sHRBBBoBugFiArF05AzhCK90OwYnAcB0DgFbAYwCsHSvdFk/LQGBJGsCvgFcELB0r3TREVABw3S2dIQBfQEvAYcysXQOARMBjAK3dK90qggeAREBYwK0dK90kwR2AbF0tnQVAQQBYQwKAQgBFgG0dK900hcSAV0CKwTRAX8OfQPHVrd0r3TGBy4CtXS+dDMBGgG1dK90aQQ+AaAL9gEkAa90ihKwdMJ0EgFkARYFNwGCO7B0r3SRAVQBtHS1dNEEDQFgAkEC7AMXBLB0r3T8FFoBt3S7dAsBiwHRdK90txHfdOd0GAE4Abh0CgIHAbx0r3RJAhMBMQGtKbp0s3QwAxIBRAEWBbh0r3QeBK90KnW8dL50CQG3dLV0vwcHAQkFUgK5dK90sgQ1Abl0s3SuARMBt3SzdH0DHAa4dMZ0HAEbAVECHQWxdLV0eQYYAbd0uHQLAVkBUQJWA7F0xnQoAa90L3XOdLR0MwHFdLZ0VAHwK7Z0sHQXAQ8BOARqAbd0qwgTA1NRvweydLp0UwGwdPN0sgGvAfoBvHR5EhEBx3QNAb50r3QEBI8BunSvdGki6QHpAQIWy3TLdAIWt3THdLB0xXRfAbd0snRmDOx03XQRAbR0snSLPa90M3UFAbF0sHThCDICsHSydFoBFQa6dLd0MQEuAUUxxAEfAa90RGavdDF1WwG0dLN0CAEbAZswtAK6dLV08RfhdN90DgFtBTwBwHSvdNkGs3TmdAUBtHSwdJNrGQGXCXkBDwGvdLgWPwG2dK90mQXFdLV0vXS4dA512nSGAbB0r3RjBEEBt3SvdAsBKQEvAX8GsXSvdDMKwnS1dLJ04HSMAeUIvAHxdK90F3UFAb10sHTeBj8BuHSvdMMJGAG5dLh0HwEFddZ0cwG0dLF0CAFYAbF0t3QsAfh00HQSAcMLowG9dBYF3RCvdAcIt3S6dPZ01nSvdNp0DgEUAnoErQOKBbJ0r3T4BE8D2nSvdMoBCnXKdA0B/QF8AbZ0r3TGAmcBsHS1dFgB9QG0dK903QlZAbR0xnQIAc90sXR8AsF0wXR8Aq90OHW4A7F0w3QvAa90OXUlAcd0s3SAAbN03HTKDLZ0vnQXAa90CHUZAagBPCxRArR0v3RHAbB0tXRzAUoBtnSvdHUCDgG8dK90vAKvdMF0XAG5dLx0KwF1AXABr3QyGA0BsnSvdHETJwHDdLB0cAFZAfAIcQG3dMZ0ngFBAVECqwGxdK90KAHJdMl0ynTbdB4BjQGqCrl0r3QJBuUBsnSydBwGBQK0dLF0CQEQAuMB8kNSQa90gCRLASgB1AdRAm4wsXSwdGYBHQErAmsBvXSlBt4Gr3SxAooBQgJUBrV0r3RVOw0Bu3SvdBUGBgFmDCQBt3RkAhsBr3SkDRx1tHSdAbR0r3R3D0QC8HTKdKABr3QldRkBlgFPAhQBhQuwdLd0t3TvAloCr3RsQBMBsHSzdFgBCgEIBBYBw3SvdGpMaAGwdK901AoJAbl0tXQrAQ0BRAFBArh0r3RxCx0BRAGlBrh0r3S+ER4B5wGqChQB3AuwdK90ihUqAQUBHAK2dK905AivdN50r3T8dA8BMQFnAgUBly62dMB0ZQESARQBhQiwdK90DQShAYAB7QfHdLh0ogb9ASQBKg5hA7F0ERVDAWBZ8gETAa90rQ/gdLB0SAG1dLJ0SwdgAbh0vHSFAt8BtnS/dAUBwnSwdCAB0QJEE+QIr3TMBEMBKgMaKbd0GylmDK90uW1JASMBOSwJAbx01TElAbF0s3Q4ASoBVAHhE8V0r3TFDa903HQ9AbB0r3TYBxIBYgEJArB0r3SVBLsCnwFzHB5TsAH4AScOLwGvdBcUGgFnAQQDt3SvdCoEEQHfAT4CsHRpASUBsBq7dLN0pyUUAbB0tnRBD9l02XQEAVsC1xSwdFJM7AOvdLYI4QG+dLJ0lwHhdB51HQHoAdEDsHRRFhgBr3SlBRcBx3QlARwB1wO4dLN0HAQdAf0CpjUvAa90BhApAbF02gFRAq90DAKvdDx1ewGwdK90HA+xdLJ0jgEoAeEHUQJaN7F0vHRmARABt3S1dPAIGAFmAWkJKAG4dHIDUAG7dLZ0MgIHAb90r3RfAbUBCwGvdKUzw3S0dBQBSAEGFrl0tnTHBR0NuHS8dBwBbQGwdK90mgzDdLd0QQG9dK90SwEuAY4BVBO9dK90nQdZAbh0xnQnAQV13XRKAgUB4gO2dLV0cQEOAWkBjALAdCwByF1tAo0BMgHAdK90PA4NAZwBJQOwdK90TRfDdL10BAFIHwoBSwEWAb10KQEFAqoDtXSvdO0iLQELAcYBt3SvdBkDdAG3dNoBXAWvdJEECwGwdLB0WAFbAa4BxQK5dLN0vwkaASMD4Qn6AV0KeRI5Obt0r3QNDq90PXUOAQgBPAG0dK90eQRaA0sBuANMBbV0wHQgAXEBJTwFAa90vQPLdAZ1HQE1AVEWuHSvdPEGIATsA4whsHS0dKQBBgEcAUsEuHSzdElR2gG4dK90NQE6ASgCiAQYARkBhAE8LMN0r3QuBiUBsnSzdFkE9nTQdFoBfQMKA7d0u3SUARUBsXSzdLoCkga6dLx0MQEZATYQeQGWARJTFAGvdPYLB3XddBABv3S1dP8qswI3AmQEt3RFAbV0r3RVBVsBUQIzA7F0s3QoAUoCsHS1dFkBkwKyAe5CsHSvdOcGCAG/dLB0YQNtAbJ0r3QdFiF12HQUAcB0tnRtBVsBuXSzdB8B43TudA0BpR98AQ8BMyWxdK904BdJHL90wHRPAb10sHRFAQkB4AO0dK90kFwpAWUBqgMFAfUItnSvdGcGMwFNAbZ0Rg0PAQUBkwG2dLJ0ZQEWAX0BIQEsAW8BsXSvdN4aQQEGAa90XFLZdNF01HQGdQ0BrwHgAcJ0r3TTBSABvnSvdMsBDgEJAbUBtHSvdNgjsXTDdAQBzwIWAsN0r3SaCF0BMwE0BrV0r3SgBAQBUAEWArJ0r3TKCw0BpAFoA+wDug2wdK906kSwdL50BAE7A7QMtXSvdMgnLgGkAR8E7APVGrB0r3TSA0QBuXS1dK4BGAGxdLh0LAENAUYBSgW9dK90EQ63dL50BwHGdK905QGeBLB0wnQUATkCvXScCEsBwnRpCbB0w3QSAeMBFgVSQf0NrgGvdDhoEgEQARYFtnSvdDgKBwFpAvoEu3SvdHkWhAG3dLJ0uANzHLB0u3QUAUwBtnS8dOZTt3SzdHoBLwFwBLF0r3QDDLIBt3S8dAsB2XTydAt1hgIHATgB+gSxdK90cwIhAbV0r3RBA6IE0HSvdCcCDQEiAUECvXSvdLRYeQLBAa90rTGxASsBRBm5dLh0iAHsA7Z0vXQFAS0BhwFrAi8Br3ThBlkEuHS7dBwBDwJ9AmsJuQGvdF8UVwS4dLt0RAEuAbJ0r3QgBLR0snTNdM10GQHjBHkBtXSvdGI+QQEoYFwC2QLtERABr3SQCq90JnUPARABwwS2dLJ0sRzfArF0sHTmASEBnmpvAQgB/HS2dGwBXAGkFrR0r3Q9DWkEt3S+dGcBEgG4dK90twLqdOp0r3Q+dWABFwHBCbZ0vHRDEkkCWAHNBbB0snTlBVEBv3RsAYMBr3S/Bp0Bew55A1QBr3Thbg0BQQ+ZAbB0r3Q1ECoBRgFTHL10r3RyadgEYQO0dCQB8gLWdK90bgcPAQsBkwG3dLJ0dwidBBQBrgWwdMB05wEjAbd0WQK/B7N0EwMqAScBHAK4dK90cA9JAbB0vHRzAVEBvXRsAUsBr3TRBr4E0HSvdEwCVQEXAZMMtnSvdKsb53QIdXsFWgHHZrB0xnRxAn0BCgIVAjgBs3RVBuQBtnS0dAUBPgFsFrsBoAIzAgUBr3TGE3YBwnS2dOsCunS2dB1133Q/Abd0r3RHC0EBKwGrAbl0r3RjAUsB7wE2BgUBr3TWdAcBugLYAbF0r3RrBAYBsnSzdCAEQgK0dLd0CQEdAYgLhAOlAq9091k9ATEB2gm6dK90mBGcATgBPwyxdL50CgJRAbh0bAEnAa90cgo9AbV0r3SXGC0B9gmSAioCr3QCG3IBJwHOELh0snTEGZoBBwQWCGkJgUu9dGJkSwGvdC9DRQERAYMLtHSvdHcOLwG9csYCJQK7dLV0aQS0dL50CQG7dLJ0SAGydLJ0bAXUdM10FwK5dFcEKwG7dIIDOgHCdLJ0kSDZdMR0UwFWASIDLwF4B7F083QLPwcBSQEOA7F0r3QUBWwC8wGvdGILHgGEAWMCw3SvdOUy7nSwdJABsCSzAr50unSpD8l0zXQ/ASsBEgK5dK90JwsUAbl0tnQfAXsBVAGPIMV0r3TQFL50tXRXGNB073QnAg8BsXSydLoCGwG+dLV0EgNaAbl0u3QfAQQBnAJZCbB05x6cAa90PQcEARsVCgERAa9002sSARMDegG3dBYFvwevdIAMvHTAdCx13XS3AVoChlIjAcZZCQGvdLYwUAExAlYJunS2dKMwTwG6dLN0mzCvdEF1KgG6Aq90swIGAbd0s3S/BzcBtHS5dAgBDgGydK90bAVFAQUBlQm2dK90cQG1dLp0YQEGda90pRB2AcZ0tnS4ATYCsHS8dDcBfwEQAXRvtnSvdA8LbAGydK90UAE9BTICrlG7dMB0sQMHddZ0BwGKA88JZQGvdIUb2XTYdB4BvwMDBshdr3RAFtR0yXQ6Ab50snT2BSYBunSydE0DUQG7dGwBrwKvdK0ODgGdIL4DOwJrCwUB/XT0dLJ03HQ6ASgBpAFRAs8TsXSydGYB2QFaAR8ftHTTdAkBFQG3dLN0XAV/NewD9HSkAY8CtHS9dBEBIQGvAm8Bu3SvdLlLMQGwdLt0YgF+AbR0r3RBCbJ05nRKAfcCyQZBBOMJBQFiSLZ0r3SCEs509HTaAbl0r3RNAV8BCwHiAbd0snSWCi0BHgKSArt0r3TtB8B0tXTCdLZ0DQFiARACsHSvdGAsyA+1dOV0MwE+ASAEuwGydK90+xCvdP90LAGydLB0rQOhAb90uHTUAUQB1AHXDb90tXSkBA0BTAHgAbZ0r3S6HRcBv3SydP8qwAHLdK906QHHdLF0ynTRdJwJtHS9dAYBLQHJAWsC5AGEGLB0r3TEBEUBGgXSArN0gwt2Aa90JxfvdBJ1JQG3dLN0WwnhdBJ1WQHPAnEBw3TGdMQCSAG5dLJ0CQUgAYsGwAJuAkYVCgKvdPYMznS5dF4BSQH9FLF0r3RmGBIBLwKJDLB0kRZYAa90DhMeARAFYwK+AVgIsHSvdCsWEgEcAZEWuHSvdBwEGgHRARsJt3TkDH0Dr3QkDe90GnWUASMB5AGxdLR0LAHBdNR0r3QRdSJ1tnQFdd90tHS1dA8BJAGrCGED01K/dLJ06wQPAbV0snQFAuwB5AF7B7B0uHTJAfZ03XR+Adx0r3TkBAcBfQOYAbd0r3TRAUUBngF7BLd0lQnwCK90agP4dBJ1QQG5dK90HwGOAbR0vHThW0cB5AjQAgUBUyi2dLV00QLQAdZ073SkAg8BPQKGB7B0qwhZAVcDERWXEyQBz3SNAy0BZwGSArd0r3QhFcV0tHSBAUUCrxcsAq906y4tASwBxgGxdK90AgQaAbB0r3ScAQgBXAUoAbd0HQGwdK90vQYGAVoBng6wdLR0s3RNAQUBqAK2dLN0oAJUAbd0tXQUFgQBVgHeAi8Br3SYBioBlgEcAhQBhgOwdK90NhAzAYUCuwW4dLZ01AsSAfEBuAS4dJEWhQKvdMQSRgI4AbZ0wRQaAUQBBAO4dK90lQ4CB7F0snQVASEBIwLCJoABr3RbBrp0tXTjdNx0FAF9A7ICt3S2dJQBz3TXdHYBHwHyCbl0tnToA2wFcwEiELB0uXSTAd907HQOAU0BjAK5dK90uUfyB2EDsXQkAX4BuHSvdFkZDgFLATwBvXSvdAYJyXTydAQC1nTQdE4DTAFbHg4EKAEXUFECsQFaAQwSsHS4dC8DBiOQAbZ0CwIUAbR0tnQIAQx10HRBAfABr3RsELt0w3ScCKIG+TaAAcJ0jANsBa0DIhCydLl0FAKvdCt1BwG7dK90MgJhAeJ0r3RQBSl1tnQaARABBAO2dK90swcmAcd0snQoAxcBMQEiFrp0OgELAaQBt3SydHMROwEJAXUMtHSvdJAEHXXWdCABWAI2AcB0r3SICh0BAQKcBbl0URYrAa90RgsXArF0VwRRArt0YQIuAVQBtgLFdK90ew7CNcd0xXQkAg8BOAdqARwBqwgJHFNRSVG5dLl0xwF4AzkKtHS7dGcMr3RCdUkCaAeydPMBclsvAet0hwFBAeYBrQGxdK90JgRMAbd0vHTwCC0CsHSydL4BYAGwdLx0GAEaAZ0JBAMMAnsuUQKvdE0M1XTXdEkCsXSydEkBFgImAvwDvwcIVrd0r3TWDBIBtXSvdFcEUQFIAWwBxwWvdLUDPgElIfYBHwGfArl0r3QoD1cY3XTvdM0CFwGzdLJ0dgHrdON0LAEFAVoKtnSwdGUBGwG0dLV0XAF2FgUBsHRxARYLwHS3dPkCBgEfAckBuXSzdGMlTQGCAbx03HTmdLd0DQHbA+ABMQG2Ibp0r3TlODIBt3SvdCgO/HSwdKJSuHTAdGABDgGHAYwCLwH+ArF0r3RZFiEBvHSvdHcJmwKjApAEsXQfH1EC03RhAuZ0sHTvdN10GgGbJ5oBxnQgAkoCr3T7PsJ0wnTOCnsVjxG5dMV0GgILASgByANRArIusXSwdLhIBQFMBJ4BCQERAfcHJAO3dMV0unTBBLF0tHRHAY8BsHSvdMYSx3SydDMBvnS2dMsBDwFMAZgftnQcAbd0snRBDCEBJwFvAbh0r3TEGS11tnTAdLZ0rQHVAygRKAKvdKUSKQG3ApgVuHQ6ATUBfxG4dLJ0LV0JINZ0r3TuAa90P3UNAY0DfAERFVMDJAFcJ2EDr3QPBwoBqgLDQcd013S6dAQBSwHeAr10r3RMBeUBsHSydFkBfwGVAlUSEQGzHLR0r3T7HS4B9wq6A+8Br3S5EQ0Bs3SvdA8ERgELAVsCt3SzdHMRcwG9dLF0SwG9dMN0GAG2dLh0BQGhAUgB4nTidCoBiAG/ASsBERe5dK90awzgdLJ0IQEaFpQELwSvdLdGDQExAXUDunSvdDADxnS1dIIBEwGxdGBZznTodFF1tXR8AboBshaxdDMl4QivdJILGQEXATwstnSvdI8RHAIxWTkEvnSvdB0hsXS3dBIBHiAJAhcBWSi2dK90EgwaAbp0r3QxAh4BBgGZDrR0r3SrBPIHuHSxdDUBdgFzAQADsHS2dDgC6QGOVicDJwMCFmBcjlbpAWBcAhbdZ8t0y3TdZycBt3SwdEEMHgEVAZkOsXSvdG8JHwGnAeQ9snSwdNk7/3QIdT0BunSvdJkKEQHDdLJ0tAUKdfB0r3RPdakfsHSzdCIDuXSydLB0wHQ3Adx0uXTfAhoBvg2aAbwCIALgTlMuvHSvdHoVr3RNdXUCOgEiD710v3QMCrYBtnSvdAALSgEUAWMDsHSvdCsfUwFiAytasHQYAb90uHSDARABtHS1dJNrKQG5dNoBKwGvdAECGgEIAgQDLwGeA7F0r3S6CQ4B/gM8Ab50r3ScCgp1xHTGdLN0PgGDAvYBBQGfArZ0r3QAB690BnXsAYAB+gHHdLh0XANFAcQCewTDdJUJzwKvdLEELAHmCm0CJAGwdH4HNAL8AmwPhAGvdEoJSgG8dK907wkOAUwBZAO2dAB1wXTsdBp17AEkJPoBagGLJ9Ux0AHddO90KwOwdMd0JQG1dLN0VwQOAQ8BegSxdK90IhDQdOd0kAE8Ay00uHS6dDcLIwGwdFkC5AGzdIoCDgEGPYsEKAESAYIMmwOAAa90fgwdAbZ0r3Q9BX4BtnSvdD4IBAEmBN4C5gHwTLF0r3TWAuF0E3UlAZABtAGxdLN0CgovASMCNRSAAeN09HRQAb90tnRfAUEBsQRXDcQCVg/DdK90R0bVdLZ0bwE3BM895wGvdEsrHAFYAToFsHQdAQYBURa0dK90VxMOAfx0CgHIAxYBWAEOASwBPAGxdK90wRILdRwBWgGrAgsGIwH0M9UxQgHvA690Gwv3BHQFsAGwdK90LAXxBrB0SRwYAcB06AEPAbd0snRcBZYC0HSvdAoHlAHiAVEk3wGyA9sBsnTFdNN0unTBAggBxXSeaq90UHWdBLZ0wHQQAccBHAHoBbh0u3RoAjwChAGWNsN0vnTDIC4CsHS+dBQBTQGydLN0bAVdARcBPQq2dK90gQi0dMN0UAE4AbEDsXS2dHMCDQEpOuABlwFnM750r3RnSyYBHwEvArl0snQlIRgBrAENAyMBuHQLJg4BJgJ6BL8HiRe3dAIHtnSydH0BMwG4dLZ0RAEEAUQECgG2dAZAsnS+bK0D6HQUAuwBMQH6Abp0uHS0AdUBQALtMdB0r3Q5Fy0BJQKSAmEDU1q/dK90MhWZAVwEahSCA690SB22A3ABvHR7AgYBCwHJAbd0s3SjER0BagKlBmYDKDErAa90pC7kA4IBw3S+dPAruXSwdEgBLQHUAZICv3SvdKQEvHSzdOQBxXS0dCkDr3RLdb90tXRJArd0snR3AY0Bw3S1dKYRDQEJAUECtHSvdEwEB3XfdAUBtXSwdDMBWQG5dMZ0HwFiCMJ0t3SvAWwBCwJwMpABr3TyBHsFKQNtZcV0xnSGAk0EJAHbdMl0hwTwdNR0oAFoA00BLnXfdB113XTsdAh1RwGxdLV0ugLvdN90FwG3dLJ08AjydMF0v3S/dCEBtnSvdJ4EMg64dLV0RAFYC7B0w3QYAXcBsHS8dFgBDQHFDRACVAHyQ8V0r3TGEBgBLwImUVgBxwGydLt0pwEOAUAEjAJVBpoLOAGkEQoCr3RLLksHu3S5dB4C1nTndL10t3RKAbgBpQ/GdK90GGRBAdpmrQG+dK90xBHzdLh0BXUIdfZ033ReAbB0r3QtDh8fvXTTdCIBFQEFATgCtnSzdGUB7nTjdL10vnTsA7R0vXQIAYYBtXSvdHQl5HTVdDsBRAF1DLh0r3RZBhMBZQGHAQUBuAm2dLN0qwkZAQICTwKFAmQVuHSvdPAWEQLadK90PQOEAcEBDwEhAjkFsHSYHxQBuAGeAT0C8AhjCLd0s3RqA+B0w3Q4G990r3Q1Ax4BLAFQArF0r3TfCVwBsHS8dOQBNQ66dMN0ggFCU5wBZWGwdNd0nAJBAbADMAJyA8gRZgEUUygBr3SlEy0BqgKEGMd0r3QUCfoQuXS9dI0B8gOsBa902zlaAZ8B9DOxdFMBFQKyGRQBCgFNKbwFNAPhUfEXr3TGUHkB6AGvdEAftgG0dK90hwuCAbB0sXRiAR91snQNAcEjCQN+BxcEgAUHF+YKr3SROFUFuHTGdEQBHgEIAqoKLwE3TbF0r3SqDLd0u3R3Abd0vHR9AxIBFwGRFrZ0r3S/EA0BvXSvdAQPCSDQdK90QAIRAbV0snTBBBgBZwISZbF0uHQMJsZ0snQWArIBr3TBC8p08nRLAbd0sHTsBR4B2wMvDzEBGHW3dJUBKQOQCcV0r3QVEZoBIgIgAiwNIwwFAQUBsnSwdFABFQEfATgCuXSzdOYkDgEeArUBu3SvdOoFJQELAXECt3SzdAoDRQWwdNd0YgGvdBV10AHQdO90vgLAdLh0DQE/DCUDrwLBA7t0r3SWGQgBoAJjAQUB/Ay2dLB0bBbOCsN0xXSEAQ0B+QKfFcB0r3QfBUEBVgNXDQgBr3RsLhN19nQTAt90r3TeBfsBEnVdAbZ0r3TID50BsHSvdL4BSwHCdLB0kSAEAQcCUhEYATYrOQKvdEMJQQFTAUotvHSvdJYG7AEoAX0MUQK4dOEDsXS5dF4DsXTKDOEIvnS6ASACDAJrDlECqDCxdK90bgg+AeQBuwGwdK90BAZpAcN0wAEGda900AMIAbB0sHTkAR4BCQGqCrR0r3SADg4BrwI8Abt0r3S7G3wBxQFmAhd1r3QlEUMBtnSvdAQJr3Q7dWkBsHSzdL0GEwG9dLN0BA/CdMN0UAHFdLZ0qgVZArZ0s3QQAR4BHwFQArl0r3R4CBABrgGjASgC8AIYAWozsHSvdGEWxXTFdAcB4Qg0ArF0r3S6ATMBtHS2dAkBr3RYdVUBw3SvdF0NBwFBDIoBt3SvdDoFFAE4Aa0OsXS2dAoCBwFxBA4DwHSvdHsTDgEIA7UB0QTjQLR0r3SEDA8B5AjtAQUBsnTRAh8fuHTTdEQB5RvmAQdpsXTXdCYE8wiAAcJ0IwLydMR0VwEfA0cfFwGvdNgYB3XQdL50s3SSAbZ0r3QKDRQBOgEGFr10UQG+dGwB/gOvdHUNwnTAdE8GxXTFdE8GGQFMASAB/yrWAb90r3TeAwYBZQEMAgUBJRq2dGgBWwE/ErB0r3TOPyEBnldvASQBLgthA9R0wXSxAcQZDSAnAbh0UwQSASgB0QhRAq904AbkBhwGFiWydOZ0bwPzCLZ0wnQXAREBcwGoAbB0EQGydLJ0IATedN50gwOWA690VnUdAbh0r3QrBhIBxwuLA5MBr3S6DCUBs3SzdMcBLwGwdLd0cwEFBgkBNQ6palwBsXS8dFECJgEJAWRFtHSydEwEOwKXAr0GhETPdON0LgEJAbYCtHSvdFgVEQGwdLJ05AEpAbd02gG/B690eARIAQUBlwe2dLJ0oAKIAtF03nTlAmMEt3TudAsBHgHbAWMCBgGaFbR0r3REDQx13XRDATYQwgEUAfIBlgFrY7B0r3T3IBoB2QEEA0wBFh22dO50/XQAdcR07AFNA5NbunS4dNgCwnRuAmkClAG7dNkDIAEGI9YBTwGvdIsxEwGkCg8DCAHaB7R0rSlhDLN03UFUAQUBMRK2dLV0LAIqASwBHAKxdK905CO8dLt0MAJYAXgSsHSvdDYLN3XBdGYC7HSvdJYoLQe8dLB0UwEPBDkCt3QdB3MBLwF3CLF0sXRWAS8BiAE1FCsBSzi5dPx0tHQsAbd0sHRcBQJ143RNASgBqAJRAh8OsXSzdBFlr3TfdNUBgQLtMd10r3TAG8F0xHQOASYBegS3dK902kMeAsd0tXSAAcR01HRFAUQB4AO4dK90EwYdAbV0r3SdBBoB1gliArJ05AxQAa904FivdFl1OwEXARsktnSvdPMfUAG4dLZ0HAE9Ab50r3TYFRwGtnTGdBcBGgHDIMsChAF+CMN0r3SwBRsBWAGpArB0tXTlBZEH1nSvdKQCJQF7AqgDcAF6AWgJgALbAVgEWAE9AY0DcAIRFbcOJAGvdM8EGHW0dCEB0AIVBIIBCSS6dK90WU++AbR0x3QIAdV07nQMA99033RLAjIBuHSvdC43UgG3dNoBfQOvdBYDIAG+CPcDCAGvdE4Mr3TJdI8BlwkmAw8Br3TyFcB0sHR+BJMBFAG/dLZ0gwGbAcEBr3TVNvcBvHSvdCcbewW3dMZ0EwErBlQBwHSlAioBqQ93BL50r3RkBHIBLwLzFFgBsnR0DBkBGALdGLl0ryJ7Fa90zgYJAp8DUgewdK90XwyYArd03Rj3B690STNKAbB0r3TfAa90J3VBAQgBr3SeahUBGAFBARoDMAaxdFcNKAGvdHAOOwN7FcI1uXTFdBgCEQFLB4gBtXTPdO10FAG9dLZ0SwEdAckDURa/CadzuXSvdG8KewVhAwUPv3TGdCQB2Ae2dM90BQEgAUwBSwi2dK902QG3AbN0Dw/JBa90shkgASIC9wMFAa90LA1SAbF02gEvAa90hwE3AcB0uXRtBR4BlwdjAjcBmyiwdK907mb7Ad90vnTcdB4BCAFQArR0r3T3BbZ0vXQCB7d0snQTAVoBUQImKLF0u3QoAewBLwGTW7F0uHSHAdd0tXRDAbV0r3TiBuZ0snRZAeEIcQGxdMZ0LgMeARcBYwK2dK902gsXA7IBIxGwdK90YXXUdPB0BwF3AQ4Dt3SvdM0FXgG2dK90kDBEAbB0tXQYAR4B8wEvD2gH2TqxdK90aRK0ApABNAOxdB4BDwFjArF0r3RqC0UBhgK8DSkDrBjFdK901QVJHLh0wHQ1ARMC0HSvdK8IEXXWdEUBRg3gA00Br3QdFUoBLAjsAo0Br3SFQRd10HTTdNd0HgFoBWMCtAX/AsN0r3TTMpMDtHTCdAgB6gHQdK902AOiBNZ0r3SCAg0BzQN8KkwFMzNLAa90VRQGAbV0s3TBBIEBzATSS9ECr3QfW1EBLwFsAVYBbAKxdK90xBN3AQUB5QW2dLx0gwI1ARkCTgr5A7J0s3QeAQsCZnOQAXcBHzv4ASIBGVq9dNYBoAIEEQUB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WQK5dLN0jQF+AS8BXw2xdK908zFnAR8BVAO5dLV0JSEbAXMBwQGwdLV0OgRtAQsBtwO3dK908F8NASgBmQFRAhwbsXSvdLhIQwQ6BD0ecwFJAQsBOgS3dLx0dwiHAcICRgjDdBEUzwKzdCJe1AI/BBQNcQKjaloBr3SFFdt08HRJHL8JwHTJAzIB9HSvdJkEPwIjARQBuHS2dCcB7AIkAa90IEXBAsJ0xXQGA5AE1gIrBSYELQHwA6kBZQFNDQUBMxa2dLx0x3TDIMEBuHT+BQkBsnS1dCAEGHWxdCcDcCNiBWIFcCMnA45W8G7wbo5WrQFzAhEBOQyIASIBzwa9dA0BWwFKBbB0znTOdMIBw3TyAQgEr3TtPGYBsHT3BXMBvXTgB+sC7AEdAckBnAWwdFEW5AENddd0PAEmB35vlRKvdBgTfgEGAUICZwLOA8B0tXRYAtgHsXTPdCwBBwHgdK90QgMsAZ4BHAW3dFoK8AiwdGkINQGgAhUDBQHyG7Z0s3RXZSgCt3Q8AgsBvnQZAywGoAOvdFw6IAG9dK90IgEFAdkCNwwQAbB0KGAoAXAB0QO9dFEW0VOvdL8lkgbHdLx0gAHbAbd0Age/B7J0eAQyAmcMLC+0dA9JeAOydAoF3wG3dL90CwEuddZ0CgF2A18Kt3TDQWYMz3S6dAoB7gaiCbF0UgIIHBQDHwGvdJddNwG+dLl0/gNqBEwCVxg8FPZO0HTvdAcgbQGzdK90cls1Abd0s3RBDLQDu3TDdMhEkQfQdK90vgJ2AQsB8gm3dLZ0RwISAbx0r3RzEzEBCAGVBLR0u3RhDFMX9HTOdIwEaAELAYEDt3SvdKIP8wGQA30BsXSzdOEIIQG3BToJHwGXC7l0wiYlIa90MxoeAbV0r3T6EA4BVgE8AS8BKQKxdK90rh4JU790vnRhAxQBCAGhA7R0tnSeamwB/WopBDQEr3RmUjoBjwLyErJ0GwG5dLV0NgJRATsCXwgFAa90M09ZAncBs3SpArMBYAHeFLh0r3Rtaw0BGguZAf8Er3R+ERwBuXSydK4BHwGwdLB0NwEZAb1yNgklAtV0tHQ+AQlPuwFgBa90eXIPBHMBt3Q4AoQBBQG6PbZ0snSuHXUBWgGvdJYpFwG2dLJ05lOpBS8BUAVQBahj4nTidKhjDQGPBK90gRMXAbR0snSTa+EBs3SydF8G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" + +const llamaTokenizer = new LlamaTokenizer(); + +if (typeof window !== 'undefined') { + window.llamaTokenizer = llamaTokenizer +} + +export default llamaTokenizer \ No newline at end of file diff --git a/core/llm/llamaTokenizerWorkerPool.mjs b/core/llm/llamaTokenizerWorkerPool.mjs new file mode 100644 index 000000000..2131f4a1a --- /dev/null +++ b/core/llm/llamaTokenizerWorkerPool.mjs @@ -0,0 +1,10 @@ +import workerpool from "workerpool"; +import llamaTokenizer from "./llamaTokenizer.mjs"; + +function encode(segment) { + return llamaTokenizer.encode(segment); +} + +workerpool.worker({ + encode, +}); \ No newline at end of file diff --git a/core/llm/llms/Anthropic.ts b/core/llm/llms/Anthropic.ts index 213790641..918c9338a 100644 --- a/core/llm/llms/Anthropic.ts +++ b/core/llm/llms/Anthropic.ts @@ -4,7 +4,7 @@ import { LLMOptions, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { BaseLLM } from "../index.js"; import { streamSse } from "../stream.js"; diff --git a/core/llm/llms/Azure.ts b/core/llm/llms/Azure.ts new file mode 100644 index 000000000..ce20b4ecc --- /dev/null +++ b/core/llm/llms/Azure.ts @@ -0,0 +1,8 @@ +import { ModelProvider } from "../../index.js"; +import OpenAI from "./OpenAI.js"; + +class Azure extends OpenAI { + static providerName: ModelProvider = "azure"; +} + +export default Azure; diff --git a/core/llm/llms/Bedrock.ts b/core/llm/llms/Bedrock.ts index 19b4c85d2..060deb198 100644 --- a/core/llm/llms/Bedrock.ts +++ b/core/llm/llms/Bedrock.ts @@ -10,7 +10,7 @@ import { MessageContent, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { BaseLLM } from "../index.js"; class Bedrock extends BaseLLM { diff --git a/core/llm/llms/Cloudflare.ts b/core/llm/llms/Cloudflare.ts index dcaf333c4..7084360f2 100644 --- a/core/llm/llms/Cloudflare.ts +++ b/core/llm/llms/Cloudflare.ts @@ -1,6 +1,6 @@ import { BaseLLM } from "../index.js"; import { ChatMessage, CompletionOptions, ModelProvider } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { streamSse } from "../stream.js"; export default class Cloudflare extends BaseLLM { @@ -38,7 +38,6 @@ export default class Cloudflare extends BaseLLM { }); for await (const value of streamSse(resp)) { - console.log(value); if (value.choices?.[0]?.delta?.content) { yield value.choices[0].delta; } diff --git a/core/llm/llms/Cohere.ts b/core/llm/llms/Cohere.ts index 6ca492bb2..fd6df4f82 100644 --- a/core/llm/llms/Cohere.ts +++ b/core/llm/llms/Cohere.ts @@ -5,7 +5,7 @@ import { LLMOptions, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { streamJSON } from "../stream.js"; class Cohere extends BaseLLM { diff --git a/core/llm/llms/Deepseek.ts b/core/llm/llms/Deepseek.ts index 48dc9e61b..e8342b546 100644 --- a/core/llm/llms/Deepseek.ts +++ b/core/llm/llms/Deepseek.ts @@ -1,4 +1,5 @@ -import { LLMOptions, ModelProvider } from "../../index.js"; +import { CompletionOptions, LLMOptions, ModelProvider } from "../../index.js"; +import { streamSse } from "../stream.js"; import { osModelsEditPrompt } from "../templates/edit.js"; import OpenAI from "./OpenAI.js"; @@ -13,6 +14,41 @@ class Deepseek extends OpenAI { useLegacyCompletionsEndpoint: false, }; protected maxStopWords: number | undefined = 16; + + supportsFim(): boolean { + return true; + } + + async *_streamFim( + prefix: string, + suffix: string, + options: CompletionOptions, + ): AsyncGenerator { + const endpoint = new URL("beta/completions", this.apiBase); + const resp = await this.fetch(endpoint, { + method: "POST", + body: JSON.stringify({ + model: options.model, + prompt: prefix, + suffix, + max_tokens: options.maxTokens, + temperature: options.temperature, + top_p: options.topP, + frequency_penalty: options.frequencyPenalty, + presence_penalty: options.presencePenalty, + stop: options.stop, + stream: true, + }), + headers: { + "Content-Type": "application/json", + Accept: "application/json", + Authorization: `Bearer ${this.apiKey}`, + }, + }); + for await (const chunk of streamSse(resp)) { + yield chunk.choices[0].text; + } + } } export default Deepseek; diff --git a/core/llm/llms/Flowise.ts b/core/llm/llms/Flowise.ts index 14e2451e4..876595f43 100644 --- a/core/llm/llms/Flowise.ts +++ b/core/llm/llms/Flowise.ts @@ -5,7 +5,7 @@ import { LLMOptions, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { BaseLLM } from "../index.js"; interface IFlowiseApiOptions { diff --git a/core/llm/llms/FreeTrial.ts b/core/llm/llms/FreeTrial.ts index b2db6a5a1..e4c1674e6 100644 --- a/core/llm/llms/FreeTrial.ts +++ b/core/llm/llms/FreeTrial.ts @@ -165,7 +165,8 @@ class FreeTrial extends BaseLLM { return [ "codestral-latest", "claude-3-5-sonnet-20240620", - "llama3-70b", + "llama3.1-405b", + "llama3.1-70b", "gpt-4o", "gpt-3.5-turbo", "claude-3-haiku-20240307", diff --git a/core/llm/llms/Gemini.ts b/core/llm/llms/Gemini.ts index 422f42e06..9a33f06a4 100644 --- a/core/llm/llms/Gemini.ts +++ b/core/llm/llms/Gemini.ts @@ -5,7 +5,7 @@ import { MessagePart, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { BaseLLM } from "../index.js"; import { streamResponse } from "../stream.js"; diff --git a/core/llm/llms/Groq.ts b/core/llm/llms/Groq.ts index 0aa5b5636..27c51e1e3 100644 --- a/core/llm/llms/Groq.ts +++ b/core/llm/llms/Groq.ts @@ -14,6 +14,9 @@ class Groq extends OpenAI { gemma: "gemma-7b-it", "llama3-8b": "llama3-8b-8192", "llama3-70b": "llama3-70b-8192", + "llama3.1-8b": "llama-3.1-8b-instant", + "llama3.1-70b": "llama-3.1-70b-versatile", + "llama3.1-405b": "llama-3.1-405b-reasoning", }; protected _convertModelName(model: string): string { return Groq.modelConversion[model] ?? model; diff --git a/core/llm/llms/HuggingFaceInferenceAPI.ts b/core/llm/llms/HuggingFaceInferenceAPI.ts index a016a357d..21b607163 100644 --- a/core/llm/llms/HuggingFaceInferenceAPI.ts +++ b/core/llm/llms/HuggingFaceInferenceAPI.ts @@ -1,4 +1,3 @@ -import { stopAtStopTokens } from "../../autocomplete/charStream.js"; import { CompletionOptions, ModelProvider } from "../../index.js"; import { BaseLLM } from "../index.js"; import { streamSse } from "../stream.js"; @@ -50,7 +49,7 @@ class HuggingFaceInferenceAPI extends BaseLLM { } } - for await (const text of stopAtStopTokens(stream(), options.stop ?? [])) { + for await (const text of stream()) { yield text; } } diff --git a/core/llm/llms/Mistral.ts b/core/llm/llms/Mistral.ts index fee8fadac..95208bb8c 100644 --- a/core/llm/llms/Mistral.ts +++ b/core/llm/llms/Mistral.ts @@ -14,8 +14,11 @@ class Mistral extends OpenAI { constructor(options: LLMOptions) { super(options); - if (options.model.includes("codestral")) { - this.apiBase = "https://codestral.mistral.ai/v1/"; + if ( + options.model.includes("codestral") && + !options.model.includes("mamba") + ) { + this.apiBase = options.apiBase ?? "https://codestral.mistral.ai/v1/"; } } @@ -31,7 +34,7 @@ class Mistral extends OpenAI { const finalOptions = super._convertArgs(options, messages); const lastMessage = finalOptions.messages[finalOptions.messages.length - 1]; - if (lastMessage.role === "assistant") { + if (lastMessage?.role === "assistant") { (lastMessage as any).prefix = true; } diff --git a/core/llm/llms/Ollama.ts b/core/llm/llms/Ollama.ts index e24a489f0..fe2eb6d6a 100644 --- a/core/llm/llms/Ollama.ts +++ b/core/llm/llms/Ollama.ts @@ -4,7 +4,7 @@ import { LLMOptions, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { BaseLLM } from "../index.js"; import { streamResponse } from "../stream.js"; @@ -88,6 +88,9 @@ class Ollama extends BaseLLM { "codellama-70b": "codellama:70b", "llama3-8b": "llama3:8b", "llama3-70b": "llama3:70b", + "llama3.1-8b": "llama3.1:8b", + "llama3.1-70b": "llama3.1:70b", + "llama3.1-405b": "llama3.1:405b", "phi-2": "phi:2.7b", "phind-codellama-34b": "phind-codellama:34b-v2", "wizardcoder-7b": "wizardcoder:7b-python", diff --git a/core/llm/llms/OpenAI.ts b/core/llm/llms/OpenAI.ts index 470f5184b..366f6bd60 100644 --- a/core/llm/llms/OpenAI.ts +++ b/core/llm/llms/OpenAI.ts @@ -4,7 +4,7 @@ import { LLMOptions, ModelProvider, } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; import { BaseLLM } from "../index.js"; import { streamSse } from "../stream.js"; @@ -36,6 +36,7 @@ const CHAT_ONLY_MODELS = [ "gpt-4-vision", "gpt-4-0125-preview", "gpt-4-1106-preview", + "gpt-4o-mini", ]; class OpenAI extends BaseLLM { diff --git a/core/llm/llms/Replicate.ts b/core/llm/llms/Replicate.ts index 7cfa6e890..5dde24014 100644 --- a/core/llm/llms/Replicate.ts +++ b/core/llm/llms/Replicate.ts @@ -18,6 +18,9 @@ class Replicate extends BaseLLM { "llama2-13b": "meta/llama-2-13b-chat" as any, "llama3-8b": "meta/meta-llama-3-8b-instruct" as any, "llama3-70b": "meta/meta-llama-3-70b-instruct" as any, + "llama3.1-8b": "meta/meta-llama-3.1-8b-instruct" as any, + "llama3.1-70b": "meta/meta-llama-3.1-70b-instruct" as any, + "llama3.1-405b": "meta/meta-llama-3.1-405b-instruct" as any, "zephyr-7b": "nateraw/zephyr-7b-beta:b79f33de5c6c4e34087d44eaea4a9d98ce5d3f3a09522f7328eea0685003a931", "mistral-7b": diff --git a/core/llm/llms/Together.ts b/core/llm/llms/Together.ts index 277389c77..eaa144277 100644 --- a/core/llm/llms/Together.ts +++ b/core/llm/llms/Together.ts @@ -19,6 +19,9 @@ class Together extends OpenAI { "codellama-70b": "codellama/CodeLlama-70b-Instruct-hf", "llama3-8b": "meta-llama/Llama-3-8b-chat-hf", "llama3-70b": "meta-llama/Llama-3-70b-chat-hf", + "llama3.1-8b": "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", + "llama3.1-70b": "meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo", + "llama3.1-405b": "meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", "llama2-7b": "togethercomputer/llama-2-7b-chat", "llama2-13b": "togethercomputer/llama-2-13b-chat", "llama2-70b": "togethercomputer/llama-2-70b-chat", diff --git a/core/llm/llms/index.ts b/core/llm/llms/index.ts index a245f025c..20f77c850 100644 --- a/core/llm/llms/index.ts +++ b/core/llm/llms/index.ts @@ -27,6 +27,7 @@ import LlamaCpp from "./LlamaCpp.js"; import Llamafile from "./Llamafile.js"; import Mistral from "./Mistral.js"; import Msty from "./Msty.js"; +import Azure from "./Azure.js"; import Ollama from "./Ollama.js"; import OpenAI from "./OpenAI.js"; import Replicate from "./Replicate.js"; @@ -124,6 +125,7 @@ const LLMs = [ Cloudflare, Deepseek, Msty, + Azure, ]; export async function llmFromDescription( diff --git a/core/llm/llms/stubs/ContinueProxy.ts b/core/llm/llms/stubs/ContinueProxy.ts index f23ea35cc..3049abc3b 100644 --- a/core/llm/llms/stubs/ContinueProxy.ts +++ b/core/llm/llms/stubs/ContinueProxy.ts @@ -1,12 +1,30 @@ import type { LLMOptions, ModelProvider } from "../../.."; +import { CONTROL_PLANE_URL } from "../../../control-plane/client"; import OpenAI from "../OpenAI.js"; class ContinueProxy extends OpenAI { + private _workOsAccessToken: string | undefined = undefined; + + get workOsAccessToken(): string | undefined { + return this._workOsAccessToken; + } + + set workOsAccessToken(value: string | undefined) { + if (this._workOsAccessToken !== value) { + this._workOsAccessToken = value; + this.apiKey = value; + } + } static providerName: ModelProvider = "continue-proxy"; static defaultOptions: Partial = { - apiBase: "http://localhost:3000/proxy/v1", + apiBase: new URL("/model-proxy/v1", CONTROL_PLANE_URL).toString(), + useLegacyCompletionsEndpoint: false, }; + supportsCompletions(): boolean { + return false; + } + supportsFim(): boolean { return true; } diff --git a/core/llm/templates/chat.ts b/core/llm/templates/chat.ts index e230fe7f7..17fae23cb 100644 --- a/core/llm/templates/chat.ts +++ b/core/llm/templates/chat.ts @@ -1,5 +1,5 @@ import { ChatMessage } from "../../index.js"; -import { stripImages } from "../countTokens.js"; +import { stripImages } from "../images.js"; function templateFactory( systemMessage: (msg: ChatMessage) => string, diff --git a/core/llm/templates/edit.ts b/core/llm/templates/edit.ts index f6bf1e848..fd288a48e 100644 --- a/core/llm/templates/edit.ts +++ b/core/llm/templates/edit.ts @@ -95,7 +95,7 @@ ${otherData.codeToEdit} ${suffixTag} \`\`\` -Please rewrite the entire code block above in order to satisfy the following request: "${otherData.userInput}".${suffixExplanation}`, +Please rewrite the entire code block above in order to satisfy the following request: "${otherData.userInput}". You should rewrite the entire code block without leaving placeholders, even if the code is the same as before.${suffixExplanation}`, }, { role: "assistant", @@ -115,7 +115,7 @@ ${otherData.codeToEdit} ${suffixTag} \`\`\` -Please rewrite the entire code block above, editing the portion below "${START_TAG}" in order to satisfy the following request: "${otherData.userInput}".${suffixExplanation} +Please rewrite the entire code block above, editing the portion below "${START_TAG}" in order to satisfy the following request: "${otherData.userInput}". You should rewrite the entire code block without leaving placeholders, even if the code is the same as before.${suffixExplanation} `, }, { diff --git a/core/package-lock.json b/core/package-lock.json index e4587f56b..2778a31d1 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -11,6 +11,8 @@ "dependencies": { "@aws-sdk/client-bedrock-runtime": "^3.574.0", "@aws-sdk/credential-providers": "^3.596.0", + "@continuedev/config-types": "^1.0.10", + "@continuedev/llm-info": "^1.0.1", "@mozilla/readability": "^0.5.0", "@octokit/rest": "^20.0.2", "@types/jsdom": "^21.1.6", @@ -45,6 +47,7 @@ "openai": "^4.20.1", "pg": "^8.11.3", "posthog-node": "^3.6.3", + "quick-lru": "^7.0.0", "replicate": "^0.26.0", "request": "^2.88.2", "socket.io-client": "^4.7.3", @@ -56,7 +59,9 @@ "vectordb": "^0.4.20", "web-tree-sitter": "^0.21.0", "win-ca": "^3.5.1", - "yaml": "^2.4.2" + "workerpool": "^9.1.3", + "yaml": "^2.4.2", + "zod": "^3.23.8" }, "devDependencies": { "@babel/preset-env": "^7.24.7", @@ -71,6 +76,7 @@ "eslint": "^8", "eslint-plugin-import": "^2.29.1", "jest": "^29.7.0", + "myers-diff": "^2.1.0", "onnxruntime-common": "1.14.0", "onnxruntime-web": "1.14.0", "ts-jest": "^29.1.1" @@ -3799,22 +3805,6 @@ "@biomejs/cli-win32-x64": "1.6.4" } }, - "node_modules/@biomejs/cli-darwin-arm64": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.6.4.tgz", - "integrity": "sha512-2WZef8byI9NRzGajGj5RTrroW9BxtfbP9etigW1QGAtwu/6+cLkdPOWRAs7uFtaxBNiKFYA8j/BxV5zeAo5QOQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, "node_modules/@biomejs/cli-darwin-x64": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.6.4.tgz", @@ -3831,165 +3821,18 @@ "node": ">=14.21.3" } }, - "node_modules/@biomejs/cli-linux-arm64": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.6.4.tgz", - "integrity": "sha512-wAOieaMNIpLrxGc2/xNvM//CIZg7ueWy3V5A4T7gDZ3OL/Go27EKE59a+vMKsBCYmTt7jFl4yHz0TUkUbodA/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" + "node_modules/@continuedev/config-types": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@continuedev/config-types/-/config-types-1.0.10.tgz", + "integrity": "sha512-QuL4g9f889JlJtOnNTy/7MlLFx6+KBAQWWWcjQswPZmGIXK6e+i13ZufuEla6AIOH3JzBTC5Z/ipX9IYmTrcpg==", + "dependencies": { + "zod": "^3.23.8" } }, - "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.6.4.tgz", - "integrity": "sha512-Hp8Jwt6rjj0wCcYAEN6/cfwrrPLLlGOXZ56Lei4Pt4jy39+UuPeAVFPeclrrCfxyL1wQ2xPrhd/saTHSL6DoJg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.6.4.tgz", - "integrity": "sha512-qTWhuIw+/ePvOkjE9Zxf5OqSCYxtAvcTJtVmZT8YQnmY2I62JKNV2m7tf6O5ViKZUOP0mOQ6NgqHKcHH1eT8jw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.6.4.tgz", - "integrity": "sha512-wqi0hr8KAx5kBO0B+m5u8QqiYFFBJOSJVSuRqTeGWW+GYLVUtXNidykNqf1JsW6jJDpbkSp2xHKE/bTlVaG2Kg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-arm64": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.6.4.tgz", - "integrity": "sha512-Wp3FiEeF6v6C5qMfLkHwf4YsoNHr/n0efvoC8jCKO/kX05OXaVExj+1uVQ1eGT7Pvx0XVm/TLprRO0vq/V6UzA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-x64": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.6.4.tgz", - "integrity": "sha512-mz183Di5hTSGP7KjNWEhivcP1wnHLGmOxEROvoFsIxMYtDhzJDad4k5gI/1JbmA0xe4n52vsgqo09tBhrMT/Zg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } + "node_modules/@continuedev/llm-info": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@continuedev/llm-info/-/llm-info-1.0.1.tgz", + "integrity": "sha512-fmRXuOSwJ9ogBPSDduoedHF3WVg1rge3o8SRRg1hkUagRnxwZqtQj1sS5SjQyAqjQv6VPMGPDEtD77Za/hc4Jg==" }, "node_modules/@esbuild/darwin-x64": { "version": "0.17.19", @@ -4007,278 +3850,6 @@ "node": ">=12" } }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -4864,18 +4435,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@lancedb/vectordb-darwin-arm64": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.4.20.tgz", - "integrity": "sha512-ffP2K4sA5mQTgePyARw1y8dPN996FmpvyAYoWO+TSItaXlhcXvc+KVa5udNMCZMDYeEnEv2Xpj6k4PwW3oBz+A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, "node_modules/@lancedb/vectordb-darwin-x64": { "version": "0.4.20", "resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.4.20.tgz", @@ -4888,42 +4447,6 @@ "darwin" ] }, - "node_modules/@lancedb/vectordb-linux-arm64-gnu": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.4.20.tgz", - "integrity": "sha512-FpNOjOsz3nJVm6EBGyNgbOW2aFhsWZ/igeY45Z8hbZaaK2YBwrg/DASoNlUzgv6IR8cUaGJ2irNVJfsKR2cG6g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lancedb/vectordb-linux-x64-gnu": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.4.20.tgz", - "integrity": "sha512-pOqWjrRZQSrLTlQPkjidRii7NZDw8Xu9pN6ouVu2JAK8n81FXaPtFCyAI+Y3v9GpnYDN0rvD4eQ36aHAVPsa2g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lancedb/vectordb-win32-x64-msvc": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.4.20.tgz", - "integrity": "sha512-5J5SsYSJ7jRCmU/sgwVHdrGz43B/7R2T9OEoFTKyVAtqTZdu75rkytXyn9SyEayXVhlUOaw76N0ASm0hAoDS/A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@mozilla/readability": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.5.0.tgz", @@ -11202,6 +10725,15 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/myers-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/myers-diff/-/myers-diff-2.1.0.tgz", + "integrity": "sha512-6s/caiGUb5vNH9kq5HPw9t9OzAq6hTJ5V5N5Damd/npcp+stLg2LxQIcgJa9o51qbfTVgfth6/yVCoJvZY85BQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/mysql2": { "version": "3.9.7", "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.9.7.tgz", @@ -12392,6 +11924,17 @@ "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" }, + "node_modules/quick-lru": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-7.0.0.tgz", + "integrity": "sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -14223,27 +13766,6 @@ "node": ">=4" } }, - "node_modules/win-export-certificate-and-key": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/win-export-certificate-and-key/-/win-export-certificate-and-key-1.1.2.tgz", - "integrity": "sha512-3Su7Xdt9UR8pZicWQDcGSWNL6We/NzAGxe7AeQ1Z/zAeGHWlTKAh3HemGvIvxLRPsk4NW9D/QL3cL6SIvFcTvQ==", - "hasInstallScript": true, - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^3.1.0", - "node-forge": "^1.2.1" - } - }, - "node_modules/win-export-certificate-and-key/node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "optional": true - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -14266,6 +13788,11 @@ "node": ">=12.17" } }, + "node_modules/workerpool": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.1.3.tgz", + "integrity": "sha512-LhUrk4tbxJRDQmRrrFWA9EnboXI79fe0ZNTy3u8m+dqPN1EkVSIsQYAB8OF/fkyhG8Rtup+c/bzj/+bzbG8fqg==" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -14413,6 +13940,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/core/package.json b/core/package.json index 37fdb0c16..43cc7d5ab 100644 --- a/core/package.json +++ b/core/package.json @@ -24,6 +24,7 @@ "eslint": "^8", "eslint-plugin-import": "^2.29.1", "jest": "^29.7.0", + "myers-diff": "^2.1.0", "onnxruntime-common": "1.14.0", "onnxruntime-web": "1.14.0", "ts-jest": "^29.1.1" @@ -31,6 +32,8 @@ "dependencies": { "@aws-sdk/client-bedrock-runtime": "^3.574.0", "@aws-sdk/credential-providers": "^3.596.0", + "@continuedev/config-types": "^1.0.10", + "@continuedev/llm-info": "^1.0.1", "@mozilla/readability": "^0.5.0", "@octokit/rest": "^20.0.2", "@types/jsdom": "^21.1.6", @@ -65,6 +68,7 @@ "openai": "^4.20.1", "pg": "^8.11.3", "posthog-node": "^3.6.3", + "quick-lru": "^7.0.0", "replicate": "^0.26.0", "request": "^2.88.2", "socket.io-client": "^4.7.3", @@ -76,7 +80,9 @@ "vectordb": "^0.4.20", "web-tree-sitter": "^0.21.0", "win-ca": "^3.5.1", - "yaml": "^2.4.2" + "workerpool": "^9.1.3", + "yaml": "^2.4.2", + "zod": "^3.23.8" }, "puppeteer": { "chromium_revision": "119.0.6045.105" diff --git a/core/protocol/core.ts b/core/protocol/core.ts index df143b9ba..aa43bdd09 100644 --- a/core/protocol/core.ts +++ b/core/protocol/core.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import type { BrowserSerializedContinueConfig, ChatMessage, @@ -15,6 +16,7 @@ import type { SiteIndexingConfig, } from ".."; import type { AutocompleteInput } from "../autocomplete/completionProvider"; +import { ProfileDescription } from "../config/ConfigHandler"; export type ProtocolGeneratorType = AsyncGenerator<{ done?: boolean; @@ -47,9 +49,13 @@ export type ToCoreFromIdeOrWebviewProtocol = { ]; "config/newPromptFile": [undefined, void]; "config/ideSettingsUpdate": [IdeSettings, void]; - "config/getBrowserSerialized": [undefined, BrowserSerializedContinueConfig]; + "config/getSerializedProfileInfo": [ + undefined, + { config: BrowserSerializedContinueConfig; profileId: string }, + ]; "config/deleteModel": [{ title: string }, void]; "config/reload": [undefined, BrowserSerializedContinueConfig]; + "config/listProfiles": [undefined, ProfileDescription[]]; "context/getContextItems": [ { name: string; @@ -63,6 +69,7 @@ export type ToCoreFromIdeOrWebviewProtocol = { "autocomplete/complete": [AutocompleteInput, string[]]; "context/addDocs": [SiteIndexingConfig, void]; "context/removeDocs": [{ baseUrl: string }, void]; + "context/indexDocs": [{ reIndex: boolean }, void]; "autocomplete/cancel": [undefined, void]; "autocomplete/accept": [{ completionId: string }, void]; "command/run": [ @@ -138,4 +145,8 @@ export type ToCoreFromIdeOrWebviewProtocol = { void, ]; addAutocompleteModel: [{ model: ModelDescription }, void]; + + "profiles/switch": [{ id: string }, undefined]; + + "auth/getAuthUrl": [undefined, { url: string }]; }; diff --git a/core/protocol/coreWebview.ts b/core/protocol/coreWebview.ts index 6aa130112..f124cf2a6 100644 --- a/core/protocol/coreWebview.ts +++ b/core/protocol/coreWebview.ts @@ -1,5 +1,10 @@ +import { ProfileDescription } from "../config/ConfigHandler.js"; import { ToCoreFromIdeOrWebviewProtocol } from "./core.js"; import { ToWebviewFromIdeOrCoreProtocol } from "./webview.js"; -export type ToCoreFromWebviewProtocol = ToCoreFromIdeOrWebviewProtocol; -export type ToWebviewFromCoreProtocol = ToWebviewFromIdeOrCoreProtocol; +export type ToCoreFromWebviewProtocol = ToCoreFromIdeOrWebviewProtocol & { + didChangeSelectedProfile: [{ id: string }, void]; +}; +export type ToWebviewFromCoreProtocol = ToWebviewFromIdeOrCoreProtocol & { + didChangeAvailableProfiles: [{ profiles: ProfileDescription[] }, void]; +}; diff --git a/core/protocol/ide.ts b/core/protocol/ide.ts index 84a5fc1ab..13988a0d1 100644 --- a/core/protocol/ide.ts +++ b/core/protocol/ide.ts @@ -11,6 +11,7 @@ import type { RangeInFile, Thread, } from ".."; +import { ControlPlaneSessionInfo } from "../control-plane/client"; export type ToIdeFromWebviewOrCoreProtocol = { // Methods from IDE type @@ -75,5 +76,18 @@ export type ToIdeFromWebviewOrCoreProtocol = { gotoDefinition: [{ location: Location }, RangeInFile[]]; getGitHubAuthToken: [undefined, string | undefined]; + getControlPlaneSessionInfo: [ + { silent: boolean }, + ControlPlaneSessionInfo | undefined, + ]; + logoutOfControlPlane: [undefined, void]; pathSep: [undefined, string]; }; + +export type ToWebviewOrCoreFromIdeProtocol = { + didChangeActiveTextEditor: [{ filepath: string }, void]; + didChangeControlPlaneSessionInfo: [ + { sessionInfo: ControlPlaneSessionInfo | undefined }, + void, + ]; +}; diff --git a/core/protocol/index.ts b/core/protocol/index.ts index ac89c3b42..495c2fb90 100644 --- a/core/protocol/index.ts +++ b/core/protocol/index.ts @@ -2,6 +2,7 @@ import { ToCoreFromWebviewProtocol, ToWebviewFromCoreProtocol, } from "./coreWebview.js"; +import { ToWebviewOrCoreFromIdeProtocol } from "./ide.js"; import { ToCoreFromIdeProtocol, ToIdeFromCoreProtocol } from "./ideCore.js"; import { ToIdeFromWebviewProtocol, @@ -13,17 +14,19 @@ export type IProtocol = Record; // IDE export type ToIdeProtocol = ToIdeFromWebviewProtocol & ToIdeFromCoreProtocol; export type FromIdeProtocol = ToWebviewFromIdeProtocol & - ToCoreFromIdeProtocol & { - didChangeActiveTextEditor: [{ filepath: string }, void]; - }; + ToCoreFromIdeProtocol & + ToWebviewOrCoreFromIdeProtocol; // Webview export type ToWebviewProtocol = ToWebviewFromIdeProtocol & - ToWebviewFromCoreProtocol; + ToWebviewFromCoreProtocol & + ToWebviewOrCoreFromIdeProtocol; export type FromWebviewProtocol = ToIdeFromWebviewProtocol & ToCoreFromWebviewProtocol; // Core -export type ToCoreProtocol = ToCoreFromIdeProtocol | ToCoreFromWebviewProtocol; +export type ToCoreProtocol = ToCoreFromIdeProtocol & + ToCoreFromWebviewProtocol & + ToWebviewOrCoreFromIdeProtocol; export type FromCoreProtocol = ToWebviewFromCoreProtocol & ToIdeFromCoreProtocol; diff --git a/core/protocol/passThrough.ts b/core/protocol/passThrough.ts index f0734bcac..5fe14573a 100644 --- a/core/protocol/passThrough.ts +++ b/core/protocol/passThrough.ts @@ -18,13 +18,14 @@ export const WEBVIEW_TO_CORE_PASS_THROUGH: (keyof ToCoreFromWebviewProtocol)[] = "config/addModel", "config/newPromptFile", "config/ideSettingsUpdate", - "config/getBrowserSerialized", + "config/getSerializedProfileInfo", "config/deleteModel", "config/reload", "context/getContextItems", "context/loadSubmenuItems", "context/addDocs", "context/removeDocs", + "context/indexDocs", "autocomplete/complete", "autocomplete/cancel", "autocomplete/accept", @@ -41,6 +42,9 @@ export const WEBVIEW_TO_CORE_PASS_THROUGH: (keyof ToCoreFromWebviewProtocol)[] = "index/indexingProgressBarInitialized", "completeOnboarding", "addAutocompleteModel", + "config/listProfiles", + "profiles/switch", + "didChangeSelectedProfile", ]; // Message types to pass through from core to webview @@ -51,4 +55,6 @@ export const CORE_TO_WEBVIEW_PASS_THROUGH: (keyof ToWebviewFromCoreProtocol)[] = "indexProgress", "addContextItem", "refreshSubmenuItems", + "isContinueInputFocused", + "didChangeAvailableProfiles", ]; diff --git a/core/protocol/webview.ts b/core/protocol/webview.ts index c0326bfa0..3cdf68c73 100644 --- a/core/protocol/webview.ts +++ b/core/protocol/webview.ts @@ -5,6 +5,7 @@ export type ToWebviewFromIdeOrCoreProtocol = { getDefaultModelTitle: [undefined, string]; indexProgress: [IndexingProgressUpdate, void]; refreshSubmenuItems: [undefined, void]; + isContinueInputFocused: [undefined, boolean]; addContextItem: [ { historyIndex: number; diff --git a/core/test/diff.test.ts b/core/test/diff.test.ts deleted file mode 100644 index 8bbd2cd25..000000000 --- a/core/test/diff.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { streamDiff } from "../diff/streamDiff.js"; - -const oldCode = [ - `A -B`, - `A -B -C`, - `A -B -C -A -B -B -A`, - `function mergeSortAlgorithm() { - // TODO: implement -}`, - `function mergeSortAlgorithm() { - // TODO: implement -}`, -]; - -const newCode = [ - `C -D`, - `D -E -C -F -C`, - `C -B -A -B -A -C`, - `function mergeSortAlgorithm(arr: number[]): number[] { - if (arr.length <= 1) { - return arr; - } - - const middle = Math.floor(arr.length / 2); - const left = arr.slice(0, middle); - const right = arr.slice(middle); - - return merge(mergeSortAlgorithm(left), mergeSortAlgorithm(right)); -} - -function merge(left: number[], right: number[]): number[] { - let resultArray = [], leftIndex = 0, rightIndex = 0; - - while (leftIndex < left.length && rightIndex < right.length) { - if (left[leftIndex] < right[rightIndex]) { - resultArray.push(left[leftIndex]); - leftIndex++; - } else { - resultArray.push(right[rightIndex]); - rightIndex++; - } - } - - return resultArray - .concat(left.slice(leftIndex)) - .concat(right.slice(rightIndex)); -}`, - `function mergeSortAlgorithm(array) { - if (array.length <= 1) { - return array; - } - - const mid = Math.floor(array.length / 2); - const left = array.slice(0, mid); - const right = array.slice(mid); - - return merge(mergeSortAlgorithm(left), mergeSortAlgorithm(right)); -} - -function merge(left, right) { - let resultArray = [], leftIndex = 0, rightIndex = 0; - - while (leftIndex < left.length && rightIndex < right.length) { - if (left[leftIndex] < right[rightIndex]) { - resultArray.push(left[leftIndex]); - leftIndex++; - } else { - resultArray.push(right[rightIndex]); - rightIndex++; - } - } - - return resultArray - .concat(left.slice(leftIndex)) - .concat(right.slice(rightIndex)); -} -`, -]; - -async function* generateLines(lines: string[]): AsyncGenerator { - for (const line of lines) { - yield line; - } -} - -describe.skip("streamDiff", () => { - for (let i = 0; i < oldCode.length; i++) { - test(`outputs valid diff #${i}`, async () => { - const oldLines = oldCode[i].split("\n"); - const newLines = newCode[i].split("\n"); - - const diff = []; - for await (const diffLine of streamDiff( - oldLines, - generateLines(newLines), - )) { - diff.push(diffLine); - } - - console.log( - diff - .map((dl) => { - return ( - (dl.type === "old" ? "- " : dl.type === "new" ? "+ " : " ") + - dl.line - ); - }) - .join("\n"), - ); - - const numSame = diff.filter((dl) => dl.type === "same").length; - const numOld = diff.filter((dl) => dl.type === "old").length; - const numNew = diff.filter((dl) => dl.type === "new").length; - - // Check that every line is represented - expect(oldLines.length).toEqual(numOld + numSame); - expect(newLines.length).toEqual(numNew + numSame); - - // Check that there are no red lines immediately following green (they should always be above) - for (let i = 1; i < diff.length; i++) { - if (diff[i].type === "old" && diff[i - 1].type === "new") { - throw new Error( - `Found red '${diff[i].line}' immediately after green line '${ - diff[i - 1].line - }`, - ); - } - } - }); - } -}); diff --git a/core/test/indexing/CodebaseIndexer.skip.ts b/core/test/indexing/CodebaseIndexer.skip.ts index db4c5107e..404ef96fd 100644 --- a/core/test/indexing/CodebaseIndexer.skip.ts +++ b/core/test/indexing/CodebaseIndexer.skip.ts @@ -56,6 +56,7 @@ describe.skip("CodebaseIndexer", () => { ide, ideSettingsPromise, async (text) => {}, + undefined as any, // TODO ); const pauseToken = new PauseToken(false); const continueServerClient = new ContinueServerClient(undefined, undefined); diff --git a/core/test/indexing/chunk/code.test.ts b/core/test/indexing/chunk/code.test.ts index 41f8c7add..a708b230b 100644 --- a/core/test/indexing/chunk/code.test.ts +++ b/core/test/indexing/chunk/code.test.ts @@ -15,7 +15,7 @@ async function genToStrs( return (await genToArr(generator)).map((chunk) => chunk.content); } -describe("codeChunker", () => { +describe.skip("codeChunker", () => { test("should return empty array if file empty", async () => { const chunks = await genToStrs(codeChunker("test.ts", "", 100)); expect(chunks).toEqual([]); diff --git a/core/test/streamDiff.test.ts b/core/test/streamDiff.test.ts new file mode 100644 index 000000000..72be00746 --- /dev/null +++ b/core/test/streamDiff.test.ts @@ -0,0 +1,180 @@ +import { streamDiff } from "../diff/streamDiff.js"; +import { DiffLine, DiffLineType } from "../index.js"; +// @ts-ignore no typings available +import { changed, diff as myersDiff } from "myers-diff"; + +// "modification" is an extra type used to represent an "old" + "new" diff line +type MyersDiffTypes = Extract | "modification"; + +async function* generateLines(lines: string[]): AsyncGenerator { + for (const line of lines) { + yield line; + } +} + +async function collectDiffs( + oldLines: string[], + newLines: string[], +): Promise<{ streamDiffs: DiffLine[]; myersDiffs: any }> { + const streamDiffs: DiffLine[] = []; + + for await (const diffLine of streamDiff(oldLines, generateLines(newLines))) { + streamDiffs.push(diffLine); + } + + const myersDiffs = myersDiff(oldLines.join("\n"), newLines.join("\n")); + + return { streamDiffs, myersDiffs }; +} + +function getMyersDiffType(diff: any): MyersDiffTypes | undefined { + if (changed(diff.rhs) && !changed(diff.lhs)) { + return "new"; + } + + if (!changed(diff.rhs) && changed(diff.lhs)) { + return "old"; + } + + if (changed(diff.rhs) && changed(diff.lhs)) { + return "modification"; + } + + return undefined; +} + +// We use a longer `)` string here to not get +// caught by the fuzzy matcher +describe("streamDiff(", () => { + test("no changes", async () => { + const oldLines = ["first item", "second arg", "third param"]; + const newLines = ["first item", "second arg", "third param"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "same", line: "first item" }, + { type: "same", line: "second arg" }, + { type: "same", line: "third param" }, + ]); + + expect(myersDiffs).toEqual([]); + }); + + test("add new line", async () => { + const oldLines = ["first item", "second arg"]; + const newLines = ["first item", "second arg", "third param"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "same", line: "first item" }, + { type: "same", line: "second arg" }, + { type: "new", line: "third param" }, + ]); + + expect(myersDiffs.length).toEqual(1); + expect(getMyersDiffType(myersDiffs[0])).toBe("new"); + }); + + test("remove line", async () => { + const oldLines = ["first item", "second arg", "third param"]; + const newLines = ["first item", "third param"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "same", line: "first item" }, + { type: "old", line: "second arg" }, + { type: "same", line: "third param" }, + ]); + + expect(myersDiffs.length).toEqual(1); + expect(getMyersDiffType(myersDiffs[0])).toBe("old"); + }); + + test("modify line", async () => { + const oldLines = ["first item", "second arg", "third param"]; + const newLines = ["first item", "modified second arg", "third param"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "same", line: "first item" }, + { type: "old", line: "second arg" }, + { type: "new", line: "modified second arg" }, + { type: "same", line: "third param" }, + ]); + + expect(myersDiffs.length).toEqual(1); + expect(getMyersDiffType(myersDiffs[0])).toBe("modification"); + }); + + test("add multiple lines", async () => { + const oldLines = ["first item", "fourth val"]; + const newLines = ["first item", "second arg", "third param", "fourth val"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "same", line: "first item" }, + { type: "new", line: "second arg" }, + { type: "new", line: "third param" }, + { type: "same", line: "fourth val" }, + ]); + + // Multi-line addition + expect(myersDiffs[0].rhs.add).toEqual(2); + expect(getMyersDiffType(myersDiffs[0])).toBe("new"); + }); + + test("remove multiple lines", async () => { + const oldLines = ["first item", "second arg", "third param", "fourth val"]; + const newLines = ["first item", "fourth val"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "same", line: "first item" }, + { type: "old", line: "second arg" }, + { type: "old", line: "third param" }, + { type: "same", line: "fourth val" }, + ]); + + // Multi-line deletion + expect(myersDiffs[0].lhs.del).toEqual(2); + expect(getMyersDiffType(myersDiffs[0])).toBe("old"); + }); + + test("empty old lines", async () => { + const oldLines: string[] = []; + const newLines = ["first item", "second arg"]; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "new", line: "first item" }, + { type: "new", line: "second arg" }, + ]); + + // Multi-line addition + expect(myersDiffs[0].rhs.add).toEqual(2); + expect(getMyersDiffType(myersDiffs[0])).toBe("new"); + }); + + test("empty new lines", async () => { + const oldLines = ["first item", "second arg"]; + const newLines: string[] = []; + + const { streamDiffs, myersDiffs } = await collectDiffs(oldLines, newLines); + + expect(streamDiffs).toEqual([ + { type: "old", line: "first item" }, + { type: "old", line: "second arg" }, + ]); + + // Multi-line deletion + expect(myersDiffs[0].lhs.del).toEqual(2); + expect(getMyersDiffType(myersDiffs[0])).toBe("old"); + }); +}); diff --git a/core/test/walkDir.test.ts b/core/test/walkDir.test.ts index 5ed3851f0..87f643f4e 100644 --- a/core/test/walkDir.test.ts +++ b/core/test/walkDir.test.ts @@ -1,12 +1,13 @@ import path from "path"; -import { walkDir, WalkerOptions } from "../indexing/walkDir"; -import FileSystemIde from "../util/filesystem"; +import { walkDir, WalkerOptions } from "../indexing/walkDir.js"; +import FileSystemIde from "../util/filesystem.js"; import { addToTestDir, setUpTestDir, tearDownTestDir, TEST_DIR, -} from "./testUtils/testDir"; +} from "./testUtils/testDir.js"; + const ide = new FileSystemIde(TEST_DIR); async function walkTestDir( @@ -23,6 +24,13 @@ async function expectPaths( toNotExist: string[], options?: WalkerOptions, ) { + // Convert to Windows paths + const pathSep = await ide.pathSep(); + if (pathSep === "\\") { + toExist = toExist.map((p) => p.replace(/\//g, "\\")); + toNotExist = toNotExist.map((p) => p.replace(/\//g, "\\")); + } + const result = await walkTestDir(options); for (const p of toExist) { @@ -103,12 +111,41 @@ describe("walkDir", () => { ); }); + test("should use gitignore in parent directory for subdirectory", async () => { + const files = [ + "a.txt", + "b.py", + "d/", + "d/e.txt", + "d/f.py", + "d/g/", + "d/g/h.ts", + "d/g/i.py", + [".gitignore", "*.py"], + ]; + addToTestDir(files); + await expectPaths(["a.txt", "d/e.txt", "d/g/h.ts"], ["d/f.py", "d/g/i.py"]); + }); + test("should handle leading slash in gitignore", async () => { const files = [[".gitignore", "/no.txt"], "a.txt", "b.py", "no.txt"]; addToTestDir(files); await expectPaths(["a.txt", "b.py"], ["no.txt"]); }); + test("should not ignore leading slash when in subfolder", async () => { + const files = [ + [".gitignore", "/no.txt"], + "a.txt", + "b.py", + "no.txt", + "sub/", + "sub/no.txt", + ]; + addToTestDir(files); + await expectPaths(["a.txt", "b.py", "sub/no.txt"], ["no.txt"]); + }); + test("should handle multiple .gitignore files in nested structure", async () => { const files = [ [".gitignore", "*.txt"], @@ -201,7 +238,7 @@ describe("walkDir", () => { await expectPaths( ["d", "d/g"], ["a.txt", "b.py", "c.ts", "d/e.txt", "d/f.py", "d/g/h.ts"], - { onlyDirs: true, includeEmpty: true }, + { onlyDirs: true }, ); }); @@ -262,8 +299,10 @@ describe("walkDir", () => { expect(results.length).toBeLessThan(1500); }); - test("should walk continue/extensions/vscode without getting any files in the .continueignore", async () => { - const vscodePath = path.join(__dirname, "..", "extensions", "vscode"); + // This test is passing when this file is ran individually, but failing with `directory not found` error + // when the full test suite is ran + test.skip("should walk continue/extensions/vscode without getting any files in the .continueignore", async () => { + const vscodePath = path.join(__dirname, "../..", "extensions", "vscode"); const results = await walkDir(vscodePath, ide, { ignoreFiles: [".gitignore", ".continueignore"], }); @@ -273,4 +312,32 @@ describe("walkDir", () => { ); expect(results.some((file) => file.includes(".tmLanguage"))).toBe(false); }); + + // This test is passing when this file is ran individually, but failing with `jest not found` error + // when the full test suite is ran + test.skip("should perform the same number of dir reads as 1 + the number of dirs that contain files", async () => { + const files = [ + "a.txt", + "b.py", + "c.ts", + "d/", + "d/e.txt", + "d/f.py", + "d/g/", + "d/g/h.ts", + "d/g/i/", + "d/g/i/j.ts", + ]; + + const numDirs = files.filter((file) => !file.includes(".")).length; + const numDirsPlusTopLevelRead = numDirs + 1; + + addToTestDir(files); + + const mockListDir = jest.spyOn(ide, "listDir"); + + await walkTestDir(); + + expect(mockListDir).toHaveBeenCalledTimes(numDirsPlusTopLevelRead); + }); }); diff --git a/core/util/GlobalContext.ts b/core/util/GlobalContext.ts index 5f293204a..3880b4609 100644 --- a/core/util/GlobalContext.ts +++ b/core/util/GlobalContext.ts @@ -1,9 +1,18 @@ import fs from "node:fs"; import { getGlobalContextFilePath } from "./paths.js"; +import { EmbeddingsProvider } from "../index.js"; export type GlobalContextType = { indexingPaused: boolean; selectedTabAutocompleteModel: string; + lastSelectedProfileForWorkspace: { [workspaceIdentifier: string]: string }; + /** + * This is needed to handle the case where a JetBrains user has created + * docs embeddings using one provider, and then updates to a new provider. + * + * For VS Code users, it is unnecessary since we use transformers.js by default. + */ + curEmbeddingsProviderId: EmbeddingsProvider["id"]; }; /** diff --git a/core/util/filesystem.ts b/core/util/filesystem.ts index b9d35cdb9..978fa0829 100644 --- a/core/util/filesystem.ts +++ b/core/util/filesystem.ts @@ -37,6 +37,9 @@ class FileSystemIde implements IDE { remoteConfigServerUrl: undefined, remoteConfigSyncPeriod: 60, userToken: "", + enableControlServerBeta: false, + pauseCodebaseIndexOnStart: false, + enableDebugLogs: false, }; } async getGitHubAuthToken(): Promise { @@ -60,8 +63,8 @@ class FileSystemIde implements IDE { dirent.isDirectory() ? (2 as FileType.Directory) : dirent.isSymbolicLink() - ? (64 as FileType.SymbolicLink) - : (1 as FileType.File), + ? (64 as FileType.SymbolicLink) + : (1 as FileType.File), ]); return Promise.resolve(all); } diff --git a/core/util/parameters.ts b/core/util/parameters.ts index 13b38626d..b413a869e 100644 --- a/core/util/parameters.ts +++ b/core/util/parameters.ts @@ -3,7 +3,7 @@ import { TabAutocompleteOptions } from "../index.js"; export const DEFAULT_AUTOCOMPLETE_OPTS: TabAutocompleteOptions = { disable: false, useCopyBuffer: false, - useSuffix: true, + useFileSuffix: true, maxPromptTokens: 1024, prefixPercentage: 0.85, maxSuffixPercentage: 0.25, diff --git a/core/util/paths.ts b/core/util/paths.ts index f7c7fc1d3..cec9b0a95 100644 --- a/core/util/paths.ts +++ b/core/util/paths.ts @@ -139,6 +139,24 @@ export function getTsConfigPath(): string { return tsConfigPath; } +export function getContinueRcPath(): string { + // Disable indexing of the config folder to prevent infinite loops + const continuercPath = path.join(getContinueGlobalPath(), ".continuerc.json"); + if (!fs.existsSync(continuercPath)) { + fs.writeFileSync( + continuercPath, + JSON.stringify( + { + disableIndexing: true, + }, + null, + 2, + ), + ); + } + return continuercPath; +} + export function devDataPath(): string { const sPath = path.join(getContinueGlobalPath(), "dev_data"); if (!fs.existsSync(sPath)) { @@ -177,19 +195,20 @@ function getMigrationsFolderPath(): string { return migrationsPath; } -export function migrate( +export async function migrate( id: string, - callback: () => void, + callback: () => void | Promise, onAlreadyComplete?: () => void, ) { const migrationsPath = getMigrationsFolderPath(); const migrationPath = path.join(migrationsPath, id); + if (!fs.existsSync(migrationPath)) { try { - callback(); + await Promise.resolve(callback()); fs.writeFileSync(migrationPath, ""); } catch (e) { - console.error(`Migration ${id} failed`, e); + console.warn(`Migration ${id} failed`, e); } } else if (onAlreadyComplete) { onAlreadyComplete(); @@ -235,6 +254,11 @@ export function getPathToRemoteConfig(remoteConfigServerUrl: string): string { return dir; } +export function internalBetaPathExists(): boolean { + const sPath = path.join(getContinueGlobalPath(), ".internal_beta"); + return fs.existsSync(sPath); +} + export function getConfigJsonPathForRemote( remoteConfigServerUrl: string, ): string { diff --git a/core/util/posthog.ts b/core/util/posthog.ts index 182758edc..c164a0349 100644 --- a/core/util/posthog.ts +++ b/core/util/posthog.ts @@ -1,4 +1,5 @@ import os from "node:os"; +import { TeamAnalytics } from "../control-plane/TeamAnalytics"; export class Telemetry { // Set to undefined whenever telemetry is disabled @@ -7,7 +8,11 @@ export class Telemetry { static os: string | undefined = undefined; static extensionVersion: string | undefined = undefined; - static async capture(event: string, properties: { [key: string]: any }) { + static async capture( + event: string, + properties: { [key: string]: any }, + sendToTeam: boolean = false, + ) { Telemetry.client?.capture({ distinctId: Telemetry.uniqueId, event, @@ -17,6 +22,10 @@ export class Telemetry { extensionVersion: Telemetry.extensionVersion, }, }); + + if (sendToTeam) { + TeamAnalytics.capture(event, properties); + } } static shutdownPosthogClient() { diff --git a/core/util/verticalEdit.ts b/core/util/verticalEdit.ts index e018d1be4..0a32a6a5b 100644 --- a/core/util/verticalEdit.ts +++ b/core/util/verticalEdit.ts @@ -60,10 +60,14 @@ export async function* streamDiffLines( language: string | undefined, onlyOneInsertion?: boolean, ): AsyncGenerator { - Telemetry.capture("inlineEdit", { - model: llm.model, - provider: llm.providerName, - }); + Telemetry.capture( + "inlineEdit", + { + model: llm.model, + provider: llm.providerName, + }, + true, + ); // Strip common indentation for the LLM, then add back after generation let oldLines = diff --git a/docs/docs/customization/context-providers.md b/docs/docs/customization/context-providers.md index 25c8709dc..77d03b683 100644 --- a/docs/docs/customization/context-providers.md +++ b/docs/docs/customization/context-providers.md @@ -16,6 +16,14 @@ As an example, say you are working on solving a new GitHub Issue. You type '@iss To use any of the built-in context providers, open `~/.continue/config.json` and add it to the `contextProviders` list. +### Files + +Type '@file' to reference any file in your current workspace. + +```json +{ "name": "file" } +``` + ### Code Type '@code' to reference specific functions or classes from throughout your project. @@ -50,6 +58,28 @@ Type `@docs` to index and retrieve snippets from any documentation site. You can Continue also pre-indexes a number of common sites, listed [here](https://github.com/continuedev/continue/blob/main/core/indexing/docs/preIndexedDocs.ts). The embeddings for these sites are hosted by us, but downloaded for local use after the first time. All other indexing occurs entirely locally. +#### Adding a Documentation Site via Configuration + +To add a documentation site via configuration, update the `config.json` file as follows: + +```json +{ + "name": "docs", + "params": { + "sites": [ + { + "title": "ExampleDocs", + "startUrl": "https://exampledocs.com/docs", + "rootUrl": "https://exampledocs.com", + "maxDepth": 3 // Default + } + ] + } +} +``` + +The docs are indexed when you modify the configuration file, unless indexing is disabled. If you want to manually trigger the indexing, you can use the command `Continue: Docs Index`. For force indexing, you can use the command `Continue: Docs Force Re-Index`. Note that these commands will work even if automatic indexing is disabled. + ### Open Files Type '@open' to reference the contents of all of your open files. Set `onlyPinned` to `true` to only reference pinned files. diff --git a/docs/docs/customization/overview.md b/docs/docs/customization/overview.md index d36dbfffe..c5791aede 100644 --- a/docs/docs/customization/overview.md +++ b/docs/docs/customization/overview.md @@ -10,7 +10,7 @@ Continue can be deeply customized by editing `config.json` and `config.ts` on yo Currently, you can customize the following: -- [Models](../setup/select-model.md) and [providers](../setup/select-provider.md) +- [Models](../setup/select-model.md) and [Model Providers](../setup/model-providers.md) - [Context Providers](./context-providers.md) - [Slash Commands](./slash-commands.md) - [Other configuration options](../reference/config.mdx) diff --git a/docs/docs/features/codebase-embeddings.md b/docs/docs/features/codebase-embeddings.md index 8b2764c1c..21945734b 100644 --- a/docs/docs/features/codebase-embeddings.md +++ b/docs/docs/features/codebase-embeddings.md @@ -231,7 +231,7 @@ export function modifyConfig(config: Config): Config { The reranker plays a crucial role in refining the results retrieved from your codebase. It processes the initial set of results obtained through embeddings-based retrieval, improving their relevance and accuracy for your queries. -Continue offers several reranking options: `cohere`, `voyage`, `llm`, and `free-trial`, which can be configured in `config.json`. +Continue offers several reranking options: `cohere`, `voyage`, `llm`, `hugginface-tei`, and `free-trial`, which can be configured in `config.json`. ### Voyage AI @@ -282,6 +282,23 @@ If you only have access to a single LLM, then you can use it as a reranker. This The `"modelTitle"` field must match one of the models in your "models" array in config.json. +### Text Embeddings Inference + +[Hugging Face Text Embeddings Inference](https://huggingface.co/docs/text-embeddings-inference/en/index) enables you to host your own [reranker endpoint](https://huggingface.github.io/text-embeddings-inference/#/Text%20Embeddings%20Inference/rerank). You can configure your reranker as follows: + +```json title="~/.continue/config.json" +{ + "reranker": { + "name": "huggingface-tei", + "params": { + "apiBase": "http://localhost:8080", + "truncate": true, + "truncation_direction": "Right" + } + }, +} +``` + ### Free Trial (Voyage AI) Continue offers a free trial of Voyage AI's reranking model. diff --git a/docs/docs/features/quick-actions.md b/docs/docs/features/quick-actions.md index c08cfc746..7c6ce8887 100644 --- a/docs/docs/features/quick-actions.md +++ b/docs/docs/features/quick-actions.md @@ -1,13 +1,13 @@ --- title: Quick Actions (experimental, VS Code only) -description: Quick Actions automate repetitive tasks and streamline your development workflow +description: Quick Actions streamline your development workflow by allowing quick edits on selected classes or functions keywords: [experimental, automate, configuration] toc_max_heading_level: 5 --- -# Quick Actions (experimental, VS Code only) +## Quick Actions (experimental, VS Code only) -Quick Actions automate repetitive tasks and streamline your development workflow. Configure custom actions to execute complex operations with a single click. +Quick Actions streamline your development workflow by providing a tool to quickly select an entire class or function to perform a quick edit on. Configure custom actions to execute complex operations with a single click. ![Quick actions example](/img/quick-actions-demo.gif) @@ -19,10 +19,9 @@ For the language of the file you have open, you must have the Language Server Pr Quick Actions use a CodeLens provider to add interactive elements above functions and classes in your code. -By default, Quick Actions include two predefined actions: +By default, Quick Actions include a single predefined action: -1. `Explain`: This action provides a short explanation of the selected code. -2. `Docstring`: This action generates a docstring comment and inserts it above the code. +- `Continue`: This action allows you to perform a quick edit on the selected class or function. ## How to disable Quick Actions diff --git a/docs/docs/features/tab-autocomplete.md b/docs/docs/features/tab-autocomplete.md index 90976b16e..1aef6cb6b 100644 --- a/docs/docs/features/tab-autocomplete.md +++ b/docs/docs/features/tab-autocomplete.md @@ -94,7 +94,7 @@ This object allows you to customize the behavior of tab-autocomplete. The availa - `disable`: Disable autocomplete (can also be done from IDE settings) - `template`: An optional template string to be used for autocomplete. It will be rendered with the Mustache templating language, and is passed the 'prefix' and 'suffix' variables. (String) - `useCopyBuffer`: Determines whether the copy buffer will be considered when constructing the prompt. (Boolean) -- `useSuffix`: Determines whether to use the file suffix in the prompt. (Boolean) +- `useFileSuffix`: Determines whether to use the file suffix in the prompt. (Boolean) - `maxPromptTokens`: The maximum number of prompt tokens to use. A smaller number will yield faster completions, but less context. (Number) - `prefixPercentage`: The percentage of the input that should be dedicated to the prefix. (Number) - `maxSuffixPercentage`: The maximum percentage of the prompt that can be dedicated to the suffix. (Number) diff --git a/docs/docs/reference/Model Providers/deepseek.md b/docs/docs/reference/Model Providers/deepseek.md new file mode 100644 index 000000000..af16f3749 --- /dev/null +++ b/docs/docs/reference/Model Providers/deepseek.md @@ -0,0 +1,16 @@ +# DeepSeek + +To setup DeepSeek, obtain an API key from [here](https://www.deepseek.com/) and add the following to your `config.json` file: + +```json title="~/.continue/config.json" +{ + "models": [ + { + "title": "Deepseek", + "provider": "deepseek", + "model": "deepseek-code", // Or any other DeepSeek model + "apiKey": "YOUR_API_KEY" + } + ] +} +``` diff --git a/docs/docs/reference/Model Providers/freetrial.md b/docs/docs/reference/Model Providers/freetrial.md index da4f583cb..ea402cc58 100644 --- a/docs/docs/reference/Model Providers/freetrial.md +++ b/docs/docs/reference/Model Providers/freetrial.md @@ -69,7 +69,7 @@ Groq provides lightning fast inference for open-source LLMs like Llama3, up to t ### ⏩ Other options -The above were only a few examples, but Continue can be used with any LLM or provider. You can find [a full list of providers here](../../setup/select-provider.md). +The above were only a few examples, but Continue can be used with any LLM or provider. You can find [a full list of model providers here](../../setup/model-providers.md). ## Sign in diff --git a/docs/docs/reference/Model Providers/mistral.md b/docs/docs/reference/Model Providers/mistral.md index 3c3633438..448b8292a 100644 --- a/docs/docs/reference/Model Providers/mistral.md +++ b/docs/docs/reference/Model Providers/mistral.md @@ -7,8 +7,8 @@ The [Mistral](https://mistral.ai) API provides hosted access to their models, in "models": [ { "provider": "mistral", - "title": "Mistral Small", - "model": "mistral-small", + "title": "Codestral", + "model": "codestral-latest", "apiKey": "" } ] diff --git a/docs/docs/setup/configuration.md b/docs/docs/setup/configuration.md index 11cb29318..26965d87a 100644 --- a/docs/docs/setup/configuration.md +++ b/docs/docs/setup/configuration.md @@ -267,7 +267,7 @@ function modifyConfig(config: Config): Config { } ``` -This exact function and a few other default implementations are available in [`continuedev.libs.llm.prompts.chat`](https://github.com/continuedev/continue/blob/main/server/continuedev/libs/llm/prompts/chat.py). +This exact function and a few other default implementations are available in [`core/llm/templates/chat.ts`](https://github.com/continuedev/continue/blob/main/core/llm/templates/chat.ts). ## Customizing the /edit Prompt @@ -295,7 +295,7 @@ You can find all existing templates for /edit in [`core/llm/templates/edit.ts`]( ## Defining a Custom LLM Provider -If you are using an LLM API that isn't already [supported by Continue](./select-provider.md), and is not an OpenAI-compatible API, you'll need to define a `CustomLLM` object in `config.ts`. This object only requires one of (or both of) a `streamComplete` or `streamChat` function. Here is an example: +If you are using an LLM API that isn't already [supported by Continue](./model-providers.md), and is not an OpenAI-compatible API, you'll need to define a `CustomLLM` object in `config.ts`. This object only requires one of (or both of) a `streamComplete` or `streamChat` function. Here is an example: ```typescript title="~/.continue/config.ts" export function modifyConfig(config: Config): Config { diff --git a/docs/docs/setup/select-provider.md b/docs/docs/setup/model-providers.md similarity index 82% rename from docs/docs/setup/select-provider.md rename to docs/docs/setup/model-providers.md index d55c95c29..c43f1bf28 100644 --- a/docs/docs/setup/select-provider.md +++ b/docs/docs/setup/model-providers.md @@ -1,12 +1,29 @@ --- -title: Select providers -description: Configure LLM providers -keywords: [openai, anthropic, gemini, ollama, ggml] +title: Model Providers +description: Configure and integrate various LLM (Large Language Model) providers for chat, autocomplete, and embedding models, whether self-hosted, remote, or via SaaS. +keywords: + [ + large language models, + LLM providers, + open-source LLM, + commercial LLM, + self-hosted LLM, + remote LLM, + SaaS LLM, + AI model configuration, + AI providers, + OpenAI, + Anthropic, + Gemini, + Ollama, + HuggingFace, + AWS Bedrock, + ] --- -# Select providers +# Model Providers -Continue makes it easy to use different providers for serving your chat, autocomplete, and embeddings models. +Configure and integrate various LLM (Large Language Model) providers for chat, autocomplete, and embedding models, whether self-hosted, remote, or via SaaS. To select the ones you want to use, add them to your `config.json`. diff --git a/docs/docs/setup/overview.md b/docs/docs/setup/overview.md index 922389dc6..d8c1bc8dc 100644 --- a/docs/docs/setup/overview.md +++ b/docs/docs/setup/overview.md @@ -9,5 +9,5 @@ You will need to decide which models and providers you use for [chat](select-mod Learn more: - [Configuration](configuration.md) -- [Select providers](select-provider.md) +- [Model Providers](model-providers.md) - [Select models](select-model.md) diff --git a/docs/docs/setup/select-model.md b/docs/docs/setup/select-model.md index dc736ce68..7189d79da 100644 --- a/docs/docs/setup/select-model.md +++ b/docs/docs/setup/select-model.md @@ -87,4 +87,4 @@ We recommend the following embeddings models, which are used for codebase retrie _You can also use other embeddings models by adding them to your `config.json`._ -**In addition to selecting models, you will need to figure out [what providers to use](./select-provider.md).** +**In addition to selecting models, you will need to figure out [what model providers to use](./model-providers.md).** diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 0bd1d106f..f330345a7 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -67,11 +67,11 @@ If your keyboard shortcuts are not resolving, you may have other commands that a - [VSCode keyboard shortcuts docs](https://code.visualstudio.com/docs/getstarted/keybindings) - [IntelliJ keyboard shortcut docs](https://www.jetbrains.com/help/idea/configuring-keyboard-and-mouse-shortcuts.html) -# FAQs +## FAQs -## Networking Issues +### Networking Issues -### Configure Certificates +#### Configure Certificates If you're seeing a `fetch failed` error and your network requires custom certificates, you will need to configure them in `config.json`. In each of the objects in the `"models"` array, add `requestOptions.caBundlePath` like this: @@ -92,22 +92,22 @@ If you're seeing a `fetch failed` error and your network requires custom certifi You may also set `requestOptions.caBundlePath` to an array of paths to multiple certificates. -### VS Code Proxy Settings +#### VS Code Proxy Settings If you are using VS Code and require requests to be made through a proxy, you are likely already set up through VS Code's [Proxy Server Support](https://code.visualstudio.com/docs/setup/network#_proxy-server-support). To double-check that this is enabled, use cmd/ctrl+, to open settings and search for "Proxy Support". Unless it is set to "off", then VS Code is responsible for making the request to the proxy. -### code-server +#### code-server Continue can be used in [code-server](https://coder.com/), but if you are running across an error in the logs that includes "This is likely because the editor is not running in a secure context", please see [their documentation on securely exposing code-server](https://coder.com/docs/code-server/latest/guide#expose-code-server). -## I installed Continue, but don't see the sidebar window +### I installed Continue, but don't see the sidebar window By default the Continue window is on the left side of VS Code, but it can be dragged to right side as well, which we recommend in our tutorial. In the situation where you have previously installed Continue and moved it to the right side, it may still be there. You can reveal Continue either by using cmd/ctrl+L or by clicking the button in the top right of VS Code to open the right sidebar. -## I'm getting a 404 error from OpenAI +### I'm getting a 404 error from OpenAI If you have entered a valid API key and model, but are still getting a 404 error from OpenAI, this may be because you need to add credits to your billing account. You can do so from the [billing console](https://platform.openai.com/settings/organization/billing/overview). If you just want to check that this is in fact the cause of the error, you can try adding $1 to your account and checking whether the error persists. -# Still having trouble? +## Still having trouble? Create a GitHub issue [here](https://github.com/continuedev/continue/issues/new?assignees=&labels=bug&projects=&template=bug-report-%F0%9F%90%9B.md&title=), leaving the details of your problem, and we'll be able to more quickly help you out. diff --git a/docs/docs/walkthroughs/set-up-codestral.md b/docs/docs/walkthroughs/set-up-codestral.md index 706f89223..5ffee8fa5 100644 --- a/docs/docs/walkthroughs/set-up-codestral.md +++ b/docs/docs/walkthroughs/set-up-codestral.md @@ -39,7 +39,7 @@ keywords: [codestral, mistral, model setup] 5. If you run into any issues or have any questions, please join our Discord and post in the `#help` channel [here](https://discord.gg/EfJEfdFnDQ) -## Trobleshooting +## Troubleshooting ### Temporary workaround for JetBrains @@ -68,4 +68,4 @@ Mistral AI recently changed the API endpoint to `codestral.mistral.ai` instead o ### Ask for help on Discord -Please join our Discord and post in the `#help` channel [here](https://discord.gg/EfJEfdFnDQ) if you are having problems using Codestral \ No newline at end of file +Please join our Discord and post in the `#help` channel [here](https://discord.gg/EfJEfdFnDQ) if you are having problems using Codestral diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 109e42a99..e6ec86dcd 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -185,6 +185,10 @@ const config = { from: "/model-setup/configuration", to: "/setup/configuration", }, + { + from: "/setup/select-provider", + to: "/setup/model-providers", + }, { from: "/walkthroughs/codebase-embeddings", to: "/features/codebase-embeddings", diff --git a/docs/sidebars.js b/docs/sidebars.js index 2ea91b463..f38b4aec6 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -25,7 +25,7 @@ const sidebars = { items: [ "setup/overview", "setup/configuration", - "setup/select-provider", + "setup/model-providers", "setup/select-model", ], }, diff --git a/docs/static/schemas/config.json b/docs/static/schemas/config.json index 8ce0b4f39..17995fd61 100644 --- a/docs/static/schemas/config.json +++ b/docs/static/schemas/config.json @@ -481,6 +481,7 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4o", + "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo-0613", "gpt-4-32k", @@ -512,6 +513,9 @@ "anyOf": [ { "enum": [ + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "llama3-8b", "llama3-70b", "codellama-7b", @@ -545,7 +549,8 @@ "enum": [ "gpt-4o", "codestral-latest", - "llama3-70b", + "llama3.1-70b", + "llama3.1-405b", "gpt-3.5-turbo", "phind-codellama-34b", "gemini-pro", @@ -581,6 +586,7 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4o", + "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo-0613", "gpt-4-32k", @@ -596,6 +602,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phind-codellama-34b", "wizardcoder-7b", "wizardcoder-13b", @@ -746,6 +755,9 @@ "llama2-13b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "codellama-7b", "codellama-13b", "codellama-34b", @@ -810,6 +822,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phind-codellama-34b", "wizardcoder-7b", "wizardcoder-13b", @@ -858,6 +873,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phi-2", "phind-codellama-34b", "wizardcoder-7b", @@ -899,6 +917,7 @@ "model": { "enum": [ "codestral-latest", + "codestral-mamba-latest", "open-mistral-7b", "open-mixtral-8x7b", "open-mixtral-8x22b", @@ -944,6 +963,9 @@ "gemma", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "AUTODETECT" ] } @@ -1094,6 +1116,7 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4o", + "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo-0613", "gpt-4-32k", @@ -1109,6 +1132,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phind-codellama-34b", "wizardcoder-7b", "wizardcoder-13b", @@ -1391,6 +1417,46 @@ } }, "allOf": [ + { + "if": { + "properties": { + "name": { + "enum": ["docs"] + } + } + }, + "then": { + "properties": { + "params": { + "properties": { + "sites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "startUrl": { + "type": "string" + }, + "rootUrl": { + "type": "string" + }, + "maxDepth": { + "type": "integer" + } + }, + "required": ["title", "startUrl"] + } + } + }, + "required": ["sites"] + } + }, + "required": ["params"] + } + }, { "if": { "properties": { @@ -1761,6 +1827,33 @@ "title": "config.json", "type": "object", "properties": { + "docs": { + "title": "Docs", + "description": "A list of documentation sites to be indexed", + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the documentation site" + }, + "startUrl": { + "type": "string", + "description": "The starting URL for indexing the documentation" + }, + "rootUrl": { + "type": "string", + "description": "The root URL of the documentation site" + }, + "maxDepth": { + "type": "integer", + "description": "The maximum depth to crawl the documentation site" + } + }, + "required": ["title", "startUrl"] + } + }, "allowAnonymousTelemetry": { "title": "Allow Anonymous Telemetry", "markdownDescription": "If this field is set to True, we will collect anonymous telemetry as described in the documentation page on telemetry. If set to `false`, we will not collect any data. Learn more in [the docs](https://docs.continue.dev/telemetry).", @@ -1906,6 +1999,13 @@ "title": "Request Options", "description": "Request options to be used in any fetch requests made by the embeddings provider", "$ref": "#/definitions/RequestOptions" + }, + "maxChunkSize": { + "title": "Maximum Chunk Size", + "description": "The maximum number of tokens that each chunk of a document is allowed to have", + "type": "integer", + "minimum": 128, + "exclusiveMaximum": 2147483647 } }, "required": ["provider"], @@ -1944,7 +2044,13 @@ "type": "object", "properties": { "name": { - "enum": ["cohere", "voyage", "llm", "free-trial"] + "enum": [ + "cohere", + "voyage", + "llm", + "free-trial", + "huggingface-tei" + ] }, "params": { "type": "object" @@ -2034,6 +2140,50 @@ } } } + }, + { + "if": { + "properties": { + "name": { + "enum": ["huggingface-tei"] + } + }, + "required": ["name"] + }, + "then": { + "properties": { + "params": { + "type": "object", + "properties": { + "apiBase": { + "type": "string", + "default": "http://localhost:8080" + }, + "truncate": { + "type": "boolean", + "description": "Wether to truncate long sequences to the maximum allowed context length.", + "default": false + }, + "truncation_direction": { + "enum": ["Right", "Left"], + "markdownDescription": "Wether to truncate sequences from the `left` or `right`.", + "default": "Right" + } + }, + "required": ["apiBase"] + } + }, + "if": { + "properties": { + "truncate": { + "const": true + } + } + }, + "then": { + "required": ["truncation_direction"] + } + } } ] }, @@ -2071,7 +2221,7 @@ "type": "boolean", "description": "Determines whether the copy buffer will be considered when contructing the prompt." }, - "useSuffix": { + "useFileSuffix": { "type": "boolean", "description": "Determines whether to use the file suffix in the prompt." }, diff --git a/eval/.gitignore b/eval/.gitignore new file mode 100644 index 000000000..2a31c3eee --- /dev/null +++ b/eval/.gitignore @@ -0,0 +1 @@ +repos \ No newline at end of file diff --git a/extensions/intellij/gradle.properties b/extensions/intellij/gradle.properties index f9e9a3446..9356c4252 100644 --- a/extensions/intellij/gradle.properties +++ b/extensions/intellij/gradle.properties @@ -4,7 +4,7 @@ pluginGroup = com.github.continuedev.continueintellijextension pluginName = continue-intellij-extension pluginRepositoryUrl = https://github.com/continuedev/continue # SemVer format -> https://semver.org -pluginVersion = 0.0.53 +pluginVersion = 0.0.57 # Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html pluginSinceBuild = 223 diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt index 4a785a4d8..444a4d397 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/activities/ContinuePluginStartupActivity.kt @@ -1,5 +1,8 @@ package com.github.continuedev.continueintellijextension.activities +import com.github.continuedev.continueintellijextension.auth.AuthListener +import com.github.continuedev.continueintellijextension.auth.ContinueAuthService +import com.github.continuedev.continueintellijextension.auth.ControlPlaneSessionInfo import com.github.continuedev.continueintellijextension.constants.getContinueGlobalPath import com.github.continuedev.continueintellijextension.`continue`.* import com.github.continuedev.continueintellijextension.listeners.ContinuePluginSelectionListener @@ -25,6 +28,7 @@ import java.nio.file.Files import java.nio.file.Paths import javax.swing.* import com.intellij.ide.plugins.PluginManager +import com.intellij.openapi.components.service import com.intellij.openapi.extensions.PluginId fun showTutorial(project: Project) { @@ -126,6 +130,32 @@ class ContinuePluginStartupActivity : StartupActivity, Disposable, DumbAware { } }) + // Listen for clicking settings button to start the auth flow + val authService = service() + val initialSessionInfo = authService.loadControlPlaneSessionInfo() + + if (initialSessionInfo != null) { + val data = mapOf( + "sessionInfo" to initialSessionInfo + ) + continuePluginService.coreMessenger?.request("didChangeControlPlaneSessionInfo", data, null) { _ -> } + continuePluginService.sendToWebview("didChangeControlPlaneSessionInfo", data) + } + + connection.subscribe(AuthListener.TOPIC, object : AuthListener { + override fun startAuthFlow() { + authService.startAuthFlow(project) + } + + override fun handleUpdatedSessionInfo(sessionInfo: ControlPlaneSessionInfo?) { + val data = mapOf( + "sessionInfo" to sessionInfo + ) + continuePluginService.coreMessenger?.request("didChangeControlPlaneSessionInfo", data, null) { _ -> } + continuePluginService.sendToWebview("didChangeControlPlaneSessionInfo", data) + } + }) + GlobalScope.async(Dispatchers.IO) { val listener = ContinuePluginSelectionListener( diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/AuthListener.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/AuthListener.kt new file mode 100644 index 000000000..b6449936c --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/AuthListener.kt @@ -0,0 +1,12 @@ +package com.github.continuedev.continueintellijextension.auth +import com.intellij.util.messages.Topic + +interface AuthListener { + fun startAuthFlow() + + fun handleUpdatedSessionInfo(sessionInfo: ControlPlaneSessionInfo?) + + companion object { + val TOPIC = Topic.create("StartAuthFlow", AuthListener::class.java) + } +} \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthDialog.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthDialog.kt new file mode 100644 index 000000000..7197bf348 --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthDialog.kt @@ -0,0 +1,34 @@ +package com.github.continuedev.continueintellijextension.auth + +import com.intellij.openapi.ui.DialogWrapper +import com.intellij.ui.components.JBLabel +import com.intellij.ui.components.JBTextField +import javax.swing.JComponent +import javax.swing.JPanel +import java.awt.BorderLayout + +class ContinueAuthDialog(private val onTokenEntered: (String) -> Unit) : DialogWrapper(true) { + private val tokenField = JBTextField() + + init { + init() + title = "Enter Continue Authentication Token" + } + + override fun createCenterPanel(): JComponent { + val panel = JPanel(BorderLayout()) + panel.add(JBLabel("Please enter your Continue authentication token:"), BorderLayout.NORTH) + panel.add(tokenField, BorderLayout.CENTER) + return panel + } + + override fun doOKAction() { + val token = tokenField.text + if (token.isNotBlank()) { + onTokenEntered(token) + super.doOKAction() + } else { + setErrorText("Please enter a valid token") + } + } +} diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthService.kt new file mode 100644 index 000000000..01d517f36 --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/auth/ContinueAuthService.kt @@ -0,0 +1,223 @@ +package com.github.continuedev.continueintellijextension.auth + +import com.github.continuedev.continueintellijextension.services.ContinuePluginService +import com.google.gson.Gson +import com.intellij.credentialStore.Credentials +import com.intellij.ide.passwordSafe.PasswordSafe +import com.intellij.ide.util.PropertiesComponent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.intellij.remoteServer.util.CloudConfigurationUtil.createCredentialAttributes +import java.awt.Desktop +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.MediaType.Companion.toMediaType +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody.Companion.toRequestBody +import java.net.URL + +@Service +class ContinueAuthService { + companion object { + fun getInstance(): ContinueAuthService = service() + private const val CREDENTIALS_USER = "ContinueAuthUser" + private const val ACCESS_TOKEN_KEY = "ContinueAccessToken" + private const val REFRESH_TOKEN_KEY = "ContinueRefreshToken" + private const val ACCOUNT_ID_KEY = "ContinueAccountId" + private const val ACCOUNT_LABEL_KEY = "ContinueAccountLabel" + private const val CONTROL_PLANE_URL = "https://control-plane-api-service-i3dqylpbqa-uc.a.run.app" +// private const val CONTROL_PLANE_URL = "http://localhost:3001" + } + + init { + setupRefreshTokenInterval() + } + + fun startAuthFlow(project: Project) { + // Open login page + openSignInPage(project) + + // Open a dialog where the user should paste their sign-in token + ApplicationManager.getApplication().invokeLater { + val dialog = ContinueAuthDialog() { token -> + // Store the token + updateRefreshToken(token) + } + dialog.show() + } + } + + fun signOut() { + // Clear the stored tokens + setAccessToken("") + setRefreshToken("") + setAccountId("") + setAccountLabel("") + } + + private fun updateRefreshToken(token: String) { + // Launch a coroutine to call the suspend function + kotlinx.coroutines.GlobalScope.launch { + try { + val response = refreshToken(token) + val accessToken = response["accessToken"] as? String + val refreshToken = response["refreshToken"] as? String + val user = response["user"] as? Map<*, *> + val firstName = user?.get("firstName") as? String + val lastName = user?.get("lastName") as? String + val label = "$firstName $lastName" + val id = user?.get("id") as? String + + // Persist the session info + setRefreshToken(refreshToken!!) + val sessionInfo = ControlPlaneSessionInfo(accessToken!!, ControlPlaneSessionInfo.Account(id!!, label)) + setControlPlaneSessionInfo(sessionInfo) + + // Notify listeners + ApplicationManager.getApplication().messageBus.syncPublisher(AuthListener.TOPIC).handleUpdatedSessionInfo(sessionInfo) + + } catch (e: Exception) { + // Handle any exceptions + println("Exception while refreshing token: ${e.message}") + } + } + } + + private fun setupRefreshTokenInterval() { + // Launch a coroutine to refresh the token every 30 minutes + kotlinx.coroutines.GlobalScope.launch { + while (true) { + val refreshToken = getRefreshToken() + if (refreshToken != null) { + updateRefreshToken(refreshToken) + } + + kotlinx.coroutines.delay(30 * 60 * 1000) + } + } + } + + private suspend fun refreshToken(refreshToken: String) = withContext(Dispatchers.IO) { + val client = OkHttpClient() + val url = URL(CONTROL_PLANE_URL).toURI().resolve("/auth/refresh").toURL() + val jsonBody = mapOf("refreshToken" to refreshToken) + val jsonString = Gson().toJson(jsonBody) + val requestBody = jsonString.toRequestBody("application/json".toMediaType()) + + val request = Request.Builder() + .url(url) + .post(requestBody) + .header("Content-Type", "application/json") + .build() + + val response = client.newCall(request).execute() + + val responseBody = response.body?.string() + val gson = Gson() + val responseMap = gson.fromJson(responseBody, Map::class.java) + + responseMap + } + + + private fun openSignInPage(project: Project) { + val coreMessenger = project.service().coreMessenger + coreMessenger?.request("auth/getAuthUrl", null, null) { response -> + val authUrl = (response as? Map<*, *>)?.get("url") as? String + if (authUrl != null) { + // Open the auth URL in the browser + Desktop.getDesktop().browse(java.net.URI(authUrl)) + } + } + } + + private fun retrieveSecret(key: String): String? { + val attributes = createCredentialAttributes(key, CREDENTIALS_USER) + val passwordSafe: PasswordSafe = PasswordSafe.instance + + val credentials: Credentials? = passwordSafe[attributes!!] + return credentials?.getPasswordAsString() + } + + private fun storeSecret(key: String, secret: String) { + val attributes = createCredentialAttributes(key, CREDENTIALS_USER) + val passwordSafe: PasswordSafe = PasswordSafe.instance + + val credentials = Credentials(CREDENTIALS_USER, secret) + passwordSafe.set(attributes!!, credentials) + } + + private fun getAccessToken(): String? { + return retrieveSecret(ACCESS_TOKEN_KEY) + } + + private fun setAccessToken(token: String) { + storeSecret(ACCESS_TOKEN_KEY, token) + } + + private fun getRefreshToken(): String? { + return retrieveSecret(REFRESH_TOKEN_KEY) + } + + private fun setRefreshToken(token: String) { + storeSecret(REFRESH_TOKEN_KEY, token) + } + + fun getAccountId(): String? { + return PropertiesComponent.getInstance().getValue(ACCOUNT_ID_KEY) + } + + fun setAccountId(id: String) { + PropertiesComponent.getInstance().setValue(ACCOUNT_ID_KEY, id) + } + + fun getAccountLabel(): String? { + return PropertiesComponent.getInstance().getValue(ACCOUNT_LABEL_KEY) + } + + fun setAccountLabel(label: String) { + PropertiesComponent.getInstance().setValue(ACCOUNT_LABEL_KEY, label) + } + + // New method to load all info as an object + fun loadControlPlaneSessionInfo(): ControlPlaneSessionInfo? { + val accessToken = getAccessToken() + val accountId = getAccountId() + val accountLabel = getAccountLabel() + + return if (accessToken != null && accountId != null && accountLabel != null) { + ControlPlaneSessionInfo( + accessToken = accessToken, + account = ControlPlaneSessionInfo.Account( + id = accountId, + label = accountLabel + ) + ) + } else { + null + } + } + + // New method to set all info from a ControlPlaneSessionInfo object + fun setControlPlaneSessionInfo(info: ControlPlaneSessionInfo) { + setAccessToken(info.accessToken) + setAccountId(info.account.id) + setAccountLabel(info.account.label) + } + +} + +// Data class to represent the ControlPlaneSessionInfo +data class ControlPlaneSessionInfo( + val accessToken: String, + val account: Account +) { + data class Account( + val id: String, + val label: String + ) +} diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteActionGroup.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteActionGroup.kt new file mode 100644 index 000000000..bae9a8fe0 --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteActionGroup.kt @@ -0,0 +1,29 @@ +package com.github.continuedev.continueintellijextension.autocomplete + +import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.components.service + +class AutocompleteActionGroup : DefaultActionGroup() { + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.EDT + } + + override fun update(e: AnActionEvent) { + super.update(e) + removeAll() + + val continueSettingsService = service() + if (continueSettingsService.continueState.enableTabAutocomplete) { + addAll( + DisableTabAutocompleteAction(), + ) + } else { + addAll( + EnableTabAutocompleteAction(), + ) + } + } +} \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteEditorListener.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteEditorListener.kt index 9320705f8..a2ef465a3 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteEditorListener.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteEditorListener.kt @@ -12,10 +12,15 @@ import com.intellij.openapi.util.TextRange class AutocompleteCaretListener: CaretListener { override fun caretPositionChanged(event: CaretEvent) { val caret = event.caret ?: return - val oldPosition = event.oldPosition val offset = caret.offset val editor = caret.editor val autocompleteService = editor.project?.service() ?: return + + if (autocompleteService.lastChangeWasPartialAccept) { + autocompleteService.lastChangeWasPartialAccept = false + return + } + val pending = autocompleteService.pendingCompletion; if (pending != null && pending.editor == editor && pending.offset == offset) { return @@ -29,10 +34,16 @@ class AutocompleteDocumentListener(private val editorManager: FileEditorManager, if (editor != editorManager.selectedTextEditor) { return } + + val service = editor.project?.service() ?: return + if (service.lastChangeWasPartialAccept) { + return + } + // Invoke later is important, otherwise the completion will be triggered before the document is updated // causing the old caret offset to be used invokeLater { - editor.project?.service()?.triggerCompletion(editor) + service.triggerCompletion(editor) } } } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt index 6d3691ad6..8731f7cac 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteService.kt @@ -14,18 +14,29 @@ import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.InlayProperties import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.WindowManager data class PendingCompletion ( - val editor: Editor, - val offset: Int, - val completionId: String, - val text: String? + val editor: Editor, + var offset: Int, + val completionId: String, + var text: String? ) @Service(Service.Level.PROJECT) class AutocompleteService(private val project: Project) { var pendingCompletion: PendingCompletion? = null; private val autocompleteLookupListener = project.service() + private var widget: AutocompleteSpinnerWidget? = null + + // To avoid triggering another completion on partial acceptance, + // we need to keep track of whether the last change was a partial accept + var lastChangeWasPartialAccept = false + + init { + val statusBar = WindowManager.getInstance().getStatusBar(project) + widget = statusBar.getWidget("AutocompleteSpinnerWidget") as? AutocompleteSpinnerWidget + } fun triggerCompletion(editor: Editor) { val settings = @@ -42,6 +53,7 @@ class AutocompleteService(private val project: Project) { val completionId = uuid() val offset = editor.caretModel.primaryCaret.offset pendingCompletion = PendingCompletion(editor, offset, completionId, null) + widget?.setLoading(true) // Request a completion from the core val virtualFile = FileDocumentManager.getInstance().getFile(editor.document) @@ -63,11 +75,13 @@ class AutocompleteService(private val project: Project) { val lineLength = lineEnd - lineStart project.service().coreMessenger?.request("autocomplete/complete", input, null, ({ response -> + widget?.setLoading(false) + val completions = response as List<*> if (completions.isNotEmpty()) { val completion = completions[0].toString() - if (completion.lines().size === 1 || column >= lineLength) { + if (completion.isNotEmpty() && (completion.lines().size === 1 || column >= lineLength)) { // Do not render if completion is multi-line and caret is in middle of line renderCompletion(editor, offset, completion) pendingCompletion = pendingCompletion?.copy(text = completion) @@ -80,12 +94,18 @@ class AutocompleteService(private val project: Project) { } private fun renderCompletion(editor: Editor, offset: Int, text: String) { + if (text.isEmpty()) { + return + } // Don't render completions when code completion dropdown is visible if (!autocompleteLookupListener.isLookupEmpty()) { return } ApplicationManager.getApplication().invokeLater { WriteAction.run { + // Clear existing completions + hideCompletions(editor) + val properties = InlayProperties() properties.relatesToPrecedingText(true) properties.disableSoftWrapping(true) @@ -120,8 +140,57 @@ class AutocompleteService(private val project: Project) { } } + private fun splitKeepingDelimiters(input: String, delimiterPattern: String = "\\s+"): List { + val initialSplit = input.split("(?<=$delimiterPattern)|(?=$delimiterPattern)".toRegex()) + .filter { it.isNotEmpty() } + + val result = mutableListOf() + var currentDelimiter = "" + + for (part in initialSplit) { + if (part.matches(delimiterPattern.toRegex())) { + currentDelimiter += part + } else { + if (currentDelimiter.isNotEmpty()) { + result.add(currentDelimiter) + currentDelimiter = "" + } + result.add(part) + } + } + + if (currentDelimiter.isNotEmpty()) { + result.add(currentDelimiter) + } + + return result +} + + fun partialAccept() { + val completion = pendingCompletion ?: return + val text = completion.text ?: return + val editor = completion.editor + val offset = completion.offset + + lastChangeWasPartialAccept = true + + // Split the text into words, keeping delimiters + val words = splitKeepingDelimiters(text) + println(words) + val word = words[0] + editor.document.insertString(offset, word) + editor.caretModel.moveToOffset(offset + word.length) + + // Remove the completion and re-display it + hideCompletions(editor) + completion.text = text.substring(word.length) + completion.offset += word.length + renderCompletion(editor, completion.offset, completion.text!!) + } + private fun cancelCompletion(completion: PendingCompletion) { // Send cancellation message to core + widget?.setLoading(false) project.service().coreMessenger?.request("autocomplete/cancel", null,null, ({})) } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteSpinnerWidgetFactory.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteSpinnerWidgetFactory.kt new file mode 100644 index 000000000..8408a4964 --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/AutocompleteSpinnerWidgetFactory.kt @@ -0,0 +1,111 @@ +package com.github.continuedev.continueintellijextension.autocomplete + +import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings +import com.intellij.openapi.Disposable +import com.intellij.openapi.components.service +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.wm.StatusBar +import com.intellij.openapi.wm.StatusBarWidget +import com.intellij.openapi.util.IconLoader +import com.intellij.openapi.wm.StatusBarWidgetFactory +import com.intellij.openapi.wm.WindowManager +import com.intellij.openapi.wm.impl.status.EditorBasedWidget +import com.intellij.ui.AnimatedIcon +import com.intellij.util.Consumer +import java.awt.event.MouseEvent +import javax.swing.Icon +import javax.swing.JLabel + +class AutocompleteSpinnerWidget(project: Project): EditorBasedWidget(project), StatusBarWidget.IconPresentation, Disposable { + private val iconLabel = JLabel() + private var isLoading = false + + private val animatedIcon = AnimatedIcon( + 100, + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading1(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading2(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading3(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading4(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading5(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading6(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading7(RiderLight).svg", javaClass), + IconLoader.getIcon("/icons/AnimationLoadingIcon/AnimationLoading8(RiderLight).svg", javaClass), + ) + + init { + updateIcon() + } + + fun show() { + println("Showing autocomplete spinner widget") + } + + override fun dispose() {} + + override fun ID(): String { + return "AutocompleteSpinnerWidget" + } + + override fun getTooltipText(): String? { + val enabled = service().state.enableTabAutocomplete + return if (enabled) "Continue Autocomplete Enabled" else "Continue Autocomplete Disabled" + } + + override fun getClickConsumer(): Consumer? { + return null + } + + override fun getIcon(): Icon = if (isLoading) animatedIcon else + IconLoader.getIcon("/icons/continue.svg", javaClass) + + fun setLoading(loading: Boolean) { + isLoading = loading + updateIcon() + } + + private fun updateIcon() { + iconLabel.icon = getIcon() + + + // Update the widget + val statusBar = WindowManager.getInstance().getStatusBar(project) + statusBar.updateWidget(ID()) + } + + override fun install(statusBar: StatusBar) { + updateIcon() + } + + override fun getPresentation(): StatusBarWidget.WidgetPresentation? { + return this + } +} + +class AutocompleteSpinnerWidgetFactory: StatusBarWidgetFactory { + fun create(project: Project): AutocompleteSpinnerWidget { + return AutocompleteSpinnerWidget(project) + } + + override fun getId(): String { + return "AutocompleteSpinnerWidget" + } + + override fun getDisplayName(): String { + return "Continue Autocomplete" + } + + override fun isAvailable(p0: Project): Boolean { + return true + } + + override fun createWidget(project: Project): StatusBarWidget { + return AutocompleteSpinnerWidget(project) + } + + override fun disposeWidget(p0: StatusBarWidget) { + Disposer.dispose(p0) + } + + override fun canBeEnabledOn(p0: StatusBar): Boolean = true +} \ No newline at end of file diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt index 3b8c8fe76..b151238c3 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueCustomElementRenderer.kt @@ -19,7 +19,8 @@ class ContinueCustomElementRenderer ( val text: String, ) : EditorCustomElementRenderer { override fun calcWidthInPixels(inlay: Inlay<*>): Int { - return (inlay.editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth(this.text) + val width = (inlay.editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth(this.text) + return width } private fun font(editor: Editor): Font { diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt index 989519cd6..38ecb5766 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/ContinueMultilineCustomElementRenderer.kt @@ -7,9 +7,8 @@ import com.intellij.openapi.editor.colors.EditorFontType import com.intellij.openapi.editor.impl.EditorImpl import com.intellij.openapi.editor.impl.FontInfo import com.intellij.openapi.editor.markup.TextAttributes -import com.intellij.ui.Gray import com.intellij.ui.JBColor -import java.awt.Color +import com.intellij.util.ui.UIUtil import java.awt.Font import java.awt.Graphics import java.awt.Rectangle @@ -39,7 +38,7 @@ class ContinueMultilineCustomElementRenderer ( protected val font: Font get() { val editorFont = editor.colorsScheme.getFont(EditorFontType.PLAIN) - return editorFont.deriveFont(Font.PLAIN) ?: editorFont + return UIUtil.getFontWithFallbackIfNeeded(editorFont, text).deriveFont(editor.colorsScheme.editorFontSize) } private fun offsetY(): Int { @@ -58,7 +57,9 @@ class ContinueMultilineCustomElementRenderer ( FontInfo.getFontMetrics(font, FontInfo.getFontRenderContext(editor.contentComponent)) val fontWidth = font.createGlyphVector(metrics.fontRenderContext, text).visualBounds.width - val widthBeforeCaret = (editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth(text.substring(0, currentColumn)) + val widthBeforeCaret = (editor as EditorImpl).getFontMetrics(Font.PLAIN).stringWidth( + text.substring(0, minOf(currentColumn, text.length)) + ) return max(0, widthBeforeCaret - (editor as EditorImpl).scrollingModel.horizontalScrollOffset) } @@ -68,7 +69,7 @@ class ContinueMultilineCustomElementRenderer ( var additionalYOffset = -editor.lineHeight; var isFirstLine = true for (line in text.lines()) { - g.drawString(line, if (isFirstLine) targetRegion.x + offsetX() else targetRegion.x, targetRegion.y + offsetY() + additionalYOffset) + g.drawString(line, if (isFirstLine) targetRegion.x + offsetX() else targetRegion.x, targetRegion.y + inlay.editor.ascent + additionalYOffset) additionalYOffset += editor.lineHeight isFirstLine = false } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/DisableTabAutocompleteAction.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/DisableTabAutocompleteAction.kt new file mode 100644 index 000000000..d7e1f3b13 --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/DisableTabAutocompleteAction.kt @@ -0,0 +1,12 @@ +package com.github.continuedev.continueintellijextension.autocomplete + +import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +class DisableTabAutocompleteAction : AnAction() { + override fun actionPerformed(e: AnActionEvent) { + val continueSettingsService = service() + continueSettingsService.continueState.enableTabAutocomplete = true + } +} diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/EnableTabAutocompleteAction.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/EnableTabAutocompleteAction.kt new file mode 100644 index 000000000..b14aa2190 --- /dev/null +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/EnableTabAutocompleteAction.kt @@ -0,0 +1,12 @@ +package com.github.continuedev.continueintellijextension.autocomplete + +import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +class EnableTabAutocompleteAction : AnAction() { + override fun actionPerformed(e: AnActionEvent) { + val continueSettingsService = service() + continueSettingsService.continueState.enableTabAutocomplete = true + } +} diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/PartialAcceptAutocompleteAction.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/PartialAcceptAutocompleteAction.kt index 1cd223df9..93c94ee0a 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/PartialAcceptAutocompleteAction.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/autocomplete/PartialAcceptAutocompleteAction.kt @@ -11,8 +11,7 @@ import com.intellij.openapi.editor.actionSystem.EditorActionHandler class PartialAcceptAutocompleteAction: EditorAction(object : EditorActionHandler() { override fun doExecute(editor: Editor, caret: Caret?, dataContext: DataContext?) { ApplicationManager.getApplication().runWriteAction { - // TODO -// editor.project?.service()?.accept() + editor.project?.service()?.partialAccept() } } diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/CoreMessenger.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/CoreMessenger.kt index 68972b15d..ded887c76 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/CoreMessenger.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/CoreMessenger.kt @@ -147,14 +147,17 @@ class CoreMessenger(private val project: Project, esbuildPath: String, continueC "applyToFile", "getGitHubAuthToken", "setGitHubAuthToken", - "pathSep" + "pathSep", + "getControlPlaneSessionInfo", + "logoutOfControlPlane" ) private val PASS_THROUGH_TO_WEBVIEW = listOf( "configUpdate", "getDefaultModelTitle", "indexProgress", - "refreshSubmenuItems" + "refreshSubmenuItems", + "didChangeAvailableProfiles" ) private fun setPermissions(destination: String) { diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt index c999cfcab..e8aa27b6c 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/continue/IdeProtocolClient.kt @@ -1,6 +1,8 @@ package com.github.continuedev.continueintellijextension.`continue` import com.github.continuedev.continueintellijextension.* +import com.github.continuedev.continueintellijextension.auth.AuthListener +import com.github.continuedev.continueintellijextension.auth.ContinueAuthService import com.github.continuedev.continueintellijextension.constants.* import com.github.continuedev.continueintellijextension.services.ContinueExtensionSettings import com.github.continuedev.continueintellijextension.services.ContinuePluginService @@ -232,9 +234,28 @@ class IdeProtocolClient ( respond(mapOf( "remoteConfigServerUrl" to settings.continueState.remoteConfigServerUrl, "remoteConfigSyncPeriod" to settings.continueState.remoteConfigSyncPeriod, - "userToken" to settings.continueState.userToken + "userToken" to settings.continueState.userToken, + "enableControlServerBeta" to settings.continueState.enableContinueTeamsBeta )) } + "getControlPlaneSessionInfo" -> { + val silent = (data as? Map)?.get("silent") as? Boolean ?: false + + val authService = service() + if (silent) { + val sessionInfo = authService.loadControlPlaneSessionInfo() + respond(sessionInfo) + } else { + authService.startAuthFlow(project) + respond(null) + } + } + "logoutOfControlPlane" -> { + val authService = service() + authService.signOut() + ApplicationManager.getApplication().messageBus.syncPublisher(AuthListener.TOPIC).handleUpdatedSessionInfo(null) + respond(null) + } "getIdeInfo" -> { val applicationInfo = ApplicationInfo.getInstance() val ideName: String = applicationInfo.fullApplicationName diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/editor/InlineEditAction.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/editor/InlineEditAction.kt index 6dddcb582..e974cf8fd 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/editor/InlineEditAction.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/editor/InlineEditAction.kt @@ -64,9 +64,9 @@ class InlineEditAction : AnAction(), DumbAware { // Get list of model titles val continuePluginService = project.service() val modelTitles = mutableListOf() - continuePluginService.coreMessenger?.request("config/getBrowserSerialized", null, null) { response -> + continuePluginService.coreMessenger?.request("config/getSerializedProfileInfo", null, null) { response -> val config = response as Map - val models = config["models"] as List> + val models = (config["config"] as Map)["models"] as List> modelTitles.addAll(models.map { it["title"] as String }) } val maxWaitTime = 200 diff --git a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/services/ContinueExtensionSettingsService.kt b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/services/ContinueExtensionSettingsService.kt index 748796d4c..6ff8277a5 100644 --- a/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/services/ContinueExtensionSettingsService.kt +++ b/extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/services/ContinueExtensionSettingsService.kt @@ -1,20 +1,13 @@ package com.github.continuedev.continueintellijextension.services import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.components.PersistentStateComponent -import com.intellij.openapi.components.ServiceManager -import com.intellij.openapi.components.State -import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.* import com.intellij.openapi.options.Configurable import com.intellij.openapi.project.DumbAware import com.intellij.util.messages.Topic import java.awt.GridBagConstraints import java.awt.GridBagLayout -import javax.swing.JCheckBox -import javax.swing.JComponent -import javax.swing.JLabel -import javax.swing.JPanel -import javax.swing.JTextField +import javax.swing.* class ContinueSettingsComponent: DumbAware { val panel: JPanel = JPanel(GridBagLayout()) @@ -22,6 +15,7 @@ class ContinueSettingsComponent: DumbAware { val remoteConfigSyncPeriod: JTextField = JTextField() val userToken: JTextField = JTextField() val enableTabAutocomplete: JCheckBox = JCheckBox("Enable Tab Autocomplete") + val enableContinueTeamsBeta: JCheckBox = JCheckBox("Enable Continue for Teams Beta (requires restart)") init { val constraints = GridBagConstraints() @@ -34,7 +28,6 @@ class ContinueSettingsComponent: DumbAware { panel.add(JLabel("Remote Config Server URL:"), constraints) constraints.gridy++ - constraints.gridy++ panel.add(remoteConfigServerUrl, constraints) constraints.gridy++ panel.add(JLabel("Remote Config Sync Period (in minutes):"), constraints) @@ -47,6 +40,8 @@ class ContinueSettingsComponent: DumbAware { constraints.gridy++ panel.add(enableTabAutocomplete, constraints) constraints.gridy++ + panel.add(enableContinueTeamsBeta, constraints) + constraints.gridy++ // Add a "filler" component that takes up all remaining vertical space constraints.weighty = 1.0 @@ -69,6 +64,7 @@ open class ContinueExtensionSettings : PersistentStateComponent + messages.MyBundle @@ -108,10 +110,6 @@ text="Start New Continue Session" icon="AllIcons.General.Add" description="Start New Continue Session"> - - + + + + diff --git a/extensions/intellij/src/main/resources/config_schema.json b/extensions/intellij/src/main/resources/config_schema.json index 657d48c16..f57459207 100644 --- a/extensions/intellij/src/main/resources/config_schema.json +++ b/extensions/intellij/src/main/resources/config_schema.json @@ -481,6 +481,7 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4o", + "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo-0613", "gpt-4-32k", @@ -512,6 +513,9 @@ "anyOf": [ { "enum": [ + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "llama3-8b", "llama3-70b", "codellama-7b", @@ -545,7 +549,8 @@ "enum": [ "gpt-4o", "codestral-latest", - "llama3-70b", + "llama3.1-70b", + "llama3.1-405b", "gpt-3.5-turbo", "phind-codellama-34b", "gemini-pro", @@ -581,6 +586,7 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4o", + "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo-0613", "gpt-4-32k", @@ -596,6 +602,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phind-codellama-34b", "wizardcoder-7b", "wizardcoder-13b", @@ -746,6 +755,9 @@ "llama2-13b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "codellama-7b", "codellama-13b", "codellama-34b", @@ -810,6 +822,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phind-codellama-34b", "wizardcoder-7b", "wizardcoder-13b", @@ -858,6 +873,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phi-2", "phind-codellama-34b", "wizardcoder-7b", @@ -899,6 +917,7 @@ "model": { "enum": [ "codestral-latest", + "codestral-mamba-latest", "open-mistral-7b", "open-mixtral-8x7b", "open-mixtral-8x22b", @@ -944,6 +963,9 @@ "gemma", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "AUTODETECT" ] } @@ -1094,6 +1116,7 @@ "gpt-3.5-turbo", "gpt-3.5-turbo-16k", "gpt-4o", + "gpt-4o-mini", "gpt-4", "gpt-3.5-turbo-0613", "gpt-4-32k", @@ -1109,6 +1132,9 @@ "codellama-70b", "llama3-8b", "llama3-70b", + "llama3.1-8b", + "llama3.1-70b", + "llama3.1-405b", "phind-codellama-34b", "wizardcoder-7b", "wizardcoder-13b", @@ -1391,6 +1417,46 @@ } }, "allOf": [ + { + "if": { + "properties": { + "name": { + "enum": ["docs"] + } + } + }, + "then": { + "properties": { + "params": { + "properties": { + "sites": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "startUrl": { + "type": "string" + }, + "rootUrl": { + "type": "string" + }, + "maxDepth": { + "type": "integer" + } + }, + "required": ["title", "startUrl"] + } + } + }, + "required": ["sites"] + } + }, + "required": ["params"] + } + }, { "if": { "properties": { @@ -1761,6 +1827,33 @@ "title": "config.json", "type": "object", "properties": { + "docs": { + "title": "Docs", + "description": "A list of documentation sites to be indexed", + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the documentation site" + }, + "startUrl": { + "type": "string", + "description": "The starting URL for indexing the documentation" + }, + "rootUrl": { + "type": "string", + "description": "The root URL of the documentation site" + }, + "maxDepth": { + "type": "integer", + "description": "The maximum depth to crawl the documentation site" + } + }, + "required": ["title", "startUrl"] + } + }, "allowAnonymousTelemetry": { "title": "Allow Anonymous Telemetry", "markdownDescription": "If this field is set to True, we will collect anonymous telemetry as described in the documentation page on telemetry. If set to `false`, we will not collect any data. Learn more in [the docs](https://docs.continue.dev/telemetry).", @@ -1906,6 +1999,13 @@ "title": "Request Options", "description": "Request options to be used in any fetch requests made by the embeddings provider", "$ref": "#/definitions/RequestOptions" + }, + "maxChunkSize": { + "title": "Maximum Chunk Size", + "description": "The maximum number of tokens that each chunk of a document is allowed to have", + "type": "integer", + "minimum": 128, + "exclusiveMaximum": 2147483647 } }, "required": ["provider"], @@ -1944,7 +2044,13 @@ "type": "object", "properties": { "name": { - "enum": ["cohere", "voyage", "llm", "free-trial"] + "enum": [ + "cohere", + "voyage", + "llm", + "free-trial", + "huggingface-tei" + ] }, "params": { "type": "object" @@ -2034,6 +2140,50 @@ } } } + }, + { + "if": { + "properties": { + "name": { + "enum": ["huggingface-tei"] + } + }, + "required": ["name"] + }, + "then": { + "properties": { + "params": { + "type": "object", + "properties": { + "apiBase": { + "type": "string", + "default": "http://localhost:8080" + }, + "truncate": { + "type": "boolean", + "description": "Wether to truncate long sequences to the maximum allowed context length.", + "default": false + }, + "truncation_direction": { + "enum": ["Right", "Left"], + "markdownDescription": "Wether to truncate sequences from the `left` or `right`.", + "default": "Right" + } + }, + "required": ["apiBase"] + } + }, + "if": { + "properties": { + "truncate": { + "const": true + } + } + }, + "then": { + "required": ["truncation_direction"] + } + } } ] }, @@ -2071,7 +2221,7 @@ "type": "boolean", "description": "Determines whether the copy buffer will be considered when contructing the prompt." }, - "useSuffix": { + "useFileSuffix": { "type": "boolean", "description": "Determines whether to use the file suffix in the prompt." }, diff --git a/extensions/intellij/src/main/resources/webview/continue-dev-square.png b/extensions/intellij/src/main/resources/webview/continue-dev-square.png deleted file mode 100644 index e4b625568cad8592d8bb3aa9fd8fb659e4c7cceb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36355 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 diff --git a/extensions/intellij/src/main/resources/webview/continue.gif b/extensions/intellij/src/main/resources/webview/continue.gif deleted file mode 100644 index daed66637a9c9f9bf2d69799ce4d5cbec5f154e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5242 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 AbpQYW diff --git a/extensions/intellij/src/main/resources/webview/play_button.png b/extensions/intellij/src/main/resources/webview/play_button.png deleted file mode 100644 index af37937584d554d88193ddaa1a5dc9896da2532b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1017 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$6%U;1OBOz`!jG!i)^F=172) z6bHFGF|0c$^AgBmNq6*hWMJ6X&;2Knm4Sh|&(p;*q=ND7^~PKg0|C~Hrn?R;Fn;mI z$~aHK#jEMb={?t*t}FjFoqp^1hh?QaHJADsH?c4rqA9u-lO=z6|DT!NYqr+$>$@}j z5K?EjeorXhm{Gxpfqv+X;Rn`l_w1i5Wv_kyVV&u8EB3AIb}v{S+`7H5lanEliT0?! zF+bz|-(tN@*Q(C7UW<8U^FZ#0njgcuKiO&wEu6GRwru;BgS~$1_yP8{$raP-=8" } }, + "node_modules/minisearch": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.0.0.tgz", + "integrity": "sha512-0OIJ3hUE+YBJNruDCqbTMFmk/IoB1CpZzuGfl11khFIel66ew9UoLF/+gfq3bdyrneqr3P7BTjFZApUbmk+9Dg==" + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index b2bdca0db..30474739b 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -1,7 +1,7 @@ { "name": "continue", "icon": "media/icon.png", - "version": "0.8.43", + "version": "0.9.191", "repository": { "type": "git", "url": "https://github.com/continuedev/continue" @@ -74,6 +74,11 @@ "default": true, "markdownDescription": "Continue collects anonymous usage data, cleaned of PII, to help us improve the product for our users. Read more at [continue.dev β€Ί Telemetry](https://docs.continue.dev/telemetry)." }, + "continue.enableContinueForTeamsBeta": { + "type": "boolean", + "default": false, + "markdownDescription": "Enable Continue for teams beta features (requires window reload)" + }, "continue.showInlineTip": { "type": "boolean", "default": true, @@ -94,6 +99,16 @@ "default": false, "markdownDescription": "Pause Continue's tab autocomplete feature when your battery is low." }, + "continue.pauseCodebaseIndexOnStart": { + "type": "boolean", + "default": false, + "markdownDescription": "Pause Continue's codebase index on start." + }, + "continue.enableDebugLogs": { + "type": "boolean", + "default": false, + "markdownDescription": "Enable Continue Debug Logs in the Output panel." + }, "continue.remoteConfigServerUrl": { "type": "string", "default": null, @@ -231,15 +246,21 @@ "group": "Continue" }, { - "command": "continue.quickEditHistoryUp", + "command": "continue.codebaseForceReIndex", "category": "Continue", - "title": "Quick Edit History Up", + "title": "Codebase Force Re-Index", "group": "Continue" }, { - "command": "continue.quickEditHistoryDown", + "command": "continue.docsIndex", "category": "Continue", - "title": "Quick Edit History Down", + "title": "Docs Index", + "group": "Continue" + }, + { + "command": "continue.docsReIndex", + "category": "Continue", + "title": "Docs Force Re-Index", "group": "Continue" } ], @@ -559,6 +580,7 @@ "cors": "^2.8.5", "dbinfoz": "^0.1.4", "downshift": "^7.6.0", + "esbuild": "^0.17.19", "express": "^4.18.2", "fkill": "^8.1.0", "follow-redirects": "^1.15.4", @@ -571,6 +593,7 @@ "https-proxy-agent": "^7.0.2", "ignore": "^5.3.0", "jsdom": "^24.0.0", + "minisearch": "^7.0.0", "monaco-editor": "^0.45.0", "monaco-vscode-textmate-theme-converter": "^0.1.7", "ncp": "^2.0.0", @@ -589,7 +612,6 @@ "uuid": "^9.0.1", "uuidv4": "^6.2.13", "vectordb": "^0.4.20", - "esbuild": "^0.17.19", "vscode-languageclient": "^8.0.2", "ws": "^8.13.0", "yarn": "^1.22.21" diff --git a/extensions/vscode/scripts/prepackage.js b/extensions/vscode/scripts/prepackage.js index 7a710e791..95aaf0010 100644 --- a/extensions/vscode/scripts/prepackage.js +++ b/extensions/vscode/scripts/prepackage.js @@ -241,11 +241,15 @@ const exe = os === "win32" ? ".exe" : ""; ); }); - fs.copyFileSync( - path.join(__dirname, "../../../core/vendor/tree-sitter.wasm"), - path.join(__dirname, "../out/tree-sitter.wasm"), - ); - console.log("[info] Copied tree-sitter wasms"); + const filesToCopy = [ + "../../../core/vendor/tree-sitter.wasm", + "../../../core/llm/llamaTokenizerWorkerPool.mjs", + "../../../core/llm/llamaTokenizer.mjs", + ]; + for (const f of filesToCopy) { + fs.copyFileSync(path.join(__dirname, f), path.join(__dirname, "..", "out", path.basename(f))); + console.log(`[info] Copied ${path.basename(f)}`); + } // tree-sitter tag query files // ncp( @@ -450,6 +454,7 @@ const exe = os === "win32" ? ".exe" : ""; "@esbuild", "@lancedb", "@vscode/ripgrep", + "workerpool", ]; fs.mkdirSync("out/node_modules", { recursive: true }); diff --git a/extensions/vscode/src/debugPanel.ts b/extensions/vscode/src/ContinueGUIWebviewViewProvider.ts similarity index 66% rename from extensions/vscode/src/debugPanel.ts rename to extensions/vscode/src/ContinueGUIWebviewViewProvider.ts index 2c22158c6..08fedd54e 100644 --- a/extensions/vscode/src/debugPanel.ts +++ b/extensions/vscode/src/ContinueGUIWebviewViewProvider.ts @@ -1,5 +1,5 @@ import type { FileEdit } from "core"; -import { IConfigHandler } from "core/config/IConfigHandler"; +import { ConfigHandler } from "core/config/ConfigHandler"; import * as vscode from "vscode"; import { getTheme } from "./util/getTheme"; import { getExtensionVersion } from "./util/util"; @@ -12,12 +12,55 @@ export class ContinueGUIWebviewViewProvider public static readonly viewType = "continue.continueGUIView"; public webviewProtocol: VsCodeWebviewProtocol; + private updateDebugLogsStatus() { + const settings = vscode.workspace.getConfiguration("continue"); + this.enableDebugLogs = settings.get("enableDebugLogs", false); + if (this.enableDebugLogs) { + this.outputChannel.show(true); + } else { + this.outputChannel.hide(); + } + } + + // Show or hide the output channel on enableDebugLogs + private setupDebugLogsListener() { + vscode.workspace.onDidChangeConfiguration((event) => { + if (event.affectsConfiguration('continue.enableDebugLogs')) { + const settings = vscode.workspace.getConfiguration("continue"); + const enableDebugLogs = settings.get("enableDebugLogs", false); + if (enableDebugLogs) { + this.outputChannel.show(true); + } else { + this.outputChannel.hide(); + } + } + }); + } + + private async handleWebviewMessage(message: any) { + if (message.messageType === "log") { + const settings = vscode.workspace.getConfiguration("continue"); + const enableDebugLogs = settings.get("enableDebugLogs", false); + + if (message.level === "debug" && !enableDebugLogs) { + return; // Skip debug logs if enableDebugLogs is false + } + + const timestamp = new Date().toISOString().split(".")[0]; + const logMessage = `[${timestamp}] [${message.level.toUpperCase()}] ${message.text}`; + this.outputChannel.appendLine(logMessage); + } +} + resolveWebviewView( webviewView: vscode.WebviewView, _context: vscode.WebviewViewResolveContext, _token: vscode.CancellationToken, ): void | Thenable { this._webview = webviewView.webview; + this._webview.onDidReceiveMessage((message) => + this.handleWebviewMessage(message), + ); webviewView.webview.html = this.getSidebarContent( this.extensionContext, webviewView, @@ -25,6 +68,13 @@ export class ContinueGUIWebviewViewProvider } private _webview?: vscode.Webview; + private _webviewView?: vscode.WebviewView; + private outputChannel: vscode.OutputChannel; + private enableDebugLogs: boolean; + + get isVisible() { + return this._webviewView?.visible; + } get webview() { return this._webview; @@ -45,11 +95,17 @@ export class ContinueGUIWebviewViewProvider }); } + constructor( - private readonly configHandlerPromise: Promise, + private readonly configHandlerPromise: Promise, private readonly windowId: string, private readonly extensionContext: vscode.ExtensionContext, ) { + this.outputChannel = vscode.window.createOutputChannel("Continue"); + this.enableDebugLogs = false; + this.updateDebugLogsStatus(); + this.setupDebugLogsListener(); + this.webviewProtocol = new VsCodeWebviewProtocol( (async () => { const configHandler = await this.configHandlerPromise; @@ -126,6 +182,22 @@ export class ContinueGUIWebviewViewProvider
+ ${``} ${ inDevelopmentMode ? `