From 018df3184ddfad36e13c86437f4a075124f49b88 Mon Sep 17 00:00:00 2001 From: Jennifer Shehane Date: Thu, 5 Mar 2020 14:45:12 +0630 Subject: [PATCH] Restructure some docs (#2579) * Update contributing guide about deleting docs * Rename intelligent code completion to IDE integration / move troubleshooting into its own guide * Fix a bunch of broken links * Some other minor updates pulled over from other PR * Update debugging guide with link to Troubleshooting --- CONTRIBUTING.md | 12 +- source/_changelogs/3.4.0.md | 2 +- source/_changelogs/4.0.0.md | 2 +- source/_data/sidebar.yml | 3 +- .../core-concepts/introduction-to-cypress.md | 6 +- source/guides/core-concepts/test-runner.md | 6 +- source/guides/dashboard/projects.md | 2 +- .../writing-your-first-test.md | 14 +- source/guides/guides/command-line.md | 4 +- source/guides/guides/debugging.md | 420 +----------------- source/guides/guides/launching-browsers.md | 2 +- source/guides/references/configuration.md | 23 +- source/guides/references/troubleshooting.md | 388 ++++++++++++++++ ...-code-completion.md => IDE-integration.md} | 34 +- source/guides/tooling/typescript-support.md | 2 +- source/ja/faq/questions/using-cypress-faq.md | 2 +- source/ru/guides/overview/why-cypress.md | 2 +- source/zh-cn/guides/dashboard/projects.md | 2 +- .../writing-your-first-test.md | 4 +- source/zh-cn/guides/guides/command-line.md | 4 +- .../zh-cn/guides/guides/launching-browsers.md | 2 +- .../zh-cn/guides/references/configuration.md | 2 +- .../guides/tooling/typescript-support.md | 2 +- themes/cypress/languages/en.yml | 3 +- themes/cypress/languages/ja.yml | 3 +- themes/cypress/languages/pt-br.yml | 3 +- themes/cypress/languages/ru.yml | 3 +- themes/cypress/languages/zh-cn.yml | 3 +- .../test-runner-settings-nodejs-version.jpg | Bin 0 -> 70112 bytes 29 files changed, 497 insertions(+), 458 deletions(-) create mode 100644 source/guides/references/troubleshooting.md rename source/guides/tooling/{intelligent-code-completion.md => IDE-integration.md} (87%) create mode 100644 themes/cypress/source/img/guides/test-runner-settings-nodejs-version.jpg diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09607540e5..1438ecae1e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -104,9 +104,19 @@ To add a page such as a new guide or API documentation: - Link to your new page in the [`sidebar.yml`](/source/_data/sidebar.yml). - Add translations for the sidebar link for each supported language (for English, this is located in [`en.yml`](/themes/cypress/languages/en.yml)). - Build the documentation site locally so that you can visually inspect your new page and the links to it. -- Commit the new file using git - we auto-generate the doc to display within each supported language, this auto-generation depends on the file existing in git. +- **REQUIRED**: Commit the new file using git - we auto-generate the doc to display within each supported language, this auto-generation depends on the file existing in git. - Submit a [pull request](#Pull-Requests) for your change. +### Deleting Pages + +To delete a page: + +- Delete the page from the relevant directory under [`source`](/source). +- Remove the link from the the [`sidebar.yml`](/source/_data/sidebar.yml). +- Remove the translations for the sidebar link for each supported language (for English, this is located in [`en.yml`](/themes/cypress/languages/en.yml)). +- **REQUIRED**: Commit the change using git - we auto-remove the doc within each supported language, this auto-generation depends on the file being deleted in git, the build will not work until this is commited. +- Build the documentation site locally so that you can visually inspect and make sure it was properly deleted. + #### A Worked Example Let's imagine that the Cypress team has just added a new command called `privateState` and you've picked up the task to document it. diff --git a/source/_changelogs/3.4.0.md b/source/_changelogs/3.4.0.md index 93cea6cfaa..01e67a4201 100644 --- a/source/_changelogs/3.4.0.md +++ b/source/_changelogs/3.4.0.md @@ -24,7 +24,7 @@ - Environment variables for Semaphore 2.0 are now captured when recording tests to the Dashboard. Fixes {% issue 4671 %}. - We now capture environment variables set from Concourse CI when recording tests to the Dashboard. Fixes {% issue 4376 %}. - We replaced capturing environment variables from SnapCI (which is no longer available) to instead capture ones set from GoCD when recording tests to the Dashboard. Fixes {% issue 2680 %}. -- The {% url "JSON schema file" https://on.cypress.io/cypress.schema.json %} used for {% url "intelligent code completion" https://on.cypress.io/intelligent-code-completion#Configuration %} for the Cypress configuration file has been updated to match our documentation. +- The {% url "JSON schema file" https://on.cypress.io/cypress.schema.json %} used for {% url "intelligent code completion" IDE-integration#Intelligent-Code-Completion %} for the Cypress configuration file has been updated to match our documentation. **Documentation Changes:** diff --git a/source/_changelogs/4.0.0.md b/source/_changelogs/4.0.0.md index 9e7ff77481..d2efa5daf6 100644 --- a/source/_changelogs/4.0.0.md +++ b/source/_changelogs/4.0.0.md @@ -48,7 +48,7 @@ Cypress 4.0.0 includes support for {% url "Mozilla Firefox" https://www.mozilla. - The browser icons in the Test Runner now display as images with the proper branding. Addresses {% issue 6188 %}. - We updated the styling of browser dropdown in the Test Runner to look more like a button. Addresses {% issue 6298 %}. - The timer in the Test Runner now always displays at a consistent length. Addresses {% issue 6168 %}. -- You can print debug information about the memory & CPU usage of Cypress, which can be accessed by enabling the {% url "`cypress:server:util:process_profiler` debug stream" debugging#Log-memory-and-CPU-usage %}. Addresses {% issue 6169 %}. +- You can print debug information about the memory & CPU usage of Cypress, which can be accessed by enabling the {% url "`cypress:server:util:process_profiler` debug stream" troubleshooting#Log-memory-and-CPU-usage %}. Addresses {% issue 6169 %}. - We added types for plugin events. Addresses {% issue 6322 %}. **Dependency Updates** diff --git a/source/_data/sidebar.yml b/source/_data/sidebar.yml index ac40c485c7..893ee7b3b7 100644 --- a/source/_data/sidebar.yml +++ b/source/_data/sidebar.yml @@ -36,7 +36,7 @@ guides: cross-browser-testing: cross-browser-testing.html web-security: web-security.html tooling: - intelligent-code-completion: intelligent-code-completion.html + IDE-integration: IDE-integration.html plugins-guide: plugins-guide.html reporters: reporters.html typescript-support: typescript-support.html @@ -51,6 +51,7 @@ guides: error-messages: error-messages.html bundled-tools: bundled-tools.html trade-offs: trade-offs.html + troubleshooting: troubleshooting.html changelog: changelog.html migration-guide: migration-guide.html roadmap: roadmap.html diff --git a/source/guides/core-concepts/introduction-to-cypress.md b/source/guides/core-concepts/introduction-to-cypress.md index 2e7c6050f9..12891ba5d5 100644 --- a/source/guides/core-concepts/introduction-to-cypress.md +++ b/source/guides/core-concepts/introduction-to-cypress.md @@ -805,7 +805,8 @@ All DOM based commands automatically wait for their elements to exist in the DOM You don't need to write {% url "`.should('exist')`" should %} after a DOM based command, unless you chain extra `.should()` assertions. {% endnote %} -{% note danger "Negative DOM assertions" %} +#### Negative DOM assertions + If you chain any `.should()` command, the default `.should('exist')` is not asserted. This does not matter for most *positive* assertions, such as `.should('have.class')`, because those imply existence in the first place, but if you chain *negative* assertions ,such as `.should('not.have.class')`, they will pass even if the DOM element doesn't exist: ```js @@ -822,9 +823,6 @@ cy.get('.does-not-exist').should(($element) => { }) ``` -There's an {% url 'open discussion' https://github.com/cypress-io/cypress/issues/205 %} about this behavior. -{% endnote %} - These rules are pretty intuitive, and most commands give you the flexibility to override or bypass the default ways they can fail, typically by passing a `{force: true}` option. ### Example #1: Existence and Actionability diff --git a/source/guides/core-concepts/test-runner.md b/source/guides/core-concepts/test-runner.md index 847f232fd8..ec858b33ec 100644 --- a/source/guides/core-concepts/test-runner.md +++ b/source/guides/core-concepts/test-runner.md @@ -39,15 +39,15 @@ Each command, assertion, or error, when clicked on, displays extra information i For certain commands like {% url `cy.route()` route %}, {% url `cy.stub()` stub %}, and {% url `cy.spy()` spy %}, an extra instrument panel is displayed above the test to give more information about the state of your tests. -## Routes: +## Routes {% imgTag /img/guides/instrument-panel-routes.png "Routes Instrument Panel" %} -## Stubs: +## Stubs {% imgTag /img/guides/instrument-panel-stubs.png "Stubs Instrument Panel" %} -## Spies: +## Spies {% imgTag /img/guides/instrument-panel-spies.png "Spies Instrument Panel" %} diff --git a/source/guides/dashboard/projects.md b/source/guides/dashboard/projects.md index 2b9f808d1b..56a36dab02 100644 --- a/source/guides/dashboard/projects.md +++ b/source/guides/dashboard/projects.md @@ -73,7 +73,7 @@ If you're using source control, we recommend that you check your `cypress.json`, export CYPRESS_PROJECT_ID={projectId} ``` -## Record key {% fa fa-key %} +## Record key The record key is used to authenticate that your project is *allowed* to record tests to the Dashboard Service. As long as your record key stays *private*, nobody will be able to record test runs for your project - even if they have your `projectId`. diff --git a/source/guides/getting-started/writing-your-first-test.md b/source/guides/getting-started/writing-your-first-test.md index 19bd920eaf..8c88c337b8 100644 --- a/source/guides/getting-started/writing-your-first-test.md +++ b/source/guides/getting-started/writing-your-first-test.md @@ -219,7 +219,7 @@ Now we can assert something about this new page! {% video local /img/snippets/first-test-click-30fps.mp4 %} {% note info %} -{% fa fa-magic %} You can see IntelliSense in your spec files by adding a single special comment line. Read about {% url 'Intelligent Code Completion' intelligent-code-completion#Triple-slash-directives %}. +{% fa fa-magic %} You can see IntelliSense in your spec files by adding a single special comment line. Read about {% url 'Intelligent Code Completion' IDE-integration#Triple-slash-directives %}. {% endnote %} ## {% fa fa-check-square-o %} Step 4: Make an assertion @@ -229,8 +229,8 @@ Let's make an assertion about something on the new page we clicked into. Perhaps Here's what that looks like: ```js -describe('My First Test', function() { - it('clicking "type" navigates to a new url', function() { +describe('My First Test', () => { + it('clicking "type" navigates to a new url', () => { cy.visit('https://example.cypress.io') cy.contains('type').click() @@ -250,8 +250,8 @@ We can continue the interactions and assertions in this test by adding another c We can use {% url "`cy.get()`" get %} to select an element based on a CSS class. Then we can use the {% url "`.type()`" type %} command to enter text into the selected input. Finally, we can verify that the value of the input reflects the text that was typed with another {% url "`.should()`" should %}. ```js -describe('My First Test', function() { - it('Gets, types and asserts', function() { +describe('My First Test', () => { + it('Gets, types and asserts', () => { cy.visit('https://example.cypress.io') cy.contains('type').click() @@ -431,7 +431,7 @@ Now Cypress provides us a UI (similar to debugger) to step forward through each {% imgTag /img/guides/first-test-paused.png "Test Runner shows label saying 'Paused' with Command Log showing 'Pause'" %} -## In action +### In action {% video local /img/snippets/first-test-debugging-30fps.mp4 %} @@ -496,7 +496,7 @@ describe('My First Test', function() { # Next steps - Start {% url 'testing your app' testing-your-app %}. -- Set up {% url 'intelligent code completion' intelligent-code-completion %} for Cypress commands and assertions. +- Set up {% url 'intelligent code completion' IDE-integration#Intelligent-Code-Completion %} for Cypress commands and assertions. - Search Cypress's documentation to quickly find what you need. {% imgTag /img/guides/search-box.png "Use the search box to find relevant documentation" %} diff --git a/source/guides/guides/command-line.md b/source/guides/guides/command-line.md index 2621f475f2..422080ee4d 100644 --- a/source/guides/guides/command-line.md +++ b/source/guides/guides/command-line.md @@ -115,7 +115,7 @@ You can also choose a browser by supplying a path: cypress run --browser /usr/bin/chromium ``` -{% url "Having trouble with browser detection? Check out the debugging guide" debugging#Launching-browsers %} +{% url "Having trouble with browser detection? Check out our troubleshooting guide" troubleshooting#Launching-browsers %} ### `cypress run --ci-build-id ` @@ -371,7 +371,7 @@ If found, the specified browser will be added to the list of available browsers Currently, only browsers in the Chrome family are supported (including the new Chromium-based Microsoft Edge and Brave). -{% url "Having trouble launching a browser? Check out the debugging guide" debugging#Launching-browsers %} +{% url "Having trouble launching a browser? Check out our troubleshooting guide" troubleshooting#Launching-browsers %} ### `cypress open --config ` diff --git a/source/guides/guides/debugging.md b/source/guides/guides/debugging.md index 6cfc273cdc..b34511a565 100644 --- a/source/guides/guides/debugging.md +++ b/source/guides/guides/debugging.md @@ -8,7 +8,6 @@ title: Debugging - How Cypress runs in the same event loop with your code, keeping debugging less demanding and more understandable - How Cypress embraces the standard Developer Tools - How and when to use `debugger` and the shorthand {% url `.debug()` debug %} command -- How to troubleshoot issues with Cypress itself {% endnote %} # Using `debugger` @@ -75,159 +74,7 @@ The current subject that is yielded by the {% url `cy.get()` get %} is exposed a Use {% url `.debug()` debug %} to quickly inspect any (or many!) part(s) of your application during the test. You can attach it to any Cypress chain of commands to have a look at the system's state at that moment. -# Using the Developer Tools - -Though Cypress has built out {% url "an excellent Test Runner" test-runner %} to help you understand what is happening in your application and your tests, there's no replacing all the amazing work browser teams have done on their built-in development tools. Once again, we see that Cypress goes _with_ the flow of the modern ecosystem, opting to leverage these tools wherever possible. - -{% note info %} -## {% fa fa-video-camera %} See it in action! - -You can see a walk-through of debugging some application code from Cypress {% url "in this segment from our React tutorial series" https://vimeo.com/242961930#t=264s %}. -{% endnote %} - -## Get console logs for commands - -All of Cypress's commands, when clicked on within the {% url "Command Log" test-runner#Command-Log %}, print extra information about the command, its subject, and its yielded result. Try clicking around the Command Log with your Developer Tools open! You may find some useful information here. - -### When clicking on `.type()` command, the Developer Tools console outputs the following: - -{% imgTag /img/api/type/console-log-of-typing-with-entire-key-events-table-for-each-character.png "Console Log type" %} - -# Cypress fiddle - -While learning Cypress it may be a good idea to try small tests against some HTML. We have written a {% url @cypress/fiddle https://github.com/cypress-io/cypress-fiddle %} plugin for this. It can quickly mount any given HTML and run some Cypress test commands against it. - -# Troubleshooting Cypress - -There are times when you will encounter errors or unexpected behavior with Cypress itself. In this situation, we recommend checking these support resources **first**. - -## Support channels - -- Connect with our community in {% url "Gitter" https://gitter.im/cypress-io/cypress %} -- Search existing {% url "GitHub issues" https://github.com/cypress-io/cypress/issues %} -- Search this documentation (search is in the top right) 😉 -- Search {% url "Stack Overflow" https://stackoverflow.com/questions/tagged/cypress %} for relevant answers -- If your organization signs up for one of our {% url "paid plans" https://www.cypress.io/pricing/ %}, you can get dedicated email support, which gives you one-on-one help from our team. -- If you still haven't found a solution, {% url "open an issue" https://github.com/cypress-io/cypress/issues/new %} *with a reproducible example*. - -## Isolate the Problem - -When debugging a failing test, follow these general principles to isolate the problem: - -- Look at the {% url "video recordings and screenshots" screenshots-and-videos %}. -- Split large spec files into smaller ones. -- Split long tests into smaller tests. -- Run the same test using {% url '`--browser chrome`' command-line#cypress-run-browser-lt-browser-name-or-path-gt %}. The problem might be isolated to the Electron browser. -- If isolated to the Electron browser. Run the same tests in both Electron and Chrome, then compare the screenshots/videos. Look for and isolate any differences in the Command Log. - -{% partial chromium_download %} - -## Clear Cypress cache - -If you're having an issue during installation of Cypress, try removing the contents of the Cypress cache. - -This will clear out all installed versions of Cypress that may be cached on your machine. - -```shell -cypress cache clear -``` - -After running this command, you will need to run `cypress install` before running Cypress again. - -```shell -npm install cypress --save-dev -``` - -## Launching browsers - -Cypress attempts to {% url 'automatically find installed Chrome versions for you' launching-browsers %}. However, probing for browsers across different environments can be error-prone. If Cypress cannot find a browser but you know you have it installed, there are ways to ensure that Cypress can "see" it. - -{% note info Using the `--browser` command line argument %} -You can also supply the `--browser` command line argument to launch a browser from a known filesystem path to bypass browser auto detection. {% url "See 'Launching Browsers' for more information" launching-browsers#Launching-by-a-path % } %} -{% endnote %} - -You can see the full list of found browsers and their properties within the {% url "resolved configuration" configuration#Resolved-Configuration %} in the **Settings** tab of the Test Runner. - -Another way to log what is found by Cypress is to run Cypress with the {% urlHash "DEBUG environment variable" Print-DEBUG-logs %} set to `cypress:launcher`. This will print information about the found browsers and their properties to the terminal. - -### Mac - -On Mac, Cypress attempts to find installed browsers by their bundle identifier. If this does not succeed, it will fall back to the Linux browser detection method. - -Browser Name | Expected Bundle Identifier | Expected Executable ---- | --- | --- -`chrome` | `com.google.Chrome` | `Contents/MacOS/Google Chrome` -`chromium` | `org.chromium.Chromium` | `Contents/MacOS/Chromium` -`chrome:canary` | `com.google.Chrome.canary` | `Contents/MacOS/Google Chrome Canary` - -For the current list, see {% url 'packages/launcher' https://github.com/cypress-io/cypress/blob/develop/packages/launcher/lib/darwin/index.ts %} files. - -### Linux - -On Linux, Cypress scans your `PATH` for a number of different binary names. If the browser you are trying to use does not exist under one of the expected binary names, Cypress will not be able to find it. - -Browser Name | Expected Binary Name(s) ---- | --- -`chrome` | `google-chrome`, `chrome`, or `google-chrome-stable` -`chromium` | `chromium-browser` or `chromium` -`chrome:canary` | `google-chrome-canary` - -These binary names should work for most Linux distributions. If your distribution packages browsers under a different binary name, you can add a symlink using the expected binary name so that Cypress can detect it. - -For example, if your distribution packages Google Chrome as `chrome`, you could add a symlink to `google-chrome` like this: - -```shell -sudo ln `which chrome` /usr/local/bin/google-chrome -``` - -### Windows - -On Windows, Cypress scans the following locations to try to find each browser: - -Browser Name | Expected Path ---- | --- -`chrome` | `C:/Program Files (x86)/Google/Chrome/Application/chrome.exe` -`chromium` | `C:/Program Files (x86)/Google/chrome-win32/chrome.exe` -`chrome:canary` | `%APPDATA%/../Local/Google/Chrome SxS/Application/chrome.exe` - -For the current list, see {% url 'packages/launcher' https://github.com/cypress-io/cypress/blob/develop/packages/launcher/lib/windows/index.ts %} files. - -To make a browser installed at a different path be auto-detected, create a symbolic link using `mklink` in the location that Cypress expects to find your browser. - -{% url 'Read more about creating symbolic links on Windows' https://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/ %} - -## Chrome extension whitelisting - -Cypress utilizes a Chrome extension within the Test Runner in order to run properly. If you or your company whitelist specific Chrome extensions, this may cause problems with running Cypress. You will want to ask your administrator to whitelist the Cypress extension ID below: - -```sh -caljajdfkjjjdehjdoimjkkakekklcck -``` - -## Clear App Data - -Cypress maintains some local application data in order to save user preferences and more quickly start up. Sometimes this data can become corrupted. You may fix an issue you have by clearing this app data. - -### To clear App Data - -1. Open Cypress via `cypress open` -2. Go to `File` -> `View App Data` -3. This will take you to the directory in your file system where your App Data is stored. If you cannot open Cypress, search your file system for a directory named `cy` whose content should look something like this: - - ```text - 📂 production - 📄 all.log - 📁 browsers - 📁 bundles - 📄 cache - 📁 projects - 📁 proxy - 📄 state.json - ``` -4. Delete everything in the `cy` folder -5. Close Cypress and open it up again - -## Step through test commands +# Step through test commands You can run the test command by command using the {% url `.pause()` pause %} command. @@ -241,62 +88,31 @@ it('adds items', function () { This allows you to inspect the web application, the DOM, the network, and any storage after each command to make sure everything happens as expected. -## Print DEBUG logs - -Cypress is built using the {% url 'debug' https://github.com/visionmedia/debug %} module. That means you can receive helpful debugging output by running Cypress with this turned on. **Note:** you will see a LOT of messages when running with `DEBUG=...` setting. - -**On Mac or Linux:** - -```shell -DEBUG=cypress:* cypress run -``` - -**On Windows:** - -```shell -set DEBUG=cypress:* -cypress run -``` - -Read more {% url 'about the CLI options here' command-line#Debugging-commands %} and {% url "Good Logging" https://glebbahmutov.com/blog/good-logging/ %} blog post. - -### Detailed Logs - -There are several levels of `DEBUG` messages - -```shell -# prints very few top-level messages -DEBUG=cypress:server ... -# prints ALL messages from server package -DEBUG=cypress:server* ... -# prints messages only from config parsing -DEBUG=cypress:server:config ... -``` +# Using the Developer Tools -This allows you to isolate the problem a little better +Though Cypress has built out {% url "an excellent Test Runner" test-runner %} to help you understand what is happening in your application and your tests, there's no replacing all the amazing work browser teams have done on their built-in development tools. Once again, we see that Cypress goes _with_ the flow of the modern ecosystem, opting to leverage these tools wherever possible. -### Debug logs in the browser +{% note info %} +## {% fa fa-video-camera %} See it in action! -If the problem is seen during `cypress open` you can print debug logs in the browser too. Open the browser's Developer Tools and set a `localStorage` property: +You can see a walk-through of debugging some application code from Cypress {% url "in this segment from our React tutorial series" https://vimeo.com/242961930#t=264s %}. +{% endnote %} -```javascript -localStorage.debug = 'cypress*' +## Get console logs for commands -// to disable debug messages -delete localStorage.debug -``` +All of Cypress's commands, when clicked on within the {% url "Command Log" test-runner#Command-Log %}, print extra information about the command, its subject, and its yielded result. Try clicking around the Command Log with your Developer Tools open! You may find some useful information here. -Reload the browser and see debug messages within the Developer Tools console. You will only see the "cypress:driver" package logs that run in the browser, as you can see below. +### When clicking on `.type()` command, the Developer Tools console outputs the following: -{% imgTag /img/api/debug/debug-driver.jpg "Debug logs in browser" %} +{% imgTag /img/api/type/console-log-of-typing-with-entire-key-events-table-for-each-character.png "Console Log type" %} -## Log Cypress events +# Log Cypress events -In addition to the `DEBUG` messages, Cypress also emits multiple events you can listen to as shown below. {% url 'Read more about logging events in the browser here' catalog-of-events#Logging-All-Events %}. +Cypress emits multiple events you can listen to as shown below. {% url 'Read more about logging events in the browser here' catalog-of-events#Logging-All-Events %}. {% imgTag /img/api/catalog-of-events/console-log-events-debug.png "console log events for debugging" %} -## Run Cypress command outside the test +# Run Cypress command outside the test If you need to run a Cypress command straight from the Developer Tools console, you can use the internal command `cy.now('command name', ...arguments)`. For example, to run the equivalent of `cy.task('database', 123)` outside the normal execution command chain: @@ -310,210 +126,10 @@ cy.now('task', 123) The `cy.now()` command is an internal command and may change in the future. {% endnote %} -## Log memory and CPU usage - -You can tell Cypress to log out a summary of the memory and CPU usage of itself and any subprocesses at a regular interval by enabling the `cypress:server:util:process_profiler` debug stream, like so: - -**On Mac or Linux:** - -```shell -DEBUG=cypress:server:util:process_profiler cypress run -``` - -**On Windows:** - -```shell -set DEBUG=cypress:server:util:process_profiler -cypress run -``` - -In the resulting output, processes are grouped by their name. - -{% imgTag /img/guides/troubleshooting-cypress-process-profiler-cli.jpg "Process printout of Cypress in CLI" %} - -By default, process information is collected and summarized is printed once every 10 seconds. You can override this interval by setting the `CYPRESS_PROCESS_PROFILER_INTERVAL` environment variable to the desired interval in milliseconds. - -You can also obtain more detailed per-process information by enabling the verbose `cypress-verbose:server:util:process_profiler` debug stream. - -## Additional information - -### Write command log to the terminal - -You can include the plugin [cypress-failed-log](https://github.com/bahmutov/cypress-failed-log) in your tests. This plugin writes the list of Cypress commands to the terminal as well as a JSON file if a test fails. - -{% imgTag /img/api/debug/failed-log.png "cypress-failed-log terminal output" %} - -# Hacking on Cypress - -If you want to dive into Cypress and edit the code yourself, you can do that. The Cypress code is open source and licensed under an {% url "MIT license" https://github.com/cypress-io/cypress/blob/develop/LICENSE %}. There are a few tips on getting started that we've outlined below. - -## Contribute - -If you'd like to contribute directly to the Cypress code, we'd love to have your help! Please check out our {% url "contributing guide" https://github.com/cypress-io/cypress/blob/develop/CONTRIBUTING.md %} to learn about the many ways you can contribute. - -## Run the Cypress app by itself - -Cypress comes with an npm CLI module that parses the arguments, starts the Xvfb server (if necessary), and then opens the Test Runner application built on top of {% url "Electron" https://electronjs.org/ %}. - -Some common situations on why you would want to run the Cypress app by itself are to: - -- debug Cypress not starting or hanging -- debug problems related to the way CLI arguments are parsed by the npm CLI module - -Here is how you can launch Cypress application directly without the npm CLI module. First, find where the binary is installed using the {% url "`cypress cache path`" command-line#cypress-cache-path %} command. - -For example, on a Linux machine: - -```shell -npx cypress cache path -/root/.cache/Cypress -``` - -Second, try a smoke test that verifies that the application has all its required dependencies present on the host machine: - -```shell -/root/.cache/Cypress/3.3.1/Cypress/Cypress --smoke-test --ping=101 -101 -``` - -If there is a missing dependency, the application should print an error message. You can see the Electron verbose log messages by setting an {% url "environment variable ELECTRON_ENABLE_LOGGING" https://electronjs.org/docs/api/environment-variables %}: - -```shell -ELECTRON_ENABLE_LOGGING=true DISPLAY=10.130.4.201:0 /root/.cache/Cypress/3.3.1/Cypress/Cypress --smoke-test --ping=101 -[809:0617/151243.281369:ERROR:bus.cc(395)] Failed to connect to the bus: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory -101 -``` - -If the smoke test fails to execute, check if a shared library is missing (a common problem on Linux machines without all of the Cypress dependencies present). - -```shell -ldd /home/person/.cache/Cypress/3.3.1/Cypress/Cypress - linux-vdso.so.1 (0x00007ffe9eda0000) - libnode.so => /home/person/.cache/Cypress/3.3.1/Cypress/libnode.so (0x00007fecb43c8000) - libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fecb41ab000) - libgtk-3.so.0 => not found - libgdk-3.so.0 => not found - ... -``` - -**Tip:** use {% url "Cypress Docker image" docker %} or install dependencies by copying them from one of our official Docker images. - -**Note:** verbose Electron logging might show warnings that still allow Cypress to work normally. For example, the Cypress Test Runner opens normally despite the scary output below: - -```shell -ELECTRON_ENABLE_LOGGING=true DISPLAY=10.130.4.201:0 /root/.cache/Cypress/3.3.1/Cypress/Cypress -[475:0617/150421.326986:ERROR:bus.cc(395)] Failed to connect to the bus: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory -[475:0617/150425.061526:ERROR:bus.cc(395)] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix") -[475:0617/150425.079819:ERROR:bus.cc(395)] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix") -[475:0617/150425.371013:INFO:CONSOLE(73292)] "%cDownload the React DevTools for a better development experience: https://fb.me/react-devtools -You might need to use a local HTTP server (instead of file://): https://fb.me/react-devtools-faq", source: file:///root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/desktop-gui/dist/app.js (73292) -``` - -You can also see verbose Cypress logs when running the Test Runner binary - -```shell -DEBUG=cypress* DISPLAY=10.130.4.201:0 /root/.cache/Cypress/3.3.1/Cypress/Cypress --smoke-test --ping=101 -cypress:ts Running without ts-node hook in environment "production" +0ms -cypress:server:cypress starting cypress with argv [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress', '--smoke-test', '--ping=101' ] +0ms -cypress:server:args argv array: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress', '--smoke-test', '--ping=101' ] +0ms -cypress:server:args argv parsed: { _: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress' ], smokeTest: true, ping: 101, cwd: '/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server' } +7ms -cypress:server:args options { _: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress' ], smokeTest: true, ping: 101, cwd: '/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server', config: {} } +2ms -cypress:server:args argv options: { _: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress' ], smokeTest: true, ping: 101, cwd: '/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server', config: {}, pong: 101 } +1ms -cypress:server:appdata path: /root/.config/Cypress/cy/production +0ms -cypress:server:cypress starting in mode smokeTest +356ms -101 -cypress:server:cypress about to exit with code 0 +4ms -``` - -If the smoke test does not show a specific error yet fails, try printing the Electron crash stack to maybe pinpoint the problem better: - -```shell -ELECTRON_ENABLE_STACK_DUMPING=1 npx cypress verify -... -Received signal 11 SEGV_MAPERR ffffffb27e8955bb -#0 0x55c6389f83d9 (/root/.cache/Cypress/3.8.2/Cypress/Cypress+0x35d13d8) -r8: 0000000000000000 r9: 00007ffcf0387c80 r10: 00007ffcf0387bd8 r11: 000000000000000e -r12: 00007ffcf0387d2c r13: 00007f3ea737b720 r14: ffffffb27e89558b r15: 00007f3ea8974200 -di: 0000000000000000 si: 0000000000000020 bp: 0000000000000000 bx: 0000004f2f375580 -dx: 0000000000000001 ax: 0000000000000030 cx: 0000000000000001 sp: 00007ffcf0387d00 -ip: 00007f3ea89582dd efl: 0000000000010246 cgf: 002b000000000033 erf: 0000000000000005 -trp: 000000000000000e msk: 0000000000000000 cr2: ffffffb27e8955bb -[end of stack trace] -Calling _exit(1). Core file will not be generated. -``` - -## Patch Cypress - -Cypress comes with an npm CLI module that parses the arguments, starts the Xvfb server (if necessary), and then opens the Test Runner application built on top of {% url "Electron" https://electronjs.org/ %}. - -If you're encountering a bug in the current version of Cypress, you can implementing a temporary fix by patching Cypress in your own project. Here is an example of how to do this. - -1. Install {% url "patch-package" https://github.com/ds300/patch-package %}. -2. Add a patch step to your CI configuration after installing your npm packages. - - ```yaml - - run: npm ci - - run: npx patch-package - ``` - - Alternatively, you can apply the patch during a post-install phase. In your `package.json`, for example, you could add the following: - - ```json - { - "scripts": { - "postinstall": "patch-package" - } - } - ``` - -3. Edit the line causing the problem *in your local node_modules folder* within `node_modules/cypress`. -4. Run the `npx patch-package cypress` command. This command will create a new file `patches/cypress+3.4.1.patch`. - - ```shell - npx patch-package cypress - patch-package 6.1.2 - • Creating temporary folder - • Installing cypress@3.4.1 with npm - • Diffing your files with clean files - ✔ Created file patches/cypress+3.4.1.patch - ``` - -5. Commit the new `patches` folder to git. - -{% note info %} -If you find a patch for an error, please add a comment explaining your workaround to the relevant Cypress GitHub issue. It will help us release an official fix faster. -{% endnote %} - -## Edit the installed Cypress code - -The installed Test Runner comes with the fully transpiled, unobfuscated JavaScript source code that you can hack on. You might want to directly modify the installed Test Runner code to: - -- investigate a hard to recreate bug that happens on your machine -- change the run-time behavior of Cypress before opening a pull request -- have fun 🎉 - -First, print where the binary is installed using the {% url "`cypress cache path`" command-line#cypress-cache-path %} command. - -For example, on a Mac: - -```shell -npx cypress cache path -/Users/jane/Library/Caches/Cypress -``` - -Second, open the source code at the following path in any code editor. Make sure to substitute `3.3.1` for the desired version of the Test Runner you want to edit. - -```text -/Users/jane/Library/Caches/Cypress/3.3.1/Cypress.app/Contents/Resources/app/packages/ -``` - -You can change anything in the JavaScript code: +# Cypress fiddle -{% imgTag /img/guides/source-code.png "Source code of the Test Runner in a text editor" %} +While learning Cypress it may be a good idea to try small tests against some HTML. We have written a {% url @cypress/fiddle https://github.com/cypress-io/cypress-fiddle %} plugin for this. It can quickly mount any given HTML and run some Cypress test commands against it. -When finished, if necessary, remove the edited Test Runner version and reinstall the Cypress official version to get back to the official released code. +# Toubleshooting Cypress -```shell -rm -rf /Users/jane/Library/Caches/Cypress/3.3.1 -npm install cypress@3.3.1 -``` +There are times when you will encounter errors or unexpected behavior with Cypress itself. In this situation, we recommend checking our out {% url "Troubleshooting Guide" troubleshooting %}. diff --git a/source/guides/guides/launching-browsers.md b/source/guides/guides/launching-browsers.md index 4c9951be90..e6ef3d03aa 100644 --- a/source/guides/guides/launching-browsers.md +++ b/source/guides/guides/launching-browsers.md @@ -83,7 +83,7 @@ Or Microsoft Edge Canary (Chromium-based): cypress run --browser edge:canary ``` -{% url 'Having issues launching installed browsers? Read more about debugging browser launching' debugging#Launching-browsers %} +{% url 'Having issues launching installed browsers? Read more about troubleshooting browser launching' troubleshooting#Launching-browsers %} ## Firefox Browsers (beta) diff --git a/source/guides/references/configuration.md b/source/guides/references/configuration.md index 21046c40ea..f48fd6ce7e 100644 --- a/source/guides/references/configuration.md +++ b/source/guides/references/configuration.md @@ -102,6 +102,18 @@ Option | Default | Description ----- | ---- | ---- `nodeVersion` | `bundled` | If set to `system`, Cypress will try to find a Node executable on your path to use when executing your {% url plugins plugins-guide %}. Otherwise, Cypress will use the Node version bundled with Cypress. +The Node version printed in the Node.js Version panel is used in Cypress to: + +- Build files in the {% url "`integrationFolder`" configuration#Folders-Files %}. +- Build files in the {% url "`supportFolder`" configuration#Folders-Files %}. +- Execute code in the {% url "`pluginsFile`" configuration#Folders-Files %}. + +Cypress comes automatically bundled with a set Node version by default. + +You may want to use a different Node version if the code executing from the plugins file requires features present in a different Node version from the Node version bundled with Cypress. You can use the Node version detected on your system by setting the {% url "`nodeVersion`" configuration#Node-version %} configuration to `system`. + +{% imgTag /img/guides/test-runner-settings-nodejs-version.jpg "Node version in Settings in Test Runner" %} + # Overriding Options Cypress gives you the option to dynamically alter configuration values. This is helpful when running Cypress in multiple environments and on multiple developer machines. @@ -189,7 +201,14 @@ Cypress.config('pageLoadTimeout') // => 100000 # Resolved Configuration -When you open a Cypress project, clicking on the *Settings* tab will display the resolved configuration to you. This helps you to understand and see where different values came from. +When you open a Cypress project, clicking on the *Settings* tab will display the resolved configuration to you. This helps you to understand and see where different values came from. Each set value is highlighted to show where the value has been set via the following ways: + +- Default value +- The {% url "configuration file" configuration %} +- The {% url "Cypress environment file" environment-variables#Option-2-cypress-env-json %} +- System {% url "environment variables" environment-variables#Option-3-CYPRESS %} +- {% url "Command Line arguments" command-line %} +- {% url "Plugin file" configuration-api %} {% imgTag /img/guides/configuration/see-resolved-configuration.jpg "See resolved configuration" %} @@ -328,7 +347,7 @@ Run GC cleanup before every 3rd test during {% url "`cypress run`" command-line# ## Intelligent Code Completion -IntelliSense is available for Cypress while editing your configuration file. {% url "Learn how to set up Intelligent Code Completion." intelligent-code-completion %} +IntelliSense is available for Cypress while editing your configuration file. {% url "Learn how to set up Intelligent Code Completion." IDE-integration#Intelligent-Code-Completion %} {% history %} {% url "3.5.0" changelog %} | Added support for option `nodeVersion` diff --git a/source/guides/references/troubleshooting.md b/source/guides/references/troubleshooting.md new file mode 100644 index 0000000000..58b8bf0532 --- /dev/null +++ b/source/guides/references/troubleshooting.md @@ -0,0 +1,388 @@ +--- +title: Troubleshooting +--- + +There are times when you will encounter errors or unexpected behavior with Cypress itself. In this situation, we recommend checking these support resources **first**. + +# Support channels + +- Connect with our community in {% url "Gitter" https://gitter.im/cypress-io/cypress %} +- Search existing {% url "GitHub issues" https://github.com/cypress-io/cypress/issues %} +- Search this documentation (search is in the top right) 😉 +- Search {% url "Stack Overflow" https://stackoverflow.com/questions/tagged/cypress %} for relevant answers +- If your organization signs up for one of our {% url "paid plans" https://www.cypress.io/pricing/ %}, you can get dedicated email support, which gives you one-on-one help from our team. +- If you still haven't found a solution, {% url "open an issue" https://github.com/cypress-io/cypress/issues/new %} *with a reproducible example*. + +# Isolate the Problem + +When debugging a failing test, follow these general principles to isolate the problem: + +- Look at the {% url "video recordings and screenshots" screenshots-and-videos %}. +- Split large spec files into smaller ones. +- Split long tests into smaller tests. +- Run the same test using {% url '`--browser chrome`' command-line#cypress-run-browser-lt-browser-name-or-path-gt %}. The problem might be isolated to the Electron browser. +- If isolated to the Electron browser. Run the same tests in both Electron and Chrome, then compare the screenshots/videos. Look for and isolate any differences in the Command Log. + +{% partial chromium_download %} + +# Clear Cypress cache + +If you're having an issue during installation of Cypress, try removing the contents of the Cypress cache. + +This will clear out all installed versions of Cypress that may be cached on your machine. + +```shell +cypress cache clear +``` + +After running this command, you will need to run `cypress install` before running Cypress again. + +```shell +npm install cypress --save-dev +``` + +# Launching browsers + +Cypress attempts to {% url 'automatically find installed Chrome versions for you' launching-browsers %}. However, probing for browsers across different environments can be error-prone. If Cypress cannot find a browser but you know you have it installed, there are ways to ensure that Cypress can "see" it. + +{% note info Using the `--browser` command line argument %} +You can also supply the `--browser` command line argument to launch a browser from a known filesystem path to bypass browser auto detection. {% url "See 'Launching Browsers' for more information" launching-browsers#Launching-by-a-path % } %} +{% endnote %} + +You can see the full list of found browsers and their properties within the {% url "resolved configuration" configuration#Resolved-Configuration %} in the **Settings** tab of the Test Runner. + +Another way to log what is found by Cypress is to run Cypress with the {% urlHash "DEBUG environment variable" Print-DEBUG-logs %} set to `cypress:launcher`. This will print information about the found browsers and their properties to the terminal. + +## Mac + +On Mac, Cypress attempts to find installed browsers by their bundle identifier. If this does not succeed, it will fall back to the Linux browser detection method. + +Browser Name | Expected Bundle Identifier | Expected Executable +--- | --- | --- +`chrome` | `com.google.Chrome` | `Contents/MacOS/Google Chrome` +`chromium` | `org.chromium.Chromium` | `Contents/MacOS/Chromium` +`chrome:canary` | `com.google.Chrome.canary` | `Contents/MacOS/Google Chrome Canary` + +For the current list, see {% url 'packages/launcher' https://github.com/cypress-io/cypress/blob/develop/packages/launcher/lib/darwin/index.ts %} files. + +## Linux + +On Linux, Cypress scans your `PATH` for a number of different binary names. If the browser you are trying to use does not exist under one of the expected binary names, Cypress will not be able to find it. + +Browser Name | Expected Binary Name(s) +--- | --- +`chrome` | `google-chrome`, `chrome`, or `google-chrome-stable` +`chromium` | `chromium-browser` or `chromium` +`chrome:canary` | `google-chrome-canary` + +These binary names should work for most Linux distributions. If your distribution packages browsers under a different binary name, you can add a symlink using the expected binary name so that Cypress can detect it. + +For example, if your distribution packages Google Chrome as `chrome`, you could add a symlink to `google-chrome` like this: + +```shell +sudo ln `which chrome` /usr/local/bin/google-chrome +``` + +## Windows + +On Windows, Cypress scans the following locations to try to find each browser: + +Browser Name | Expected Path +--- | --- +`chrome` | `C:/Program Files (x86)/Google/Chrome/Application/chrome.exe` +`chromium` | `C:/Program Files (x86)/Google/chrome-win32/chrome.exe` +`chrome:canary` | `%APPDATA%/../Local/Google/Chrome SxS/Application/chrome.exe` + +For the current list, see {% url 'packages/launcher' https://github.com/cypress-io/cypress/blob/develop/packages/launcher/lib/windows/index.ts %} files. + +To make a browser installed at a different path be auto-detected, create a symbolic link using `mklink` in the location that Cypress expects to find your browser. + +{% url 'Read more about creating symbolic links on Windows' https://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/ %} + +# Chrome extension whitelisting + +Cypress utilizes a Chrome extension within the Test Runner in order to run properly. If you or your company whitelist specific Chrome extensions, this may cause problems with running Cypress. You will want to ask your administrator to whitelist the Cypress extension ID below: + +```sh +caljajdfkjjjdehjdoimjkkakekklcck +``` + +# Clear App Data + +Cypress maintains some local application data in order to save user preferences and more quickly start up. Sometimes this data can become corrupted. You may fix an issue you have by clearing this app data. + +## To clear App Data + +1. Open Cypress via `cypress open` +2. Go to `File` -> `View App Data` +3. This will take you to the directory in your file system where your App Data is stored. If you cannot open Cypress, search your file system for a directory named `cy` whose content should look something like this: + + ```text + 📂 production + 📄 all.log + 📁 browsers + 📁 bundles + 📄 cache + 📁 projects + 📁 proxy + 📄 state.json + ``` +4. Delete everything in the `cy` folder +5. Close Cypress and open it up again + +# Print DEBUG logs + +Cypress is built using the {% url 'debug' https://github.com/visionmedia/debug %} module. That means you can receive helpful debugging output by running Cypress with this turned on. **Note:** you will see a LOT of messages when running with `DEBUG=...` setting. + +**On Mac or Linux:** + +```shell +DEBUG=cypress:* cypress run +``` + +**On Windows:** + +```shell +set DEBUG=cypress:* +cypress run +``` + +Read more {% url 'about the CLI options here' command-line#Debugging-commands %} and {% url "Good Logging" https://glebbahmutov.com/blog/good-logging/ %} blog post. + +## Detailed Logs + +There are several levels of `DEBUG` messages + +```shell +# prints very few top-level messages +DEBUG=cypress:server ... +# prints ALL messages from server package +DEBUG=cypress:server* ... +# prints messages only from config parsing +DEBUG=cypress:server:config ... +``` + +This allows you to isolate the problem a little better + +## Debug logs in the browser + +If the problem is seen during `cypress open` you can print debug logs in the browser too. Open the browser's Developer Tools and set a `localStorage` property: + +```javascript +localStorage.debug = 'cypress*' + +// to disable debug messages +delete localStorage.debug +``` + +Reload the browser and see debug messages within the Developer Tools console. You will only see the "cypress:driver" package logs that run in the browser, as you can see below. + +{% imgTag /img/api/debug/debug-driver.jpg "Debug logs in browser" %} + +# Log memory and CPU usage + +You can tell Cypress to log out a summary of the memory and CPU usage of itself and any subprocesses at a regular interval by enabling the `cypress:server:util:process_profiler` debug stream, like so: + +**On Mac or Linux:** + +```shell +DEBUG=cypress:server:util:process_profiler cypress run +``` + +**On Windows:** + +```shell +set DEBUG=cypress:server:util:process_profiler +cypress run +``` + +In the resulting output, processes are grouped by their name. + +{% imgTag /img/guides/troubleshooting-cypress-process-profiler-cli.jpg "Process printout of Cypress in CLI" %} + +By default, process information is collected and summarized is printed once every 10 seconds. You can override this interval by setting the `CYPRESS_PROCESS_PROFILER_INTERVAL` environment variable to the desired interval in milliseconds. + +You can also obtain more detailed per-process information by enabling the verbose `cypress-verbose:server:util:process_profiler` debug stream. + +# Additional information + +## Write command log to the terminal + +You can include the plugin [cypress-failed-log](https://github.com/bahmutov/cypress-failed-log) in your tests. This plugin writes the list of Cypress commands to the terminal as well as a JSON file if a test fails. + +{% imgTag /img/api/debug/failed-log.png "cypress-failed-log terminal output" %} + +# Hacking on Cypress + +If you want to dive into Cypress and edit the code yourself, you can do that. The Cypress code is open source and licensed under an {% url "MIT license" https://github.com/cypress-io/cypress/blob/develop/LICENSE %}. There are a few tips on getting started that we've outlined below. + +## Contribute + +If you'd like to contribute directly to the Cypress code, we'd love to have your help! Please check out our {% url "contributing guide" https://github.com/cypress-io/cypress/blob/develop/CONTRIBUTING.md %} to learn about the many ways you can contribute. + +## Run the Cypress app by itself + +Cypress comes with an npm CLI module that parses the arguments, starts the Xvfb server (if necessary), and then opens the Test Runner application built on top of {% url "Electron" https://electronjs.org/ %}. + +Some common situations on why you would want to run the Cypress app by itself are to: + +- debug Cypress not starting or hanging +- debug problems related to the way CLI arguments are parsed by the npm CLI module + +Here is how you can launch Cypress application directly without the npm CLI module. First, find where the binary is installed using the {% url "`cypress cache path`" command-line#cypress-cache-path %} command. + +For example, on a Linux machine: + +```shell +npx cypress cache path +/root/.cache/Cypress +``` + +Second, try a smoke test that verifies that the application has all its required dependencies present on the host machine: + +```shell +/root/.cache/Cypress/3.3.1/Cypress/Cypress --smoke-test --ping=101 +101 +``` + +If there is a missing dependency, the application should print an error message. You can see the Electron verbose log messages by setting an {% url "environment variable ELECTRON_ENABLE_LOGGING" https://electronjs.org/docs/api/environment-variables %}: + +```shell +ELECTRON_ENABLE_LOGGING=true DISPLAY=10.130.4.201:0 /root/.cache/Cypress/3.3.1/Cypress/Cypress --smoke-test --ping=101 +[809:0617/151243.281369:ERROR:bus.cc(395)] Failed to connect to the bus: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory +101 +``` + +If the smoke test fails to execute, check if a shared library is missing (a common problem on Linux machines without all of the Cypress dependencies present). + +```shell +ldd /home/person/.cache/Cypress/3.3.1/Cypress/Cypress + linux-vdso.so.1 (0x00007ffe9eda0000) + libnode.so => /home/person/.cache/Cypress/3.3.1/Cypress/libnode.so (0x00007fecb43c8000) + libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fecb41ab000) + libgtk-3.so.0 => not found + libgdk-3.so.0 => not found + ... +``` + +**Tip:** use {% url "Cypress Docker image" docker %} or install dependencies by copying them from one of our official Docker images. + +**Note:** verbose Electron logging might show warnings that still allow Cypress to work normally. For example, the Cypress Test Runner opens normally despite the scary output below: + +```shell +ELECTRON_ENABLE_LOGGING=true DISPLAY=10.130.4.201:0 /root/.cache/Cypress/3.3.1/Cypress/Cypress +[475:0617/150421.326986:ERROR:bus.cc(395)] Failed to connect to the bus: Failed to connect to socket /var/run/dbus/system_bus_socket: No such file or directory +[475:0617/150425.061526:ERROR:bus.cc(395)] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix") +[475:0617/150425.079819:ERROR:bus.cc(395)] Failed to connect to the bus: Could not parse server address: Unknown address type (examples of valid types are "tcp" and on UNIX "unix") +[475:0617/150425.371013:INFO:CONSOLE(73292)] "%cDownload the React DevTools for a better development experience: https://fb.me/react-devtools +You might need to use a local HTTP server (instead of file://): https://fb.me/react-devtools-faq", source: file:///root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/desktop-gui/dist/app.js (73292) +``` + +You can also see verbose Cypress logs when running the Test Runner binary + +```shell +DEBUG=cypress* DISPLAY=10.130.4.201:0 /root/.cache/Cypress/3.3.1/Cypress/Cypress --smoke-test --ping=101 +cypress:ts Running without ts-node hook in environment "production" +0ms +cypress:server:cypress starting cypress with argv [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress', '--smoke-test', '--ping=101' ] +0ms +cypress:server:args argv array: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress', '--smoke-test', '--ping=101' ] +0ms +cypress:server:args argv parsed: { _: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress' ], smokeTest: true, ping: 101, cwd: '/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server' } +7ms +cypress:server:args options { _: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress' ], smokeTest: true, ping: 101, cwd: '/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server', config: {} } +2ms +cypress:server:args argv options: { _: [ '/root/.cache/Cypress/3.3.1/Cypress/Cypress' ], smokeTest: true, ping: 101, cwd: '/root/.cache/Cypress/3.3.1/Cypress/resources/app/packages/server', config: {}, pong: 101 } +1ms +cypress:server:appdata path: /root/.config/Cypress/cy/production +0ms +cypress:server:cypress starting in mode smokeTest +356ms +101 +cypress:server:cypress about to exit with code 0 +4ms +``` + +If the smoke test does not show a specific error yet fails, try printing the Electron crash stack to maybe pinpoint the problem better: + +```shell +ELECTRON_ENABLE_STACK_DUMPING=1 npx cypress verify +... +Received signal 11 SEGV_MAPERR ffffffb27e8955bb +#0 0x55c6389f83d9 (/root/.cache/Cypress/3.8.2/Cypress/Cypress+0x35d13d8) +r8: 0000000000000000 r9: 00007ffcf0387c80 r10: 00007ffcf0387bd8 r11: 000000000000000e +r12: 00007ffcf0387d2c r13: 00007f3ea737b720 r14: ffffffb27e89558b r15: 00007f3ea8974200 +di: 0000000000000000 si: 0000000000000020 bp: 0000000000000000 bx: 0000004f2f375580 +dx: 0000000000000001 ax: 0000000000000030 cx: 0000000000000001 sp: 00007ffcf0387d00 +ip: 00007f3ea89582dd efl: 0000000000010246 cgf: 002b000000000033 erf: 0000000000000005 +trp: 000000000000000e msk: 0000000000000000 cr2: ffffffb27e8955bb +[end of stack trace] +Calling _exit(1). Core file will not be generated. +``` + +## Patch Cypress + +Cypress comes with an npm CLI module that parses the arguments, starts the Xvfb server (if necessary), and then opens the Test Runner application built on top of {% url "Electron" https://electronjs.org/ %}. + +If you're encountering a bug in the current version of Cypress, you can implementing a temporary fix by patching Cypress in your own project. Here is an example of how to do this. + +1. Install {% url "patch-package" https://github.com/ds300/patch-package %}. +2. Add a patch step to your CI configuration after installing your npm packages. + + ```yaml + - run: npm ci + - run: npx patch-package + ``` + + Alternatively, you can apply the patch during a post-install phase. In your `package.json`, for example, you could add the following: + + ```json + { + "scripts": { + "postinstall": "patch-package" + } + } + ``` + +3. Edit the line causing the problem *in your local node_modules folder* within `node_modules/cypress`. +4. Run the `npx patch-package cypress` command. This command will create a new file `patches/cypress+3.4.1.patch`. + + ```shell + npx patch-package cypress + patch-package 6.1.2 + • Creating temporary folder + • Installing cypress@3.4.1 with npm + • Diffing your files with clean files + ✔ Created file patches/cypress+3.4.1.patch + ``` + +5. Commit the new `patches` folder to git. + +{% note info %} +If you find a patch for an error, please add a comment explaining your workaround to the relevant Cypress GitHub issue. It will help us release an official fix faster. +{% endnote %} + +## Edit the installed Cypress code + +The installed Test Runner comes with the fully transpiled, unobfuscated JavaScript source code that you can hack on. You might want to directly modify the installed Test Runner code to: + +- investigate a hard to recreate bug that happens on your machine +- change the run-time behavior of Cypress before opening a pull request +- have fun 🎉 + +First, print where the binary is installed using the {% url "`cypress cache path`" command-line#cypress-cache-path %} command. + +For example, on a Mac: + +```shell +npx cypress cache path +/Users/jane/Library/Caches/Cypress +``` + +Second, open the source code at the following path in any code editor. Make sure to substitute `3.3.1` for the desired version of the Test Runner you want to edit. + +```text +/Users/jane/Library/Caches/Cypress/3.3.1/Cypress.app/Contents/Resources/app/packages/ +``` + +You can change anything in the JavaScript code: + +{% imgTag /img/guides/source-code.png "Source code of the Test Runner in a text editor" %} + +When finished, if necessary, remove the edited Test Runner version and reinstall the Cypress official version to get back to the official released code. + +```shell +rm -rf /Users/jane/Library/Caches/Cypress/3.3.1 +npm install cypress@3.3.1 +``` diff --git a/source/guides/tooling/intelligent-code-completion.md b/source/guides/tooling/IDE-integration.md similarity index 87% rename from source/guides/tooling/intelligent-code-completion.md rename to source/guides/tooling/IDE-integration.md index 1bb29f29d7..048012c120 100644 --- a/source/guides/tooling/intelligent-code-completion.md +++ b/source/guides/tooling/IDE-integration.md @@ -1,32 +1,34 @@ --- -title: Intelligent Code Completion +title: IDE Integration --- -# Writing Tests +# Intelligent Code Completion -## Features +## Writing Tests + +### Features IntelliSense is available for Cypress. It offers intelligent code suggestions directly in your IDE while writing tests. A typical IntelliSense popup shows command definition, a code example and a link to the full documentation page. -### Autocomplete while typing Cypress commands +#### Autocomplete while typing Cypress commands {% video local /img/snippets/intellisense-cypress-assertion-matchers.mp4 %} -### Signature help when writing and hovering on Cypress commands +#### Signature help when writing and hovering on Cypress commands {% video local /img/snippets/intellisense-method-signature-examples.mp4 %} -### Autocomplete while typing assertion chains, including only showing DOM assertions if testing on a DOM element. +#### Autocomplete while typing assertion chains, including only showing DOM assertions if testing on a DOM element. {% video local /img/snippets/intellisense-assertion-chainers.mp4 %} -## Set up in your Dev Environment +### Set up in your Dev Environment This document assumes you have {% url "installed Cypress" installing-cypress %}. Cypress comes with TypeScript {% url "type declarations" https://github.com/cypress-io/cypress/tree/develop/cli/types %} included. Modern text editors can use these type declarations to show IntelliSense inside spec files. -### Triple slash directives +#### Triple slash directives The simplest way to see IntelliSense when typing a Cypress command or assertion is to add a {% url "triple-slash directive" "http://www.typescriptlang.org/docs/handbook/triple-slash-directives.html" %} to the head of your JavaScript or TypeScript testing file. This will turn the IntelliSense on a per file basis. Copy the comment line below and paste it into your spec file. @@ -50,7 +52,7 @@ See the {% url `cypress-example-todomvc` https://github.com/cypress-io/cypress-e If the triple slash directive does not work, please refer to your code editor in {% url "TypeScript's Editor Support doc" https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support %} and follow the instructions for your IDE to get {% url "TypeScript support" typescript-support %} and intelligent code completion configured in your developer environment first. TypeScript support is built in for {% url "Visual Studio Code" https://code.visualstudio.com/ %}, {% url "Visual Studio" https://www.visualstudio.com/ %}, and {% url "WebStorm" https://www.jetbrains.com/webstorm/ %} - all other editors require extra setup. -### Reference type declarations via `jsconfig` +#### Reference type declarations via `jsconfig` Instead of adding triple slash directives to each JavaScript spec file, some IDEs (like VS Code) understand a common `jsconfig.json` file in the root of the project. In that file, you can include the Cypress module and your test folders. @@ -65,7 +67,7 @@ Instead of adding triple slash directives to each JavaScript spec file, some IDE The Intelligent Code Completion should now show help for `cy` commands inside regular JavaScript spec files. -### Reference type declarations via `tsconfig` +#### Reference type declarations via `tsconfig` Adding a {% url "`tsconfig.json`" http://www.typescriptlang.org/docs/handbook/tsconfig-json.html %} inside your {% url "`cypress` folder" writing-and-organizing-tests#Folder-Structure %} with the following configuration should get intelligent code completion working. @@ -84,21 +86,21 @@ Adding a {% url "`tsconfig.json`" http://www.typescriptlang.org/docs/handbook/ts } ``` -# Configuration +## Configuration -## Features: +### Features: When editing the {% url "configuration file (`cypress.json` by default)" configuration %}, you can use our {% url "json schema file" https://on.cypress.io/cypress.schema.json %} to get intelligent tooltips in your IDE for each configuration property. -### Property help when writing and hovering on configuration keys +#### Property help when writing and hovering on configuration keys {% video local /img/snippets/intellisense-cypress-config-tooltips.mp4 %} -### Properties list with intelligent defaults +#### Properties list with intelligent defaults {% video local /img/snippets/intellisense-config-defaults.mp4 %} -## Set up in your Dev Environment: +### Set up in your Dev Environment: Intelligent code completion using JSON schemas is supported by default in {% url "Visual Studio Code" https://code.visualstudio.com/ %} and {% url "Visual Studio" https://www.visualstudio.com/ %}. All other editors will require extra configuration or plugins for JSON schema support. @@ -125,4 +127,4 @@ Or you can directly add a `$schema` key to your Cypress configuration file, whic # See also -- {% url 'Adding custom properties to the global `window` with the right TypeScript type' https://github.com/bahmutov/test-todomvc-using-app-actions#intellisense %} +- {% url 'Adding custom properties to the global `window` with the right TypeScript type' https://github.com/bahmutov/test-todomvc-using-app-actions#intellisense %} \ No newline at end of file diff --git a/source/guides/tooling/typescript-support.md b/source/guides/tooling/typescript-support.md index 675efe6f17..80108d77a5 100644 --- a/source/guides/tooling/typescript-support.md +++ b/source/guides/tooling/typescript-support.md @@ -16,7 +16,7 @@ Just as you would when writing TypeScript files in your project, you will have t ## Set up your dev environment -Please refer to your code editor in {% url "TypeScript's Editor Support doc" https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support %} and follow the instructions for your IDE to get TypeScript support and {% url "intelligent code completion" intelligent-code-completion %} configured in your developer environment before continuing. TypeScript support is built in for {% url "Visual Studio Code" https://code.visualstudio.com/ %}, {% url "Visual Studio" https://www.visualstudio.com/ %}, and {% url "WebStorm" https://www.jetbrains.com/webstorm/ %} - all other editors require extra setup. +Please refer to your code editor in {% url "TypeScript's Editor Support doc" https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support %} and follow the instructions for your IDE to get TypeScript support and {% url "intelligent code completion" IDE-integration#Intelligent-Code-Completion %} configured in your developer environment before continuing. TypeScript support is built in for {% url "Visual Studio Code" https://code.visualstudio.com/ %}, {% url "Visual Studio" https://www.visualstudio.com/ %}, and {% url "WebStorm" https://www.jetbrains.com/webstorm/ %} - all other editors require extra setup. ## Configure tsconfig.json diff --git a/source/ja/faq/questions/using-cypress-faq.md b/source/ja/faq/questions/using-cypress-faq.md index cd96b046db..195462b750 100644 --- a/source/ja/faq/questions/using-cypress-faq.md +++ b/source/ja/faq/questions/using-cypress-faq.md @@ -141,7 +141,7 @@ We have seen many different iterations of this question. The answers can be vari **_How do I know if my page is done loading?_** -When you load your application using `cy.visit()`, Cypress will wait for the `load` event to fire. It is really this easy. The {% url '`cy.visit()`' visit#Usage %} command loads a remote page and does not resolve until all of the external resources complete their loading phase. Because we expect your applications to observe differing load times, this command's default timeout is set to 60000ms. If you visit an invalid url or a {% url 'second unique domain' web-security#One-Superdomain-per-Test %}, Cypress will log a verbose yet friendly error message. +When you load your application using `cy.visit()`, Cypress will wait for the `load` event to fire. It is really this easy. The {% url '`cy.visit()`' visit#Usage %} command loads a remote page and does not resolve until all of the external resources complete their loading phase. Because we expect your applications to observe differing load times, this command's default timeout is set to 60000ms. If you visit an invalid url or a {% url 'second unique domain' web-security#Same-superdomain-per-test %}, Cypress will log a verbose yet friendly error message. **_In CI, how do I make sure my server has started?_** diff --git a/source/ru/guides/overview/why-cypress.md b/source/ru/guides/overview/why-cypress.md index cfec3f1aff..1d28ffbdf4 100644 --- a/source/ru/guides/overview/why-cypress.md +++ b/source/ru/guides/overview/why-cypress.md @@ -43,7 +43,7 @@ Cypress может протестировать всё, что запускае # Экосистема Cypress -Cypress состоит из свободного, {% url "опенсорсного" https://github.com/cypress-io/cypress %}, {% url "устанавливаемого локально" installing-cypress %} приложения для запуска тестов (тест-раннера) **и** сервиса Dashboard для {% url 'записи ваших тестов' dashboard-service %}. +Cypress состоит из свободного, {% url "опенсорсного" https://github.com/cypress-io/cypress %}, {% url "устанавливаемого локально" installing-cypress %} приложения для запуска тестов (тест-раннера) **и** сервиса Dashboard для {% url 'записи ваших тестов' dashboard-introduction %}. - ***Сначала:*** Cypress позволяет просто настроить окружение и начать писать тесты каждый день во время локальной разработки вашего приложения. *TDD в лучшем виде!* - ***Далее:*** Создать набор тест-кейсов и {% url "интегрировать Cypress" continuous-integration %} с вашим CI-провайдером, а наш {% url 'сервис Dashboard' dashboard-introduction %} может записывать запуски ваших тестов. Вам никогда не придётся беспокоиться о том *Почему этот тест упал?* diff --git a/source/zh-cn/guides/dashboard/projects.md b/source/zh-cn/guides/dashboard/projects.md index efc09f917c..1fbc42dc55 100644 --- a/source/zh-cn/guides/dashboard/projects.md +++ b/source/zh-cn/guides/dashboard/projects.md @@ -73,7 +73,7 @@ Cypress uses your {% urlHash "`projectId`" 项目ID %} and {% urlHash "Record Ke export CYPRESS_PROJECT_ID={projectId} ``` -## 录制秘钥 {% fa fa-key %} +## 录制秘钥 Cypress使用你的`projectId`和*Record Key*,结合起来唯一标识你的项目。 diff --git a/source/zh-cn/guides/getting-started/writing-your-first-test.md b/source/zh-cn/guides/getting-started/writing-your-first-test.md index 2e20cb63e7..de0f80c5ff 100644 --- a/source/zh-cn/guides/getting-started/writing-your-first-test.md +++ b/source/zh-cn/guides/getting-started/writing-your-first-test.md @@ -219,7 +219,7 @@ describe('My First Test', function() { {% video local /img/snippets/first-test-click-30fps.mp4 %} {% note info %} -{% fa fa-magic %} 想在你的规格文件里面查看智能代码补全只需要添加一个单条注释哦. 阅读{% url '智能代码补全' intelligent-code-completion#Triple-slash-directives %}了解更多. +{% fa fa-magic %} 想在你的规格文件里面查看智能代码补全只需要添加一个单条注释哦. 阅读{% url '智能代码补全' IDE-integration#Triple-slash-directives %}了解更多. {% endnote %} ## {% fa fa-check-square-o %} 步骤4: 写断言 @@ -498,7 +498,7 @@ describe('My First Test', function() { # 下一步 - 开始{% url '测试你的app' testing-your-app %}. -- 为Cypress命令和断言设立{% url '智能代码补全' intelligent-code-completion %}. +- 为Cypress命令和断言设立{% url '智能代码补全' IDE-integration %}. - 搜索Cypress的文档说明书来更快的发现你需要的东西. {% imgTag /img/guides/search-box.png "Use the search box to find relevant documentation" %} diff --git a/source/zh-cn/guides/guides/command-line.md b/source/zh-cn/guides/guides/command-line.md index 694fea5c96..bbfc63f639 100644 --- a/source/zh-cn/guides/guides/command-line.md +++ b/source/zh-cn/guides/guides/command-line.md @@ -112,7 +112,7 @@ cypress run --browser /usr/bin/chromium 目前,仅支持Chrome家族的浏览器。 -{% url "有浏览器检测问题?看看调试指南吧!" debugging#Launching-browsers %} +{% url "有浏览器检测问题?看看调试指南吧!" troubleshooting#Launching-browsers %} ### `cypress run --ci-build-id ` @@ -323,7 +323,7 @@ cypress open --browser /usr/bin/chromium 当前,只有Chrome家族的浏览器是支持的。 -{% url "对使用浏览器有疑问?请阅读调试指南" debugging#Launching-browsers %}。 +{% url "对使用浏览器有疑问?请阅读调试指南" troubleshooting#Launching-browsers %}。 ### `cypress open --config ` diff --git a/source/zh-cn/guides/guides/launching-browsers.md b/source/zh-cn/guides/guides/launching-browsers.md index ecffb0832f..98387c5e79 100644 --- a/source/zh-cn/guides/guides/launching-browsers.md +++ b/source/zh-cn/guides/guides/launching-browsers.md @@ -65,7 +65,7 @@ cypress run --browser chromium cypress run --browser canary ``` -{% url '启动已安装的浏览器出现问题?请阅读关于调试浏览器启动的详细信息' debugging#Launching-browsers %} +{% url '启动已安装的浏览器出现问题?请阅读关于调试浏览器启动的详细信息' troubleshooting#Launching-browsers %} ## 通过路径启动 diff --git a/source/zh-cn/guides/references/configuration.md b/source/zh-cn/guides/references/configuration.md index ef0116635f..d13cafcda2 100644 --- a/source/zh-cn/guides/references/configuration.md +++ b/source/zh-cn/guides/references/configuration.md @@ -256,4 +256,4 @@ Cypress在网络级别修改这些脚本,因此搜索这些模式的响应流 ## 智能代码补全 -Cypress在编辑你的`cypress.json`文件时可以使用智能提示。{% url "了解如何设置智能代码补全。" intelligent-code-completion %} +Cypress在编辑你的`cypress.json`文件时可以使用智能提示。{% url "了解如何设置智能代码补全。" IDE-integration %} diff --git a/source/zh-cn/guides/tooling/typescript-support.md b/source/zh-cn/guides/tooling/typescript-support.md index 0a5e53a6ee..0d3fb2e515 100644 --- a/source/zh-cn/guides/tooling/typescript-support.md +++ b/source/zh-cn/guides/tooling/typescript-support.md @@ -16,7 +16,7 @@ Cypress使用{% url "TypeScript" https://www.typescriptlang.org/ %}作为{% url ## Set up your dev environment -Please refer to your code editor in {% url "TypeScript's Editor Support doc" https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support %} and follow the instructions for your IDE to get TypeScript support and {% url "intelligent code completion" intelligent-code-completion %} configured in your developer environment before continuing. TypeScript support is built in for {% url "Visual Studio Code" https://code.visualstudio.com/ %}, {% url "Visual Studio" https://www.visualstudio.com/ %}, and {% url "WebStorm" https://www.jetbrains.com/webstorm/ %} - all other editors require extra setup. +Please refer to your code editor in {% url "TypeScript's Editor Support doc" https://github.com/Microsoft/TypeScript/wiki/TypeScript-Editor-Support %} and follow the instructions for your IDE to get TypeScript support and {% url "intelligent code completion" IDE-integration %} configured in your developer environment before continuing. TypeScript support is built in for {% url "Visual Studio Code" https://code.visualstudio.com/ %}, {% url "Visual Studio" https://www.visualstudio.com/ %}, and {% url "WebStorm" https://www.jetbrains.com/webstorm/ %} - all other editors require extra setup. ## Configure tsconfig.json diff --git a/themes/cypress/languages/en.yml b/themes/cypress/languages/en.yml index ae05bd3340..26682a51e2 100644 --- a/themes/cypress/languages/en.yml +++ b/themes/cypress/languages/en.yml @@ -62,11 +62,12 @@ sidebar: assertions: Assertions best-practices: Best Practices trade-offs: Trade-offs + troubleshooting: Troubleshooting changelog: Changelog migration-guide: Migration Guide roadmap: Roadmap tooling: Tooling - intelligent-code-completion: Intelligent Code Completion + IDE-integration: IDE Integration plugins-guide: Plugins reporters: Reporters typescript-support: TypeScript diff --git a/themes/cypress/languages/ja.yml b/themes/cypress/languages/ja.yml index a1b64b25a0..4a0a603f88 100644 --- a/themes/cypress/languages/ja.yml +++ b/themes/cypress/languages/ja.yml @@ -62,11 +62,12 @@ sidebar: assertions: アサーション best-practices: ベストプラクティス trade-offs: トレードオフ + troubleshooting: Troubleshooting changelog: 変更履歴 migration-guide: Migration Guide roadmap: ロードマップ tooling: ツール - intelligent-code-completion: コード自動補完 + IDE-integration: IDE Integration plugins-guide: プラグイン reporters: レポーター typescript-support: TypeScript diff --git a/themes/cypress/languages/pt-br.yml b/themes/cypress/languages/pt-br.yml index c56d034473..f529d11af2 100644 --- a/themes/cypress/languages/pt-br.yml +++ b/themes/cypress/languages/pt-br.yml @@ -62,11 +62,12 @@ sidebar: assertions: Asserções best-practices: Boas Práticas trade-offs: Trade-offs + troubleshooting: Troubleshooting changelog: Changelog migration-guide: Migration Guide roadmap: Roteiro tooling: Ferramentas - intelligent-code-completion: Conclusão Inteligente de Código + IDE-integration: IDE Integration plugins-guide: Plugins reporters: Reporters typescript-support: TypeScript diff --git a/themes/cypress/languages/ru.yml b/themes/cypress/languages/ru.yml index daf49be6b9..09b5862f5a 100644 --- a/themes/cypress/languages/ru.yml +++ b/themes/cypress/languages/ru.yml @@ -62,11 +62,12 @@ sidebar: assertions: Ассерты best-practices: Лучшие практики trade-offs: Компромиссы + troubleshooting: Troubleshooting changelog: Изменения в продукте migration-guide: Migration Guide roadmap: Карта проекта tooling: Утилиты - intelligent-code-completion: Интеллектуальное завершение кода + IDE-integration: IDE Integration plugins-guide: Плагины reporters: Репортеры typescript-support: TypeScript diff --git a/themes/cypress/languages/zh-cn.yml b/themes/cypress/languages/zh-cn.yml index 8db469fe9b..fc548a8f1f 100644 --- a/themes/cypress/languages/zh-cn.yml +++ b/themes/cypress/languages/zh-cn.yml @@ -64,11 +64,12 @@ sidebar: assertions: 断言 best-practices: 最佳实践 trade-offs: 取舍 + troubleshooting: Troubleshooting changelog: 更新日志 migration-guide: Migration Guide roadmap: 路线图 tooling: 工具 - intelligent-code-completion: 代码智能补全 + IDE-integration: IDE Integration plugins-guide: 插件 reporters: 报告生成器 typescript-support: TypeScript diff --git a/themes/cypress/source/img/guides/test-runner-settings-nodejs-version.jpg b/themes/cypress/source/img/guides/test-runner-settings-nodejs-version.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d170bfc2469022588ffcfed12647b9e49482bd0 GIT binary patch literal 70112 zcmeFZ1z22LmM~hl1d`xELkf3yNq|DC&?*Xdr*I7x5`qMWP-vk+3U{{zf&>p95-h<& zfCMKHB>Z)6_wAnP`TNbAJKg=}n|Js3Rqb>3*-Q6YTh>1NT))3w0o+mcN7w@ZU@$j; z5b)P@{S`n4^0jde0AK-dF~uqX!1W3aucMEThqQozn>W9et-G}yzm2=AfWMW8fDpf+ z06_M>zlW8Lvz-sKwVeaPO%Ax%(FJ5i*vbJ7#54spJ(TPm5o&>6cDjLDaGOA98!21h zeR*bCe`$YL4_7-MD`tOJ7dLNde>vc<$fYsYzZ44qnSZU~<17bM_=PI7p{5SAlDn53 zvlzcPpN){HB(sDRzmT}7polmxv#_9$lz^b5fRG5EppdknxU`rA^PdwCL(R+9UK$2c z`7}m>@d|?egXE7R`Rm5@^SZqySuymrbQh`cOQ3eM|Tg5%7g`(HLYwA zZod@#3ZSVe4R-VPv2wGq1B2v%7!>>ngsn74LQ+ChLQGghOi4vZNLfKrQBhGzQCUn_ zSqhU$iTwr(a<}nywR7|N4c7Lrup)mK_7_`l^}tXD*?A!z+S#gjxw|s|Dzh}=@AD$~ zck%rh*7oo7BJ_7*1u)DA{L-@jrlo%?!kEu5mw&Na%*|gc-_8wV?p_$XzTO4g{MA|k zw%r*2!Ma`mgadGKeo2^rTzp*2j{pxB7mt7tAD;jppOBc42$KkjiAjD*n151I5)!gs z66IeK7A_thApzknV&YqrH*enjOZorni|cLx86oy7oG&<7WB_b3EF3bd>ps9sjFV&G zVPRqY)&Fs^u<`H-a0rPorGH9)d4`3JgNu1~8vww=#>Vh-ivSlJ3mcaJ@TUi4NR-QnLr%Cz3b^EVjlU`JcNES-` z>v;eP4hDz}hYWBZ@Pn*Xa8W^WjSDv8B*uBrH!hTLK&HX}^^2St)6Y8JkUw42zQbvF zapDtn-fMXCZP@JO-VUjyjPxx7)vijhKdStpmp_aF<1PPxcM|FjY;t;IWDgk3A}l9O z62;D}X0xt)4H$VVn9%nUKjbg{;lKKVAnO_c+}zLmO0JNYq9Wbiba|6#dr^Csv+sbuKN}YqAtHj+a=;Nu?(ZOsQZ1jg)@Uv2NON_1NXH{IqqGr+xTEnw}kOrQ|2szg3vvhHx zxsN0(Q|66!hOp13q7}>B8&H<}G`=tnIzO-Gv}yYS{k+hkFLH8Y_sGRYvLai?GBV2B zzirKgYeHMdyilU(xf`iO!hP}P+MLaDJF>#7R4rQ84W0{B+-9^V&GQc6gd$Outu)ht zi(>yTVb$r1v#ttTQimi z|IH@BS!R&ZqfOe{H-bk`ErI+;nd?jv+6y4$${$5!0eBW_QmN+r(jrWzL7Ad)rh}Ud`YU?65wnh-OBu7qA1i8gIrUom!(fHE z1VweS6+oEA2n8=mT;rWOap8yGVr_NLf+(V8L8%5_S$cUultzgTz2zdLfQ&w2@UaS~ z0&Om#Dpy3D-N)Yd(CxY>{2Xn*6Xl|41C;pGhqsYb*;CJ%+U*Tm$a^lfJEp>`Y%OZiSC8k)bREltA)CLb zJ{kJSDDl)&UP&LzgH5RCCO0^|JS9lF@+)qAwA?+il%lMg;#z1#FC=QhwuXig%R}g4 ze{8^V?DHkGLY5I+ktKDKRt#Oa7~bRv6xp+hGOSd;`8^MsrxxK3zgq!&x8TdkH(=Do z=+2v^AQ>k@ZO4RHxO{_NZ=`!?d%CvJe74+lFjfl5qQ_M;Aj(bhu*G&X(jeo~Af+?< zAV5u>VZss9#;(-qHw8Mj?DbQz&7egU57(uAoB$#q9Wn^g?AczZMwiZ`zwtR8aN zNy(+HFYBUn~Q>c-TsFMRSqzE79IIR6!o|R7^>V z9WF5yEqwW&o$GhBs)Yt}#}u+fl!L=FFTDpSZAAvY7pM@guZ&$d^w<~rn)njS$(>NR zLehG&9N*bRv(6SptC;m$@+GSJ+x4lq?)4`c&x)Fu)F;h5#ns!Q zB$8RQTmz^YoM*C|PgOY@lNnXsuEe61)h6j}#+;`te*) zGMf^Wr(ajsmzm_v<=D{gX9!RAw%iwlmrebf0uEMWFF-1*w-1Ndi;#`h=7Zn(HF_5X z+PD3D2V9Nd0jD@VMD;+)fT@sV;@VviAAWNLcyT}NIUu1?u59uW@RGW{hL({r0I zvCxkZie&QhMWT0qfJr7CHYwI5jl3lC%%gyU1diXnERi&z@H6!RZC>!aEkORV^ zhb6b`QsR4d%9DK;Qe?J2R>G|2?Cw3A8Z|v)QpmlbVas_~HPzRtBv@B3^188a#mqfg zEF-m0-77C%$y)Rwatc`QPx+zToI|tO; z=<*iV`4c)cb3B-ylEwLX>P$-n{#}8b*;m9DiN;=iUW|B6hSVB9%XeFR(1#u5z zn9_PN<4?wgUzC(|+S8{dF1G<|z1#Rn$3d;FkS<1(jf8i-spHIOIxt6>^#ruOL*MRhFYgKFWFs0&so~W6}w98wSbC#5ukD96QhQq*YnkC8eH#J;5dHXN= zpRwm^9elR#lNT`5{aO)EVOmkVn!gxr28;GY_xO4ndK&BRCJTGA`wO%!?~$_)Sk;=Z zlDCq&3iX0u>$7CW<=n;nI%U=CmP7PSY*aYiakEP*N$iy_0_fqfo!%m|roov6zB))n zLB0NQX}m++w9^-zsm&7>)qq2>66z5Jn~+ctKG(b1GMC}j(m0dGcG7R!c<@Zq z=~%we6Q*)$@u_5+iJp}LCyZ+Gyw#C2t9ETPQDQsQyH1Q<1|G=yKoc=aQ~cw4&$P7{ z+0YlrJch+#Bf?th6-I)X6KR9n#Fs1R+UC+zWzm&6Z;^Yrvx5t_7e3Y>9+R~W(P^d~ zS*@NPkW2HdtxWzmM_K^AHYv}(tNFe8Q#PHt;;C)u`bc*Jt!Szx+G=T7HEWSvb@|e; zm}-moeg1TA8UI52=K?XOLU-Zmp~va%x@DkfcK;Se)r+A%uLzHti)f?fe5HmnPta0I zIkx^$-Ms7)x%dW&;BX=snF1bry44*up5jbyoJYcPK*twBo&S3HoVy_xdCtE;_e9aR zSU;Js_v@SV!zfR@H7;q-?~O(^aCbhX7E~7({4}G`6>2K5lfpixH(v5;UVmu8)&E2i?Sm5~v?nhLO8b@Ic8bxKK1f z3q-2O(sb7>j|15LDx*=!S4fk19c_c2LYd|)Q$``Drr>MI!na|)DzKqv0O54D!oJMZ zgI<~32qQPKI+a2l8om>_amQGw=g@Qm`OqD` zQZI6}j4mkI^$;YW;Q|+-vfppTWuk`v9_6Z8~RX zEW49wHlQ3K4dEhZm30&LoLWWBPlO}sSwyYY*zlruZYRWo>vvA~uKb&~^xIj$r3!7_ zNITU)TgMnB9t0tzt9n(4MSg#5Ccb>Q%=nV~Nu)mBfMMuKK>7OliJOK)5;rNgMtk6j zqEaFUr2`}-qH@Zgg9MaYcuT9$^isN^HR_axn-5%UkW4NoPQ2NqW2RCNJ?Ot77|z$r zif*hN^QR8$HotmieVqT%TQb`BfFBhgq_$Ey?-TjLlyt-%ZZ~Zfqvn>oDB?}wX~CAv z5fcbX7=G_sno7JtNsR7Ev+lND1Q}k!T6nmg%^14&iKYZJ{@{jDuM)QKXzhWw_Nz5ULzpd$9Q(Yf#{=o1a++_R)#YBra4 z#W-)=rpWUcO=;?YjQGRM+0d0&cV zoJJwQGu*(S*DMyFW{uqE7sWBkYF~F_7cG#|-ZXJ3&p|76$A56_UQsWTf%P9%>1}2 zWgs(4m}v({N6oNho3{HdfYjeOI&(XgN3?f@aC0%*ELgH zE-1aH6D#YOR6Im>U|1|hovlZ0ZcSYGg#Wgw?bU?0{_K#=sHBtCdz5;);$a}VLS0DkSu_7YczGkl-+NG73S0)jc>NOhqeeo(a zipWU=^x_`;eI-K)5%io@_$_ERrHY9g+$p>YV&%EBF~Iln0yc6}FQr@tZU<5iX1NCF z`o51fDkNEW$$vMu~H(P(j4yjj?cW_EzvODIw(=HtCnQ4 z9Q_)!%2=LIZSt&3yvlul{Y&MTDaTS*wGsL1n@32rcukRF zo|`;S$0TmnZL4ak3Z?l#Q@5U}bif)IsLnU)3JRDigv>0v(?3`C+`GWx%nGwLnJPO# zq#A>0SvREGvr^0ISmd|3irK(MRvB?AjjU;vMgER-{q(m0l1J_fB<$m>8k{vcbdZE} z6I1cL$Ko(CH^$fa=;kM_kILj2vXPeFuY^6VmO19UyGt5Wn=H$~Xx$9E;%q2WSip%m za&$GeZ4fzOHZ4P@lo@|Z;-~WX%Ki7OVRwOfKg~U(86#gz0LrSIF#Zffh7O0LP)N0L z2ExSWb+SHyI?d+7el-^PA4zwx?y(w@tHpMLuv@9wgQuq)KHj$lAeEot4ZV07D!)%` zt76)w&gDf-2QdBb4#)r;>w=GSV{LfwVZ0$&@pNi}5OCPHI97rmj;z&^*TUB6mOYv> z_X4F;A4kHSeK+CGp3eHouoR5X$p47p1!uz5!I}D|F<=y}&DZC|cD#bU3S0MG@Xcpi z*^DK`xVK9hr)P;l#h+^z*6rsP5k^tzDTDj+yZFpu@Qe-Pd~x(WF7>0lK=o*qaI_b- z8!u8d0WT(kHgu2yU6XpW1Cx^ZP?7*cdwnnkf_ouKiLlb}#0nW7njv5nQyx?1sNRXmPe1eVT ze*?bYBnwB1?4ig)%E-tpK_IhL0BccgciRo@?>9QJQss7cC4=Oy0WLV$-6O3I(dpjg zyPtkVh-mPzqDfniissTT^BmD=tB^Av{EzBT+JD<#DL zWs2*mwdxYT(ry|vZc5r6GRO7FL2MM+NJ^bZ-?5*1J9cqOu4GXndG`VTraun1+5wQ) zqxY^Q0Ez6yUhf-uFR}puvZfL7-spV5ZHNXnqR@ylZkFzmd0{Lih+cyA07c)ybo6Pr zAg{O8nwQN|_n#mKZrL!I0(61G8^cCH?;WvpA=(OQYzdNnLVF>WhMBboi76MwSgEXr zn0*Q+wr{812H4YIG0lxp^Ixaf|1M4yf_e1+P5LWCs*6HTwr<^GQ*l$|r(09=i3fd< zp*&o5C}c{Ibmh}sI2P-@1{m?=A_YG5FGKDtnchD^wrv5gvL%p-6LYt&Y^wv+x*SN? z3;#{U-T=-kQjcrEJIH2H?01hpzyv=0rjlFN051bMR*QybhcKEi6_KxM4T4228t@OH z=iDoMl~f-!X}-ShOnDsB8nlDwH?4dj=+1VxpqlCYwb}9H<5Bt{)&FrotU}iS)w4(E zBB=wWTG@ij{qmSdY%}S4NzE7M$e;CpmKJ(Ww{i`rOdSW)d|kl^_^kEG4x9Is@`WTu z!2IgF=R>B)Nsr(DBH$lTe`wI;ITa3IYMQGRf^yn9WTR-Cmz*GXYu|>K=oCRx! zZ5M_c94J(#Q&d*Vm6Zo>r_li2yAzNiEXzTR6SU`*WzP{)cHN=v+3$3mt#hX)MiP0u zJb65ZxJ33!31mtRV4GzI4hwZ>e$a0a0~I}RL#e{+6b%+#rvY)|epZLj2R>0pFEn(^ zBKV?Jdg^60q$4$n_XO_c>V7A|mDr_Y5#)d;>%?6eJ3BwL&Im3Mra*|<=@WOS_*;T1 zg#^h;PkpZ!gyDhx^G3<=*7<1H%4juX zjg(Z@ADHbO+B-LX)xP&*_Jho)y|g-8vxLIsR9uzWX-0`jjTE2;6>d+5k!Yq+7Od(I zAHQqOx9{xp%{d++rn$9>Weqf42VIsdUbEQ^7YI1uV7**U@BNNej8J>3m}Fi)w}_mP ztjn{PN(VXS7?o*T=7oI?*>5?E(WATg{&GMm-Pyo6+*bva`_(Takld6#ZS}653UaUz z2;~9LBiB`3CeoQ)i9NYZY|%yWUo1Y8*FZw8dNe z9EwttxJ8Ej4_88P^ys_~vqSsd@4j_VpEL<*>Wq`}zQ-*_)Bb=p1n?J|lNwulQz1TS zYL7g3CN~fET(84>H`BUMIE)!;LVjp9+iT& z1nY;;(>EF0TB~a0(22ytOqMz?G%ErdkGez)?M{Bc;lTwEgt1ua3Tn&!?$AMRUWV;s!6mE!oJBQ7OqR;3QgF z1PjZ$upkux3;Fbr;8OKx2;1*>%-Z#?Og(c~`bH_u@zdX14a6qaR-baJ)m zjG)t)j?q^5WHTMNX!3ngwr(igj;RXg$o|onBOd*J6s&sww*EFlRsHcp(&GUU^=eSU zcJ#pWWJu$ev1d=sP%#!1uH{YoqIbsG+I`x2XmA4?BTcL#gxHR(_-G|<5k|C#zN-*= zljIlmp}t!#;!{}?$fox2qIq5+BU%($QJnyNvKld?VlGPaHGFVGY6dwU<1Vhv$8MN} zrfr}NVtv4QqJ?7YaRPlAZAT|_xejD0#!mx<706RmGX@6_4?|v}CTw3F8&07f!@YZy zNTnkgTz&`|!|V~KYIt{Y@O5j1sCCKjCIr}uj+A=3<^>?YsG_UdJ3(nH6%&hbF=jQ; z*62f{)^@Me7bsB_8Tq+V)t0`r@Y*1bZp0f$iqeB^l7(53vKek|Xz8)-v2T|+2xK4Z z+L}&UHSN!two=2-wuIGaOcQ6))E;I=tjXP=nl!O}9Nib1#JGmpTGedg;#Qmrc;1+c zk7LiiDBOp%H@hUkBfX)O$~v;Z3(&z0_^6nC4Isaq#@bN32GG)+-Jj{!1Yixi?HGSj zrE*M1YYA7Y3v|Oxdu3rQs=nN)X38qREu+RS1n4s z4E9FsEFXJ^E;#E#H!wlS)EfHa)<7S?-gmTkooWl$%t&aFZ(yH2Y_a`m3HyQFUM}pw zn<>>R6X$#GS#7dRMwUH3K%%fgPh3R!@#)8`Ohnu-c z+TewXfjFb=GGNcN@}x)h`iI#NKc_R>dO;?k4|U6pk_aKx@wWOz*_6@q@-c~GleaVQ z1vaiSbPQ=*AmP+2U0$D%ua}f5(WWvbS)wyjg`$_uHmY{+Qnar3PCgymB!z|dX2R$7 z290k#xEcD3x8ZDRUy$mU&?s}W_`cU6g79YT)n3}SL{jUPB> z%a*o|9k>fu#KbcSXj>5whXIhsal=2vq@%vsDRu?XNXb0IX+40TxN9Eo&yz^Um8-v1 ztFVHGXztCA5GM97=lA))x0BT!#8K^ZZLgwx83<*A+b{VNpCk&+Ys^1o)201VLn}j7 zV8`h))d?OgQ{W-TlCB6aX$gKjrrgHUNI|?<<1=95YP-PSrVat8mVtpBk97MP&`Vf! zVa_^V#IFH3JMb85;2gVp+>*+R9^uho@~v^c8R^X)C>O|(ypcLi5G%A!>#171E8($X zm^so{VqvkI{&=K0tBb>Lq_nJwt7SojUHzk@9R34&GyqF!{k~(j6#yXR1Ngy|E*@rM zDj}M++W)+i%5Km;n)dThpRl8^ZSh1)EgRWt-Zl%xWMK+{#xw9*Yw3D4P z8#yWi3G7#1qYL^ZAN6VGRaP%g@cLA$vK?>hH06op(U3ZyY~wxGYL%Px>cF?l!K}$Z ztd}8xp$9*3eqy4$56DA)8&H0C?zt>pP^VJ5V6Y_A@K}!4O+=`HMK^#+H1{UW1vRLM zb6h29bE7pQeeKB=rPuyu|N06IgSXIq@Y!Wa18T%8f-c9?Jjp3>OeXP(W~@50=lS=a zQ1l$>EGpAf9q*a0svqatbjOh_%3~!`AUVN1{c|S^Z9+@BQP&UWEelnbmEZ;)v`2rr z=#*qbIjOoQr#Wk}G=lTFidipE82bG9K-v0guJ-K1*-xfBn^Yp+7B{kr%d9-*-_^AS zW6!jkdZGM{4?4s(vEG=q>1@U=eTT#{#oQM-oUJBbaQW-ZtBcsao~(OXa=RKdu{%mnOt5->7--?K<8q zdOW?$os((=en}?NQZ)Q!GFzdweyT;&35r&i{Sb$L_gNBRq?6azWLDZ}JZhw0KLS)Z z94#cIC6!#Imm6>d)ITC2MTpU7su5VOUKyh`>n$RbJvH7r9~Ml!c(p7wuLqt&xKT6C zh&u~og|2D>BM~r{63el`Ma?>ag2^4%ey&=p{K3z|G2Z@3yXL@QXFk?W5`uJmmNAs+ zE4R&Z^~#<~^{76`P~GI6j8YdmGcOUdH{@uy1zBx|)>TWfw^I8FhZVAZ4y4;ntZ-A9 zF6>2v)OTZ_8QYvAyiV4lk<-Z+agFJIw?F!;_eQ6YQqX-fH*?#}OexQ2*GMlCen$sR zBj1jT=91T2iAj9l9pWSScUCglQD4;)z8Yzwzl`T=$_|eRQ_qiZBManV!m=a;@#0z7 ziP&=dsf=V?leaZh;wJ4}8)<+rvria*A&h3XM|RKnmyW1#d=#XFz_PuPID}R!31cbt zaskAwRqUxrTpYux)NG$HbG}~^R%DHF+StStUF(*RlcO`^)l1ouLA2vLvgTaBTC=f{8{+RQ{M zCXTNmb&g8mU{4}rOoZ8pJSy>(VMyzxwXi-?4qvq>?&Wimpq#fFav>xS08R#^aT`wM zDhtu9+7{eqR&ibvh#47;gcXv3y0b)7FHy=6Mt+Tx` zWl@jEI1EfXB`#4RDO3a0uWe5)he9YPF~I|QRX#>%6_jT3(utM6D^%3(2WKWSs67)M z_;g_N$^UFr!zzAlp~QJ-GJAtQC`GjBT{>!vWzre&vF>f5V^fIx`%P%0aks=*@6vfbOZx9pGp^LNq!$d^ z;<1MKR|&rK%9S{e2c+W*-eLXA0RirHPp<)b40*eJmVzB`t^vz=L;!dCYe3*5R;*6< ztF8U#_y=95B|Q)5|G^JQ;%HFpB=LP@pXK#v>b`~~|I20n*K7L^ivJAb$L{zOR?0v7 z+kWN|$4v!_C=v1Wr{u9$7>69^ehM-AELmm!SkV{IvVX!+-c+0O;BI7@oL*Jla-O#O}7>OV7!_Wd)nJike7_GgJ9ze#NHo5byZmiYH0(fyyNl>cRI{D(OIBoCBj zUpQ`jV^k~x@-M+*Wldb6sl~ZvA`=+?>>LDYzi7>J$tUU?Y||JWQ2*q9bVpYhw&U;8ub{&v^f z2htw@a(;dz_;2_+#jsWRw`>uT7QG9FrFClGT{d`h^_<4-68){h5Pxsje7-5V0nAaebxA*4=3y6$Bp;r^^Z_ZL zP#Tlq`w)<8@~hry4fB6pJzGx38_Tat=?{mPwji#!12Z%t*TKGFN-?aP5PB7t&SD(S z$r(v{rMB|f^U;o&Hwe#EXWcyGjdz*J%tOiH+A_~hZuqJ#(WThuNQR_puc9CF1+sNK zHomzaQhvaukuSaY*-2=f|Axv@UABp%%GUae2CGnHpoicc2n~}nl^S)-f>l?w_B)!)#fR`eFSyJrU!#u{g8-33#eRXjBJa5^ZQ-0Ur?T@rrf z%1)>Mm81@ZAkFfxkUw!>@0)URZ@0&((L1X#=3aW7q zX3=6(xu|+EIAi#tPFAQ7@4LYr7IW`!oElT6Q3htjdOZuV0X&O9o^N$+Q1Tl>6#-e| zaWdUPO}jE8ATH2S3xC075PC!^>iLpl-eZUj#kbb*GFEfxxU6A^!WFtkz-fi2;#Elz z%004N6ojV8+=byKBwzY(*$Vx~AzC|RMu z9U*R0yOiBaz&w;fAMF$0WG9&kPiA{!z;FXV%l(AX%4FueLA2aXtHTq%C*6dfsPfpF z(esCkfJnL0TQ;slvc{qru(1BuMg$hHa6pQBga7NLm9reUy-JPb9b=IMUmNuE^t!Z0 z@+6v#h-J7zw2a#&E^z@XHQ!U^CHG$80*z+wReS#kHE86a)8__0Egulu9365R!8d}U zgs>vhmj`Y$3jWhQ1n++5_`%&wOSTX|qRf|y@6(&NZ@NEul5Vp-bo35;=hjxk&x*@+ zoDvKp;p0Q;9TysSpTtJqjuu;po~5*RBmhYeuA`pKaZyW4Xz&v1Fo{PznU7hd&iYLl zZH5jCJCK|OmH%RS+GG;#($|Xwz$ggoppZ~&-k<*j4tfu<5b933GkU~l2ode zy*c~gVbM4vLx`}d{ekdN8-i-*N;J^a#7T5_v}Ee;V+%-`c3f%kMYZg-N%QjvS~M<1 zRvR2r;BV%cPRx6QVL5t%x^tVMJvpoY*jEA)%-^ZW;};V**r@?CJoUh$>*{gNEK^u@ z<(JtXR$eoUFhFy;NveVT`)^3e+J4A1z-)1J60sJnPvO987GeIuKA!w|Ej|kq%(HjD zId#wwuPc@6+6_mgNFIwv(>mPi%V+;^PdO}?E8|ws&7M^%_PG_k4W~DuCr(LjFCpbn z9<2_7JF`?R_im`iH*TT(=xzvWGCac(0E`m(&zdrpL7WKNt(wsklJ*Gs1QVjdl;BZATBFkv5L_CkZ!oiC%< zif0P`J!}SFyqSUD(92@61u>(klBFSfXkd5&wptOnRCdLCxYd&DY<>=7Lr?iPhe1dP)ZP(sZFx27l!ulP3IuJGeFz z>BMQAqE-62Ux{=#3TazOnMY5-2awSDr@I5?&!hW&j}akh0BqU4f|>>G><3aWuYQ^( zR&b0P-l)7^Jbqqt^!#QvW(1?S&u+f=O^_z!H>M(l<5f!s?adT(s7*`fZMyC~Tk?Fh z7lkewlmA5Y;4>i#cI)&JSO)ZgGIeiD$kdSA3#9e~B;H)-&# zqe%~{0bpH*Gf5ENp#ppGF>_;)S zA>coaW@ucZg1Q>J&9SK!Kho&anZ$6FIL?Lntp;PQQvp2C-Rzg_Xc(I zN9~~K{%;Kiydv{1oGpB%amO6UGHVJUrqJZ)2#t&8 z9z_oHi}bc*v%&VzFt>`p@s#w03aI+ZZMQzC?9)$r*A!5BC=%I+2bCN>4wZ)Iy2P*-)FW z(2=B=zYf`9{ulHZfZsPA!%B=)ES%o<<(|2tDWqRX&jHVv_jst#uh9H<|DugNK=&)4 zN--8(K3FnRrsM?A)JQ;S`p$fY2S`yaA24p%87F_cL&7)N>x_Sr(zj5*6rqn|q%ST4 zJI438j59nd=$?st;%oSv#OQsK*nxPwFZzq%H+8pUc9aSlWT%$YnbXce+S`|wKd(-F1HxoP4MHH`1H5*MHH} zwkRFu@M1Ti(;{Xe7GRcuSfp=>86^5Fyh)pa$NufmhvRKh@1d_WPhmO4=eaPj(`O!H17=Z8@tM`aP`qQF5JrF-zbSO}EYR`I`s?*4=e~Dc&`czj*t7<+lwS&W^T6jt6 zl{{%Ctg^2GxEq4L6$jnaTb-&lF|R|gmyn%Du=|=d2a0?Jxj)+C(~$hUfp8xf+$D&t z$HtRMgh$5|&DfjhW!j~hBNw^F7KDm*@ir~=Rp5VwBCWu~&y#Z7K=e0NUH zFI^I6DDHa8XBRWV=FK+-G@EEMX*xWRm2!nx&7Sk0OXu}d`D?VxxRDl7TqIf<5D2+W z4ia>(k0wiEo=kAJ#Ah1s);2@tu-1av6og+_;gbld?geh(y%jOdlvI2`x>% z#~+G?Od2p2;lHn|*<}#e8!Nh1U!yEghC3_!*gO(fv_2G5HL+5 zk^7Y656iMNh32@X2!%HQ#Zmg}^Kt$5Td+G5d*9@m;kPgXpmc3lneJvis8TH>A(b`M*ZZBbqoDMa+ry z!$W2l8ztMkjNY9RInQv4&Wmwvdy6?Yp}uv_L{a*gm^e^#vF4~(C#$h6TY{&H@a-OP zR=x9o(zl@E*`%5C&|urw7!+nC8>Up*hEt7s-wj^p{CtJO|eiZ6>9`SKjjmgsEN(PgVu!#=-_ zzvrmr6h^1Ocj=8H@6>o?{)JF%gs#ig6G(7d(wnS=`5jTa-O&RM`k3hhdfrMc2Prh} z1>P#k@ohXnN?H=nq_{W9p}~5(g2!|&ka0)6=AK}O+z z3jR=_vF2>+M{pBo{Rgk7o}ftGS7oKLJBoY;QL9|GDgodVzGgUN$~MuGU=rUyS8o3w zZl(Vb;eRK7|0}jP4_f%n^&t61#Z#+&6|*U+Gn>Lww=YwfYgv44jZ!1)Erl)rBiVm= z$^X7Jh0r(2lowG$#w0(;?M+L*0y-Y$9yaTh;{1{Qp@KiG;O{sB77v^35E-riz_5x% zd+W-s>sY$k&lm9}z z>R<#`YInB*j{GMQy_=tkO*O|JrnOMVJeu38_p9Pd<`U9CuCS&lqa<@9I229+c7pO+ zU-0p9$S@kHfFR5Jt(-NieKW>Hhe_v_leqdCr!~cm;Z0>AOaO1_)b6E5E0=iV(4g{b zlaGwj*q$b_8gO?8SpC}bsE+dPxZ~R-j34@6-8B;9A8aju(+?&|DHB?IlPm;XI3L$+(^4?d{b6a$CAr;%i@iA{2T;26uHV~$tN*%_+(ieibn`0_`si;5T z&e51)VV{iAIzh==dg1Zd@>)fT_Ua=SS%S)nz&~@1oqc5wCvp zf@8c9VeAU$@oD6aWbiYV1d+{g_2ctP`(O)}`yM$>YXkNldUl1TTH{I(H7Z|6BEsGE zZqIchKF4B1PON# zdjQKv8BENyddq^8SikIM;s0$Z;P*u`NpHl6R_yBWQOVq_zLeUB6+X@wk_ayz*Wwgo z9rw=`rP=fH3W@A-a=$%HzLUOTu0E3Xft``@IG=rrWbicMQ#gwEB6^pGKli~Fv%GEP zyjV;Pm1JSShce(QX`Xn5bW9Gb?j1eO7&rk*8}wd%cgF~81_{UK?VVsivyY<4f} z7m(T`(p;Y~n_w*XP@`YI$Q5B$CE4r88v`sF@uC=OpBz#r?thmyoDv2}F&dn(H~YjO z)l##Q8)gNk5^wOFx=*B(YEWe2+o+BZ~j3nQ1O0{{FN!qA?qEE_CDpe{( z4`V`(Mw&>>bb6OAfeYC~d(}uzN;mfUV$VsOpKWHT6{|LJrk3~1NANY)vA<|pXC1pG zmcu%NBGqzB9N3q&Mo1tMBf5av^Tuu!Bf}QHB%g#$TBfv(>4le;fyWzpnf)l)&XmS2yj3PAR(EO zIUC)tev`#d*}8#lH&V~7i>``ueZVvd3T10~?>LBj{aHjye=s@y0m(Qy$;N?9cuD|% zaAtd|R#D^K*QTYnsa~ZpGk1#3Xfzvo&gm*1X||hK?I2ClDdFYLDg&xkLkTtH+Q$bl7Eu-Smh26N z2kvR4l>@h2GD)+eRe4LFXT^6xEn8A1?TwLfp53G4xTk~!BRA}KRq<#2kT3FZbv+(l z16I66zAcC9nO?lgRPGq-IyepL{P9TRll<$_*Tr*NQ)RyFQ2rdbWG7QqDe4h4ng=MW zPAWLjoZYhCj3aICZc9$;cPkxW3ezgiEQn~n2N)lV$;M{5=9ZofUYA1&lMwHhpwozmAxN)q4+NKK594?pPJ zWJsbC3LhO^p;<2E>|w9jISFVkeHY|91$=B)A`r@8P}D_?c2y{+q^9tL0SCBEH|+{| zycU4Iysvg|2#+O53x6KKn&XTbVbZ8;yEGbKic_9*#(XjhKB_UQB_wvbHXkIRU+KiU z@V(G^@S#&F-!B(BYMwf;G3EeF`(fw0(JzxVeJH^OF>N$X)F1*jA=ZQC6A*A@)oI% zl#rdabw($+J@S21`{p3trs#O*vh$ATn{03I08MQR&~VvLCbQQr%6Z&54#16~{@epK zk2&%@X`opESAdh4ctl$&d*wWlQaTOB>avsL?1s*cGPXYQdX;YNh`zJ1f8RH1)A%?^ zFxH=6j<9;3F-bS5Hd!r!bF8w3#)1e7XWfdois z(u<&gv;+u-(5oV$8X!nl5mAuP384g#nnI{jLlcqSr6X180s?|4DC+&?dEW1x^}e%a zt$F62XV#jT^__pNoaCH+?VRhJeVwv@zpYH^Nth(KPsE6mA3dju6ue(hcF62?Ml9;csMj{5RbbAvyuc(chs0ry=JeV4szh9td(lA&V$Lv?1S{oGWT|dS zB0ezn9~#1BT+BgGmnxYJV5hWx@T%ANWN9-={p(0|mGRbmMbOrCTe4rgk{0>_YUoif zGiY$q5vXYK+8hrVZpVrP?tNMzhD`j z_kI0;+f*KAde1jdOu-LrLrTOU*Ey(79ZxYMJJ^(j)MLm!+At})-xfgM9nz=1Ece%BiDHp@NlmRUZ zF$}VSU!J`Io+>)cG8%*22!^|MDhQxgg^?O+oR+>^fvuh(I(@B9j`Ee{ml}iVxz09-xSBFQd1$)btUI9 z@BmhC2&LGnCAFM4>)I;b( z^_DMQEVwPrJFiUCfHks7ItJ_G<%hCRcmcJVT(r4}qn67RBY&oD#ra}OY3}f&#`%E? zI)ViDPY^i(At2#=0MSo(*S)*SvAjV4bOl&;yHR`$JSjZp#M^BaS1*+hZXpl9-aa@y$#qP7AZ)i|Khp5I4@{o-=U~fZ#r^CX_H8a&Q)w(#k!Ih>z0jzY zXP!B@hNJ@Ksh8P>(6-%@lb$&Hp8fi*YHz{Z5GUD~HMijyjS!4A-!hrLH#sLQ`6p8S zw?xh$YrsB-Jk#z&WR~B=Y*D-K*F&J#vodIErDpQ#)14Y~rBiD_D(mzNXu8V*7=hRBFefOB`mpJ@qbG4(sq%bF7 zDQU$i+4%WH?4p|kIvbK{G(OEIX=wV${QL2lM@e>D8s_^qUeic@)en-5VN%s;zz3Y2 zNQEvS8NkU2qtx+dTM(BqgoJlzx&r3BtBQjzdmCbSg#x=`JJBlz2`QaYCa6>?+9Zw; z8_%Vr#9EU}+VC}|5nqQD;muGbWAo9%ta@-cE{NCJ7+!rhs29NY>QNqUc|b)AKQy$k zaJ=(jJG-~Dri_fp1wjG?FPMI2@d6R}Z>DRQJj8^a0A3wbj{*XaJk#O9KOVE)tAc$R ztJprPE{71aD6BRM(x=|77bYmybEKwH&gPQb+#Cs-$ano24lsn$K~uxMWWKoAxbVqO zlW`NEWIJ+C$*X9OTLH7TwxBI*CgSbC3-fN=KiT*)fX>H_uhSka;67@a{_Ew(O>Opriq^7lxJ`dl5*3!X2*BEI%L z(sC#s*H=Ai`{_S;%h%S0@+!Z949MkUDB9iwFcpmaw=Qy6Yn`0hxi-^tZXYsyjJ{ z2V*q-X?J8)5K|Oa6u+U@3pv#R({AGak4?J3Ax371_SqsO#jed-031gzLK`R^_7(($MA1BNh0eMSXCbc~hi^RkqgjEp(M^u}76KijNQdn`Rw zFo-#bNbJcZO6y{=$j|(q*Dn9h?(%BMEtw(cEONk*utOhUna(Q(mulHkR6LHf{NHyd z#`FCKai$4P3gW#fbO|_HLf>GUQ7lVjA)X_Zro$mezI@%80x5ThjHMebieCGFNMK~` zi|66zxD3jRqP56B66>{f`j1Bqd~nrTCI3O8SV;L78X-U5h3mS>-&;OqmN3-u{YB@~ zh6#`S_kSZE@jdYJX~x_*mWGHrTj{LxPmSp4{^kz!NmXLnKKRP-bbN@N8+mgs@O%&@ zg&Epmpq;h|^#cW@7IvyUWK0Ipjm+g*G%T&Y{N1fyRcZEWDp91YS$CyoF&BZ*K)2@t zQyU`s*z&GiY0QMY@OGY=qL@Z^I&>fu?!GyL7_lrQxl0Pq^uOcKC!8#Sc#{r3(MMMM zRbHL{<+w6szZWb%{jF`>-BCdxU3SgTi^SW&Wri9b#CHPH@co)$bm8+)zK>8OsHhfn zCw1)pBIgA2r7bHSNX3NOPT%-OU4$HyyB*DzX}_ks-kt3HMq1@Udi=<|!5LvqbZ>$2 zt^SAPPH~rSLm22_-%9}voq+sPhE4|#lIP_MmZ}`~6^lo<^yJ+uGrLYvd3Rgq4- zUtM77+ws5Xm?zz@Gp(j`uoG)DI`Wi_;8N+WdYsU1O(j>%IyAX)&LezK;Zimdi9or=$!M2?EmdU)ShPQLf3Y*CXm*Cp={pxMf_z?0!C z?c$*rsFIE79R^$K&Ch4IE;E7?9Ws3;2R^z&3yNk-G-OY>#Ct7q3JTIEUUq=7*M1<6 zu@`}7gF{!lYL;`IB_=CMt!~6ysVh(h9mbcWwz12FTVE~4xjkcZSx0gFRSCnv!dv-I*ER2ID&oq;=cmx=A*C!+;Os9?eA*iL4!E$K^Ws0q|5y+Ln3*W^q;mG4t za`Hf*@J6=|*kYE_+#=Bsqo$}gB>h|k>s;eV-v#+r@0ph@52$B(uR2=V6Xt~NVto+R zRuT-)qh-_Od-{qL6@gw?1#*+b(Qy|v<#65Vc#!-DY=n%*@#i$}0hqBdvc>1hCH7Jt{$^N@x zzu7=yJL=hh6NouP{FB(ayWX{++O=`oytVdbH@k$jt0Ofi)o&bWr#eJQWyTx=)GSMR zWDW5!Bh|scF%BZ+elF0xv+<0H5TeDebi%Td3$YcS&@IO3OSWv}{b>)Gy6tNeH;;aV z+R(>WxQ9x%-qBbmcT=Vfij_+hJ|g6H^1fI00Ib~wl}p3lE4Kjs+Vr6a)F&t>R@|kQT#B~aK^i?x)!#u;2%8Y5do z)>fhe()`pks|-o=g8{l4qJ}?#l#PDBLWvp^c6_1uTbC}!7CT!Ph$=+{CS1KKRu+KwvEob2(K$)RObT7i4APu3(nt{-BKGvWH{q6Fg zSF7E!YrWaYzx7q2s)rP3)%!881unADiTM}DQB}TLB@9tf&GjOVz`(R2k%3A0zuM)i-mq~FXc%OJq3?I<*|43Z=Bf5gdZE*ihVhSIWQ4aAJ=ufYI(==&9hp0$;WoO`F5$5nI6P>avd0B~Ky ze8#WmR-0FB5V+L5Uf-}?m@yN}Qp?@<-!zf4h$Z8vM$5vA_Yw-7l}hy| z0EFsMsC_~jEvAb5?weEAm9it-%ceW7$QvJT^~|BNqc(;}Z9_p26N}N;>_7-Km1Y(= zkM72#2yAltIfE8k`7%Rp>Jx8O`}}6>8_Q0;x&yy^U7^_3q*QUCOqF?L?wT^T$((_H zF*NhRRCx<~MKJts{q0OcB$r6+K?%08qC)a&->6#{b{Z);dsQHL(=G5o`_v5WAg$f3 zFbQ`aDj&#>rIdj39GjqGm=RMQ@6>&hyv-cbarK@B&NIxGkn%9Mc}mnr7J|rks*8T>g1l?V-01ZajIlsN#%GSW@}FhSFav5RF72{ zE{JUp-V<`R(GD&PvZv;%D^!|Tm|EwhLJ_6W5?bHYJ~uvp6E_;lfyKJtQ30njo#RoT z@OQ|Jg9R14O?ZvyQm5-l0L+vgy1PGR&J;6*ff@EYgS_Z>5%o7E?k$Fxv*voiN3!ti zom9(WOzZPyuzm>vwuypz(5#RKo4)fX>&v&@y{W3Xi$no!J%;Jloq=M|H+iPJs{KL$ zaxijLYb)FQ$|8gYUbz@AbersuF>`7ELPSz`qLU-jhGFEdbgQc>2n#`X=y1oPEEAD1 zIrqqo@Wb?gepNcjCR#gZdOcq!aw^`gz1G{6fr`O&bbQ|cm&?;!7U z8`yFptSq?DyyV(x?Ur(wFV(TQdBS}~FkQqI>$`$%hBrjLwf7$+oXcbnoegoGYIZPj zU2@bobV^20#Z80alaii$46MZ<1(-jx0bpFlG74SQSA{>-d0oA79sMNQQ7bv{%kPu# zzk(MVE9(>-?9Dnf%(R7%9Zm9Xie=~*w=+4vKr~;4G|P^hv#&D_ep#r}SCd0|4Wfco zEWFtJd=*r(a>T@;YDw3LWpm<`inYljIhWD{Cz#w zNf*O(k@XTep=})P*i?N|U#*ZC2AEafaJBfy=n{q|2j2|&a;UQD*$ds6@_JkdiB=MN zDQYH=GDvzReu7LHmSBKI_o(?;`U(vdcY4(As|g2G2!D09r%{=Moy`+O?eKM5jpwNMN))ycK@F!^EdO|5Va5kHQGM#@^7;dzV+Xqb^HQN{vhqmFXen1 z;^KX{<(<327TSlh+}Oar>^c&W9$Z;2V2U?cy~0tMomi$@FZ&Zwe?4aES&&Jl#_=5H z0->!TPaMFRQFlTy@sgD&9uK|5b{tP#_#D6P7WN#rc4jrJYGJwfi(~WVx3eq=FAr zt@O#rU5E{e8|s}USDPgAq;pL;+U*NrX=LX5(u~qDO*)fg8s4uAQF0omawFBDrFfz4 z)N5}fn+oF0DO21jha`(LSQrntmO=aN*ub)ybjVegM=1OQo6o8s)psl4v$o%iN=w7h zh?nsy;Dwr)2%B(klp8VoFqK!`tNon8a>Y{F_a5p#Pq!3oYNhB_HM8CLJU;OP)Y8om ziI;rwieYnvX{NOGM%LudA!6V1w_}$w9m$tU%Humj=3yDe&6rVgEnJ zl@1MwsAsIGwbBVh6p4m5&Jn!V+aShB29mk?a)@ zr+p@`OH}*MzY@edkvkke9ra6;R|OcvvYM|>(DtJTAD|9<{k|av8a}r?osAR7 zJQ@SFidxsMiUhR*r*;q~P<)ZLW2u={eqc7qtVk>73J`?t?gAQ?GXo5(E<*z&mqL+YHkBE2ET}0K znd{jzr5eU1!WzDETqnx&yR9R~y$}#PFUT5ujX(bTTBe6x&>)FXWuR-o)Cj0#<{`8X z5`M>x3+2^Ff6D*SkRfZ%@qQVEJS}(O=}tJ+$KunzwKK)OW|~}lT?k{uu5V|e2JsO; z;MF(4+$p-smwoPcbeVbCsHkb0H}scn+Y7U&MkOtBj}-%BaE&E-Nk)Py9ID%MfHn9b zA6xRDX4q@Vd7jKl>Pr7zp5`*R5OVgSv1Cr}p^IMPS49a6H^?1qC^k$d$k0UT@X3Oo z0Qx&KsGaGB;YyiGm}QOT*^|KV))_B2cpvn#f5azj#SQ2&P%#&q+sPVuv3hVft(X7t z$%w7tM6$ySd246(pz-yH(%_X^sa`EI-yjin`RC7&hiY9XNjF8z@0ppEfuFebG_lTo z+QIqeFl$evwv@>if?>$@y*o-b<`uXE4G)s$f||?r=XNSoMAk2Jk?dji`{R{6)bO^9 zE~i#qN?TT6!<|82+*Ie8G`VG9O$={MR*ais%+PRm!7umWF#oRbM=lKK-}Ea`R|lnf zEB>N$z??i<@{@lz;&afo^FyI0V9RAr?B41ja=X=nI6*sL`n<&{g~NN2r+nBNI~-i~ zh5>FFmNh|L1=CoxCyep)$9u!wyG@%3kH`3tmy@)^duQrgil_SbLhs^wYSmX&GMqHc zCt9bzWvCjQ+7fP8k+#98Q|w|kngTEe0FNv&lCT34-4&mK$G=F|S3fTI_jgvAYKR^F z@cF%<__cO*bz{Er(F5CG-~Z%qqj(k!Z~pQ1%0!G)E;bHX*gIdG`>dFcvYRxIC+S#VI}NuixAk*ZSIfK9?*)U6Nk@ zQ&{POp3&%JRUElTdy2t1C%zAk zY!|x2hb=#xDpJ`Nn$4VYBGQb~oGP0;Hsyp2>IUrMqW6yD(d$4U-Wkj_P%IL0@$%ta zEj*I%UeJTb9$Qxi-=wbp(OOLw^3W>XmL@#fcoHLYQp|}^<|>4ftw@ftCXU8tIi`&h zuXu4<^BXG|sR1ItKy{~4&8>;Q=n@C{-#x1CQQzLIa%!PD)BF9((=Zgcr(q794BV;; z&5u?!v0sS~9=$icdTq^pO|arRuP*O5a&aTc31w&6cUVF5;gkCE+r1U%V))2?P^m*0YB<5-9n68OGv^ z%ct*Mwca7J?P**?m+sg;Qf?5_CtFnw*04B}`?0_BV!OdY*13+9L2J3j<0P6-N`zuE zj_LI7(lMLGO4WO6-T9Qt0R}Y5Zz~?{FVUWpl@nI<@Mo-|1$T6z?Z?NX!vEYq`#W4v zw2B(Fjxs@7-Z|Ybyk)O5Avu&);JCNh)j+_o`*IbC(65f{--{eW$^Wd@tKW;Cv$MqP zDDIO62=%vafl(*-hk~f)(z8Q2vuxJXm5}N+`b`?jyD~G7w4398)HY$i++7Hw1ZFE; zV^Jn2Dda6T$?x;T-8Rb94G4+!aPt>?uwdBY>)Lob7^YM;=S*mYqW>F``IGL9y+ko>%;VoM4SzI`-*}5jI+S4F^ zA^h>6#8$Hny1NXfVd**OIR_3zsN^k6cw4(3q>+uTp5yo&QZ?|H^MX>^*)5(qRFH{- z`<8l~&-{dEEH0Pr(euj9&~vW?-UU}h%w-n212ZZbzzG`X=T$&|CQx-8*smOt68l^S z=2z}8QLH{5m8M%$EzF!q6E@9KGkOA+LDIpC!VNhHriUF}3yZEMd-wY8C|rKR=zIFM z>H9b9t*1A}UaD_YgNscytWMZKE00#Y@ofMA7MWh36NY_BcU`7L!M!~kukiX8zf7t0 zuEwedvP;k#$bYz!HqMY{@5uPfXnA+o)iFIp+PldD?otYTJvgizJ0RZf1t7|ECD3;B zw3!~aiyS%geUK{Y2;OKeFeZ%`-xN^}H~P9^y@RjetmPB{5T*!BhH7kk znl`McGVoH<2;R9NCoW^V&05B-&E}IIvuGEz(+c`9= zP;}CKs~NilmO=>X9sR2h6gaLNB`YAuz4zz_T~zN;pM5VIHZ@gj*r}Et;ha}f`xKYS ziQ;8}A*`Q7ljrEmKjiYohoH|)ukffA&ssqNjqj#rC5BOx#T|By9o7&Fe{`)1C$C#5 z(3Y-uXqjh+IVWzR){hs&t1<>Q?T23>=Vm|WD#7R0={?HRW0vDDnP^4Xu^!Q7v~k&> z!iU1&vG`P%gi&sP3Iad27Te}};w(Z7_Ss+5AnocekH+hrI(ratrx@#hk~@$CPWCX1OVE?MKd3{NY+y ze>^5%Hc|`0-=-G#C-cwADp+nQrOQ@~XKGAoZ3KuNV3@^Z=5*W}6FX1iK3C3V%2xZU z=#nubN+B@@!V9kECNH%8j zge)MeseD=OvuKPX+S}&alagAC1DjV2Qcu%g@oJ05tRldJ7OYRi@;-enyt(T;PoG>O*3oA(7)wC{j0-=AeG&=eY}20Lv|M$igehQIJgY zTRo!1K=yB=@cviOyp4knMX04mdJ#mR?vzetE|Wn$T5-UL)wXR_tm}EhL-kw|B}l~} z;n2xl<^|?ZFUQbAre9a;i;PZ)#;an>JAI^K-RtZQ(uu(0H3wM1XwA+03GMza6Sp=y zV`PYnELOjCvqad#MsFKCJlBSTXtr-2D`|m^i=_e%ozfsi6E-P`S31oFQiM=<_ zV9RqWJWg40gnqrFk0Z-DwtZsr9$OZEtLyjT^VHt?dfxJL5^Cq)KW`j};Ldu?Ly*6m zp}%sm$KnT1|I>iT1=&-LIp9|4VtiKSe6tk{fo86S7Jm;!UJJ|cRA;Q%#$ayy~!^$OlqLvTb|Fy4ZiuPFcEP8+ppk#a)`cs8wmM9R zSyN&+*$$m(@p8i|ndlQa{jUiYeu)9>s2JC7FJ{{_yn&$f zLU3=Y(?<@^1(h}%gfDU`xck$XDC7l4OF*t=rc(sMaK;3?+_;sKn7Ve;rmUL zZ=tG$@1@sD`$&Rn+?5F)&EBSqhiSNjw-b67ZqR9_Q<>JIhIQ4nok~0RM;`xtn9w5? zEy6NHg-_~xj}W}N-!0L{y)GyF&b`dP?d|O(Bln^#y3Gy|8K?Fa;<6POO%?JWmI zCWv-N^|Av&U=71tm3YBQ{0dpfE+b)(7AU>5jUl!8salhR@+qSY!Tc>Z6c?T-q3Kl$ zs#Fp2GSLq+_dBFW9bhD$bKpOE6uhFpas07+HC)AxN?yDqVfPK=gPTZ)-W{r#a0u!^ zn|7qPK{;{wJL9;7+fH9Nw_C3^6;Au4eU^^OH;WF)@w3F2O|THfw7L|tcG5W(cS2>o z^i0Q>K^jMqTY=sWt-D*;b3ao_Dv;QWrF_ZW$K!YTDyG(C!PZR01J0xD*Wda$<1JhL zBCfWZzL4oZ%zx%tElcdxRZt$2AnmX<;$&sD#c2Xv&YninqN9uZ);5?#Z@2Q_;7ofT zDDpJgZL4eVq#&?jZ$BhCK0hd5E|MSmhNX(La?x+@vZc2+HN3E>tSf?kAd`Q(2&V!T zCv0EJ-6aBl>q~>SXuXpmT2ZF7TZFU@Z;B<_-$rqHu~KT${%*2gQw)8qnc>oMFpK@j z+5K?Fh-HF`$ZVC|Qh674vH|G(Q$GY#4uP*L;jhyoyu5_~IS%>hHV*DmEQ&TG?9| zZ+4rUo%gp7I`>p6l|N%1UArd`KTDrN@b|43+sY4F;<2}z0>Y8EIpf1~OMQHcf(83I z6MLQ19AP4&o`5a-pdJ*bZy=D6Jof-4sLbuAxX& z-Hz;gEuAL6d)eu=E@Z@3-*YoOC|&1+YpwG=ASbmIZ^B9!{$+eDxV^f>`r+Y(_S|)* zjt$XTq#S=Eam83gYH<1P0E0`Re@u>GO#KZ(M=Y1+Q_FOVjJ22?RqokIV3RCS)sV=q zK9G?Htv-QtF;(k*l=WV!lkHPJEsy(I@BN^(Za%uN6#XKOL=22^dqsXAD+hGeNP8X@ zPm45Xbk=?0pb|6ltpiaxn51Q#TFTwG$f+Wm?XxJMU`RWzf@eGbDH`@UXi}#8X2jYU zZ{LD)$oSFn(Xwc6#269S$34~Q3xOsy?gUMNj;{swJ9P{gBry`sve=xhEL9G*CTi|r z1m2PdOb)2ZT}5rTNB4eQYxeyzmUiXR!lFli0b?#I`GJb(0(WV&ZctG(crxpIv;dp- z@Mp_fP^L3##vX``?Pqa57$WG~(%~cglfJf$d@PQTAVcfqcqko-jwE5jAo=j9TNrYy zxhM#hFubX|W^#_ac8{T1q z>^5yljwlUiRDS~s%yxEoU5y#6A}v&!vb-UqFjlN{QQ9Z^a)ku)4GTF~FJihO7uEOa zsfoTOVPjQNoXsq?)!vL*Mrm&}_r!}HNBlC-Vz8XXYap;0fOmQ!yLBL)YWKF*A>8BCJMkFi3?NZKpW&N^_ z&L{liaF8@ahfcvU*ExG05Lqx4@`t9Tzd!HI z2eyabcV|u>SBmDo#6_Fx%5$G)J#S?@F(1k@Vhvox!4| z`M}ae|BmL0MLF$`3Dr996<@wlP0`%62Si+b&CdJ~+u8D2MM5%{3|g$+TYE716voxM zOc*};)4X61a?fJaT5N~XlDPAmd2f8%2liy66USAnpXsnXOS@~}+UvR-W!#;a zpcg`euTA7dCtcI;#zDNaNUrzx;98-p83*d!kDDybJ66aie)6cSwLzJ{tbyRuS53)@ zX1!l$Q!Br0@#Jh|1{Vdduv*;N4y;&m&01qrZ;VrM)psCjBunI;_y2f&v3GU7+eRrU z^H*@ioABVx?(*4n3KO82h8V*Wu=S>%+UXnR1R8Q0M(pWBeBgWKu3Mvo_&j&gMtQp#Dw!1XO)Vz%F*FU!>vmOcVnCcSYMFe ze!X@;_G{apkVuCQ0xeXpNxZZ#pL**)Xk{B+K=H0RY~FvD&d>5zBc?La-6=4POP)(_p{ zUp)-H$GkEqL}qK~-AgQEwFYFMpj?z)Vik~G`RcHW2Sz=W(xJXbJAg=qTlqL z26K@SMNMkK?;H?P+BiR=9cO-)H?XX`{m0|T&95~4fL5x4!-&dZf~%{j))R&=>%9u; zTl_8~53=z2nbxlFs5U-u7M*AF2T)!y$bZm#tzO^__C=*j>?-Bd}#`bLXl*5ZBN zH4{>z5Ztm#e3!bI6_q_{nf2y*vU`bRuWTKank;B)ac@9*02 z7ON~LSrVp0Lx!+Mkr!`_CNDi0lfQk=(`aAgpH6S$$GJx)lk{^Orz7FOZMxm_zc;lx zztIIhkNBEL^M!N7jAhgqB7smXu9qyj{KwVsOUxqg|Dn}?Bo=-`LhMlNI|v7!WBJ2B zUF}#|>F9>u;oASR$p3cL(4bS$Lhl{__g`3tegsDTqYMY$>*_zQ|1+IYlDqYvpZ|HK z=YNl1P_qv*t+4fI$LN>SVtAhx$bL%xMhsV`3pDyU{#t-eQ~bA=b0VEE$Dg_?!$@`- zp2ps$Sm&JnlM3mv0*0cS)9If^>Bp|@K#x4>{ts(P`RCdp1E7=7P9OlH1ahgXE;0j0 zWCmP)1vNRF8gl+W{S*J@-s9D4wk?3a=t7s^_jWlr=q5kWHb__O*GiEB@t~iU%*hk( z)3_ry)ydfR*sn%vYO_kbmL+54%#?Fc>V;4zHXhe!l4QC16QAm#vGKU#H;V%1Fh@fE z_UfN@kzJSHnmhSEV05w3&8y|$Oa<>7RCnbqAh#w?b)(lLI;#JoDoj#=SJUK@z~*I-F7lY{ zjC;G8?nTEsYeAHs_LbnB8VD#fF&!}Jc~elV)hgoP4ufeaIt25Z=|^Kp@RaDhZ%3)6 zD9p0ofEQK>8}(9COvz^yG*|jT>;8-Ob`WVp_2bAp z_!SzfuITNOUq+3)ae**_X_vS(Z!L0eg>Ez)E!&IxX&HrdbFUK^ebx}r1Y zoyzIUsBnI5e+k1pb+6jFx=5p)&4OtN$ro6a{senliNTKfI3D+Axj1iTZ zrx+l=>V&67IB%+i|Vn^L= z?=UzOqH|&oORSxa9UCZcnfOXK0iOigzu!)fD|$U>VT_CN3HFWHkSK5T>P^x3jZ}%* zcJywo@>Y?nY}Q*waL16|p}Iszo|Cff8mk^EdRZTI%J8&~ebEVqwCcXuKIZ9$E-$j= zXl8l{!neo4HO_Zu(=0pObl-bm@l`Iq=r=vN1x9}fWss&<)bF-tD#o8 zeVN5)3?&E77)*5eN;n{SfwbYEn=;9sgD9KchSi#eTTItTrEuCg+ZBRf2i=5tu2Dk< zL`ZC|?(4E&d`&3Q)poKY%JQX?s(up$6~KQNg3atFARRmbn@OSk8|z~9S)>EeZ6WUp zu~8~M;&aspl~P$n!NU)qDz*8JYb1@)!z(FKdJjMi@vQ!URJt^$Rh4D8iG7yGtGAw> zv@HtAn?bV-W`$UcIG z8TRX;>rG}t8wu!l30E@Aa$@G$+s07(-^}X2C-e8-QD>R1EgAQwMYKNtD75@Yz0$1h zjx*QV_|=!17VC0WBH{<7N?8MhA}uQSRzuw#WbPqcr0n!$}jIYo_k298_)^78_r{xnd4@Maj0=}$JA2`9KeftSI-mE=H!!o_t)1alK z4vdqqc^Y93Th0bn0Stl;>4v5&9%de-I;+-0S#8|feKRehEs}P2D@e|WJ~UBr)jgdz zi1%Cp(;Meyr3tz0`fiwav_|Q2&F4Pq*>gb33%n;@<=QIj>R|;)Tv@*P%)QoY*yf3P z!%|k|j_t}R4t|*u3|o`2=3QlHRS{5L#CIn;)lxS8;Po6c>SCCpFcE=&-gF*PCAA0 zxM4HJzR>(}qWpC0hthh(ugh0TdQw%M*Zt%Vd};EK$_B(xn2KclX~bi*9$)sXssms9 zzt*P6UiY(*Jxq$3jOM~s?0Gy8NT{g_E7T%JGCLYp6P?jsoS&w|iWgPaj;uU`E(>h2 z5|0YaWU1LhX$W6YZ|E!dl~AUto6o6MtEP>Jt_xKUt;!@g;IvS{tK4%Ybu;0&N)D0`lmkg+;=9!nDCtSC7bx(#g-hmf`Y% z6AopH1N*bDNQP+B3Im>N^9j$OeK@;ehi8h)%L5Ghucgo3{ct%)*@rT3rN)3>pDcV= zd{b-PSiNhkzo@z6uwn`bn43pSrX!R1=<@G=Df&UOTTp70;#wV(7mP>+pWS}!tAw=+ z5QeW{QOy~SD6gPeK;Ebs9ka$phrodqVdzQ2c3nnNEsM;#ky@CQo|RUSyUZ7ESRrTxIz%Y1*%%Lv z?1rn$hdLaYFv;FnC70IT87j%uknae(4<%b-j4hn>oFQpl>5l+;jt?Uxj6YVu6+Yxc zs;Eq#^KZK7Y}XUfuztk zvf|0nL^(qdWXI*V@($f6Z1~JybY`0Ent;6ezvw1luh^sN@m%{kiL00f2!J*{r}>%R z`7bImY321^{V(}{^T+=y)X4uI3zG0}ZmEAk+~4ACrOD;El8tJ-UlWD)>eMJXB&r{4 zT;vjnHOe&09I9`qisQDMKz@})m90ec2F^YjbnreYGEBX>ajY#j`6P1_Ao;4FRqFqS?${q*SH4RBKBw<^_1~h{zaXSpZ6ftAI?i8f&%g7F zM$;<%9X4WGH3m)>S@A!}Ck3D4pVRRSJYGF}O>zCIl|~pn-E9VjUiSUaON?~a_Ks;m zh3Ni?X{BZ9G&FSonPFhx_x~4k{g;dUKk`7|W3K%-A>b7 zerZ7IY6N-kmKl^y+#O72w;vx*GO4H_UplmaDt`>6FxiLE89#`f^4PIbS8mqwx^F=i zV!kwTSH;>NTLjH>S4@jaC3Bz58Oz+)(m~&Uf6P@OYmDap!J;?np3Z^22;uh<=QX;S z>{zPv%2(R3Mbx`Ox3K9(>g^#f$I^%88_<5+)tBia23x%;U4qI!m5tj4^9|jyr7sPI z!K}@>_!^iJ+fj@KssIPE$E|!(+P@sg$kp}2y`7{6A%NzKh;nA?Tb#lYslq3W3D1JY z#SbnS8X6j4R(P+KFMb2d&IeglHX5DZ3bb|izjq^mFU&ioNN-k!)0i4l1OtmHwja>v z6@EBG&WPULf#13I4Nkpm9-O1yv<6em-A1lJI10l8Q!_wXXSz<49$wnZv7_1s%{YOv za|m@@%wddJOS`*~;EZYrA>^mWxjXC`My> zU#?g{^~T+8Q^{$@8C>d#E-{Nzq}wYKB30_O#8RR<{;tA2N_tqdtDv7cD+$=i%E|-L`)QC?=7nLgEDRsY0_((WM+{uUv1{Lt)Q0(Xjp(n zH`E+pE58&opUl4NR0DR7rsX{q3k)<`61f=2)t)ew**&}~LZ=XPLu_)sT*HunxT^uy zlA6ev((}6&U9bKWnOoFQg(gYTWB&TjmOM(XT4`%&PBE5d*G&Kb}lxtceVA9hi zBNLbC{&+uBg3A5TL5nn45}XF9*c@SB4(_(Jgu^(p8WQlnKT|?8V6&I5 zx~T(i6+yY7l_lk#GGJ$=T966xkPOYWiANIo%~=)Jx!ofFWqbC2QqW0oi$=tTi3rep z$ePkY6Z<#UZy5Ou+PgsU&1j%O2OV4RS1QqQvT;;QYo1-<24G6|^Q;-iOCSY^OE^$m zqu;S9>?>KAWLbq3a%`QG`QT+&TSZhhhM8VqW3ornS51{`ChDGIHi*}7)83Y)&(5~~ z5f2wf@YM{0_DAI8me_XTc*31QyK3? z&r>O4wKe9IE`T(9A%9+pI7t}5&cy*T!TOMtS)zy{;wc~nNqEKiBJG!U)dFWFD8%x_ zt$E@6mtr+~b^+H)@%ia@=ZtF!$&l4SOv>#{y;`4Y@IfhJu1MFHK@Qlk#i1x?8eJ^r z8032u_ne$5?Jk8;v4UKFoDL}+LhfWs^B8TLBjzm}keqyrHQNwmG31Wjo6zUHM$5mu zC29>ztS>|K%fi@eZOQ zTF;fJQEVPpml~%M5*qL;M^#0@v_ZIWHajSjtU30YXFDp_Vx|?PZ%CSi_P>xjb311L zqI3{TP#E68h;-9}T>6p)D5pRbzF?1mhRv9rUB)lRSbl0}>P3&1)n<{3GS>JNR_gA* zE1t4n(!<$t;;IyYP(2#B_VKfEsrJzm^ljpIM0_eoU3bNGyYREFK?-(W)7@2hM&9S?jdMu#c{1FaYfoVMEyoixqg4Tj`=dxzd)Zg(VibRq zTNSzBVl@BrG53)lT_Y3r!yF9B(Fie&$y?>;;lo_=QO$Ik?ZyRve0gg*km^C zQGr|^feq5AmvY7x;^bq;sSgw~0q z*Z-rv_l|0E+xCV73eu4(MNlC@LK8wqKlac_TO7DsS z(iK7z5R~4eih>1wv(I_&_nmK?Gw$B^+`Gs3j`8mN@r;bM=JU+;thMHR)?91O-vn=j z#CF#voX>+mTrgh4HXJd2)_fDNSM51bKC|OxNor-x547=*zOM(a)cfoqW?ra^n3;yE zBcxV^=oM-3-s5rJ?B>B8;J1mrC^d)ltOeCE?U~80q{}iyy`>LD6ewCYdq}An&Ik{; zP^g2b$!FPr*{Z0VoKt$`Iy(#o5-$$Q5XR=U zM_c{jYU=g(aJ?S}pD-M6oufG^3&(#Oa}F9>pYk>RXH=oo*?-_JEn#HMeOrQQZ!9L{ zAItxN)2rSmC>IR9n_PA7vE!o#8JLjg9g@c)^X{q9r#yfHBE z8^k{CO{D=KClcb<#hWYLJ(-E#us5 zi-BgAVjoYKWU||PWh^=%=#|a2E9YqPdN5G~xpF5CrirbV4Dq|GOfp-nc z`$4aSTDFT#kBC@r5>1jmaV+QNha||kv~KF>!g*G8c^0iNfZeFjaUyc7d^qN1{n&5N zyU)mRZnnm$WS9KToB4CtFB@x+=ju=BCPeI*NG-rd^VkH)HD2q$Wz7EAJ2e1=0%|MR z!Lw?5M^+syI%`%lX#kaIK?M3-Xgo!`{apw3@xiDf9$e9_NUrm%F|VKm1=)%4tPL(5 z9MGij8^rqY$3KB?SkQS_@uh+N&9SPwi^+IT7iLWQF|4AgWApU9!Tv zJl32F=|rjK!d_+;-VLeM@EXn7mx*Ltj{M~XwySZtMs02ZwkT6Vp4a%3N0lDV)UDvy?4y__=|%}C)q;HPW2cR5G4>pcCiQou=mP0C}_B6F05iXk*vStYg6 zHgDda?UE1we17a3%^LU@D!sg#Ju7_HI6j=_pvvR@Kfxn&N-I0G9p?|(m-GqMc1(x3R+|E7nI z97i;2Swb;xB(&i6>ju*#o%@;Or8k*ngjXN(7trm7*@QbCAy5~$r{w&abfvq58nY^3 zO&5n(U(J!`3zKQMa;~=$QuXz%h>(JtUa_%9p3Md)WAd&NVHoL}*ea_96H$nJ15H8W z?Rs}$rFNuUv!HI@o7RRvf?T5H^UxP)cbyg~R1)Nr&m_{r^gRL({h-$>>lHgZ?jwQG zaI$dSO=5qdM;guOfeTocaAz4euDbTKn-?O;ZoOQWuUra0tafZ%VJ+4UCNax5@_0{@ zUbkbLiA36Z!eBG1D-BDnwxZ+oo?uzUJBk!5dxbny_(Z_GUZjV?WRVbwpzFrz-gbML zuI2*-OJOL|xHqUbHRGL2tuTUI;RO*g^#ME))Z!3skP?pzmR&cfXpQO-*Bs<5O=)+& zsrI|d?_Ux8DQj&CBL)d90Sva($uh(|voChZ-}?gaea34um0l_J^z*2dSON!UTH>_I z(%TBGYe|YSx0b0OufDzjr)gic^Q=yHy|VvvF-gUzBN>9xEt0&?$&*1wrU@MT-m0wE zqv%Y|p75O{xily^5QXvvhouk#W^c?>7x)R}d8o=Fw0@&kKs8(es;DNm*5)B^$~-Nz z*iG`o(+*ZP&L(ShX30x}mey7ETL3pnCSqw|%OMq%<($rzdRe#sO{83V6FXGGn2G6o zxJ22cq;g{=QHy9cId}hwdM2(AtH&SAp5;#;I%ks~TPK)&ga53+h4{*Q&0*ez?D>kq z(pl(bmAX4{YzA%Mcg?=BU7k(D!CVPxq{ehCjD3bFEjzfVGY%B3-Weres>~UZ=Qq<} zBNyn;;Gib=l^u*E)qi5v1GWf=nTiX=1>%d2YN!N()_zKj%W+)1lZS_6Pqg`R;d$>e zJ$3JEW|%tOtjnf=g7!-o^gt*%sGti`Z?3s%+SPv{5#Y~^WCfadU0xlPL4ufDT?rhS zs{>A*BkT2FR)*@P@#lhHN?nbZP}p)Mun{H+U~QLZ9yG7h#W@e_jiiwG^ez~e7=aQc zZS1mUhIa~tk`}f1d3YhS(OdJMqF`UXxi7h=mox%=PzD(CH!KoF6w$8e7=xU3H`y?~ zy_Y;3lnK=y9|vQ&>l>oFH&;G1;1{wfSjIQiX!%M9pT_SNTA|#NREkWn8;CJ|?P=MW z)arFH)yGKL!AP?uZmo*~t$Bl^>)7=J^9FrnW@T%M*E}CtU-(S~-gWmwXo0Z((m8`4 zz}Fv%0{rz04}hY)uZ?f-vJzb80>3_B3C;3Zgj5EX>(`6fUn?C~(vQwY-+S%a!dM7e z&9YyoH%Pb}N0takT-AI!8n;0{Wm*l@>FH`+;}B!H#=te@NH~-QRW=okEWkXXYqR7C z6DL+O#t+X5Ht=9yHXfIrM2>A+S0g?&(HL=b4>rhw9WM2C?@r47VLsgP=!4}iw@h9qB zyndiMM9D~I-oUiYg#`KT0r?N#*io?Bz*5kfDMxV4@%~&Kw zO-q3F&tR|MJng!V#ZwOfZBZ;_{02$gLW>J2-`1^a+zFOhc-f=lrenoZXM3_fMYo>q#LFo*Ibq~>!hKM3rJzOQ((K3?8r@d zXKg%WH)jr2O`Q-Xw5;f4nAxLYp`&B?=liB%HDHtMqR8*zp8}|Fd{9HEADTO-7D}NR?m0ABc0<8|W@v zrCZ`v7*%jts`%c#Dgn5Q>tK2HIM`NEe$CKr{WHwDaZCPkmj5f9i9!)LDs)!(g)X)k zstTYWufw`Z#wCJ=D>G0dD7l!KAm)yCRCGE?_koyUT%n|h9)acxxY0%P5cTk^?_iCK zN%sA>UZa=1rX)QpmU%&iy#zkRkoKNz)+hq4&~!b{*Ya+#(FwbGqisWp%13CqzewT6 zhG@^_QxdO1>A-_(sJJm0u%RkwPuwHVgX6u8>jx7Tf8O>LzS8`NJ;~PiG@3h=Ln@lQ zoo20(pYsc_O*R6{t?tJWZ$%)-QZ7yv%2`@aM_ARBH!Qur( zVAV2jK6>5jGNo<=@IVhl7+u+#z5+uVxXqYp*Ec=}t&ykEd?pRJz#4%0HyZA@ZQJEp z40EkSSgFe09E-n2BUq9-$$}vXp5}Qyh1U0QktCZ- zz(0G%AUp@wb*?hzIo;+tpCslV$9Fe?XvU(0y6al<%7A_#h1eVWOc5W6$!+ECMT3G?b2x`zMiBlvq|f6D&*-s)0s$m56=J$M5+(PaaMmX)qb?_rg`1 zBTFeD+F!3*aqRv^*ZuYC<34JFt4@Sq)XGIB>wrImAf{|b zMk0DK?d)nWUl+p2qSc&4yejMLr7TPCjiSyri0X>v^TjEc(<;suY7# zcq0HzgMPoHIn(g`p2d3V_7qRBq{yj}_p#mD{MyrF?+g+N?PmM>Bi1;-$mqaLNs`S_ z?(qA$YQ1(&@ECq&V6Dh8KYyF{t5*Q-LfVZh4^u@|LLAnv{sM?Ry8$q%*)SzQmIG23 zr~SpWVil$$F|{wW1JC&-iUw(_cqp6?4pUct6~$Ix$9L5TEZI2b5{bYFjc99g0&{g} ztpyJU+ua=V3*dQ^X)oRx9iX+sQ(Lq z|9_7nX(&jr224Q!6WS-%EmF=7kKOIC>ppWv%JPbiS>F@UAmeOhgZqz{2(g_GTJ40Z zVl76ki#57Wu8W+{Jh(95tw4c!Xh@5P8C@=diiY2z)DiRWROo27>I@qvG{dU^PuHqsKzfuXAU8g~uO>;iZu-*+D!-o*6=zF95!KNP+KlZ&O zpB9d@CQL5*4alut?gsHOufGO$V-m25WJ*R~w%MKdiSZM{y;`&BSReMfAW#kuK{_0CC<%%!%4Jr0E6*>szQ78996$(lb5rYWzzC1Njz_zZKOEGz2UGqY`4Jv%f zYm~$+d)xx_=d-80e_s1R6Qil8vh)5Ybx$yRkYe@i{=M(d05$MO$^P?4T|39rT?IvH zp*x@fo4?(~%!9v|+udTI{^TvU3<8CHJH@R2RuQCZUfPS6p}*TVG9FlrCG{Ha4Zsj_ zbR&V8)&qwWAF7T3!7pLgo=T{&D^L9g`>nQz$BZl#K6B5GnkhCY`gL2}LEtaIF~$1U zUvtGplPLcPp~h5oS7 zDtS@T<~6bLbk)d(r38q1r-YIeb1@hoUZl)6-Rt6z59T2maat|}HNL9u76H-pI6@(j z0d6k?Vz2WF@3GI(DL^=>_>uO?EL@#mC2y;-vr`=Xzwz39h?4E$tzqP+fh{$WIP6Ny zH)}2phb-TIcEIngeJ6q!q?eq^h4(Tc?dI5gRvIM`W}vlOrJA4gWknLec}f+12S=UG zL2~~}NBps}Kjn0t!kW`Ybc9e~V~K>o_Igi2Mgl_s%I}#fuP)ButnY7^-+vT@GS;~l z+O%&YIt)KvwviF;0@I%=j92E`I`&XC)ZD?7k>j5V^6?LZYk3fP8}9qerhP+$QkNsv z&))pTf6sLHcoJz?I+HRs9meil&?|VqFoy1(0lXFCJ)VZ_g)3dS$edv@s@GDrrN8c3 zWhYZGo~*Uu(cL)nE+#?&h0w2CS2bupbqW@PNQX5FnbGT$)b3c=#yjh#UCvmf$c5LN z=2NfBEo)b18j}Rm=(4L{JTWw=N#k`xGkdf?dj8B(vkOv>yvEb%_dvWB*Bs)FZiG|7 zBZ~XRGW)gbH{ekexOr#fQKDai)SBm2VDxjEd`$Fcx>ELltPn7RCsyXO@O_-`FwUl| zm!O?%P*R*L6ed?j0dj0!##wv7ju}9UC<^KuwVeKl+o(qiyI8H8*_ct-Srk{6@4f5y zg)yA9iA%~E9+JQyj5RLS*|C!){pD9iw40_aY1_;M{wxEZj62(vlveg)bz~!pj8kU= zo(xlWj+BmnxolAPHk;>3vK6RvGs~YB9nXx?C{29Y#V#zN&EHVMTZ-%08^4d}_HToG zr9N8Ls5DK1#Ky+fsP9n6a>S|c?W+$C!cAa zDHCYm3UgxT&#_=|eyp0&mp9*Xg{E{O`mSO9g{Oj1tQJVqYv)F{KI<;N$u+^Qxt3wf zT!)b>54XzXq9F2t&Fs>UKIe-&oL`NC^+yeytU=x-*YS=G=Ft**^o4v{`IHO-hKp_sbg-R14L5+d~_ zXBu=d%IdSdEX8I#XKquh=&^4)OJkfKUuF-~2qLN$pEHN0lh5(O@gzO$>^xY7*|Cqg zapNh@ZRVWh{g=TZ{{4Q=uh0UlS1%n?Xz`T zz^SDP1(IAmaLy$Zz%n`diFi(-k|D!jBTXqyd7cpJ98^sL{7>dmpYP=ev&d0T(A zzH^~v@tZ8UV`o>mY=yY+T}B#GPSb?_IUu=k=Vt2J%504I)8jjCX=E-RMAe<|s7sAs z+%_~<32~qCH*M+&Bf1Y{e0%_}?D`4@&1p=X`_g-W^Q?iDt>2S%iA^TH4-DW}8<(8S(Dfa(8aQQHuQwr+3L!-Ptk~>1q|Jh$5W4c%w3jI6n7nimUOs( zK!o|ZE1z=Z8;VD@?f?l`kFBsXh3pSYMvsD;O7iN=QDReSpSOH`xqj>yHXD+otoT66UgnE5717)B>b+TSW<%mcaiyV9&*?f~ z8G_#0O^w#R$R|;#cvfL}Eg*MGfVsG!*#fk-ls&8l_rPfM-acI#OK$hpxOuUYjI@}{ zpYc1C`-n=bFHa;@w8h)sY9i}#HSqr60A>XR0W``dB&I4D??0yH-dT+j%ZVxEv?w&R z$_k>#G^M9L1qnKJzj@Uiu3rt@_}n%RdQdiWMhubTommUkF$wll6w?jNivV%BQooj zrtxWg1ViOSM;2V6Sr&wpQ_C{isekNi^UqX&-pLbnGv0@X_VWAXWh%`PYwpP1a~Ekv zsFKsvHx8bJ0#0!N)Ibp%QueIR=q@B$i$i@r1Z%(@O_&UStLpB&+B+wuwHtC>bzU=L z8uNgSS2Xr}F$Lpjp6a7nmZS*$k^{M~sB2D0=J745cvbPLoZl>6EFGgP*kcS^I*>Zh zM=rK^+=lf9ZuB9qIiJb3ebr7+}%>IWUhgZL?v=)DBd539SfItpG@V%`zMHt1Oc0!bm3x*DPC;S)&Ykm;sCC zMRt|DKE2d7uE*929qRMpT!vo|K?&+g=qHC$B`iO~c|uS)XalmGIA(FlJ11QPm2^ll zm^TbEuBd@=EMl-h1}xXPnl}8(QL1mpKkJ+MuE9vp?tx%xKc<+c=#?(1gL#jMyWxX= ztJi)E^D%yNU)}@!_WzA;$8`baMCtv#UC*h~GuW6hP@M~*blBAfOUTlXP2pJSv^}>d z7xN8yFIo9O;>YlA(|fj{`%M-FTB)P`L`qKNV3GF(F})!^zBKgrE(IdL>uaxTjh1-HJAmh;Nqnr;3pz?ivt0jR?QLG z#q~2t-%I100xH0B3-Tb^B_wuVj)=cF{y<9YLrosuF~74^5teP9AV~PapPAe~Bk1Ts z6Up?ONwaN+`6%YspGa&_6Tk_0uu9kXlA8fi+y;W*iridw0CK2^S&)~wCim$mZ4 zV8&u^~xht_wfW2{Y#$`gemD~Hn6B5+CYlu15DN~^TW); zz@C~=_h+_ivwJ}8l)T0hoyRSF8v0t$5;RE!roqdHy+MDiH5hP*uX-epB$YS}7f*NH ze?!BnP%_9Yq8q8|2j~m`=a1AMEBP}`sY1=#ioSlauJfF~9lSA}xw?>E^T6(4i)CKk z@rfWJZIoYeLiilLF3PVilo~Rc`uB4;9lO{?6qoM=kP`Dre|ji3rH#uVfLPrv57BkC z@m6KJUSUv6w86ODU;e7dr5XAvi$I)ay#{W@#A0V-DIT+$wnDFqBzbPXr;1J&^tDvG z{|+3u zn!!%rzAQZ_x7Z)-I1*Bi@xF4CwqJ+j^{sHb1l~k?EY`%ubFomtd#;4tTCSC(7ioOT zD&Eae8GFjwq8Db&NU}sL6*U*WiSHhGupKhVoE0Yt^VOxNoIvm%;3;T-!B<_b#vQ`6 zL{ZC`gREw^YbW*Q;!Q_<6e-X!kGY*7&<$xpg%@3=4wkhf|Jb^`$QYx$2&5X_QjdZU zsU?~Jak|n6?KEN4PKDP(Io6*;U_|?SK`5=vZ)L6o{tAVI=|SFJjP?UDtK>8ZIvc)@ zS1WB+B@<-|!{8~&)w22~PcWLjDnVVG*7eH<_5)00AHGL^!lSWa>%%u2;Y zqk*aEI@1nka5iNN#rBtCFpBinSqAABWh`uoF(T7-B&^$T;d7P(0|WHv`PnoseSdoN zb5(*1-d6SYe&T7{mkf|yK9?@@IQAk)XnM{Wk{+Z;vWema;ovR!I?XbXz80FHb?J;v zWy7UB{&Aj+hBnDo;nE;aG-yI8vlu3i=8MJN8L-Yn7nIwKmxXEWM{jEi`@q#o^hBUv z`nw5p!mvFMTZV{Ec+}OG#pH?N=5@HP4apqu(k>0N)o!8(3+=Kop1NLHjG17K9XGEZ zlh-Pj+tt;wYf@oMeg)+-#M~H@RXeSFan{rJs`>ZVkv&aZrLqD=mQGJg*A1+*?>4o7 z`1EUD=oOviW2SF>pMWCUmP=>7Q?3~|FZD~Bvy|NyKlfT|)BAE7(`--q0^0#k)Vi90 zOpda&FDn%zP`QaCkN7~k(dh>J`J^tK(~$k+?BqK7fm-v(TkIL5xP&%&(&@SZ6t6jB zV+ri(!c2~F19N{yBHb<7Y< zW}a%-AX~3uFK;n|_t?^$TMQiQU+M$Arkkc^kZecDvNL{~DmbZ~ZHo)C60>})1K;~5$%S)oP;^!k;+hxxPa*N1bc6CP+o@6Gj4$GExizu{l3?f3u z1{xoqMqV{9QPMX{vz&dDSp10n)9uV3p8IE+o1)XV_$0pvj(W6KxLkiSJy@jUsX1@( zT9J1J`fd%8xM!LE;gtPTw?ssNSH@cW#|A5LUto8+ez4Z--NGt~bWr*wlpN-)hw!Ca zMYB|55egKGw@9)+9Jcqd`UlTR<738(lySImsFHI%Kb61cA-f3;?>F*x4R>*uJ)vBQS&>@!my@UO!W)>gm_Sy3)xWg z@a7_>R^v%qcoY@vPLO{7D3`^p@_5xROdD*ZYbPslu_3Yv-k+7yylPaWy4gjRdfLqsHzPc&@Ghci8x3d$@^m;sehvS^Ze%k0BPYBA!#PMdNjBC z$e94a-B22KZ2nUXO2T#yAjLEGXE-%Xf2c1u=>}cjQ`s+_5JKWORAS&*FTyD>pwp@? zCEywLBP?NvtgTx~*`*e~c9$kdzwZ#e4go;f^)VPAp`ML9@**b`1d7zhST99z)1)+0 zr2}1^b>g3~eX!0G*gFL??AO&s8NZN~FzhJW0hH2)1DF`w0o0k7WvZ!PyF`>Ti#Wbz z3!48= z^Y#xG{8=Yue~|ruhwM+YS^qnY`h)lWS!>}x$o{`Y_CK~I6?6fkH`rl%tRFr4KN>vv zpS>MpQJAuNmqG6w;y($sakJW1vBTUR=ktK;i8R6a=q4y|BamK}g+=Nu!CWu~ueLfq z%OczAuFPkomwX!{yu%Gp;Q;{X41eH5p4WFeQd&SQyEk%hL_%Z*Ffl_r_l1_bQ?Azt z57tdhT0KqDoH3o=+7f@On_rv!=7x>qOL-dX{oro{U)V||ivCWb;UbXtthVD3ic$3A z=g;XMg-vYq?o?M)-{OlLxT+TB5<)l5{ntbO>XX0b$$w3Dto}p1)Rta(DvOd`iPa00 zwuXDlN2l=(A#@bU{TH!!cKvP{L!0!T-$d;nh$@%g#VpK{tIEXrJi~QefaX>)6<;* zz*+oP$k9V&c>C`>=TE5q7a*OC*KLpbuN)hH0c28E2prc$9Cx>+&xI!_5RHq|&X{1| zA+QIx^%SxCpl7SfCX}PNh5Xa`fb%Dzis==ag~q&qB88L~2k zgo{TkB=Z5xPOaT4~h!*B=>QR-yllCIah>lh7il zuI5w72G1<6ZH*Y8Swy^xkhkb`fLLlFg44~G`!O3>Tr-wTz&q)lnpvnOOWLYteSQHf zKwQGG7^Z{VfgDvJ!f`1`bRU7SrK9ryre$^7-KJkV>qm2yxp0?UHKg!qePfgCEo>~d zo)Sv1LFLirnBa>Tvx*Wl58U!!r6&zZi7%J#kchmE3v4U0&@AJlw1`xusx!$v$Xx(0 zuMaw$a>)Qt@H_t8-|y<+{|8UX=iYaEcKh!txh#xQ`k5z|SMNeb`7(&4CMZzb;oWu5 zFA|K&c+^<_9A*sCI2Ne7fs`vb;z#@fgy~DtKHGhE%8BaJXYo%LJ~buW2)EMKl$||M z-FhtXM$t8I*MHQoK2&15BN5=_DRp7avh6+*v_)D!lK&p6roK`(3N^_F4wSUxc$3rl z5-~>g+UZv~hL?QMfWFyA2bHb%U3cAu>dD)PyPA)Un{LWmrt_}ezQ#$YD%>J@WqeBT zMhSV3A@tLt0rHB~38Q&@Z*#PZCV&&i8SiG27;w;^MV0pTs~3Xm{NJuagb{p5h$6*r zu_e@rs`dreaxS;)fh1xlD1FAvcc>cm2sbzPtS3ynJI28UCRcB=%ttS|a3Y7sg`Uy= z@aZ$dkE@Zt08cKh-JVO=BbW*+En>$w1MiGFd5+vkze?83Qzh8cv4v0E8WHoqx_Vr> z=W}4h-I|ql*I{xFMeVBT6MFwF_E{o#Otx0i$_qDH=mu5(>t|JBl;iq(lAH+G^L3lp zp?je~gPL4s12~m$gF$o*Yu$(!xAgz{ElDKjZ6=e>3at9UsYRVOFV0xb;B&XfNt}A_ zC)EmhKU%;plX>2C6pTf7=Oz7z3KqzV0us#u_r|V$@KmaHlHaeM~z#R9?~wBYBidMktGi&-ea1I$4WoD4L|$FkKHFBg>81o4dR?@ zD^%#JG2R*_oXSk&6=iIEa79-A=lhj9Uq?x@=35?3GN>?jg#O;}67Ndquxh@VlJmRo zknau1014Y+L86x?TA&47DbS-)t?v>UX1sVX{C0#b;Iv+o+=`fQcLTb%~9?l zSz*f2g*tA}{fp1)YXs8KR{DA2Vgk~Q8>{#@e8g#|An9`tdSzlLty00R58 ziZIgFOLr}#62srJIkX~SzsJ9@vy{T^J~b)%3pYq~-hal+CPZ zhi9@v%vM~HGa588Qz1<|6d zxGLkbpnM0+do$9}u%`gwh!;YzmoP&;BnxS} zlz(Et`Sa7Y?gz;53;?z2ZejJTan5x~D);xm-wc&g_BS{K?^ASj>-t+9_&(M+m+IbX z2}_52QP>K{+VyMlO8#38{JT6)Q~+mV=F24?caBJ@uU~=Hfys5h1sZXpi zKO0RS9K?OfzmOSv?Q?Cy5rsS8N7uqHKqdA@dtvDMnZKU@SO5GqfBurM|BLm5pr%MCHUjps5T9ij+XlNF^3&u(%E6_s4VGVkt%kjcllr5R zf{kK92bK$#?xQ6pCVom`Hr2Yh8X6-7{;nN-{xoMaA5UZ*A}Il74CnqgiKxS0B>zYC z3lnx$w*Zbdj#G&*Jt!NJk;)i&3lEZ6$zy6BWfOF64(15=W81v{ZM}ilJib9*dNY-h zdI~Lwq@0K<1cDiaggg5VdHmRdIi)Jz6v6Wg6mTBb>{6F))kKT?kuk*9F=i0VFtATi zz-y2-@(~+JZ=NNRUMn&bjUVejk=tZodCXWYyFOMbYEW$Vda{gd!#wzgF=^07p8LEj z{Zx+4&rJjtpXtZG!!K2dG`}jgp5LNRayB6HIr|`8XTEahP;y=Ety~g%)M~}N6Ti)8 z(WBGgVx0f-4Y^FFAUjd`z71}P-ET!wY%p11WL+8!rh5X4H34s=Lty0bz>g5P(o%vd zI~D|%m6cr<;*Pdlep){1mvL+E{?a%Sa@Mog^RAP7V5BM&B~^srnfyI9fl(oX9va!k z9cA1i7;~Ovq0D}(+lHOl^^oGdjxJ%+kImIRGj}e(&-R^sOZ9E^F?`miEEXSZHUx=u zDRNYXdR`Hun}~k2+TEQMA?Og}5Psq$x8=W1mRttSEE($p#rQoXB@2w%V{3^p1oZM; zw+ho`iXh=Bf+YEyME&;XZxVIqZ$d|rs3#Pm)AX}LX|Ho^rfz7TC}1;i2<$9aVX0X2 z$b&y7I&pK~>|=}uV}a)8(6@i=bQQ|5O;Ls|f8C_D&M`?PGKxYn9Q?mYX#VS^1lzjdG-Goqi_G;G2+q|wV~unub2Wq^q}OGbQ6W44`UuC-KaNR{ipT)?-rce zQ0EcL_L{bQf7YEg=G+TCF~-vRg^W7|l681}-7|xay38C$*3^EMy_MLqBv(#9(k7C2Xk3D^04F$32euDLgvP;{l)Oe4N*@4=W;Z;7RC z#b|+LIZPzWvjhEUGJv4i`xCkF2V5jdHhE(_C5>CDzg_aNk2;dc z94=m^@3(3F3!u}tOOzB+2gSJ!1TIR(-tWHZbLT@gw@xMWzChQlf$|AdLUi7kkFTMj zKW-MC>^dHG>)M$Gf`fY zfH?~M{?GGNVY(yRv{{+p(v5rUTJG|$cU(d+z!ZI z#)HATgCPzz4rVL!TlUj+8P70+1+h^k#bW!{EEqP@)MYGO&y>Na&T!+%rPpo7{2Otn zJb0=CA!+_{1I@P`eRc(AhzeSSJIlh&Zx(7uyaCiadC=R))9#+4cK6j|zp-rw8cq2Y zYE0JHUBj#fk^Jv|T|tGZjfX%o%2HF+%aYo<%if$HmDS6!v45*Yqj<1n`i+$k_>uN{ zHLSFRASp9)nDm0rIH<)8pDjD!toh?i?svBrsN8OAi|-0Fl`gaHv6cdZELZe`ErUGj zXUwi}Y!HPY83#k3Rv^9Cwd0y{^T)+lxr#)3im%s7&KO#}ZPGG{g8)JOY#3u9Bt9oy zWd_?&&e0dFYVSpt*R|q3`n%%&PXt_gUB-S^K2DTZ;5rFun%;KO?L+Bk{SrI1(q z-6`TESV9NkQA7d-ZSTMO3vMC@z;^;VF7#~h%6jhg_RQZZ!lg;G2A2|AbM~o?Ag7-wGG|`-9znuQJqSF(VXCJ;qFn#1=hK_#_49cOX1bEderJ+J+u|dL6q}!w&QOogb9I#N`F|lZ0 zoy~<^=ZALMLxX30={Mp=q%Pmmv=F1{bfX3%1;)Z+a1TY37#(HYNmj03WHXm*3ei%{ z{RPmUr-Vt&&)<_7PEPvbxpQrICy5oRRx`5b_Zl}%d4WsM=MNwL0vKG2tG&3@MB^K4 z=E0xwgm0!`>}DPJ<;9r>=GF6Nd*m(W`E6#HKen+X!1YM$9@BePs?36(=+6J@ECie$ lFk=Ib7s{w3ZfSZibH*9KCNpM-Y|_)~EA@(+wJ-jf{$FFnwMGB{ literal 0 HcmV?d00001