diff --git a/.codecov.yml b/.codecov.yml new file mode 100644 index 0000000000..bbe2ee8e93 --- /dev/null +++ b/.codecov.yml @@ -0,0 +1,8 @@ +comment: false # Ref: https://docs.codecov.io/docs/pull-request-comments + +coverage: + status: + project: + default: + threshold: 0% # Ref: https://docs.codecov.io/docs/codecovyml-reference#coveragestatus + target: auto diff --git a/.eslintignore b/.eslintignore index 2f59b98bca..c73074efb3 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,5 +1,6 @@ **/node_modules/** **/dist/** +**/dist-types/** **/storybook-static/** **/coverage/** **/build/** diff --git a/.github/ISSUE_TEMPLATE/rfc_template.md b/.github/ISSUE_TEMPLATE/rfc_template.md new file mode 100644 index 0000000000..c4990ee5d6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rfc_template.md @@ -0,0 +1,26 @@ +--- +name: 'RFC' +about: 'Request For Comments (RFC) from the community' +labels: rfc +title: '[RFC] ' +--- + +**Status:** Open for comments + + + +## Need + + + +## Proposal + + + +## Alternatives + + + +## Risks + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 57746da2e8..0437698301 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,9 @@ That makes it easier to understand the change so we can :shipit: faster. --> #### :heavy_check_mark: Checklist + + - [ ] All tests are passing `yarn test` - [ ] Screenshots attached (for UI changes) - [ ] Relevant documentation updated diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..59847fd65f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: '/' + schedule: + interval: daily + time: '04:00' + open-pull-requests-limit: 5 + labels: + - dependencies + - package-ecosystem: npm + directory: '/microsite/' + schedule: + interval: daily + time: '04:00' + open-pull-requests-limit: 2 + labels: + - dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 492b008431..c8c92c57ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,11 +69,14 @@ jobs: - name: verify doc links run: node docs/verify-links.js + - name: prettier + run: yarn prettier:check + - name: lint run: yarn lerna -- run lint --since origin/master - name: type checking and declarations - run: yarn tsc --incremental false + run: yarn tsc:full - name: build changed packages if: ${{ steps.yarn-lock.outcome == 'success' }} @@ -90,9 +93,24 @@ jobs: if: ${{ steps.yarn-lock.outcome == 'success' }} run: yarn lerna -- run test --since origin/master -- --coverage - - name: test all packages + - name: test all packages (and upload coverage) if: ${{ steps.yarn-lock.outcome == 'failure' }} - run: yarn lerna -- run test -- --coverage + run: | + yarn lerna -- run test -- --coverage + bash <(curl -s https://codecov.io/bash) - name: verify plugin template run: yarn lerna -- run diff -- --check + + - name: ensure clean working directory + run: | + if files=$(git ls-files --exclude-standard --others --modified) && [[ -z "$files" ]]; then + exit 0 + else + echo "" + echo "Working directory has been modified:" + echo "" + git status --short + echo "" + exit 1 + fi diff --git a/.github/workflows/e2e-win.yml b/.github/workflows/e2e-win.yml index 5ebf67bc9a..5bab1b1299 100644 --- a/.github/workflows/e2e-win.yml +++ b/.github/workflows/e2e-win.yml @@ -27,28 +27,15 @@ jobs: steps: - uses: actions/checkout@v2 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - registry-url: https://registry.npmjs.org/ # Needed for auth - - name: find location of global yarn cache - id: yarn-cache - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v2 - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - name: yarn install run: yarn install --frozen-lockfile - # End of yarn setup - run: yarn tsc - name: yarn build - run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli --ignore backstage-microsite + run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli - name: run E2E test run: yarn workspace e2e-test start diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 401fe7297a..d53ca1b607 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -64,7 +64,7 @@ jobs: - run: yarn tsc - name: yarn build - run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli --ignore backstage-microsite + run: yarn build --ignore example-app --ignore example-backend --ignore @techdocs/cli - name: run E2E test run: | sudo sysctl fs.inotify.max_user_watches=524288 diff --git a/.github/workflows/master-win.yml b/.github/workflows/master-win.yml index 296a7511bc..3f65cf9aec 100644 --- a/.github/workflows/master-win.yml +++ b/.github/workflows/master-win.yml @@ -39,7 +39,22 @@ jobs: run: yarn install --frozen-lockfile # End of yarn setup + - name: lint + run: yarn lerna -- run lint -# Tests are broken on Windows, disabled for now - # - name: test - # run: yarn lerna -- run test + - name: type checking and declarations + run: yarn tsc:full + + - name: verify type dependencies + run: yarn lint:type-deps + + - name: test + run: yarn lerna -- run test + + - name: Discord notification + if: ${{ failure() }} + uses: Ilshidur/action-discord@0.2.0 + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} + with: + args: 'Windows master build failed https://github.com/{{GITHUB_REPOSITORY}}/actions/runs/{{GITHUB_RUN_ID}}' diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 354838037e..f99c266241 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -51,7 +51,7 @@ jobs: run: yarn lerna -- run lint - name: type checking and declarations - run: yarn tsc --incremental false + run: yarn tsc:full - name: build run: yarn build @@ -59,8 +59,10 @@ jobs: - name: verify type dependencies run: yarn lint:type-deps - - name: test - run: yarn lerna -- run test -- --coverage + - name: test (and upload coverage) + run: | + yarn lerna -- run test -- --coverage + bash <(curl -s https://codecov.io/bash) # Publishes current version of packages that are not already present in the registry - name: publish @@ -71,9 +73,9 @@ jobs: # Tags the commit with the version in the core package if the tag doesn't exist - uses: Klemensas/action-autotag@1.2.3 with: - GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - package_root: "packages/core" - tag_prefix: "v" + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + package_root: 'packages/core' + tag_prefix: 'v' - name: Discord notification if: ${{ failure() }} diff --git a/.github/workflows/microsite-build-check.yml b/.github/workflows/microsite-build-check.yml index dc86ca2630..ff290b71e4 100644 --- a/.github/workflows/microsite-build-check.yml +++ b/.github/workflows/microsite-build-check.yml @@ -22,33 +22,17 @@ jobs: steps: - uses: actions/checkout@v2 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v2 - with: - path: '**/node_modules' - key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v2 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- + + # Skip caching of microsite dependencies, it keeps the global cache size + # smaller, which make Windows builds a lot faster for the rest of the project. - name: yarn install run: yarn install --frozen-lockfile - # End of yarn setup + working-directory: microsite - name: build microsite - run: yarn workspace backstage-microsite build + run: yarn build + working-directory: microsite diff --git a/.github/workflows/microsite-with-storybook-deploy.yml b/.github/workflows/microsite-with-storybook-deploy.yml index 2c8b8af40c..22fd48789a 100644 --- a/.github/workflows/microsite-with-storybook-deploy.yml +++ b/.github/workflows/microsite-with-storybook-deploy.yml @@ -26,36 +26,24 @@ jobs: steps: - uses: actions/checkout@v2 - # Beginning of yarn setup, keep in sync between all workflows, see ci.yml - name: use node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - - name: cache all node_modules - id: cache-modules - uses: actions/cache@v2 - with: - path: '**/node_modules' - key: ${{ runner.os }}-node_modules-${{ hashFiles('yarn.lock', '**/package.json') }} - - name: find location of global yarn cache - id: yarn-cache - if: steps.cache-modules.outputs.cache-hit != 'true' - run: echo "::set-output name=dir::$(yarn cache dir)" - - name: cache global yarn cache - uses: actions/cache@v2 - if: steps.cache-modules.outputs.cache-hit != 'true' - with: - path: ${{ steps.yarn-cache.outputs.dir }} - key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} - restore-keys: | - ${{ runner.os }}-yarn- - - name: yarn install + + # We avoid caching in this workflow, as we're running an install of both the top-level + # dependencies and the microsite. We leave it to the main master workflow to produce the + # cache, as that results in a smaller bundle. + - name: top-level yarn install run: yarn install --frozen-lockfile - # End of yarn setup + - name: microsite yarn install + run: yarn install --frozen-lockfile + working-directory: microsite - name: build microsite - run: yarn workspace backstage-microsite build + run: yarn build + working-directory: microsite - name: build storybook run: yarn workspace storybook build-storybook diff --git a/.github/workflows/techdocs-project-board.yml b/.github/workflows/techdocs-project-board.yml new file mode 100644 index 0000000000..b389cf6bf5 --- /dev/null +++ b/.github/workflows/techdocs-project-board.yml @@ -0,0 +1,53 @@ +name: Automatically add new TechDocs Issues and PRs to the GitHub project board +# Development of TechDocs in Backstage is managed by this Kanban board - https://github.com/spotify/backstage/projects/5 +# New issues with TechDocs in their title or docs-like-code label will be added to the board. + +on: + issues: + types: [opened, reopened, labeled, edited] + pull_request: + types: [opened, reopened, labeled, edited] + +env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + assign_issue_or_pr_to_project: + runs-on: ubuntu-latest + name: Triage + steps: + - name: Assign new issue to Incoming based on its title. + uses: srggrs/assign-one-project-github-action@1.2.0 + if: | + contains(github.event.issue.title, 'TechDocs') || + contains(github.event.issue.title, 'techdocs') || + contains(github.event.issue.title, 'Techdocs') + with: + project: 'https://github.com/spotify/backstage/projects/5' + column_name: 'Incoming' + + - name: Assign new issue to Incoming based on its label. + uses: srggrs/assign-one-project-github-action@1.2.0 + if: | + contains(github.event.issue.labels.*.name, 'docs-like-code') + with: + project: 'https://github.com/spotify/backstage/projects/5' + column_name: 'Incoming' + + - name: Assign new PR to Incoming based on its title. + uses: srggrs/assign-one-project-github-action@1.2.0 + if: | + contains(github.event.pull_request.title, 'TechDocs') || + contains(github.event.pull_request.title, 'techdocs') || + contains(github.event.pull_request.title, 'Techdocs') + with: + project: 'https://github.com/spotify/backstage/projects/5' + column_name: 'Incoming' + + - name: Assign new PR to Incoming based on its label. + uses: srggrs/assign-one-project-github-action@1.2.0 + if: | + contains(github.event.pull_request.labels.*.name, 'docs-like-code') + with: + project: 'https://github.com/spotify/backstage/projects/5' + column_name: 'Incoming' diff --git a/.gitignore b/.gitignore index aee80f4c10..e7d294d55a 100644 --- a/.gitignore +++ b/.gitignore @@ -89,10 +89,7 @@ typings/ # Nuxt.js build / generate output .nuxt dist - -# Microsite build output -microsite/build -microsite/i18n +dist-types # Gatsby files .cache/ diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..9e75b74eee --- /dev/null +++ b/.prettierignore @@ -0,0 +1,8 @@ +.yarn +dist +microsite/build +coverage +*.hbs +templates +plugins/scaffolder-backend/sample-templates +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ae9a414d..294c57815e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,40 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re ## Next Release +### @backstage/core + +- Introduced initial version of an inverted app/plugin relationship, where plugins export components for apps to use, instead registering themselves directly into the app. This enables more fine-grained control of plugin features, and also composition of plugins such as catalog pages with additional cards and tabs. This breaks the use of `RouteRef`s, and there will be more changes related to this in the future, but this change lays the initial foundation. See `packages/app` and followup PRs for how to update plugins for this change. [#2076](https://github.com/spotify/backstage/pull/2076) +- Switch to an automatic dependency injection mechanism for all Utility APIs, allowing plugins to ship default implementations of their APIs. See [https://backstage.io/docs/api/utility-apis](https://backstage.io/docs/api/utility-apis). [#2285](https://github.com/spotify/backstage/pull/2285) + > Collect changes for the next release below +### @backstage/cli + +- Change `backstage-cli backend:build-image` to forward all args to `docker image build`, instead of just tag. Also add `--build` flag for building all dependent packages before packaging the workspace for the docker build. [#2299](https://github.com/spotify/backstage/pull/2299) + +### @backstage/create-app + +- Change root `tsc` output dir to `dist-types`, in order to allow for standalone plugin repos. [#2278](https://github.com/spotify/backstage/pull/2278) + +## v0.1.1-alpha.21 + +- Added many more frontend plugins to the template along with the sidebar. [#1942](https://github.com/spotify/backstage/pull/1942), [#2084](https://github.com/spotify/backstage/pull/2084) + +### @backstage/core + +- Material-UI: Bumped to 4.11.0, which is the version that create-app will + resolve to, because we wanted to get the renaming of ExpansionPanel to + Accordion into place. This gets rid of a lot of console deprecation warnings + in newly scaffolded apps. + +### @backstage/cli + +- Set `NODE_ENV` to `test` when running test. [#2214](https://github.com/spotify/backstage/pull/2214) + +- Fix for backend plugins names requiring to be prefixed with `@backstage` to build. [#2224](https://github.com/spotify/backstage/pull/2224) + +### @backstage/backend-common + - The backend plugin [service builder](https://github.com/spotify/backstage/blob/master/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts) no longer adds `express.json()` automatically to all routes. While convenient @@ -17,14 +49,31 @@ If you encounter issues while upgrading to a newer version, don't hesitate to re still had to cater to that manually. We therefore decided to let plugins add `express.json()` themselves if they happen to deal with JSON data. +### @backstage/catalog-backend + +- Add rules configuration for catalog location and entity kinds. The default rules should cover most use-cases, but you may need to allow specific entity kinds when using things like Template or Group entities. [#2118](https://github.com/spotify/backstage/pull/2118) + ## v0.1.1-alpha.20 -- Includes https://github.com/spotify/backstage/pull/2097 to resolve issues with create-plugin command. +### @backstage/cli + +- Use config files according to `NODE_ENV` when serving and building frontend packages. [#2077](https://github.com/spotify/backstage/pull/2077) + +- Pin `rollup-plugin-dts` to avoid a later broken version. [#2097](https://github.com/spotify/backstage/pull/2097) ## v0.1.1-alpha.19 +### @backstage/backend-common + +- Allow listen host and port to be configured separately, in order to support PORT environment variables. [#1950](https://github.com/spotify/backstage/pull/1950) + +### @backstage/core + +- Added new `DiscoveryApi` for discovering backend endpoint in the frontend, and use in most plugins. See [packages/app/src/apis.ts](https://github.com/spotify/backstage/blob/master/packages/app/src/apis.ts) for how to register in your app. [#2074](https://github.com/spotify/backstage/pull/2074) + ### @backstage/create-app +- Added catalog and scaffolder frontend plugins to the template along with the sidebar. [#1942](https://github.com/spotify/backstage/pull/1942), [#2084](https://github.com/spotify/backstage/pull/2084) - Many plugins have been added to the catalog and will for now be required to be added to separate apps as well. This will be solved as [#1536](https://github.com/spotify/backstage/issues/1536) gets sorted out, but for now you may need to install some plugins just to get pages to work. ### @backstage/catalog-backend diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 69f6457dd9..55269dd2a5 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -4,12 +4,12 @@ This code of conduct outlines our expectations for participants within the **Spo Our open source community strives to: -* **Be friendly and patient.** -* **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. -* **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. -* **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. -* **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. -* **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. +- **Be friendly and patient.** +- **Be welcoming**: We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. +- **Be considerate**: Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. +- **Be respectful**: Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. +- **Be careful in the words that we choose**: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. +- **Try to understand why we disagree**: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that we’re different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. ## Definitions @@ -18,7 +18,7 @@ Harassment includes, but is not limited to: - Offensive comments related to gender, gender identity and expression, sexual orientation, disability, mental illness, neuro(a)typicality, physical appearance, body size, race, age, regional discrimination, political or religious affiliation - Unwelcome comments regarding a person’s lifestyle choices and practices, including those related to food, health, parenting, drugs, and employment - Deliberate misgendering. This includes deadnaming or persistently using a pronoun that does not correctly reflect a person's gender identity. You must address people by the name they give you when not addressing them by their username or handle -- Physical contact and simulated physical contact (eg, textual descriptions like “*hug*” or “*backrub*”) without consent or after a request to stop +- Physical contact and simulated physical contact (eg, textual descriptions like “_hug_” or “_backrub_”) without consent or after a request to stop - Threats of violence, both physical and psychological - Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm - Deliberate intimidation @@ -39,7 +39,6 @@ Our open source community prioritizes marginalized people’s safety over privil - Communicating in a ‘tone’ you don’t find congenial - Criticizing racist, sexist, cissexist, or otherwise oppressive behavior or assumptions - ### Diversity Statement We encourage everyone to participate and are committed to building a community for all. Although we will fail at times, we seek to treat everyone both as fairly and equally as possible. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. @@ -53,18 +52,18 @@ If you experience or witness unacceptable behavior—or have any other concerns - Your contact information. - Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please -include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. + include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. - Any additional information that may be helpful. After filing a report, a representative will contact you personally, review the incident, follow up with any additional questions, and make a decision as to how to respond. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. If the complaint originates from a member of the response team, it will be handled by a different member of the response team. We will respect confidentiality requests for the purpose of protecting victims of abuse. ### Attribution & Acknowledgements -We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established code of conducts and diversity statements as our inspiration: +We all stand on the shoulders of giants across many open source communities. We'd like to thank the communities and projects that established code of conducts and diversity statements as our inspiration: -* [Django](https://www.djangoproject.com/conduct/reporting/) -* [Python](https://www.python.org/community/diversity/) -* [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct) -* [Contributor Covenant](http://contributor-covenant.org/) -* [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/) -* [Citizen Code of Conduct](http://citizencodeofconduct.org/) +- [Django](https://www.djangoproject.com/conduct/reporting/) +- [Python](https://www.python.org/community/diversity/) +- [Ubuntu](http://www.ubuntu.com/about/about-ubuntu/conduct) +- [Contributor Covenant](http://contributor-covenant.org/) +- [Geek Feminism](http://geekfeminism.org/about/code-of-conduct/) +- [Citizen Code of Conduct](http://citizencodeofconduct.org/) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 853332f74d..0d6a8db50c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,35 +62,7 @@ Have you started using Backstage? Adding your company to [ADOPTERS](ADOPTERS.md) So...feel ready to jump in? Let's do this. 👏🏻💯 -To run a Backstage app, you will need to have the following installed: - -- [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -- [NodeJS](https://nodejs.org/en/download/) - Active LTS Release, currently v12 -- [yarn](https://classic.yarnpkg.com/en/docs/install) - -After cloning this repo, open a terminal window and start the example app using the following commands from the project root: - -```bash -yarn install # Install dependencies - -yarn start # Start dev server, use --check to enable linting and type-checks -``` - -The final `yarn start` command should open a local instance of Backstage in your browser, otherwise open one of the URLs printed in the terminal. - -Depending on the work you're doing, you often also want to run the example backend. Start the backend in a separate terminal session using the following: - -```bash -cd packages/backend - -yarn start - -yarn lerna run mock-data # Populate the backend with mock data -``` - -And that's it! You are good to go 👍 - -If you need help, just jump into our [Discord chatroom](https://discord.gg/MUpMjP2). +Start by reading our [Getting Started](https://backstage.io/docs/getting-started/) page. If you need help, just jump into our [Discord chatroom](https://discord.gg/MUpMjP2). # Coding Guidelines diff --git a/Dockerfile b/Dockerfile index fa89debcee..174548a90c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,14 @@ FROM nginx:mainline +# The purpose of this image is to serve the frontend app content separately. +# By default the Backstage backend uses the app-backend plugin to serve the +# app from the backend itself, but it may be desirable to move the frontend +# content serving to a separate deployment, in which case this image can be used. + # This dockerfile requires the app to be built on the host first, as it # simply copies in the build output into the image. -# The safest way to build this image is to use `yarn docker-build` +# The safest way to build this image is to use `yarn docker-build:app` RUN apt-get update && apt-get -y install jq && rm -rf /var/lib/apt/lists/* diff --git a/OWNERS.md b/OWNERS.md new file mode 100644 index 0000000000..1e7fe5b774 --- /dev/null +++ b/OWNERS.md @@ -0,0 +1,19 @@ +# Owners + +- See [CONTRIBUTING.md](CONTRIBUTING.md) for general contribution guidelines. + +## Maintainers 🏓 + +- Patrik Oldsberg (@Rugvip, Spotify) +- Fredrik Adelöw (@freben, Spotify) +- Raghunandan Balachandran (@soapraj, Spotify) +- Ben Lambert (@benjdlambert, Spotify) +- Marcus Eide (@marcuseide, Spotify) +- Niklas Ek (@nikek, Spotify) +- Stefan Ålund (@stefanalund, Spotify) +- Kat Zhou (@katz95, Spotify) + +## Hall of Fame 👏 + +- Andrew Thauer (@andrewthauer, Wealthsimple) +- Oliver Sand (@Fox32, SDA-SE) diff --git a/README.md b/README.md index 4009864edc..9ef09aee06 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ ![](https://github.com/spotify/backstage/workflows/Frontend%20CI/badge.svg) [![Discord](https://img.shields.io/discord/687207715902193673)](https://discord.gg/EBHEGzX) ![Code style](https://img.shields.io/badge/code_style-prettier-ff69b4.svg) +[![Codecov](https://img.shields.io/codecov/c/github/spotify/backstage)](https://codecov.io/gh/spotify/backstage) [![](https://img.shields.io/npm/v/@backstage/core?label=Version)](https://github.com/spotify/backstage/releases) ## What is Backstage? @@ -31,33 +32,7 @@ A detailed project roadmap, including already delivered milestones, is available ## Getting Started -There are two different ways to get started with Backstage, either by creating a standalone app, or by cloning this repo. Which method you use depends on what you're planning to do. - -Creating a standalone instance makes it simpler to customize the application for your needs whilst staying up to date with the project. You will also depend on `@backstage` packages from NPM, making the project much smaller. This is the recommended approach if you want to kick the tyres of Backstage or setup your own instance. - -On the other hand, if you want to contribute plugins or to the project in general, it's easier to fork and clone this project. That will let you stay up to date with the latest changes, and gives you an easier path to make Pull Requests towards this repo. - -### Creating a Standalone App - -Backstage provides the `@backstage/create-app` package to scaffold standalone instances of Backstage. You will need to have -[NodeJS](https://nodejs.org/en/download/) Active LTS Release installed -(currently v12), and [yarn](https://classic.yarnpkg.com/en/docs/install). You will also need to have [Docker](https://docs.docker.com/engine/install/) installed to use some features like Software Templates and TechDocs. - -Using `npx` you can then run the following to create an app in a chosen subdirectory of your current working directory: - -```bash -npx @backstage/create-app -``` - -You will be taken through a wizard to create your app, and the output should look something like this. You can read more about this process [here](https://backstage.io/docs/getting-started/create-an-app) - -### Contributing to Backstage - -You can read more in our [CONTRIBUTING.md](./CONTRIBUTING.md#get-started) guide, which can help you get setup with a Backstage development environment. - -### Next steps - -Take a look at the [Getting Started](https://backstage.io/docs/getting-started/index) guide to learn how to set up Backstage, and how to develop on the platform. +Check out [the documentation](https://backstage.io/docs/getting-started) on how to start using Backstage. ## Documentation diff --git a/app-config.development.yaml b/app-config.development.yaml new file mode 100644 index 0000000000..da274ba1a8 --- /dev/null +++ b/app-config.development.yaml @@ -0,0 +1,11 @@ +app: + baseUrl: http://localhost:3000 + +backend: + baseUrl: http://localhost:7000 + listen: + port: 7000 + cors: + origin: http://localhost:3000 + methods: [GET, POST, PUT, DELETE] + credentials: true diff --git a/app-config.yaml b/app-config.yaml index 2620f6b9b7..5b704f9b8e 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -1,22 +1,27 @@ app: title: Backstage Example App - baseUrl: http://localhost:3000 + baseUrl: http://localhost:7000 backend: baseUrl: http://localhost:7000 listen: port: 7000 - cors: - origin: http://localhost:3000 - methods: [GET, POST, PUT, DELETE] - credentials: true database: client: sqlite3 connection: ':memory:' # See README.md in the proxy-backend plugin for information on the configuration format proxy: - '/circleci/api': https://circleci.com/api/v1.1 + '/circleci/api': + target: https://circleci.com/api/v1.1 + changeOrigin: true + pathRewrite: + '^/proxy/circleci/api/': '/' + headers: + Circle-Token: + $secret: + env: CIRCLECI_AUTH_TOKEN + '/jenkins/api': target: http://localhost:8080 headers: @@ -29,6 +34,7 @@ organization: techdocs: storageUrl: http://localhost:7000/techdocs/static/docs + requestUrl: http://localhost:7000/techdocs/docs sentry: organization: spotify @@ -70,23 +76,27 @@ catalog: privateToken: $secret: env: AZURE_PRIVATE_TOKEN - exampleEntityLocations: - github: - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-order-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/podcast-api-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/queue-proxy-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/searcher-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-lib-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml - - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml - - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml - - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml - - https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml - - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/hello-world-api.yaml - - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/streetlights-api.yaml + + locations: + # Backstage example components + - type: github + target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/all-components.yaml + + # Example component for github-actions + - type: github + target: https://github.com/spotify/backstage/blob/master/plugins/github-actions/examples/sample.yaml + + # Example component for techdocs + - type: github + target: https://github.com/spotify/backstage/blob/master/plugins/techdocs-backend/examples/documented-component/documented-component.yaml + + # Backstage example APIs + - type: github + target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/all-apis.yaml + + # Backstage example templates + - type: github + target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/all-templates.yaml auth: providers: diff --git a/catalog-info.yaml b/catalog-info.yaml index 4221ee6dc6..937a55bfca 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -3,10 +3,9 @@ kind: Component metadata: name: backstage description: | - Backstage is an open-source developer portal that puts the developer experience first. + Backstage is an open-source developer portal that puts the developer experience first. annotations: github.com/project-slug: spotify/backstage - backstage.io/github-actions-id: spotify/backstage backstage.io/techdocs-ref: github:https://github.com/spotify/backstage.git spec: type: library diff --git a/docker-compose.yaml b/docker-compose.yaml index d32928b4e3..a9922cfb6c 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,14 +1,10 @@ # Make sure that before you # run the docker-compose that you have run -# $ yarn docker-build:all +# $ yarn docker-build version: '3' services: - frontend: - image: 'spotify/backstage:latest' - ports: - - '3000:80' - backend: + backstage: image: 'example-backend:latest' ports: - '7000:7000' diff --git a/docs/api/utility-apis.md b/docs/api/utility-apis.md index b4c2fd161e..37cde87262 100644 --- a/docs/api/utility-apis.md +++ b/docs/api/utility-apis.md @@ -17,7 +17,7 @@ Utility APIs. While the `createPlugin` API is focused on the initialization plugins and the app, the Utility APIs provide ways for plugins to communicate during their entire life cycle. -## Usage +## Consuming APIs Each Utility API is tied to an `ApiRef` instance, which is a global singleton object without any additional state or functionality, its only purpose is to @@ -55,52 +55,112 @@ from any component inside Backstage, including the ones in `@backstage/core`. The only requirement is that they are beneath the `AppProvider` in the react tree. -## Registering Utility API Implementations +## Supplying APIs -The Backstage App is responsible for providing implementations for all Utility -APIs required by plugins. The example app in this repo registers its APIs inside -[src/apis.ts](/packages/app/src/apis.ts). Here's an example of how to wire up -the `ErrorApi` inside an app: +### API Factories + +APIs are registered in the form of `ApiFactories`, which encapsulate the process +of instantiating an API. It is a collection of three things: the `ApiRef` of the +API to instantiate, a list of all required dependencies, and a factory function +that returns a new API instance. + +For example, this is the default `ApiFactory` for the `ErrorApi`: ```ts -import { - ApiRegistry, - createApp, - alertApiRef, - errorApiRef, - AlertApiForwarder, - ErrorApiForwarder, - ErrorAlerter, - ConfigApi -} from '@backstage/core'; - - -const apis = (config: ConfigApi) => { - const builder = ApiRegistry.builder(); - - // The alert API is a self-contained implementation that shows alerts to the user. - const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); - - // The error API uses the alert API to send error notifications to the user. - builder.add(errorApiRef, new ErrorAlerter(alertApi, new ErrorApiForwarder())); - return builder.build(); -} - -const app = createApp({ - apis, - // ... other config +createApiFactory({ + api: errorApiRef, + deps: { alertApi: alertApiRef }, + factory: ({ alertApi }) => + new ErrorAlerter(alertApi, new ErrorApiForwarder()), }); ``` -The `ApiRegistry` is used to register all Utility APIs in the app and associate -them with `ApiRef`s. It implements the `ApiHolder` interface, which enables it -to provide an API implementation given an `ApiRef`. +In this example the `errorApiRef` is our API, which encapsulates the `ErrorApi` +type. The `alertApiRef` is our single dependency, which we give the name +`alertApi`, and is then passed on to the factory function, which returns an +implementation of the `ErrorApi`. -Note that our `ErrorApi` implementation depends on another Utility API, the -`AlertApi`. This is the method with which APIs can depend on other APIs, using -manual dependency injection at the initialization of the app. In general, if you -want to depend on another Utility API in an implementation of an API, you import -the type for that API and make it a constructor parameter. +The `createApiFactory` function is a thin wrapper that enables TypeScript type +inference. You may notice that there are no type annotations in the above +example, and that is because we're able to infer all types from the `ApiRef`s. +TypeScript will make sure that the return value of the `factory` function +matches the type embedded in `api`'s `ApiRef`, in this case the `ErrorApi`. It +will also match the types between the `deps` and the parameters of the `factory` +function, again using the type embedded within the `ApiRef`s. + +## Registering API Factories + +The responsibility for adding Utility APIs to a Backstage app lies in three +different locations: the Backstage core library, each plugin included in the +app, and the app itself. + +### Core APIs + +Starting with the Backstage core library, it provides implementation for all of +the core APIs. The core APIs are the ones exported by `@backstage/core`, such as +the `errorApiRef` and `configApiRef`. You can find a full list of them +[here](../reference/utility-apis/README.md). + +The core APIs are loaded for any app created with `createApp` from +`@backstage/core`, which means that there is no step that needs to be taken to +include these APIs in an app. + +### Plugin APIs + +In addition to the core APIs, plugins can define and export their own APIs. +While doing so they should usually also provide default implementations of their +own APIs, for example, the `catalog` plugin exports `catalogApiRef`, and also +supplies a default `ApiFactory` of that API using the `CatalogClient`. There is +one restriction to plugin-provided API Factories: plugins may not supply +factories for core APIs, trying to do so will cause the app to crash. + +Plugins supply their APIs through the `apis` option of `createPlugin`, for +example: + +```ts +export const plugin = createPlugin({ + id: 'techdocs', + apis: [ + createApiFactory({ + api: techdocsStorageApiRef, + deps: { configApi: configApiRef }, + factory({ configApi }) { + return new TechDocsStorageApi({ + apiOrigin: configApi.getString('techdocs.storageUrl'), + }); + }, + }), + ], +}); +``` + +### App APIs + +Lastly, the app itself is the final point where APIs can be added, and what has +the final say in what APIs will be loaded at runtime. The app may override the +factories for any of the core or plugin APIs, with the exception of the config, +app theme, and identity APIs. These are static APIs that are tied into the +`createApp` implementation, and therefore not possible to override. + +Overriding APIs is useful for apps that want to switch out behavior to tailor it +to their environment. In some cases plugins may also export multiple +implementations of the same API, where they each have their own different +requirements on for example backend storage and surrounding environment. + +Supplying APIs to the app works just like for plugins: + +```ts +const app = createApp({ + apis: [ + /* ApiFactories */ + ], + // ... other options +}); +``` + +A common pattern is to export a list of all APIs from `apis.ts`, next to +`App.tsx`. See the [example app in this repo](../../packages/app/src/apis.ts) +for an example. ## Custom implementations of Utility APIs @@ -128,19 +188,33 @@ implement the `ErrorApi`, as it is checked by the type embedded in the ## Defining custom Utility APIs -The pattern for plugins defining their own Utility APIs is not fully established -yet. The current way is for the plugin to export its own `ApiRef` and type for -the API, along with one or more implementations. It is then up to the app to -import, and register those APIs. See for example the -[lighthouse](/plugins/lighthouse/src/api.ts) or -[graphiql](/plugins/graphiql/src/lib/api/types.ts) plugins for examples of this. +Plugins are free to define their own Utility APIs. Simply define the TypeScript +interface for the API, and create an `ApiRef` using `createApiRef` exported from +`@backstage/core`. Also be sure to provide at least one implementation of the +API, and to declare a default factory for the API in `createPlugin`. -The goal is to make this process a bit smoother, but that requires work in other -parts of Backstage, like configuration management. So it remains as a TODO. If -you have more questions regarding this, or have an idea for an API that you want -to share outside your plugin, hit us up in -[GitHub issues](https://github.com/spotify/backstage/issues/new/choose) or the -[Backstage Discord server](https://discord.gg/EBHEGzX). +Custom Utility APIs can be either public or private, which it is up to the +plugin to choose. Private APIs do not expose an external API surface, and it's +therefore possible to make breaking changes to the API without affecting other +users of the plugin. If an API is made public however, it opens up for other +plugins to make use of the API, and it also makes it possible for users for your +plugin to override the API in the app. It is however important to maintain +backwards compatibility of public APIs, as you may otherwise break apps that are +using your plugin. + +To make an API public, simply export the `ApiRef` of the API, and any associated +types. To make an API private, just avoid exporting the `ApiRef`, but still be +sure to supply a default factory to `createPlugin`. + +Private APIs are useful for plugins that want to depend on other APIs outside of +React components, but not have to expose an entire API surface to maintain. When +using private APIs, it is fine to use the `typeof` of an implementing class as +the type parameter passed to `createApiRef`, while public APIs should always +define a separate TypeScript interface type. + +Plugins may depend on APIs from other plugins, both in React components and as +dependencies to API factories. Do however be sure to not cause circular +dependencies between plugins. ## Architecture diff --git a/docs/architecture-decisions/adr002-default-catalog-file-format.md b/docs/architecture-decisions/adr002-default-catalog-file-format.md index c1cb719bf5..af22d33020 100644 --- a/docs/architecture-decisions/adr002-default-catalog-file-format.md +++ b/docs/architecture-decisions/adr002-default-catalog-file-format.md @@ -68,7 +68,7 @@ metadata: lifecycle: production example.com/service-discovery-name: frobsawesome annotations: - circleci.com/project-slug: gh/example-org/frobs-awesome + circleci.com/project-slug: github/example-org/frobs-awesome spec: type: service ``` diff --git a/docs/architecture-decisions/index.md b/docs/architecture-decisions/index.md index 91d2c668d7..0e9ff21812 100644 --- a/docs/architecture-decisions/index.md +++ b/docs/architecture-decisions/index.md @@ -4,7 +4,7 @@ title: Architecture Decision Records (ADR) sidebar_label: Overview --- -The substantial architecture decisions made in the Backstage project lives here. +The substantial architecture decisions made in the Backstage project live here. For more information about ADRs, when to write them, and why, please see [this blog post](https://engineering.atspotify.com/2020/04/14/when-should-i-write-an-architecture-decision-record/). diff --git a/docs/assets/getting-started/create-app_output.png b/docs/assets/getting-started/create-app_output.png index 52dcc13097..caa39ec6d2 100644 Binary files a/docs/assets/getting-started/create-app_output.png and b/docs/assets/getting-started/create-app_output.png differ diff --git a/docs/dls/design.md b/docs/dls/design.md index 23ba84024a..b434fc8791 100644 --- a/docs/dls/design.md +++ b/docs/dls/design.md @@ -116,8 +116,8 @@ components. If you’d like to help build up our design system, you can also add components we’ve designed to the Storybook as well. **[Figma](https://www.figma.com/@backstage)** - we're stoked to be using Figma -Community to share our design assets. You can duplicate our UI Kit -and design your own plugin for Backstage. +Community to share our design assets. You can duplicate our UI Kit and design +your own plugin for Backstage. **[Discord](https://discord.gg/EBHEGzX)** - all design questions should be directed to the _#design_ channel. diff --git a/docs/features/software-catalog/descriptor-format.md b/docs/features/software-catalog/descriptor-format.md index 78dfcf365c..fa4b8c23da 100644 --- a/docs/features/software-catalog/descriptor-format.md +++ b/docs/features/software-catalog/descriptor-format.md @@ -34,7 +34,7 @@ software catalog API. "annotations": { "backstage.io/managed-by-location": "file:/tmp/component-info.yaml", "example.com/service-discovery": "artistweb", - "circleci.com/project-slug": "gh/example-org/artist-website" + "circleci.com/project-slug": "github/example-org/artist-website" }, "description": "The place to be, for great artists", "etag": "ZjU2MWRkZWUtMmMxZS00YTZiLWFmMWMtOTE1NGNiZDdlYzNk", @@ -66,7 +66,7 @@ metadata: system: public-websites annotations: example.com/service-discovery: artistweb - circleci.com/project-slug: gh/example-org/artist-website + circleci.com/project-slug: github/example-org/artist-website tags: - java spec: @@ -235,6 +235,9 @@ The `backstage.io/` prefix is reserved for use by Backstage core components. Values can be of any length, but are limited to being strings. +There is a list of [well-known annotations](well-known-annotations.md), but +anybody is free to add more annotations as they see fit. + ### `tags` [optional] A list of single-valued strings, for example to classify catalog entities in @@ -290,7 +293,7 @@ Exactly equal to `backstage.io/v1alpha1` and `Component`, respectively. The type of component as a string, e.g. `website`. This field is required. -The software catalog accepts any type value, but an organisation should take +The software catalog accepts any type value, but an organization should take great care to establish a proper taxonomy for these. Tools including Backstage itself may read this field and behave differently depending on its value. For example, a website type component may present tooling in the Backstage interface @@ -304,9 +307,9 @@ The current set of well-known and common values for this field is: ### `spec.lifecycle` [required] -The lifecyle state of the component, e.g. `production`. This field is required. +The lifecycle state of the component, e.g. `production`. This field is required. -The software catalog accepts any lifecycle value, but an organisation should +The software catalog accepts any lifecycle value, but an organization should take great care to establish a proper taxonomy for these. The current set of well-known and common values for this field is: @@ -418,7 +421,7 @@ potentially search and group templates by these tags. The type of component as a string, e.g. `website`. This field is optional but recommended. -The software catalog accepts any type value, but an organisation should take +The software catalog accepts any type value, but an organization should take great care to establish a proper taxonomy for these. Tools including Backstage itself may read this field and behave differently depending on its value. For example, a website type component may present tooling in the Backstage interface @@ -508,7 +511,7 @@ Exactly equal to `backstage.io/v1alpha1` and `API`, respectively. The type of the API definition as a string, e.g. `openapi`. This field is required. -The software catalog accepts any type value, but an organisation should take +The software catalog accepts any type value, but an organization should take great care to establish a proper taxonomy for these. Tools including Backstage itself may read this field and behave differently depending on its value. For example, an OpenAPI type API may be displayed using an OpenAPI viewer tooling in diff --git a/docs/features/software-catalog/index.md b/docs/features/software-catalog/index.md index bfc3d53d4d..9b5de16472 100644 --- a/docs/features/software-catalog/index.md +++ b/docs/features/software-catalog/index.md @@ -1,7 +1,7 @@ --- id: software-catalog-overview title: Backstage Service Catalog (alpha) -sidebar_label: Backstage Service Catalog +sidebar_label: Overview --- ## What is a Service Catalog? @@ -48,7 +48,7 @@ There are 3 ways to add components to the catalog: 1. Manually register components 2. Creating new components through Backstage -3. Integrating with and [external source](external-integrations.md) +3. Integrating with an [external source](external-integrations.md) ### Manually register components diff --git a/docs/features/software-catalog/installation.md b/docs/features/software-catalog/installation.md index 397abcc6b0..85598a2025 100644 --- a/docs/features/software-catalog/installation.md +++ b/docs/features/software-catalog/installation.md @@ -1,4 +1,7 @@ -# Installing in your Backstage App +--- +id: installation +title: Installing in your Backstage App +--- The catalog plugin comes in two packages, `@backstage/plugin-catalog` and `@backstage/plugin-catalog-backend`. Each has their own installation steps, diff --git a/docs/features/software-catalog/well-known-annotations.md b/docs/features/software-catalog/well-known-annotations.md new file mode 100644 index 0000000000..18de63d704 --- /dev/null +++ b/docs/features/software-catalog/well-known-annotations.md @@ -0,0 +1,134 @@ +--- +id: well-known-annotations +title: Well-known Annotations on Catalog Entities +sidebar_label: Well-known Annotations +--- + +This section lists a number of well known +[annotations](descriptor-format.md#annotations-optional), that have defined +semantics. They can be attached to catalog entities and consumed by plugins as +needed. + +## Annotations + +This is a (non-exhaustive) list of annotations that are known to be in active +use. + +### backstage.io/managed-by-location + +```yaml +# Example: +metadata: + annotations: + backstage.io/managed-by-location: github:http://github.com/spotify/backstage/catalog-info.yaml +``` + +The value of this annotation is a so called location reference string, that +points to the source from which the entity was originally fetched. This +annotation is added automatically by the catalog as it fetches the data from a +registered location, and is not meant to normally be written by humans. The +annotation may point to any type of generic location that the catalog supports, +so it cannot be relied on to always be specifically of type `github`, nor that +it even represents a single file. Note also that a single location can be the +source of many entities, so it represents a many-to-one relationship. + +The format of the value is `:`. Note that the target may also +contain colons, so it is not advisable to naively split the value on `:` and +expecting a two-item array out of it. The format of the target part is +type-dependent and could conceivably even be an empty string, but the separator +colon is always present. + +### backstage.io/techdocs-ref + +```yaml +# Example: +metadata: + annotations: + backstage.io/techdocs-ref: github:https://github.com/spotify/backstage.git +``` + +The value of this annotation is a location reference string (see above). If this +annotation is specified, it is expected to point to a repository that the +TechDocs system can read and generate docs from. + +### backstage.io/jenkins-github-folder + +```yaml +# Example: +metadata: + annotations: + backstage.io/jenkins-github-folder: folder-name/job-name +``` + +The value of this annotation is the path to a job on Jenkins, that builds this +entity. + +Specifying this annotation may enable Jenkins related features in Backstage for +that entity. + +### github.com/project-slug + +```yaml +# Example: +metadata: + annotations: + github.com/project-slug: spotify/backstage +``` + +The value of this annotation is the so-called slug that identifies a project on +[GitHub](https://github.com) that is related to this entity. It is on the format +`/`, and is the same as can be seen in the URL location +bar of the browser when viewing that project. + +Specifying this annotation will enable GitHub related features in Backstage for +that entity. + +### sentry.io/project-slug + +```yaml +# Example: +metadata: + annotations: + sentry.io/project-slug: pump-station +``` + +The value of this annotation is the so-called slug (or alternatively, the ID) of +a [Sentry](https://sentry.io) project within your organization. The organization +slug is currently not configurable on a per-entity basis, but is assumed to be +the same for all entities in the catalog. + +Specifying this annotation may enable Sentry related features in Backstage for +that entity. + +### rollbar.com/project-slug + +```yaml +# Example: +metadata: + annotations: + rollbar.com/project-slug: spotify/pump-station +``` + +The value of this annotation is the so-called slug (or alternatively, the ID) of +a [Rollbar](https://rollbar.com) project within your organization. The value can +be the format of `[organization]/[project-slug]` or just `[project-slug]`. When +the organization slug is omitted the `app-config.yaml` will be used as a +fallback (`rollbar.organization` followed by `organization.name`). + +Specifying this annotation may enable Rollbar related features in Backstage for +that entity. + +## Deprecated Annotations + +The following annotations are deprecated, and only listed here to aid in +migrating away from them. + +### backstage.io/github-actions-id + +This annotation was used for a while to enable the GitHub Actions feature. This +is now instead using the [github.com/project-slug](#github-com-project-slug) +annotation, with the same value format. + +## Links + +- [Descriptor Format: annotations](descriptor-format.md#annotations-optional) diff --git a/docs/features/software-templates/adding-templates.md b/docs/features/software-templates/adding-templates.md index 4f7af7c015..1472986c2a 100644 --- a/docs/features/software-templates/adding-templates.md +++ b/docs/features/software-templates/adding-templates.md @@ -105,13 +105,6 @@ curl \ This should then have added the catalog, and also should now be listed under the create page at http://localhost:3000/create. -Alternatively, if you want to get setup with some mock templates that are -already provided, run the following to load those templates: - -``` -yarn lerna run mock-data -``` - The `type` field which is chosen in the request to add the `template.yaml` to the Service Catalog here, will be come the `PreparerKey` which will be used to select the `Preparer` when creating a job. diff --git a/docs/features/software-templates/extending/create-your-own-publisher.md b/docs/features/software-templates/extending/create-your-own-publisher.md index 391f6f0658..111125b49f 100644 --- a/docs/features/software-templates/extending/create-your-own-publisher.md +++ b/docs/features/software-templates/extending/create-your-own-publisher.md @@ -7,18 +7,18 @@ Publishers are responsible for pushing and storing the templated skeleton after the values have been templated by the `Templater`. See [Create your own templater](./create-your-own-templater.md) for more info. -They receive a directory or location where the templater has sucessfully run -and is now ready to store somewhere. They also are given some other options -which are sent from the frontend, such as the `storePath` which is a string of -where the frontend thinks we should save this templated folder. +They receive a directory or location where the templater has sucessfully run and +is now ready to store somewhere. They also are given some other options which +are sent from the frontend, such as the `storePath` which is a string of where +the frontend thinks we should save this templated folder. Currently we provide the following `publishers`: - `github` This publisher is passed through to the `createRouter` function of the -`@spotify/plugin-scaffolder-backend`. Currently, only one publisher is supported, -but PR's are always welcome. +`@spotify/plugin-scaffolder-backend`. Currently, only one publisher is +supported, but PR's are always welcome. An full example backend can be found [here](https://github.com/spotify/backstage/blob/d91c10f654475a60829fa33a5c81018e517a319a/packages/backend/src/plugins/scaffolder.ts), diff --git a/docs/features/software-templates/index.md b/docs/features/software-templates/index.md index 1c67676b3e..86493c0120 100644 --- a/docs/features/software-templates/index.md +++ b/docs/features/software-templates/index.md @@ -1,10 +1,11 @@ --- id: software-templates-index -title: Software Templates +title: Backstage Software Templates +sidebar_label: Overview --- The Software Templates part of Backstage is a tool that can help you create -Components inside Backstage. By default, it has the ability to load skeletons of +Components inside Backstage. By default, it has the ability to load skeletons of code, template in some variables, and then publish the template to some location like GitHub. @@ -14,12 +15,15 @@ like GitHub. ### Getting Started -The Software Templates are available under `/create`. If you've followed -[Installing in your Backstage App](./installation.md) in your separate App or -[Getting Started with Backstage](../../getting-started) for this repo, you -should be able to reach `http://localhost:3000/create`. +> Be sure to have covered [Installing in your Backstage App](./installation.md) +> for your separate App or +> [Getting Started with Backstage](../../getting-started) for this repo before +> proceeding. -You should get something that looks similar to this: +The Software Templates are available under `/create`. For local development you +should be able to reach them at `http://localhost:3000/create`. + +Once there, you should see something that looks similar to this: ![Create Image](../../assets/software-templates/create.png) diff --git a/docs/features/software-templates/installation.md b/docs/features/software-templates/installation.md index 73b4f20359..eea78e3571 100644 --- a/docs/features/software-templates/installation.md +++ b/docs/features/software-templates/installation.md @@ -1,4 +1,7 @@ -# Installing in your Backstage App +--- +id: installation +title: Installing in your Backstage App +--- The scaffolder plugin comes in two packages, `@backstage/plugin-scaffolder` and `@backstage/plugin-scaffolder-backend`. Each has their own installation steps, @@ -174,9 +177,6 @@ docs on creating private GitHub access tokens is available Note that the need for private GitHub access tokens will be replaced with GitHub Apps integration further down the line. -> **Right now it is only possible to scaffold repositories inside GitHub -> organizations, and not under personal accounts.** - The GitHub access token is passed along using the `GITHUB_ACCESS_TOKEN` environment variable. diff --git a/docs/features/techdocs/FAQ.md b/docs/features/techdocs/FAQ.md index 1a52a35cfb..cae0288889 100644 --- a/docs/features/techdocs/FAQ.md +++ b/docs/features/techdocs/FAQ.md @@ -6,14 +6,11 @@ sidebar_label: FAQ This page answers frequently asked questions about [TechDocs](README.md). -_Got a question that you think others might be interested in knowing the answer -to? Edit this file -[here](https://github.com/spotify/backstage/edit/master/docs/features/techdocs/FAQ.md)._ - ## Technology -- [What static site generator is TechDocs using?](./#what-static-site-generator-is-techdocs-using) -- [What is the mkdocs-techdocs-core plugin?](./#what-is-the-mkdocs-techdocs-core-plugin) +- [What static site generator is TechDocs using?](#what-static-site-generator-is-techdocs-using) +- [What is the mkdocs-techdocs-core plugin?](#what-is-the-mkdocs-techdocs-core-plugin) +- [Does TechDocs support file formats other than Markdown (e.g. rst, asciidoc)?](#does-techdocs-support-file-formats-other-than-markdown-eg-rst-asciidoc-) #### What static site generator is TechDocs using? @@ -30,3 +27,10 @@ package is a MkDocs Plugin that works like a wrapper around multiple MkDocs plugins (e.g. [MkDocs Monorepo Plugin](https://github.com/spotify/mkdocs-monorepo-plugin)) as well as a selection of Python Markdown extensions that TechDocs supports. + +#### Does TechDocs support file formats other than Markdown (e.g. rst, asciidoc) ? + +Not right now. We are currently using MkDocs to generate the documentation from +source. So, they have to be in Markdown format. However, in future we want to +support other alternatives to MkDocs. That will make it possible to use other +file formats. diff --git a/docs/features/techdocs/README.md b/docs/features/techdocs/README.md index 8bdbd27d3c..03f3d452f4 100644 --- a/docs/features/techdocs/README.md +++ b/docs/features/techdocs/README.md @@ -8,16 +8,21 @@ sidebar_label: Overview -Wait, what is TechDocs? TechDocs is Spotify’s homegrown docs-like-code solution -built directly into Backstage. Today, it is now one of the core products in -Spotify’s developer experience offering with 2,400+ documentation sites and -1,000+ engineers using it daily. +TechDocs is Spotify’s homegrown docs-like-code solution built directly into +Backstage. This means engineers write their documentation in Markdown files +which live together with their code. + +Today, it is one of the core products in Spotify’s developer experience offering +with 2,400+ documentation sites and 1,000+ engineers using it daily. Read more +about TechDocs and the philosophy in its +[announcement blog post](https://backstage.io/blog/2020/09/08/announcing-tech-docs). +🎉 ## Features -- A centralized place to discover documentation. +- A centralized place to discover and read documentation. -- A clear end-to-end docs-like-code solution. (_Coming soon in V.1_) +- A clear end-to-end docs-like-code solution. - A tightly coupled feedback loop with the developer workflow. (_Coming soon in V.3_) @@ -26,12 +31,12 @@ Spotify’s developer experience offering with 2,400+ documentation sites and ## Project roadmap -| Version | Description | -| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| [TechDocs V.0 ✅][v0] | Read docs in Backstage - Enable anyone to get a reader experience working in Backstage. [See V.0 Use Cases.](./#techdocs-v0) | -| [TechDocs V.1 🚧][v1] | TechDocs end to end (alpha) - Alpha of TechDocs that you can use end to end - and contribute to. [See V.1 Use Cases.](./#techdocs-v1) | -| [TechDocs V.2 🔮⌛][v2] | Platform stability and compatibility improvements. [See V.2 Use Cases.](./#techdocs-v2) | -| TechDocs V.3 🔮⌛ | Widget Architecture - TechDocs widget architecture available, so the community can create their own customized features. | +| Version | Description | +| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| [TechDocs V.0 ✅][v0] | Read docs in Backstage - Enable anyone to get a reader experience working in Backstage. [See V.0 Use Cases.](#techdocs-v0) | +| [TechDocs V.1 ✅][v1] | TechDocs end to end (alpha) - Alpha of TechDocs that you can use end to end - and contribute to. [See V.1 Use Cases.](#techdocs-v1) | +| [TechDocs V.2 🔮⌛][v2] | Platform stability and compatibility improvements. [See V.2 Use Cases.](#techdocs-v2) | +| TechDocs V.3 🔮⌛ | Widget Architecture - TechDocs widget architecture available, so the community can create their own customized features. | [v0]: https://github.com/spotify/backstage/milestone/15 [v1]: https://github.com/spotify/backstage/milestone/16 @@ -44,7 +49,7 @@ Spotify’s developer experience offering with 2,400+ documentation sites and #### TechDocs V.0 - As a user I can navigate to a manually curated docs explore page. -- As a user I can navigte to and read mock documentation that is manually +- As a user I can navigate to and read mock documentation that is manually uploaded by the TechDocs core team. #### TechDocs V.1 @@ -101,7 +106,3 @@ more to come... https://github.com/spotify/backstage/blob/master/packages/techdocs-container [techdocs/cli]: https://github.com/spotify/backstage/blob/master/packages/techdocs-cli - -## TechDocs Big Picture - -![TechDocs Big Picture](../..//assets/techdocs/techdocs_big_picture.png) diff --git a/docs/features/techdocs/architecture.md b/docs/features/techdocs/architecture.md new file mode 100644 index 0000000000..4e063a8559 --- /dev/null +++ b/docs/features/techdocs/architecture.md @@ -0,0 +1,6 @@ +--- +id: architecture +title: Architecture +--- + +![TechDocs Big Picture](../../assets/techdocs/techdocs_big_picture.png) diff --git a/docs/features/techdocs/concepts.md b/docs/features/techdocs/concepts.md index 2fa84cebd6..8f5558c0f8 100644 --- a/docs/features/techdocs/concepts.md +++ b/docs/features/techdocs/concepts.md @@ -8,9 +8,9 @@ solution in Backstage. ### TechDocs Core Plugin -The TechDocs Core Plugin is a MkDocs plugin created as a wrapper around multiple -MkDocs plugins and Python Markdown extensions to standardize the configuration -of MkDocs used for TechDocs. +The TechDocs Core Plugin is an [MkDocs](https://www.mkdocs.org/) plugin created +as a wrapper around multiple MkDocs plugins and Python Markdown extensions to +standardize the configuration of MkDocs used for TechDocs. [TechDocs Core](https://github.com/spotify/backstage/blob/master/packages/techdocs-container/techdocs-core/README.md) diff --git a/docs/features/techdocs/creating-and-publishing.md b/docs/features/techdocs/creating-and-publishing.md index 037c4be172..9d93eda9bc 100644 --- a/docs/features/techdocs/creating-and-publishing.md +++ b/docs/features/techdocs/creating-and-publishing.md @@ -11,7 +11,7 @@ This section will guide you through: - [Manually add documentation setup to already existing repository](#manually-add-documentation-setup-to-already-existing-repository) - [Writing and previewing your documentation](#writing-and-previewing-your-documentation) -## Prerequisities +## Prerequisites - A working Backstage instance with TechDocs installed (see [TechDocs getting started](getting-started.md)) @@ -30,11 +30,6 @@ the documentation template. Create an entity from the documentation template and you will get the needed setup for free. -!!! warning Currently the Backstage Software Templates are limited to create repositories -inside GitHub organizations. You also need to generate an personal access token -and use as an environment variable. Read more about this -[here](../software-templates/installation.md#runtime-dependencies). - ### Manually add documentation setup to already existing repository Prerequisities: @@ -81,12 +76,12 @@ updated documentation next time you run Backstage! ## Writing and previewing your documentation Using the `techdocs-cli` you can preview your docs inside a local Backstage -instance and get automatic recompilation on changes. This is useful for when you -want to write your documentation. +instance and get live reload on changes. This is useful when you want to preview +your documentation while writing. To do this you can run: ```bash -cd ~// -npx techdocs-cli serve +cd /path/to/docs-repository/ +npx @techdocs/cli serve ``` diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index 414b3baae8..174894b020 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -6,35 +6,8 @@ title: Getting Started TechDocs functions as a plugin to Backstage, so you will need to use Backstage to use TechDocs. -## What is Backstage? - -Backstage is an open platform for building developer portals. It’s based on the -developer portal we’ve been using internally at Spotify for over four years. -[Read more here](https://github.com/spotify/backstage). - -## Prerequisities - -In order to use Backstage and TechDocs, you need to have the following -installed: - -- [Node.js](https://nodejs.org) Active LTS (long term support), currently v12 -- [Yarn](https://yarnpkg.com/getting-started/install) - -## Creating a new Backstage app - -> If you have already created a Backstage application, jump to -> [Installing TechDocs](#installing-techdocs), otherwise complete this step. - -To create a new Backstage application for TechDocs, run the following command: - -```bash -npx @backstage/cli create-app -``` - -You will then be prompted to enter a name for your application. Once that's -done, a new Backstage application will be created in a new folder. For example, -if you choose the name `hello-world`, a new `hello-world` folder is created -containing your new Backstage application. +If you haven't setup Backstage already, start +[here](../../getting-started/index.md). ## Installing TechDocs @@ -74,17 +47,28 @@ export { plugin as TechDocs } from '@backstage/plugin-techdocs'; ### Setting the configuration TechDocs allows for configuration of the docs storage URL through your -`app-config` file. +`app-config.yaml` file. We provide two different values to be configured, +`requestUrl` and `storageUrl`. The `requestUrl` is what the reader will request +its data from, and `storageUrl` is where the backend can find the stored +documentation. -The default storage URL: +The default storage and request URLs: ```yaml techdocs: storageUrl: http://localhost:7000/techdocs/static/docs + requestUrl: http://localhost:7000/techdocs/docs ``` -If you want to configure this to point to another storage URL, change the value -of `storageUrl`. +If you want `techdocs-backend` to manage building and publishing, you want +`requestUrl` to point to the default value (or wherever `techdocs-backend` is +hosted). `storageUrl` should be where your publisher publishes your docs. Using +the default `LocalPublish` that is the default value. + +If you have a setup where you are not using `techdocs-backend` for managing +building and publishing of your documentation, you want to change the +`requestUrl` to point to your storage. In this case `storageUrl` is not +required. ## Run Backstage locally diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index a0d2c27f89..515b52afa7 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -3,4 +3,34 @@ id: configure-app-with-plugins title: Configuring App with plugins --- +## Adding existing plugins to your app + Coming soon! + +### Adding a plugin page to the Sidebar + +In a standard Backstage app created with +[@backstage/create-app](./create-an-app.md), the sidebar is managed inside +`packages/app/src/sidebar.tsx`. The file exports the entire `Sidebar` element of +your app, which you can extend with additional entries by adding new +`SidebarItem` elements. + +For example, if you install the `api-docs` plugin, a matching `SidebarItem` +could be something like this: + +```tsx +// Import icon from MUI +import ExtensionIcon from '@material-ui/icons/Extension'; + +// ... inside the AppSidebar component +; +``` + +You can also use your own SVGs directly as icon components. Just make sure they +are sized according to the Material UI's +[SvgIcon](https://material-ui.com/api/svg-icon/) default of 24x24px, and set the +extension to `.icon.svg`. For example: + +```ts +import InternalToolIcon from './internal-tool.icon.svg'; +``` diff --git a/docs/getting-started/create-an-app.md b/docs/getting-started/create-an-app.md index fe22935002..cebf3f5de2 100644 --- a/docs/getting-started/create-an-app.md +++ b/docs/getting-started/create-an-app.md @@ -15,7 +15,13 @@ To create a Backstage app, you will need to have [NodeJS](https://nodejs.org/en/download/) Active LTS Release installed (currently v12). -With `npx`: +Backstage provides a utility for creating new apps. It guides you through the +initial setup of selecting the name of the app and a database for the backend. +The database options are either SQLite or PostgreSQL, where the latter requires +you to set up a separate database instance. If in doubt, choose SQLite, but +don't worry about the choice, it's easy to change later! + +The easiest way to run the create app package is with `npx`: ```bash npx @backstage/create-app @@ -25,50 +31,45 @@ This will create a new Backstage App inside the current folder. The name of the app-folder is the name that was provided when prompted.

- create app + create app

Inside that directory, it will generate all the files and folder structure needed for you to run your app. -### Folder structure +### General folder structure + +Below is a simplified layout of the files and folders generated when creating an +app. ``` app -├── README.md +├── app-config.yaml ├── lerna.json ├── package.json -├── prettier.config.js -├── tsconfig.json -├── packages -│ └── app -│ ├── package.json -│ ├── tsconfig.json -│ ├── public -│ │ └── ... -│ └── src -│ ├── App.test.tsx -│ ├── App.tsx -│ ├── index.tsx -│ ├── plugins.ts -│ └── setupTests.ts -└── plugins - └── welcome - ├── README.md - ├── package.json - ├── tsconfig.json - └── src - ├── index.ts - ├── plugin.test.ts - ├── plugin.ts - ├── setupTests.ts - └── components - ├── Timer - │ └── ... - └── WelcomePage - └── ... +└── packages +   ├── app +   └── backend ``` +- **app-config.yaml**: Main configuration file for the app. See + [Configuration](https://backstage.io/docs/conf/) for more information. +- **lerna.json**: Contains information about workspaces and other lerna + configuration needed for the monorepo setup. +- **package.json**: Root package.json for the project. _Note: Be sure that you + don't add any npm dependencies here as they probably should be installed in + the intended workspace rather than in the root._ +- **packages/**: Lerna leaf packages or "workspaces". Everything here is going + to be a separate package, managed by lerna. +- **packages/app/**: An fully functioning Backstage frontend app, that acts as a + good starting point for you to get to know Backstage. +- **packages/backend/**: We include a backend that helps power features such as + [Authentication](https://backstage.io/docs/auth/), + [Software Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview), + [Software Templates](https://backstage.io/docs/features/software-templates/software-templates-index) + and [TechDocs](https://backstage.io/docs/features/techdocs/techdocs-overview) + amongst other things. + ## Run the app When the installation is complete you can open the app folder and start the app. @@ -80,3 +81,13 @@ yarn start _When `yarn start` is ready it should open up a browser window displaying your app, if not you can navigate to `http://localhost:3000`._ + +In most cases you will want to start the backend as well, as it is required for +the catalog to work, along with many other plugins. + +To start the backend, open a separate terminal session and run the following in +the root directory: + +```bash +yarn workspace backend start +``` diff --git a/docs/getting-started/deployment-other.md b/docs/getting-started/deployment-other.md index 3b7796f8fe..d3fb9d932b 100644 --- a/docs/getting-started/deployment-other.md +++ b/docs/getting-started/deployment-other.md @@ -10,21 +10,20 @@ title: Other Run the following commands if you have Docker environment ```bash +$ yarn install $ yarn docker-build -$ docker run --rm -it -p 80:80 spotify/backstage +$ docker run --rm -it -p 7000:7000 -e NODE_ENV=development example-backend:latest ``` Then open http://localhost/ on your browser. ### Running with `docker-compose` -Run the following commands if you have docker and docker-compose for a full -example, with the example backend also deployed. +There is also a `docker-compose.yaml` that you can use to replace the previous +`docker run` command: ```bash -$ yarn docker-build:all +$ yarn install +$ yarn docker-build $ docker-compose up ``` - -Then open http://localhost:3000 on your browser to see the example app with an -example backend. diff --git a/docs/getting-started/development-environment.md b/docs/getting-started/development-environment.md index 421ce6d2c5..9c75c8eabf 100644 --- a/docs/getting-started/development-environment.md +++ b/docs/getting-started/development-environment.md @@ -65,6 +65,7 @@ yarn storybook # Start local storybook, useful for working on components in @bac yarn workspace @backstage/plugin-welcome start # Serve welcome plugin only, also supports --check yarn tsc # Run typecheck, use --watch for watch mode +yarn tsc:full # Run full type checking, for example without skipLibCheck, use in CI yarn build # Build published versions of packages, depends on tsc diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index abe7776371..c528ad34ad 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -1,83 +1,50 @@ --- id: index -title: Running Backstage Locally +title: Getting Started --- -First make sure you are using NodeJS with an Active LTS Release, currently v12. -This is made easy with a version manager such as nvm which allows for version switching. +There are two different ways to get started with Backstage, either by creating a +standalone app, or by cloning this repo. Which method you use depends on what +you're planning to do. + +Creating a standalone instance makes it simpler to customize the application for +your needs whilst staying up to date with the project. You will also depend on +`@backstage` packages from NPM, making the project much smaller. This is the +recommended approach if you want to kick the tyres of Backstage or setup your +own instance. + +On the other hand, if you want to contribute plugins or to the project in +general, it's easier to fork and clone this project. That will let you stay up +to date with the latest changes, and gives you an easier path to make Pull +Requests towards this repo. + +### Creating a Standalone App + +Backstage provides the `@backstage/create-app` package to scaffold standalone +instances of Backstage. You will need to have +[NodeJS](https://nodejs.org/en/download/) Active LTS Release installed +(currently v12), and [yarn](https://classic.yarnpkg.com/en/docs/install). You +will also need to have [Docker](https://docs.docker.com/engine/install/) +installed to use some features like Software Templates and TechDocs. + +Using `npx` you can then run the following to create an app in a chosen +subdirectory of your current working directory: ```bash -# Checking your version -node --version -> v14.7.0 - -# Adding a second node version -nvm install 12 -> Downloading and installing node v12.18.3... -> Now using node v12.18.3 (npm v6.14.6) +npx @backstage/create-app ``` -To get up and running with a local Backstage to evaluate it, let's clone it off -of GitHub and run an initial build. +You will be taken through a wizard to create your app, and the output should +look something like this. You can read more about this process +[here](https://backstage.io/docs/getting-started/create-an-app). -```bash -# Start from your local development folder -git clone git@github.com:spotify/backstage.git -cd backstage +### Contributing to Backstage -# Fetch our dependencies and run an initial build -yarn install -yarn tsc -yarn build -``` +You can read more in our +[CONTRIBUTING](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md) +guide, which can help you get setup with a Backstage development environment. -Phew! Now you have a local repository that's ready to run and to add any open -source contributions into. +### Next steps -We are now going to launch two things: an example Backstage frontend app, and an -example Backstage backend that the frontend talks to. You are going to need two -terminal windows, both starting from the Backstage project root. - -In the first window, run - -```bash -cd packages/backend -yarn start -``` - -That starts up a backend instance on port 7000. - -In the other window, we will first populate the catalog with some nice mock data -to look at, and then launch the frontend. These commands are run from the -project root, not inside the backend directory. - -```bash -yarn lerna run mock-data -yarn start -``` - -That starts up the frontend on port 3000, and should automatically open a -browser window showing it. - -Congratulations! That should be it. Let us know how it went -[on discord](https://discord.gg/EBHEGzX), file issues for any -[feature](https://github.com/spotify/backstage/issues/new?labels=help+wanted&template=feature_template.md) -or -[plugin suggestions](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME), -or -[bugs](https://github.com/spotify/backstage/issues/new?labels=bug&template=bug_template.md) -you have, and feel free to -[contribute](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md)! - -## Creating a Plugin - -The value of Backstage grows with every new plugin that gets added. Here is a -collection of tutorials that will guide you through setting up and extending an -instance of Backstage with your own plugins. - -- [Development Environment](development-environment.md) -- [Create a Backstage Plugin](../plugins/create-a-plugin.md) -- [Structure of a Plugin](../plugins/structure-of-a-plugin.md) -- [Utility APIs](../api/utility-apis.md) - -[Back to Docs](../README.md) +Take a look at the [Running Backstage Locally](./running-backstage-locally.md) +guide to learn how to set up Backstage, and how to develop on the platform. diff --git a/docs/getting-started/running-backstage-locally.md b/docs/getting-started/running-backstage-locally.md new file mode 100644 index 0000000000..08d2ab385b --- /dev/null +++ b/docs/getting-started/running-backstage-locally.md @@ -0,0 +1,91 @@ +--- +id: running-backstage-locally +title: Running Backstage Locally +--- + +First make sure you are using NodeJS with an Active LTS Release, currently v12. +This is made easy with a version manager such as +[nvm](https://github.com/nvm-sh/nvm) which allows for version switching. + +```bash +# Checking your version +node --version +> v14.7.0 + +# Adding a second node version +nvm install 12 +> Downloading and installing node v12.18.3... +> Now using node v12.18.3 (npm v6.14.6) +``` + +To get up and running with a local Backstage to evaluate it, let's clone it off +of GitHub and run an initial build. + +```bash +# Start from your local development folder +git clone git@github.com:spotify/backstage.git +cd backstage + +# Fetch our dependencies and run an initial build +yarn install +yarn tsc +yarn build +``` + +Phew! Now you have a local repository that's ready to run and to add any open +source contributions into. + +We are now going to launch two things: an example Backstage frontend app, and an +example Backstage backend that the frontend talks to. You are going to need two +terminal windows, both starting from the Backstage project root. + +In the first window, run + +```bash +cd packages/backend +yarn start +``` + +That starts up a backend instance on port 7000. + +In the other window, we will then launch the frontend. This command is run from +the project root, not inside the backend directory. + +```bash +yarn start +``` + +That starts up the frontend on port 3000, and should automatically open a +browser window showing it. + +## Authentication + +When Backstage starts, you can choose to enter as a Guest user and start +exploring. + +But you can also set up any of the available authentication methods. The easiest +option will be GitHub. To setup GitHub authentication in Backstage, see +[these instructions](https://github.com/spotify/backstage/tree/master/plugins/auth-backend#github). + +--- + +Congratulations! That should be it. Let us know how it went +[on discord](https://discord.gg/EBHEGzX), file issues for any +[feature](https://github.com/spotify/backstage/issues/new?labels=help+wanted&template=feature_template.md) +or +[plugin suggestions](https://github.com/spotify/backstage/issues/new?labels=plugin&template=plugin_template.md&title=%5BPlugin%5D+THE+PLUGIN+NAME), +or +[bugs](https://github.com/spotify/backstage/issues/new?labels=bug&template=bug_template.md) +you have, and feel free to +[contribute](https://github.com/spotify/backstage/blob/master/CONTRIBUTING.md)! + +## Creating a Plugin + +The value of Backstage grows with every new plugin that gets added. Here is a +collection of tutorials that will guide you through setting up and extending an +instance of Backstage with your own plugins. + +- [Development Environment](development-environment.md) +- [Create a Backstage Plugin](../plugins/create-a-plugin.md) +- [Structure of a Plugin](../plugins/structure-of-a-plugin.md) +- [Utility APIs](../api/utility-apis.md) diff --git a/docs/overview/architecture-overview.md b/docs/overview/architecture-overview.md index 9f1d6d3291..55a1aeec04 100644 --- a/docs/overview/architecture-overview.md +++ b/docs/overview/architecture-overview.md @@ -171,21 +171,19 @@ The frontend container can be built with a provided command. ```bash yarn install yarn tsc -yarn build -yarn run docker-build +yarn run docker-build:app ``` Running this will simply generate a Docker container containing the contents of -the UIs `dist` directory. The resulting container will be about 50MB in size. +the UIs `dist` directory. -The backend container can be built by running the following command in the -`packages/backend` directory. +The backend container can be built by running the following command: ```bash -yarn run build-image +yarn run docker-build ``` -This will create a ~500MB container called `example-backend`. +This will create a container called `example-backend`. The lighthouse-audit-service container is already publicly available in Docker Hub and can be downloaded and ran with diff --git a/docs/overview/logos.md b/docs/overview/logos.md new file mode 100644 index 0000000000..39071ed793 --- /dev/null +++ b/docs/overview/logos.md @@ -0,0 +1,41 @@ +--- +id: logos +title: Logos +sidebar_label: Logo assets +--- + +Guidelines for how to use the Backstage logo and icon can be found +[here](/logo_assets/Backstage_Identity_Assets_Overview.pdf). The assets below +are all in `.svg` format. Other formats are available in the +[repository](https://github.com/spotify/backstage/tree/master/microsite/static/logo_assets). + +## Backstage logo + + + + + + + + + + + + + +## Backstage icon + + diff --git a/docs/plugins/proxying.md b/docs/plugins/proxying.md index 658df3dda1..1951f41763 100644 --- a/docs/plugins/proxying.md +++ b/docs/plugins/proxying.md @@ -52,7 +52,10 @@ configuration will lead to the proxy acting on backend requests to The value inside each route is either a simple URL string, or an object on the format accepted by -[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware). +[http-proxy-middleware](https://www.npmjs.com/package/http-proxy-middleware). It +is also possible to limit the forwarded HTTP methods with the configuration +`allowedMethods`, for example `allowedMethods: ['GET']` to enforce read-only +access. If the value is a string, it is assumed to correspond to: diff --git a/docs/reference/utility-apis/AlertApi.md b/docs/reference/utility-apis/AlertApi.md index 3490c1900e..d000a6d6a2 100644 --- a/docs/reference/utility-apis/AlertApi.md +++ b/docs/reference/utility-apis/AlertApi.md @@ -1,7 +1,7 @@ # AlertApi The AlertApi type is defined at -[packages/core-api/src/apis/definitions/AlertApi.ts:29](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/AlertApi.ts#L29). +[packages/core-api/src/apis/definitions/AlertApi.ts:29](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/AlertApi.ts#L29). The following Utility API implements this type: [alertApiRef](./README.md#alert) @@ -38,7 +38,7 @@ export type AlertMessage = { Defined at -[packages/core-api/src/apis/definitions/AlertApi.ts:19](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/AlertApi.ts#L19). +[packages/core-api/src/apis/definitions/AlertApi.ts:19](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/AlertApi.ts#L19). Referenced by: [post](#post), [alert\$](#alert). @@ -67,7 +67,7 @@ export type Observable<T> = { Defined at -[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L53). +[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L53). Referenced by: [alert\$](#alert). @@ -86,7 +86,7 @@ export type Observer<T> = { Defined at -[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L24). +[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L24). Referenced by: [Observable](#observable). @@ -109,6 +109,6 @@ export type Subscription = { Defined at -[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L33). +[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L33). Referenced by: [Observable](#observable). diff --git a/docs/reference/utility-apis/AppThemeApi.md b/docs/reference/utility-apis/AppThemeApi.md index eda1bafef0..e7d5296ceb 100644 --- a/docs/reference/utility-apis/AppThemeApi.md +++ b/docs/reference/utility-apis/AppThemeApi.md @@ -1,7 +1,7 @@ # AppThemeApi The AppThemeApi type is defined at -[packages/core-api/src/apis/definitions/AppThemeApi.ts:50](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/AppThemeApi.ts#L50). +[packages/core-api/src/apis/definitions/AppThemeApi.ts:50](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/AppThemeApi.ts#L50). The following Utility API implements this type: [appThemeApiRef](./README.md#apptheme) @@ -76,7 +76,7 @@ export type AppTheme = { Defined at -[packages/core-api/src/apis/definitions/AppThemeApi.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/AppThemeApi.ts#L24). +[packages/core-api/src/apis/definitions/AppThemeApi.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/AppThemeApi.ts#L24). Referenced by: [getInstalledThemes](#getinstalledthemes). @@ -87,7 +87,7 @@ export type BackstagePalette = Palette & Palette Defined at -[packages/theme/src/types.ts:67](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/theme/src/types.ts#L67). +[packages/theme/src/types.ts:70](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/theme/src/types.ts#L70). Referenced by: [BackstageTheme](#backstagetheme). @@ -100,7 +100,7 @@ export interface BackstageTheme extends Theme { Defined at -[packages/theme/src/types.ts:70](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/theme/src/types.ts#L70). +[packages/theme/src/types.ts:73](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/theme/src/types.ts#L73). Referenced by: [AppTheme](#apptheme). @@ -129,7 +129,7 @@ export type Observable<T> = { Defined at -[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L53). +[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L53). Referenced by: [activeThemeId\$](#activethemeid). @@ -148,7 +148,7 @@ export type Observer<T> = { Defined at -[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L24). +[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L24). Referenced by: [Observable](#observable). @@ -204,7 +204,7 @@ type PaletteAdditions = { Defined at -[packages/theme/src/types.ts:23](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/theme/src/types.ts#L23). +[packages/theme/src/types.ts:23](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/theme/src/types.ts#L23). Referenced by: [BackstagePalette](#backstagepalette). @@ -227,6 +227,6 @@ export type Subscription = { Defined at -[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L33). +[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L33). Referenced by: [Observable](#observable). diff --git a/docs/reference/utility-apis/BackstageIdentityApi.md b/docs/reference/utility-apis/BackstageIdentityApi.md index f75918a8b3..87318ecff5 100644 --- a/docs/reference/utility-apis/BackstageIdentityApi.md +++ b/docs/reference/utility-apis/BackstageIdentityApi.md @@ -1,16 +1,20 @@ # BackstageIdentityApi The BackstageIdentityApi type is defined at -[packages/core-api/src/apis/definitions/auth.ts:144](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L144). +[packages/core-api/src/apis/definitions/auth.ts:144](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L144). The following Utility APIs implement this type: +- [auth0AuthApiRef](./README.md#auth0auth) + - [githubAuthApiRef](./README.md#githubauth) - [gitlabAuthApiRef](./README.md#gitlabauth) - [googleAuthApiRef](./README.md#googleauth) +- [microsoftAuthApiRef](./README.md#microsoftauth) + - [oktaAuthApiRef](./README.md#oktaauth) ## Members @@ -62,7 +66,7 @@ export type AuthRequestOptions = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L40). +[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L40). Referenced by: [getBackstageIdentity](#getbackstageidentity). @@ -83,6 +87,6 @@ export type BackstageIdentity = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:157](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L157). +[packages/core-api/src/apis/definitions/auth.ts:157](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L157). Referenced by: [getBackstageIdentity](#getbackstageidentity). diff --git a/docs/reference/utility-apis/Config.md b/docs/reference/utility-apis/Config.md index c0264489fc..9374fb9962 100644 --- a/docs/reference/utility-apis/Config.md +++ b/docs/reference/utility-apis/Config.md @@ -1,13 +1,19 @@ # Config The Config type is defined at -[packages/config/src/types.ts:32](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/config/src/types.ts#L32). +[packages/config/src/types.ts:32](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/config/src/types.ts#L32). The following Utility API implements this type: [configApiRef](./README.md#config) ## Members +### has() + +
+has(key: string): boolean
+
+ ### keys()
@@ -17,13 +23,13 @@ keys(): string[]
 ### get()
 
 
-get(key: string): JsonValue
+get(key?: string): JsonValue
 
### getOptional()
-getOptional(key: string): JsonValue | undefined
+getOptional(key?: string): JsonValue | undefined
 
### getConfig() @@ -106,10 +112,12 @@ These types are part of the API declaration, but may not be unique to this API.
 export type Config = {
+  has(key: string): boolean;
+
   keys(): string[];
 
-  get(key: string): JsonValue;
-  getOptional(key: string): JsonValue | undefined;
+  get(key?: string): JsonValue;
+  getOptional(key?: string): JsonValue | undefined;
 
   getConfig(key: string): Config;
   getOptionalConfig(key: string): Config | undefined;
@@ -132,7 +140,7 @@ export type Config = {
 
Defined at -[packages/config/src/types.ts:32](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/config/src/types.ts#L32). +[packages/config/src/types.ts:32](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/config/src/types.ts#L32). Referenced by: [getConfig](#getconfig), [getOptionalConfig](#getoptionalconfig), [getConfigArray](#getconfigarray), @@ -145,7 +153,7 @@ export type JsonArray = JsonValue[]
Defined at -[packages/config/src/types.ts:18](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/config/src/types.ts#L18). +[packages/config/src/types.ts:18](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/config/src/types.ts#L18). Referenced by: [JsonValue](#jsonvalue). @@ -156,7 +164,7 @@ export type JsonObject = { [key in string]?: JsonValue Defined at -[packages/config/src/types.ts:17](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/config/src/types.ts#L17). +[packages/config/src/types.ts:17](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/config/src/types.ts#L17). Referenced by: [JsonValue](#jsonvalue). @@ -173,7 +181,7 @@ export type JsonValue = Defined at -[packages/config/src/types.ts:19](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/config/src/types.ts#L19). +[packages/config/src/types.ts:19](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/config/src/types.ts#L19). Referenced by: [get](#get), [getOptional](#getoptional), [JsonObject](#jsonobject), [JsonArray](#jsonarray), [Config](#config). diff --git a/docs/reference/utility-apis/DiscoveryApi.md b/docs/reference/utility-apis/DiscoveryApi.md new file mode 100644 index 0000000000..39902789cd --- /dev/null +++ b/docs/reference/utility-apis/DiscoveryApi.md @@ -0,0 +1,24 @@ +# DiscoveryApi + +The DiscoveryApi type is defined at +[packages/core-api/src/apis/definitions/DiscoveryApi.ts:30](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/DiscoveryApi.ts#L30). + +The following Utility API implements this type: +[discoveryApiRef](./README.md#discovery) + +## Members + +### getBaseUrl() + +Returns the HTTP base backend URL for a given plugin, without a trailing slash. + +This method must always be called just before making a request. as opposed to +fetching the URL when constructing an API client. That is to ensure that more +flexible routing patterns can be supported. + +For example, asking for the URL for `auth` may return something like +`https://backstage.example.com/api/auth` + +
+getBaseUrl(pluginId: string): Promise<string>
+
diff --git a/docs/reference/utility-apis/ErrorApi.md b/docs/reference/utility-apis/ErrorApi.md index a630e65592..c05f060ec3 100644 --- a/docs/reference/utility-apis/ErrorApi.md +++ b/docs/reference/utility-apis/ErrorApi.md @@ -1,7 +1,7 @@ # ErrorApi The ErrorApi type is defined at -[packages/core-api/src/apis/definitions/ErrorApi.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/ErrorApi.ts#L53). +[packages/core-api/src/apis/definitions/ErrorApi.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/ErrorApi.ts#L53). The following Utility API implements this type: [errorApiRef](./README.md#error) @@ -41,7 +41,7 @@ type Error = { Defined at -[packages/core-api/src/apis/definitions/ErrorApi.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/ErrorApi.ts#L24). +[packages/core-api/src/apis/definitions/ErrorApi.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/ErrorApi.ts#L24). Referenced by: [post](#post), [error\$](#error). @@ -58,7 +58,7 @@ export type ErrorContext = { Defined at -[packages/core-api/src/apis/definitions/ErrorApi.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/ErrorApi.ts#L33). +[packages/core-api/src/apis/definitions/ErrorApi.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/ErrorApi.ts#L33). Referenced by: [post](#post), [error\$](#error). @@ -87,7 +87,7 @@ export type Observable<T> = { Defined at -[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L53). +[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L53). Referenced by: [error\$](#error). @@ -106,7 +106,7 @@ export type Observer<T> = { Defined at -[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L24). +[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L24). Referenced by: [Observable](#observable). @@ -129,6 +129,6 @@ export type Subscription = { Defined at -[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L33). +[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L33). Referenced by: [Observable](#observable). diff --git a/docs/reference/utility-apis/FeatureFlagsApi.md b/docs/reference/utility-apis/FeatureFlagsApi.md index 16e30a1c60..5efdb176a4 100644 --- a/docs/reference/utility-apis/FeatureFlagsApi.md +++ b/docs/reference/utility-apis/FeatureFlagsApi.md @@ -1,7 +1,7 @@ # FeatureFlagsApi The FeatureFlagsApi type is defined at -[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:41](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L41). +[packages/core-api/src/apis/definitions/FeatureFlagsApi.ts:41](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L41). The following Utility API implements this type: [featureFlagsApiRef](./README.md#featureflags) diff --git a/docs/reference/utility-apis/IdentityApi.md b/docs/reference/utility-apis/IdentityApi.md index f26ad4b6b3..4e37ad5300 100644 --- a/docs/reference/utility-apis/IdentityApi.md +++ b/docs/reference/utility-apis/IdentityApi.md @@ -1,7 +1,7 @@ # IdentityApi The IdentityApi type is defined at -[packages/core-api/src/apis/definitions/IdentityApi.ts:22](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/IdentityApi.ts#L22). +[packages/core-api/src/apis/definitions/IdentityApi.ts:22](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/IdentityApi.ts#L22). The following Utility API implements this type: [identityApiRef](./README.md#identity) @@ -76,6 +76,6 @@ export type ProfileInfo = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:172](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L172). +[packages/core-api/src/apis/definitions/auth.ts:172](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L172). Referenced by: [getProfile](#getprofile). diff --git a/docs/reference/utility-apis/OAuthApi.md b/docs/reference/utility-apis/OAuthApi.md index 766124ccb4..e73d5f645f 100644 --- a/docs/reference/utility-apis/OAuthApi.md +++ b/docs/reference/utility-apis/OAuthApi.md @@ -1,7 +1,7 @@ # OAuthApi The OAuthApi type is defined at -[packages/core-api/src/apis/definitions/auth.ts:67](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L67). +[packages/core-api/src/apis/definitions/auth.ts:67](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L67). The following Utility APIs implement this type: @@ -11,6 +11,8 @@ The following Utility APIs implement this type: - [googleAuthApiRef](./README.md#googleauth) +- [microsoftAuthApiRef](./README.md#microsoftauth) + - [oauth2ApiRef](./README.md#oauth2) - [oktaAuthApiRef](./README.md#oktaauth) @@ -88,7 +90,7 @@ export type AuthRequestOptions = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L40). +[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L40). Referenced by: [getAccessToken](#getaccesstoken). @@ -114,6 +116,6 @@ export type OAuthScope = string | string[] Defined at -[packages/core-api/src/apis/definitions/auth.ts:38](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L38). +[packages/core-api/src/apis/definitions/auth.ts:38](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L38). Referenced by: [getAccessToken](#getaccesstoken). diff --git a/docs/reference/utility-apis/OAuthRequestApi.md b/docs/reference/utility-apis/OAuthRequestApi.md index b3e0d0d979..c6b9e09189 100644 --- a/docs/reference/utility-apis/OAuthRequestApi.md +++ b/docs/reference/utility-apis/OAuthRequestApi.md @@ -1,7 +1,7 @@ # OAuthRequestApi The OAuthRequestApi type is defined at -[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:99](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L99). +[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:99](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L99). The following Utility API implements this type: [oauthRequestApiRef](./README.md#oauthrequest) @@ -72,7 +72,7 @@ export type AuthProvider = { Defined at -[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:27](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L27). +[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:27](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L27). Referenced by: [AuthRequesterOptions](#authrequesteroptions), [PendingAuthRequest](#pendingauthrequest). @@ -96,7 +96,7 @@ export type AuthRequester<AuthResponse> = ( Defined at -[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:66](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L66). +[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:66](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L66). Referenced by: [createAuthRequester](#createauthrequester). @@ -121,7 +121,7 @@ export type AuthRequesterOptions<AuthResponse> = { Defined at -[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:43](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L43). +[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:43](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L43). Referenced by: [createAuthRequester](#createauthrequester). @@ -150,7 +150,7 @@ export type Observable<T> = { Defined at -[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L53). +[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L53). Referenced by: [authRequest\$](#authrequest). @@ -169,7 +169,7 @@ export type Observer<T> = { Defined at -[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L24). +[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L24). Referenced by: [Observable](#observable). @@ -204,7 +204,7 @@ export type PendingAuthRequest = { Defined at -[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:77](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L77). +[packages/core-api/src/apis/definitions/OAuthRequestApi.ts:77](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L77). Referenced by: [authRequest\$](#authrequest). @@ -227,6 +227,6 @@ export type Subscription = { Defined at -[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L33). +[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L33). Referenced by: [Observable](#observable). diff --git a/docs/reference/utility-apis/OpenIdConnectApi.md b/docs/reference/utility-apis/OpenIdConnectApi.md index 7bc571ecb9..41a3247af6 100644 --- a/docs/reference/utility-apis/OpenIdConnectApi.md +++ b/docs/reference/utility-apis/OpenIdConnectApi.md @@ -1,12 +1,16 @@ # OpenIdConnectApi The OpenIdConnectApi type is defined at -[packages/core-api/src/apis/definitions/auth.ts:104](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L104). +[packages/core-api/src/apis/definitions/auth.ts:104](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L104). The following Utility APIs implement this type: +- [auth0AuthApiRef](./README.md#auth0auth) + - [googleAuthApiRef](./README.md#googleauth) +- [microsoftAuthApiRef](./README.md#microsoftauth) + - [oauth2ApiRef](./README.md#oauth2) - [oktaAuthApiRef](./README.md#oktaauth) @@ -70,6 +74,6 @@ export type AuthRequestOptions = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L40). +[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L40). Referenced by: [getIdToken](#getidtoken). diff --git a/docs/reference/utility-apis/ProfileInfoApi.md b/docs/reference/utility-apis/ProfileInfoApi.md index 68b0dea194..09c0f88f83 100644 --- a/docs/reference/utility-apis/ProfileInfoApi.md +++ b/docs/reference/utility-apis/ProfileInfoApi.md @@ -1,16 +1,20 @@ # ProfileInfoApi The ProfileInfoApi type is defined at -[packages/core-api/src/apis/definitions/auth.ts:127](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L127). +[packages/core-api/src/apis/definitions/auth.ts:127](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L127). The following Utility APIs implement this type: +- [auth0AuthApiRef](./README.md#auth0auth) + - [githubAuthApiRef](./README.md#githubauth) - [gitlabAuthApiRef](./README.md#gitlabauth) - [googleAuthApiRef](./README.md#googleauth) +- [microsoftAuthApiRef](./README.md#microsoftauth) + - [oauth2ApiRef](./README.md#oauth2) - [oktaAuthApiRef](./README.md#oktaauth) @@ -61,7 +65,7 @@ export type AuthRequestOptions = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L40). +[packages/core-api/src/apis/definitions/auth.ts:40](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L40). Referenced by: [getProfile](#getprofile). @@ -89,6 +93,6 @@ export type ProfileInfo = { Defined at -[packages/core-api/src/apis/definitions/auth.ts:172](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L172). +[packages/core-api/src/apis/definitions/auth.ts:172](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L172). Referenced by: [getProfile](#getprofile). diff --git a/docs/reference/utility-apis/README.md b/docs/reference/utility-apis/README.md index 521628fd33..cfdc3b6ef8 100644 --- a/docs/reference/utility-apis/README.md +++ b/docs/reference/utility-apis/README.md @@ -1,59 +1,77 @@ ---- -id: README -title: Utility API References ---- +# Backstage Core Utility APIs The following is a list of all Utility APIs defined by `@backstage/core`. They are available to use by plugins and components, and can be accessed using the `useApi` hook, also provided by `@backstage/core`. For more information, see https://github.com/spotify/backstage/blob/master/docs/api/utility-apis.md. -## alert +### alert Used to report alerts and forward them to the app Implemented type: [AlertApi](./AlertApi.md) ApiRef: -[alertApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/AlertApi.ts#L41) +[alertApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/AlertApi.ts#L41) -## appTheme +### appTheme API Used to configure the app theme, and enumerate options Implemented type: [AppThemeApi](./AppThemeApi.md) ApiRef: -[appThemeApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/AppThemeApi.ts#L74) +[appThemeApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/AppThemeApi.ts#L74) -## config +### auth0Auth + +Provides authentication towards Auth0 APIs + +Implemented types: [OpenIdConnectApi](./OpenIdConnectApi.md), +[ProfileInfoApi](./ProfileInfoApi.md), +[BackstageIdentityApi](./BackstageIdentityApi.md), +[SessionStateApi](./SessionStateApi.md) + +ApiRef: +[auth0AuthApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L273) + +### config Used to access runtime configuration Implemented type: [Config](./Config.md) ApiRef: -[configApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/ConfigApi.ts#L22) +[configApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/ConfigApi.ts#L22) -## error +### discovery + +Provides service discovery of backend plugins + +Implemented type: [DiscoveryApi](./DiscoveryApi.md) + +ApiRef: +[discoveryApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/DiscoveryApi.ts#L44) + +### error Used to report errors and forward them to the app Implemented type: [ErrorApi](./ErrorApi.md) ApiRef: -[errorApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/ErrorApi.ts#L65) +[errorApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/ErrorApi.ts#L65) -## featureFlags +### featureFlags Used to toggle functionality in features across Backstage Implemented type: [FeatureFlagsApi](./FeatureFlagsApi.md) ApiRef: -[featureFlagsApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L58) +[featureFlagsApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/FeatureFlagsApi.ts#L58) -## githubAuth +### githubAuth Provides authentication towards GitHub APIs @@ -63,9 +81,9 @@ Implemented types: [OAuthApi](./OAuthApi.md), [SessionStateApi](./SessionStateApi.md) ApiRef: -[githubAuthApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L230) +[githubAuthApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L230) -## gitlabAuth +### gitlabAuth Provides authentication towards GitLab APIs @@ -75,9 +93,9 @@ Implemented types: [OAuthApi](./OAuthApi.md), [SessionStateApi](./SessionStateApi.md) ApiRef: -[gitlabAuthApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L260) +[gitlabAuthApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L260) -## googleAuth +### googleAuth Provides authentication towards Google APIs and identities @@ -88,18 +106,31 @@ Implemented types: [OAuthApi](./OAuthApi.md), [SessionStateApi](./SessionStateApi.md) ApiRef: -[googleAuthApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L213) +[googleAuthApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L213) -## identity +### identity Provides access to the identity of the signed in user Implemented type: [IdentityApi](./IdentityApi.md) ApiRef: -[identityApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/IdentityApi.ts#L54) +[identityApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/IdentityApi.ts#L54) -## oauth2 +### microsoftAuth + +Provides authentication towards Microsoft APIs and identities + +Implemented types: [OAuthApi](./OAuthApi.md), +[OpenIdConnectApi](./OpenIdConnectApi.md), +[ProfileInfoApi](./ProfileInfoApi.md), +[BackstageIdentityApi](./BackstageIdentityApi.md), +[SessionStateApi](./SessionStateApi.md) + +ApiRef: +[microsoftAuthApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L287) + +### oauth2 Example of how to use oauth2 custom provider @@ -108,18 +139,18 @@ Implemented types: [OAuthApi](./OAuthApi.md), [ProfileInfoApi](./ProfileInfoApi.md), [SessionStateApi](./SessionStateApi.md) ApiRef: -[oauth2ApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L270) +[oauth2ApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L301) -## oauthRequest +### oauthRequest An API for implementing unified OAuth flows in Backstage Implemented type: [OAuthRequestApi](./OAuthRequestApi.md) ApiRef: -[oauthRequestApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L130) +[oauthRequestApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/OAuthRequestApi.ts#L130) -## oktaAuth +### oktaAuth Provides authentication towards Okta APIs @@ -130,13 +161,13 @@ Implemented types: [OAuthApi](./OAuthApi.md), [SessionStateApi](./SessionStateApi.md) ApiRef: -[oktaAuthApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L243) +[oktaAuthApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L243) -## storage +### storage Provides the ability to store data which is unique to the user Implemented type: [StorageApi](./StorageApi.md) ApiRef: -[storageApiRef](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/StorageApi.ts#L68) +[storageApiRef](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/StorageApi.ts#L68) diff --git a/docs/reference/utility-apis/SessionStateApi.md b/docs/reference/utility-apis/SessionStateApi.md index 44d329304a..c1821f2381 100644 --- a/docs/reference/utility-apis/SessionStateApi.md +++ b/docs/reference/utility-apis/SessionStateApi.md @@ -1,16 +1,20 @@ # SessionStateApi The SessionStateApi type is defined at -[packages/core-api/src/apis/definitions/auth.ts:201](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L201). +[packages/core-api/src/apis/definitions/auth.ts:201](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L201). The following Utility APIs implement this type: +- [auth0AuthApiRef](./README.md#auth0auth) + - [githubAuthApiRef](./README.md#githubauth) - [gitlabAuthApiRef](./README.md#gitlabauth) - [googleAuthApiRef](./README.md#googleauth) +- [microsoftAuthApiRef](./README.md#microsoftauth) + - [oauth2ApiRef](./README.md#oauth2) - [oktaAuthApiRef](./README.md#oktaauth) @@ -52,7 +56,7 @@ export type Observable<T> = { Defined at -[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L53). +[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L53). Referenced by: [sessionState\$](#sessionstate). @@ -71,7 +75,7 @@ export type Observer<T> = { Defined at -[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L24). +[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L24). Referenced by: [Observable](#observable). @@ -87,7 +91,7 @@ export enum SessionState { Defined at -[packages/core-api/src/apis/definitions/auth.ts:192](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/auth.ts#L192). +[packages/core-api/src/apis/definitions/auth.ts:192](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/auth.ts#L192). Referenced by: [sessionState\$](#sessionstate). @@ -110,6 +114,6 @@ export type Subscription = { Defined at -[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L33). +[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L33). Referenced by: [Observable](#observable). diff --git a/docs/reference/utility-apis/StorageApi.md b/docs/reference/utility-apis/StorageApi.md index 5bc871e7bf..bee52935da 100644 --- a/docs/reference/utility-apis/StorageApi.md +++ b/docs/reference/utility-apis/StorageApi.md @@ -1,7 +1,7 @@ # StorageApi The StorageApi type is defined at -[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/StorageApi.ts#L31). +[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/StorageApi.ts#L31). The following Utility API implements this type: [storageApiRef](./README.md#storage) @@ -79,7 +79,7 @@ export type Observable<T> = { Defined at -[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L53). +[packages/core-api/src/types.ts:53](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L53). Referenced by: [observe\$](#observe), [StorageApi](#storageapi). @@ -98,7 +98,7 @@ export type Observer<T> = { Defined at -[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L24). +[packages/core-api/src/types.ts:24](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L24). Referenced by: [Observable](#observable). @@ -144,7 +144,7 @@ export interface StorageApi { Defined at -[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/StorageApi.ts#L31). +[packages/core-api/src/apis/definitions/StorageApi.ts:31](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/StorageApi.ts#L31). Referenced by: [forBucket](#forbucket). @@ -158,7 +158,7 @@ export type StorageValueChange<T = any> = { Defined at -[packages/core-api/src/apis/definitions/StorageApi.ts:21](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/apis/definitions/StorageApi.ts#L21). +[packages/core-api/src/apis/definitions/StorageApi.ts:21](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/apis/definitions/StorageApi.ts#L21). Referenced by: [observe\$](#observe), [StorageApi](#storageapi). @@ -181,6 +181,6 @@ export type Subscription = { Defined at -[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/f8780ff32509d0326bc513791ea60846d7614b34/packages/core-api/src/types.ts#L33). +[packages/core-api/src/types.ts:33](https://github.com/spotify/backstage/blob/82d329555c16af46db9b4e5cd2f44a3cc006a52e/packages/core-api/src/types.ts#L33). Referenced by: [Observable](#observable). diff --git a/docs/verify-links.js b/docs/verify-links.js index a218cde71b..9bf8a67ad8 100755 --- a/docs/verify-links.js +++ b/docs/verify-links.js @@ -53,6 +53,11 @@ async function verifyUrl(basePath, url) { return { url, basePath, problem: 'not-relative' }; } + const staticPath = resolvePath(projectRoot, 'microsite/static', `.${url}`); + if (await fs.pathExists(staticPath)) { + return; + } + path = resolvePath(projectRoot, `.${url}`); } else { path = resolvePath(dirname(resolvePath(projectRoot, basePath)), url); @@ -103,7 +108,9 @@ async function main() { console.log(`Found ${badUrls.length} bad links within repo`); for (const { url, basePath, problem } of badUrls) { if (problem === 'missing') { - console.error(`Unable to reach ${url}, linked from ${basePath}`); + console.error( + `Unable to reach ${url} from root or microsite/static/, linked from ${basePath}`, + ); } else if (problem === 'not-relative') { console.error('Links to /docs/ must be relative'); console.error(` From: ${basePath}`); diff --git a/install/kubernetes/app.yaml b/install/kubernetes/app.yaml index ce284afd31..c54e25d519 100644 --- a/install/kubernetes/app.yaml +++ b/install/kubernetes/app.yaml @@ -18,10 +18,10 @@ spec: component: frontend spec: containers: - - name: app - image: spotify/backstage:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 80 - name: app - protocol: TCP + - name: app + image: spotify/backstage:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 + name: app + protocol: TCP diff --git a/install/kubernetes/backend.yaml b/install/kubernetes/backend.yaml index bc82731958..f0695753fd 100644 --- a/install/kubernetes/backend.yaml +++ b/install/kubernetes/backend.yaml @@ -18,10 +18,10 @@ spec: component: backend spec: containers: - - name: backend - image: spotify/backstage-backend:latest - imagePullPolicy: IfNotPresent - ports: - - containerPort: 7000 - name: backend - protocol: TCP + - name: backend + image: spotify/backstage-backend:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 7000 + name: backend + protocol: TCP diff --git a/install/kubernetes/backstage/Chart.yaml b/install/kubernetes/backstage/Chart.yaml index 23ea41ec41..efc3635a7f 100644 --- a/install/kubernetes/backstage/Chart.yaml +++ b/install/kubernetes/backstage/Chart.yaml @@ -1,5 +1,5 @@ apiVersion: v1 -appVersion: "1.0" +appVersion: '1.0' description: A Helm chart for Spotify Backstage name: backstage version: 0.1.1-alpha.12 diff --git a/install/kubernetes/backstage/values.yaml b/install/kubernetes/backstage/values.yaml index fd4dd66b53..d91808ed28 100644 --- a/install/kubernetes/backstage/values.yaml +++ b/install/kubernetes/backstage/values.yaml @@ -1,12 +1,12 @@ app: enabled: true - nameOverride: "" - fullnameOverride: "" + nameOverride: '' + fullnameOverride: '' replicaCount: 1 serviceAccount: create: false - Name: "" - image: + Name: '' + image: repository: spotify/backstage tag: latest pullPolicy: Always @@ -15,20 +15,23 @@ app: port: 80 ingress: enabled: false - annotations: {} + annotations: + {} # kubernetes.io/ingress.class: "nginx" hosts: - - host: backstage.local - paths: - - / + - host: backstage.local + paths: + - / tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local imagePullSecrets: [] - podSecurityContext: {} + podSecurityContext: + {} # fsGroup: 2000 - securityContext: {} + securityContext: + {} # capabilities: # drop: # - ALL @@ -48,12 +51,12 @@ app: backend: enabled: false - nameOverride: "" - fullnameOverride: "" + nameOverride: '' + fullnameOverride: '' replicaCount: 1 serviceAccount: create: false - Name: "" + Name: '' image: repository: spotify/backstage-backend tag: latest @@ -63,20 +66,23 @@ backend: port: 7000 ingress: enabled: false - annotations: {} + annotations: + {} # kubernetes.io/ingress.class: "nginx" hosts: - - host: backstage.local - paths: - - /backend + - host: backstage.local + paths: + - /backend tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local imagePullSecrets: [] - podSecurityContext: {} + podSecurityContext: + {} # fsGroup: 2000 - securityContext: {} + securityContext: + {} # capabilities: # drop: # - ALL diff --git a/install/kubernetes/ingress.yaml b/install/kubernetes/ingress.yaml index d2ecae74c6..f93a814a0c 100644 --- a/install/kubernetes/ingress.yaml +++ b/install/kubernetes/ingress.yaml @@ -7,14 +7,14 @@ metadata: component: ingress spec: rules: - - host: - http: - paths: - - backend: - serviceName: backstage - servicePort: frontend - path: / - - backend: - serviceName: backstage-backend - servicePort: backend - path: /backend + - host: + http: + paths: + - backend: + serviceName: backstage + servicePort: frontend + path: / + - backend: + serviceName: backstage-backend + servicePort: backend + path: /backend diff --git a/install/kubernetes/service.yaml b/install/kubernetes/service.yaml index bbbc3d6e17..4d947b7afc 100644 --- a/install/kubernetes/service.yaml +++ b/install/kubernetes/service.yaml @@ -11,10 +11,10 @@ spec: app: backstage component: frontend ports: - - name: frontend - port: 80 - protocol: TCP - targetPort: app + - name: frontend + port: 80 + protocol: TCP + targetPort: app --- apiVersion: v1 kind: Service @@ -29,7 +29,7 @@ spec: app: backstage component: backend ports: - - name: backend - port: 7000 - protocol: TCP - targetPort: backend + - name: backend + port: 7000 + protocol: TCP + targetPort: backend diff --git a/microsite/.gitignore b/microsite/.gitignore new file mode 100644 index 0000000000..f5bcdb3385 --- /dev/null +++ b/microsite/.gitignore @@ -0,0 +1,4 @@ + +# Build output +build +i18n diff --git a/microsite/README.md b/microsite/README.md index d7187888a3..d244caa22a 100644 --- a/microsite/README.md +++ b/microsite/README.md @@ -2,12 +2,36 @@ This website was created with [Docusaurus](https://docusaurus.io/). # What's In This Document -- [Get Started in 5 Minutes](#get-started-in-5-minutes) +- [Getting Started](#getting-started) - [Directory Structure](#directory-structure) - [Editing Content](#editing-content) - [Adding Content](#adding-content) - [Full Documentation](#full-documentation) +# Getting Started + +## Installation + +``` +$ yarn install +``` + +## Local Development + +``` +$ yarn start +``` + +This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. + +## Build + +``` +$ yarn build +``` + +This command generates static content into the `build` directory, which is what will be deployed to GitHub pages from the master branch. + ## Directory Structure Your project file structure should look something like this diff --git a/microsite/blog/2020-04-30-how-to-quickly-set-up-backstage.md b/microsite/blog/2020-04-30-how-to-quickly-set-up-backstage.md index 65ee02f6a0..dff567eaf3 100644 --- a/microsite/blog/2020-04-30-how-to-quickly-set-up-backstage.md +++ b/microsite/blog/2020-04-30-how-to-quickly-set-up-backstage.md @@ -34,7 +34,7 @@ You get to take full advantage of a platform that we at Spotify have been using Just run the backstage-cli: ```bash -npx @backstage/cli create-app +npx @backstage/create-app ``` Name your app, and we will create everything you need: @@ -50,7 +50,7 @@ yarn start And you are good to go! 👍 -Read the full documentation on how to [create an app](/docs/getting-started/create-an-app.md) on GitHub. +Read the full documentation on how to [create an app](/docs/getting-started/create-an-app) on GitHub. ## What do I get? (Let's get technical...) diff --git a/microsite/blog/2020-08-05-announcing-backstage-software-templates.md b/microsite/blog/2020-08-05-announcing-backstage-software-templates.md index 51c1da2885..81d495e1c3 100644 --- a/microsite/blog/2020-08-05-announcing-backstage-software-templates.md +++ b/microsite/blog/2020-08-05-announcing-backstage-software-templates.md @@ -39,7 +39,7 @@ You can customize Backstage Software Templates to fit your organization’s stan ## Getting started -The sample Software Templates are available under `/create`. If you're setting up Backstage for the first time, follow [Getting Started with Backstage](https://backstage.io/docs/getting-started/) and go to `http://localhost:3000/create`. If you’ve already been running Backstage locally, run the command `yarn lerna run mock-data` to load the new sample templates into the Service Catalog first. +The sample Software Templates are available under `/create`. If you're setting up Backstage for the first time, follow [Getting Started with Backstage](https://backstage.io/docs/getting-started/) and go to `http://localhost:3000/create`. ![available-templates](assets/2020-08-05/templates.png) diff --git a/microsite/blog/2020-09-08-announcing-tech-docs.md b/microsite/blog/2020-09-08-announcing-tech-docs.md new file mode 100644 index 0000000000..48b6eeb7cc --- /dev/null +++ b/microsite/blog/2020-09-08-announcing-tech-docs.md @@ -0,0 +1,120 @@ +--- +title: Announcing TechDocs: Spotify’s docs-like-code plugin for Backstage +author: Gary Niemen +authorURL: https://github.com/garyniemen +--- + +Since we [open sourced Backstage](https://backstage.io/blog/2020/03/16/announcing-backstage), one of the most requested features has been for a technical documentation plugin. Well, good news. The first open source version of TechDocs is here. Now let’s start collaborating and making it better, together. + + + + + +Internally, we call it TechDocs. It’s the most used plugin at Spotify by far — accounting for about 20% of our Backstage traffic (even though it is just one of 130+ plugins). Its popularity is evidence of something simple: We made documentation so easy to create, find, and use — people actually use it. + +We are quite sure the main reason for the success of TechDocs is our docs-like-code approach — engineers write their technical documentation in Markdown files that live together with the code. During CI, a documentation site is created using MkDocs, and all sites are rendered centrally in a Backstage plugin. On top of the static documentation, we incorporate additional metadata about the documentation site — such as owner, open GitHub Issues, Slack support channel, and Stack Overflow Enterprise tags. + +![available-templates](assets/announcing-techdocs/docs-in-backstage.png) + +But this is just one way to do it. Today we’re most excited for what the open version of TechDocs can become. + +## Okay, let’s start collaborating + +If you go to [GitHub](https://github.com/spotify/backstage/tree/master/plugins) now, you’ll find everything you need to start collaborating with us to build out the docs-like-code Backstage plugin — we’ll call it TechDocs in the open as well. + +You’ll find the code in [techdocs](https://github.com/spotify/backstage/tree/master/plugins/techdocs) (frontend) and [techdocs-backend](https://github.com/spotify/backstage/tree/master/plugins/techdocs-backend). (There are also two separate packages [techdocs-cli](https://github.com/spotify/backstage/tree/master/packages/techdocs-cli) and [techdocs-container](https://github.com/spotify/backstage/tree/master/packages/techdocs-container).) + +You’ll find issues to work on in the [issues queue](https://github.com/spotify/backstage/issues?q=is%3Aissue+is%3Aopen+label%3A%22docs-like-code%22+label%3A%22help+wanted%22), typically starting with TechDocs: and labeled with docs-like-code, some labeled good first issue. Feel free to add your own issues, of course. + +![available-templates](assets/announcing-techdocs/github-issues.png) + +What we have on GitHub so far is a first iteration of TechDocs that you can use end-to-end — in other words, from docs written in Markdown in GitHub to a published site on Backstage. + +More specifically, with this first iteration, you can: + +- Run TechDocs locally and read documentation. +- Configure your entity (e.g. service, website) so that Backstage builds your documentation and serves it in TechDocs. Documentation is displayed on the Docs tab in the Service Catalog and on its own page. +- Get documentation set up for free in your project when you create a new component out of one of the non-experimental templates (labeled with recommended). If you are looking for a standalone documentation project, use the docs-template. +- Choose your own storage solution for the documentation. +- Define your own API to interface with your documentation solution. + +For a full overview, including getting started instructions, check out our [TechDocs Documentation](https://backstage.io/docs/features/techdocs/techdocs-overview). + +But before you go there, let me tell you a bit about the TechDocs story — and why we believe TechDocs is such a powerful yet simple solution for great documentation. + +## The TechDocs story + +Here is the TechDocs story. It’s not an uncommon one (we have learned from many other companies). + +About a year and a half ago, we conducted a company-wide productivity survey. The third largest problem according to all our engineers? Not being able to find the technical information they needed to do their work. And it’s not surprising. There was no standard way to produce and consume technical documentation, so teams were going their own way — using Confluence, Google Docs, README files, custom built websites, GitHub Pages, and so on and on. And those searching for information were left to hunt for it in all those different places until they found what they were looking for (if they ever did). Worse, if you did happen to find the documentation that you needed, there was no way to know whether the information was up-to-date or correct. In other words, there was no way to know whether you could trust what you found. We did have technical writers at the company, but they were mostly scattered across the company solving documentation problems within their own particular domain. + +So this is the fertile soil on which TechDocs was built. + +After a Hack Week implementation attracted interest from high up in the company, we formed a cross-functional team made up of technical writers and engineers with the mission to solve internal technical documentation at Spotify. And we started to build TechDocs. We went for a docs-like-code approach, fiercely optimizing for engineers and engineering workflows. We also went for an opinionated approach, telling everybody: This is the standard way to do technical documentation at Spotify. The sense was that engineers appreciated a documentation solution that was in line with their workflow and, after all the frustration of multiple tools, were relieved to be told “this is the way to do it”. + +For more information about this journey, take a look at my 20-minute talk from DevRelCon London from last December: [The Hero’s Journey: How we are solving internal technical documentation at Spotify](https://www.linkedin.com/posts/garyniemen_how-we-are-solving-internal-technical-documentation-activity-6646078605594030080-4L31). + +## Key problem areas that we are solving + +We have come a long way, fast — both in our implementation and in our thinking. Here are some of the key problem areas that we are addressing. Note that they are in various stages of implementation, and we won’t be able to release everything within our minimum plugin. In fact, see this as an appetite taster. What we hope is that we can build together. + +### Stuck to unstuck + +Very early on, we decided that the main problem we were trying to solve was to help engineers (when using technical documentation) go from stuck to unstuck, and fast. This became our guiding principle. Is what we are building helping engineers get unstuck faster? From this, it follows that we need to promote quality documentation on the one hand, and provide a high level of discoverability on the other. One without the other is not going to cut it. + +### Feedback loops + +What we want to build is a thriving community of technical documentation creators, contributors, and readers. We want this because, we believe, this is the way to drive up the quality of the documentation. More readers, more feedback, more doc updates. And driving up the quality of the corpus of technical documentation leads to trust which in turn leads to more engagement and, hence, more of a thriving community. + +To get this working, we recognised that we need to remove ‘friction from the system’ — we need to build in efficient feedback loops. For example, help engineers get their doc site up by providing documentation improvement hints and build information as close as possible to where they are already working. And for readers, make it easy to give feedback. And then for doc site owners, ensure that they are notified when there is feedback and incentivised to make the fix. + +![available-templates](assets/announcing-techdocs/feedback-loop1.png) + +![available-templates](assets/announcing-techdocs/feedback-loop2.png) + +### Trust + +How do I know whether to trust this piece of documentation? This is a question we want to be able to answer for those using technical documentation in Backstage. It’s not an easy nut to crack. It is almost, one could say, the hard problem of technical documentation. For example, some might say ‘last updated’ is a key factor. But what about stable, good quality documentation that has no need to be updated? What about page views? Yes, this is a good sign that the documentation is being found and viewed, but it doesn’t say anything about whether the documentation can be trusted. How about a button: Did this documentation help? This is good, but will people use it? Will we get enough data to show trust? We have lofty ambitions of one day providing a trust score on the doc site informed by a super-intelligent algorithm. But we are not there yet. For now, we have landed on surfacing when the documentation was last updated, top five contributors, the support channel, owning team, and number of open GitHub Issues. But going forward we are definitely up for solving the hard problem. We think there’s much more work to be done here and look forward to seeing ideas from the community. + +### Discoverability and search + +How to find stuff? That is another big question. As mentioned above, it’s all well and good having quality documentation, but it’s no use whatsoever if you can’t find it. If you know what you are looking for, then you can use a search engine. If you don’t know what you are looking for, then you are going to need more — like a well designed information architecture, a user friendly browse experience, and even intelligent suggestions based on your role and what you have searched for previously. + +In this problem area, we made use of Elasticsearch, the open source search engine that was already being used in Backstage, to implement documentation search across all documentation sites and per documentation site. In terms of discoverability, we implemented a documentation home page in Backstage that surfaces Spotify’s most important documents and uses metrics to list the company’s most used doc sites as well as the documentation equivalent of a “your daily mix” playlist. + +![available-templates](assets/announcing-techdocs/discover1.png) + +![available-templates](assets/announcing-techdocs/discover2.png) + +There is much more to do in the area of discoverability and search. + +### Use case variations + +The standard use case for TechDocs is: One component in Backstage equals one GitHub repository, equals one doc site. This use case comes in two flavours: the repository is a code repository with docs or a docs-only repository. Then, to meet the needs of one large part of the Spotify engineering organisation that uses monorepos (multi-component repositories), we added a third use case. We built an MkDocs plugin that enabled doc site creators to include documentation from doc folders in other parts of the repository. So this use case is: One main component in Backstage equals a monorepo with distributed documentation, equals one doc site. + +These three use cases satisfy most of the needs, but we have had plenty of requests for additional use cases, for example, the ability to create multiple doc sites from a multi-component repository and the ability to create one doc site from documentation in multiple repositories. + +### Metrics + +There are many good arguments for standardizing the way that technical documentation is produced and consumed. One of them is metrics. If we have one way of producing technical documentation (in our case, GitHub Enterprise) and one place where it shows up (in our case, Backstage), we are in a strong position to build up metrics that help all the various stakeholders — for example, us building TechDocs, teams creating documentation sites, and engineers trying to get unstuck. Just imagine how much harder this would be if technical documentation was produced and consumed in a plethora of places, such as Confluence, Google Docs, README files, custom web sites, and GitHub Pages. + +One thing we have recently completed is a Manage page in Backstage for doc site owners. Here teams can see all the documentation that they own, the number of GitHub Issues per doc site or page, and last updated. We have also built a large dashboard using the open source analytics software Redash to inform our own product development process. + +![available-templates](assets/announcing-techdocs/metrics.png) + +Again, there is a lot more that can be done in the area of metrics. Did I mention the trust score? + +### Code-like-docs + +Code-like-docs, what? Okay, it’s just my little play on words. This is what I mean. One request that we keep getting is to be able to have code in the documentation fetched from and in sync with code in GitHub. In this way, you can avoid code in the documentation going stale. MkDocs does have an extension for this — but it has some limitations. For example, the code has to be in the /docs folder with the Markdown files. We are working on developing a wider and more flexible solution. + +### Golden Paths + +At Spotify, we have the concept of [Golden Paths](https://engineering.atspotify.com/2020/08/17/how-we-use-golden-paths-to-solve-fragmentation-in-our-software-ecosystem/) — one for each engineering discipline. My favourite definition of Golden Path is that it is the “opinionated and supported path”. Each Golden Path has an accompanying Golden Path tutorial that walks you through the opinionated and supported path. + +The Golden Path tutorials are Spotify’s most used and important documents and have shown themselves to be the most challenging to manage within a docs-like-code environment. One reason for this is that they are long, divided into many parts, and ownership is typically spread among many different teams. We have had to make use of GitHub codeowners to handle ownership and had to create datasets and data pipelines to be able to attach GitHub Issues to the specific parts or files that a team owns. Another challenge of the Golden Path tutorials is that parts are often dependent on other parts. We are just starting to look into how we can solve these dependency challenges in order to remove friction for engineers writing tutorial documentation. + +--- + +So that’s it for now. As you can see, we have come a long way AND there is much more to do. We are looking forward to continuing our docs-like-code journey out in the open with new, enthusiastic technical documentation friends. diff --git a/microsite/blog/assets/announcing-techdocs/discover1.png b/microsite/blog/assets/announcing-techdocs/discover1.png new file mode 100644 index 0000000000..5b23e64b43 Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/discover1.png differ diff --git a/microsite/blog/assets/announcing-techdocs/discover2.png b/microsite/blog/assets/announcing-techdocs/discover2.png new file mode 100644 index 0000000000..3737ee68db Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/discover2.png differ diff --git a/microsite/blog/assets/announcing-techdocs/docs-in-backstage.png b/microsite/blog/assets/announcing-techdocs/docs-in-backstage.png new file mode 100644 index 0000000000..f3b724ff4f Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/docs-in-backstage.png differ diff --git a/microsite/blog/assets/announcing-techdocs/feedback-loop1.png b/microsite/blog/assets/announcing-techdocs/feedback-loop1.png new file mode 100644 index 0000000000..4e2d0de5df Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/feedback-loop1.png differ diff --git a/microsite/blog/assets/announcing-techdocs/feedback-loop2.png b/microsite/blog/assets/announcing-techdocs/feedback-loop2.png new file mode 100644 index 0000000000..516780e3ac Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/feedback-loop2.png differ diff --git a/microsite/blog/assets/announcing-techdocs/github-issues.png b/microsite/blog/assets/announcing-techdocs/github-issues.png new file mode 100644 index 0000000000..3d5f3465c0 Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/github-issues.png differ diff --git a/microsite/blog/assets/announcing-techdocs/metrics.png b/microsite/blog/assets/announcing-techdocs/metrics.png new file mode 100644 index 0000000000..b332a65b0d Binary files /dev/null and b/microsite/blog/assets/announcing-techdocs/metrics.png differ diff --git a/microsite/data/plugins/github-pull-requests.yaml b/microsite/data/plugins/github-pull-requests.yaml index 917198a221..6479452c8e 100644 --- a/microsite/data/plugins/github-pull-requests.yaml +++ b/microsite/data/plugins/github-pull-requests.yaml @@ -7,4 +7,3 @@ description: View GitHub pull requests for your service in Backstage. documentation: https://roadie.io/backstage/plugins/github-pull-requests iconUrl: https://roadie.io/static/7f13bb8d861d8dedc5112fb939d215f9/351f2/GitHub-Mark-Light-120px-plus.png npmPackageName: '@roadiehq/backstage-plugin-github-pull-requests' - diff --git a/microsite/data/plugins/graphiql.yaml b/microsite/data/plugins/graphiql.yaml index 6c95d1b175..e997360b04 100644 --- a/microsite/data/plugins/graphiql.yaml +++ b/microsite/data/plugins/graphiql.yaml @@ -3,12 +3,10 @@ title: GraphiQL author: Spotify authorUrl: https://github.com/spotify category: Debugging -description: Integrates GraphiQL as a tool to browse GraphiQL endpoints inside Backstage. -documentation: https://github.com/spotify/backstage/tree/master/plugins/lighthouse +description: Integrates GraphiQL as a tool to browse GraphQL API endpoints inside Backstage. +documentation: https://github.com/spotify/backstage/tree/master/plugins/graphiql iconUrl: https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/GraphQL_Logo.svg/1024px-GraphQL_Logo.svg.png npmPackageName: '@backstage/plugin-graphiql' tags: - graphql - - github - - gitlab - - api + - graphiql diff --git a/microsite/data/plugins/rollbar.yaml b/microsite/data/plugins/rollbar.yaml index 0118fab391..8ef3d8d66a 100644 --- a/microsite/data/plugins/rollbar.yaml +++ b/microsite/data/plugins/rollbar.yaml @@ -7,4 +7,3 @@ description: View Rollbar errors for your services in Backstage. documentation: https://github.com/spotify/backstage/tree/master/plugins/rollbar iconUrl: https://rollbar.com/assets/media/rollbar-mark-color.png npmPackageName: '@backstage/plugin-rollbar' - diff --git a/microsite/data/plugins/travis-ci.yaml b/microsite/data/plugins/travis-ci.yaml index 48c0a4cb86..520b884c20 100644 --- a/microsite/data/plugins/travis-ci.yaml +++ b/microsite/data/plugins/travis-ci.yaml @@ -7,4 +7,3 @@ description: View Travis CI builds for your service in Backstage. documentation: https://roadie.io/backstage/plugins/travis-ci iconUrl: https://roadie.io/static/af2941eaf0af675facb281d566f42e14/45f2b/travis-ci-mascot-200x200.png npmPackageName: '@roadiehq/backstage-plugin-travis-ci' - diff --git a/microsite/package.json b/microsite/package.json index ee3c7f8dc2..734f1e4d49 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -1,5 +1,5 @@ { - "version": "0.1.1-alpha.21", + "version": "0.0.0", "name": "backstage-microsite", "license": "Apache-2.0", "private": true, @@ -13,7 +13,7 @@ "rename-version": "docusaurus-rename-version" }, "devDependencies": { - "docusaurus": "^2.0.0-alpha.61", + "docusaurus": "^2.0.0-alpha.64", "js-yaml": "^3.14.0" } } diff --git a/microsite/pages/en/demos.js b/microsite/pages/en/demos.js index 9f9dcec819..d891e05613 100644 --- a/microsite/pages/en/demos.js +++ b/microsite/pages/en/demos.js @@ -78,6 +78,41 @@ const Background = props => { + + + + + Make documentation easy + + + Documentation! Everyone needs it, no one wants to create it, and + no one can ever find it. Backstage follows a “docs like code” + approach: you write documentation in Markdown files right + alongside your code. This makes documentation easier to create, + maintain, find — and, you know, actually use. This demo video + showcases Spotify’s internal version of TechDocs. Learn more about{' '} + + TechDocs + + . + + + Watch now + + + + + + + + diff --git a/microsite/pages/en/index.js b/microsite/pages/en/index.js index 7a58ede25f..f595032bd0 100644 --- a/microsite/pages/en/index.js +++ b/microsite/pages/en/index.js @@ -296,9 +296,7 @@ class Index extends React.Component { src={`${baseUrl}animations/backstage-techdocs-icon-1.gif`} /> - - Backstage TechDocs (Coming Soon) - + Backstage TechDocs Docs like code - Subscribe to our newsletter - - TechDocs is our most used feature at Spotify. Be the first to know - when{' '} - - the open source version - {' '} - ships. - + Learn more about TechDocs - Subscribe + Docs diff --git a/microsite/sidebars.json b/microsite/sidebars.json index f5741bd355..f7aa0630ef 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -7,10 +7,12 @@ "overview/roadmap", "overview/vision", "overview/background", - "overview/adopting" + "overview/adopting", + "overview/logos" ], "Getting Started": [ "getting-started/index", + "getting-started/running-backstage-locally", "getting-started/installation", "getting-started/development-environment", "getting-started/create-an-app", @@ -31,14 +33,16 @@ ] } ], - "Features": [ + "Core Features": [ { "type": "subcategory", "label": "Software Catalog", "ids": [ "features/software-catalog/software-catalog-overview", + "features/software-catalog/installation", "features/software-catalog/system-model", "features/software-catalog/descriptor-format", + "features/software-catalog/well-known-annotations", "features/software-catalog/extending-the-model", "features/software-catalog/external-integrations", "features/software-catalog/software-catalog-api" @@ -46,9 +50,10 @@ }, { "type": "subcategory", - "label": "Software creation templates", + "label": "Software Templates", "ids": [ "features/software-templates/software-templates-index", + "features/software-templates/installation", "features/software-templates/adding-templates", "features/software-templates/extending/extending-index", "features/software-templates/extending/extending-templater", @@ -58,11 +63,12 @@ }, { "type": "subcategory", - "label": "Docs-like-code", + "label": "TechDocs", "ids": [ "features/techdocs/techdocs-overview", "features/techdocs/getting-started", "features/techdocs/concepts", + "features/techdocs/architecture", "features/techdocs/creating-and-publishing", "features/techdocs/faqs" ] @@ -92,7 +98,11 @@ { "type": "subcategory", "label": "Publishing", - "ids": ["plugins/publishing", "plugins/publish-private", "plugins/add-to-marketplace"] + "ids": [ + "plugins/publishing", + "plugins/publish-private", + "plugins/add-to-marketplace" + ] } ], "Configuration": [ diff --git a/microsite/siteConfig.js b/microsite/siteConfig.js index cc5ad89e09..d7a3bd67d0 100644 --- a/microsite/siteConfig.js +++ b/microsite/siteConfig.js @@ -67,8 +67,9 @@ const siteConfig = { primaryColor: '#36BAA2', secondaryColor: '#121212', textColor: '#FFFFFF', - navigatorTitleTextColor: '#9e9e9e', - navigatorItemTextColor: '#616161', + navigatorTitleTextColor: '#e4e4e4', + navigatorItemTextColor: '#9e9e9e', + navGroupSubcategoryTitleColor: '#9e9e9e', }, /* Colors for syntax highlighting */ @@ -93,8 +94,10 @@ const siteConfig = { cleanUrl: true, // Open Graph and Twitter card images. - ogImage: 'img/logo-gradient-on-dark.svg', - twitterImage: 'img/logo-gradient-on-dark.svg', + ogImage: + 'logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png', + twitterImage: + 'logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png', // For sites with a sizable amount of content, set collapsible to true. // Expand/collapse the links and subcategories under categories. diff --git a/microsite/static/css/custom.css b/microsite/static/css/custom.css index 5e078582cc..111065a5d5 100644 --- a/microsite/static/css/custom.css +++ b/microsite/static/css/custom.css @@ -113,6 +113,10 @@ td { color: $navigatorTitleTextColor; } +.toc .toggleNav .navGroup .navGroupSubcategoryTitle { + color: $navGroupSubcategoryTitleColor; +} + .toc .toggleNav ul li a, .onPageNav a { color: $navigatorItemTextColor; @@ -203,6 +207,54 @@ td { border-radius: 0.25rem; } +/* + * Fix for viewing Table of Contents bar on documentation + * and blog pages on smaller screens. + */ +@media only screen and (max-width: 1023px) { + /* Nav bar hides the docs toc bar */ + .docMainWrapper { + margin-top: 4rem; + } + + /* Toc bar does not have to be fixed */ + .docsNavContainer { + position: unset; + width: 95vw; + z-index: 100; + margin-left: -2vw; + } + + /* Toc bar does not have to be fixed when slider is active */ + .docsSliderActive .toc .navBreadcrumb, + .tocActive .navBreadcrumb { + position: unset; + } + + /* Fix unexpected width increase when toc is toggled */ + .docsSliderActive .toc .navBreadcrumb, + .tocActive .navBreadcrumb { + width: inherit; + } + + /* This pseudo-element stops toc toggle button to be clicked */ + header.postHeader::before { + height: 2em !important; + margin-top: -2em !important; + } + + /* This pseudo-element stops toc toggle button to be clicked */ + #__docusaurus.postHeaderTitle::before { + height: 1em; + margin-top: -1em; + } + + /* Useless button causing trouble */ + .tocToggler { + display: none; + } +} + /* content */ .postContainer blockquote { color: $textColor; @@ -288,17 +340,17 @@ code { background: linear-gradient(70.44deg, #121212 75%, #5d817b 100%); } .bg-teal-top-right { - background: + background: /* linear-gradient( 178.64deg, rgba(255, 255, 255, 0) 57.61%, rgba(255, 255, 255, 0.17) 127.71% - ), */ + ), */ /* linear-gradient( 144.35deg, rgba(98, 197, 179, 0) 56.68%, rgba(98, 197, 179, 0.59) 109.25% - ), */ + ), */ /* linear-gradient( 192.29deg, rgba(155, 240, 225, 0) 54.17%, diff --git a/microsite/static/logo_assets/Backstage_Identity_Assets_Overview.pdf b/microsite/static/logo_assets/Backstage_Identity_Assets_Overview.pdf new file mode 100644 index 0000000000..ad091c18e2 Binary files /dev/null and b/microsite/static/logo_assets/Backstage_Identity_Assets_Overview.pdf differ diff --git a/microsite/static/logo_assets/ai/Backstage_Identity_Assets_Artwork_RGB.ai b/microsite/static/logo_assets/ai/Backstage_Identity_Assets_Artwork_RGB.ai new file mode 100644 index 0000000000..f849131417 --- /dev/null +++ b/microsite/static/logo_assets/ai/Backstage_Identity_Assets_Artwork_RGB.ai @@ -0,0 +1,2999 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[11 0 R 46 0 R 80 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Backstage Identity_Assets_Artwork_RGB + + + 2020-04-28T11:21:44+01:00 + 2020-04-28T11:21:44+01:00 + 2020-04-27T17:08:19+01:00 + Adobe Illustrator CC 23.1 (Macintosh) + + + + 256 + 108 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAbAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FULqd99TtTNx5EkKvgCe5yUY2XF1mp8GHEk0N7xvoRDIJmklQS3ALLzD1HFkO23bLD HZ0+PU1ljwniuQuW4u+hHkmN5qNxDNMqAFYgrU9N2ry61cHiv05ARBdjqNXOEpAco1/CT9vIfFVb VoBM8XBiy1C04ksQwWlK1FSwpXBwNh10RIxo7e7vA7/Pq46lxuEieNkaQUWMgci1ada8aU3x4dlO rqYiQRfTrf3UtXVVkYLHExPNUYErUBq9RyqDt3w8CBrhI0AeYHT9baavC5KpGxckKigqSS1ffb7J rXHgWOvjLYA38PPz8urhrFsZETi4ZqAg8aqSxUVFfEdseAqNfAkCjv7tt67/ALkdkHOdirsVdirG /wAxvOcXkvyVqnmaS2a8GnohW2Vghd5ZUhQFj0XlICx8MVfM+ofmjKms22t6TqsOueYrx7W8n1qE 3dk1pE08UUmlNaSFoprernj06lvtipVe4/mL+YXmXQfMM2naUIzFBpP6TCfoq/1SSWX1ZI/TLWc0 S26UQfHIKYq4/nr5btrqG1v7aVZHszcvLbSW86l0sf0g6RxrL67IYgQkhjCs2wOKq+sfm02j6lpk Gr6Nd6WL5p7dbK4WF7ie5rbC1S2lima2YSfWSG5P8JG5WlSqp6j+c9sl1qdhYaPdTahplxHBJBJJ aIxU3sdm7mI3CyorNL+6Zlo+xrSuKqj/AJ2eX01a+0o2F215as0VtCj2jyXEy3kNh6QjWctEzT3K cPW41X4umKqOofnv5Z02Vbe/0++tr2N5lvrR/qvqQLbyCJ32nIlBY/CIuTMATToCq9KxV2KuxV2K uxV2KuxV2KuxV2KuxV2KqF7Zw3kBhlrxJqCDQgjvhjKmjUaeOWPDJCabocFnI0hb1mNOBKgcad++ +SlO3E0nZscJJviPu5IuWxtpXZ3ViXADgO4DAdAVBAOREi5c9NCRJN7+Z+61h0yyJJKHetBzag5H kaCu2++2HiLA6LH3faeu/wAN91w0+0404E16sWYtWvKta1rXvjxFl+Vx1y+0+9pdOtFNQrV2oebV HE1AG+wx4igaTGOn2nopyaTBwAhJjZacSWdgAvQD4gR9BGHja5aGNenY+8nl8dvgQvh023jSMblk pvVgDQlhUV3oT3wGRZ49HCIHl7/f+LRWRcp2KuxV2KpR5s8raP5r8vXvl/WY2l06+VVmVHMbAo6y IysvQq6Kw7bb1GKvMfy5/wCcZfLPk7zLNrM98dajCcLGzureMLCRIsiyO1XEkiMg4sFWnhXFXo2u +RPLeuX/ANf1CO6F2bf6m8lrfXtnzt+Rf0pFtZoVdeTn7QOKpW/5Pfl68lTpri3qxWyW6ultVL2p s3K26yCIc7c8Gou4xVEr+V/kn6vPDNYPdfWUliuZrq5uriaRZ0ijcPNNK8hotvGEPKqcfhpiqxvy r8lO8zyWtxIZldBzvr1vSEs6XMhtyZqws80KOWjINRiqX61+Tnli8tbkae09lfyh/q88tzeXMMJl uo7yXhAbhAnOeIOTGyMG+JWVgpCq7Rfyf8tWenJb6g019dmW4lubqO4vLf1hdSiaSKX/AEiSSaLk q/DNJJXuTU1VZ3irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqld3UVrA00poq9vEno MIFtOfNHFEylySs6ndRXcSzVDzOq+gACgR9lZXG9fnlnCKdadZOOQCXORG3SjyIPenOVO4dirsVd irsVdirsVdirsVdiqXeYvMGleXdDvNb1ab0NOsIzLcS0LEAbABRuSxIAHjirwrzN+d/mzRLqDX70 PbQ6gLebQvL8S295Y3WmvIiTSzXkLtJFdAy9R+7B4qA9SQq+hsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdiqF1OyN7aNAG4EkEEioqMlGVFxdZpvGxmN0lel6BLFMXuqcUZWjCnqyk0J26 b5ZLJ3Os0XZcoyvJ0Nj3hPspd67FXYq7FXYq7FXYq7FXYq7FWO/mH5R/xf5M1Xy39Z+pnUYhGtzw 9TgyusgJSq1FU8cVfPv5c/8AOK2v2fme5Xze0Enl9I+KtaTnncOk0cqCnDkEPp/FyofDxxV9SYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq0WUMFJAZug7mmKDIXTeKXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqhdQ1GCy h5yGrn7EY6sclGNuLqtXDDGzz6BK4NKutQBvbuVopXANuF/ZHUHLDMDYOsx6Keo/eZDwyP010VU1 G90+VINRAeJjSO5X/jbBwg8m2OryYJCGbeJ5S/H496c5U7h2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KoXUr9LG2MzKWPRQOlT4nsMlGNlxdXqRhhxVaWa bYpqJa+vXWYv8KxKdkHvTpk5S4dg63SaYai8uU8V9O5u4gvdHQzWsnq2gPxQyb8amm304giXPmnL jy6QcUDxY+49EDe3c99LELgoqKAywpU7MAas3QbdfDJxFcnB1OeWaQ46rnQ/Sen6GVZjvUuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVIPN03pw21Ptl2C 8W4v0/Yr8Lf6vftlmN1Pav0x77+Pw7/d1Y3BqLwOZ4JfRddnlRTwG/SWLcp9xHhlp3dLCZgeKJ4T 3jl/nR6fd3ImfXbm/wCMMtykiVr6Vurcmp3+IAD6T9GARAbM2qnmqMpAjuiDv+PwEVPccZ4xRvSK RcaCkZPBacD1mPh/TEM8u0h3VH3chy/n+X6mYZjvUuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVJvNOi3Wq2SR20kayRMW9KZeUclRTiSPiX/WG+SjKnC1 2mlmhQI27+Red3T3ljdCC7jkt7tB8CSSCKWg2rDc/YkX2bfsMuBecyQlCVSBEvfR+Euo9/uDZvZw tLgzpEev1pxFH/wK/FL8lxYkn+Lir+lsP1y+D0XSdGseMGoSws168UZZ5ftAhAB8FeKnbt0ykyPJ 6TT6THtkI9dDn7u7om+Rc52KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxVLfMH6A+oH9Oej9Urt61Ptf5H7Vf9XfDG+jjarwuD97XD5sa0H/lVv6QT9G+j 9cqPS9b1vtV24ev8PLwpvkzxOu035Hj9FcXnf++ZvlbunYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FX/9k= + + + + uuid:a094fc3f-430f-7744-b388-fdb7ec44f815 + xmp.did:17c4aec8-eddf-4473-bdc7-9dbc4289c51b + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + xmp.iid:c8804a9b-d36f-42ac-b594-d814edaf8ca1 + xmp.did:c8804a9b-d36f-42ac-b594-d814edaf8ca1 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:96cc7365-26ab-46ae-a826-605707e77cc1 + 2020-04-20T16:59:06+01:00 + Adobe Illustrator CC 23.1 (Macintosh) + / + + + saved + xmp.iid:17c4aec8-eddf-4473-bdc7-9dbc4289c51b + 2020-04-27T17:08:17+01:00 + Adobe Illustrator CC 23.1 (Macintosh) + / + + + + Print + Document + Adobe PDF library 15.00 + 1 + False + False + + 346.562312 + 440.050339 + Millimeters + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + + + + Backstage RGB + 1 + + + + Teal 01 + PROCESS + 100.000000 + RGB + 53 + 185 + 162 + + + Teal 02 + PROCESS + 100.000000 + RGB + 125 + 242 + 224 + + + Magenta + PROCESS + 100.000000 + RGB + 240 + 55 + 165 + + + Blue + PROCESS + 100.000000 + RGB + 46 + 119 + 208 + + + Grey + PROCESS + 100.000000 + RGB + 64 + 64 + 64 + + + Black + PROCESS + 100.000000 + RGB + 18 + 18 + 18 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 5 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 2079.95 456.054]/Type/Page>> endobj 6 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 337.465 428.499]/Type/Page>> endobj 7 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 2079.95 456.054]/Type/Page>> endobj 8 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 337.465 428.499]/Type/Page>> endobj 9 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 2079.95 456.054]/Type/Page>> endobj 10 0 obj <>/Resources<>/ExtGState<>/Properties<>>>/TrimBox[0.0 0.0 337.465 428.499]/Type/Page>> endobj 13 0 obj <>/Resources<>/ExtGState<>/Properties<>/Shading<>>>/TrimBox[0.0 0.0 982.381 1247.39]/Type/Page>> endobj 91 0 obj <>stream +Hd6y +dFpO.`%Ͱf"}ϗնJs+T-mWؼݼ=Gc)נ_=Y +Vx{ߊǴVԮ뉼_f\Oēl+m^ɧ{x"Wy/7kqs>sƺ[,[ mDyhbWbi?ne.Ǧm|{ Vae#{6ֹv@a:cC>_'B r܎ +i2lb{ʄxWʎ޶VR+#Myfڬ|yoi{pv +)6≼A]gN:57gS+g aI>"dðu3^aG5rDam9QVP;cWv_34~-dak=u2FjQBg,0ȹ"1QoA{KH̸!֍qT(6FBDB n@(k@-N: ={L1DHZH{X|!y#J@6}q~du{ n7:xE1| ְ=4j +⅔@*5Q fbJQUP\k?dqk![#5L%Aa$l~6 TDCkq, +#d@I]E2$-|"+@.c=EHZ%IFU6LazE%AC4N@0I癌ewSȸȌ6'ŨULqwF7I;p~xb4 bHZu5R5v'B عȊrἫ Fyv5EqqDJNDU "j&&0ZyO) 9 ᜨ;)Ea^]d{Yhx5!%rx47D:V'ht9ZKj,.M~k5 X CfIAS=z4m=W&U))S!oSI5ym<6o,ܑߨ:]dj#T]ijtj7{6 )fѢ +Gk$ue(-뎼/51~ $ u4Z4v#*ÚYaC +fEPHq" $7!BJ?pnUtnEwxwVB*7ZXj7L<+at~%#?W]ʹeW7Mq3ej?fNے+mD3=az1-ODqD"?](;K&*Ʌ\T-DLxz>Ei4`7M%I] +CJYe7I.䒤3RzKr%LM&Ʌ\tF&]d=%);Vn\%Io8KS֛$!K}9ˁ-%o[ȥC}qG_Էޝ}-% 1Է鞆–ȮzUբ>SCk2*n gL^=xEz*\TYٌvWEoe :GUU\EK;XE80WW**\bѶYwjEغZg׷JT .Ф:aZ>MCH%]߷o~}/߷ׯ 0c endstream endobj 92 0 obj <> endobj 84 0 obj [/ICCBased 94 0 R] endobj 93 0 obj <> endobj 95 0 obj <> endobj 96 0 obj <> endobj 97 0 obj <> endobj 94 0 obj <>stream +HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  + 2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 +V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= +x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- +ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 +N')].uJr + wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 +n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! +zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 80 0 obj <> endobj 98 0 obj [/View/Design] endobj 99 0 obj <>>> endobj 85 0 obj <> endobj 83 0 obj <> endobj 100 0 obj <> endobj 101 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 23.1.1 %%For: (Natalie Strange) () %%Title: (Backstage Identity_Assets_Artwork_RGB.ai) %%CreationDate: 28/04/2020 11:21 %%Canvassize: 16383 %%BoundingBox: -5080 1539 4131 5351 %%HiResBoundingBox: -5079.08096277355 1539.48247256369 4130.81283900864 5350.91952314631 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 673 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0.070618383586407 0.070618391036987 0.070618383586407 (Black) %%+ 0.180392161011696 0.466666668653488 0.815686285495758 (Blue) %%+ 0.250980406999588 0.250980406999588 0.250980406999588 (Grey) %%+ 0.941176474094391 0.215686276555061 0.647058844566345 (Magenta) %%+ 0.211763471364975 0.729411721229553 0.635294198989868 (Teal 01) %%+ 0.49064376950264 0.95199066400528 0.881853818893433 (Teal 02) %%+ 0 0 0 ([Registration]) %AI3_Cropmarks: -880.950314739645 1539.48247256369 101.431041134967 2786.86926132895 %AI3_TemplateBox: 306.5 -396.5 306.5 -396.5 %AI3_TileBox: -669.259636802339 1783.17586694632 -110.259636802339 2566.17586694632 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 1 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -3450 7755 0.09852450408425 1242 674 18 0 0 11 51 0 0 0 1 1 0 1 1 0 0 %AI5_OpenViewLayers: 7 %%PageOrigin:0 -792 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 102 0 obj <>stream +%%BoundingBox: -5080 1539 4131 5351 %%HiResBoundingBox: -5079.08096277355 1539.48247256369 4130.81283900864 5350.91952314631 %AI7_Thumbnail: 128 56 8 %%BeginData: 3000 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD35FF8BAFFD2EFF5252A8FD4CFF60AF8AAFFFAFAEAFFD06FFAFFD %21FF277D7D52FFA87D7DA8FD05FFA8FD40FF8AFF8A8BAFFF8AAF8BFFAEFF %FD09AFFFAFFFFD04AFFD14FF277D7D2727FF7D7D52A87DA8A87D7D7DA8A8 %7DA852A87DFF7D7DA8A87DFD32FF848B848B60AFFFAF84AF8A8B84AFAFAF %60AF8A8B84AF8A8B84AF8A8B84AFFD12FFA8272727F827FF7D527D527D27 %527D7D27527D52527D7D52277D7D522752FD33FF668B66AFAFFF8AFFAFAF %8AFD07AF8AAFAFAF8AAFAFAF8BAFAFFD13FFF8F8F8277DFF7D7D7DFD0452 %FD057D527D7D7D52527D7D527D52FD32FFAFAF608BAFFFFFFFAEFFAFAFAF %FFAFFFFFFFAFFFAFFFAFFFAE8B8AFFAEFD14FFA827F852FFFFFF7DFD04A8 %FF7DFFFFFFA8A8A8FFA8A8A85227A8A8A8FD4BFFAFFD19FFA8FD15FFA8FD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFD59FFAFAFFD2EFFA87DFD4DFFAF8AAF %AFFD2CFF7D277D52FD4BFFAF8AAF60AFFD2BFFA8527D5227A8FD4AFF66FF %8A8B8BFD2BFF277D7D2727FD4AFFAE8B608B60AFFD2BFF27F8F82752FD4B %FF8A8B66AFFD2CFF52F8F852A8FD4CFF84AFFD2EFF7D52A8FDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDE6FFAF60AFFD7DFF668B608BAFFD79FFAF %608BFFAF60678AFD77FFAF66AFFD04FFAF8B8AFD75FFAF606684FD05FF8A %66AFFD73FFAF60AFAF8B60AFFFFFAF8B8AFD73FFAF608BAFFFAF8B608B84 %8A60AFFD73FF668BFD06FF668B8AAF8BFD72FF848B608BAFFD04FF8B8A8B %84AFFD72FFAF848B668BAEFFFF8B60AF8B8B8AFD72FF848A608A8466608A %608A848B848BAFFD71FFAF608B848B848B8A8B84AF8A8B8AFD72FF846060 %8A6084608A608A848B608AFD72FFAF6084608A608A608A60AF608BFD73FF %84605F605F8460605F6084FD76FFA8605F8A6060608A60AFFD77FFAF8435 %605F605F60A8FD79FFAF5F605F60A8FD7CFFA8FD3EFFFF %%EndData endstream endobj 103 0 obj <>stream + mgcR^vЬe1@QXH|rueEZp/:A] tP7GRM䜭Je^N9,l1,R58I>u "rg&$20YEo GtCo: 4d1bO9D+zDL!2*4\DbZ$$,CRH(`Bx9j솲.q8 `jśQo`.Mpl"#5񴆞2iՆvB3k':%4nj.ښZ\~(IT !㕗;:ySu!kfxׂ03;MNq܆J5ptKNAi]2qW7Zz# ր;0ǽ943bLIE՘Uxb/љN=N%.!_A0UN3m@l9pfB"FQ;Š DtS[ڗ8~*` y? +P3! +`0mT`$2P֩,"~uf3\aNߨW TA@i@&KxOg!ѵqFy@-k\|vBcj9I #T5u۱:"1x ťb9@OQ^ʺv]cfOGȠתl)QMC5p*@`eFQ=ճ h{ dr+` BB3,C",D jFfrs ?=X90j`;lκTŌ:0y5ilQ͓7 ߧB +IR(GCh۪;MkAoGF3f; ޗhʶE. +3lwBgPyXiANs]i>=X<㦟."{\HD- YWRI9?9B DR#6M3LbC*shӃy<<\|N~ƞcFB6 +A|@la +o ZfP4*{=&P+BM#hA]Qa]Eߑ zd }%Sx-0YLv?rCCM˰5gF/֧UK0 x49 FŠE"uɸih"xt@9/. '0͎Aϐo@$<4dĘi"r]e,`MP2pn\ǘ<@-a1 y,2jzbR28\Ӛe"LHChCACz\ct,b:8j y5c_0YhlNf*A/3?h~ťqi\#N˅[sҏqً9Gz^itܗ3wLA# &3C&0wOf.5N>&XTLRf9dfwgC"̨85v 4wK@̺XF47"L.3)ЋӃ`uffYy@N@_S@1SAYੲ +.4Ug\ǂ4fJL8rtW3rt4?\>=X +s}*R@E&%VS/穙MQxФ +5E99dQs^s*!*_ںէ/wqFFP1%V')!YUN\]~!`@:E%7~yq8*SjrG40"(i:ƛ<'3=XpK +\\( }[}ǴMLnjt^ h` ȝ>igVf8uwI{>#FW=r0xTz~J}T!>6$kp#MJ&LECMxor*72q?fHr +?6n. 8XaH; +}z%4"LtA&j#pq[9/4! @m[Q>5o?Z}V,46rV` 3E:x"š \F}QHYFCY35e 9کk"qk:BPh?( E+/Bg8Χ{f+! X}R-@ErfT ݔ[u/7R8Y!!Zf]΀`ĠIQ0a] 4C(C~K!HΒYV|*<ٚNUyAwH P9JI$*+$j`yx7qM0A`g岣9HGH2a%m-C=1>$ԫZX*c^. +@?/CvС +s)@+\3? pZKT@ ~s+k9L,j$H +c#}s0Qjv0i%&+zX5_=td1q£lA3qXr2O`a2,KO1V/?Y8e4@;j +fl 9!_XJFX4L|IӼӲ4N#):\NA26?V>qǬ`wq9.U &.ue3^L[򫳄1oi?xVTdLTyo09ӛID[۲hC5-V|q7'WߟR}sLۯ R!ڑ$Df>0jUF 2 kdf~6Z`g|'߯ +ggW? #ݥO煬8!'OOT?0àD{]Bzޕ! }rfb!"0n9'yH"6 Lejo?YF$WBm+Ex,=ί{{( f$aN<bkov4Ƚ;҃"9z7mpޚؽg$gpW?3w +7Nf-u!Ki<^r]b)EaHK"Km,6(HŐ6_HzHq~բ񅘇H[@!"ֿ6[) w*piyFj\7Suä.N0\W?bc ]xi3hNƛʗuo\|QcU +Ej¿,)t?'65oⓉU褛A͝>3dOz>&Zŏ'F7O)^chEBt 2}bPGVC_ǐ!M"C1Iܺy(:3{%Ǔ|з/om2nm^zu}kv={joVڛv61 R=k]F[Uh_^Z@r}in;}OH=otyGWoyz|Pljȵ CA֘P'=h#OtCл\kl1Aj\ +g88{tk,>Lb1i.x&sFqK䞫PD +U5^HbFdqvX'g;d#IrvAD#;u,,,dBl "&a> 9OӐ#F͋.TT'^oaѮ3%+|OtB#2SYUο!!|!"IwU]a.UޞI%edzniDMd ވ0;UU!iV{/t>p+մ[{p3зZq[M^n2/zytLxSV騥مٻhfuoԢZ@nh+2 M>n32L@ZɝC /wo40u"iF|sNMsGDXIR߲"S=KkQzp<*""Q PŬ43 ECP1В ZˍG֔\&c{-D6I,mâ͈a45[mimx:Ċj',ְlrqni(m5kycC i$AY{+}Y&i+="&#Wd WglG9~'VO|ٓgB^7O>鋿]?9{~}}8xr̲b^аq5QԦVeׂz0Pf${]-!([}4c?gA?FqzhtX,AŞQţ2GBg\`ɜ% <5/۰KOB45LGl +++ShD%`рLXNe@XA)1v;|!P]"w{e`HP:iDKgٺdHXQ  mV\e\]nQZ/Cy`^ 3\2D0Hpڄ!4Q[ *-.OP^Z +H%'d)jV %z=DbTƵ,w]HRl6sv` EDF (oEHBVkGvkV=&yZpHڋAA<܃ F,fjC1Ⱦ]bK<{0R+8*ҰWXmhXhqV:e7TPl#)% +s Lo:-1 bnɧ2hx5zȵp[TOZX85Ъ}tײ$fk\B-UxPûR'U|fW .פbHbR=v5:E}+;mb=׋M` +uxvk@ MlR;Gpne PO c4khqkui=:6&EFٸid3lʒO,B pJ|=d8;UZAkAXX+ lya(:gġFO #eҁ= 'Np,8ĪٍEhs$X\zKĶYEo7M ŭYZ6Zm TI°ȜPgdWqAV# ]6Cx{ڄPJ{AjS4a]%zώѮБ'v%2zg,nLй'`gj!F0fq;9[Ď|sTXOku@EOdg +!!2E]sԐ;C#z^+zU4!kn8aV`殲g'&=S:1b(*9Vv|OAU2\5,1zb`ijh3j#8 m'olrM(ŒsKֱz'lp@b/kv~1{^8~Ud DY!BsrIyA)Œ*Z뼋*+!+J2g + #ƒLu,xů.+1 ZO"ac:kl +Bfgc" gUT;݇F{uNŷ"2q>5晁Sk D2*NE0C,zl`o";X JCD:/;:,ǜe>vw7I!Zi5L ֬5!x,ǥ{:AёePWt0mxW><DJ.p,!8YA\f,i>5-@kު,|]v_Rdސn2k\50jVqko)=; +.X(٣S ikat;(J6rpL{Z7Ѯ/!*1xOxzaYNJH8ĪDηנg2v8{ &"*i;> )(c +*eh::EVP"eQX-L:SGI!L]HikjYLt:Y*ڒøKil,jF# Z,i2Ue/6ߔҖTp\ʉ[߫ϓfzT'z +yk1 L]^O;]6)֣ Z .6;"#HKRuq0)2AR{b#*fAyrI1FM䱛im5T`6IrŨy +,l^kг2%2T;0˻Z&J61>G&` k Pk!VNe)ԳmW9_iW؁{.7B]"A;)uUD*/ySv;-mڧ5vY`& -TOqm2 T5}IY A# gʍֶHχfP]Ɔ3I|SLPxhQiVI@ VTKQCZ5ͫEEUtŮi̜m~Pe璏jW"Zjφf%r]ݔz; ^N4q i΋&{)KE}v5N@ͣD+}ߍM-,AxhJ`U!h(%I5{J,a@?Y۔4Ъ#`ݦVSKje옜7:r\kr|5$X>R6IU07k|"gcZlPl(ZgV[>=ʎm>;;e~ZC9\}~rëӳoh9ah1٪s|0u|J (*d1%t5HZV xZh'-˳NșڨPKY~M)zJ!K~ ~UmQkD Tdf> 1j(W +=-W.~'j?narGΦ-i9@k^E *^PA!bPkS!('m Og_ j ӈ,5v+"V"lA>,Rǡm(ehM 6A:@kz8^,Na`*ehj1>= r\_tRM-K8'2*K&A~&!2=j*S>&jBl~n a դ0u@w~=1lȽQNv e!ril .s &M~+ۑ='=(TTNwHPɇ)c6MBM2zu:vL(տ '"nH;!AZNN8J=2B7ֽ:/Wv܉2M~+ ?4(R(tW R 丅@oce_떷6qZ,P6`  /w-T?d'IT&Kw̐D:[:=c wmtPK>GcCn+JqvqJ!΄8y ~-tNke@M|9RLbo&i&L:t@kiv H}{@i(7'Q.b/]1_sK{=Ecl/klp].ZmW ?td 5I-Ki EBhStMk4?*T2[)gG" 3H +,0y6ID]WBT-,QDI +)-bj +0|@. l $eNX}{PA;xtu%PuȚITzOm502r #(*員=ĒHp(u +kS&3kPئ,WvR/ۭɱ]N<;yb 2 s7K2` ͤY @GIc.r 6}λٻ.ǚljAZ[ w,&?0bwQ/H7ludg nDTP@ooΌd h59Qf8 +ף;7"j2EuRMSv\IVGςtdHkm53I(biW2eQlr|Ƹ?}J8@DTα~sMY97r#A+@c^x!3JBlQs̨&[F +F\nN͓M_}|?"b&RDTe5"/?^@HrN +`DwB:F1ПpIf8ۮq&1<:Qzjq-Lʇ j + ۦy}CG&2v$l>+e$O?JXlrl FllEv^͠m\;~RAɩ?8L⑶fMmU\uG`G彌>h!DiW #fv1] ,i t4+fQ|(5Rv2V2Z Thf7Ժ̞AAsd&ee/yζ@[sFWPȰ87DuÌjSF`WtӃV?X\>(27yvK|VurӨ!MW&*\N5ړX.l qaF"OZ{Mk&yal،Qd@^Bt2/zB2LDMF'}:bJ7E05|peR*5"TtWYT8T>xj̥s#+Ѽ ٷtilIW,}TLN@3{b&USbj|=):0@TvȨ)y+.+A䲲˪j̖2XH^w|LjG)\V ]dh3d ܃@ +ʨCa Fzr ʱ^r(딙!f6fWCjdi zN^Uom_eYRĄԾ6f\V0'*%hV5¨1O?Q1 M+x\nFLnT4m`rփcuUۊ w;^1pRr]m!۪|ni(D*2gsr~pHmqrPx?#qk551M;*}7v+XJr[oSŨ2V+`T,~{vJ\0 %a]=JMٿ %ى8dϩ;W$S1f[!zi:c`0xǦ>{%(+Yd적>!ge@][>%`fWmE1[]Tp'z\\*U+q%,&N4zH;֕"?¥pՖBTT6L&>] .%BKuk]uf!]X#"#\(SnB wݲb%]E4!GX^=ub9i,  HgB@)<8C t`hKMf5j>@1lչּMKMXxl{p  ,á|Bc8ʏFc%E iq]9ꥀ&!=uh@Rc-=mr4vc٫Q't"IP =,A/g0Yoh+ў3a3Y]38* epx|Z[06*N=;5zq A :y٤GdW/fXSH;ˮ0hQmxk^^k̉/YZxjgٹ0Aytir1VfPPw<ޖA+@\iP*0[u}VJA ɭ&o„' ҾPw `*RGn!dxJԠ j1dCE9te:{#LbU1dh]nO͡%LCw)s5*P.3bvx,sL|uU‡`5G*yvr3dQ <#2`T/kZݟ꣌ufnJPOTّ\`|zrH~0T64js([#˖`(OT. ' GlFI1ffR>|ވZߺn'#ڻX O8>-d*#/-KʺNJ](e@^aWV3k +횼 +dwO5I ,<,opaF'|BjtV_D%$ +^9eV7N47ȧNtQڍQ-Yqz8CyqjQZ$0&15g'=>-#{|ZDiMdO=>>M#{|Z"ǧEdOk"{|G4729bǧEdOk"{|ZD4졦[e#0ǧEdODLkms= -I=>-"{|Z"ǧEdOk"{|ZDiMd9iӚ=>-"{|\."{|\D&[q2EdȞ *4BG+=>#{|\"Ed&kd]$`쎏k"{|\DqMd=><~`==>."{|\<ǧEdOk"{|ZDiMdO=>i"ǧ7GPq Gwyj2P0Pk琅bM>183)& 2pb2 Vj2MEjP--M>U/ &{MddA .0Nm2`2 |Z lb2pf2 h x+&& +qSdAMY @e@ia2g&Non22&.vj2lJ -&QdAuddPl6dPe2 @&ك*́>l"IZ fˠ`Z5Ld-Lɀ'15ddb2lYd0C(5L'+3`g2dP}6dPXh +-Lލ/ &Pmn2NՏxi2Zx;.LVLmG6Fw(MSaP$4Ӆ& uX%^T5jj [N^=uGAf, nQo# v!Pؚ@ФYW@y$'i_f(40}GxAr|`Z- kSAøE#Xj P̅b> +*~d 8+fiw Y Ul=(PI@T;/:F]( m$Qc8x +9=Tփ*"AV+QmѡޭcxP@2Tl@zLHbB*q2sA.]% ZKl=H֊ +Av׌ͫV/ƃt&JDWã Y v׶= M֠A[3\U6_9lpКmlN0ȆȺb8@C6f#3AȠFh;|*0sJ൅dk=.`\(;9b8ҥ ZJ&xj7Z\7%jA[ydQg]ni;tY ;R8wu;<, `WΘT?XYGߪ]pE8Z.o~boHXc:a!S +?WWBk4Vuj"R8V3TkFQWk]YrLke_$Im\ 7N6W:Î*=+5o4}% +9RGJp~\2+XâvJ-榥2CJ? q Rvٽ.?M]].6C*vtۃΎq|tubvEg>WWˁjv}]j3nV,%H FYSpIk|(r&5%0&PBc'lGP`&.tPйiُRJI,QcLe}(~X?;6Rtw>K¾l5Rzã!q\EXW +cp-JHM]=o*%ƱJ] 6UƻBB^6m \Tq-CV& I݇l + {X)i-+В|||3Pqc&$ :RQ h HUL! oUW̷ϩt@i.o !]@3P'Vw]iXj2Y2Te+gzQ3??t7/cqdP־ U۪nA|&/M0=”}By +^~46dL4ɘ"K[HV,ёF@Ey@Whh|#:K܈GQfdtR]+֮QD 7 BQ/{eרdL3(5$a?eQWCbϺ;8~Z;ܚ~u@ A%=/u+q%+}K _Qs\VpQňj9TS`:7~=7}Þ93'2USN ٥է4o(?ec?^jHJy-w YwwgW7崫0yC):ev1}TVo!fZ|VzWȫj{AWQFOe Ϥp:}̅uVWgOLnr&xV~w.wK r)vyQu.M9)3djM`h"cld+X́5] zg7klu`ucC`XLy붣%kąd#~r}}?g_-_ޞ\Ջ//A7tpH!5cAVDCNS˳Ono_]}uzrq~nΟ<W;?ggS7L? ?Z}ȃͷzOdWkٛ뛕L#AI^OâVw8/!iZ6grr%I-ZMKdez,hz:,D`C!O +$hkOD>h5ᶽvNp;  lD!ڍ e֒CtmQ_f1)߳:[pP!QRo @?ZhA9S+HgB2IQ M<ưԧ]RR霦"!TE%6KZ'jEԯcOh7c2N`!'gVrƙ0YS-)KՖMaUe{M"yYg7\T>azaP.m#W=KCJ:~hozOZ'[qH +BX}q{hȱ,˘]c*#u{xAcV^26fFpL),/-Gỷrqw&ܧCӣoNsi_f \UF-Vh9F uzz5K̬͍J rv9kf8ɚUa̧ :ʴ`&YvВghLc ҰJ~FFʪqSO"F-rn_[kG7< %`{i@g,j^193oi-N81 d"cԩ%-gRdjUwByiiBEwvGky4*c4$5[5 z"PEkDMZdc"A +.C U#!NHw%*dPDOkBMCxy54eJXlZM.n#iAJ(bK9AW ڠ)fimо`=⥩!SN~e%4ũ~ͺ?B4 byB()ʽˌ6dC܃XA4x(َHKu;2E +ϱ| +'_P`AbX=B!kؔ1\? &$BP-F[>N0|6ORiG"&mɎ!,(=`Rf^<//k@sV ~4W.j.y_'֎ mRK2z(D`@4 J w)MtN#W bXVݭV#Oۄ;{xF@r|_@@B05z:JTJH( ނ y;hX!VO-GK :6:#*$5СJ-i:0 :eJ/rRꕎF-R>i Fi%.e'P(YS.jV,#C<)c)\]p 8c4x#; COl#D~A%Sլ'6Lh%*R"|k+[+? Z1AKŀ7ٛ3NxK6Z˳ G;W(+) |'XJ.NRR`uت2@(DAK1"Z18y< + :ǒNU#B-3ho(V^L$;LN`L$ +(.w=#UARH'#(Px+> @M\+|  gu~CgbX@Dc7Bd 2)%Q2| +2 +-H*ع;P8WǺ"lSv"p4r"~f򍈇XOXDR68Hm!3@J׎o`R($0$ 7.F0E?~p%p۶L(h$ C#DMeWB7K&q̩G^G +pzF +By ^%˃N'!l}J1n(m0%YVlt`ԯf fizGȐz$lıqb/sa}k% 3ެ^U +xAإU%\ۅ3R3"):׉O ,bLU#m2I7P ė$"%6]hq $gVw$vHвQ<R ơ& z)/X+&73XmJdiYTop %Ա $dj4dr>`Nwa~Wa`ߊS,u Ui87rl(I8[3 +$') %Xb EjR8gGnSXG)N`1ߖiّX 'exg^5A,J QˌPćˣC(%bTRً<`Xc\Iq0Nt@A= 40AAל'0B!'@u4QDۍ~%O$˺`|R^$~zl,n22 Zz0*;bpgM꙳X mVU KIJ)N>V@"qxB3-ɆA2%޸蠁Z dRyOV/I.RQҏރCꨬF]K$hp6 CjxgI:+ʺXgIFa?Q% 0ɝ$$) (qq@CΣ#N 52 }ְ$0*~@V1;2$wDn '8nb*r$M NأL&Wi53Rajpp`ɇ$ ہ]U@Ӌ,Ix  +Ot~5 "h-&1e-mo1XH^T&=+$" +o4)TDx!0$=kB@Fkĸ6 +X$YBY "Ȕqup&p /Al/r2,!_+@Ht?.  1d ~`, .ΐYkY49!V&N(6Q"F}/NG*%  R,KnԆOdoHzV" |{D2"GǥJC&Ec yf3L8`H1 +A[HւoN.)Hqx.>%|"CUkM݁ى#.'Ithִx +ѠHbpt2dEH,h,,d 5@"xH,_*J8`(3ãIΗ#+dH=*H1b"\!DU& tLB;p'w<Y xRp;$ 8woHh^ "Qdx ܁W.P`*hdSE:rD!!]a zEBΎjVT刌#@̈́D +:U%6#@j Č}DCqfۈFЁ[#%@@hHUqHޱipIy|26TX)Rt'Y܆KL| +NhPUX¹"Riu)rd͝"Y@C5>CY(pIa ֑(JArƚhW\/^=.(!q"B(ølB= ,Aз @8yaH +uO0>X>-ӢD~V4p=$.cd",v[ ː@3d }ƂjweA784~zdN_^.#l*f5>A1(>D*k\8FԆ a~OnѴ! ᰬB$ l>,eu; +z`HJ`] * -X3F,KRx +#AB_idOy$,zD'8 +@ +npI \47r@p6y||9m8KsB +(7pKqiP`Ik1& QYBeGZ +"ACj_τyDKȢRIi8S 0R$X,XA)pYOg8!uL,F8rn\<Ջ" 4%x8au\#=EB^V4^GWa[8nH`q$cE&] "V RMg#Wp?.`, EoYͅr( x7QToek’(^IPv=R{܏ɄcDqz!5DrZyș8ψZH|T, +'AZB`hhn(@a $+HR ^")ged!bF*[1DCVOкl + gHCc1>k-Y6rpeݍ{ dx:=Hj?.v,%gߎocO4eiOdzrұLqPfpuY|1%#ȔB<=Nvr:j # rțhVO܉δZr޷S5KE먚; yRFAOSfA[o@YxlԀBz,/6}P>mOn8>;Rt?6׈+DT_S܅2,YPubYy:3/u2[2y,A#68sZ7ačƊ,%!"X{/K/:jɿ`t^5]A D5=d,!dՎEY"%GB|duЫ(<7 }hb_G[#MPk 5L`˞QX9P;F JcxNaݏǺБw:Qm".dPOm~A61ٕ6ƀҐf<eZc<4j_Ep%״AP8h(, 2y^}H&1݉و%dgoC)kFH@{ i@zw7x Ń?P_(zH*A4餳,4rb UmBGz4EMmO?؁G IQȢ0aX9~1(EsM/0!\2>K6+LTF:QEv$*: IIhuAS6M\bFϳy\鸮tsu>H2 ?"ګ:s7[2]P`#v'r@q$uIg#OӳLFK:(}eP~+B5oP(܆uPX(Y2)OMf'V'.@//+V~\)<5h\0z;] &WAQ'/$H,rxD.W ݡ$pM$͌K2N7r[!VmzOVvGJ1lO"թtK/W^NהNzez+tcEx|'뫃^jofoB %hZ3ӥVod!ՅQ /sr8LdH&GکP5]ln4m):[Bf63ӗf{z*qEC+̨Jh u>mYyKzy2-[,%e[B&:-geX|6qRƙl$ό1l*^e4 3j6gY-bj)3X3K&B_[䪻4Sz6楎fZyjܔF-\`%OK [nW g5uu*z=SR6\_2SڨmNUv#uE~Qoߜ${@,UY ZjpY&pamڊ.Yh0Q- 4F[{L=*ꃔI |R_X49i/Қ?ӃB  {2Šg ~vM0e՚_L(` KW,f.3.9,#v +"v|#뀕ۍHՈY8 B~d0#11>Ց2QV lN=ß]#tY-E7ř#]0ʝ:4JTSFESޅ}=,)dhjLW"vI_h +|#+\K.lLH,-EJ+f3-,7zW]V͙ )XQY.f'5StTlmiF Ӽ,˰c(zAMl2~]YIіҴ7}!;>фKֹ>)(5w$hY ʔD2+ kOiP|:Zeԣ,Т 牵p )(-_<\Ekhmo#oQE32224ca 0t4 +c#!p %ECcI,i '"҈P edŠ4[ +>"#p0\J_*+,RE#E$t?+*{NBYV'K2B<2˯Hqnb 0tbDh +"2% F/TPx"(^PxjcX?+(ɓҼ-'?$4%!M3"{!ے"@GH"3iT|$,A^`)N$vl#M!A<%M34-%E멄2FoWCFܓCD`ze>s6$z7'i$zie+峹’- X[Iʊ@{@R C_hքt@ܕ|+2R`H54ּ%y*L:=hs4ƜaJO̩Ï=VLe0I0);\3eqt )Yi̛< N7zGh0`{Vѧ -pR[3C}$?nW +>kV5.cӡʅ*,Y%6rij7]J|!Rn:s߭VkjlV`;qH|)S `UFjz# +crɸq=o>{.ym 3&Y)r?+qm3!]3}GRƉ# +&o/4r%_י`O

fS?g {w +GLx.2ﳩw^3eFD-{d(PM4l&eOi!u]8%Qɞ80} ϤlI>&]9;PFXP=߿c:{TCϾ}4]gx80@ zG+bnI^%2HwDsLfBvޟ},zsG59 wAJ^+Ϡ_;{b<-l"v3582?oL){)ahchR'$5u.c:?3l2|]'є#E%ӢDE|%C:ɻNQ|&G%yMh<O \&Kkߗ0\xJH- $x޶:6Sj/euHtg+LуՓOb$h]ْVi }d؛/֌S;fqchWfvk1LXKzyXN!oj%zYkksfNYAyWGk[[ZڹZXڟ* I]XwY7օYf%6g6_ꜲWUV"6.O6-\I.-3;Uλ.w{OH픷^OǗXqf=Mi}7i??; sfT Nbt:_Y8˒÷t=:Ke #z9Tr㨋ζu<@pVn{vvAxD[ >q8sB,'Ά漿ʵ +5=pN7A2q97W@ ݺS<)WW1vge +w>׸q-s\3;ؕo݂,goFneݍI~|TNaVr^$6+=KysO58xn Z b >x#v~_pC{zS{7U˃=i\Z+]#MV)V&8{dh`̳=f&`4# @"| Gi?Ǜr`=%A,67f)zTQa2 + +l4Z!cCs^s1"z>(;k:,UXTTZW,OM\ڑwN4} guO+T ݢSSzrQm2Aa\>&6͌bs Edwt} +MlUL'4ξzgP'.H +w>w=]p霛s7.xFT_*Q+ +^o\ ! ՅF"F.9E#tȞ型b3 Ŏ6ؖrF^\̤b*Iȥ4(d{%ȌZIgs&_eQU=E.Ea*ڬHgwj4'iq4p\6NF\BD)SohG}޿Rg1osvg/٬1ҭeћܗcyK2+Uϕ?}9BȺui`A"ӹ%nz7ěK'][RZ%9{r}'T˦L)/TkOoX `0tOgz& 2I\?Zw|uݼͳP_^laYHϹA=9ܻϣ]Pr1ujË~&v1zy's`X{μݴҾ^=\~E[9ͷxFW2_jEjjiV[UkK扣]i1tsզθQūճ:JEj]ݭ.n UΗp>٫I_ Pܣ'2? &%} vzutBf(FwKZnDZq3 Y mDAݍ:W-Z}!msSs2WW+(sxLWzDnvtiGӉE MAQ [}:A,E[ p*N?!iXq4 e|Fzu7hF7de`?u[֩l*)Qt~,њ~S2HA pj~}Ym:F64SYdP a;0 x{ۑ۷ivv̫-$QsGmkD\y:4(tg ]y,|-L^E^Sore? gtF|#Gfs3yNْ10(TH?D(3=h? + +\ tV扉2#)/sZv3{]{vn"j[qhؽȼo{iR!L{D1le{31Z+_QnY $Zn&BwR%8?/2=y*ǵe[f9NQ[N7y 8⑒U[5ZƣK:(T_r*?NiOlb}Ms7ɷ +Tҷ_a]\(~O<8e֝tb.8ʣ촻WgZnnaiߝ'SQͫD#~24o/,hlm9ͺtGE!lUxzΦT&]02ɠhW-!gScƖ@I&G +cΦ-QIҝbMPgq ͫG㸶3DIw3t He;q0eVQO32mʝs/QݷtWM֪qH? ȩ$ U(ʏ|hq{҅(FK*6(9dԝ™T.V-WN7yu\B19Aoʟyxd:qI-]=a1 ^Λ;V@%%i,l%;g5e+z,gf\ҕ"sq\q?D_t/{!3UOkT˖ׁ*I2y$:J%=If.C_!lASX̟CDXiRh]_Ivǀxn=֍%Lrl\\|sg*M8bh.;ΖlzD')*T!G ҵGNrx =8HliYլ9B>Ӣ޴i~4j ':JKuFYM{|fnA \Y2h:NEđPSZAլgB>F d LHe6afL|gLmf |ư13 D&븎V*>w7VWGrbu{T_,ΐ^f_<־I6NC<_"0-l;,٢-Me6FdueU6= bı8Lޤ͝QxSe)Y'_DmZ ;e|΅vP̔=9) )έGk 6'MڥcVZȌAVMr7L8F1AB2 "p_Sx\-%<. +"ח09rWm;* 5@jfi=р<tE౲f.~srȜY/V'(Ʌ$r^מLH*M14 R!yUWRΑ7A"k0uRp٪RYpWTm c_ ycTX:&GfRGweHr$E <<'H1zA +3f+\d?d5w&[]~,+MQ#$aIءr1bFB6ZHf׬[ &h>G &` H89fWEV7cī,9t׃)+Luul5Pq3P4uϧ`> @Z=EM6G]%o.g{:eC8MMHCI)rZH|HU 0×tz٢ KVzp&3.ppj.7HՋo'A=a;m(\#iuV)~U COtQ 6GF6=?ͼPtf2vuJ^"6ql9zJ[> >kyBOa#,yEٗH? s݇ ڵLHYoE8}dSٳn̺U|HTr9b]<2S[vt5ntZ[M)ޕM0H+tr$%H=[l)&vS1&'h4B8Nwߕ$/}980_<v%4Rv'KnOEnOBgNL(TZ qM+,yC3󥑻!IyFHm=27cS] =:`qp]-OASn~85(&/J٧HbCi &w^kы U9q1şD}鶡1{Fqv;5dy+ˎ8yk=  +W CIkx0GLXk$d_yȎ%RNɞL5:Dv5|Үy5oK}5痷@N](g!J +=᲏}|_?|O]fz˸57^+!xz5z=%}Ť+a4j;-~"Qkv1ǧE#ѝcf +z-iCձL([l 3C3om1>2N{+XG{,D}0Hw#"7ND}1xLufSI %Rn3tx<+?xi [}"0S^ +Ynte`IpSϱd_wؗW9Qg%R@$ #4\mIJǂN|\=⚕n`%&jr#X/ Lg/آ@{3µ=#q"Jsh%d~.Rb3fρuDv#(jr r,u79q/[ӲJ<]TQ3s'[c~&fHweWD)?[V{Wž.&3!GS֕N^nO'ktsK%źR$ߠ=YƐH׀DM_ G׮H>UލzR$BNRu#`C.-}"uO +o/qsnzM/Oi=9t?=m3,[3mcC5PX5Fv^аs]b4,PQԾYUOW&n+S#\ HtWA>*)1|#zvjM[A|M뭆>Pzɮ]ծ}t>Z#8PjwpADiU.{`r8f*fna?$k(Rl.4i5*?>砶>;O@[ӭh0 q^&~Bn[3V+(u,?-im hpHp#F[Xn'ۭͤ'caŽt>i0K޸]Z'8KM 6QKdvb5@*tˁf`5sg!H"[XzKe:r{ !B#*"jWvQl;ͷA'Ą~Fv#P`{aP}$h? D[+=ϡ^"~^ z%^]00ݬMED#GO 4m}r~Ij|J<ێT|ZWxߡX8Fj}Ķ;Y;<‡R"̴\|tٺ_oqEcY}?<5?0O ׸@'C +#+9[wm\5^2 +rՃ{;渋tɲ "hÍsf{Ihc`,7ǴYg-Cmche:.=1'jc\y ~35.E-QĈP  tk%I ,&HeLŃR&S?B`~1M?%c0[qvY5/gX1Lf0>02$Qr\j.Bԛ%#ȉ#_28eC~I"odNZ󓝇(}1U7[!*+| 1\*̮^\/"ycLw6l*.u[e|g5og@U;qX}a깼zenoUfٝ)7ge4;ؤJ½0g2-uN;k%B(cE&s͌xOwYM{Dž^Ro + K&dK)pnTkZd@@y*4#KEyTIcȕu5/:1]`h.8=~F&GxhN|Nϧ5PaP9vZڜvhVGƄk'5ع_݊.(yEڲ܉~=v͕&=@DzLe5P|x6g:Kc'؋^>x@/24A#UwÈ +rml tԟ4+=w}>zq8eݑsZZ *剽K"pl en˝@mٞxZ3]@aSv\c8)UhJTx8uw/3av}*z8 u*Ԕm-=+{ +vq>'ǁ7ߴN YjPCxl:/ˇ{{'Цk ޿zma's}Q,hu\gѳ@g.H'Kζ؃ +us^LZe^v} (ؗs};=@%i> +z6Wd`/d/5Gg ƅ@ˀ + =߷f"@[gKh<%ŋ2bs%NP(`Qo?ӶΧ3ܷ5S!@wt~Sů Z)sE@S&t13X4*bE{iJk@-P[@[X4zmSq"l< }{wEWrG75ӗ2[o~ioCT +v{޷㭽W]+}|`oK9mҍnaLWlŞ EzNv]ַ׾vi[Ʈ[d{Ҿ퍣,}.6ѐ"޷ǘ=iKvZG޷D}[`m~%̩'-AeμƜ[_j~MRyxyܜ6#q=tۙf_xz%kC1S0S@AC[ ³՟7#txJ-ih>ƸΪ]8gY0ƲI"BeiBqVFWY˃--_ uNk8TC(ww(2"o?f+tcQl+]&&ӾPv fm vg^Ń^Es٘^sn?P=q=ר5xhɵ()@A7Oؠ*_:!x˺w~' ?{)hЯn~:!8uS}}jf+'Ǟ7P+:ՄIfebYՠS5AP/MhA¹[nWbhW 6L.HC'c;ƻiQrwXꐭTl˃kd}I}zı03#oa,8B.6dk{`H^[Y9ƥCC;qGAt,>7(8qt,@\upOtV1.$GuiP:.cWpI؋ 1Ѿ8fU>4]>vf}'z`ŹIek2Y@ X2)qױsgs||m+iacxvdx[9P>G d˷1|"ٷD. u,Jnn2Za歠)g`ORy>NG@ݎWeA-AfX_+cs㐾+|׹<, +J/< {v>{br}XW!x( !"/Sy.ȹ!;ϳKkmeH +)JneHƅM~OPyJM$H:&)U=r,@z;'w|ڲ{>'CYqw~*h<׷ +k;Qlқن+_n҈'u|3 X.n_xsl~=][ažd[KsxjyqmVѳ7NGi~D_;Oh~b^>Iҟl},Ζ}Y2*y +=;JSh=q|.G ~yo{9G~7ضF=4|wFۙ!I!V]5~Ńsvr +tm%h4D]˲F F^~~s`5ȟtVqB']jNE> +mD1χ8<Xþt]БY +yeKIkjuִ~Iɞ8)MKoD? mmjڧa>8~o/8-=l.^ޱ;jb |]lZC43I[mͱ,Sb58 ~ՊվhŠMl[1~W/uO?Zöke{CAO{/}ޡʲȂ@yA|y;s2{ٳ%d +"G Ⱜ쀧F-+iƀ,Hܯ˛_YxusBts5tm-W9CǮ\A'2y5t +jk&Wе穡\Aױ模\Aשnr݄jj&WIj&sy۩=9k&WЉ=6HPavnW9`K +Fzwu|caw\7}]]+Ƿ6}Nvȵ[+Z!`G=D&M65lV97xNᇾ5z*D&-)T2ǽT47H\s g3AA ~,=l4`sǫmn]$䬁AdcS֗zIӊ 6 qM!לjNɺ,gl?U>Yvgrz+B9SԾXu8ݷarٵ=Φ?ߝ0 ~q4{^[ֲ:f:?03Vr/M/lJ3>ٷˡ"׍`oh_sZM$b9*D6ʔY&NO`Ħd#юubo|ft*ٲ^wjV[NsӉFL6~g8{v&p1ǘbZksUcXܱnM4]T&M-X6=Ȱ41$ͪ'#I5rKSʜr&ɷAi듞 2ƴ8ϐ:Y=&,C2LOh,x[6=3?z3?\Äў'aS|Ԋ*ˆlb[eg߇k=$tyfczd̳BȝaZl<-{iSuNƵ ?ɍ:uE:q\Hk}UěE+Rߝx?$d0o!/,","bWrETram8o:3hm~ fC.,] +'xEepǏ[vOl>_9G)\'pP + ϞM2 ۢ?yR߽X!x[4ũAdNnFk2z4=v^Ͽn*ZdqCLT32y?hdgU~0DT^?]:)v<r۵`׿trDN[Lit5ǀ%b5 : aE$zv$Se@tiKr3E^ HN3="77<"׻лoo >i8x?n8?D wHq.Toq.n`9B1A_毦 򱿚.#穦`BSMrjcjByZW..TKSM홡.k^`_\5]v%һjqƎ..TKm~j:I췔[M2NV]Mjj:wo +϶\l5Ι͉/X'6s5UӅk]M_Yp5]([`PM]utS2# _QM:_T5ݴJTӅjzlb3n}c`ӏ)9[[6[ofy^]u1~霚S !Y9հHE9K* +.MLkI<1,jg'-) 0i³="Z]R79>U~\Z֤~jI~gz_5Vi3w}\ +$&㓛滫g߇231J5虻EYfCws?sgjߦ 00Dd`ȾT>Ο +ዂځ8Ϡ]C]2W^. *{-}/}uq]9B2j=G$ Y?J<A=Pʔ얄?E`ן"gz/Ƈ6',P3̳.fy_6TLp8VB2k6|2aP~ʾ7pq߭텻IsaEh7hKy/φ^% 9 w{wp79/}1sl41o֭|Lvz>W21#,v4:O-SĴ4̈́<7K}{ꔋת}X4̅׮'bCʘ;m亮 +n{͕Vp"3qʃD|;q0<5stw @ăg EԸnE{Ǟ-53ɾ-YokmfzqKy[Ǭqmg P<K\9ytΥ.|{O{o;FHh;ݹN=ʯOkﰝ~n矷TW&;exپڿګ"^N~׽{N>37ޏ?ö|j^>-Mu&?ݼ#*ǵK/>>vߜsk{{=N$wv61X"̈́?wGݷzIzkv])F'[셭Qv}e+f\?FMb謓56Uĵġk b689@7c naII])QCJ6Z,Н2HdhUy/gMs:OQ6iNii=9IYWGYw7+=KPZ. >PZK+'mI8-눫k//&oϕ7}}mQm.p8ibxyhy:65^˸cS3~}협nMVۄ6+^lc]H nw%|w9nd?_Yz*@9=ә  +ɼ,xmr%L5VL}ZKr_>MO;KjAmŵ3~:5jB)'_y7Pg018_aiqk'LhNlj-Mv3stf:ed^p:'v*5 NP8Џ'R8p*5>v`T&x.v*5}Q(ߠ+yUࢲE#Vn.7w]]pJ}o~ xorT(_&:ƻ~)yMFԑ9VɵWVf +7ykNuw@MPzw刓?^xor:'>~ݶh79,ӻ~gaMN, gw"L֫~9s05syJT7u!M~կ9 nU_SEձ|b.] ^{|g'2=) ~owY3k5߄hۣYlɳ"OLU&qN{or"8~v7H=O )bֽj[:߻~]Tjһs7顱]~s7uM~oUHK]÷^k}ewPrU.g7hc7Ĕ_^ZM 7]-'6{S_9ǻ~ +wlDh2߻~ CX~ׯIU?ɪ_dl)7Ȇ]M յ=~orXŹX$0+J?;x-v&{svMOv4[s0ݣ>;Otk_/C\^qTu)7XO|h݋_]vꏫwj?篟}ǃǧg/VtwƷ?_vGGwOVw镵dt_ߎ.~&;Μҫ{^ܸ/o/Yޗ΋=|<^}y9_h꭫oF{?-W*uuWŽͧc_7>6W4վ ԗrx; H'Z9{aa`O^޽JE3GN>y⩯?vO?'?XJқUqn+D>[dvoU4[[[X leݣy@sރ~u֯w˓]{zYƱ}+׳ɏjZ|Zʮ|FJr7מ\矰{,0nO񜢭߫D#m$V:>SIJ'_R s;zaC$3b/~wvŷ L{=ZXz q/?(,{nR xwjJOۛ?W?TÍ{j#\߾ww8:+}}n?/$u7[G|sg_}z_גzOjmӶokI\b_C-sƪ\f\Y/gpagJT(nn#^椥gzߥw7-eAXß^(K_+oĸtLaqSO`Qת^{v5>W_/7o^܊bK&ܭ8zgw~.N-~flɆ410^ϡ%߯#.OTq3ݳkO6ORVo~ͽw*R :9EZ}\;'qQg_Y߃'-o~zv?Qi__Xhy7~8.NӞ61saҾ;%CWV*zcj#-kw4-5 `_gD!+xR׍~M 4:k7CH wn9x?8UX"!Pկ~>uWmΏ*Yz1r}+W-9[3m1@YsT{W [jD EُݐX#~_뛻RUdK-cV\Uek+_w~pxmȫzZGIoW C^-r><2g*7mǝ^ة^{ۮ;xfݷ{S 19}^]?{٧뤍#>tȜZn4Oh_~zXj}0:!Vjbtmt{Ϗp'OϺM8V{9Xu͘y?>{QYx0 ߟzėV7hN2?l34ij7RlVCW#; ٲeOפq9_Cx[d9CЗﯮCxwQ؏.?9Pյ[!\5>t`y>$>ûi.aR-)Hxo=Ah hϘ9i˹.jmWE#׷ўbIQQQsVSud_mNb&I'!l{b3_#L?%B⟽r.wlkKS p4>cX$5E{Ҳ=G-v=Q6NXS :L5A˱nc^o`\G Z׉MfF\!kXrZAyvgɟ-|ޓ^=ԕNl[OZBT9DZ>S7Z}Թ[&E?)m#\޼Y>_,6ӯ}wmC:* +g}r!a퉾ny|N}ș Rq)Y*f|CqVMp'6~'S'6̆_cƹP[^LVZ;YC^om+j^x&~y.48)VLDJ \7_?v +y^+U)n1ϒj}l{gXݽvIa3/it\F +SRIy?:X:uR~{/G_΍<ܾqHw}8mTJC6iCv'hʽOO>nѳ]?u(Wԕ7^,oĻW_Q$dQΞ9yϵO) `W\Wy76A29,ߧ01Nv ?qyEX޸}p}쏓?8E;q:^7DRvoTv[z]m|xQ26)9V[WW=:kO쁆V׍$|?SV7IyҚMR*/:4$55$l$$5agi&$8l_5f_lK+]ZIjBZgiXfcPZWiF9ߤ5cE.M}LxbwO]ڹ׷܍lIDZ\ު! ^¼Ѿƽv5jy^@ԮN}'b|v"e"g"WTo3NVt|;)S;rWZ݃=%9^ZKk럋q@B(t^ɏg~nszm@l̄T0 +dCոɂ-8y&\54BPC^@N*ȇgChf}'W2.3%|ܽ픰7Es$My$&Fo +ym ԟBgXJNlm<>5SnʍyhZml;zoNƻ4U.Q߷6%J&ubY/~{Wّ ߽93'@Yq3A/Mh^;|4}]롱SoL%. [ @cC?1]0 /Qr nz00r5|AvQ~뛻񆷆l_7_zOYϋ['ǏjM|:J#O\ń5|WD򾻊S\qyaeKZND) n\j|E)ayLZl.&;yꦔCz <}z9TV(sYW9aC|% {oqR/=>a*t4j \[^3VW$wFbXB[?^Eoc4m(*!)߬S U6?Ylؖ#6Iz_(g{^,M ^h<9)ִCżuZi3F_?>38s%a&=?\/8y^Z|T07ڹhG>۴&޵yϏc?/^K$SA)"y9 n7#oqxg߼+%g>u,H_{t֜ :?EN1,Y9ڻ*WBCYg.R)V7N b5=Sk[崮+Qgˆo5(塘VWU9sնLxyxc+J2+ӬDdynt`.}E#RFM@mfs["v<"if&RU /._Za͵ڙʥ?9 }s?_ߣKjd'y9Rq1IKW~:kmu)]f;w?tp{ѹQ=<7 _֘!}E,߃?-<ɳ2"MʌˈƱUP*R~Qh M8K2U%~%Qb ËT?EG}ERd7_&/~F*x>p6q$IGITj\B1g E\ǙkAX'iKcfdX%YIrs"9$G*DTq^qt&C|(Q8V8T,8, 5I0/FcETN!/uU*8 Y2VSyX"S vҴwʞ.\N-BLQQFI^4(,JKcRAӖđE FttuȲ1 +TiAPO9Cp:qGEKd< IQV1 ܕ弱M\ dUFu8$%PT(rnJ="NAIqE*Qs "7C<2?H6q<8+c*r8cD3 !8 L^E `=)V + +Nb{1 Oa&.0үP1Rg%'9;āِ)J%h 3$NRp#.Fs\nO:(HW"8 x:m~ ShDЙrګaƁxh:Œ 6-c0瀗As;-hAq9Ǜ^=9B 42hf̓)aƁ +* `cPDz3LZ1fz0'Lō qNY(tzYL/.U9_ԕ0 q(aؗAq9ǝ'90!q"8`#ȋ^C7m! ۡĈJ1Nֆ¹evˠ]\UN_† kG ;<3(?BTDI.@L`b84ЫqJ(ikՌ0EO2O6CIwƹTq{u0ih1cbb )%<Gnav((%Y@?&)yH+r:. ^nL!h%4ԝ W+-`$UTe"DAYctjGHPMȨx0n) *ל:c8"x`xg՛ī@̂+ JCb2AqK:8? &CI\awI~:gBau׬2ZF{ j,S+΀/Н# @ ڰEHA^xE1BA7{ qAaZ`1$FS$= ;uC&i=.X]3 xPȬ;ΐ93 +u4A|PhQH^ b8!g>y^0WATsٕXAs%5`$VA?+qYTP9362lV +Fqn-߂JO,\ FަzxO› )֚dð*#puh S#Ub⼉rf6͊@rYuB"7yŪ(ݪ}3s>qXJ .q+)N*G:Uce f+.r(}_R$EjcwfdK԰B2h7vs(m3 QZm"f eTKظm8fT#~)Sg$t$Y Mdh]40@ +UWGl4j%qT|15(s*:0yP]:WC#R +MrAMBӰ1@Viԙ|)Fqv}ȌmRTH >I%tX+T7+:׸^󕸪ĞAF؁|%^VU%,AA9)cpӅ廄Q2qf,a4"I쓤%lt!*UĄVaLyVBuZL=6irG% ßaUO}t hxҙ|'A32Acހ.NgxLD'8Z4jK&H-0.\f1KS5q0n=KaGu$pp0m0x2hTbQH+#/Ao\BfE~-[kb*x͕TŭduHTtVu&j\ˤ^ B#2썡|p׳VYȺ= #d|hrS|:ʘ4\ :_u}`DK0޺oB6S܄ e^0'B-,:3@C4.yJg PP{> PaZOԾj#s*Dž_. Wbvz*~M0** ɝ{B[16k|FK +un| {h6O$<0XSE;5-mdѿwKj`!1JBT1y`Wa$q`Wf(C`l2/O +w-=bIy!+F09:qucACǺJn?)XWj FBb,ź2pI7XW1r+ +c]-ಀߊ b]%@pAjBXW] B]bƇhbS/U7CkO(n&+RN#3 uU9b昃PHl(]t +#s )PW9"wCT]rBhX!@)0#24ũOyPW 2UN k–U> + ]y^ y(te5&0ZчteZCb c0jGA+a䐋!`08 +HWשt!!#]e. đ3_i!T>!@15@ +hT*V ݚHWIpEDF6_rӕ B 9E*܍2Qvťf\S~ڕL\2;۩l@ +W + z-v-i5]1p\&QJm^ST#7`Gh8$ͱN5~ +}ZeT\*Fb'] +bz LGyJǃ0hJsU<8 G֘G5ؕ7eu6`W2Wѷ1v̅Qi`W#t\ٝR!4"Pni-0 Q XNW>50 vMʰr]rѮrP3Ѯrf]Er]ac3ڹ vƀA0e*@2(u5Cp,kI<,ȸ,$`]2SްMwHo|c]= `]߸XYo:X .taHWmHWm<7u*CMt P&tƟ곍t y50&t&t}A.B5p>5 Y>HWm<6cMjئ[q60Khxqhֳg`פ tIH2{`WW0da]=úzud]Ay;z`t XWR;x^u9u' .. >PW((aMPW*@&)6X}dos.ҕimwp͙MqH@C.5Fv0tJH@E>d+E .Ud@A$1|"]Mǚa|IX 3p&Q+M*1bt/HWd⺰CJ:E%H Lܬ#]M֌:P"]z9lKanA\.IHWL(LG>؉to:%'욒>54Cʠ{EJ"';j@t(iqS!:OumajЦܻt5::eצf19g\E՗=/{هi$8>yBY璺3{ xø/ arʈ c fւ"o{hy [thv qs bQ,4yY-0>c@IP Aau$9Pe3}UssLTBYh2\y-pi$qD?(ƒRy`IE̓Ay`9FЀA 27<)1OKḶrд#dH3gYS}̣61y ؚ-4R_y@BW%4{0/+rǛ,'4&-s100{?`qou-\8)Ĉ+!$gO|S8ug&|ÌƌmAB ~`i [1&@MP\`<\d c\_F!Ad o2712:8V0d KL(7Z氚MVc"v>3aJqْ`u(e 4'J; 2;$@<>B|%OFRl4){'Ki1t; ,ےю8}Ѵ`週ur"Yܜ!Ou1" ӪR)H0٦,؇F+0+h&N2faK2"YSI]M3 SI@]13h&]&dp"AFBld #&Ԡ@ +#rG|n($)1j*wC`{\ 8z}&A嘑zUhIJOG}[bJLH.(2B3!QD%} ͒nyŌ6T&hcx+abfyn0ܘce&AI21 e,0C9 .J3YY&)c 2Ɔ3|fdIA88WN%$-)4rf@1<~Jb:\kr!DҔY!3Puh$A$$%pz"~QQCaĒo1 fSo(d)iaƣRQ꜔UY prHT}yF7d%ma`Ą$i.%J?7rBP,$5Ըq8)aXѿU3RThsJ4Cw!\aXR] 2V3 +R㌀\$C1$xAd"efhnE,pH긬$^ p'MC`'a6X^Cgx63*Q`|B)#a=Ү p,B QlkzhJ!͠VQ&j4$$D +F!'-N4~cUXZ"/YSˊI%- *^Ѝ<ԋaQ0%},Mp *aiV!f7aܸ/s_ 4#rGJKitL05hjCZ/3Ձc_ 6T]FEkav8Rvka{3f/XPo"šm`s}-Gr)@yZX04m@ k~MEP TIWXLU>BT<*Z`a|̗D^"6I2Y D . :f, aZJGM!J5gŲjɎN4. +9Z+*Sh11|X_ G̣Иe yL"Zm`c< 0f^dE5nW=t)( %,!g=lgPI#[BDфAX%o7"3}r6' L9.SL5ukr\Ϛ`>d"yLԑ0g5H F$lR:.)ď,':$˥co@̰9RR+/0'R&*05![nXJ{Kҗ2 }RFQ) $1jtFA2c%Bƾ"48  5N2*FRNRO +*bD(\@((rMDŽj >|s)@[lZ0m6%gI5Bm* ΂)H&0*b ԗd, 55Oʈ\`9Zĉh,hf[ҟ3COpQbt>;B#7 FRY-<`Xb V%˱t_[N[Kf- +9=qRuDR8m v<^QEB븭8 B-},%&ɂ`#pf,$fVDPVRR4t +&=2IM1"K8P?יy6l&xH4h8 Q +X]vϾ|2L97OM4ih&_L!) +XAbgLKʼnS΂ a$]|@`wR a{ҖI(9i.Yy!dW6~b< ,$sC)1jćqɨI=ci ԙDcL8TX4`[igy#d0MG\`w,d WҢsdlĮw"#o6H11|I\5] t U61,ćN8FeLI`+4~)(xF0cB%^nIqllƅ:G[-oT0hs +AQInLfCQѴleVV g#!*8H h~`Op%Ml.TZX@ِ011X"}@֩&s؊b#"_JQ>sSʶeOIF!+С?蛩ġR a :4 +gZK6cFLXCCT1*A_ 0 >%)l򁥄2ZE(8YkS*HpIap#DQjJgռipMӑDT͉49ӑUl|XݖU!ʜ^y'c +ThJPA Dsʨ`&feDb6!9ΐ4b}0[2BA,eL:Ce:+)5 }u0V&Ƙ/ _CebT4@Tɔ?,UoK[`XP%+]#yXy~MD)'Ṣ#Ml-_%Y DV"y&BQGp%5Z}/GF#&=X ӆմc5q NyeN\pWBj1Bcp6iS`AN6K OxHF4 +Mppn&}%hQHRI>A}JX],m4Xk"y8]={i3^1 ,-̣,reLH3]]Զq֚6?/v&kBR^5^իKiO-H2IUieA/ +`ZaeIwd$J:?bᄢ +zOͧ?$j.cV~~wiMHӒfab=HQy+WT`CFNx cMtQM +v'GN_Muc2FN_~UԬ%0/4fDIAd?k>ǯLoI2bJ7XEU;#o +ȫDvԯft5ܚL R_P!/WnV.8 yT7"=Z٣ۋ7pßa &y=:=x{أӃ7lzv:Mn 8}s}ÝNt[ t{z[N8ֻy?:wtpH?.aN4΀ xm7fa6 Gnk鴛\3Ap^݀kNf&i?:=v0{tZ!aNݤaV,a7jMZ=: vCá|aGC?)#HM%Ę^2Yu2$=[2~/f.99>PjZW˩=s\!)Q6cx]uiز'-Vnf$%qm"i~O] vi3q;}UQ75#҂p +PiKi5{Q;tXpOvϝvoB*AyGtːj[j矃3kw$>7`etfAInN4ltB`~!;CI|;37$fs{N4 g sCfHcn݆a3/7dwKVΖ,uaTƨ:r!r:X镛6n\nܲ +紈#W\F 'lTv\$d 8qYmrm&!KJOz+K®4f. , dX/7lm5;#76!NJ4"VJexڄK rmPR%%Xm Wtk5wP15`MܨAv:0+Sf[p{$Ns،YL9 1e+QVe쥩m,꤇7p UwZ!¼eOt%90~$ 4M* vzCl#II&z^lnuL^n^e%X1T[X6"`$:p3X?iW׉VY8 endstream endobj 104 0 obj <>stream +65>DS9`N [1"/vm:d5m#&VwL%4Cl6m)H/>-[+{\y!Y|i^[@4d Zֵ:h%v&!+ݷVN"l$zq:d$v:ֆN"d$v!#ӮJtMBӬ6(;j{zWmJlub֝F=VbQm@MCӦ VҀ}|RzIm tWV{-j# #9hF*\K=|fx ƒ + +Z +VDK$(J1BzIމ!lGT'R)OA8P,FJk,)Gf Y`FncP2ZH[R;qP 9 3V OVϲ eTNW'&@;ćRvݯٝ!_JXgƏfy,Y +ywF=(,fo *LF:0/;!Mve6 NY^!zaslVr"zGCR$UI"2֡fDְҺ$"dxDZLzEr9c Tmj3X`V,gK4 x B3/C`MW0crr +qA1e}>CK8VxeŦ AE4˲^ULaUز#1؄:Ɗ_i|&`5LB [`⒏0D*.)\?Kʾ~l LkH6<~aS`̂M |(Xᐉb:lBQ;z8>5CZL<MuL*"HBHx#Or A 1ҕ, ScDdy?I6ŤA cشX00~&EU O束3"14>$ҿG\UL>njn"aئCBb Li +fŠ\\Kr %028=blrS6*&g)Q"a熭C 㰂auTBdS3g$wHD3BRd58QƑ%EvkGcSjiP&SҊGV#gR&6NpL&0ijOJ~\X&bfqRf6rwm "ڶTqV6j܋ c`df*A[4'M SbL,bt2 F3Z9}Yp&28C\6 Ta슠{Q202c&(庄zX2O\*3AM21K2R7G>sQ,}ě#*J+pFG-w!1VcƞUfXQg{d~msHɒYM %QKՍ$ɘE +"&Ԋl`a2m9wO׵/eвdX6Gٔ |0esFt_dmlHJ3WUYfvR!"dʤ ]G ]U$৩F#&R}*br'OQbO< ;tl zc-alqBԞ&[Tf"ou<.(Z)ZQPjgzoRVծO*1`5"wL{E2"r!i|z(e|L199}J(1uTLٰY! +DS$-km[&7\J +jEdn􆩣MgH[' Ȓ`+6/\d$AK#qy¤51IJKLLyf ε1u,ј)}~4yOk'قUI8 J}4jt>E|έ#J}Xz=- l!|%Q'I!7 OSKTx2.s粎2G2m)0쌬(Pi +kHe$;S!#Z!,nP-F$ĊwbɎ +|3 'g_l#31h>V0B4% Eۼ\Mw3BAo͗؈or4/eI|vOIFeJ,9 ς,u0rh3+R6C4:~q9XM7Y5WXG̐vLy03 +.MYGk%żlIoS}p5!WARΆ%]0A׈7j m|c ISk {CC2GpֺRU1A#vAK~ nH2J Q4v%AڋJ%c:/IHmքA0`1_7^5W@V+zp~lE{Vp؋tBfd/06 3h ‰ܒ+X.! \ثX꧌7RJKV7$c+X~Hy:0 J ͬX;pD#:H{y$5`2o*$b{̗bI1aF5q"& r)aHKrTƿX$PL1/E yR ɂُMņW9 ħaZj1%aD`@<5[ ;6AU$2ќa" !$ь/Ny<Ͱ?@нslq'WneW ye)L3W +36!Uͨz!|Y+dTS]H#SEFƱG> qe>)o| J-7`i/wTJ U.eES@юz4fyfS:^.3q0:)&+F\Jٞ +Zf!a>D<1]Ӝ-q'cL*y^#+O,%_?eWs{|*jڀFGŋeȤ)4.ݣlq4?B^״rt]r<X69ą +LT[jqWWe'n7K-1pܗX~3F}}a -kGirCzT`҆,NݰNPr_?(F6ے_d7 *rnpa.3"¿Ei' BB4hj?ɯE@Mva4 %7d?XxJ4w+CqJ%=fG̽A5܀!--^DC} h~< V*k y6A]5*6ȑZMss| OG##gwhL9lw;/, ؿgB ?"Z@ҫfP2LyEz$Hq*D{N Bߝ ]ZCU>ǠwA򳪥vD]8\a`{\T3=u2#MZěd,Cu̴+(V$Qc/KA@@t4" qsׇx\]U0Vy^&[7 Z06 a +<앶4& f(7I#DGK -,}R +R+r_b(q5^tX2`]nkjq}i:5Q=Ր,bZ}ɤGǒ%SݶӒo+ |3_WF4iBŸ1-F 1X5:{-ٷOOK +#uD%]@1b(=|ĩZ HH0S}s{wӣ7ڣpՑP?}/U@G",1܉io%K>n(Hzs}ȌZ0\ t礼gQݜ8`ZK~܀Ǡ +7Sfo)- 8j3_iջ4rmŭ]wkԸSϡ@Ԡe\v#|y P?U,"[ׯcNH/#4~5B0 7շRA~Ȑ3ɱSI !6G>@4J]5vѨg8{U 'W2lC% lj4~܉BXbr0Uġ[ * iRbvcwt e^EI7"X[*:38SpyA,8pM9j ײD@ i!AEDm &l"S_iTَ-n[+} ]&_kEE&Ҹ NSkpl|t65@g2AfP~.qRD(~ lQF~á9x79zP曈,K@MhO5x"c@ 4jg8x`¾dE﷧YKUt#ڮ[Ux2J7Ƴ;6=1q i*P<[\nud̵E&D̾Q6lj&kN+E>[Osx>oz.lK ZȡD(.;0AS}G\ +5wB8δd;1̎E7̎-\Mܱm{Dtj* ~#j|9ѿ5rhaAš[8Vq*"RO +c[Ȝк:l2ݽ9R /d +-c=-:푪zלP?cR  Z^-~7$S@i {P.Ld2UɩB3ݿVu+y'Qk(qgHUT+r"x7,N"KY:F?u'._GQ"#KSBؿ5G0a`% P1er&]9x8=+"Bp W*#8A{2s/MdWDq_>ۚШ_*#tWˀ!+d569 /"-LȐք gJc|"|@0!~o&?)צAބ/Hy^s@t ox0\M3vDEo+ a@c9v` wB._ L> )$1k=mǒ[j<[wa\H|\}͑]jS`Qk\Ѳɼ?RY˜mTľZ7;9vue+ Ϩw :5@ln/ꊻZqN bE[13l+8!C,^k/7դy[[;el%/dek &БOCaDm*u.3ꃬoEVYK@­bS}ݔ ]ڍ/93:/naÆ"mLrxF=nntB%VMEH>h2ԗپ#Bҏ- p+Gߜ`.$z<Xik +Dݣlr/׳kߟNOpC@.!?S&}L-Xf , Q^Qv&2uȁ +bSݚFlژnDR/K.ڒ:S5XS.rGk¶:ΐ̄b\G=}9*q^3U +ȌS}<+z%vk_OW:,:ڠo߭9fEj'!aO_,9GCM,7u^c>_~[t翆 zAA&q-7:- H mi(_l3Nf`Gue+v7}@F"|pў'D"iyx/7zLW#/\"G^=QIL-$<ڕ ʫBOX[Гj_9|'RkxB>vTTB1JE$ގJ)J%%[.}࿢(9,Etl_ %h%iB/oW&`I% ׿2`m d ˴`SeX[D(M 58h)+;-{SW +Q_\J%"B v)0= ಀH+Fve[;_9T#?^ٯ͊A^YٯfH:F~婾=ב@.J?0_QBl!Vk@ +5ա_ Vd9nJ{ð twDJՖ$4F|G1͍Uڹ mmWK҃_^Q^]+PConW[q[|ܽ^lz%X[֫\mӒzX^Qշs+qCh:wt^!9'zUbhb~WylYiό[YJBzeYyyUDon$ Bۑ4954w"9|r6Ϋu7:]rzU ۫YX +?{ 1qZWΫ|>`ҍ*K~Ԯ3^Ș]^6y%M׀ [A =e+܈*e/fz&]p)[Fo(͔^(7fFou~KP3~\/ cu) ADFBt@廦d@yi8#L! jVQOse-m0sx*K%K,BؿE9=Vwàdպ/Kr^$@ +$$wR +=daWPB,i`Sh"DZhL#ì/݃.4QF9Hb*']B "!w!1_o)M .}oE`:eoM!iFWYB:512rJ so6RM|ѹX~fE +*iuÇ=%_ў8dd(+$V@}"2mzg嬿!<{VݏÒ}.aA:cBԢ /8j վuT^>>#0+>.dYPR-ϓ ѹ-M2mƗ$4ky/F@P"L82CAw@u섵Vv +,ѝu$u (z䗎Z}꽓SV2.ⳛtKnb<#QD;&rr@-wZdh۪>[K&:Z,: \4"n@vBz;{ y dߪ\@J,݈'^kal+Sr瓐M%`M/ {鶓 <d}Ub~Clx-l.Fj i:m|hN+OP%C3n?h^n X@16&(ssKR(V= M E'H\|Eч5-l19H&Pۍ< jNJ/H0]1AhVo8?́sGvއO[DAU]ɠ}|\@^ +\Yv>=@t{!gG F/LLC7z<@8-dF݇adoHj=X<)Rc3|H_#bg>NMdS0|rWLc>+PWFRCz"DC qA@7H>֙sR˚?Z(,MX]eOߓ:S Oț_JD09MEa եv,K]/M5xI̓Eb(qρ6(da7uaVԗ4ȼ#ҡǸj@#3g/ȿI03*tq.{٤]ES&F(S 9d%E TJZ ^=(ǘkzZGɻ°܋QU1:# uzf|~ eAFͱQ}xHj3nTP9 9{nD!1PBMԣ9o$nNS5PjB %>q36e,EORROQ=fdʅ檄V<{klQbT: 6GLY;g `Q 7V8!HxjJ9vJ28p&*Y#<yagu.EP)Bvxlcq4裖?c7-bwσ $ \V2;/h[%;QD0{~U,Yx7:4֘FԌy3QʶR,"TGi tqRv=<K2Rֿ`PQ @TЬӺJs +#sHFN'6XS8e>OLe 9Z `oNLzMn;2+j2m*=az; MIߜM - IeTLOgCN ² |16GvaJIn>mYO *ss<0QHrBVK8g| *>㉡[k;K{>1=5'O !rm{ˊ.)Yȴrv1G~Ba#C6tcY&("Wjo< EA=2'ztzS"u1Ab׉Ar,> {:0Q'`5S]S¢ $DUQMdEt;t|A V~źϩΠ$ߞF渆E: C<9_: *k0ьr&m{b$[xTGp[ O6ԤI/he6Jak7KR8+\i"\/P[GKMAK*R='mQ?=3 `PG5Zij#r$Hn} +YCâu}Ǒy!/MR&WE2] MO5c&7E]pM=ǐYq!?wǐg`܄B4 2A-?xBЙeE `l>ە S̠'(t{̌na`ZmjCeMv-6IԺNQnnՏ:`cNQr!`fm wVcH4EA3bJ3[eH%})`G H_!)0 PceZ;1 Y}پG5,Fd PzI4Ml!ؾN}Y24@s"=tSn +x"qe(ݡRSя83vÞt Vş͍̀|F/"`ڻ!#u{lҽ>LN0 DߦV5%{}uJGYjComG{;d#T7S|52 /%h`MT3en9g?'ۍ_*o 8f6C~[]֨3Ō6=µ 54y5lII8oo2Z`e/>kh{aP Ñ4D}b937(<5Qpx3$'ʋq' z^5Uy1ELC~QKHLmsq̀FWmnŋ +{!cV{9fC8i7b{Q $FlkS'WzdL`vѧIa> KT1uz&楢d +IcABZ_:Zy\s$-Gzc"5 lBUPnj}7a[|SD|f~"Ir}I~PITu@&x1#{hQ`&!"\/?it`O@ޏjmKggksQla7d[*H[]¯~cm`3~Ԛ7kN [$grZZS-1dyZG'6tdϱh4s#`=BLRmܺ)@BP +M {K',d"O 5Dj5E; ۶u<1(q-Ŗu0]7hUJ^͒joK>HHa>FsZ:q1 ++[g0'W(9Z0W75tlBgki7Kg[0Sr/!&;B4$bzr"wopd?CNjnpJ|Qlf?!%E٢|'jDj-X>׻t٭$-AcE$}Tl>e{2#Q-m>͐ŗ6mW_#O6Ug[5Z|uX btu>Jhܶ6//2Z¯_~A ߋԱiw+_YP+ J GYۤv"Tnw }@#mxWe@ʹ_;UKӵxWI_6+գ/E[x1]':ny:I={tdl{8!) Ӥ^6|x=ɒ})]>5 % #썞 A7 myuJu{RHw+Ǿ`I ]Iy2Kw+Q(X>^Q7ЫCA{ +E5c{jG2OxxYu1W+v*TRQ}!թ`&gvث>L%;%N|:L=!rFS|j|Ps*bwdľ_EGdn%wZ؀u 3+/Zr<[p!ıׁPSW@:ӷ#_/^Ί|ub+WV^f _ 0PwȨ}w'6Ws1N߆|N}&MR jfRx(n͌WBތOYkRJ^ hh .ןߡL_)~Uc_4^7 6[=IWM~G j9_.n'~u$}R! +<hK㷝+W&' }U]WHnǭn~Kz3kx2T }q!#B~Ewwa| zx;vͧ,ynuXL z+Gv{A)/xY)ۖ^eav0R+h+QԾlnfnfGus`f{86; 8CH`! +`={il! +C {84+ph6 @éYca>ߝ +{87+pnV Xùٮ {86;pl60a= {87+pnVpùٯ{87ppV8plp|TV8l;7H i|a>ؠHłsG<,3.-Ϯ +EQ* wC:ix&wHw>uD'EWA[i6Pj6hؽwBrK7P +QbBa}ڠ {Zb{alŪwqKۅ(s6'T!XQT`{HL {Wv\aю=;0 +,C&"ZpG2:[&"c=d+2v2v3'dfO-Y[H!c>4{ lճ|BQ7hNK4ZgUZŝ #cc[mp*܊峂= +6INJuG/-2ڰ Xo98:7ll-eopfƪb/.X'%nt5a0BW潁C76![fd+BY$evW?_udX IRќ9y&dDAU\7bC[v (ٻF! +B|}ID:ROzB?3?*@"ތ 5PMu6m LW=} f\7(ݔvGe6L'OAWGi&}unI⪌rݻؖd̯"e&Rj_c'HU)>^W3I1RStD@t+&xV8a=`(t{0 F85Cdط%Ë'@ P>9չbwf3C,pIbu8ۅC-B7Sc)? +# hWcIn +{} W}ZBhgx}~b"QB>-kys 6[lf,cծm04XmmJZEYa_g_?w阾H&^x\1#BK-K z vE^DCPiNL{ f4G&nK+n۫D>.Eu-`7"s@V,OD9#*ji˶"as؉nf E}ƋYh4k$7Q+>ym2n&RmR47)k\2o&PnT%|2@^_ ݆b45>dy_Im]_, a"cI=n%ѪqL֝E7)eǘӡYe UUg v4 Ete 2̃Frt\ړLg1폢,#͕mlc'A cUqC6YלC^X`@o 3k3Oxd0i|=`VY?gŔ_ל%|;.ij:mJ Yסa RUc<әT O3nQf2"V;<>EUط!V;S7}֪\:zt=c;qbx[p鴄Y fMpf +a:f?,? 0XQC/ၞq5 +nF;j N)õ!4u^ێXf,A[Y&$GPϊ  mIK~y:Bҋѕ * an#k".fkxd0&C bv86fWoMI +Ki&sahPϧ. _zsS;m&2UJa'^Z$ hO=yo?&][ro KP4R^Qs`|ۢV̮:8u2'f 9Ӱ[}i޷A)=n׵:Td)9B{ 5V0KS!Li %t M3s,cNt8ib\ +3==gVIǎO7,0(imk.!kح@Ge=;i|8Q~B2 4_ /lDAZmq[|I;&h^n_m= Y/~\Ct +;-kr$m- a +=7}+4;Tu bZg|#HT{jѲ0k:״HG⨺SmD3H+Pɮ_/=%1rd 'ؘ0y–AgD]Mpo: n(! fs܈5k1Ѹ͐o:]gޥEE2%fÅtNy)P{'m+S"GNA:#} Io^; 0:+ρ`}+gy-[q#Mf3zb|ݕӣUg;o9 a~tkB$"DLgiԟ Dz9O}VsQ|WPݴVg)46b͈LG[Y$`#!憋%aʐ6sv>LFg)Y#oFf\f(o+%Y#HOy3hn 5\tN@" {V{c'0癐oD̤]c<8RCUx}/YPͭgq0h9찄V_Jm٩#|ԩ"Pc xl-DnkZR.w}gD+en~[ o +s3;c5j #JU .y ZYvArg+}=:YC;5pdovb"XSD{3ӳGkN8N~1W4ĕ"d1*=ɿχQ-W1SA];x=^м zcE [Ք&jV2#K Ώ +(tS_)Ayi34;enXǙRBPQ}_'OVS,`TRA*ܑzK +nDk׫vόwi{$#̘s_ ! ;g*1#Qχ$32 gsI5 / VYT`,: DʢEQ0k1E0+r+ +mPÀO^+Z cf~9|{p +;x=5UkU:˵v@f DsRf/C{/fΟg*Y,+IbI'L)-5X`(3ļTEF`\; v mϽ+ +Jq4o{!t}T=|kn$ +vyZr%Wa +B3E~`vA2 ,."췋m!XhlS5):EJ=Jz+=2T4a P͡WZ)CúMԭKE8)/w6ͤK5'ϟ!aLQ*J[*mwx̽% +*҈MP}jmSxysD2,rsuCmiZ?rol()(&2ov2 #WYU\ OK: G*%8v\1r77=*I.c->AC~ ?(0Eٸ6ɿ3(m٠a0'ofiu7PƺvHshm{%m 1؛GU=uiE4Kn 4QJGח=0~} qd=gVjg6w[5š)de~?4C { pۭKTU%z +9PaLtugh[r:1Ƙm-SSz0 dڄAx?o(5ٹrCCp +uaxa>9`k7'&夵o;.%rkH;` ŋyT.q9&=ѩ>E2r6h]C]h; +b[q#bSkܬ wn8'D^mV?eH}/M\?]oوD Í%i3B^E_BƷ&U)ܭO8(@%K@7!`*S)vvyM,xBn*̵hsղS+rvH/KQG@nGbJʙy`^5us2ۗw9db05؟o AvUbr†OM3 ֏,C$ovIHY]W e7[tluGq+1޿!-wB}19 =M甡-a[6Ƿ̍v9{Wz cwqj'e͖1 N /=%O@k)<ә Ge-rK7*D8:ET!xKy4e!Glb%(s_1@rn#MjR3\.Sѻ{IV.f ǰ4|o T|bnv,Vu]lv˝9ʯ- wrWK.a] F%|3.ahIЀ@R 5TRZ/F¶D-,ՀIvlG>&8tnbK`KweRٟOq +ψ J!T5@"yFQG༧NWW}?Cbt-SBbNmPY2i EJHb;eIUΤzc1<P^u4-DsYzt?%"|7nRk@s# SόtJ-Eoٶf8\Stb=yx `A/M￶%ooѷL,+~^ˆG]nm~&21}/4T``fwى/Qzh$, !NMxP)0-iki Pe' =jl_+ \5J? Ê iP )ZB'^;Ljq=xA!fs{'_:qނwG0JK^WA K.1oODsYEyJOOpP|14vB>X6{_p TC0Qvd:%n-2;B6 ½=9pMQ-ylV) 5iDZA1MX|ڦgꑋ(fzZLKGnD7)zb`n$Sy h֫|L- ܮLynfcIk +;$Jie:P9-R>5i/mC1?Y3Hv)+GҸV7r)%N4驵=K 2B(>ȥCf6YbqB.` [Kž7rZVvå[-kW +`ZN;TfmgᖪAۍ4"D 3hH̴Hu[{d$=]* TCYzJ-=XZJ +MWf)-Fp@,rDѶXJhObm/.XzmxڕX;9E[fB?t_Kkb)+n@!woJ=ڣ7D#h87V/>?K&   .LE@n^I[xh~;ԋkeq([RGHr'qDtRN;I0"E~I]`v+j|B&Ň%]+T^V*%v}?Ifм;r!ʾ>_b呒ex|HxDgnށF$af$,R<,ӊEzXH,foD*NJ0J`휯A~paQ^kI!% H3(O +)cmRšo~A2 % I'Tde/߽$䀪ao-[1^r 9P5|G 7(R޻,QY#G±BEu|u`0v\^9e0G}%Y];ۈCE^-у]h kG-i4qC#[[+1N/E^CTb6LEodCkhkb!OY Աx_U:Be@ڄPVb"B/hNI C,#^+"$:ǴP 0a0z6@ pDl1P)^L!=H̤,lRs FՁxB m}5|4!NOK9}rB&ĩ|csP"P-w<֤,hD̼I-7H,b?jjf2۸+zbY[^jqh]I!^mTNCj3\ Z k޾e5jO2SvEmfD_̵ h#crL,MlCǨV|m\Kq2?5[o=-{rÿ[W x5`^BLej(̰fn}~ i$H!hƟ*]ŀٶ=/QOlͭHaKAGlN;rJ7¨<>a(x Z8Inp__ޚ٬!6ԫxg͝PmI`>%DQ+cRb+3smAY[O¤Z 홍[PI8>8j4iJ?yyz{C*]fxB }ُ!&|m6xE6\ti4 &VZZjO*X!ogD3[7)ОZ]c꼾z%.p)Sy텄 JX0A} 44U|ze/2 Bf/(NTm+O!"gfiLo 3o"pABݬ\3AQi~n4Vl kta;T0-tTmĻm8L ~i%+e3GT<5Lce~֖n^I3չni| YTPx룓^w.(x/( +=E׻#PW9,fQe h $0RVhj'lm :oh(޶s-G^Da=N։TK<O1OFGS._bIsF"EYi/BXa.l,-ZݜF2\׈׿3Ov=v4Tg!Xi#gqm 9时(O?M%dҚ2II=u?16f&v)ât_|a+~*]ayl0z +&bFmeݢ-=G- +g>8@V @_;"=?&h |p9ʷeNl:X$OEOÇ XyR Y805(hfcfHݶHdкfyrVPKK.վ^kql^͟"wpѐHZAxWc +͝&gژKN힗%?5 \c" st-08{DMf>M$pRPsœAl˸4uռQ!M0$ag + :p:qc|D!.϶Z5޷5v +yq;i zX0LB k&bcΜ"`Eϕ TS5Ft<K<q:Hq>_fsA vpm<}:A~wo\WOnt#Idun|#ٕW3垩{:474nx~Bٷ0M[y䲴yM[HGЇtЧܦs\m֙ UKbWD4ݫ%έ lf% K$ꑋnf6ۭ\gU =^{o/m8yU$#zdؽ}ho77d9U3@eu*cejF> +[Hmt$ *5-bL2Y\{ϴ )AщЕj]}ӼUQ%Q]"t,>[Xx[fB(Y$Y9fRܗH+bMv0BU褧2ݯVuv6e]UHM-Ԯ$ gc3)DF8Y,K(-XkXAx29rP [ױpAPEK"ݭ!˫V9 f0Em M / aΘU0v]ۣ~Dnm1ϭm7_E^Uּ}7:O@r%m$UDn^^w\'~ JH# zEHsXe4|F@ݜQzxTEI5R:a^p?<2Į&Mf/kH9fL8%\EXQ{<"w EL8 sb6e@Af$~wlftqm^s{S ﻾1`n/ Ċ5M|[:om&2E! 1DYS[)AxA% v [@Omm3]@? +m}'͆#,fv6B>{{]µq Bv + U  &{uzEWфHAdGTXי–ʶD~!K5<] 6ݎղ07% +Bg_ stLs>>]PG7ABfс=fh:aObtig(Ch$<|OY|=2a~Vd,?(>˄OT3inޅ1Hm[Z@յD8\ZR{PLUl2 ˈCA\Y಩z`:?je*}tn&rtnj(\+)[:Q z u嶃ͱARy3 +|_ !-:Lo)ASpYril!J'M%d{7C㡩"?,e;4LjnQ.PGɕߓ95@ x<6zGOsC ў;qj`v:7hlKf~n@_tX㱁xHp +;w#@pNQn|T6|nmW"gVsˢE1K\ZyMbQiUClD!/Eױ>mSG QZ@(IZx[!# y]>|[]5&~,iPTYzEH kC솂G셱jp)mBF\6OlmeZp]!C.w9o4ckc%T`Ξ +}B`>f_lJzΙ_W~{i.ɷ,{ʹ {9M*0Ue4̂9X3:[&i2$Lm(Sϙc@GP(`jp|XՀrkWee^VZ_Yُ:/D-k#Ԇ#}mJf@bTӪujX26rT4.3KQG[v%<J v+L^G`et+1JMX&NBR7ጐ̧y)^jV> ?>2&-`ǚ\q+);0z^F" UcEP^% +gbqWswuI! W2t8hw$:~F3RS;9/%NaOߣ9)ƑzBZ@3]/Citwl#&V$iU^cMPmyh齚@-)ZasIS4-((N޷b7'JdG듵~LZD0mr-!3|k[B +^L,G?oLIK@L*1L42ZD{\Tfny@kPFCG]z<@?d OM"_HdzF-WvhQTپ9johÞ ۣ>6H 0Cx|1+r Դ0*^SԞQlApXm]6`omOhۮ:va4ȂxE^"rll8vv3$k_t%ys aelf۝o 0`J+SםELoR݈ oDiwtkZ +Dg&m嚐*n!/0sú ?R\.Qk|Z5f^4 X"ouewixUX2Z*u[e|t/ v_Ζhel5Į\Xѫgk0FwNAn<>yěagš5d_u["O{fX9 R[&Mf =@ +ծyENd<8X}:2`0>ʜ=Z yz2szmk x Α2(XcTPJʨ)f7xcavW[3DQT0JX;.z594S>E,+d'"7k_ï8>(=L $@8TZ1ꁭjLj w,NJ}HF DŽ͛EXa&?2j >*Tk+#cgLm)T +xx2Cj4(?Qzi3#..Z9dݯxZ/̵}i=L4+8qBz攐Ju`Z g@im`I6A i=T$HiaYAxՎIh2iǫF }h=R9jNz%8c_=_ iږZFq^36 gIA6e Pp{:DFz8/]RJ>vf` u\mƳ"vEa9 pVOlu7[ט $kGuZqĆWpl'^Ț>e bUPk/6PZ'meY'^%ϩBzI4%4'oX| }}fN*_~wm w0TŒ,nBY(rd(8G N >)J&&KHcSMqX e{72ĝ=X73DB}YptS/l]s2^*:<i9E|HQ K"otl=+(fz(-Lw 67ʼnS2h̤f8@= q;{ {OYOx*c\8ۍvXB+$HE +DA@fɂ]8 8 ĚvnZqLNvA.Nv[d]prK |7 9.dbfl[c ["xKBo ~jw ZVys@&,M(_^e> us@&Ĝ_7A E:^7AVݼ B,Ay]񺜎9us:fxЮi<&|LXw9 =_e _U tuo,͚&fV7! m ٧ې}OMȾ V7!X]lW]L 'LXMȾlfs/X*M%5bHU[42|uq}TsFqj+kuHUm8*F3@M'Q]CQ-k;!TU'JFO+@PpȄO5ßTz} OWGN]kПNxj6CSnJV/xCS>\T/dWqW/`*{wYpfWb>TjuYAu IG+҄7]fX rPHO|ďxMGVi_hmvc',ꦽ]{oAm7 zCEl">&j >ZGnK" X'Lv$tkݾ1g)3T{'@Pk{0wAZ^w-݃֝~?oE7jGj4g=]S=B<~ȕ"ݸSirkܩ^>'A \*V}KmfQdo-g_ r*?c q PC{IgiK0 n+yM>zI9\} z_yiՒetm™nҵt-0SJrpeiǍNdwenl1ؖ7tc[j[^Ұ-tc[pn͌-%=tPw/dih<,`ն ngƙ/Tij|a[LƶLf[Pd3!J7(w474IknKZ]u@?v ޢ'*Dx!I~9GUj'A`+‘"zK{D5:aS7/Vʏ~үX Aڬ`%Qut..M.NM^pqŽ 9w ċ/赋'Ʀ/эMFΦ0@FWn /1\tbAn V* (1/3D YRGN8Ѡ4Wy;٭KluB-W[ FUS3UfM? Y:x[a ǫ>z 2oN^]]qA(M"TPw9C76OjQ+J+eTA%=MdRNHC~{VPtIT@eKkvNb{A댄6 a'UJf3"O%@Td:͌Gڪ вkI#b 긂Fur(LV6D +j2a؜bF[`ưb~e;؍$fDe۷m5Y8Ǣˊ7Q_bAc85}&`W?wIGPE)2 #\b2z`'VjL} P@, u5޾Fd5_ Y6]mElO聱{y^j!'ȩyN6?* Q!Җ^WTYofo%̡9I4V ѱMDq8Ԓ0%yVeRrhL6qAJw6/'=tW[ +A#Yk2?iWY'QERB +G%|]m%ABBUl>e ?:>iDs%o,u@5 AG( vP\%1KlپeH$)fl߲f?ّmR˰2,;py{aˑflF6v  BH +c)Zĝ|}$ ++tC1>{(O-lǺ;WD[,ɇAh< UdSmhwI.0\ +4'V9vpeуh-Bg EՔ"j61Tvbf*med`M\ל%|Jtf8 аWLV_xiG#xnB:x5OHGsPp:"Zh7VWpb"yuɼM) P8;B!x-Ki >t9׈bķ:%ifjOl&QOTRU@I"BDOV_$M/\h,Jǥj`H޼ze@%be3z_(3( ʽ r}evqg 1-_8骆߂NJ 3{d]D/Q9P5TM" Z|gJ@ܾ4e|Qut! !U5Phcr5lvd맍+5d&-sAnqD3++hשoŲR|A40)iT Z({"%_]EHD͵1BzYA^u}_Nl;Q߰(i^#nGz͟H2uyʋE)QA2S̢'_9ڬ8B㭯bfJ*g4CfUg j +rb(*gK?H +{JUEHB\MdE{fl|4|*_>~j b.f(_I ]T5u>`ZG71'^I4wu|d]xt.oQx3@9vé&JuQ5ZFA>E:^ϖ,50r9P]BdQY􈴺B;<ގH5I.Pwupɴ6%Л@ahWdTZCҒKXC[uLhLmpy2Bx FXp.`^wWKY502C p`mzT&n!ZPfI"j\Yk~5dxfJExUEŒݘ@orkD^1 v I XOa:0Z{JЉ]aV.c#"mͪTcy"YNz;88W;L2&8F\iu s(Y;'%G}BD˽]m˓tsTl +X^!f"^c0QVkN\(Pdzn1V&7'[[ g/^~5E +8¯ǙIW9&;zWU)+ʔn* *a z~hRJfIt^Ykv5Hr{?wk&3[BaX,S+NW>,˭ЪTWQ7{, $U9=nme S렝imCP !Sr ` lo|!>l9z`)ԟmc9/wg Մz}ȭ=URy؟Y)h8Ռ3D&JoS@s<\qi1Gʹ'X~mEL+BHeH(Rg(r}AW@dJˑA}qLBc#:eiB˱irYj+CZ(HҘv`H5۟S9=kcGu"ww~UN0,ESz,+&Y/!uݤm" Gmѫ8 ? #'l^vS/eEa0MIX=ǣߡc) g)Bm +^AG\4^3ζܾo@>Yi]6LڑCŭ,D U?[al %M&&sM=YL+íR[?vCW`6;Nwwn>\NSԱZx-h>K G~z,TIDi zRWh<aqTP2,7s +{"ڂ 3ZjG蕝V//KA1fD>ڀ<0ZLA!R7s\83ox%Ev@+>[\jhzT ^#ht'CsL}$)|(#g?}t^9wS3nns)\a}랫2n?. QV_l,޼G͗gK?U= 2X"vNxE n3RUQGN'䤽K%YE)]Gb5xg0EL@z@5IwTc +kE~XM_$za@Gd'յJū!~~h[sq̼KK&I~Rr /90o3 +ì +QKއ_ ƏANMFi{Tv--d 1Xzy?P˷'f}]SLWhO +iEB)%ViηT2}5 NmU|K~\kY.yp % 9~{z }. uфu +vY{4ha~Ihlj/5Almĉ6:{e@AgΠwKAAn̓7lkq]S 4k6o6 !( &I蠈ۯ0?$u~)6gzT(x<Y]kڰh\ml+4FT +;hX*ż VYd{<#0Oa=N1~+3́F2"olM ͈m"l T;DCfW +,V?0 +(W݄AhQ` -1`J{q9T_HG:fK*}SEC.?E2+ +u(HG"u{ơLa fn`2TŽP94 ݔ .3(5C%a:\p&+.GI+[DOBZp(/+<%U-kxPqwvl G\uBv5I*ZD~SC#؊lT``֪7;*@bZ~vAc$_`@<F̏p}*Mu}hI:|(\ :h}H#Ëg~'"kU 6~|/402gwod""h@<4zcn2E2ekaaF:GhQ4 x +&/ϜD%t jC;uܫ2Y1gteͻ^dU`ؚp7T^g"5OM;4QIzi0R1x+G t{Tl.kdUzkN4#4c3VQ5Іl0pGz^~BEXZdkz8JQ X:(vO C0 +-,DM`3r| +{@C#АK=ˏTƿ:K${! (Ԇ%w +9"=e6>|Dg+-zNG8G,[.fxګ+x5bYW@pѸϲ)ZԞɶuCȂ-αQ$ْ\twHc½Y=qe+pL=oX) 0ݻն<կTZC 9nա5cZWC=y^=\m+ NT`BѦ0 +1sCE@J"Pwra ]&ZT`1z% ,k{r&{s{pyx1o)L^S IAMKpFظɑs" 4u$׍Ιyīzz4`|/w½<5\.KC/8ct/)G@f0Yط5}ed\mU`ZpnMDY,U3$)'kBlg,kR-McIpPS"Nx 9[kɴe5?5:.?L5Sahs+uLߥu]ĕ4`ICV~XfYݙ',$$Џ{I}0X&E^,3)݊yrf/PX,En,Ȇk},sw١Z<},szf͜sB#߾e-f>>K7p3E{m_`U9(KNoegb mqKt(xܬX-5f4n y,r;߃ЧiҾΣfqXF/do3z T~°:n4zY2^b-%K[``4ԗ;=0),PN%zڐ^QZrT*^}^qy=N|$nm3ѓ(|2I cdJ Wr ڏާ^~~Y~0 {v<mmk(cbky!V 5Ky lA$Nz KaVBu^5kFCn]@[W8o_~lx&qBMFnZw2/M Dz4k#4 -`9 mqAj >ҴGt +ezR1 -Hch]4c>p\a1DHssWQ- <#{תҐXMUf',ޕHʼn͙Άiʞ#@ȑFh%Q'i$=m(If}3x_9 +7lwů,r6W91b_jL M7(66ҿMʲ!nyפ"HS yݚ/.5qGw5T;N?a ߚ#|4]Zڄ0Bu PgY"[{/b*{xM8z޲*KyƤEvKv ̼b~Ct6HC֍PqPWxfx7U0:iʺ12}qͿ*Tpε __>#頻p>i9V2hyFwu7Y9rvgNq w\ lQ%uh4H0G͵B!!c=2)MEhwnޱ$k3(s[;MK)3 3`۫L1BՒ}t=<|cI]Pҁ^MXvIy?$vj:}#( +5҃}e;+F "@'%djo$A|Oצ5sKeg=fbجX7k#ߣ%|:c?xרNC-D+Wvդ87*BeGo52bFkqg(B>Au\dev>b?kECԌƍ}eD2Qx> +n8#_vGp!߹-4;vT ۓf0GE{~ (ԂhҘt ~0svg-EIQ u+@,"c_x +JO3 bs(QHU8L.8L1V<<ZT_G6De' TFYhIxUJ$uty :46;Ľl!w>=G2]w-1[f`#?`ae59a]߃ZE!d1j6=͎ 39J;QWիMo\M@}V,ϺKx,UqmQ~ X +Fi;@jku)>R.)Ou7Ϧ0śF]nѕ(P2J5},^M #6gk0\: i52On+Gzu Jf8N{Q$(eb^%prsެِNͧ +bhzdԊK*[k؊֍gWe-xp1qg47$jxlۢ'0]co!`/FZ)m^DR\Ntœb5vUl݂%5;m ^梵F 2ӥ\ME0^ P@ɍǛvvZ5BGqu +__\p|^9Ju8Ess0{7zbTr==w=7(YM¥h5u*#x8 53Ƿ P */kH]S 8*(I<9,gEM!=|U:zm~ G3ֱ7l + D +BO^ rk0(Ƴ;@!q фdϗ .@ w?|Z6@}a36m {Ζ|Rjz5?w0HXTo~=Q;M!ũEiL#:Ҫ<*RND)XrNH*N$\D14ŸEА \Io=}+gfǠdNV5yž"xkwwB}Q۩^ngH[8n{9kǨ?CRYyU< hzi)[^hqθ8:e|k3cD(FP4zkқ>UxGnm(,ܰ#\W9ThA} l8l|!K*k!TOE8Kmi+^`#mI/BU؞?ķ-C +I&@!Xh/^1$p:|.z9E)Z$Ϊkj{RhGmAG^^/_)UvgZ&0Ӷz S +UE5هd6>4Ex6lהHP5ZhCJg?Eq +CV4!=2,vxv\%|'Go¼"k84 \+Zy6]ǖ@Q`GU)4ސB ė($0IWkqv0ъLWx0?^+6P9>Ę}gWfzhoD1nDm>ehObK7)^ +2 tz.vdPYG +Qՙ,SV\=z{&zR H=z,tS$Y.sQ.*SF@cOUS=e͉v 5 H82ť饢mcPrNk%U/9 N PMF,!Է s'KsՑ0! er 9 +擗֙_b.˂ +~O l/K9[5Q(&e7yb.<) Eszn/i3 gyiJg.s=!$Ou"Fo_/]Oф-詒K-9vdgD)CeAȧP]}b#ڶ O/WaoCmRMFp +c$g%RښɫA;9eA{H=K, 9TA;ƽ&>;YR 0mP"a$ڼin29و {'ɲ-V$zuUDОiPE+9D}tݻ:.db8x8ph+x_#⤢W=P2 1|\bYn?:;.g7[ڠe)9z@%̎NDl JM+6d|@TByy*d·n>”җAoPuH} )y9n&,Xܴb.WYУ*Lfps>*۝CiidR6;B@DOheCmDc񐐷#4"/De$ vzh)V& D#Ftj 9s*PkysӊXxIT b'8Gl>sD+w + +Z=\b~>^uJ!]DZK%A\j 8+ǴuLY!d6y"uM$4Pδ yjӈiϔ+=t{{Ͳ#BӻHb>ʻcҹL)OƝӊm>_e OHHWbx {DalWʹIѧZ"7ۘ,3ZH&c˫VlC*K:-*kȎQM|ݖې=Fdbjs}RF +$6FWY6fG;ոr I7!ͽh[*3 V\_%&ς@ 64_d>z\4U,U.~ZOBZW^L9, jQpq ?kR?.ZƓp0%qԙWcߪ|`EU2s-v!Uۘf"^qqf4Ǐ5y)jh ۻLATxyI脮I" ޞ]0"IItm]GiF ZVu cU`[{?EKڵNqRFOi c%iC4d=1}rb<}֏$_/fK" 3|;;ű!YsPKpn/PK=KG!ЫIevZMS +aj%Q{U^~Q&Vk{[vN[=tҺ)LB202֠s_p5:]Ndz~4gr w!Bzs7xFxVߥWog v " +kt|vO\((V}Km3){7󠷟="{K GNM|`7T蚟հ.P]%tSvz%*)ʞm#{;s}K^ v)@Po1|L +ЏN;b_1dN`醽~X/<x_Y̒.풮1b \ߦkf&Rs[08#r4SN v/@?$maxQږճ4I|.S޶PW mȣj[@5!X=iqIn0q;LU,;oĸHMS %ɗ 5]y7[jd |-Y¶RykYzd-Qb#soŎh"ZlK-&g9Z6q3ptM+>S\zofB9% !ZoB|_*b,g}>stream +%AI12_CompressedDataxi$u% ?|@ v`؞FJ"XFQHUleeYYp~s/e-]U3,mg:~_^?oO7_Ǐ~_\~^7>L=8T>ۿ_~/y/QW_D|/x?ߜ^eqy__ᯧqz/_Q/~Wopz84}W{m\и)gO`|(n*cI8ygǗ_|^~o_}?xs;/opz0W_bzx!yL`"?Fb;m~r9WԺ2:FRM$$))PʁsTb1y;XTkj'w/;Bc 7r1b#BLɇxEy‡| +5G|';i1z#?%aatP|N56]g1NJT=L_߽+3l˶+R-}Magcb-w#^a%=TTjN?I~cz_GŎsRzT<9rc]Q]?~ܸmqus9/o߼ٳw߼~߼zp _|>_Wq/{y/Up~/-?|1 +g<I+X„„@_<7niZ6-?{Wo~=~do޽r9y:K=`qNc~RaMfo0nEhƇ /r}W\ޯI߀~|?ڤϱ~9j} oo cKyg/}W0 I//?gviwO/Ķ? >݋/}n|wXwM}ۗa/_Oo?v/޼x7OV_?r _⏘]g>A/7_~=m.gw~?{{o_}YשWxݛxcrq=)_ׯjxoAS^}gˏ8k}jsیGxF(/_=q?xWcWoĘ?I|)>|-?;_9ү~5͊_ͻ_:o޼ +!t8}9Nɝx|<^x:X%1=ʄPXrF9գhȞ50TC\#rB9BxOFI%~Bq(c~DK>|:ÈQ!q);1=k:ɿ ?&w3@)HcGsCW?M!/@M[vƣQP8AR8y + z^/i/ y/~B9 &1 0Yh3r1G}/x/2K`\tɗr).rEyW2qz0^37µ^ˮ+DS<>(ezmk.rq1xľƻ=N㍢s1tQp"yqvsYb! L,_gdW\@$2+YLPS.+RmQ_P:ո|<"nS-WY12{xر#ppb |Q'p L>qzy<P0MvdUg&7\4mF.V_T`7wf'x?+J_5\,ኃc)kϭMZ\5w6~h%7ejŷR+e?:c+Vsrm屗WLsV4QcLx͂/ x=[3*d將*aqq8X\#ѭ-)3W\5G윾szԙث156kݪֵԻov%4aLw-O,76b&UL*n䊅'ܝ8>8k:M5!1~W jgevExda$"C=ϸ~8 "!B}`r }jrH[&GSL>hb@|&'etpQ"9ǟ ;UJBNtRplgo}mbmQ4c" 8 +jE1]ct;z^ naJ 1j^!T!c!kq392BFP :zSguTTDOPYĮQZkۡYl8j/^J\7^gU{m1 0xi;Fm)0glJ9/'}·жEY+ϵg--xR4,nJfeߢB9mTw-; 7:ԊRUq2mߔ-5nJڔ)eS{v]Λrٔ㶐w+6e)aS iSMr)'+CyS.r^f{GѴ}RGJH6<ٔLio*-գcSklA1mSn4pwެ]7Z7AWSfiUS +~C3~cpS:>Cm}_=-bۡz_a[Q&y56{Pr跠Y(A7 ϸv?ϝiV'N~v}Ӱgw0ŷ,Am\/ݡdl>N͇kVV5}\[mFɵϳƢnNK] AS̛zjv PYK?&红9qd![ܚ-$$EHMw%M1ϱnṄf{9ڗ9k7w: mAs3ۦ&b#c8J[n[`X2ON_Z{%g׶֭#|>ʦ~f6nn%UAimf#f ϳ!5:xe+<դ߱TMNCS K%2~.R x ة2$ 8e(ܳCfO)VdO +/t̩sY6^gE=le?yS@YZiZB.ZJ-mLW Z9[;'ۣVY&Y'6'-iSfuz.4Qભpi,IVŹ m.}b{%4]Mm8C͈2.s9xSN) OeYٺmMbaahń w1/~ƺhy'iokK86ΰ2ǛrccvS#R~ֿl Y+zƔ`Ƅ {ͨP6 +H#["lAuv}^Ca 361YgedYҚPA;;>@`u襁AКB~7 qkkХWw{^+js +hHkyQ +Bs&alRzI3Y|7.f/'8;Or3Yz e\VfJУؗhړLyh0ݓgtW`YG ]orvnz怡7!%&t8JFÌGq3:flaЙZl-m5OCCԖKxm{M6"K,DňEXEthB0  M . +5^/iR̨c֎1z}~:ֿӣgi-x9x9X%6*dkQ a?WsXQ2;X1_:M!'ӯAiϲ'(GqҪ.e_Wi$kG RJz32+ړgӒX _t{UI<[r6Vifs4Q)\7.{Ek0ɴqtw@+r1.:YWfے͓?^7ˀ?4x*VJzץ†WéD2T ˩Uŋd $΍.M8 YcixX-jnZs +:g๓8QܪCz w!Go6 +"@~+z +cqRң4Rk 3v ^\ӛ1aW3s]I"nݯ\$N&YjWYdNNec"#>88ѕ$HGN\OJs35Rp7C-_ ̀0zW0K "g +{VW8ٺqm&rk;c|̀Cu m;{ⱃ]eW|aݜ1Y. )n4v(%^te5Xh.30-djf`hzj~LFmAD}ZI乔UYV>HGE";[/#KP>\)cq>Ev'ݍJaQl5 #Y=/"ٕ46nssϟͿЂvoM7_woNYח[.׺|=nG=nf_";\|1G5ᑦ#dj-(KŨсz% `\QYKn*IɱYэU"0Yfþ6:tC7+?[p9v-9 M6גּOs9ΥΥJ^$>ޔS _Zǔ'B8<]R0|/3q+#T4k;ǁQ4@ׇNz;~zqO{ Zv76aC>􋝱oGX:{i6^7D֌2tjXrol3]XuyC D$щN)jÜ'N !,|V 2|zSNSk/EЇpy!Zuig_)W%YHRM w v)!-Ôa)_tgllũRSOL|΅0:yK+4gqeF,98:v\2?`Co{oXn?~N$)H>ő|#G)Sɧ8Oq$H>ő|#G)dG)SOG=nn6@:F-0gd[%|=3||ӻJzhJ.HҤ(wNtwc<:7fEgf YtF.ɬ,)ɷ*,e͚~sz~6鲇C~~V> ѱѾH9w{ls*04k:o(Z^WԕUDS1EW<'}KYnt?47),J>>)1aJ%>% L?E'7oy<ƂU`~6%9J0ߡ)t)Yg<̌||n5l/M~69o3}=ʥ|mDKa\TrS Mwo&X׆ru]u!jc-%$.7N&o UeK ޞAj̫fd O x,mxn4R rݤ8>^YF[{_K@09rَކn!Ɇ[p^saOpmPK3PW7#϶ԯ3chX {e7q\{yW7%mJܔ*+Ьao*~InFV%::m9rص[':TCu~ 7Fь*PBCQ'Jn2&-}.ܖ#8?uv,BmȒ5YйNVy&#>{I=ۄ:7G\35ZĄLgEO0̀I+WJ.=<)7e}kwM7"g0 le}֧]H=O{9@I@=q B؁!.(Rv:44$rwA_E4XFsҕN.&i(NL()]yCxe%e+c]N8)#YIveL^CQ>n8n^!#Y,M]0%:qoa{105٢-DmKLgG7>tUxܒ085mm*aJZUݝj7:R̒}d59PO Q|]6rI/txojemt3Ab^k}imVڅqt-P\>PfZv:lGXi\ߵ{プ~S2M5T<V~tl.u|n:qEVVH8U:}#ʟ768{0^y=\) ts7̴UvƚΚ֚~KSO oT wW\6Sް~l9Uvu:8~ص9T>17ts]Ëc=DnȟneQ534=t=6R} z.3NIo.f?;YPɌr\a\O-龘>P~V|3Ѥ8pޘfF3!Ȁ ]AږͤaGey힨ni}q+'}Evu@&]: oMDHWnQؓwL?C4~l p+Fq;mڋ4sH&Y2gCJ(O9 +C>:b T]jx |tޛC KJ :g`؉"67"W e6i3eqϊOo];5u|#>ӓAbabM&͍atki /mο!;)ogTCWt\йSZՊ#b0YifH{`1WlT-n՛!l4-|pvوCy&DAc%5z ";‚q]0Tׯ#>{+ƣ? Ǖkwk|ÌB޸{Yfr:uPhSգݻlN4-/\3?*>sͬgґ̩Mph,?CWU`e[ '4{c[$Vi1u؋~\_mx8֡So r#K{:̿coǥ>&EZ$qcQ9E9qm#ix6eǽ\#ۊ{\Wjpw]EXث2"Ƽ}8msk3c޶nqnMt*m6ٶQlk@v琇 oմ~|?޻ƧrsO>؃16{0'W+oPZl6'\a{n.`K7@UU↯.QSCş֣n}h»}=}0ҰJ&?0NU]V Q64z<ۡ:@wyosoຫs˾;}@M\/D6~rq̛:u3+ޕ= rg8-zp{gb[|Ƒ\Α,>GڴQtK UQ*lSvmfY˃'"o1F FqS*t +%aH#.CTa)G3l(M97ϧ{eҏqQ&~cG֢@8ؖQK!Ħ]4 bļdYpV>\Kش#-va-N266ݺڕ~/gw?SOi>SOi>SOi>?SOi>SOi>Srp駅A|JdgϘ.[*seI8|"]!1׆I^Y 'tRuf=+ILH@[FEJƔK7,BI#iDp/l"o&-1p+&@} އϔdIpxwD9^L{vu2Qa {mj u*nG;͛ڳpV57oF$źAXvmB%7`oV!.IFY;cV'KXdN$TRaYeT??-֡yWOMg2rpSK857ih˽F &rK'lUF + \ +"Pf2ǡƦ,`!KJOq:M]*îb1լVmuaTmթx .Cg^t.+{/_;0˭Sg׽3zx~7/s]/?_kwcmi+aM>qV&góG,2(u~{LՕyw6]N YZ~ϭǯ+{ެZaL~~m>opk-kb~Xȸ=e|guәVaǡ >ܝae]ޮ!U['Wxv&q/.q7 CF)}I\C!8HKN!\□n9BS]Ldˈ3wG 4?1,C#˘Q wjOa Ywոo]{_^7g=;YɾS>mailצke4l6 -qܧ[e- e'-cTgU2=%|_:u_W|mI[M5Wq{hcE=265RԶxK@{QķVD<>FgVGUЇ~vu5칫M1̧;<5Q̇'5s7eSо~DzCp% ΍|\g8gZP-VC%[/:Ch^;\/_>|~oܠ+}Sگs98шr ?D:l{\7]YVwQ0}]+h@}x;a.f΄synч''A7ETM8D,>|$JcRB +7)w} :EcRR*| ]Nl Ve' ?Tf ?`2={A nBg ,)3oK..mijE.=xwZ{_ߪ~-UNw/W}XHeor{ 5VnYQFd{eQFN]RVqc59-P~UK]tb)5Q^q3hq׶ EzX\+`{t^UO쿔'oeoQ_(C`nvqQۋh | 8uf:2Ce5Uѷ۵ B{h[ ЮIR_eDulq9k|AVgV/)KJ,.&$nE Ԣ;{UG{Z@Ǖ{8bshhjKiiM5eVꗲoX'ڔ't+wŽޗxo[to(?u.I+։++I,nYŹ.Ŷ]6gmϔT6oY2}t\o[߿ ?D':q;\e⑾So.ԯkYfil609.ޜ6~K~tdZn^{Fdoعo{-{F/ɨۣ?|޻Aye>_OrtG&sVvѶ;/:Υw}ޣ'fp"yquOFE3ֽb{a ;^"{q>9FbslnQ-(| 6qKdnA 2qm<44⩇\w5>%J{0/?]qwet(e/o^lp(2_|fc+N[hD=o1^) +W:zPy]g @@܀wH&ӎg4׃n'3Tz$FtH=3v!6o~Fr~y-cڶo?~~c8;fVC,6Jv K^ɺ&OJhu.aӳZ.}TvG]4p.9+I۽m|q{Ze8ebtC M:➢x)iUo IT ]n!.BM+e)LSN01"Yvn5]D634WJr@PC]ވ[6oHxsoO7}Wo_׺b?[o_ݛakZ0jJ$wpcm@5h )UX TSPV_^o_|>;>o܎I~~j7w/x|_޾}}oی~>?߱r뗟ynP/Ł㍗!$X˘*g x20颃0 ~F:LFjWj7'K\ +P͕!AaE=QN+PoS=t!V̫nU,Gajt8_S|,Pi\kq чmf" +A~![%^@F9[`l`ȄElbb-?#: Z@am8M2Rd ZѭalZ><'Ma,Ct|~@Iqo2q݈91>L{Z o4YK =b4 +46)"]RE~m&O%wR8^y#Kl +^8 +6x_ v'b`Oc:8bp]:f6 hl|NKR"rR=z13#zCB4k`'!"z w8v@SZ25!aH^0L' i>a;|,럫t+/;X x:6 F91kE "\gQ~Hp盷;c}`A@=:9"P "i#@v@P+1h 1]%v1᝱O供lM ˊuCl+LRqڥj^VXk_% Ϗj*#@@e|0Y J`1C" ֢`26.a+ 6qZ=h Nmr >&C$0nU Y;-DL<؇(¼x'ԃ,B`C!xvJ* Q2gx 2W-) E H1"< +f^.XR89.`Q,qc謅Z380࢔x'Q/'a|3i?So6Z0TщFυ A8s1B]&yUla%άt緸QXT1B6* (Jf a%QVb[#+U2=&c@yD8Lz$݅6chE2* wlrJ^&!Bc7M[:t._Dr${Vlwy-qsܞXgЭlLLaH5W0Pn -K o9R"7m{,;#UM +;Vz v,$ 8=PCC{\?HE:pGH \=U`+'ij3Ni@U^9݁S1d%H y;Ʈ߽g(#O:>NmsT(K8>|L T{ߪP+pWvS 2Q +ʀC‰.dMзy&5.a0uWkU +E5e/ڡV;zS}dn+#")qli-8Fu.(2<#CwQȿ-Jm:N`Yb+fNz(xYN$ZV%ٰ)%;TR-TC:$Tϱzt"3i2*9ڨf^JpʉןO&f/**(+uU#=^= RUHĊFX#\D?'tjBA{r^$# +pv^'#DVyx;-H 9&)&G+'HH (5^SYIa%O+KHrn`2 +x*xCl31/![2:2TzV۔̸ӷ(ɨz+0ߠe J,@DUrnlYcIc%;>8\5I e":W?8.sM4 ΋VPLTߐ1A"m1JUZTCoH/ˬT!_G&N* CB>Fߚ(D=pt` +lzNlӺ\qQ!ZzJ<<ԐTbȊ*ϭ7\x:%՗ȈA04+(>JJ;NR# +#`s>͟3Ӆ/MIFKW,I* 4IcԐA!"CnJNBX\o]*3XB 0!G'io0U4P}ki\YP L*5[*/uh43=Uƀ<6$>f4MNj @<_M7}nҭxE>8/X1! dP Ɲ(;ukMB6p^y:3D6P7Xd$?Sfո݆M,ܲw0 J"5=O TL`d-91qAXq}+O@@]YivsoFPFӁ[&q\H``p5 %=˘3 +W|(=Jǀ84ew*t:k$%$$6qS՟wF\dtrSˠ+ę!%ɉA*a<:$P3ӷHi@&Y&RPA"@LNYY*d(KC`qz%-Bܐ!Ig:ø8bMa*w Lt`t &{kQ2Qihv,޾/AJjw r^›"F? E 4 l"FyhؿC 6GLxЎh#5QB6_5H@Y}5^kYA`xM}\Ԭ;um)%M5FaV4V8pcm&bjf0 X+DӾr=נҊ +Rh5cBPN0&f|sl͌ +5Z *u`kYHFiIZ?챙X)m3u'ÊTQ %Pwr;^}+P^>yg 4*rÏЍDDxY< \4e6.c=%:{W q)wS8F0ε3 (8$HOlTl?o=5$K!N0eTfzԠ;[ Re|Tmը)9_6 Ш >lš@f)ġ8_^v A?d}UwP'E)ޓk8N_dQAK_m!pU`A X^u5PSb ?Ld(% "pr 2F_ŋ H +'7Ɉa+Pʫ/<P4a oWqȆM)!8~KZ#Q lav[&rvV /MsV`)ކy1 fV8È݅yVfZhPZf$g#3~#xQ3䫑B] +P 0H=mE0g?$KMit ʞ8KU+ VKJ'%%Od~E (ZHE⓾' X> O29_9/ %†eAՀFBy aU=L"@\5NMj]4#Fnd[?6eb#V65ʗy`hmX h%-&|%q|"4TB}JNcVfϜdo?"c +khjh2tfS%dΜlk1}N:a~R*]rk1Cc +'cpZ J)+D+u ZX"(F:dE0ҌD20 -Z<91r~H˦7;[$*')*"قW)Iw DbQ72;c/S"6װ"9lO@m;ݵzATZ%WVMOaoV4: +TA*hb(K*nغUѕH` [y_"I.,-`3l 8鯢ךTΕ[T]P Gs}?9fʔ A ?8Ж6Q2 dԍ!lQbN$d'ՈX2?Ɉng!6DlT~XȢ%Ī8"> 31^ZHU 82넽I+"6:EM t]+y ++IDĒW\ tW4 m`-lm/ǰV+a岧a#.DZb6BCVpDDiD ugZ0K.hqksd&HUqnSI(H|ænj1&Toa FGՓn[%aCSahq ۊ0LaZDN68g;VGJUy0 Q#m8T}hkAg cala0*:Cjet)j66sZiool HOX`")OÖV5 +3v7W3N+co] 7е4:ؒ GSI?xA洂X0B0%xc)ηE:YI5)7`VxD e&icMgcbP"om6 Qъa5Ia^QiP"H\hU#L8ҧNzy߂B>)j clZB2-Cx![G Ij jzN]" +N?dRL Ob;-nyɪ@Lh skԽEĄteݜiUdNW( n bwۆL:=Ү=Q9ٟ,ِPtuK*2Zh)GTj<4Qq72n Sdݦ2TogP +60[}0hs`"qҸAi7c-lk:jv&=NQitag /5k.+0b&2K nCj; TO"oI AځO5P@$ɞ^#Â3--HAJ*D-4;m.&kEcN 5@=9`݇죙T:aCV1H*J(j/#Ob;jAhTe:g3Ђ("jݣQ `rEӮ";"!MD^Lfˍ-]umTTnz jIQHjޜ@+DH+Uhn>Ӏ&,M q22H9=8 bGC䓨 +Q_Dх̨?FW!i8p$xSR+s10 2F2~Ædq fK'_tix#,o-hc Upd `Fp;MǾs:{DF4x +-BY‘ `!؂fIUWfq%MޣujJ9J{'%4wZc XcۡEpy2ьiˡ4Ž 2W vP!,6TJ#2&LGh}0I,u ٨a2Ҡ VL,]t;B ݔU4D}av"_a9 8QS$T" "h(c! tV(R%J#sU>=%%?9Qh@#|f+Eo1}%MA'z.skcSjS]d5=FM;j&fQm08Ln !3!GdA?-d-cM#l(sr {*=Q$=0t6u}& 3h*w:ʒТD|`h!ɛK2rkV4ѵ`8`h^fK0rBJqG +F}!h1 E CI_^/wo߿`M 3(QgPWyBa *6xc)'a|:ژBC8g5ՃWKu4HO(3w?JKH䂄VH2jq9;$%~dm2!$AI }G @X#sUИb=(搧L߁KK2@4KಈƉn:/ K1KOVЖg BxS-NOޤX2@=5[gt) :vdf, 4Ї.!S:h:Á|bL[J&RNY +g^Jge]*Q@+E֊kV`@d 7]%lцSeSj!tMjәY8E\71tS)DnTB;Ξ$r7* g? uT#lIЎ aMU2Ko<_; +?|¯SE)xc4Ng]Lj.G1_j%KxvE7w ?[XYmopN"I?hk!) +۠GgFwi32S2*xEa+ LJQR;"-睜SӁQ(T!0aҙF =bU!>I>z)L-(d t?5*nSSm6*Ȃ*`YԬfe(zw!#-=5EFP; /soE.;ɲaIT_j$E t/1!=&XY`*A#̛R5AMU!fDCVjga1!=[s;C% +|!p+K *XjRPHq] _CMXg- VJ2PiU(lyE7BgVܭzEG~  -v,؃FPTttJe,Cێ `[_% gr-)jJy:%a$֩a +N-hj +C7e+6Қܛ?d3(d rJ!83{jAFJ&[$J rdЫmNJ$J@FOIuNbTp&BșAqT%W*\Y'AT"N bRrQ-snl$ҞdQXجQ$aW*rt.R`r׻r5=j5 ѼZY &1N-A2MUNQF g,8=R=rĊF:YI>Jl̬?/o2aGȽ %J#TWII*%Q-^.LMlšȬLS]Z-W!P){e455ӜQ +B='h sكsC,1A\L-YHZD]/&nfbC{nPbfDiy&%4Hܠ2'Q +;/) ؉R(7ҦTW}c`^$x-5e3d$$y縃d1$ؔ77:cV. 16@Uq7tDi$33-)Ƞ,'cX2)K&. +5oEp3ʐ7 Gʤ³+dŐ'g1,*-} MU|,LI' asѲ2*Q<$;WN̡{HyLjA+pnT묅v"}߃*3'gcȃ앋JPssFdxjA8#d-*HT2:1)q4vQIwJbmbF[F^j6+)cb]Ih*9 &1cf>JrTPa0<)֋,2$k1_0VT.{C%M Lj +1)B(.wV,p=^=^1V$ơ&u(;mΥ(}ptZ4KFP1_UXFc[ \ZsÀQ+Ƌf|V2IQ(ѓ-^oTdTS2Iͮ,9v}31`Æ'FFu`r[,2*v z&+=2K|F}%uٍ hql (cW@.:bЁ"ITC-4_cS@}B+ +!>'.,¶!ht񅦘᫦5LJD*4q.Qpq8Uup4<'-/r>g25+1j>x!ނ-3[2]!~hr==b Rօ@܃P瑌G{EB' GvNFFZ6ߞzhB6j2_AG/!l\hHJG?&yxs;(T`VpO-N8 r#ems6Jz5xbwrenx7So *7֘Wˎt"!&TBnv=kNwRfކs'؛~ܜҿdN li  7/]~75 &]Ⱥ˜rr4\`!G,56Jo$^~oT`,˲MϜƇ P9dF9Q9 Q2݄LMfYD>*`vwPn|6ρ +#G:1uRt w((>?%L wʫՔ# 7J ާ"&DoI$<3x+/YCoQkT֪t%(xċ(J|qc +xϢiE񦘽0 귗ՉȐ)>B,R<97f? %U%H l iIl.Ud!]pQ*(ژBPao$qQStlkUoiC3 +kZ(6)k:'%~ཫYՖւ]^ R)X)ipEau,okM[RWM1n0IcCt7ơං`,n1~+b +w_8) +4^u Rbpdj09U&')5|3<g=>YP*搟H-`f"sBP%XX#;Ӆ]CZT%dnb-pEc1rWT%CP7ɀg>pݜyC tQ,O9+=MUrE egb-ADt`T}_Y@ylgPcal߁V%G:=H\z Z)A˂-\QdZ q*%>Q ԫB-\| ܯݡ%6*c|ь3 +o!@5+&?WR2^iO9 4G$QNJ!&jr65UE>r^CP!e?LZ-,y$8) liIc%zhyp/_+vRס =ySa] +S 5g#hnldczlcp}< OeZ`9Y[=ɛd>z!JWqw*ONOi><:Dt61Ba*eH_O X+>_ +e9 =FژNlE5;T4GvTD N>PQJ }$ F "f:x.qָTyc;Nd&Lu^ͥ5Cv`K3{|I*ADedia[۰qrtuq,wEH;[yIL!Gm,}"Z٧<;Z&BLy~{~ytCk33.f;1XϠO^ߡl&u0\onSzI<$ "7SlFĆkڔOoTGPcXtϯ6C r{ yE7D2:/8vhjJ>筢\6.Tn(=>Uh@3!۷M)7c ו8ARtU]nɴȡ#-Fq>ӯz(>1 :SR(GyOD^V;ZؾBq ++;מ9 +|Vx5F: +k>¬ब }!^nH9x%ߴu&c~Ra??0>؈U&$/BD7Q m2OS`l" 9o#AnΕoU`)J|Q= YepK 9df^ 7b~`|i,$Ԯphඞ7]aV6ĤYMF%-! :w ˿jpu%Sv+huntE xt_oVjG=q+1Ւ* 0STɹ9w 1l!bcE Q}@"O-5ªsi$Y>OmB-V0S:YAy]N)] :Kq7k07zX$CD!#||OC䰸NGAj*-˿oChGv+D)-Fb])w1w@dd&=?2v}@A->X'+GPzD1R΂D `"IIH}Dpc3Eʘ[(= D +"i!>7Pu2 4;OwNJW-tP&+i@-m';o/>Ȟ9ԀuzwU$3.DzF(X6Tu5t1WȳѾL!5daHA q+8RoC#99eG0y6oF*J<%ףf*[ɡmsFz24Z3F fբ^a#ot2b9@cZ2/2C)qu!I hǹ@s*PH<"]Y;JxwWIBD7pKS,9O;mi-0{h[]U踓cW BYv$@ÒSEu\enE 9&f|áe{*7+֋۩+I!Ռرp/~SN<MԿjV܋6ؑ +kKY!m{ wLjK -M+0q?R~O?o?~~?8?O_]󺂿@W;SݘAs}7Py0ۭZT'U6 >_ڛb;`ouA"'8eI7 @moQpўTy5ҠwȎk|xO60xM¦PKJ(? Ԏ}nU"Aa4u@ގ}o +8n&Eq̽׻_@sd?S#sOgGؿ("z(r ?sDmu8?]*=F!0UҐ;N=2њ@q"ԛ”QH}! E']!"ݬN'q^Hs040{O!PXA*`}ߊN}h1d9SMSv%GuelJ 4=t>pDd*=g +7Iѽ^8YvP*rg%{y"*wa鍂^6+Hbs8}NM"}гNubD8IN0N?=GJ;E^U64Ha%Mo =룇ckO'fv!HR`2yp5`8BRہj:/ ?wSn@Q}B}2+ +[~a$ՠ0N! F; 4HFj~+] zt~eQC:l1 B 2Rt#ۖy2ȜdKv7r?PTߋJl9$Ы̊3ib@ a}8,hLN J>B ?h藯@#,z{ JqH&}@F|,Cb<n? T;{(cGe?B\( +7{:" .b9>t2_pâ|-Zo ;>Fq^4 +!}.)qj 'tM>IH\w|B: 8􈷶&/=Q 6X(ЬU6[<=[bjV=hH0%݋'O oo5PcLN;+e,J22pQ%C0(7d2[ma7PRq0Q%Fpz[ +6+jo0I9'kQr#E? #pCbG;"MɁ%!6"OH"H]B+IQn a,,UG|eZՓK W2[ UɅ}l8aDD̗J{X;%)2vk;eލ a006C[ +08MorwA_ DϤ=! {y0bNՑB& Cwt*@Ły-pej|h`*^~qǪ%ёqUj V-'\`cנ—!Lcս%^͚joRAQ'˧Nl#%D]p+7|oUo½eI0X9&7vR|:U3">0v=̕%Tʅ@ȼBBI|ߊde1D.?OO"Af)tR~CIG_xIUJ\ +nȱA\Xv!%&%%ۭBl^=.V9Ҵ{xcK]]AiW!b&UY`@k 3q /=R +qeA^*J&pfoNGxUv8>HƇ>p;~lSmЖ㛡Q~;]mM) +oދ9 ˷*P}n\$I1:tp,esppf~|-Q3JJIU)nҲG+*v9 ,| Rn˷~Jɭ$@1:Z-S1b4p&fcP -PnjzGMI[?~ĥ ޣj8GeC +u:V{ 5xU2}2!{VN&R +oW/7nW ^9hxk !ؐ\ߋr-9+m9G=M`Y|;T{(L$rMsglȮb X =֘uxJ4Gh={Od$q-1{҆+mm2TAMТ 8i2iV赁M⹅ PD$_.sҽ3^v>& +ogʣ;Z(1 +?r=*8 d/?& +M͉aaK`QC*= Z_s+&Y {ᜂh z8j%dg\V0^am%+bC Bt|_yz< ɽ 81P$*ӽ!o}kxr2#h;8L Y+'QI_)ld``U8dD9,>0'tk9fXGŷ4Ed!@=ʄ*HOT ,HA_AuiqXwG~y 6~~#Äd: 52VR(zޡ&wi{r˶ 5(c\nv@u{"F +!U=Lδ{ĀkOeCGOpε3L!3!8p&ًd(5D CM*(L.d` eV3?yH{IZ϶ADm_8bLP2 +5~"6>'-EA^" 0}M!|:JscƉYӱ(MKv$J}{M`y:Jd{) rs@S DɛkN@d)G ?wVD}\s +Cbs/簣JDxJ +Ĝ khG2@F +f!\V_%U;lDun0V)OC"v4)IS +ɡ> z +MQ' oG}CBW:DF""S B!<`bzq>5ΐP } +pOƞJUv + j,G7!13#-񝜗aHGh#ďm@lЇGD@aQz{`m +\,(ph5 /(E|"ZX$s +UdN`Y-v8q{w~H tuec6 CQ+gG߶PO1rJSe**]'nzy9ӫN M + Baj@Cz+֐U3g{=䐬s>_uƇ`cNHvі cmb:ivN iy^G)\9 (RIDB2'tvMgߨz]P20HE}) z%w/ᬉi۪[o<,d XD-'pWіԁ kB89}ciɌAAgZŶSQLR2?"?Qu-X=d=HF"gdFiUb͊I]N#szU 3Vs`:0DЧ8=,\1=L3 zN,$[/ +xCeCbԑb /5q|y=o P`c8k M҈R[=N2P a`+FھfcȬШǷivʞ=vRv# {pcִjy 쇃 Q! 0:Ck\g;5Y#nN*Sh U~E=B?Ӹgq +ryDe0_Rv C }Ok,#; +#–iߥրb6N z1}ħ|h+H{Q`#M6h6]UOٯuVW? h#Q~vz`7{Y$.(iP(Q4T_ , TljlqEN"bWɤP&pFeLxW}C7"b9"XY^+K*-a!v@;r5HAK{{VzLK =zexqCP&Go/e@͐rcszlf]pMWme[=bc?zwy:n8;rTǓ,D8P zx&΄k)µg]zejǶWGADR8K{AeҝhJOCIS熅 +&xu\H$#ٞCAzP>Ҍp^$/aet/X|=!N4C"lj0;,s<*•*אY+ =#k&+0ESfiT xą(P Irr*ZV4KՂPAЇ /qhkyBN +|B:iҊRcͤ/]Dlsѳʺ&hcǥ#nO=XYPTo:=ն!~T(_*B @ػ-= %Roуu$h3)V~Q"]ϯYOK=_'o3{3IP D$X%p-Pe +y9kU8(7HT^qzPTf{00!dܺ'LLfG A˪tu8UTB"\ems4y)m 1|w Es1@Ьb'Dd{eTbqz=zp'/0*pWP,(\5.7*m4ng9q͠UYqD9=JgXLQ濽` @A, +̎ӡ>;þ$mѺ_ n94V("xXU D+/ 0\vty"p gN M缛D$XҠ4HA`¿M!)MD7U0k3C c҈%xa|]Fy;YՍF IUߩɬh_Y뎥S]n΀V};%%H +cO$\hSm c a4jOXD҅vC$(Kg h[8$sxlpA :‚z06PAWH#fkC0 {V=]ZD>Bb-ob8Bϋ 16(PNƦ>dzT-{;;o~jJO΍QX> uU.D쭺!%8 #A N)c*VwC+UأBmoǰ7X V+pUqXk{w4͈aN" 1g/KTGvdZdزp0FwjAr  $ʎTR&Y ɂ3ەI|Hxf, +by@>FՊR2=3$3#`g"ǙT%(S6O'tzAI/pBڽJ[l='Uz瓴0 +[}5y)) BafkCW# X+rLݛ7M/HD ^-ao ɝNul#{A_ +Մmh$)I`ͮ@Yt ut@Csz(Q7^f)p@ZPԕn)܁ QP U!gkxDA +A@/Av=TK1%{)HĪu^M83 +ƌdV!MBE4V?+Yŀ*+[l\O Q[XQՒ@kAB$pe$ SA )^I<$T+Sز2񀢖nUɣV,]<;GT9aЖ;n0JO`1g !~ıl7cAɤ$9E2҇L922F!e\Kn6=RLȡySrŀ[-FP2#kR{Aw9kATLmdӤ2C9rtJ]x O[ξ`r0s|qay 9| +dkFs@ HBpݜ##fr&}񲷩<{o2.yC [Q +$D]KB$YB0^^!@2@a#ƈ6άAF2z,9Gz>h3$(x4N 8oȖ֊Np@F*N9 +$dkAAۨA\ŷ~Pcg-R|-jj/{]Rh-0 U,6$]%-ۤdگo?i6v䲐DԘ&NuWBA + UMSwiR(#l7PObثY +7pIunY-~UI˔~*/X3 yp-+(ZtrxHz^H3ДMs ^QDp`d$u0Ml(ԕ=徲< +,R6Vuj~ jJĢצ9}]w3יD~iX”gAZV[`_6sl D +!ZXyIRQ2ܽҧ_Wȿu;²'!z8}U Ή٬0ba{ˡ?w >өDܒR( y:1a@@}MO ba8fc誽6p DRv$9:B }//)⠋ދ:Alp@^ +tԩiz~+K޸aad s]Aa=Dp~'ksL ryqYy,`JBP.iwi{JO&k5Q::#+s@ +ሪ-#_- %,zk EJ l|pSFPH>9S5!QkA"ҟ!c]$(OI]M83! +"ek?ŰvYp$٥Z&CxM +;tf?Z!LM8Z-q~  <_0]|(#$|u훝{qv,fWaz|݆P)J= S[2,SE7jyPdr%C'P@,Ao(Uy*BB}\) +S+F= 6 MpCaW}9 +2s]n `.vws剭MR#EіIXы?`9aWrx {i X8[12x]տG,+̡d 3.W&_cyOm! ϒNhid}H=tvmYuIGݟ6* ytmL 5yKTt^Ǘm >:i974~rܰKHS 510&uO\pǵ%#Yajb1[s mˢ!PИiTmSXwA= 6?n4xM M(@i"? +?ΤS`iff<|"|\Z(EGKa2AL^o(A>5R }{qT~,Ҁ_ h8qx6[j)YZAc$*LUC9{&V /Q-fTLN })q kG_m9r -*+w 򎂐GZC0^|AN~+Ň1F8 +bK_`=E2!Ld)\xh ?"a2+{|1<BNqܕCW=ypm(ϐRIcY3Y&0~_fc-X?dBF +H.|O'#UI44W癗mN +(8ʺGҲDN7ˣ(=~9W)i J8VuCE&ľte#FFT]{OқۨXXsጓ]zĄ Ud{ +CWQ*ߓ$JN{ %,‰HH_I"D`GT6e=zudwB +eٟ\rrpbk#o9*5W؛SalW)|գ-5s/X 䲹Mnv 34vጣ#b?zov(eKk4J %{A0T# ū0"[fCYu]6u +ڠ?B+RkCb!+ȯw= [ AFkXg  +'|" \y0EÅv".#s4sqbth_BLIc!:O[nu؉P(>Dצ +@@!@Bɕf*GɵJy~J <ꧨs5k`QeSCtH(p/pVX;N&P$m1[' $/HM|M&73@%2 .;˵P[i2莅^ '1ˣ̩k(У2<,:Ծ 9Zjva{QuG-<|Zsj=,=z^+:ʔa}Fv{Ho(7|5'h :R0}#+P/q-+Jސxԃ&H@4c#3`B 3+ay~ +%%˩ x6LUq*`֑f=%Q%#L/C*2tXjZ8=0xS.f"Od}%`r[^ VC3iYr֣p)KE NlE'>Ntz\~ 6dҊ +):PX[F^+/:#hϫA2bDUna5wLu{_FaqzQ|8Ck9#Cp" +!N}PV窜i|]P'TkH5 8(2 BT⥶?Ȇ"O{=tmTVOTCU vy(܏V X"*eb?b=39js^s^#hWlwPѿ?<-z!塖*A +[ #wGvD ܁`Rc8ȟ]ߢ _T_fJ'2HMk.dQ wşWHvL +/9[VAP;;ij׌Ba@<횽R#D:{a>%X{ĽjZЮ-/su*_K?= QKL Yؒ}-5 +nb6=#BMCA<g=<`@>ijN'пqލ`>F"ʶC1 +,(pӢrҙP^=B:#Y75BF;ZXnuQN>^i Ks?DRdog-@m$^['Ҕ0] *g%iZ RԗWz3zi˜+=T{X:W(J&{"Jvtz(<a5SΉ"ĥdjS#x6 -z(ڴL91يIkĭ t],{ws:j>Rbi ٸN,Q/-0[;Z!g̽#CiDY-dT+vo-yTUę&CEۓ^Iws4Huӊ(PdgdV)2 _K${_na RJ~>γ.nhg^WamE/ͷ^{QEb5E3?,9,Yp9 0p/?Xְ M- n_EČZY҅yKLc .`#┩wˌBR "5/ӄE AeP +`%* &|6S\vjyyblA:=f=n;z{c{9D$q+jH=M2H xT*Z׉ԓP Lj iƏ}%\!6ɡU -H"c[d1b"M[*= Tp8[PM0&EM8 O3#G{\Nڻ/?WB/{B V# 2Z.{cr$'qB5br a:)*(1CSkaeҒ!Blo=IdNzaNSh/۫hZ8Za `2aھç9`{Y$nu{8DT_s,8( +4AGLRH4 -R!ȿhlBH6JԆ`oEo?X؝SjVn+!'~)׋ލd#{[M)&@0#h2~q<.)7;+kyI` >IL;˺hm_g ˩ұ! Ɠlo@T鐠aECu?`dOnW -a0^uNf0[p xAynNţ&.O}ao ך@8C0z<1-!>Wa \X!PTN5ߵLgMޱb&f l,#dw rQi^IIWua_)<{˹“t=w[d*s8[7o_ǙGyRLp'yS#TL^'@ Wy^-x6lD[y\= PLy TgEWSNnjui;Z-@FAi~O~pll\BaR(.H<#fO+QNLjd:ߚp/ -blZ-JRTzI[z9TU xnB+A/5@;WP;x#*!6y ŏ-(|b4#[g%ҟ$c/!'ֹ[gUUZ>*&@GQ% +wJ D| m!q^Ě3s8$TF34P];ҡ>P=L"Sʒq&-jjgxng92g-$Ҡ 0L}("Ɗ6a1[Ƥ~SIv0$} AnT[xB"BuCX%f,+c^I?F|ߚGkg$$Qsc A)i@W4 ŷL5 Z 'eBCφ)rz"2X aF*T;![ '4!BfkNh߬{~N/ύ+[념M}=$4,&y+8STI>Tdp 31fX`Ln qc4.R{AП0#{=BR#h?].;,CHNdlU-= }&W#mÏB30DN|jl>9|8?KLo64Nt}"hX ;xfh6AEsYi Nnjj{0qTr߄fR#Qel-KBoHܾ$,r!-PT"f(~-H!L뙸*O!{TGMtʽ(y'6HUa CjƲ$2 ƎGŸooo?O?{^WH_ #'K-@ +K D|3/ՠ~37m?)j-bNj-(BL|`DGDXt<\&꟰' +d(g FpM̽7Y ՘ j2VD4Il )nr2rf~,͏ vnd8xkoh{\;AX jYdBsfar8jҊVt+=7OM vD (x #u$Ր%-2 躷g~8h`֛옱ZV,,\5_apVw*򐣈oH+X͓̲Is*Z [Y|Rd)2( +3#$W \pAf؀95wWhǼq*ńg7gNQw\zx|< =fXs-KRpgW-8L9FHZYLJJTŕF@둀;Ko=tANRY\p)_y ;@e"  c Aӆ?\0fyԞt +^ gP*n8ZU~sf;ӻԌ86k{ᄹވSeL_#_K!M]#l31؉)4Ԍ KSPsn8ϦMtĹ+W{NlΛTv߿H`8;֧\aTIQ髖s @#ż+_+{,a a@'cOpڌ ϒV27h ]/<3Ĥz]tҌE8(G%W1@uRxā1㲲]V?AK:&ޭg[X!z3ZJGAؒQ5z88uI;*ŵ)!QxԐޅ:k{ QϿ_;Xu# +ԌY\5'+*~A® =M₊6mrSi++3P]vhQIhfZ"'W +<^Sa m\1,ŷL%}3vo8Rw00|.0{eA.M@! +A +yR $u8uWmyH 6E,߿Q ,'Lx[fj C|;1{i:ǔg8--zz#6oEIsA!NCIÅ/P7)I$?H;e__ZDᶣ#݃wgxKK]yoۡjogBoq? cDM-%_aVJl {KmD & #od(9 &D 0s̻QcC8WpiAD9zNDZaNFRFgr $l0U AfER,?;@VPS5&6L(^yIX'#JCuD H,ِ4ix^<}k:.Iɦ ی zc9)IU'#trĎ&:az9 AsΨ2h٨#o 침S6v^/YGW#,إY^!s}|9ڈ{H15)x>5"tzìCTOc#0Et#46 P}h&v O sҟݕ1.h9]G#)X;!i| e]_I,8 h`DC[gz5/47"*h +<5ynܹ |e2QfOd*QlO5`~x5Z{3zܐOdދNȵK4Vh^:+,)@#M|4zzz>B}}45>F?9JI jϗ7C׺ސø2i4@EWZ ]:hAZ^'Jp^MO^¼gOᗰ_6aKӌ weTV6~ɿ[/[꫽BUzkTΛvhHƈhD +A )_VgԷd3)=/@\AȜ\%z$Ozoks?7;&?^MY&&T==0@h3$?磑K_w;opݶ@A*='~o;CDgdOT7ZUrs=x!{F9F Zo0L~ǡ4w JTLHyIlD~ +:R]\%㐆/Bk똾?9pHg`8ظ]^)!ƒZ,"Ьp$3tP,yGUx(wCI<\Xk`p$jGQeqdNmH 4lk. N`ڐZ3u 9㫺F:z) Yìג'"u)&er|`ע@~Ep*!$) C 1CNj]q1 ԉj4VS= n~&KI>}HX({B^dA`8@.s3q T`-\6Z)> O 0BaGȀW?K+w}?[ Ԋ̂pzs5$>Ԁ_tsKK~Uvnq4~5 hTňE{wC8<m,rE 4M/zad8~5uiXmHᘹ m62:*EyD w9=ݯYԬ 5CX|($8]H娾T_ԛiw@޼:R3Mc&Zڀn_3n5bW{5},1S}"=ϳz>"~ qv.k:3CLؖ/h(;HPAKSKuT.m7@Y@8e!m`b&G +}{ OE \W{q:>9LFio^#wGCn/]Ǔ0v$T PrY7^L!S8SP;>Cg*4!0lvX x da ΐͬ'UOX +%Ķ{U;Y75ŋBV 7\gׯ݁=ܟkCkGfxV/3:ۿ/'HQ(VkϽn>0SU*j<]Dr㨺\UT)fk Œ*oǁ )֏=~+Ƽy5>^z\Lj?^{ùd\vlXݩ?;sd9<z@Tmwgz"c]ss#;*b1LFq)8=Gdq7q&YZ `kJzxzs_[S^JPR/`^}n'ħ u4h..[:]Dl!C[S@)6@69܅80nl{>נb(a2ȸѵ8[{۷""6È?4<vfW#:2``'jsWF}yQ#~ʼnBKt%^wٕ@pHЌC)(A&RЀ*}o}}g +Nq6N'sc78]y2*u 2vC:(@JўjSԮs{c,YI_t{@ף8k%"D.kh#&n"Kk8tc?} >]լ2΂uJM0TdG\Mh'诃w/=PUߩ$pcy&cQ3|iîo"޷4ޣz " }t7`d՟ }ʌ +ؽ\Ŭ:Ժy6>Ul +E'Ċ{~ +'C .ҟk;R6 ֑c)].6CqM%VlWt"hlސN&=-#.8~~MVvX9YP?#!y;8BV9Ǥ_z$_7@U h臷mV}KW@b'FnX`Gv%Em%> +;)Ϭ8+<EPьEIJU7]<rlNC7cOH^q٠|ϫn+`( @no0(̄g-N\QEO1E jlgޮFtњE7E:ڈ=4[Ts9j$@㡎_@+'Ab31 +7 Ny0/opB$sz. u@=4YkR1QTW] +=Vo^эXO= hO hdDջ7\;Ohw\%PQJ{wϧ#wJ!5?(eHSXwQ#_pd&C2~ 7轗a:Ze)YD3gq)ɵg{E@$WNd+ӏ- +qJɭaoAD:/i@ q,i/ rsBB:n^2= N?\řBR8r|1IrLqFNKMK+BȞ0ܤ@4nE/;=Mu> 4W,ǃTLizpp#K:֯9[àbu(fe#uZ8VvPōT +i,8U*yyMY/āed鮛#b^̵$`&^'UO ԟ&h/s#L for@/{1! hB"ؙ/bX֞[ٗ)1Zy\QaBkvշ[ӷOد t +%Tn%.,:8K r ײ$qai)uSѾ ͍s3z4=D/ex@|怜Xx2e˱*.(.;8բ1vߟ3pyWұc T[ew} қY) a bLM,mn>%6;ElAE9q>u3Y . 4݅>CJƢ]@u +BJ}w(|Zwٝ-iePI2O b՗۟ymsQW(N7zLGQNni=H ]gT9<J4 38ξ!PC-X Q kY?7[(5׳Mԁm!PHw*Mɶ U`,t@zG!կעT +:x8NNvJ]Wxz@o$1.]㗧sDKRy?k(Zn;(B+ezv548m=b·RR||H&*~7`54uYAum:JDoNXG.{!mG +GmPY'ՎcwCƨ|nӱmoVΛuC0 =S%W) `d^qozvFF0wG +u{ M- C %TeFnI+ +ĻBǗJ&FטXPcʒp~VW| 3Ďs2T7W*!\or@OG}"ӮJrڢ vU~5G: }*P ձTE~/ ZR>3:y!i_^8o6 ;CU]o6TLjQEye zj Oj5kO>d==`Sl7[I&8'$< G_8KYEU먧A\_lebVpY?)26o;<ptѰ&ח +俯x\Ηu›"N8U{㘋H2n~L{}ߡ(hk>!}j'dGQ1]/owd@ 1bIz]fnt\nV*QeѱY֗-%?.:j(hIлb &bw@~73ߤO1 6Og%=Clĭ5>=^_b(4@c3{Yӌ8 1.;ͮ^wv>;/!2PW U =JpﻜX#"r0|jjD5}&gے0B;%N8Y6?|| 4Sš@ (*SgXN{>i5έ>%qlF\H!1L¯(9ۏJd TIEIT*OIS+)GFo"e;\B7u6u!~odW}YtGY%6҆#@-<(;<5r!+' ӆYv*4VIcưL{ +j@0,FNU~_,-R- Tv|=;qu1{iT+| m׌kT{=e>y[rc%IaBt +yY\$W2ilfe OZ-2^G, ֤Qս^y/H"iIvO13uꯋmK @h]n/gN TS9mEлcsVMX˲ccatYIcR:шC\b]Lp?m}aᛮHG7W;z~=8N ^M J#D*LD1Z*<(6鑼ED,&T#5 +"PU2}k*a^lvEϲl* ivAz: @3NJ:*lt/?t|qiV'ʕތ1t;J$UWMKеbp=Hvd Mİn]=b 5zT9$&C"}Tg=`C~O}wV4$G}Vd xV:Y6@U>+JG߸6kRA'dK^>±pU'sv: v?BY͂ŬrmmLV H&5nC,6Ǿ6/v YQ~`qB\iղ_tZY&p8C_B i" 1zWNi:VmdFCɹaDGq Ħ[7)rJY2bBx/I rPܱ<]S#m|4 T! ;FP Fz.1_$o_da;ɴCq8G Qa8BD㬨Ғ:8MɿhLL Je#6o^ALOۍb ԍTt-Ȗ+- pk\Jmp^uStD4arpfu5:2cWejjL&wFƒJT^k}^Gԣf?0Nt0=P׼lN̓upero2`|jwOA.!IFu [fqoGG1s' =GtJPgb&xFL#n5nPl]CSnfdJ|A6 x{H52Q@@Gv=}ΰ/"u;%B";pdk'KE8Ka,<$/xH T5-[u8CopèGÊgZamu6Vfԝ~3B2y& Wuʰv +دȰRfʷwh!@kiL>)H+"[sx: +>3: gX\W'0GW27x+9^Q)b1x@5}{隓OV:wJ +tҵjfΕP+bBRAq"QOU!Rjdger3Kh 0kzSާ;ȅUz5jYJ~w+jH;%ޘ İqGaRKU:V +nA8h8]j축 .g"E.88Vizڮcl ȽmPcO6Jth~`8+7}|hT\b^w۪`./375*Vk~ʶ~-aV~_2"30agQbۿ"FW.\EC)p`҆xGZ B1296y>cNC;`##_{ww|T}gi"¹$z=,E49zęrE9 l3c?~l; +{ غ@1&)WzսEʾsaIhlWxgrڒN=L`wTzH fLyH3p9 VWCm#9<(٦gC[֢sDj'h?#+͡hsI9Gcֱ<>x{쌬`pP@e}X]AOj-iL+is=ZDE@(|l<;3=kNF|eqnS"$d=1U9R|)׊o}g^Ce*=*";hV~d! O޿ *f"%^#=qrpZ/#"Bv?bc!7tp@]C[ӀVTW`R4;([d-dNd>_M64|MLeY<# Ҿhۙh"c NA25A[}== hW2fX4ἣ^ gQaǰoU\I~ǰ"8~t9XD/!)@ͺk()\k(G]"7= +-sk=+F΀fTbZ yše7 *ƖV,iFx2uc+@yvNGVa˾cKzze؃~Jv;*Kƒ|'cI}ѧw բ%( C!ӕM0:W4tA,W endstream endobj 106 0 obj <>stream +>S&$m6iD+>,`5(1_M=;ZhC܂Os|;F,ӲAɌHɔu%,)ey=GNF[oXB ݹ̞UKԂq5><ׁ-̓cC\Jt A!yAa--"9c-C UlQ^2B݅v|- )vAP沏toǞ}M3\Wվ77M$Mk20$ێ,}`3[FLgFآVVF4|x?D-{t||tl]S\/ w3J .CbȖM#S7)1 zQM+ғR4mhBR/:ej̚V.%lNNJ>&.֣(_Qz/B?W҆,PXoEK7U>7.fZ7*rP:m]oU ~Z:5~GJz~WHtViI%260u>n_LgOSIx2G7`?h'fU@So}DS 4/rOMwKgD^4/eZ,/|3-'o\ZOH6=E0_0~WpLFt=)FXS#r1>1t<)5XX㬴 + :賞گ/<2JFXnԍ_e画߇h,y5AG]fJ] + 4= #|7K$'}lO3ix+ &rj^|ܯg~@5O༃'fbT-Zp[4t +NgcUNoѺdG8|p>܂9~=y)zyQ6׿Q^?]~*k7v?#Ivc-Sw1%16N3 \wo?~ =_c XHȓ  +;;fAr_/Er֗42~D(I/V:a8{|,|џUP RF +E{}D<lcf:`Gh +kS;vR )Edo-j ++lq{L[뿻B"qL)Ԩޅ&n7̴;oj: 0r3 ;-,zE㷇Wo߇)dQ1Jd~cwo%A||nҝ$~g[{[9e1LT!PxݻWNjαNw\_u>@lszGUS!7@ d+ pLc*J||9S.~`yIH ;-Gg ?>݉qNp\@7>]`/DD7^J ; @~shW68~ c>~)gvsah [Mg-]&.\ +DndhC 0g_wG .a1ϤzꃊFNU)mIP +89=}be>*=Q+oU"}A$ߢ܉3\)& YΓ6}̵?btFш !f~8DÕ;ן,YER| u\[= +l:]ώ@s`TgD[9ORnn>;ٟ%mdy(=׺ +`#;~Ejh +^ː6ϰH!0 z|xU q`<NG5Qg,RC7PU}:+܍׭r +BloJo_vuTG%URѿdEg?/v_ >_?| ~Br֓,^`Uƭ釵=Ae.Z. ̠em\_'~]TIJ4דe +Ug,N>EDCVnЈDc_w}Q-RLl<@)5 Ҭ2 + q<6U&wkec ]VD7i< NsӈrF^ {^krʡi-,~+ŭiV2dj(lDk#WY_{g]uV +# aJq7]CZZplz/M9N>q4QgEzʂ4}vFu+A9z1Z{(@+|^(I`IEPh +ׇ'udG ={=6\w6ǩ=ko[/'O=Lh"Q)jWVRr +:µ~ +b|w>Oy"pfˣB;a 7an BA\+8vkWvE698osψbz\8՜f}/7ufBgQvF xよA!l|#L1{qQox: nKu.*u;0}u{}yAP=}/^py_QÙx>P]"k9b\&nAaq<«Iݭ +M*d JEgwOGh=}|S$8-c@Z.4+bX{ƶG=Үd`UH꿷q@|3C5y!613FfU60%9l.žߐVa +k8XEO#qn: lus*@a~!ldH™xĴ*A8$$S]~M%glz=g 깍$6: HFFI(6IFMrӰ'9}1L 蟯G6De(# +ǓxuB,OPVY~tXKjĄĨ'¦劀Tc(g"o#b {F_ +1"-Lq b%\DX6 \@\zJ2YJT=Ι5EÐetᤌ#E]lf.o +0<;vXyLlyӹ2*R 5\vbwYs5*yWj>6c2>[$]o w11&ݪ=Аݯn%fOHA}^eFLbFxS;.zʅHs%)ǹInu%1c~w߃_kmBG j eG54έ4tF'ǶzoY萏*n}uA=pҔdNL7M/F- Ga݊lI~r}iZ/g F[ϣ@FP{ڀ$P{*u5Y^ޮߜG $oihsk1c5x8B:OOɅ޷L +@^Ǣtym;C^PR- +vAj^ht&sQX֩WJW8@NW<]@1Ki f5b=ʾAgk*ׅ*x()r G9Ic.݉ =K)r[Ψd$;"j o"zt'/'ϕ>(pKj/P1IzbK0BH7UJ9O>ʮOA'}FI~ހM>B<Ȟ~B d䔆:|| r=`;ldvqkqn+nևγؒX0\u:9[Er7?RGg=kCY8fU ipv(cX!#2IEi1J?P~Txe:: X;u<V/c%ۨu+bp텯LGDI7ЦZ&jl,wLϳjy&D\['RXF#o_L#~rG0c-o6?~?szJP  S3f"誏QaeԕFbr (4V}掁 Z*זuޏ +1 Xxt8a- t/\W +eCQvo$b!.yy.Pӊ8bW)V RDZӽhWrq +:Hq(:i-T8^"WՎ8`W:xl6j^@ͼR D+χs#-VFp.0-qByt'4=:hj:;tJcnJ <"f*@6bE9Rk=uW!E` *-wD(8^?omRu +GP b`eu|SPd}2Ug4ߜ]Y7:YO` #!*{[94+]BUIS1R?"fT-+|B2i.1y&¯g<- OoΚ(+j]?#Vu^(LLu +oam_xQbZѵ@RY[9l \3">GBGJxGctƬ + l9p!6Y0-0`&yX8vX<:(^]L :άl˘]O5BX=btF +loOnro)jx u0ڌLiDk׼๒#Rfy$JU֊ +o<DjЖdJ&δI1;95հ`%5l!07){8;/,Iِ'W: ^=gyBPZ#۰gMfQK{" <Sq +fE:G7;(MȰ"Quce>l, +n3vGҎzU 'gF8H#3*0iR|xQ + ` :B&dV$g{X8SՓ"rUg#X[ߜji]Mfd}gdܧzvŁ{ +P'ăq_QCR4&6p{KYm,f# ~|rf9Jic%WZP;?؁|(k"ڻhw@|Hw~WfbOc྄(2շ5ґNUYi +PvM]rngyvgT-Qd(+ +yRCMDIC F;zz+r-^__txf\>|)sCbGnM`[45KIm%?Vif8BMrh)CV~D+UWjKbЊI*$^0_UE2I-`…z}Ni7Rs(;.MuW=?d/@ۯ_XbGğb]>h*Ml IY0 }">r [Ri@8%{Dm1AC`&{6Od@iC9;j z 2"W%7B|xvO7Q_r+M|sb\u8t{M#K8|lgA-0݁}#;i+ +0ZFdm-}ƿ,4ʈ\%}m1i(76;w$ u0fik=O*Vs-!P4|ٛ|>Tݨ@ϵL;2o&`$q <h%ؔz\`!n9@'4W=oTC9ӱc7G{FKO0nڬF֦zxýu [;FZ0 1Yg\q\TO_붬*¤83z'euHD,3 +<:6JZ9"zj3#[%VY_}@ViŊ-%  "}t*4?#fTA<̦(kyXU~nZ u[x%ݤy%AU>.t9YCtpt!MVKA|E\'-T10Z/ZG+PzuE ϕcZIm?jYNÖr]@ؚUh=XWu\7g +Z(WNN2J9Fu;KDY JDbJwzU up|̊`AgQ^ 9\Asz!OtGyڝ9?`_'N;DҴɆ3wJGE`M@~X7`yq + +e?HKm9$^ +462| +\•+FJYtM/WUy+A SRluƀ_)!~83 +2E Y35To˕zu֭ +ѼL 8Iq' } 8ʉ2v +~S9`~Za#5@6^XmfZ ̯N܆Ucf9Er ++ Taf`LߊDMa9,.:Cd;Kp|DbvSGPUs%``&] 9)gTلs6 k(!RVFu&Pl*P!#6}i+id [TM uo7!mҍi%,LH -9/'F"԰w56eoeVmMJ@V]kqnJ8_\$q=ڝ(WU ]¼"9تI]JәB:3V]+u%X+[%*<#Xiw~y)%B/B[gA[Hv?`3F0Uifk)MK68Gr 6:!~1/RزkC +dmi V -{T$Z:H3rweAщC@•C y16ZA n0s??`vX1$|HאY\2ybritʅjly|+b =JO:%H ڶ NiCГ? "8JkݺZOYPlE` k;apʅॻ(t;5rc~ hOQ0gwz#9-ceT]2<So|οYUHRBPue2iΒ QPAICk"l:DA5XG==Dϋ tD.3WR(U"{ DhG@[-$qJO׹r.އV CJj +-ߗ^.=mO S׊ڵ ?y=Q_XrR{vWd`xhv0UTzpfky%‘P}*Ʈ^ßѾpvW/EFAzM~7=8u[wyT** + z _uoXf뀷 cV@-oMgDIV"Dv.zɷ/aV # +0;hPJ~fGzcyPdhl@Q3T v15v>\æa/W}3d_<to7l|@tDw4XFh2wdu~\C`6߉xRjZ}]I釲 /P.-$yR+kb0e~XW>zvٳ (t-,U#[?l *FÅ._@Kr=בX!߹ᖀ"!ޔꯍ<= ɽ +mruT#b+! +r-q!by"KA|l_z01ЏFy_T,)F+Q{&|B+:G fn08np%%WiQj:{nJ`~oIʨ#kUE{U76 1`ZRgϘsP; bBy<g̒q2yr*^DV>thK̰[I/BTAyR{t!EM KJpv|+*$R(i vgUz%ÁVt/!#tq#j`vg];j]d 8"~_y@}(U%J`sRSr,0JDotIE>!'rm@ڱ$/g/6^I1Uz70HvRz}d$|6fj@Mvн +:ʈ40E9A=2BEԡqρTJՒn&{<*m`2)|ԝgx3qyL5Uge L7,RTՇ4 6x#sv^<^rCu{%~:#sk֞{  9+ :yX1H]6s`3)C" Ж9u2-6d=CwX=-n{OiOJ0焝gVˀB@JB#v igvMTݸeITtaR +86MnGx7:I}%CB3ϷS@G2FT-Po Gȏ + rФ98=sDfM6;9)-E)nW%L}%eѳA7z,/m-['#"`';y(ya]==x#Y1`Rky֋ЉAӏ3'~8;iu*ڧ#F O_KEW|珬|֊q6ѵ+Xݹ;}^[h[B+cx5e+. u&񒟼Q]3N'Ξ-^OdQ6x4L/ȸTrr^0#Wp}#=S#؈1Up啰{h-Nb>UCtQ~-cqlP]4=zEon4a.$]=~[:Qre 3=ބqypcӐ#*JRܷpDmH+;؝Q"KB6s_&jFM[XǙ^8P*:.QVS&/@g Uڻе&ӶVC_{;@HC Ǵ/S:eCԶRaU?HZCnm~1ud_gOuzj|*Y]M*!<٫2Hd[M:_"t#<bz9vqcɧӑS6r) I +ޡZh*n(BÍ:`!RHMLoj3!! q _)Irgs"Cayl? :#&zqzAy|xvy /:-JQ)H3r)q +9hy|{Qy)[; +yrcU67 +E V]Ӷh%w~e; + n*oP6=.f\U^&M .#0C[s+rL}ÃJF_`֭Mϕ-2$}壂,Xm|=zܧM< g4 Jx?lnkh ̨d1fgs]2<]\{2oZ!E#kQ>?mV Zf>$Q;j˸3<qLӣSJIOGu?EF.?f(ZDh6ӂ鴼)KGz:3xqd&= 7Nt2׉~ɬKFyTԎ-Z ī,)j^ӛ*`x`C~ןe|^Gao3i۔v@\86n 7h!3B^˦:3cxf5kh&:<']Fx0 zhil BQ>p~bqnyV`^)= tZDRFy]qe8Y grmRJvޕ.0!;?SdHOy-<&T+ &;;1 k0 FYD׺0_vPءv,9""\? -*ZMqb[QVq4ij)yU"hgq_~uh`IZm#V\DP¼/DB ?bȌQ"ꣾtzUxzR#S&ΜBm\m|T2Sm3JT%fQGh梨C#&M|'<Qfc HʠlE(i1$M? +r en/#XTwrJ$1M} +fLǙPVZӛWdp ͑wL8dW ]CK'>gYΨTso6I_oЇ~*X00@9K_5{ß# j? MUG?h fGx9pѬ|ٟf8?\La]3z(' ⿞,VyLm@<&ƹ\(MQWTqntha=ˮYaX4=M=j0Dʿ&` =]kI9O%SS&$+oh-Z6UsqV4nA4bv;09xؾ&Y܈WXO9WTԧ7KLqPKO96@B> ݢ%c:%tߛmv!_t?~98ikr͇9j(t"zXV <~J!V#C{EHOp@Z1! (\vf֫wR"*@+3xTIscLꂽmK~cl^D[xf@Ʊ zt4tAxT{cT{:\({.R)VziX`xMEu^dCd0B[>p?FvdY0tQc'`!d3Ⱥ+x2)H#=mp1oс^o*ԡז>w7R$b +2VM1D,jl3/P%^/D2@K*Zh2k{c1<%%szu){+Sv4z7PmMW +I(HQi#7Y*\AF2vS(t+ TmTT({Wg%{_0FD ]n +6^X ?W>qhυp=#J?5#Ή8r\\HkoA,slPxP$*ˋ%ǵSozaW{2VA?ܔK=+` +##f3\#%7sX{Y?]=_W;+N#qN+  2Z Uy?Πy ף4$\[QFK΂|P Bvņσp^M?\ +Ȃ-JI f.v[`z" 7Rx~YOEIq٥XL1YTclECXuGVh7[U͠Aq48y _Bjz +V$r5fE@`1b_x}e28W:SO W" :QCF4DYDyy-a8|׌l PiPF-|Ew5Wlj2⠌@sò -@73^L?[S:?mOb% Ir؝bY3+f0'aD%׽->SP!fV@_1=7ؙ0)Tp# +agd13X7iG +!9 +my1f+&C p܍Ztɴ2f뭡Sa:tgo7CgAjjqg=S^br$ Bz)Ϙ^Ir%nPצL^5Ed*9uBw;U'i3kD#)Tbs2:yl"b{>1Hd. X%c0^)! '+.~0" q*C{2x IwgxH \+_D菓EMNީqP#$I};J]apAG;wR˭4pU4b3֞pfˎJz%6{@WjPTm?4=5]u}p2 +%T=Xr:LFB +Um<60deZ\v2zڅ/2o|iѱ-{Esc-)Z3<>ci\~TJZ]`U ^&3e_Ni\9bC綔*$ޔ})hR,HG0ɢڎ0 zũI@w+&/P?zdB1Pox~[PPD< ݁Ү|kؖ"Hl=B9 B6[Ⱥ@:++":Nڹ] D"MӮ?͉almFGz->gf&\6Uw,q_^`;xIFߜF) zycHH@|qrk{vF@~6iۤـ *<S2uM +(i'?EطTQx7 +†ߩϻЏb+ #:`6:ζA7#\vo^HA8J=_{r2h2EnPv) yBF*[~P% RՁfѫ-O+~#6i;l8>.W +Kw۰ 𧸠Bzdq"@O)іϣ1E#Ҷ&o_Z۪"huveHag<\T"^6w|՚reXU V%Jy$[R0LJ(Z%G0;PO]#~~7 +f݋m_N`ujf :BHY^7@.6|IqtZpQ<:cTv}bqW>F0*JE>ͤq11i9W&Zd=Wh>~no~ՋlиĄܧxIQH:8:KFHژWThpn%`vQ(|0­`l_]Yl:L>ND1WxMQ)(d4@ebhXaObVд)qiw)HvPN'"B ]U 3'1+h-*??wLQ$mSJkZ_Z䇊k]C|Q遵sB7?m",n$SqrKV )/AmXjڕqBőJZ*K`!/4=l-B@*+DevS)c +k8j^܀(Oz٘"@EGKJ+_#"ѝQ)\$>p f(g8зF,$wq_FgcBx_O{4kk.G4fT9uzUX#l mK5J2b=t OX?mEJ]V2ĈLvT{AYj]F6`UhIBSd|ݦnЭRmɜU+XoЛ#&LPB#2skmEe +?<ޒ3iYa@" QVREeI2(+-\aB7SC*6a:  PZ ,H"mKK iQe 6m3B?%ƏS5)ߑUTM~uC_u^)P>l@o0b0'fn ߼% +K& kO}c}GĦoGChn:D MIxzF:| Bgv7i̾TT6C}}FEˈ厅26w^7ghuUp=j (\kQ̭GecpÞ`oGs$^qɀ +;<2YثUF\Nu}%]GBG({SpAgsüvQ"iuzWa$ŔA6Ϊu+ 0,y=}MDI49=p,SFt(-7nD'"4%@H1|Ԙl/¦F9 u + -ӇDq%ܯY1AiF NoBvh2wphZqi'n$)4 `6+q|"HInM=u`!dֈͳ@nIqC yx;XREV}Ѥ?X0)tkw f'8Ybz`49?Bt1ʓP܃1"% n 74o"g)5yNS+E~4 Rֽx΍£[C6=Řʚgq']HIDWTAAƕH"#‡UEʍD j"ҽsOgd_yOqh#;D'% :zn:ψ->eL>͘;LYH%nT"cp+`7%(]114GU)B +QMM`g4cr+:iψ/q6Ad gVI+=|I9cyhdl|b-Zmy#Zst7U+}F|I-xnp>6'ӜL"Qxjk4p*b8C ( WA&SNLv?*1jaf4"RcGեzp jui;eEN Fܯ-ć{>SD`j^"[BDה1S8*Ơ ڶZ@݂jBi8.bK7f"B9ƒ^}E}O`i9DȼN6ɢ;⪯C\#wHfoQJ40V&뢸2aHjIQ9ߣ:PGMDx8PB"1;lNR8_*ɶ$ ٹjSz8qJ#)AMHt)FN}rIU"@/r~: Pw5הRJ˓I@-tQϼg&kc;⠍U3$hEЧ2,pޢTQ!li4߭w>4kj ҵs?)zSgѳw]9z9>K{V eMSp(Br!D=j-pnUm[E'^>?};-LFG~w陴,ci.E ==R<?Qo'W';A+`CN_31砶,9X@,}=,P _b.:#(-C$BҌ5lۆpQ-j\\r+s⩚k +k3]*ڰRw~ x([Da&cyǺsGQ掘@Y;dvT>G =1Y IJB݀8] Zm Jos:pR^AN͖o7 ,gY㬍\v{g?֘CCinZ9lfLޘυCi +>8)櫬.VDMD*jQek{?ʠkw(Wc:Hkc? +]Ga>FpFAW+E%>FϞ/ +RybU5:4P!͞GRmmOY6UC/(ux!@N#:: `yX#ӯ1j&J; ށ~nH㤆I-xKL~x XBbcZj({;ӞZz%BX+t? _xqkwK@MD>AMٌ7;|n@rvƋ-F?Gk~ 0)o?QL|0{4@EhGxoQI0KlÉ2` [ߗpd#e%*e[TT:#y]BBRua]R,x kGے,ۆϽ|/vE+FT\r,5ݤM#ozݥcVvA(~@cںzmL +*aBt}}ou0]@lIRP2qni#mV1Zv#U`:3\9qݹH?0pX6J6tgfvQewY2\~&wZ̐խ5r5GdNiqb=[>B(/7P$/Yv9#-MN-Po|9 <F P5Zv.pv2-+s>iQQEiB~dCbk3O" 5an+ һ WMYy`s +לò?v#$gF`3>VDK}ꥣtr?UF8]WÝ:nen[? uGd~!Vur?-h!5Nǩ/*bC줐`Y[0e~֛EY +zSKSzHe-c)4E%tCHY+-+$bl;+|x^VP}Ya?}k$ : j}Qq|:"7:p $a6G7ν:sJL/ 6k(c)#??;׾[HE@cقT0BC˨-6tוm,"{}d?pm,8CJێ[v؏"{NbL龜-ۯ73h]Z,sTiGE3 + $)Z9_T8C#${3B%, `uL~xɋdj{wϕ&Qh>[ow˲X8c`F2^RؕSEW"8{_&(Ϣjiu"q),r~-#2rD&uG;4%Qħ#0.?K+MWlˣQp8 `a0ba0ЭzuQdVKc4ؚL%D`ISs7F!#ϯ\ +&|fu}zxƦEJo>=EOu[N.Β~H5U#@:,?"nnTSR^UC 2׿+n@y)V=A{շ0-y|/G3X [V,HE>h Aq9Z1+6 <7$+BSz1@^e@$%D9{2$_cKb7_oV~?ǿ߭P_???N~o rŔ9  +zx k?)8@nbB+j@ \_-m-.c86{ hPnlM +灂ݠclaE]}y[dHwم +R2kwzȹ; T_AkRHE=enNCH<#_%BUTe@Mhcy3bmkCz|=8!_heѻ#n}kZYWaЛOkW 524]:YoD9#8jSpN.ۂV[RUl6J$dDCWR[=@8k(<zg;z(B޹}^1QSJUhyoo&M:Chl:6ŘVNT\+U"nd&xmڹϤ[Y(d^1F( (Q4P&C/b8KJ0x21qY.`ۥ K@ӷtxzmAhEi."r O܀ WHQ౯y @,<m7wu&Ra^SEd9 +(bȯ +`Yo.G <384>?^"5TEIRu{ + mr:+|gCt9X\kV&N9u2 ӕWv7QRWZ= #%1F$7&El>G%u^L=(oٝ ۷(jc\rZX+Ldą@8!D-i#?]}5.ScD _XY*ѹ ?{BIYkn,:ר28G~͠Ow`w(AdVGQ6&DZNCPWY">U*1ېfE`赏D@&)W5.b tFQПgM!րW)>K~N\7N/}[%ciLX ;s9,2p<8!_!*'X=y2o"ۅy&Ux+K> +~&B:X`m}sAI=d(`=+s{FCU[slǻ{Ŋ x# R.-rۻwSР*q_H am+ث ?Eɠ U֞`S2 4oRޞa'n[x0GRnwP+,ѻj* ˺@Q[ Εa.M-_uVFC1 0ʗC-4ScߕDK;xc1DlQV v<@Aw?QP +}ӏ!DL3!Eo~ +?OGP't/N!; +>3d [.T 1MR% +։QjO176$>wyFX]$9ҵ;2eXȜZɯ]ڕ6 Ե_la^YAv[l(%N0)mrǪĪD9Xy 9(P :=݋_t~6$J +T҆Ix `lQ +I՞(hYĬM%'լ.S +#wD9֟`'z̓EGO;]]49 XU[zJY)¾$ٷ- +[F}N-(>{n?WR#EՍx1Y<3A)&|~1SGRLSk%հQxJTGzy჏v:)d  `[CCnb'EׯuUufFUĆ}W=WvGG]9 շ_ږȩf{r6a(Yn(eD' =zJp룥}7M +M$W"t<[fa&ھC۬vSCW-67%7x=򻌳Ԟ5`ATՂ:sӄy&A3Ж gx^]&V?vn9̊e挽5">g&~Jp|9[ZS扙6o'M3Xa][cl~F+?fjk +2CF'^48yF`Ǻ·=slSh{gN\Lfc{^z84aYqis>R 0RVH%KnΪv~3p{=f0lsΜВn{b3v7M5*$J?G=Z`J$44AEa0"b+9i*eKJ"+:9\x&S(E".%ͧn[@Q07Co{E/{jӌOGYl}A@h9'1Uv +Zw=j3Ē}w A:`?F3ԮpfgVb¬-4B/Nxxr|9/6ڂHu<fU%xʠߣmy[7|!i8Ҟcz;u))+ +~Yol윌K x*QI{t:~n Q0>"ďh *<\ ƶAM3A֪$)3Si[={Xɽ{|J'0Ǯe2Ě]u$8ZdT@ĹrmC"T9˷_c S8|w\p(Pln_L Ϥakwt}]?Ӗ$*4$ + S_x?jS\j2rW<:.w3bjJ$xwʀl`͆,Xy$%7JPWe?p +9 0+0ˊx)[8΃xHk1y#xJt2#@QX}oQ%F;3/|H9G[K":, 2guLl_bp27<-WCP J vu c+OyꢼzW6b,GUQ[L:07t$KGiGGUkK^"Sħ-Hk!٭3P-Vk;qC ጶ7OA),1J߂iE hfٍ) b](jhNvx`jX䚅֏Zoށ~|mdܜEfYtE? +5OU.b#I}lzg} ls GwqHJ=v6F` +>'ί6s٭J!:JFNLGbJEMr-\4Iئ= +8.Un"Xj(aE[{Pk +'&Ɗ5uJ| vҦϙꮚ41t@tI9ŧ;*ϑ=&y&|wE5B6_"&h]htlG;< i[V鹧 @nl*\#yv=YzSN87nz.wUhn +$I@2 +|c?uIIۣ_[EA,u5&%fRrwKJju LgdIfk ?D6b] uM+[a.ecg YyL5nniŀ^\0WcMY-v"ju }Th&+ +PZ Owg]W4v#Wy0s![9Έ1ЈQ=pxykŊTL }gyԹ8XqvzG~#@~eNx+Ѐ%޶sR@T\8"l+u1ךeg!P`mmMƁQU-(u|8Ē"<R?D"%B*2"WhӚj׭;ȏKD$Av?1ziͯa +`ᝈQLȹ7W+#=(۞ڕzrZGaଈ9SVvOeQ_1Y4 B%ԷUY58NI?0,"/h÷m%X^4vzBSQ?|~.3O  x,P_\fL:K5)ڼN1YnVK\Msۓa<\6<첐*D(H}92⦕"x3#nQXP'̴Oc+tթ˯ʘ tAϗ} H=`1DDu]Ƀޫr`, o +_z Rڗ@Es5Y+pWH="(rQ%)Ec[ E/lu9=+m|5MlgI,nL8OY'\)?CdůXPWt>\i Y7(sF&)-ujnlZUem':_y| kH) /R{$)A*ū:wWf)%^ ]s`bKi# -DX{]hp@>*apEvkgCDK *+z +֏NftzQB,WWظX#4-g{Wjq /إ#OfR)M^ 5\}rdxm0T Q3$uB·iHTu8)<OZ+mE&^թ_E#*HrJ˿en@/ . +b3NYresL+jȌ{{6oALJ']7CqpH[w)zd-#9o}Tv-.zO#1]}ZIZÚ}8c>~ @xFK L^0nxchϩuȫTDk?w7 R'YRayã5d"IhH_O?UFL`8( qPiCz 9%A̚#]FJpW8=۞N?:ͬe uW8x("oȠLu=-Z:D< kFTibJ~ E- Gh@PxY3+H0OP_ZۯaPZk^I؝Tr| Toa}] ({4h3/+2dqYAP8Yw[6/[Mqи:8YE~x@y |u#r=bq"rvfiT֖ a@{س7#=Y\r-< :(ʞ\PצYƝ\5E^ Ϸup,a2ֺK?$Ya^'7ˈ)n2G#bwn8TV;!$eoɣZiEnV:GžA7[iF,QeC CSC5㹞6[%£l5`=.D- Uzc I}ieCFtyBV`ki/~2Fn"1*M5*f=5vV/@,0:h7f[҇{Tyg8YX=S2#5#EŅO\[g^ng}j +z+O@5piAD7Hl `c0dVUHt=K5P8gV@ ݲ~;д ;ձc +rk,gBhC3V0ZCmQ#zG\th>r\ Ts> +Dauxй@z{Dxr^1\V%` 3hRQp|DZ^QXj+,<톪xW<@U4c#LS^0؍IZ acJHTwhb4kX8_Yl ؓ}{BsMŞ6]*4p\7zk|K w~fpMgL U Zx7e Flk77uYXxxMjGpՁ^߃8+,C.M^GRbG`Mef'ֹo't-h2GdƵ?#YY=Uh)x~[hDMpAgKDPW@$9$"QܾտU1/ +rvϭ 0ZN\BVYvWIWȭ,;|v1s.aڽK3弯,L)yy·D*Rۻbu'AAO2+eu@:MfRعHEa=?)z\]m^PruokV֠W!JT#R~#|Stɯ0c]*H$,Q$ϙ#a0dHӊ jxeI[PEazoh 0k%搬@Kk`۬##z _"PJa3Hdܚ<ϢcT |cUfܝ xX湟RJ%NVk[ss<4׮HU4P",,C>󥪽yڴ]@&qҎ ]`+xJ2Et$խֈV~Xp7ga: 2k/Lb w%_!Wb)ժevl9=h0Z|#8]A ,n]<A4uo톈zU[x)ZPi^wCm$&3W@vhXDD!Jef="£~J(v sz &!00@/G:qh̸0_(.S5fek,k5>R{0l߅#tZ2^k?! [gDt` M3u*U`Ftm%h mR{LS[vCo_7n;DUǶ8s_F''+P ި3zl-9[L5~S{AantΕvFjU6:\%61Pwdh]C"r%PN'OMIϼʖ:"0wNey!)QB"GpzAp7FH%QNu6cXR"vE_s,N&ܚ k³-f̓^pB耋,, "vƗwJmuN?U3U{^++̩9[jo1RZKpsS6ck}k P_ (($puڲH!UW].6ƥs.<Ȃ1{=q̼du4TZ̑X{?eK&-{H=3""hneީXÛe>vFI6&FQ*}O؂ZF͍8Mc:shaԦB, 3zt*7s b": bvH4E{d=\֨^eį,Ưߘ&M(TZcMV괊mj$YtTG~=>(P|}`ݵ5Г ~ZX*tғ)@9gy>00$0"x5тP>n85iBj¾RDMv@֣B~gPQY܉3RJ] +V0xE.$W%UIO@Hb[M`ڭDx=m{=la;U =A-Ju@H\k3|ҏ,PKf !mW\|nՌvUJemg;.ʁ@!4Q"7+CH9"*l;5+U5PUmW&gOyiǦ^&[8(1kMp2kQ ܘ s TC}[Сް h} eU84OS-6bX/*I4#?E$!U. +%Cz辒ͬ(Y2H9n#%NSj-l܍ lZ}(=**T8}! 8\L[js㱪r5PV9l#]gN u$JԲ`bG|`\uͰ޵׸(S%__'@:CHQذ&|;[{z` jjipKunl6,t}ҥ.ћ*@bT\^C+$J t$iFѮ-.n6qvWش`CAL5gu#8r490qkSD}g.$a5$44yJSOۂwvtpI&ӞWQQ.L 7L4z9e2fҢkQp"DD#HT +SX[;tVJƐJKN +Nķ OL>n}?Ǿ5HЭ>Td~81|+KaI ҃oZ&M?T=i0'A8LtVnvҬd03K44_=L@{bs)I($MYTJC5jA54;CVFVH~ޅ(4VP_F_\eJQw^n(yEzKo[EZ_kE!Ag.!U@9镀.E`LX e*Tr_9Y=a-Yw"= ̥Kw)BVBxxVK:Ұ1'u})Pa}P_9,8E\>E"X}|UKԑb +R<|X#}&[j`3-A;\WYk˦ΨeN~Nc 4_'1qaΩb[A؝., ~#tutbCHz6DEFف^?RGJgؚ|bs^P,^#.'r]#E$&j@Ee3Bm( ]\/"PbvØ'4n! +hamS oʅoCl6 y3ȫ2 k7wבR"AN1Q![.1Ɍh,YyWi|ypazTzM$ȩڵ䊣ͥl'.04(O0A}Ƣ>o@P@䖑 +Fe`aoYEo&FE4nHP/ÅrL^&Ɉ +>0p [ёhίSNv'P3"#̣SK/i^ +XO4~6ZĀDߥ!=&l1+ؕB]ɗ DYo'䗽%4DG9D%;bg+ט6NAVSޞ٣k@/4a>Pûs Z :dP5g#h5Ȅjhq֒Lz]f ߥ=$f E =J[r xQڋ|33~̾E<y$+B*V~Ӣ~|-Q4:,)z rY L5˽#Xk}wj$o)`ai"TQ7{Aj]_:q>hhfX[U5ҷPkD&ܲ1a`6F^Q KR@@rΐ1if%&8ӄ = T93%Z*hm2njGwRճS- u$м;CCSz[/1iDf5n^x[ Ucxpy=*(EzI/ Iqd^ȯo?yCFI"}=8Rb]9UǕPٸ2_jw.d;o 0uJRV=Q] }8w_9; _O)@46c ~e$>Dt0}eO9 nȢ wKƃhK'u0yV{2(% 5+z"лzʅkx`DZDJ5Jda7d>Wd>gtGJv`}s:4& +3ȵ5 =]t>*䁿l$)ʶv@z1$x#Op2pYO39GRHѡTbФҡ/+&/Y\QأD+$6(*T2A7pv3 eEvY~>εRVL +-QĴ$Ns+BUf".mRﭿ|, :D5W^w3A"p(r3md]v;. +B?&=9aSiM]xuRd|oP*giD@ Ĉb- 3}gR>R0sea߮:&֯  *7}mptoX[?EH2rS+6+j~>h{\rEt 4َrQo:@>Ӏ2Au!}v"xQ%H(F\$Opy7sŝS6WO\f@@ۭ.g4߷y]W"M> jUQr|"ڎؤ^sD UuC҈Cf[T@8I0XU"V۸7 +E-;L)gPeET@~"s Rqn -@q5c!bxN7X-GsT%ٻ diL1k `Y{[ܠRF5eRv[惮vP?"vUy\WDE4b-Gb?5-o)O="ȅFeK}4\LŠv~7 1ze<_L>%۬ƿ/(:=)s ؐZ(pڀ +ŕʺ1H Tsmz![utIf]/~bQe,fm!̩Z!KX2K[[:^ˑ48ՃYQjwuG!Ơ+Rü#@0,xtr I 灬_S +2ED=-#m/{W ݞƆsA*pXX*% YkjhH"]QךjW)'Kdڏ+*بQOD*Lm)" k4iܣLq"YKoRywS2wq.ڷR]g%zO<([hT?VPn6$^OR^RLt5B_8 :kK('JD0eE>,mЅ2XCʴ 2|-/0T|+ArnY #)v "ԓn_}?Qrn_v[ɎRϪfzfMEtNYv-jOS5̑"G>"d)UvhWѴ?=\V@O)VPمh7h܅`S >HZP4$ԏBs "g +Ŝ8\TlS+k( ܷVo% y6nlc& A3sEn%Cj/b1)`[ƭR"{mmCf7;5lefj񛘍~4QIh4)f*sUE?%tLN;gZ:Wrn\؊`EJZ顟fy/V>:`gPG\RrBs; +ܑS ` +[-zpbSfVfǘ- +&*ZL3`Ia5Xc)7I+;p40VR ymoK!DK=0i3U0_cLO)PSTN(j:GpAq!-xolx d]R*|$u'@/[YQzĢ)x%痛]~HfR赙bR\S2Ҩc:`ꪮ b9;N:t5+^>-Q"[f~wJu{1bż7Cj%*ZWL:(޿ ADPCk$ *uw\!TY:$7dnvKa1MUVD"qp:LtVL.3 3{1;s.X($QvWNO7ѭ=̴Ǖ)e>z/v̔q}mZ^m`b4QNy=!GꖒBa$WC=|3l]+b6w<ɢE#  KtN2( D.zZΌ6[`:toϛ4uYcԤm7Zˠ4@ۮ=F/ϤQ;񘬍 Czۢ=>r~8J^~ (_t{6ɱm-񮒞ZMD }JD^ =8Y:h q}TCH[?-'a?ֱ?Q#r˲k22>OY@.NXkN>EԠwEņR©<<لM9ki•֛/Q\{@ŀ20'b-JRR}仝է-0Ԣ^W EُJ6|[HeP%eg1+qdKO#raYlDCC<~hT*S|e@=H?-ӅIa?{Q}}Y[Ǚ{S~ZvDHCaB]t NjTdE4?^GZb57N dcR$֎RSaPܡe$#vk(kۆTN~ϛZe+$3T9J^Yrf;1lj; =ȆӶSe#N ?$x ZG*@($#$iD4)K($"׮Kb(tEP$J5 Ftd#iaQ,ލ4y#J#1Sgg8VF?%izrze~ ӛ+fK Ίڌ[hEg7dk7G`ȁ _ȱW}a@Y|rHOhN֟"?#8mSʔTc=G5 T\h\5ALF--6WbrV,=2PLZ$F\gʺ5S:W}Q.XZ6U.rM^u"qfɽȭߔS^ZpEx'/=g;lGyfGgxD{NҺ뽋-$xþ68^1>DTC +ĊaL%zɝ +Vv^N66&a[]; % +(1Q~ ˉj3Qt +ᣈmFZ@ynC}ǮjluAD%wdRC9D4* +B<-"ꕂ\~-sT"RfV=|E3\9 ml{2)4i:#q}46]|&|Ca/CX( )ɲcGdR9Ut~TjSTa +%(&L& ?MtGoYx)SF1`v_ɕƩ,B$G}_Zq׳GBV41QTo`H6(WAblMۄjx:{dDiiI~:"Ba=r +:-1*2?d>÷ 0j}#jmAC.zf_NΈ>/O7az[? %U.j >|n+UvG@{έ̛ZMs {K: zV#$lFZ}dAdA R%YL|MAlyߘu6Z/,X!@N$5U]sBc_Փh{K-<|VtguDsB4sSAV& J#\,/ڭ`)fl!"4f AF|!HJ3sE b +RAJ + /xԑ_jYxd +~T am{JAB![8>hr E:{aIEB0y閷- YV|G0;*c䎍${7;Y4;kmR1(}L'K۲/G z~(DQ$r_cN;3IlGnR862^o(BBӊf'M:囜#z蔃fYwĝ%OI9GQI%V}U+j4o`¶77ZWQT~%02:lf2%F4Q?~Uɫ/߬9ſ?>Xſ?/_???z?y`A&V:j(@Z5J 9-)MQ0*QZlC$'075$Cߨb[aw&+Cg8'18=Eot (5xmCS<|q$-(ؓX$CixEY?qIU|}Q둧҃ÀN pBЪ ұTv6;?K=$3gի~jv2JEzb[OiH/L/Ԋb[[b.L +S4Q ?Qw?cI+۶C{߉#•JXHK&eze=#6YP@bho9ōÕ4W|-: + ܎_N +НU;@\ߵnJ~ jI3ֺVn 2@'!ҴkRP؝ro< qhrYH#E\25Vm[)naQl̟#D(|8mXN_*EƮ=fp:ak&qg1 :+~4=ЇNAGߎ´N%VL5TsdULagrO{'[Qz F(O-$iZDP# [0-s9Jq箹1xa%p4{ SfG&/ ֐˔9e.FV`97{}*],i{rh,ڨpyӶ_8Ll/13顡A@/|]Wкq#&$;%󜎜wH&>X>SD.Etɺ[~?zhwxc=F~~>Rzn{]';PL Ǧ' !*d%j't2e=. 4Hn\7m~A}? vRyq1 jX+O=ߎ/"/fH z-B }`+X_̂İw4R{h-(nm_ odm%D%{Fȅ`e⯍0vpڏ[Q [pfj+6z֬vcjPR1!_V[dٟZ2aQЯ@c +Q掶1B.u|NW`֌2x$HTy D.ݺN$򯨓v092AװoVI^+TYkyϓyO :NT4X'RJ[7_U *݆1_T|O&{r1tCeވ CEuM:-@vKx5 W q)>gts@HSIjhN45OvN=r~c\©k,m{.:n WзiҼ~C4ɊeoQ<یx0^+:?D|ǔ>/ׯa.C;>$ߩGSߥ U9Z[{xE( %{Y}m`;} ]@ek .s} L86W7ȅSF\T~.nАz yBOz-\X`c` P34A@ S~WDFqŶn,+̈́u>Q7eH-2#[ޗE%Gq3f(4IeXn_-^epJ^_)|cS,^)"koApCSI/}{`ri1p*2}{Օ-#%k%- b,o?DAu發E)Tj-qx <]1o/1렟c T?7h>5QvPAҸX+:[rjxfOI!7}W\άάT +.pA8lCOYN=6"w3e"VvٍȣTkYM[{ΰ +9R+ +X'o@j6֜:Gܟ"N}okILyu}i.-;BbH݀@辦qf9F|Hн}~>v1b􃘐CAE( qiTʵB[ M]M yV?+vkn^ 5 -XyDGy*q6`7ɵ!xf{mxOpç69}uuA{zͩ2B> +>Z`|m#Ҭİ\kX ?{LUTXi@D^w:f>~/O[j,Z4}5B:vs[L̙VP!8䊨tq7OUzDv]c03'07yIRSzG`a P]^Bˇ*SegIP=mm+PBMgxB$b=%6:H=nφlTL5ٙdCq멬 qkiG-:.Y6s+]X s*ӭ?:q`~bidMSoLN,Qm|k#V]ԺG/6z O͍-lG9DܝeqtMn IO}gU f +s--Fӕ^wɡ( y/+o÷^Q<ȍbƀkÕU{s^'#‰?dXZ~IBV1^ЬE"Tݔ)NiM}k/ֳ, fbϭ*5| "&ˢ_|FZM$J5}["I [V"(/ܨ}~g-~n:3LT墨p3D3v*K9<h"*0@jFT}coJ>E%Uh (gʃ3~f92-J;i/0d@P^΁j[}.F醪Ƽ5ύ7Y||jw"TlgQ_p+diUܔd(8MBw VUï>wkùjkc ߚѧNC>&VƢ)L~cQŝ~x{mWK->=&fWoMZKEI\73Z¹|~.#5D]qm6@}dìazrl k!Y|5#8uQ7rWqq Pؼr UDHCOچ+eIцK+q(m>=ݟ3RwqRy"߳9Չ ї#|}{h>Qs%'x c se22 +"&r"`)}Fdz=_؇#i]43] 6?nveKza]Î/a !B nRBBEJ==ṣNUrvD~I&,&-}{"h>i%N7dʑžxJ_|DTh3`uGRI +C}nNX>\[sv͆ f[gW@\z_񯵂Pc7dzPfIjA$Me=f\CL c/uG$Q8 U^lx,YduM73@2cmdG)8Q=cNo~~ǻv wd< +C`L:$u. p(|ҿi^<0$EI+4p}i$;@ZGi˘~@.1P}kd63G/#G|'#ʫkUSO!,ͧr43tt8(bݮ@e =5lgc鯉A w Q*&bVUҢOTX^Pvy"M `f8-@w^4fIƯU=3 +Wފ!׭B3G%EkW2hDd2P]ݕwyH5 B6ۈ))EK>Q!j:RY"G`Oo"D6 E께P +M}-^(:H=u?]qXs V=AkWSz5#na-H#H\2@촢c |Da]T #Cg4&Dp*|*X_Wz詒ɒC`*\FAKB0"?1y 3w~эXPLۦ5@'X 48O. + 9C̵v噝6bv*Y4qZKXg](-+FƲΨF}uocNyƍ^]~PeUf4F(1Ϟ4JQ1Cאs]QaD%J;دTFvgkڎd '6;#!. x`2Uw^%nܞ'`f|RpEm?E9ÉMiY6j<թɫàt|qG$ [`Jmw:X9hCjdM tZ.[dja u%f䳽E3,ҎHpKn6"ϛ?6BwD +&,%G>t=9]] @Os#8q @;FAؘC73gC?U{d(믿( _9Yۻ?@i96oH-SyFR*.@/Mt^Hs}O-OjPT\3S :ҋ$tbdQ2f|=iLu'W eJ ceo?!QA/g:A/M-S3rxt`uSӖ`?DS*׮s]FyǽGQiJ6jl<^P?Tj㤏ad+<ݿ. p'TgJd.{0tjFpOˤ .VEj:2S:OWx!vCoȣ౯1w)깰ʟ9 :n8bĭe"ÃjG/ҷ/g'ŇdGr1SSk-T]v:N<Τf>@2)U)f$azlK?:nje(GW<ư+(n,:R "OiNՈM%XǂiWkח2RAޯP#w?Ց뽳iFYJTzXB\# n4s'S'"]\ b" r{q[<P}{zZQ?^KfLֺ(gўoy (nK݅Vߦ4sn"λT>rsy3KNϞtvp{-" +XU~XlZbѾ;#[,o(Ѕɧ-X1&zS{)QJv";3ƁjVPs0T: +gh(1\x@"7lZ=lCb7fvc~$SE}- B F[{c"?#HYjmO=CmKx9-B7@3RXU\iw sS#?N!TJckY8@ΡA?(Ŀ~FN+*z{bu݁bO +KvAݧq9X P_r\JcUh` +Q|6e10p@Za"\!D-N{A]!kfXS0u/1Vr#k-|h=vD}$RqFR8Bݓ1pYUj|2 oљ|b|M|pa>N9eU8%K$,.4":K\-gy2D*RZ}aOfLHl: 7`͖.( it{P!DkqԬR6)'׍*L+>=,v8ʖ{/. +j-%h! ¤YF,Plr<.V<ՆoQ(n-D7 ~+<'ɥr7)=>J8`R#FXmO#1K鷜%5ҘY7A& ^بj=tm=T{LB-̓*d;+i|jipFɷtx5!LP?f'@3**Xo<n渚u%xG%szED(JC_Sa[V_zť.g/ѷ4/L}l΀Qc*Bc7brURx}سΣa%1\S{v98=[.{U?@Ar2@\kVY ǭHr3lkD,Aty;`5e`]()U?'5NA #o5S5Fӻ<\)L{<]h:{KJROVFnd%0i2+@I;iWqt:dz3@ *:HtX\~V ȯ.oƌ7:%Gfv8,!\xTNNAvRl`oe[85U-OCe]]M](5g4TEVʫ |/ z 4g'AG n!o^f3-Z?"+B lFD1CY.l ..8$=:Qi BZ @U>2AU.;B[!_7$-izJHFeAb(yQ^Sր߰=Ztr|eҍm|isDq3T Wt+4:v+E΁|ԅCuwfO=RG ۱ڬfkdhRh&~kDPUd(l߯Wyבy*}S^;5izd.֑9WlDPnk*w@z9LRYuga?zMt6gU_iA^ﲭge@|@XE"q4h&H[~n8'cK2ѕj{)W{!a0C_t&7ӫ%)7*6\ habA훨iZݓ0>dzҝB92O{yAOWa,:.NkG"p`?v&@xMG4Z:3"]N#b/D\z޾c>&,z$o̰լ1O{*MYL!RFAHq{~ N&Ff \L _y!d\b2p HE%NT* w|$ǕSx (xQ_ 1#+V%$>?{.`P4[#Z&sUP7. '^D1 +>h6Q/L嬤D;#\ʕZD}&A{dt tļt^:{'aOK^R_}U@ݱk?KbzT+ÎOBPAn#, MbIw+9}]IeϓPkP9V̗,fL_&Ms܀Y_"hm"KQW-!2Rg -+lJ^:AjXz\ sEaɾ-;D>nc뉸wKu ƃzRo +oJܔvhdvјg*3^p#ӳΥgV̢hZ@؉88 ƍO_@iAD|̯+ uA[ Qۥh_#__W ge8@y)(A}r\_m8GNsD0jr) @OA^t@9+ ddA\@nU;̂WpGFi8:ߓf=)}5mPm3׀Ǖ%ٛI1݊/m%G + z9Ú<R]̈W~܏2M&3?˹ڂg$41?d$m2R۲P~vq@Tk=2]=E. wjo`[:6",,C 80JfP;.(9_Q̂0࠮}/>š;ܕ("GyD}JsFFMG[X#)dѧѮS×KUt`Ӓ{~k_w xFN43*ΡbFpX0{avBҿd! +)|eӶLhK/zAXw !bO}ezkU ;ATkwG}bo $݀ tTED });9~^c0wq=r|9ʸ]7]Wbwv]ñ1t+Q{>$0;,Q(e>t|$-D:nP$:5 +YMTڭF?ޟ#YrBnNMџ{j V/*W?aqp<8:l<(0[Ə2 ^ r~TqcY=ψ&NhXu(Ķزy7{Gd+;d+ڄ]:oN~^n}UA8jhUk~.)= “ &l;b]1) g4wCLP41vfb#,m'vG I7\zGo,KG`HUG`SjHNu_1>4p!' Ycpds@Dz*bPp?[? +0}+_q!z)?g2ELCz*եDY}`IP] `V v3UEou~DH3y`8В;tEE:,:.@`^iuX}ڽಫI(?Ώ1UL/">02[ >0ľي摩7$<~,`WH'?ij${ %%5j|YQȳ khܞes&[Rdؗ0/f]b4S/(ծ'+r~' fTaz~ +R|%s0V.0W=4_4;PRk1;|H~>sOPuGTwԌL𥉉>k'ȥF/LFhq;mQҒ&a GIUy@T(~cv ۇ.8Mz?tW`g u0d`e : d[2WَB(8] YKrq%,QFBڍď+wԩ`.QT0wX+Dy+M!*_4%{R3|9Q3{`5# UlVYC hЉ檖7]*a!QݣHj7s\wTSb3fLWRH +J}}p3Fāγ^ 8CXAZtaTZMv2qcW﬑=[~!TL%'\F8s(&-&4Hا(tfGަJP~H&Kk=w 9t?-~(.l.aD\)B (j}GDj̖)&W:zj##\ . ~ϳ2E  WSq4/-JT^!uߏƶz|DiS @”j㈾6mG&C4=gbbܤKfW8|D8%4J9YÐ#/VT35h4)5nBG*(kܦTAF<lGUR3D.Y0 n_{689\8VKGD5$]l[@p=J1NwEp:dL.yrUfҠeGDQpF_EG#<CN5`eN^Ż:U{|/ؠz9u~U+jCTl3Hd;")R>_[u~ay {?8ЂΘDw?4޿Ld Kxn,A]ԯL]Feؿ C􎥠Kn]$#mfhޮ@eYSo{Wgd*mz+5'p#ntTp]^g"v[){c~׎Ev}R!NgeʧR9v -:X'X{{x|(;_Y/ATT<+~@[cѐ<^`?+"Aσ:9ֳarR +|8Խʛ=V gRwa(v/W?Q74aGⒻ*MRמuߍ'\5=l霯ϳJOUX4 Pw񧃑뵵#[뮛LP/ӽt||)pe2Ff_DzE5_|V%$q͘;uGN^o)^K/ʔf04mlv灳O(뼏Mn2Mݢ@}ыL:AFAp +)ND}U I'"R30>04+9G0p9x(LQwylTL=؈mQ#>Zg|sJ'O2i  P Hryk\?D/h&"8W@?ā8 &((z{n*NF*~P~DjDfX  t?dY\ #W.Q j^>6sO&.Ypa mSAiG HiyQ'|`5#⟪v(* Ƈˈ!?Y_qŠ<1|:+|@KУKt +Ly@Fr;ADRR%p\3HCS2]4iF~ x}3 >H;3"@Ӷ1i-*J,O52%+n]邎KM$1G=3ǺpeLZrYB$87Vgn]!O0(!~@52,eq#7T[~c8YTKh K<X3־8Nϣ"Y=#@&3;ZHW9##گکA$ +F̟ `Oģ ЎW9XsL)Gt,)LXON/h'Z1͔h_qbTA#A,(n-J5#P0~~~_`&Ans%e>>c?US}&Lauk?{uUԍfI +OjE("/́R "5giJ ڼbO 66 ' +*ma)7Ȓa&ƫ!@)G<%p~£gl GAG:́/s~zѓ]C_Aس sU)NɬaG[ I^r"L_#l/Tt"J3`~+#Ah!N,Ed%LͮyhB a5%#*Z]au|z5&[?I5[!J`(G49q .0e5֔a2\yVRAu{γzJ1bRooWH +*+u<*3g:߻8j0Yyޥ@x*8;p4D=#.6;j Z>z05G: +JO0PbvÂY|+0#λ#&>j Qni%ECq u h/I[ı2(a]vgXG߁^-o!T5Q6<Ƌ )gUx=Rڷ2N4D +thR±^ rLܽs%FxsZrg4e 'Vdx ͘(!IWhwPhwnG2}Sęf9^۷QRcL^XN5}Gt!X@y(AΊb_": T܋O1/u~h6/D=3wDm=Gd +Վa{UɀU;P#VIGcm_o'j-;G`+#~' hRr2@J} Q;ՖQ "{o)= +)߷I~zWQ_5Rx.W2yz ({;-eRv~#7csy?(yoLdIz$>'<)"KV\iY`Z;n ϞMߴƶ8FP'hE30_,Jo Rr';0mɲ___ӿO??ÿqÿ?} ن܈F] H(ѭ/L_ 6S tjGLMʤ+TNQD:%bsvbs1b!YnW'H1OםVc;~M}kW +U>:{麛7psBыS0M;1i&ȅRUf$g=*OQ\tdu8\+"#psi药0pM=90i0<K"+ 4#No7PazNǤ#(UF!G\]1O8TnoA^{ˠ((nzPe#ycOWC 13-~"j}HLvų0POB)!⧇#膐)C![yarZVAW;}]Q eZeta,,XY[+|vD 14%iP)B47Up-<@ݐcw i,28&"wIF&x< æqKb#;v\yܠ;ܛ H |-ZK^`Q;YYM>Ar$ik<*i9L|W(d{d&?c7yDeOj&7=mU%-r3-P!̴ ~!uX[c Ф`.h +i]Pc?cA<bq>0sjʈD`YK++ZXZy:pEq&CZQq^8p.Xa'~`WjnWTM`oe.nh8Y`ُIhu@1]Cic¶*Z=}O֍2ɣ֝O$Pn?y^dHl-Ǔ3s3y_gL߆rLv9p}:T$Vg}i.>a ++4k0YLe"0QO_Ӝf Yq"]sn7oj^?ٙ{^{#puDxG]hyqtUɛ%!{B_-hiՇ + *CWEHN<;!Wb6ȯs֞hC%N,t/dG]@6G׆jH $?#‰5F*E6Q# )Qw 5Ct+@IzBQݶA&t""LÞ"OP07ib.(&BtEsdG;njՅdzcZJ۫ +~N$ٷN߾H{O.xS* +@km*3-0]7+ 8dTиC +p$?fz0&Ft;NGG(# /{<D 3 ?Dt:SPw4XAmi;uxImK[3!ʱ2B&_g]uk]U$Fqz#unF 8b{[zN,9pٕ˘ +nF>J=./`]@1%{'uĒ\mf ? +(#5}ޔ#/mHZqGAi~4;Ak & +}`WJsHjIşQ B yPMIt+mF-itkV:GQaG] '$SHd+6?='~(#vmZJh%%rQwgq>stream +r9έ3%0Bx( 0&{bBk&u4wPA`<, w +3?S3n&'}fz\L9aWLV>:P!)OH|KL1n3 ;/HGK"YИ%﯂S~~l琖y+(:*;7gB cQx}saon`GW.1r3%J>yZgxh3 u"ȿ4$n{#ؿθ+i>y[PEf >ZҌaèV E ih.(3_4ivVߥ1+{&h;8a[[If˻rR4SC`>W#x˚vFt 2b2C>\/ i0* D~"ׁtd>{\$:qVlh RvApÞl\o]A'PqG؃ΊFD.:!A=Ԁxʳ;@W3 *3RF0;z(]<IkjL pȨsQȄT>5l;ʟ}^UH|ADgWtNf(; ڏyE!NhX?b1=0FX0przxGt|4dA7LZP:G"D+9_;pf8B/@YI?>9© Kbp: p7wsiY†񾝾⹀I\G` t4k`-+q4(]q/{~>#P.8އ{Naw1,L)T,F# }CvƧg)%87m>?]١kSϨyߝUi0, Injv$W:vRc֬]# +C"_ןf$cTyů}- +t\._GoV(F:,'GBp%ª"dҸOp@PIn3f{+@l#/A"5S#fd.[:~W:p8ab9~kD)aGD"X)#at10yPuACYprP÷fu}ZZ`dy(VfUrUVl5ݮw?{ c5,$bH6:D 18s%̣.R H9\V^AfJ/G6/xw]~[WtxVN Y u8 )\{qn ğBFF^,xJŔ Nš&oyd8῝]t#5N# 1S5oz!~E7=S<>2ir +q13 s"ٝU!i{s+Om \S86ЛU`TuW0u)Kw +'3`gk?E'v^WWzCq ;|*qH 3d෦ޛG8Y w=TWE53qqð?,񠁑{UIIrth N > ŽЬs|#49{MXIS+x Co$uF#1䇃 2d"}I +[_ϰQMlAt$™﹨}t%w#qF:AɅvt)ksgw-tA{->@# A d0D_IDՖ>E$> +2Zg?gf+>TPz~BGjRWnђ.j7X Y;RLp|&i=/ +5d5}K}fڋqRb߿z_Ûme=#'gI_hNmXq!Ff!ԋ$-IBqx_TU]z2d|L/,I>1 S?gra~~N>.= > GO,LTfo/}dF3. w<``Վ(IX? +>ɝoZg<TPRF^e+SnkTSy"\y,3Br{IGM[cZY]ľMrbM ]B5X8ң ᣯ$1>3E 9Bl}QQRQ^9v7YO~<Ď0@ +h1A`w/ GFԻH! 5lypBه#_RA FPї{4؝qxoɒt1Lz'&:řU.TA?]&P +k_>79. +vCύCԋG5 aApuX: }陖q$cń9監L|*v^Y`cEܞ@,}0ϻ"NͥRvɸ p0ydA?-3ܩ]@KNxJbRĽ9SuȲL\ΡG] dZn# `~1~wɁ?4"wwPsH39X55b6;Crm"(LUA;$4 r},k0 d{8HA+#h~laǜ}v^FǨ L1|D.3ʖ+0yW/rX#l!αW*#%b}S;ތ n DA , $np8v9h9!B1hi so]/r`eEi=M:,4'_Ȇ5qQf@zʟ Upw_*O0 E:m~m%nG2w18-˞.Ц +`(.K v@~%iE0?y#t/kS6r_Ƞqmא-#.3Qݤ.o7Q&ϡPZQ4@jfu?J@`WYnzt K^wr6DZ}f}J /IB2fNyZ!<,?tO+!s#0[igG>H :b"S[l¥ˈQ@tA&z@8žnܡ@f|lҰyB9 +%ʀD +,tOnHݵb?jTϒ#)v>a cD(QRaI<\!QK+LKGpy`p +jݛ}1#EӨxZs-D!.u.AeH=|qUK9JA\O:5qIp~OTg $? 3$ւ3F÷RTpXvlK%ϸk40bm{s=9# 5w| />4Js%RcƗDRQӦT9 '!8h(D })n$(J!&yyLII{ +6I\n~1Ð (v; + ͈̉=̜@ZbI +N rz7M Ywaxf`D;=ً.o#9&+{0ٯ؉-?Wuϖ<:9A)AxK`uϱ5r:gu1O i_Zͧ +M^{[owZ~p#%PRFDq_=)=YItFNϗ[~f)"lb'0I>ˡ!`]8<3 P8mp}% ™I Ld +5x)#:;A;Ӌ:ˈ.eN6(Datdyrcתr?Sdx,UfՇ+.Bj1)eݣ$9W*]IUn(l`&#agE)$Z,)t~ 1N׺!jM* WGE{̽>dA>C6 <*0.-)İmsv2r(v[0&+ABWĉF9/(vߑW@mћi m7)Ťk9nf[oH;ef*lʂ)bw7* eEgYR>=:ܠ3T3*0jo&cxi|zOl9wTHُFN/K +PM,w7:H#v` +dW(gC74F2~1eFA`H&bUVዄ&Xo/|̗"ort+ZS $ ˿-9#B?f!>tqƳV.i Ni "*ŻA T>' +] W+Z%@a^+01CuaDuFGs(?񎺯\tY9qUX +KA K;PcN5ȕ +e\1{~`bU!׫=dT5,K7,; + ZKRU[ saY$-t Dʷq>xq zR2X:tG-VtWFu*>O#qi>]x{ Hv,bګs0-˕ m} +6b `6O|`}4XW|:n-4H!ho)g/IpgjڐD%ˀ4)tLqc('QjԱ.8hA鷅K櫌D!)E}V,D,JUĊn>=3?>g|E17ٺ`Yxbkh9Д]Q,c's%u}j#i%buQ<^ǟ>|l^2ŒmشGn" dc`T074S:Ni-y +x'ͣijUW҈ +p? <@=JL=DXdPS9epOOīLLQX$ˍ:x ӯ5a!J|$rZ1k*\j֜|e"]-KBC缯RE.>WewElhOV +VUg],Uzci?GPs޵,"2_ypٞ<r4v];"[~"I K*+$6Y$8fS%&jЄCe:K$J.~77†g(G{CspCq8WV>4\`|z04̴'qT@cU U|Ļx,i@_İ\~A! R) J:`KX*%\M<wfgG 0aQWZ+@bXra6 }t+\l+&3Q,b| Pp=0S$YU Y|M"Z3g=&M A%1xΩTz H=khQ ҆gyMJqWN4Z#̬`=m0ۿ.gF +$\uՁ;N*gNL?=rVw$ +E(7;nHh{JaL#fF.ץU ‡Luє?pZ ~rT: ذA鋭1$ibľpfpZӜhLus!ʏfX\. aI]׫?lm"TJe5͕Lqv7I} zd޿.{=&w "JY4mDTgTgU:wӥ01ѧalh;/-)<4;}N'ӾQTcMs/xeqQX/U)pF@ZҰF؁XyuKVVk31qWw1MFr_kh|"PvA/02)Y  U# a 2ͯ4rx<+ir{ByAA`e&-Z!e9JxI3_r 15n,~`e[rQ5xi$"fEP:(4XͨIFi y \V˗啥E?ȃ M8D83$02)8gq'"/pؽ&<稡Ti#peQc AE]~zvJ܋73[l>H\+ZH%aĂgM)ZъkŬ sAV-Qlyا}_[\ۢ9y{BiLsBȼiDri0m̠da-܂a hK=fR!;)be-#C]"kQ8R(YB| 2>]V f J7c3S05HyNU.T<ܳgJK-`z+m H_#aƎZ8pgncgIٿ.ނz gڃ@`zc3sa + 40^&%@ )2yhM! d Q1@=*twr!-pM G|f"*R#WFۚ=i mD7," +M+c}^^l Vr|wUHԱ(lJfہ +Qm N<,Q@ o5N R8{ږF%B,̕.qhxRq[+1Y: iu(TyaQ|X|?I:Pw,?xLWȑO6{JMqW14?(=3:=y o9Hޫy)"[S~O8 sn3l(2, +o3^oCfjnG)=2tGɦX,{='e伾x.E!\pƨr3Xm&d+VbS 2,ޤfeMp|#HjeF;H(fW嚑hD`} |-4iz3fP-[KFxPƎ/4`]7Ǒ+w`P)=ԄzP u"Cư):Uhv!)g:W*U LeBCo.׉(cd jʎf⸗`h-t֓F ĤW8 —uGgRpH"N׏[PnQd~=Wiy +/l4"+ƴKa+yf6kJ'2>@nܚr/r%НAN.PĈMD\]RtZgBB +`NCHϚi}3zJZL &ۯM )m"2{.Ci+Oa;'I_o b$w\~b㐞$4?_'gs,"qWfB#V%Nj2$ɏzIX1 +{"൹FidIKӣTPx,= +y`{,-B-nZM`#{żLdq!/ybr;j3È~Cx'R:ӝoK7[IamU O͇~5AV*t%`-{8zT#g0ow(/dj|is_ ]thZ 6 N2zt +J[R8'͕F+{v`(qqѴ'[bW1d7w_(my ^If:uQHU"%þ€ t>kpx*:T +ptqk^uۋlh1"% RC +Le?2Z"d *Z:?\I :ZoF;:W65K-@&ΓJ;T`П,ai`Ls>~C-h|o Y=.\/W숭+̮7GT" iy%JWVҰOLSS+ec N@y!"|}{0 y̜9YwY07f0V{i}#WWJK_%/-D{P^ __}/S%.iܨI uL(gD *we tf4X[EF(]oPEؒ26R;F&}@vyNġ5%w +tBuHkQiN|w)IiáRJ.$m*:EhuC )/:G*Ժ|z\fណ||g""kRHtJDKs5oܘ)gdxB +avX)I_zݎjSѢW:ĄT'2):\k::dA Y,&;:?kokng_wt",$H'IK0d0Y|5>kN$ @8{՘_k#P6YyƑMe5AU hWf!!"Vw=.Ocܬ+I.Լ| ::Ee E>coQ[Y.v{Xt`#"TaIcƂ";ŬفfM;[F(_(97sA7 +[ck:"@ov9:-siOv"raGbE"ШI.{WQ#fƓr#$HT3S6~#0^:̈,4  +M7P=ocv,A#Aw# +̮ghUya W6Vge2:t;b{Ple{VVK;b*e}>;U/Gk^Y vl5Qmv]1y;O{NJ$G~a#B1Ys ښ [ +aRAV` W9! ,LmdϟPM +%9cRjP Bpk5ۚ+ZGb[FHjCܪ^!LԌr!Sz{P~ +y\ɜ8{=PXD +Q4! 2՞G{DnX+}?vJQ,`|i\SZlkϝB &ePLYBfS>E<\G+j"/[s> +hUh9>Dp 1 زt֭\ a$*@S%P?kG?gMڑƌ4 " +5~fMXw3; +~QID!{Ve«D4v>;Jtu\ilNmm?;}5a?WhFeDbis[zhqiOuhH9XvvN"rۼcIWɟ?=%vfmA3F@OG~CS f>C^Bevy)FQtGA`-wA#"jgq1^ER Џ5TFr-5(zxjj1sAy2_MԵisj=ICm:N9I*8!d=@nv*DEGVzm LR8l#Xz#M3vA 0p|׶ fܽ9ql8^¯~x p,yրB]~x~f<1ae P`:6HkfCllq8^s}΢bKR{댳o ZNV,jzv\few{MLbkvޚᇈ_Vc5#q8a^Ltw05G rE)'D_A;* +"s%`Q4 cq,0T +GȈou$ٲ{KV ]u}IwQAcYRE8`sQ^Fk]7(֑hN솠qI~ȑj={ϱل7+{0Ѯw%O\@ٔٛ:wGL?ڂtO;5Z _4Ђ.wTNٮjDllHVuXn+L6ũ9PE9xJ[y.ޡ)N- %K# ,5*Ŝa-wnHkЅn»F1@|WQ؍F\3!v`!vǯ *_R():=0[`Fa];pMt7JnvF8r6 =lOOrf~*4J97mư3Tb}1h_vC#>oAHՏY@ U>>Ú8vwƿBh~`etAʅUb<,$uOޅP0nD:ٝD Qei"Ӻ`--fjm{a[ .DF DmX `QM@ vňF(IE Dyph-b?4GĎ:1!Z4᪣Er$g9=FwrD 5꼌Ҁ5 +d#n;}>iؓG `nqq| U FhEzI ZˡG*Zhsv'(Jg˼1k;_B2fjEPw3/_ +ixq̸x3Zm񭀥jLوRwH[ @ 9P !1Zͨᳫg/M, @zIHi3s|{'#>00'~3+Lmg|4!J4T3)P͘rTt4)J!Ujejw:X."-u"rZHĥa{F&ED d,!f8eoY NSNWoOǕYh}vQjj09`!^cTnwו鸤 +zk?G~X[4KϱcD܏;Qhհ2#Jٔ %3Z.聪S=ʈoP9#“}9b.T{̋S菪. |:(f(@bX2l&s =qd! x YݜHz#wzS阯J,u{3A/Q5h|+kHy܍tp6JD{\ٗ\O".&S1"vA*p">AuDdSF3]R"R' {t*& 'R}Z@ +P*)P)@oύQ'"!L0L(Dj1IFNbx~n6Q?s[T߱ Lڽ]Iђzo>r5oz:#@7lI5u +#X=mcUѻ̷51քU +ۺY2oG@H͐Pn4B;-6m؝@nNGÈ:=EĦA9di +2R0zQ-IY`iNV%#V:$2ǍEACtx6ql)`n˒4yEx*j5=aďT}{)_յ[uYE ^g(){&V{4P"5j[2)dQhaVfZfI!ݸ9ѣ9 gMoZe>,7k8s%U` =Q' p)Ǒ>i1Azk&b8Jt+__TʀoK}R^dch k}2Jvm,20#*Py\mLr+m8$Ll4aOf)جvn`zFqH#h_8 B'S'm7g{ADśW5H]ڭ0= k]'-= c"rpt=#aV!\GPs_$`<^d*^4Ea#_I\uEŵ\+}8uu͑=r8myf3*g=N[IB_{fT;! )ϦL][-xuHESwD=Ŕ; + 5WV^N\1mugfy ]9r#NX"1:BԳ+T> t?l-q2wM3崙h)`tqu{L;v{#UJWXKW^xd.!Aj!.ӤD{49RhCDzyׁTb >vf䧀JKr y_[˧G誋D +)mRJ*~5|ZTR&`FҨuVsSbӨx`Hyޡmfܸ" u#bap{⸾=pI? 1S<5PQ?Qnnu|WXk:aHD$Uzd_cA طdNwb@aJlqѧkRZ. CC_{+FL|vy4;̀<@'-CWiB𰁉oh)` +w-ρޢ!OgH7';AED S[5М=" 5}L'$~hRu12BV*SHߢ+sJ^A)dVo#ox>r|yU] 7pprjWoߣFܕ;Gf;LG+#Rs ="wVI+u!3Qvϻv~w~fQ]rԮ4Fo^Hxd1bGDž$X^\%ߢަM{IquhLliɴ❈/nj1pjw;0GYxᒕM?8}s +>&eBooHrQ31ѡS!/?&g~_ߋf jf3. +WQe1Ѓ~F+.5څ)|@ 9TJwڦĵ6IN Z8 @fͪ 0[JDy d&DP~Y/7.L΃]wA-= drV; o[Ԛ߱\m)纂IZ'& ӯh@Xʅ5a qV,֥޺M4%6~8ų̲ޑ93Lrj5Wr9uڴViK=j dPʚe>3 59靮IоmER8K<SbȽFhlOጢFaNXGiv-ZjilGԔ]t4:ۍ*և=Z-^:ROVΌ޼X)i=JJe- MKY1=t`Nְ*/ +gWڭ;>RxIŹD+p'YrF 5f5 +ғAZP5:ЬmW`ߑVIGMs۹BFEaQgzZWGVE!kYx(8[p?e +FLTQ\am!,5בSfU@^S^#mUAovӕ"Y%ZTGYjO p\zl-."xA_O'~,izO3L#n ^&xuz*h7\杤j2k#;HI9u+ +OB6=xDWDkAAwE][h*Cǻ0Q/[T`c-u +Gg"e;J"jE]E_t-L(01 ebN= FICMshfJ`kÚhnG~6Q֚m?:AlfEo2ҼGopƻxU3SXU{9|mmQm|LgE68!H8"DM-P/{Fiϝ}{tΙM +F5={4+Z1ƈ,0a,Q:a0Dv |â߷_'۷ '>"\XGyZ EM!Qۅ}T*a˽,y%k z@T쁫h. J} GprvY`FR8c+FFbշڈ7'XSX 1.[s.H@ + T1 (9WR+82 VsSx+cq mcS +*Q +K@ nd'L+FK `02nfHt3ۮԭץ=?hֹc=̐_[]'n7ZHo]TcJ:UFD$Z =w[a*7*. B] +գxK-ݲɦ{dӷ 75oAk +#B[+,?*(~Pn51^f-l0,}+*Rȁz+-0wfkk "VjS!&< ^F=hຈڏw~j5SȏD2-$fFMƎ&DX]Җu1ϡ1|쑞J.": u;CGPh޳aAixݹfX%d^> ~tYlw/q_k쫉쎵.JBPۧ^tlX+#?iI[*75w$T+FQl54](z9r!"oRFb"6t10=z.jy#*&qʞH`KZT`]cgW  b4TdxUt х}к&~I"uEM_sd\ oѴƒӇlAY +YpxMģӔwdwڸ z |E79κH_Hk]zؘRa܈ܨ׊#0X1SZ$uUt0Z_>mpTU+.,g=KΊ}ps'Ɩ}GۨNZJfbM_`{VR%$d*gX<"pǗ}qR^P$I&ۗ%qmk* &m#<ύ 4U"ZKOܺU.2LB_qms$,H˳3mrDfD\XkCO 6RξJ=8@C8FNyjU5aٲD@fvGCD csAÅ99%7*;esj]O/-Z̰zgh侣5S.U n̜q!tO~_t46yu6D)qG[7^(6j54 +\~e?U_]`L KTw=ITi\@I1Zr`'׵>׹q1)6}M踒wP E^7p_6AtzaXuUbԔkԔ`kLؔ@*SX'ʈryRPtq^ :un(ح(ԏg7 +hp[j_?0~^\MzVn 0__j!#"4x^TglQr GHwڽ hjT4dXjߞ@ +\?|>Sʑ5q"u@.Bd?TwiwDm[fذY<3qBHˏOiY_m6(ϑnC[Pxj6-yXB(1Ϲ^0M(u2Qa '[v1L~T 0XMGVÅ +G8z.C=fBe6S.$9Ɗpݶc)߀V[.L<xgՎ9F@P]f2vq0U.ְֱ;u luޯ,\0{ܻ,["FD +yNdx4KnA-Py+>)"IgGv cE-i yHxh9l}qb[w?\_RA{ӡZ1Yuth/0oPt[}WdXhv VRQļ (kwIG<̬ٚWەBt+~AbO + Ϣfy 0hAe@U0UKSe_{;=Œu#J`b%.EQǖaLWʧbkB.WS0BKDZю0"Pr$jMT. JM6F $ 0JtQ/Bg.Bk +udE47,yKVvsDgfÁ(xE1t+~g\e[Ja=2 OJ)>OMBSr1#OZyfKpG~d[ R>skbj>2/ +CbӚGH6#8Wh efV^,HU,χR6& קYG?]7cb,%^Lm|Hut @LvݵPcfTުN#q.oײַkc`ȟj=%y~jWBtBO%m 3{YR^=ނ&_=H\2x9uO?C@Ͳ8疋 pMEfs#5Qyy||<ǻ \(];*÷ U=R׫@nR!hUqƣ#,lf[@-x4&n@]S}{l)2 ]P[傰pe=Qn(qB'SJ*mGjd񐸮=[2]QnY~r:IJٶ7jԼN J_f;ڤd^R)ڝIzWl@BN;2_mn2)wQlj{{VtypEO*+-)ZvU .vMQHҪ&u+i%F5iw78嬈KȉS\TOOn s^vhQaXӺg3rT YwJ?3އ]Hص m3CQ:(b)DUongJN)hsF3L# wIS u@x,&<Sq?%\ ٫zf^O5[v&oduFu#޼~DMMA*ě +q-UA~<8s;e0g{Jef9$z +VeN#T8џϑ>s-sfmhnoivH3Yeql kV4~w!„J+oi75X^v9;2A9A l kmZwX 4ʁPn6_'ӋAAr99՝] pOibPKvuDޞl {)ȫ(׌Qf"bvbXPHy.[%|5 &bFZ.(_cbm!>% BikJ c6"FR7 Wq]i `EٞCx}DNUweGբX\}NЬm.?-5͑Pv`a7D&Td dp**` EQs[//-iwЌMF)Z>#H!|CؐЍlS`VIVϧ0п} +Ꭿ&iuNT?)w岣F*YuKNAN/cu NI@OŹgx=3mY8R|<3:]e!UZ̓GQ uOi +FZdPP0{Cun/X•󇠴ԧ61JcD502df@!} nm_n괾4Fd$wjAzNa@H+I$1hzD*^;)ңcm%..'q˙7BygB|x۽jtn酅Uks9 +h f^TZ*bi#HrhľHI~7"#*L fTXVXKsiU@ gۅYa*V35 +cKj{g( &ImVfV}\8|ظ1 d jvNrSM.|LLmtDJ􎷱؃*ls&[Ck>t%Kܚ6KY(AFY=EtJ䑞H2d6~3;4z'`uj`uXm$W*YI۬cj]aIF4(Dn@u-a{[<#4Gļp$GzMnJ"Qi%CTF +t?fd4?|ğ/gŤ>khk߀(3OMnRshwwvPQuTÔBa+NcA[; +ʩFgc{Cp8~,c3fjG/4(N/B٦"d~<-9RȠV6F>p"P FESm|dJ nf-1aQ oU&3D 2N|H0ui6P2HgH)iF]ۘLҤN:~oM|n)͐^7rEœ<4X>>cFb\/+{1ܖg#x7]fXŦgX\^~%AѨ>,&D] +w#)>#yT SՔ-;{j*6e &炎t}[WrSԃg.I5u5onnPP4o8sl%aQR!kq)eQSy Ҩ~˔o!,XU[+w)gPddA/(5 (҄DAuzl/%OAMWJUiN!mӑ.tEf +3fUVknUBGuU:ar1z~an A` ' ׺F[H}n" 3BIN@B׳@RbWZNIЭC#)4SY`;]EjD#\Q\7NV,ЩFC2xAoT QTF +uk>2\ߡwͪ^Mg}vd%ew47br߉X(l}t<^o@-.4št4B'mKOk#d oUucx!S[,a&kˎ`\[3l%1Cm~n-0CTJ%dj-){gwch4FL'?_쎡R;l#ep,}ցL"9DFx=i׹m +9Eڽ)P +nQPPEM Hq &JJrh QAw(;zL S"30 ++IqnBK~: kcvUS5-o~w|I`)%2u!{ot #/颺'㽆r 2^'XR֞Lt~'gόn̅޴ϫ0*cnѤ2 +b#0YE{sCoN)) 3a^8Xy2g~umG +??ZL@:<`XG_WZ5,g{HYZޏ0=2!zDU+YYr2 s "JKw+Vx'NmUJ]j*]e4Y*/ +iѯ}^E+)۔ewLRLi 5iVvB'4R2DN5gͧ [̼ː)2MTS;@!¹[yE*Vg/s!xEG!"AT? ÅT"pʕ]&G$}՜F@' +ǽŎS-w# p_S3%F^S#"H݉8yP̝w:HX@]ze!&ҳz5ԣ57-]2CA\HO"="RVyr؟SS+Ë~^9̥)SOq?q':E& 3 /- G~CTYca}?)2nkH6rPx w#xCkc輶0ԕ= ]Q.jn4UUCyT w/Eu*>å]:Qk WuuR݁z]Ě˕WF$LRe# G|tR4êE+muھ7@!bTokG{Ա?Lf}$c%~m4UKuoy]vFi}? =!uFa{Pk6Aqx<_ߢ^qQVi9]9,BQ9҅} uֵ+4|<m l!DF伿 tS,\&L#1~l>L %',* +GZY߽Ue\ƒ)i೬m+5AUA$+L+\@jt5!Z?Rfpc`Sk4 Z6r>v\64H=V?qajU5j+{6~Dh0h`@@)-4@<vD:q托( bŜfꖑ_\s$%GZyN@>0RTd@dYB_lNltc+M3e{-D5" s:ULOc zEDqAbFgMn`-/ʻQk+ + 娰)+/sv o8{7u&^N;ʗ@]AS;qR1O*WpoO:Z +y;f7ct +(H&6>?\En(Ǜu1["o @#]{"'H5KeĠ:P*u UjDρ(RP$Tֿ05WyaB7W?Kkd=.nW*{ĵGݨnIK<{?2p@u5ttF*ODl[{_ l+v`\l+ hۇev/ A߮KG/@.gnZB +DWwe[gfs:[Y#ȅ w7+Och &5\ @TWVT2 4Z@דiiiaR֩Rj #~s>|k?{2H#DTۈĞ6%c<Ǯ!o^?&:w2u*OFج?t?]h4U2&tDm$T$ c +Qʞv/TD+aTRWZw~XW\G(? 7d=HvЪ2qx8^[2j/9QcfEU32"A=b+\1{ 1A*4R-WȈ_t2pv; YQ ⤑ygeQ4睓–qZ(!N{U/OQT50j?ٴZcj*H$ sE"úP[$xR'@Gu&#rZpDza?*hCϢo>X\fQxJdž(6dM3Y45@)̝ b+1C1 1 9㈋]@=]~"0p.eR7}sIe\4Yψd-ۑ,Zɏ榞yWSgDcrW ?qGԱJB[n=Q~Q)ncI4jW)ax:%J gr.@#Q-""v֘r 4/kl-P-bLCuegNy+">ngDX5?-5@V`dE3 JA-E +MA9[ '@cf٧@-!(W`z=QvEhURxƮ/fd`,GR'0vёKɑ +YDC wQ^9#9AmP!E; +̢1s#+2_vNz*}l!D4W\`,$AuDRbHY 1x᭤f؝Xn#gfwWDk>Jtmd9x}׺0B)ZC + .(58A>0Pb'͌G{eXR$?1{m:?AZm²Rj~? ֍m~W6(2\⎪3E[*owsB(uת鍝'l)ʩ6qͮs0eJX9z؂OlxtĖ)[+­HB.Mz4Ѥػj%Cz50\ZCŷ&g(bV iP\ȉF `QT$0'AȖǣ_CMRm"t|GT \ UuT bD#+LQ0LT7&TňC J8 ͓Sz3i6MycՄ6,V0!:sT98@o9rVDnm~}]u}IApX52r^ +@auMȣާ$#CRXX#St{uj  ~.CJQB~΀1xRho*K'y56ܾm'%~Pc*?zfrGM/x#qڏW"#zؾg,Ó+5JfhS•E:-X$LI;4i:l`)(\~= ŵ UMmMH!ӠZTOD+3^tSQ=On~*{8|e'NIg*  u*-898)({ڹAܬ_DgsMeX+ۭ^Fw="'8۷ +^iz|^lHQڦ~@Q a{;~K6 +n0tElr7JX=6'OylZaW[c *Hk += = aPjH ]QS".VW|6UVhs[{2 Vo^3fV7g;}x('΍J{K)ZؒTljx%r\.Ms_9{x`Sqpǽ秫]Me)IHᏭFV>93B7.. 扐[ +92| 1Sm֫dhoQ^FQgplpFގB$z(5q7B;|K,,Oh#-*EK@ArD`ͻ;jaό_8m-yIɋ3_ aՇƮUW]Nn_"66,j;+(|O-Z9.M^#y{g"|"JkoGD 6&2""KL֤wHp7EۊA׌ZѠoG:>~5ot -C\=Th-IdKSՓW hf?qD͙@)@3/Th6(ĆҀ]I*J=¥1%TLLTc׳};Tu۲o188]5;4(cXp{J-Ђ +o7NH2K碑eB"hE;>/ ؓGrwvsWʏo__/?͟[?ȡ>ǿowww8:_'7,',B+o}Hk"tQH4Ïq=R=ex%uv㎠g񧇴lq΋+ +h +w6V,UOr`oŀN`GlIiWyC2[/6XPp&STw3YMYjkޕe2Yn6?fin.&)kT 2QrէK][UL\9 A#QFIO !ۖؽ *@«;NEُ|ړaXMi丈uFI7,Ԩ-bt{wT;,z { +R}B5 |܂JNmϠ Ƒ1&^=vZ -͟[ņ5_ @6iϵ$)ʤItDo/Vo `8'Xh]෷1 +ݹAKit46l+y6-U~V G!+B+@# jq m [2~n}_HN'@ +%D!6',. +T!̧ȍF9dQtՖZ'f],%\*k4=>GP_Gpf)'wl|esdADT]Yo-6yyȮmE26d9*5fv +V+[OmkhFlQ=ƮP!7% jD;ѧCTo假s(3#r?ue N4]7^TF +C3:"h#Y셊7=lw.ϳ2]XkhP#Zi)8L"},,֨|OFe.MP5xkGMGPH31EW/i1e}QGiPrn?/TSTx pNəts|鑩$/p*.YL-S14 +|#* *PqYIB|d:P {4x.ˀF@,zIl?7d6Ѿd- AЁ!ѵ]opEն նO$;G)ȅ8fغQ7"[]ЮqwZX¯}"}>(DN޲Rj*KZqGs%%nNg5#NF%T7܏h7Opg0/`5:׮/^)+Gc~CziH0Ƭ1<:nQ8(lVT[Nh q}ֿt-[EĥQL:=˜fޡ'q,,>^ݶs%_tn1^ԩlGAqm H'Ke)ڹem[kvU K6k#Z&^?X02S!R Q`oB:~5E<PǤ\_$VY;{6ψFAY9'k#}h1]GLk@D)V(qpٮ#8d.ɒqK#I-c{g^xl`4QM?)SN?s_됛F$ׯ_$$5 +>~ #hHKo9H58Д|4!cJgF%11xf ,}5TT\ӷ":dU/zv8i`QrjV-}ZbS6꺩#p;O9Qv]Bye.)krc".&Nx6+~}ړ=+.1M3FNSSNk$P{' 3i:U*K;ˣSTaE辝׷Cma#HC^b"/F̌Q+58VTq=D +ٔ,Or-t2PLff1`q)=i>ׁ"ԤBgD!]b&yKĭuRSE]W2Nh>&6p3rGqxx_n$! +scks%k1q~:_GzG82MH L:"2Gk}EfWsM}=5YnE +c}υ> q(>B`+0c-{DSۆ+U-{Ckzc Bc _"M1,|Jk4j%] + Rf635U~F;p>l*纂W jOhivFEg4=>:)ADN5v2߼Cw!y -ޓ64hUG(DgiZ iMNAE@ Qnz׌6L{pbH+v*@َ Ũi@P:ȁm}EɐJ^r;,*ZT$ᯊ׊Yڤ_5[D*~UET9(%&ޣ؉{,Aeu@&R=ow}=e(Әm?4"Jލ51]@G^1)y:ߣT0R޶oOlS6@L.mIu.AAٿMU vվGثw 'oй?PMq_J~ A`?jHR>9L,tZ4DK[!cqQZd'Y:|ߙJ 3}4FWpl^בC}+AfXgQcc^Ppy\^c |ca,v5F6ҙ mFIta=r2[{fYL?/&,#`yL+87)@lPPweVwg)P {4ٕ]]].eF7O k%U84h#.Y'mn3UE 2؃ǒ:0)Dn$ za֯RWX]ڣ1U1e@>zMׁkVY)7QRj~W,^#OWx8IIZ@on)d-*R6r}p@88[vy6nIQ%Aĝ;yUbo8(ֆ +6R&!->,>v5`|?UQ<@꼺'E6ian^ 8PH?~ևur ϩz@vA 6R˶"t(U'x^Uek龔.ay~K~ 7TA.,IiUm)R$> *H 2Qz{q[(p̃0eI3|LJ>2LIAAZKeq +蔰Oo[X=[;ik͐V6Ip,dŅFNV# @aIt;uFK$  W85}$CX\ay]\P +-آfV9Oӱp&u EHh@*t8\u9gqkuS*Qb:tjDd+ͽYÕF걃lW]b+GٿsMiеQš%^ H[_]RC|Ml)QNyhGTf&F?h(詆TU7=@ޜ7K.`%KkȨﺨXд~&ycme^O_sv ,@!Sn>s*{LRїdҥŒC*e?JB'8_Yn(6Tpb8ln. db6[*u_+< +zɛ"uuxܬ:+c>5"}bS-]?iAI\$U!a 7L([1vPuyE*ˁp52wJ& 1.3?aՋ׹dydVTNY$D@ězyN4f0L`+{7܌cc;Gc{Ew>%*Рyq=! ,Zzu>hKy4OGUJo2(CkA!OFΡ7VhAfj`NȚ"\ QHU[_M$6"͈}/^!g5";Z]/RICUy+ޮ8(0eR^ȗQ6MdtlPFܳí2rCCFtDp +fS9l]lu^ȟh7. +h"uĵRJ! a@E +̲.8?xy\=(!2Bq2J'4P(pAt ̈9x sYSq}6@ $PruL1(5!oPh;[FM ƿ(lArn+͠ UUbti(zR$([G0W8~6J%`$Ur' gr}ȕF ՝_%q뢽n~U.(p`#7<ɠ;GR+wNr`A,gi.:Ih$2rG0hK|9pv5>|OexẠ{ Ҩ;ra՜9Ä'U)pcR`Ϲ^ +ўa2XJtMτH(  +GjtaꖕeΖ4V3\M&ɣe\qa?畮di!A79= (.\K{瀒hԀA|C& M!x ~-,><_weel-4  '@@ZUG*] D{ʹ#PM=EV@AI^4(j.v/$l'KV7Յm(;^&heW5o/Eha)^N; $,N5? Z IED]_rR +(8A]duhbX5i"uҨ + ia1%fWE_d%鋄@4U(׿{-Upۇ6 bP q8v1K&l ^F#aV%vdKHݔ +(|NO @IgKY&VE +C$&M6] cc rg(\?712uO T灰ŹfRx\KNQ̊J/j< o$uL]@9ʐRp¡$=,(Uk}lk'JmeˠJZS' f+f>E6 d4fk<9T}x:XS+`i)%UӞB̋g :-I]*JΖ/^6Z ]ItP?%,򓠰W?ȳw!SEs$C`]>CN>IB(bA# +LJ1B +3:d&=%aG\>bf|ӗgs8eVe7iMvhCCsE~yjbe{F)VQ76 G,ȴE<$kSC.s +cQ#+ɒgEbCK-^lPk`4@luבvɴNw0=I'11HKY&!t`wSvh@ iut 8.uD'[>j=h0FHF߄dsmS~sΜH.iVXΫտ H#t_F$[ǨgUtol&k7ULC~R/nЀ"vib\; +)NKG9`ڑ񵜬uIL&lqAJpx"2FvRv`u/u[>E, +!Z: 1i0g鵼`e28Dq8׾h&V}Mo c׊GM hqRB H +h+ }Sb}RWOW2H%40J/K78-N#ۈ*," CT"P;Eu 6J5] v΢~AD PҊ7O>k@$hCJm7DZoǩy D,n*H0$ WK*I4`EsJЪVD AG],x H +!?<4&Qޭ}u?cQho qCV7qx^E=U(UjX7sL9!>gauA +7)rH!֎(65agD4fTD%0=A/_Y%Q߿Dž#b>q؏&ETDRs5X OpGlB>d+ɵ!XQtzgt>#Hw Bdl&E(.ܮ#,7'8Q@E6*'<M#``,$Y(F;A'o0)tWW!Ny>( s +P<ꋑg% +Oئ{Saa$$)AUKؠV;l,:Crn5'Յ`KpOy4ICu1I{^e6>e_9D;)<]zMLN?F>""E"WR:GK_9Ae;}Rr`Cp c( +lM}0Hѳ7D0Phw^D3[,>e\JVpbd kpF7ɒlīsq iй),!.+A.e J . +$C9ܲr6혨S SnDAOx!W9~5VcPAkb>1/ +U3U~D*7((+S:.$&+}IQx7Q@.r}{o1,7xF Q"u +( ;C<"qJ\ =z8{(+KE>[OCRfm/a?t:u>= Eؙâ[8RI{N9_"K{5@-PTpBVz +Ҝ!#1tQi:ʝtVJGv!+pگ@\ڤ*2ؕ0X:ODW9a.}uH.TPuuXu 4\#nHV6|.˗: ^- eB39$$ecDPJ b{t 8 +oԎd`@SpgMЫ:Z!;J +dnaJHYL(UY m(:BG˥ rD2Js"6K `Gz +/4>n!NALlLtT^Q1h^*= "pF9U $Rhv} շ.CE4T->D1eQ SLu)a04yjRq>w p W'Vuf оLUjQYa4p<]eY^/'Kg8z]En^?f(ɟ]xl2R&X?>$4t;P@,F%htm@x +(y1;Z &K/NM p>ؖ_ XPU]R*h\;C($c艡Q&|Ay\\pGo +e=V}dкWtuNɊNyQ)cyY݉D]PMڒ0>fGQϡ#I2(y(t U請BBƧO, +:Ghk˰^J9e4ƧP:y:tPQǤ[L}54D˭ Ι(|f6M̸+bݓ$V醰z-+﬿IE193x'EsCkyL%^\'FB=GT?Dg2XԨš(8&]h7hʝ'(Hisx(V!ǔ8)?[$ћ808?\ձI p@qEw۹dWc_ώ0*$sj"(-zj$q]|9̇e)ihn#\W:zTͲK$q ']U=FR^OMwn e!L< D\~>%ɑLq2_ϱV팰 zh_&PFT U%RǃC`ݝ?͠~3!2[t` lrrg$ycꐴ-S[듔;v@خ;v~7}A ZܕCP8,(Nt-B:^@8RQ,ʌ&# ƈ|MNe@Q/z~|3 ԯERDBzalD쪕Wŕӿ&Fz}ĺlveZh /p$bYȈyE5?K*&fX(gԽ>'5_Uۢ^NGe\P*TBqQQgǓs/m`lʋO}0:tT"<^˚csf;Aʬ͟}h]Sgn$ʀIm*`Ww9crCnrkN'RlWt6f%;@Pfټ4E+ Ԣ6 GJƸ#<1p%\~"`ǡ#n^Ly5 1Q_eR,q_sQ!=\G%%xSx}6 +5 ~T$ɖbY!s}|PHnvsjeJB)`VSZi.``:XoYYTaG\aD~t# "W^PF꽐 wL0jDEsiҘE,= ҵfDQ q)D> +fRI,exK(U\IN,`/"?zLiJ7OJIW~'^ha16| Q֖%J^B҉/D .px0A.ck,[oCNDD"0Ji-_к@'iCtIOvG!OC*E}!zCt}R,2? 9 Rndsu"BTiMJ2lp7:J \q]0FH4MfG4W. jtGVډuٛZ~ AiK36(D#1wM20h.B e~H« +͙A1֠ohIJu?qJ\9e-\k-{#ʺM%[\WI#6X'ev ~ԳhXy;'63I`eYG1yY9 u>c 2 qu}TT`

gב&gP`bHu7(*L#$!]tAJ+TE'=, 84Ty@$jD,r#kFc7E+vʥC"WDȖVl8; AL ǐ$Sk`˦< _PEpO7ŃFy\k{8"wO*I@UӓzHy}G8 2!]AREE3=mc;_!?ZUv(1ltm.ؼȾְE)r 9?7p&|HQM@a% lDKa7zAyrHlCy<ІX\dNh $j\ m*SiR &/$pGb {_v$ '~ɽfAI"1m?iw]xdR +vN2d!/rCR[U#TM?͐H{K#E9OEK {~`w:~,$ UAj#Ap?|>4bUĶ'Բtݿ IbEE>D ۨ/g`2ERӥ)ښeGc|VI2|Σ.kK|D\\QQG9 TSYIOPr;_!J+R{^U>®&#bN'4yobC/R[zR. /k;vMonn4bc>«=E?N<{ĞQ Uq0P +"{'F#T $XjRy\7-sT觷Fsp|4@65R2*E # $ cds  CJa\w}C_$8Yj 9&LJt5}S> i #3K}|>>ra R.2쐪4BFHXw~)J{v+/ju[Jy!MR"kR" @RE@H~n#)>''6Dz9&(8Te?/j:s cS9 :A +$~!7ZWx\eo(T|?Ci'p'IʂK7)*$9  F Lڇd"Jez AlOl~ΎqAhV/e<(`$QE4w E!i>Bµ`9ȖuF - 6Ox="?.Xb_p\H-FG*O;G?r-0 ;L7#<=*bwD33;Q& 8<,gQjkUm l=?HIRE LYF %FXvM UyB?(@(oHeٔ=ʽ:Y 4r RZ6T4ؠ=$[ĕmObX9%{;KQ,w0g}㱇gͮ֐*)Kϡx⤼TP݁Ils}uTsNDrAP` 1u f0rҐ)ZQ8dc7BFH~|Y+Oe%֔Qup<@S:PXH46y`Lj +n șDgTd!hA!/P:16d '?@~ǤRQƚqK$ȍՁ.C;w!iJ hNJM&QW* (-9M_SR%c +- I-HFߌ!Zo[eU -BR ·1iSc,BۇHv][őMr*B/pg/1'` f?(MS. `ܭͭvJp!÷ǃ3;SòtD+DEMJwq +*bj`Z&IP[9iRnF2]Rx=AtĔ[Gs"2H?<FGJ-v*^p xkk!)N̷):,A L鑉R^]ZB%v5vjtŃBL Jc! tJbHNT5A +5!ZApDdʇm]Mrq5%9ȕ9uY3tp%5um[Gh&uE v&ܦD"JFccCW2L:#F{vsQC;R>@ʆVLQZ@3Jݿ܏ML +ʤE's՜'=L@\,(쾗:PʰS7'SN% iٍ.5A9@TU2Ad7#zF=gAoCs̈́>q<(#׿ۤsM1tNR^8҃$ 5vR*˚D*? x>#B]d-4fl0! + tz׮N/B(zH wN 't#XcMp8莃Dn'V/ONG` +1\`]\f)[||gwazIqrP"~_)m7tAȿOmHoBmBŦO.WqeT@#5U a6I(v\';'~  XE8QiFzpF!qO(Bm RK.F'>T!m MG0e8PlE"x:pF&®Rg )?R[HLtc)>D!}Q-ʎƝ;Q 䀄ޯ-l#"Ov=@eTVBW7UFS:_Jrd̡u2 +$Ƃvtk&eIepc;M^-j +3<_Ζ[D: +s+Jlţp+6#}T*~w Zy[''4UMb}opH%Ⱥ!Vc(["*OJV=dZ=(`5i4 lD 7F\(y~O41#yYFDcP+S%Z DOF#`F@wFz0M:K2Pq.F(RGI7Ƀ(ܣ{ +}K[8bNTh<*]dW@H(Ў!ʛ]r/?b{WB#2ɤ~c' |F$)C2CțRಢqeBPݚ^тI*(C?cP 6n^~MzxaP#n.kP()nS9y|TX?~zb> "ך\#^Ф3YR^4òew(4Ű\~zrH#Jf%H,#HfۡHiH#p.IcJ +oէctɷ)xgp@ԽFZʸ,7 Xw.Q\_59".-w/ 8q՞+1MCFGUBIcdH}g1^i+!VURx_ ^Bmvޜ)` +/~V'Ԫav(%H0e<É&_y&/w|_zFv(s|z81Y FTi>St8 +u_A,~ }^w e=id[T{HD^oc4eȀe.>Ӗ:-ߜ4^!]hJ +a}?]?D[&o= xP) V~&%J8]@5fqMi7SΣȨ(vVM GA>7}D_h#Ǥrts0$Ww(*L^\$6 HUʇ"K\Vy=i}`)n GG11J0I Dlr`$ba"|-"7kk-Q@7 z9* eq^\sᏑe! +vl5@u!\iMk۲Vz7Ёp_bi9 , |DP> $#= ,"@{ei.%I6Io*?i|> 9@MEeC,~b^TU,ͪ:! Ts0:Z}ʐ1C&޳;}7h!% 7K-Z+CP=U<9 c.))3#ҶV'Fa2Ss-m0"L?AMB֭PߧK;UIyq&DE' +wR Nt0luכmE蠀mm-.Əg:=ՠeKkHE M"fP_1 d׃QOV+(3ŇHVJ7ӂUz{(b4tn9kl}*I?W ,A51q?߾KOvZYhм?eg~߿/~/_}__}n_|}wxcW~o>1'ڿ}?9~OO_~~o??v)|?-y73} pV~dQc˯qϿ;zlw06RBoDv'=j{VNd(?Pܱ̬Sg#. Re6vWwHiL_M}H,[.jq)r$PpO'8+$/6(en{u=L66ɶyÇr-#L16ޞ&EEWXiU@ +>U.X&w%BX@\tzʹFe]ŭ\P{}y@ z{(Vv*i,gpt+NVOciu3Oj_" c']'ګns?i:9 d|JG%, .dy4C, +,[fLQs糧7vTjk3,L9yɋġ7ѭ8:e=*+q]])6B0 5" k' 2J$$0\Z]KXk~Vx#qG7QQ k] Ѷkbu8.6Achޘ-=QKDz0|H_}k / vgn~-!@%0y|SCgLenŴjB +BЃDE\̀~)galP9^͐b1 X@ˢ m , ʷTczoAȶ*~8g@D.f'rp D&&u⨤45,pWv&rNd`խJn;sDҍ*zJKH0)Eƻ |7P׿o,axK>*>Ov!10sJڊ)?J66*rZ +oھH\U|JxC"QS@'*b'JiRJUx $6wlC+O09ݓP>觨̳Q RMJ6L: g)+'AUWX:b&j"LJyx"L>ijK. +eYlv:SO=g-_,N eq ~g?ſs?waE_}7__K<Ԏ?Ԟ[x܏G5Y+D6</P2C[1,Ax`XwضWOg;<1%bJFBAٳV[Z s*jŮֲsԽ#G6f "8&36xz;'],n> qÍĢZD1mklm Hm,r+\+)Kix\hHw?v8"Gz^{M i [UQ 5-6y{t-,#lC)Գ|ۏ Xօ>$(*Pħ(ru;E]u%fl߬l,A,$R=n@6$zQ f]SO=C2 ts. CAfV$ِav ='9ORkNE"5]v4, 7Z{T ,EEiyRxdDQ3hC+rٮIj[ՖFLWvY7*6~C3Z(Iw[E_:~'U*k0 OqBi=]fb̨[3኉! >aXIlٲSW]>cdAsm B@YfHctz(Z&v݋'&;-|#&r[e#oT &eɒWFf @È +w\D$<NA+Ҥ $D@;.D 2ԩ>rBoIcl=@H0Gkk5F: +Z$t z;k&dgGlm+Y֛>~RE*5Ԏ*/<\pv`XתX%&Jh"l_Voˑ#"vACxc!=$gĶud3αBm7V6u|uqp$"ixAP6+9QC8҈g?D?8_PDLȠV)>0ʡgz̈`6qQXQҮeR֛RN)jyYtYaF^LԓeՐϊ ?b2ǂ[PW$d`s.(Q"̧UD[A .Zzj{A6~@O[N mLFE_.#g"=e,*wy +YIU# m_@#x^8%;5eykg/3zG;Ō(qԁz i6Y;ɣ(Nאޣ)w6E*EL _b/qP`GekCwhFg.1)#{ +"NTLW$X(B";n#SS1N+ՌlYw{kEs[>l3ρlS(>6vRy^_sh <\>+ГSR($ۚEK?{3ߡD)XL +kKŏS߯H2n;.L5Ɓc#]ȽN<+˴^|M-ZrwAnΌOIf}}LRF +ۤ0Ʋ#s1̺i^bAPItxH,9+ush[|F +%yiqJ~`2Kh)蕸 +ČjzñR؆sl"C%4,Yݮ Rt񐊼J:4?WM!fP%KL`Y*r'C%ޒYݨĂsYk,I0 Pqfn\k~œZijzӦ^k~u+C5.`F#f15_5eAb|L,4-lGEBA'51UOR\))Q]EB.RVRcao-j?@yP˦ ~Rդ9f:~8ptCBbm IѠmŇF!YXi$߼2ح-eO )VJsyV" ZF@N/+k@%eQF϶ў<%/tiUntE. un6!-qyYbK4d$V\09¾<Jv?@Ԅ8rAjĬMYE \YBK +ɂw +o+q{;ʈvug_zg¼ lqzyM5H& c2 SUB խ<#X(^M!zH M~uxA-dôρ:]yg7&2%Jڧ+_\9ŠL'E+_k@ n(1>52K2oث{wh d} 0ޒ54,߶"IZvQdkFr/ ~tId@@>T)2 Ȣ1+Y}Ě˱8c] +asI1 +Z~Z @L>Z(ʺK+DerMYDLCעsͽ% bm侷 kOYED.`(l% x QZm.e8eb 8z[7%3k$H tDάc@׊ >QVOVFcl Ð9ɂ&׷Wv +)Jyi)V<g+zJ"Lx]Kϕ+;(rV LRnkWPM{-ubNx6\7S޶O7*+Ժ")/m ?,de8\ուH&?Cjt #B,Dk)_(r.V{#@ J,ME5[} ic^g_ih7U크T\ByدY;&v92}|5l}NikF,GaKepq-ESN oxV 9&WF׶.ݲ$g(_4Bw?hݘܵwCRq>٭1M̼S]Q{~Jݯm6lmmYٺַޖ_-~nmzۊAnw Qn@;al];nC'w^<;\c7>l@0dÙlDhOf6̈6mav8r|fA;@ь{76N{➶}CK%j#6֖l ۜfÈm/}]ZҽBwoﶤu7yͨ%[ƾ o 渟eEHn5iyWptl έta@oK0t+lӭtWHuAm ٭alo`Dwmޭ"*{xnYP w =zNmuEko ʸ(!g)yoE TP[|oE o[[ICnm&_3akllĆƋ+;bmO%Er佭U_Mt̯NznQ1ܤkU)-tyv,|@գᦁiЍ!WoUOvbHjĐg{KG,d֢?2L3>ew9QYlΡze\~iSa !V}j-]UznZ7=/ooڲoz|},7_n]~Zk8MgnLZSng=jt&hG.D@Փe@@;7Yd S@EѲ= yTYǏ0lX!!w&%Ѓ" +F\} F71Sa]l߃d@ffuwoh/sO3j2f>g!10<0Eʲ&cVes‘`;qQe dQ[ݰOIq0G=u ȷ+6*0+QOE">w#"q7Q&k{$(z!R1+|Tja*!+.c≷gjhל&`r=:U(ZK :߸TUඍ|̉s&(Md!t zl h *{2ZZݔ+X ?wOQE <@^)F*%{M)m#r*|Z޸BՕ!@rO{ph<])βv䀑.<"(Q뀣-{!Q6pC:Gp<rK$20֧w.oٞ{oƶ%&7ڦjGY-Z0(}|a6%om:XT,`[_..,l25৷kıy%h/^V `ڂȿMTT=>rYۋm -s>}YQ͂}[gӾi3r|om_ߏ-X_G߽{XG4A,-R`9{l ?PKnԷ?G+yܚ!$u7M(]PI߼#߅ˍӽoW)D0 2 U&BHP F!;W*lskwd!n `1weϼR %P\-89/>yMvNL 47^*+92EVFd A\ endstream endobj 108 0 obj <>stream +OTQeV{EdmÈӥHm:AX5  pRꋶ3UЄ3Ⴟ[lT~r.MSWWEXMa чwl N∎^_0>:Fen2fmjY絓ӕ2%wx`݄bwh¹6WePq};>W?NiXɵ:wT;F~?b^vrI)B(ӫX?PF#F'O +mz M&J#(43^sG}i;99֏%@JO8ǾxB[>G_$9߀Aj0qZ4luG{k\ ˛l_ ,2Dzi4pShf p128/Ei + aRQ:!'CjPhl9XpB'ZvpߓllW`KR''F>>jP߱U&c|ARDZ>!tsﳎިCAAjVsF$ɱ[-Kկ? nLf>G;`w^%mZФMMZz)~2|W tޙ7l?ײi]){6]תۧymlݼu;/tB "g{~l{4j% 8SByPN6vnYNI;`%`NmҖRHFH>.;?WF"6~slW;a/ 6#l*{O! Kξ 44OHa3mtfnhX2*'6ӕIS;RԶU(6Ҭ "MKTXF5?4p `72IY_uoD Z;qܢ*=Kj'b%"-;ʄW$ +s{.?;Ю8-0۟wĒx^7;\m3^g߉2 of+dDa7?'NJٔAvN6੔v,a1󬱾8nv24ųvxjɶ6~eRwcf\OoqXn{3P$Z2p(яHl-%wKKyJVN`595#͡FByߚ|޳Xf&Kk:j/-=$.kg_Zcޘ GtI7f b67f=m<З -v1ƌ!&Iz4KcFfNz1E3c{c[&rAg3rD6e~3zW:A5f>jэ֞!m"ovINsߕy$MO9GԗbE9?#G̟ 1m $͘wmBw '6 +j`p.ֶ\R֋&k8$C&8-%NculXse: ,/⤜Σ  6܇B%BH`©l͆;偦-yYYVwԮvOZ +*%zm_qp)R\%6J( K%Nk1ٲX{->^mH:@z!( \/ +b$ 6=B;zBUУSK[pp-`BYbΓ!d4=&-~emS +ҳ6۰XMdz\hH# )L +϶Lig9Xv M6I*e|Xs%]d? X4/-!nʡ{ˌ8 ]~K(Pdͼ(kqo=ҒEc$8,dީ>,4>6Uɕ*\Ls.!=s v6>h-=ӹȺIcqxRfCj;ZCϝ H{T<3'QFuv?dbĎIچ'Dn;Bsk+HϕCJP^"#q@}!\,J\:GZK "–aQ4`U>g՜$D *l8ڧ^7=!袙Re+R-Kb(`ϴ`Uqۅ./^xЪ /)JEJ3x-:"s(1^? mJ1++Ӓ"b{Wd[)4w[s X X4jySyMQR}@ط?aӚ%heP|ju Łs)h\हM6f;l6VKD.b+۶a^CsJЪ㩾օy/״~8&TB΂t`_x%-= p@ut(8DGBB|Ot%< 62Ű_=&&z|`1lΰ{Wx^d5OK +-jM ~5y)\71 XFhS~\I]k|(J:,&J?1b=ƾ:´)x>vhy>{t;}ɋZܽkSp_vSUf`nRv Y.t8]n_LdN8C^Ñ)J߈aBhG~x1=J/q9 6+#[m+# au PBBB:~p_ڧߟc AM#8YW.RŦR_Y8S:(V!btgTPe͕j{G7z Rn?-kjWrLM P.uKP;A]Q:3s# a13SUafd2\Mz98U2%__= ^/ܻPV%.XMe Rzڅ簽4]UP_ JXfy~VPb]Tb+xPW9µpR|@o A7z)IHwVdpXE;#eK7'4j|$@뻒'v f&|ɼ;=[ۓ{]O֌d<݂<2­tӘ75Vͨ}iO]|îz5^{Ѭm[{+u}hHͥ`ƭ&Xc6EmbhczPmW]+%6V[nps}=:}o1MnSnw2ys3zsYNoo$71gj v2ܶMqڟ``\CMq Dn 8fBHyNw[`n&z[xs%ܤAoFHތZJg@|s` oR(|S\Uup'ZcgnYʭzl*[z)鎜Nw_6%©=e[2:GҺ)$V_y—(gʻHEG}ӘB=,lأ"= + +,LWN*y 4ʍou[,B&>>w@)B&򾕟n&:?]S~݊ϊڦVwտVl8[^loHoMfmW}ĝ>j[Ay-[늭f+oWEۨάuew5fاڢf[ckkdkcY2ۛ6twݿK7Z9Ӿ,%k|mK4Vͭvnmޚ}Z?[[Xvى;޶-uGݺ՚]쭙m[/6XZ[ugpoCED[|Pk6[жugn-6TcX[ ʰ+ +b7]!0|o!OVȞr ɞ9j_ў Tz8YQ{Zn+J**+lIJڞ 4u6^Xۂ҆Q+o+d:0\i2q6<]nCCJ߆j+򶲸B7Jf Ngu"Srg}n حg-(oݭg{ ֽUOL*^;@@ dwɖ.} +Xc~l1RW`{@K(ZX:k.1i1"tm[$VrgڻB +$ᜭSֆq8v ԫZzX~evyE[,u^ HZX&6Y}e9V\m-Ψbܟܟ]t*kumWM:gxI֮\TBZxOq=fϖԗ +؃ ~^y Q;Qƽ =%ĺN<9ȝт>Q;M"}5VE97d;vSWw2n+㈽o +۱S owqcZM"R n4_aoR#eߝg޹_<W|]VےiʹzP0QZ mDuOkj21Őw?e=xuY:9d",vہg)ӏ9dpm88L1|ߵ' >?އ{޹As>RM JWhcnj_mJ[-7"U[A\ɶy +SVyoUmf nQQWbwHĆU5_E.Jwwc ob`c_pP^\ηZŻ}wn7v*kzPIVQ8hm UwawRWE7 +kK ݵPf%[>Uo-AL`n7on "~Fjor٤LEfVZ >[ $Mp=`.[u'{n ߼]8oӯDe5:h9 jUB~;%ǯ \EqBtSa_ѝIcWm6vKvSa{WS3g+ b[,$Eк^_-W-ۯ+u{}nLh{ۖv;;qcι;Nms^-@^޾[:K`cDӋJp;Faݼ!w-hKm\Ba-թ|LZ5௜h&\*w$Eo$һ?K6<}U'ai8Wʛ-bNo*UywZ]$R3NzJ>WݸS^4K_@lwd[[֛Lf.lۣmvlk,m:fOӽp| {$WcQ[lrcTj9->En7O#qTgRN[ol>t4b()@t[m*dxTHYTO)`Z=|6%٤{ycT7ж~gT"t(WleQ"ZfېKm*Lux}fD\nɭiP-7%$l7H7>JuJՖi9)B,Ű[*Pr̍zvէ7mJؒyN$7s%%.7JOeJ5̓,o% {+kC 8;JvutqsS=Oij]Y+IǏ%48Gu踶[+XA-M!Z~?$eeR~//wX_{Sgտ}b8nV#RI<%GOՄVD[b,X);. pњ(ބ\t;a|H[| Y_] Z쭴PYmX,f]wwh @GTc `EN E^* Wuז|z@e3mu݂,F}XbT޾7""^1csK%^j\:s 3xΦؑ&Dk yyw'w I)JPʦ wS|R8Tc@wjBT7CVC7[*J< 83&JT% `E`'yl. FUuyPhU|u]3c$QMFEUh%$58 4)a?Σea*xKԽ!Sx)B:TKo];[2]pt2kr`&?@JzpvEk ('y8a鈡)~WU8) |P(Y3>ePLIU5->nЛ(8)%m:LlӠDe +TOE OUI=@0DSknւ2ߣjGz""߿< Rh4s4t$B:\3abzfezW fN^ +)NNUBޖ;w ue6lXy>g#ɵv?BB!?Gj63BccF;Kp4MgMJ\xv:@ٙɽOhQ1˒ +7EQ0{dЧ0W}HcW/e[V@Ս˫}F(6n\arQ !wa10X%i@d(= Q!Z +fJe +vc\*\ )mMٶ*M('ZJ:J!B% Sb'YD;eY;i1a%+cW>ӆ 6Qu)cjpe@HN#fZ@\4mmkrrсG1rU#tpy@>Iy'XHG&KwS'J7dѾ +91~踥0UӔ>ᖸ%$FR%`2r#MkV5W P3ΆIZn=E Ҕ Η +z~lU AW QW Ma^S^vmMGI +ZXpm:(ذmq@ᇳR8ylօr-omlMK'(1JՙO XPljsITfa[}{{G]4! \95`IzsHϼyBմ39JJLkTa#צuvʱ dڎ.cjFUR&&`z>B-%7T auZMo(bP([$_MR{k_6{m!Pth W]tyE +,E +Q허ۛ +BKtIkR/PdL쳴,31 +I1;D!#܌zB{N5h;!LKdnf4Um;J>hAнf:=ɤsiS1νmD +8@V TXDjW Ze5c'ʄ@C+Sw%;)if¿TUW-v灍P%[%)(m4;):BͣEsEoza8[Lk-#V v]R_~vJ*/seW'{I!k;F'j&aҔ|a%$,3L;sCͿm}" +X,r P)֥ 9兔X)dY6DCh+| +r.zwPS76@'z7N/4ǶLo qZʹNƒ#_$J${ qS#Xۋ;XiEP^)dtJj_;%,>\TADa&iXC?AfHqOFbp+"s 49 -DӅQ1`QnM'It-ߒf8vgMPGgTL/DKBW_)9HeoiR>>C"Ϳeuulk$InxFU遞օnY+䯻E0%%ě]y*|udRgz(q ݖmF^5ތ֋囙 )7XR"$دx0 +u26K76fRk#YE 1*Z;sZ1f&h//"`MQBA'PA*OȽ֡{I$Sv0o PqcW=lbďl0IyvIfwvMLt_<;$(~ +`;wE$=nzZ A5Ae=tD:a[Z"{z8 +>MdBV?yX xmaY=X .}Bm  +$ +8qly-~26S Tv10C/=Z7B3C (ƏoYvF _Mg^Ngҟj L }U:v8-)̊ |J='%iZ6If0s4wY|fHuQ9ħ6V'(|y[$Hgؐ#,МPXg.gf/ 3Q`]yB0Io3} !z^\8jbgE'?ev5"mGT!3u^f0;s=}IK,ܴ>0)7og!I!Gyqy[5as}u,& K:Swhoc{Fj, b_g7x9S?g͐ht4p*ث5ѢPʤY5X۬r>6&eڮ#\|Mç LzY."#Un|6,PDA0뤚}-ڋe>0Slb .g}Ck`YyϧɌ6 .&v PΚ 5TMK6Orj΀{jpq['q(=*SnLiIA4b7%[55wM?mte$ +wl]}: J w]7p W{ℋa(W +J:WMيZWD+Wt:WUtrxmն+sY"4lB%j-6Ct,atft]%3]E3.lEw[?::n}WZP:ya7ZYhʵJy>:;J;z➻o/CoYk]oBޅK\! m5-XHwk. +:`kp0df s .GvBwwe QmӵҸ™ٻϮ?#;X.چ]L}N.ڥArvak]6\k\&.{Fu̹ۦ^\&%{ w:ƞ1[RP+4sM|K K 0fҵɰu 5fl4@H\#CBnÆC6g +;"I_^ӌ3Qd+%AP Ozֳm]M2ys5!9T+>y@ 4ښ8 +Vm=kُeD OY~]zhuT?&ww`];ܵYK'[/f"+A@;,OD߼?7cI5qNQ gsحeb=Tso<\! +2&;pl 2aP)eh@.ᔍ<Hi'뎼)Ǎ(ɉ69V Oe]Y(4%P,Cӭ!Ŷـ{QpuTl/ !|L=;O"G%<$I#qGEm$I'oGIL =*RqlaӀ|ŝ"%BUD>p*F":IItZz\a= CYv"N{Aۅjd?#yŸD\Uw~\(gWOuwJϰv޵N܌ +vVy +0)'R*"0(Zpĕ48\pΗ h3Kh+@ˍCs4 +{-:Lc^( wTVfuk1+ț$KxJ[toJ28+Bᷞx V"ՀGX튒#ޫ81ZZ=gR6Sb2嫁?-N8P7WM|/} ^ޓTGHIxBaT1؛cC +`j` u*hZ%uɕx)x!l[a{>4CS{Hꂪ)8IPE\ФBx**zY iI  Ҭaj];;]AUfmTEZ}"6YP*d [ j+d$dQpHcz^"$mJ8;B/zhx=-g@@!;eѷ;J6%`h? cN^BUö FS*rL +a:>"o m3PّpvEZ +w^aYC[X'%  ,ב\dǂt"KGsބ^s&FJ2#5[Ϙ) <} M[0lSQ +ρ,֙#vcEC VDs)P}eO%̀5Ƚ9.FtpD[.”D"5Y2XɊxTIZun*ΒBc&<ӋzR.q%џL2r"`QunőȏKA(PUQpFא}*[rf.^=$=;a(ѷ6c?Dfȫh{kGL&V2C&(ܬxTQ#2jIm}D#O tr=q p|*;ASQ".PڜDFׄyi.Bu Rٵ o:{4:@, a厉=Q"Mi),A4=<3#tM0XcχEu5a`SB gxZgņO?tB✴$__zgJ J86 Mw>nrT#3HYW,&|>Ə"BTX&²%/G܏T=  fRQ֏1\`P%. b7t)g t1mչlW9ă" +4Jր(K;(ܾY& s&3cgs҄15"  -"C32#謺"~*N^c+xCh 8D"MV ׶j`MVvpr7J4HX;coM%iq@XТ*X"cR=>pPrI3'HkJTü +-U +%5Yp} kV?Ի6Br88jĊ{Q,#T%x3l gCwV3,]Ts=B,ж;2ĠqZD)Lшgi6UxN@*9z ;vM(,dg7l,a!Y’'w_T,EI̞%kH<^¥K vMe[;:;ԾDϑ"(tS[":ԎdGn-ɴ=ԵAK\И̡fYyyD/L?G}}i&S5lcxԗ=TNl> ްZс&/kw/Q+N|^ \R>4OX:@Rj4eʩ5 +0ٳ Reb@jhjv )"!4WuC +?A^G~?9*Th+&@( _(,N/UJANբYE]Ȩ.E:] Vz}-uT_¹tMBl$U#݇ W jLdj)鹘kȀ@؃rNWtd?h3B*0dm*(+l3d>MAB +O~U'Amo +GNx?ٕWTe`#)^ t( Epb{ 0LK53F4AMzjј{sbtVTX< P! +[} paz7b@k ќh mdwLeo{Re:#Mwwreؔ.vwoj{DʼnrP7٦ӣ['[o R#F%f%nSb(JlYQ&!@o@TV.&j@\+dN%ht6H~gu圜̣U0F ;(awĎp@M75 LoT"n T^]>Q +@W T1a]QlV @+~ٯQ)a>^+@J* ]Pڧ,2hD YA6g7Lpr@=3%j+R@4lL ⬨@=o +OU|/\Jp. WUJ5b`쩋qȆviB(WE{7__BAbn֐ʅY+8_vۘ?\VHb!{s0N\`$TP`p;}0A=䅬1 4ګ\, +ԙ1#lJP|XUaxte( #y*xkuGJ1< e>!SMnP0wb^^! &z(_%aVduZEl%⬖_@U7Qm"!a{ tv^{f.6=цbloO=)#NxYi _)€TOsV zP܈(uJ-mD74-h`'WI.v3fqP9I +1p D`1|VLjO7Ǟ ~fU#koEWfwl&C‘x*( Nzom| P,b0wN*LHK^0S%4)*PISZUBN%aM$A;l1F`P0pxߠ.D)NZ`0{|7S1u6,q&|O1w$;AO%!!>8*KPadI_vpA1>J+I"&qP܎#A Ka\/uV-z]4Ezg3bzcVScS\"<2.,g (& IObt:7ymTeA% IU` ;a|WO}ҸB[el;ïÀȞQgb,S#i*~zُO3?*yi胯'RJ JBj0.`Vt>\pqX 0`=# Ii&n,cSzdMAS#'JE S:H1ڙQv N]L8H! aw.K$acbfM!T)t~2 XF %"S;\Xm]`tGl9h(Ei0?}q&MoE@BbOE}Be&/`?PHE!̴[u<,_V@\'@jD&I^36xŦGÝb#cz +6{Rvbns!L>MN" +(%=ŔqF^>`Q!#g~RHHJz +=&28Oc!&9ф*-פO=,!I>%IڪK/ݲډشMq2OTJнH/ [TwBPg'!d`vZӡxZMt2xvJGB'Bw( g6%1 +6/A9yLR~:'7R΅@k!p|#UmjC=j]nS bhp +50b~(/ ;Ӊ(( +t^up@+.>\~(ʲkkФlAr?phYhCt@3(/:KffQ*"D`&HvQ8gl:+6ISɱY'&1QϑU\7_/R/'wOySJV>H>]`v+ePH_tq6HJ؉w)qD!#zdɶDeKH""7 ?7!BU^ +f"qwĢd,4` +$q;S#GNQ"҈3y!ʡAZS= +jHžxS&W&'/M] !]B;O#0sQQW}۴+C#ԀDR@ )TeQH]YEab[Dv 7Q(6$x!Q*~4- LZ{.:#Ekt֛,$/o<_1+SlWq4n;KV"qA@;ar <% Sśѱ #Cdo+w)4L$f/dX7~a3Lu2p:G“J i=^/#UsTVT72LP80sSDA94 kwfJmH_ظ2N%*,>牍+r.9 +ePm s*AMT@4YԷ`1g<ԕzfQ[JxSO>VzױC {D#pP\\HQxTxoK MjSM߇adz u8aV2_m1#V$vl0.!GzApeL7н%9T}!U${R_3g,l\P׵i$|<5&K*EQ㲔,rsa]sA#RKatl,$!ft,4Q#*1N]FQF}èbgcEq<<iEF1gxj¸%@"6W_l{bi[NGmݼfHE GcLţf8FPB)Yg*), +3q8qu;Y $AѸvv}d]]a02L]?cԹler$[eXJܣLWMjKebzD6B/q0Ko]gJ8 _e~ON׎ OfUUk7I |6% & ].Xxk߄.NJe +QP"C,+c^Zf- `Koem+ +b"91L( +jٛƵ^^E.Lt 5$94ret^eD}1.56ӴFp #",`J} z@l;AuўAA#kyw')Y8ΟOn9 Bsr=d\djG \;j0ΙPR,|; jRG\0^\'Ԧav3FH@~ vQci +Oq't(VIVAy<<O/KThjO"`RO'[z̑eg} +%%jrp$:C7wt>ٱOώ}z| %t bEZ_e=Uz +d";.XFsx9> ڢBh|:eK +t2M^>ϑbjj0Q GwKkֵhl(=UHdl>zh/)I=cOy^C#B܇fE&e|CV0Pa8K>C[CvSzL DA92?:TگaPҝޛ5H^Υa^y,滴[f>C+BEp$K +Naz)>R PkFGfٙKGܴN"Fzc|w&ZH5/ +0> MUGR(ͯ \Z62I 7#_?ܚ' >Tb`Twh"_)%Z19U-,q:ʼn*W#Zi`g +]WĴڊhUvYU[rj*=Wt+]W+$s6G{mBr6g8gŸҺ54+1AjZZ8BWɵ٥wEμu5LƩLgdNgН +LTָn]W+\!Wf)_ǻsSw +ꎷ_^V_;yrn"֐{ߕP+c߆4\9#wAWb;!`\?.PaD\36* oXqUQ@cF]6"4kqQr::v\duX}GJk,w=bھgj+Vw[ks}If|G.߳f,|sܚMvo[0o]F(~UrO-%ZXp'$gdimg' [aկ2Pp=&D)LYKA)2fc%v]>q]=f͈8̦H-jh/,F|.5+fGAGg#~[&t˚#Y~Fkveքk\}1n[ִ5s]ε]-+kMokY ̩ jNuglj= %W$ x5t&HӦDYӈyԟF:4@lx?l4?HwQl>Rz뺹wx#P$l86ARr(:d$e[}H1hj`{[FXL_`T< e!*!Oh'Deqo Hwg| A +`ٱS5G\ܭHGbVs̱>@jJOoPn~p}bؠ"=qÞP DV5?f`6Q .^+SmKS2#D`SLoV<,p1iEL2:LzNvtR~D7 Eq>Şlʹ%f%xMDP*f mEg-ifUnK`M,^ejʼn':3#|DjJw2wReg)GD.u$v~.k(Bzk ;+Q] % NdpN軵tc'r[jy(V=RNzR^g +waיn3rV􎭅gL2 +, ίCP: ɇ& +{$zo;NtH}RwH[Թb;N:Wp N_q:kN?q:_78Ht@o1;@!o:;tiAo:=ϐAo;tAo;\`犱عB므Yv:d-`CwYt9>FO4,fIg أ`2RbӖJ@ +FqwL +߭ uøf]gإG} =fg)w:]ʈviA{¹HƕrA4wel];̤VHczܐ2 $ǹ{ Ë0D箸͈WKs]MPVPgnZP+mgsO_ZIx('UɎׄLU9:6ޔ{BFNx>tjJs|oy񋟒w(ψ/]'Z^x0V&Y#d+Vި +H ac H-p'6禭Y?eou{*oҎEϞZvr[uF[*~-˃Pu,P.w|Qr|Qr|Qr|Q)(UsRҩ9G)9՜gܩRrUs+rRrSw\r;)vSrvSrvRr<<H1OO=Z2ܚKh 琣}9ٽM{Ux7Ҟ.M%+ HQ?Gtݾ(iW:C#JǛ?_{G@x4Ը He(Xi׳_.sՃ)}L֤r=$S:$r 4/ fUlSHE&RGp:W4Pt>KMPAYLr`&Ux&wҸ7de !VֳӤͨ!-C8$FIB$mI."[Yz{J+:^ӸeQNEt裆L,KH&mqK}dj dm 'zȯ԰Tp5n,xhuK\]WU.t}#GUbI!R}6U]GtXp7N~GOЍunN&y3tj~jBRon^tZ"ˏENe73}b{^%/25 'ji q{łicb>P if9,ZOG:Eiȩ)˘1v8eG A1,_bS.@ ˼r_ww;QINZmI=Nr%5;^=1SeZ\ =V!@v,=Kk7/|-Ⱦr8\@Fj DFQxB݇%0""3R= :e7 ("CrhOtWG̩1EzEVj!ǐ6yA-eDMP{*ۢRLQU`&V#4 G +L"fLERFVHMq7iV; RP!<[OsckM $d#%x,Idm$h/2NX;[]Y/Q[dzR[h5Ie͜6h +>ZGeצ(I5 YzD_f4"hHzOQܼwu~$۩B(osSwz>G| f\;@əoCjUsGO1I")ڗ)4mcb`_ߢuvzނc'g`@\+^3j@p7_aOyI˿ӧ~Wsgwg_=+uX\iT%C$gl_D>,àԄzI#J`)V7!&qeIC6&?F&,{dH3N399q2'U;F,-#例knTDdQ!~_&.); ~fN JlHf#YF UGaMS>%Dr&;SZuuTe(Cl6U#Dؿ @R3 ΅`p3H4[R0`hLCјVe)L,\_[L.>V3bڼAeTa[ xtBTSwC{|v:YRj}alS9NN^dxsz;*&!i([g*ZSɢ9E^7ء&IhǾ1Mn(WMx !25ښT:V8&>Qܙ_DdBK`BROPyBBf:AX3WnR-4 LrvzgOt 7Ӌߑ~#upS }n + +eBIb99hLs&1J53fJRչU"5 +aie@܁ф^$D1vr8xl >Q[BQETvֻB_GC1{X9.Ou6!s]];#3c (-QŤW<qQBvZ]>N$ цzƼ2Խ +-6ggmn3?;~t(uh +ԚDž9 ,氇*'E@rX̺B&s"]B!yTK}EîqvƅRadTd&GcX s@&KA[N0VSP}wYRM:SYSIŸ@q9IZk(<_Pu y\R&zAQ! IȮrg %Wt}Cפ8.y_<*g50W/Lج;yc@ ,\U9TyCTMOOAc Z`6!~,W jU 4o rͫmyIəB 69A)0gge\݊8j^; IiۥG> +- 'Δ{b/fƍ l賭7{s%m9d;y`Һg (fU5p:1 SLr$= p$zv N:78 >}tO}ЯC^oPA"Ĺ ޯ֧nDsE n +~bǖ!t(Y}oYRX#`f$p >EP\v8nXWPaKckb%4b)dF4!5"B)jTYým#Դ',!f/9Ct2űnX?},r97+=<96s PN!.0g,tyes \a7hAAϛCwCASo4/RF儭@n)QQ-x(^FZn>t0m4 oY$6jʰm7xG +0ːjG? o\ R@X$>ޔhRyq- )kݟS0Mm#yvj!TG7sglk(9o%&Ls0OT.S@O h{ k[-shة9Ǧ8( n+j:̀pA`SHy:F5; Խ9~]qy+ۯ;J}Y ) U9w3'$`w궓,o2gQD S:au{auq-4cPMdħaY>ۛ,;[ )>=AD^x7 "=pz$4>^տ&k^3\0TkM0e[oV3oQz!XʩR}Ԡ5xwE~z=5hMi߯5}ugMN3`MM{oc+ # P3qW;`<`@t΁ <SJUdhۋJMmĥn}?8yӫ[p ?͗t䬇NH6dsT `2eU-n8Xy UԸQߍKA\?7go_`0VP,!T2y{_Μӧ=Dpk_f"7 KB5ag!ZBLTKD"vY.00)Їc'VyP~$): MA=сDێC!̖L + ~ `Q r,JX K u`WvA P}9x`Oǵѿ#L;;%Ӱ?oN4;~^@'#ݭYzLɧ? z{"`1a`RL_tyoQ՛n帲#!@,z84/\[u)i ,){+FPB"xg=' 3S $&lfߍzO5M\y;Q-1^"+v`C Jtx<+EPbO#P=08t1e;iO2G dKi,%hV'1*DR8zb +A'PcmІ4@kafL88t_d1yJ:)xzwz)HYzYtxELJSE4i zط +R2<%j4ىFiU>3|&;M5t[/ѳ#,bGaISc#="LH5ѮJOAq:JwpiW/vW_fH$RV 6Uq^W'wb˩:xCIE.]* =B'^PRĜht]L4; }c0H~K$T}B;Y<ҦTA0Hyb2..HubhqQ[BFyBѪXo MLE^T;[AJj<[:`(Xk\GO"SNx۝cTIGJC +n`Nf5dhIDgS#{wie#EqBggeWWYHScz 7|Tۉ8D9&!OQ _wU)u1M75<`^&7Np%R;ja@}۰ERJd1'*ec'FeTaҝCQظTjЉw\Sf_#*^ `;^XV Eu!"MKMmGa@6y݅փ%O?PxinzOe.MJ/ +ER\%:"nB1Obz j*&{Dm̙QRLif&z;ڹO73)KP݃!2h|Τz + fBst]ݤN-SV$T:3M b9Hyu`kcAFde bV$v&uF m +Q$G@WR%4+ɤ1zo$킷YMFފL=E3BzvNUYX + =61 +^}=&q%TNpӈ%8ͬ)XR.T ;pYx$(l/0+;"~UZ bwrt*qgwUua͝Q={fSr19 +{e& +"v&_=-*-J@Qޘ_SHmpjTcoS([̛}ܞOkԾzr$)(7-^KO`7'W:݋)V:NC;^Ư]]17tO4__I>x/x_~ӿ0uo7zͧ?f|Wf[}Y K;w?|O_?I&owco/_,mY^-{//m7oߎ3XYP??{s7K~/>^~/7-__g_= ի>cD1Llbseh:PNf )s|E f5zVOŜQoBU=_P}9aT"XA*?60^pl)/}R8F_[j*{W핖<`o/uCXCfƗS7m k0gz61 l 5?4sh*x2yů$ǔ9&Ҁ,w]NyLF>?LJDGP=-|N!Ya_f;g|1'@и?6>o Pu{t}lDž8H0*H7͸i;iwGs-M^x!Kd9qe`V1uvk@9Ɠ:1 +qJg#x܃!hγ<ċfz\r1u/19qYXs_?LI&gze|/hC|{tE0ъ4%b8+st+Na:4ߍ8` gKiTalc>{zs/BRsOTëu,nZDlsq"Y/ln;T9Kz1b{9M8o c ])nc +w>z]c> + {2]UYs5cK1c:3[(-LqxofrߍOi-Sƍ9nV'1Ep@->a7_ORZ^3sd-8s C4%jS2Le^$s_=NK`=xR} JwFqT1>cLS՞V#xwhm ʼWÇ|39OײϵQ{/ЅHFC$gYUC-w-Y?k׏evh]|i(y u~H7V5>lk D_ *Ѓq KqóWV޷ +5&2M'4b ߍs Ch$ WA_S6n 0S_x8\^B:Cǰ'-Z*-Ϸ:L-W[ t[r*2PLӖ?c- p=gǙ'A"h-펹\@)[J$ոE yK߃=9n5'Pz,aqqp݇<[-rj}r nu^%sճZJHD C^zg==i~XfW6 5eѦ8WqaWfܔ0:!;,t/©L# A:lTeW27OO|RuľFJɛ=Rm_= ╃sN(tAm'__2.>N3Шsj| и@O$Gw@ vfKJQZ몮rDY]`G>h4#ãjĂ-v}"##<.Ӄѱ +2\z9/5aLO+a;"+H})H +QUDN\ +ѡG+REпO+䣎~"mX +鷉0! DiSd#'(!5rDca:!j'(գ>O!Ied1"-_E@JϠش)pvb`/?6;rSY'gVF=SYioHXU3:U(ߓ$z,WTzjN5=5g-lU}^ ʸQM׏b5+"L(FTX;EUSfjy{e ybSԋ&`!P阈$.SFCbHtR#$b`JI6ih IR[>Sؕm=Wm.ʨz"U)Х`H`# JRDas NKhJL/Ӕ( +,}?!e?򲤊w?呧S~5wK]Hrs#&21){ɜs|zxLj2Ӥ!,!(̨BбUi.͋reAAް)xP*HiHV,MCI)͵Q^-<䰩j}܉D405B,ۆ[h*/` RSg +*G]Ef̥ӥ]r []!B8μf O|; R2 6Oy12PqI{I"W"I84ԓI;*%DeP*\= ߟ))h^_(i)#DYH +>AhȜ\74/WyIDa0Kk ."HAjyDw(/qTZ+,iҠnZ!yJUeZenDz҂/I pM9U2UU͍^B=C')|Tc"pH0ʖ@BFPkO>:ٱSeC6vi,U({5( OXjK{ +PQpQXdYx_7,7 yN4\b/A)x8oiJ~{|Т!]q8I)&S/k$ѿW)ubgokK)=뚎~&'#TOڜ9$,<=EvU򂧡 >˴ذRxp) q$O]{Vp=-4d3G 2 -0BIjYЂ1-V*)?$E1&7)Y0VgMQx.;,XW}rq{T IӨ%+=:n((8DxiLJ\KdѨ'k*S"EF5I{:رx 856%h 4 kd+̀V4X*[z\U'QkbKC+T+8xyEK$֕o;%pDK؛a;<31P2W.l)ˢ䀧`65 +QC1(*iZYУB.\FG*%W(ǎ>=UK0aC[SRI&W'Wq :Q،*l(z*.BOhH\klTgێ~nr[]ٌ"\W!e +hu@V*jm)Դd TDCcj+65>h[} d|HJץw"-PMYq|S$cv~t)ǝU5w5!hݍlHL(mcG ])0JxҬq4T.yt4y1M$cpU>]FrV^'z)`KIUk="]Fz 6[2bL%v`\ץ NA(aX֕=t%-},K3lL2(I]1x_.~tt9PQnsÊ&6u)83H# + pZ(i=2e ud9[rښ]m+pUP(nC'"Q +^ML\Om7pTH`ʄt?Jb[n(iLfڥHMLDIiS[R^Й\젔bS:Et{~ly4" +ؑ2~lKbA%{ I__OF+@4t.!Q3<e,{>i9*b &w'%zJ41\W~-p]LKPTx:QNB/`qE Tc/xGlb_ fķl]+o70:R-(J|*8NR>iY:(TqL-ץ%6UquMFHWF8:@&Δ(8 ؎IF8ia]*U`(5:H%UyZRO&=TSweJ[TG x147Yss7-OIκ]OX46pU"\)ϖ:kQWkpBGdF)r{J3d-:ih`QAvS/[WZ`AVeL4̝B:۠T'/`u)K~V?t +*}[)Q!%YI9K3S{I| A$}OncigQ4ǥw1=}x'koo*$D%cZcF]dj6n5cT}XB* Q*gIql&כ&9iCM 0KJqv1y+iUډ&rWҾx +' ]+ӷ!\qH1S{Q0FZQBPZub_QPȸ0QBl">޵KM6&6ebJtU42&t?1k͙&ݦnP2;I H0D/`JT1ÕMz3ݷ[2Lk(Pn`)''u%xivt]d]&D'krwC֊Hi=뙹]@OHtuM + L\]oxyI.YAD]T(Uĺgt]S?-:Nxljf9X׻p*4Ry*¢;k0J!)b@r݋N-PIxʵRD ev!|>#6,l铺یr/VL"Og* +V4OCxճBڴ=Y8LC)KJ4PA`I Ȧ^t:3ذllO)5+ÙʇMIYKG%SL9]aH]QETZbrelnSB-JeR>i;B= +Ôqx9^ +Hk2%5j]KHf @ZKZzj ӊ8iLM2<,GbS)kJY`(ZP9dâZDF Y,΂F@Xt-2{#B6h4d =zMV%enG6)+QhK+ptbf0P&&9Z0 41M JTّR1LY2rɊsWWXNUd\GV\e\{U+3%5*Pl(8Y|و,K)bDp3U`Z#M L;ݦϪh郖GX&%W U@z~*K,h\= L"WQ )-2IWSН>eb/m\@Ee+9C>4\F0 B8\' G9S| A !eeL 0 %R/p-{E֒8]#"Z6< dZ/:"t3c?nKCRyr¢hdvM.(*CNg% hߪrR>4:F+hirnLCBu6hD՛Rn@! J +;oWx3"%i)+P`HAFa zJL?\Sw_0(U рGga +0*8PϮ;TzM]}e1R-%3"E+4; +*0k!<>8+kCT^nfܣ̵mFsDíB.l朢35f$Q)D Nÿ7K(@\滑R}0?@ r,7ith]!+U)@=@`5U `*QN fDqP-4lPZ4S'n֔HRreN?bh{5S! 1 )ɦ˶IME +0s׍\}$_k Pg>YR +毋1&AEw]aȁ+ -yh&@$Ldrꮡym]uغŭCM8GP{4swGTBuH&݊3$Qh`EW$LQ"\"O3nY=s#WSF Du0ѓP}5 mj?_ӊbjk\0Ry7$eU}B|VE%Q;3h&ۿԛIRI^RG۳%z:j?tSR$l{pFEZq"եhTuD伤Nh;o$>BGE)zMDơkWIIk3_9+M9gI rŵKWD!٢pmwʡ9Yk–R"}Za8/5\%(ߺ~ uvC7gh&US)MP],#RKOt;O- ʇa-%皩FI"RRj5vj ζշx lQ*RDtMm@wwCg0BkN"= KMeV urYS?y⦫{gRv*x&j/0ÇJh2UlI5XgGrTfZyU>&,oJu)UlAu) +'F(3qPNI_en`/Eb#+ >=zQg;EV6#Ik_о`,TpC_QyG59Z +HON@Tϊ;E6u/W!%~璮-j@uȽOmpT ڃIHuը*!$A+i̠ջQTޅ=STPp>{ Je(L-Vme[)E څ.jX'e(%2UpMBY a~pecѬ>u;FOstXFk8#6^ekQ*⠎fŅD݌ӵ~黮Uz]L(kE3^o__AO Sc[5c,;" htu79f+7׎[+oS;vt'UJ3-Y+al6t"xiM 殪0v.~u  W067H?u7t34Zi͝"SJR"d?=riYf9n=i q-Aq,-0;VĹJ?%?˧rVI}6]r?XP0Ş=CqsгefA>g9 `FL2^ Ho&6~x =fӈʝ NG #U#0i%41e;M}+yzuDpjXxADz"ە? 6zQ7?xOEȓ~J %o5q5í{͛k$4YaguA~/JY) /?c/$1#N!|feXA)k*%&&˴^o/mgm##]C`o!a,_fӬl:o?u\f,1zQ>d[x٦BtPZiz$s u"*)}GZe](pMAOո 4I'L +ueC/sщd軰 +e|F]໰ %?.°eR{_ƱZFf pfK^Bh+@Ϳ}Xa>IM#|{xk``ϊw.&ʽCD!/M~{ 6 ~~A fG'ܓ?C9ٛ=t-fk^P*{"Z8BTO֙W9^I\9(Wn4̋ 다sܘTWA:r,sV9g6sR>Εhɤ ڍy;f4\ՇOZW) m,Q8O:bC74nJ3K#OhXj^ӫ/g34bߚ>X| ƪJCQٳa5rV<y+n0Ѣ F0R/7VO/wK7>(xȻMԫΙ!ZkFo^n8~X o FaުZF~քWx0k7 +cFn04Jhv VǦ7^8Y8sna+gJެp_&>!o+uag[sC x NvX [,4Cr,j\|[>6y)OEm(YhU$㉛۝VPo o q`ny [~2kN%g'AuY<)oxLρ9ځO ΢qet9|W>zXѬz9AK뗒C ]3UXC &0U=;ZxK'۸uk\?_?ooWrqjrSkuZpbsn}׮ݶ*J o^]ux+Ewuk /h*<-幨V;q:iuer-K`ӓ'hoY8 +*Ye«Z%K<6nw +2@zɑ.-O +Q''ٿVee<G7yZ]npbǂQupۘ {n ƑgڮA +Yt[Ya]vVX|_eNKƬm#X[2RĔ7Y;o$AĂźYX_a]?+"2~YU;XZ0&#=ȉL1t1s ]j;A-XDtEq "ex6pns;>Ahæ\hX0օhY*ӛ_=,*h gyRV'@wʓzϥƾuY4 օe`¦gy}xm%xU?n3~[ܴf7k݋dxvEEdx phͳ|"o`/_;;7hCxTvWnSu ՁO^s1{RV^{ɳ^UgZ$VVY|n扈 X< ʀ*qvil,[QY;ё_Oaʺ=yowfƨfͺA,g}O2nFH2. E8M-VvZn w͊Y?Θ՜"k~~ҘaB8[(oe]`3/+;Ϲ-8Wpk( gI UXe7/ѣrF|vHik85~Ȫ~Rݫ;N<6z~(lX\WJFV8us|;\}7WpA by ^QqعzT]T1,> I:786ﵽ~}m7Q/(֭2 P1a H2DWNŠ([5ܜ3vo51Kj2j=,3Frqsp`(S n}8!g%NT-辬Q)93Zöfhe˙:'l2b9zd '-,6D8-``ЃB-$YTwNBaσ\ʗ3 @qs<37Zh +0[伇;Ś^8Zo+~r~h"yh\!O˂?94/_uW0sjE7}&ɳύ7Eж 0ʂ!Xmһ! jN_,o>{^?vƩuR\;6AQ!.Nj K#~{NlZ eǟ$Xy[[ }E`*Yyԥ_;^2D +7Lh]#[50'w +cAbl;_kb/?kǀJ q|x2I> gNN1ns0x0_W'Ӱ{[ |'~ؾ^'n*6AҠ;sEY .[9WTj\Ec+\*@nQm'v'pHuz W;ԄӰyThI l9~ܮ[3@KPIY#{Ú7yWp;`8#?Yz07z;6`9`c;)7LG|9PVlzuAf<3_`´x4|1nJC@!ff St-_ܽV!۪݋J[0 ֒|uYy c0`j坊!.ystN ՖN=2MZQ9:\<쵨Zuc 0hƓߵ)XpA窿6{]^Ѹ96o /^M4zX( `VɮȘ %XFǟx\ (S,d|'+0NVof/3FA[[-Of'_o$̚kQlآgz< +jFx[(Æo H'm;=y8Jy?{g8 ѳ'88M(yՃ"7/O_gg w@ҹG,NO5iP[U^U߉0F@G?{蜞.'jo3 onAa1k'&E#K]0@m瀅@,0+S:8,Cw((8l^y ww2ȓL$R9,Xnsܝ1 "&pZt!ڥpV pw"'X- G Ѱ֒HVzP[].=pk{('wzv0.ׇ]AصYm++I ~`RΪ*X01Y<*h\ȣR/vFOߖjKxH?H؍&J٣%'^4Gd3p▇o-h.⽤qV<~QjA^hJyo﹛,@8:up=l_q(Vye<>j,4G]V@7G{1%ou+3OWO3h?8<趧le]`5VJRhJ ?عv0# +@YG`dY\F̂> qp0X]k + `*0YX0RcLT^]Ɠ_kJ̘ 0xS,eESu'ֆ'_M&Ϝw@]$~ڊݎQγɛnSpy `έn9y]-nGONXܭkŰu8+Վ 3ٱazA jw&/{'GNNd] [G8*oY0A8:;_ׇoxZVbN[/y9AތADBЮ "6vHv%@@E &?|mw-ւOq_W71jSrXR?BD7,|3y'KQbR=̊{2>wAQѡR|hvQ]6(eX_YX~^+ofpUkn4-% 7^x`$`q 4VE*A0mmI;F6 pћ7/L C?$+Ã7]pY#ڪ’`@!P'"NM,x}'bgat>E^A7bu})e +|49 D8 hE?vy8P7XN=|96gM1povdzS#K@:Z6H\/Mo jp13uYhDU0h' "37nj3Wc @; `C=3@[#~`?fiu7Q0g&lvT*! v K72[6ɢ[d˃yv 64г9f{ P&Vŝ +fA:z>?r+ ;rs *ˤuwa<6:|:xkG `߼ڵWS9(:Gwh`6ϼxNyw`km,EqL x'E>*qNX(?LJu@Vg?VEy)n}\{|û"J/@,\m] Auf]ɹM![.0p59wUcZ#]MLrm Rt7x΅~bd/^ [LŊ^yafp~~L|}ムɅEiiot?)MҜquf@?i6/M|hF_^?)y3-\t|AFoV ț +V-҆EKST=@0a1Z;Ps ZmhRڄb4i(٥R70T6O{cRq!f5#8hƙ[;/AAIZgR%kV`[VEyvy _}/FxK o(}0ENmh5ynayP.)!9FH_  _X+8\zQ 2jpxn Gi8볜 ,ę"ا.zudZklL`Əkr3p=8qAg{}LA]ӆ7Hbǃ8znyT}hb\iը8 xl~ز4mz*[usnE[nQPʁ.s[Q8Z|CPa +mWoJsmP%݆Wdxg +`^[Q 5;3: `5ˍ30AU= 2VL'@Y`;l0[[oU=8n L  J>rq RI1R:} zd +VϾ߇?NԷm$S(kq%~0' ZiP_TYfF6:C<[XU85]}41&ϱB]H` RQax:s0 #r)i095Ƌ-7^1"o@1txƷ0n1 dwX?4/@}C˖v U ]ݳy?W +pkWo'N&3V#p}Y`- Zm`W-7-XH@4@9gZ+^`u`( j^JdȤ|21aU@ gOM.PabB [dy/@JOekE}>j.z<)w.ޘ=k-vV_;ɡbbYj+hacQcƚ(jQܫJԺʍZ>I)Ybt//;;һp|McЃn<, EˠvXn^ʝh^n{˼Ek78#^YKc'ZFw݃/x$KmTm4:-#E{Z NyՎ6jU7RkpƼnL fL2őj` )Ҏ9>00 ,okOԹ;b +b'7hGHi{YW׽w߶,wy<~ۧ% 2hզ%_swv.Ó)01FmFOc~UY?~UUK$> z7 \U%P=u^jx#OY*Y;5ל~΃ꑗY0-Fu[y}Rj{^ TOyux7OAlN0*]ÃuՃrmU`x` oKqspSQX}⽨jNnz[G;0;}`xP( ;/U}~/isX\N.__$dxœE9]u(G{69~ǠudG 9UozwnM3y,, ȇis:mǣvE6wEku2?I>MѰ5{m{&_Autc&E.l (["b @\ftٗ\Q\Iu:{29nxMcpEsN(O~our~_yrmcﯾ`i2q=Y|9L2{Ja~cgg&XEcxt͏~SV眨TwϚǓmp7?ecbr˿~ "k&`vL烓W/^yw ϟOm;8tZ^|n~u&[oLpx痿~O=|Q=^;z9~9zSj{a|yp^^>^yM7UFQڇ Xw?ٟwuϣ׭7ǯ4Mutۘ?5y9o@w^Ϯ|Q]W2j6~x?,`,)|~-RƩGg?+YZ>Ż8{/_Njl-^U-o{7Ko.Iu)fhwu{uWwi9~3 HB@ }eyꇞ3%{kg條`yUqÜaBrԁ"\"R]]^X8xBz `F+zK@|X* }oHq%׸JDsBjjA +zi(3ZeOfݸe&7GRVvq 3q,\=x0gʳgꋧ+Z[kG|FcQH'jӇĤLibk^OƳSZtsFU˷I&t Hظ_sFs3cުV]΂!e}ɮσ,T*qLj lrq%hA59^e! \l.Y9KjB·+nexklKk֬Oi,v*AJ$v:҅8pi/g,HvNRɋ {a>O15?'Jf"XubB ƚ^cC@d{Gp+ 0U13wHyPm腉n, +v[9\:k\D>{O8FyN/fZyի>G&}'/_MQjeS-,J^2i.l>OY 5kS}Rw2 UWϛ= +hĂlF!u)݈f򼚟SVoIm:1MI.Tז/H\c?Dyhcjalwxtxe1r҄RӑzyG~-Zl4&{rSJf]8y2Xb +S'z;<3~lnTo +r2>&&p5Z&v8x?@)!{2P."ēZz!|3'hE[xHV]:ot*: i->^<%[=;u8{>ZnSL0~0?qQZaR%5.%6Q7E)ű3;/NZX=5qTrLǨ-Eչ?wWau8PP@y63Rvz!JRvM̪RfލA>^p1`d!=DŽܩO/@U~:nlVѻiR!TYQ˫VyCNDSx` Un'铑Rv &(9zq>,t7L͍ 66m +X6{vFja!3y"䒓\u]'>jCN +-r1PӹÑRo?} U}$=VT^FG@͟.-^Fc\R fX:3sn!=D})0sXs pSzl xa2cjvhm&gvhOJ\OEvHcd +VH)z- +G41b*-L-ZV|P݃j;o^Կٿ y]*gbZj,\xuq#3~JL.V$zh3X=t@t”^˙0XeRFy)7u(NC'U3@6j[Z36"\HC$ӵ"D 7Fx b03A(g>]?mw ZMRrCL@w3 PP} E{{Wk\.<ԙ?7HDbbGրhe&XexeLaW@ނ9ܟ#&fxX`+T5cdTSJCE`99\2;< Q@|jŃl HXi!ޟlo%:;H" ]ʑ>s BdCW9@7GhH59,K{p! 1 ٜ| ^$\L85$JC0!nq",nʋj\5G%}WMiTOVi[>kyZa|̉0W㸜4Ĥ`>/%RqB,8! "jx"@6qyA\Y @tp!V[Q3vAK^8Ix-/a+)!ղ$: 3 v_k< NB*-/4 ZHSVȏ@j991ί +fVDdb +ۼQx8Hyvќl@&!^H ŻBt?k1ߘ%Hpo "JE!FgC9@%* +Z6U_JVpم. +66/ ',z-Rݨ/LĪQqBz^s P3 +vpVM&K3Gjs'rRJq氓IB 'zA @ +m"D-B/ؤC +z.RKNX ep&兔QP|םG >6\ $fATQ/gv 峬 +eS 51BB6 Z0d11)ǒc .m v/ K.%63lFSrJ01OI d'xF3hpa50mMEɭ3OVwdJ-jjqp8X5-ErDl`G.<8&t=;$'l(RZSU#sE2JA.5eTƅtMHU`IbH\an)ҙɆvۼr3.a#/#R֓\SJޘY57FK "n.f Vy,/8ł5tQakJXQƎJ6Ll'~#0->΍ ک &N'` 1&ǁ}&;Â19p@I6@HV2RGC7G`.Bfb54<*F )Rڍhug FDAjB\tP +VbCE6RJe9Yӳ]=7).Q GplB4nrehcwqRJWWEˎa3UB1ۀُ +pa3^zyؚZ^xݐp f"wLZjZY->q_xgٟ`Xgksu a|Yw@y &2p.wN]}/=/pѳ3^x]o^c|ߎj)b8*vNfw;|+䵟O>_ʔ'1Ptjl*_:Y B#16A^DAGٱ.޽}Ż{m\9noFszqy_z'_{?|_O>ox׏?dkӅMWU5g#'/tG[+o?o~|=O zleb#Y\2W_8y~܋/~7_oI_}<[T-()tڞ_Wn> ?~卧_|^ko'|_}♗;Q`Ah7V^c!`Z_>|=w?ݏ?wg_y7?oşy߬+QRQH)$JQmM/m?tƽ3O=H>?O ʿ?Z/xyGmZ3 bY|՗_(dۏH$ ˪!M/[[\Gy߾ѯ~λoW|鵷O_jXkp*F,S^]^Xv[?}w_~p|_|__;fmWK7`Q)=||wk_{͏?|~__~O?>{|k!tIz5BņzRo?Cogw?~}7ǟ}7|/ҏ_~mE1Z PPIM4>~KwWÏ?կo$;?r{ՋN ^ +Wmǟ~W?ۿ?=Ͽ/|Gg|87&#>BE=F +Xena=/w;7>'~{%J+aOt{90Kܑn o~O?KkX+U]D)U\35>413p~ʙSg5$I?Վ8 +F0OvZژ?zlͳw<|b{fAfX5$.}O#IέlJRBf{}c7У}ɗ~񳧺9}DN9rz5&ՅGw{_O?˯zWW_}G<\ީȱTȍ#vk`s{pWo\}W^󧯽__|#[l X Ƙ \ +F$G"Jely~#=y7^㏾˟}w/ endstream endobj 109 0 obj <>stream +K@PIg"GLLL-.S(Iz.i60A @[.vHG Ğ DWd#ѼN! AJ2"ɤ#qFvgF + LrEV2㳫dGsHd- ÄD ZXSX<ʔkcS EǚJ>@!Dᒷ=x!TB$x8iKh݌&$)>2I?Ym7=&װ{ A +D_|n95jbq36Ӯe%?v}ցA9I$dXT2!=Ob+h~?j4Z8Tڭ^{ZD,)Q.rЊXQ;0JQ +8?Det[>ߜ>*(1%K)RF)qM#|cqyeD(ߏEcdAd84 wXg2yNg@ +b&SZ=|$!(S+ Qܰwвg2`Z,tTkFŅHH& Ԉo`$yǔ,*tC0R1bP*6lϼoN CY݄n5^qrgㄐ0ET㴬6 :<~ c\NNtz؂bG;Y\6+~̱F^ Fdjbs}[?yzEqN'lH#,rF ه6{C# r%g@q9+UG,>AyQCE U=dIؕ@BR@aHNDlG'Bhy5?~\` 3? ~H$c!JtF{`67 !A^Pba'0,Aq_4? 0IVoFgp704;,ۃh`vd7VxtW@Y3h뷵(&)d`2}#ށK"|Aq1e4<.I&TùF 1viq[Ia} ?D K1jAֹQV +\60 4н̗dL +>6h2lz aN$`sƭVԏ@޶״gb^=!#ܾН~P/!NxAz=#> 6`|!lχkC&@s^ -}CQd +¡hq/@`3ِ}N!2&b|qzK8|͊G}0̗VqT{>"=:rZ;e!2V8dr;C{t eR@3|ip{f\h,_ɂm(ox+uVbqߐ׃ȌC v'} hוx.LcBP +#-6҆ [!mЌލDuz ڿ!=Onn_<R d(BkMS"erXPfZ3\x&b$@v v.L'=F\y咣b  +yϐQ2hsb7 # .ƤG'T܏΀6`ݔL +N0KY6#N8@-NzȂ|6g k|C7QI>#yqT?bq/iɍx8sb`XJ%] +~54Y?SX4[ݓlCǑRڇNއh"kJ)%F.(YP GG,0@cQ/\%ŬEZݔ Y "|o`x :3lc #W7wV*TtJ. >5IV{m̃n&j1&/D $:g̚|2$'$Ml +&1J)h c!e\ +1]5DUbMp.E.XӺ\gرg XrKE 8v{ &BF-3*`T-d?a¤Hme~TG  &iu>t5vphT$"|l}A3drb@BL 7xRSL}^Oa2*`rM>0>qǐgOyC[x-8 q +m a(o5aB‹F wF p Zî e윗{U,X3;VyD̓1M9=jPfns./Ao@qQ+>j']ppjwh˼B褳 awj,]j@ :4 !52q̯_ܹ6dJlROӳ =0v2J{"Tc+l?zQ +3Q߈cpbcF#?j.% d abQMQJ܈jrP$`2>2 y!2 +QI'fP"G}J1^ZfԤXǃRby' ~rrK0IKH}Qs BtӸlvQf;oS=\zІ8!>L3;H-6HV{F|#vW:OU.Ԥ*==Y4\O2m iL.@TT2`oCFz:L&)M?4ja.:6۱Ag`*+E{IIY\7V9)) gv"{/cA|L + Z I:U3`q ta"Ba +; +.-__'a7 n`xUڪrK73sGMy+TZ(-mRERMt)\i-?=%e\xȏ)Qn +pfC,Ƚ\m'Zgm>} +RjKzCDGȺА^GN=dY%d'Q +KsVeTs3\^a@3A ΆZa^o@Jת@^fqnDBPjrJOa?oXbPS)T)&V|T| +Be-ZLlqeVaL +$ؐ%00,%$VLW`)ǺTi\V'ϳa7 NDj9ƹ/z +NoToVrmh`pq(g%Z+Dc3R^7bM%=TV+ =ЛBwz~ [nv؎ypHyv]KvD'R3!;'u)n9u\|裂݃njA`LhF{mq.(H`cfl~XX<+Gm8b|<=x)O3B c0DfIBkMtQ6B5Pűԉwv(NąAow@v,n߫N} SgOrxi! 6 r)O.d c hm|hd20PZ5&b\>RXt(LRz` [0XJ5*@!!á}n9>Cfh>:5j,Z=Ӥѱ*h)MSzeDb ;"oƘ//ũ=A+jT+đh}I<4|ҁɡlwZcJrP}Lum 0!$Č."yh+vIj}mhE?DłIQZv$"e1)-*$)Y%+sp]|w<%x"c4Tn3zk#V:鷠DpffKS!Pw?Y<יP;Y=zfOԵ` ÅgBF`ag@փܼ=WG=.P kUJ7o`bb +Vx +Ț4И>Pد禤,6b |l0}KN^Y܌8!uJ<(/y`om`&q (ȀA:pU&dVBWʏT}D$RYH<;QQ'.A-ry:Jk> lqpu>4bw`s$uy_lϐ9ҴĽ#nL:؆ib9|6uThÍ"+r)ܙDj_1 -p6!E[3vHpc1:=L.r,.Q)^߸zSL#OڽϐZԑJE?cȻQI>㌶36 Fq/cl<_]9 Te#?v/pŔz?bA3 \eC],,X $,n ZzF/Wm}pz2ru]0e8 YYpn@8@h-\ZNK(>\Sc6/cRzfcӇ,_IO;}0j?"zG=v5߀73s"Wcӄv؇HV꠽s92X묞)GeBhbﮧs"%fI)Ǩ%Z.wC&s"W]>!0HI9PAT0hq\. +*i(rB&pe :ǃ +:f0.5lb6',dR*FDj\EIUX^+wkSdq~n\6s153jR3skLyZ Eo蠬4N,x=(-9mwnr,o]ӓ>qdĘ連냷:BJfg 6@L@顊r9О? .`q~Fkd v8cRµJi|˝\w?lƎBkU91̯erjĜ ` j6 dNloZ1ch Djhybl .Hi'/Z~NLÕB{k^)U 4x6ҡZZ̞W(5rw%MNRb.^];r!iA0btD KMzء2.#fr:q )a2>ʰ +T̎d/V]RSZa./f)r=u(ds @Dwxvxjx=~`T FKޚoZ b`O'ɕ~#v J.c|r&QШt ˸XEÙ݌I:px+Hd0τJc?~Ak(lLsݙ;,9Q/zy.`&ku +V{!bk@ { :F͐ن.E) ! Sz%R\6k| zw#S[e q %rаg\˜Fkr>D!mAN0ZQLF$!)>]l&wqcnCN` ~D%[uA aR)FKa\MfGOv-GFf2̐ l0 $!q.A)L1dF9奿t[*cj0Qcxqwޱ[3<0}V +rfܴj9H7хݻ-~@&[ v|No"M|¨eQBH{]BEXPa׫jMk|YSJ5.t[dr0Dø!A8~ϙQlv oab`v/}&k_H5VʄPR]1֚^;S8TPzvD,?X/;(|t@Ԃi6FZN ZI/l^*v}lW`Nˢ_:kBd(=JN2rE6p ^lϐeT.X~wq2fsуf/ z#QYȨ,vǻ0+`m‡!+eVL OWZ9pPdʲ1@"HC +S_P ch(9ar@e~ԁف2QɎP8P\VbbTעU([=iU'tV;n.:Ulnz`ie%k5XB? 17f *+?'ҫ|j[W'7/hX:q0][RD) E0ʦ\hvQE]ӯzPP;`pR/d0V]=Ό|D͎7W/Y=#mOLe}τFp7a(? Rv|=;AbdLOPZ5@]~![Y?/ +\ +fQUT 3r"l.Ml>$͇wxhiI-?mK3+P`=B:&%M~P>Xry9oe41[q: (;Fn}{ wC gIZ/é݁j K )9r'rӓoõ׀gdCpqVL 磓I|b3Kgxx`6b]M `QRH_&۹Zuj'S=S-D̅ˡBupb 1ڎ$:.zʎz$LgpZcTԉ[kBl8jjNJLs>E)5\[[9yb-^|:@Q.Y!6@Ƀ:&@Ѱx +ٟÂڼ#,Eb \I'-kMUYJBk6aKA1 _ߴQщvg (UJDY#UV-\T>F4U-X@m/D >-tM7nf##ח+|fWN{A]IV0JTjN/P>7mtdg6,jCހJr3 X .7w>eP&I:Ґn=ӌv{6|{8yD΀ ^FK7{}{L$ZPBqVcfM.Rq: -Zdqr39`v"bu9ޓuZ)kn†S|' h[KeN;F|fFi*&)٩T{wx>K.\AAMfn&pOAy2@TJ|rj?M4fi=Ad`+y q0jEe1/>H85cf'm#lRKL|VSZEȈ/% ʸfc̼lݘ;`ikv$mgaT =:ivG+n3Ah!'Gǡuf1ĩAO@$R&Li|#?\|G!d\p4F $q!K)@]/&`t {xLb 깛_xy%N͜q t{hz嚙er:滟scnK~6S֞# Jsl80&|Q pj~:qr'5kI%^8in>޻.e&1𠢠AmQbE#!KjD$ , ƩPoI)4v35'ҽ^lkRT3}9t?, Zܹ@šn<~㧃d惷c:4 YvX~w jT1!ڕDgy'7{Us68@E=;0kȰvQ^?nA* !\ gD m8Xon%^)D +@u 6HAYRW.xֱ.%=G|蠛$"i\N LwCQ+LuP jݼr D͏~~âdu_:TUs^0vb٬9”9\TۅsðQ)/j!.B 3l1S (mƋ}=!1+Vq`~U9-y+jwm˓B|?V1wXvFbLt@k%ZgK+k'{[fο[}woun-}??z0$u?,W~4E,FO$(8F-QZ2`n *!1=clw6ʋ'^ܾ_[{nqNN]|e܋#blБYRȈ65L M~Ƈ!&_8gfť?ػjf0|>ƁנA)|\u沕_d QuGYRm+ʚ7`Q.6d!ƅh=ZKזXhT}+tw\TWf'nHk+FЪ<`T>sn0ǽ$)\=72d޻ǝG06.>DZN <{buYQK7͝"c@<ŕTݺ t^xqժW/fʆ[ظspe֪iln95Ι Rɑ ) +84df1g&Ds8{!5yƮld;k &03FsB-g/$)w7H̹Ht +.Hڵ0y_\"?egbiٸwW#AKeCN%L. C)3@=y!bSݱkaG;O/x4Hs /|u=,'hB!3+P<5_&. `HAU}VI_y;/0+jr:Q]߹}{˄\ 7!İ[Ϗ?wXؼ'd<D'=#o0*p0I1GN{+Y,Ζge>{:s+??Zoރ׾nV~9J,݈Sovi9 qA`R xrfc岔m],HcKSP>tKi/cARehO qYҪkyXfX +>I"@x AөvvVegUTk}5?m:;/p8"5X/A:dU1%Ŭl7B@zyj)?;5 Vچma$iB +`0k^ε{oOoވd 0rq壁OWӕHzjG?!lPe"`P.JF2FsUlX8x\d>@,Fr<{z`""lLG)3W_"o=7:k5{֍o3rtf~9C-9&2\irec0L(B<~rt >q<PBm$".ÙmNQDRJ/͜wZwgwVfvҢHWw`U4,%H617Ep>#Uɵ;7ߝ:~n̯~Jf61y*goۼ]~{\,%./tFcver/2JM) ش;//S?wbmrW/?z/VYη7/O6.Rgڼ2F kFĠ3L'*Z#6iĕ +c6H+0Y0 1ZZւS^Ul +81i1z +*9̢iqcM@h3W3'ݵ]CH0`:͎;`"B +iٙ /Ļ}'$K VwZy朖4vQmA#T`3U'ta'!~T*:H:>y:q(eCĠ$>ĄȠ'/(!g01&*`d)2jHĔ)n,?ofi+`-rz QBrl`\ "@pG'N{P0= DWolg֓F]lҕ~ dhVHMpqoq%1OEH^U1m,%j+zvdA{vN{z{J89gWd>^zgս^ݿrgͷwZkwgww$(ݧ6GR4)%Uc\ufnћ>w߇4@xX.J:se;!Wo?-w9d +Ak*rBM[ PzSB/za^E3j0 O Ĺ`D7jADomJlmwQH̢B>O]e`׀eГVns )`* Fب N %:jfV|U#MOXS.D' B)m0 +T'ӓgƙL,)S.TJV PG@ջ1:Isb{c@$7$m%n`F R.5"0*NPrCAlRHɱpwKrQ +܁N6T5S653]ngJyn`[ݷ'7n"Ea\ &kgn+>DW;5ǻS+w6!WB7pc EŹ~_WÔby\kH>*<50@8B.^\^O>5*U!9Z\>|jݸGߵ=0'a7 01rx;wڭWc~~5vdЋDB3.HR +熨l*JZ x'R^Q2}Ԓ9-WОOs&C zOBlS>pnb}URo^qQܘ0atp20a1g2-flR.^K#5F㦤^28x-vv8--^h:ahdi>*$k4KQ%5rfm|! c D!|,Q ͕RmP~'f7# QOBˆdI!P0 Lh +)fv>RZVb&D}L0ʱs )x3]~:~ 0ҹ\} AT +18Ì OL"R( +A(-=!1E:\HwH G,,P$ rA%"8cBp:.yITKK@3i 0K^\3GCmtp`JLb lrz*LJznnE9-uΚ0kڢ/$? Y^K]4! acJX딚ǸtX`c@P @L?I1()#Iu=hE3K|s8 1Ni:R +#儨eHN_f[a +B8BmFS2`8>0&500a[ +$E"6oUp. ^bĤbdqRx?M4O +IbaHDuoDp¹$h! ^ `" .T ۇ5ITi!8(5UWܜ+%!L75iILMٹuɊαhO) M3=EIoX Q~X6AzA*ca H j#M&BYtR=!X +#F*Mڄ9 I%"~fD¡0F(m\ pgGc('N`$„CE0kYC4F)]QGG# md482M3Z4" f>)! { K\#d4 +;Č`VXLwD2ŽAjx<<rWNnRBqOq:J(dsڅFFcc^g8`j4f"O cl:eXEDa|A&%%yP@x VDg&D7#bLQEDB@@;Ctx@`6%D:] #<YJ:-ΨXn9 ٴȠ G1}nwxbav@DD4*p D ")UIJ`6B q|Ȉ7!L/+GPO.hfnw 8m''qA\PҔ` ϏQ 9=}bbwb$D3$nIgo$mBB8S цt!X(GǠsaXAix}Njx{t4"q\XjԈc:6| liN W58#|a'H 7dsgo=7nD>qHA)Fr2d=miǂ? ~i Q1m'd'Fi#q``2$(p')r$o!u?1IB1O4<2EdfGcN|,k1BA<v![JO꺑ux3< #sC=?7tC^IYFH,Gv4ssyB ;6rX~SY@>=4s'O'ǎ{ sp{ O0!ZW(H\EE9!b1 " aObTr\Vw9uf7n_Z6+vC17Lw$B']YZ&kUی)QKDL^]wcT GmIbDbHPN%z%gC3~r{ɝsOz{68#)9a, +لժDDvt.ARz%W֖Vir*!?<2;u;aq#?Op*l EH +!ATŋ[ݮW64~UbFA%X6sB1h ;3T+Lg^ʽ^~gI'B@D~ LA0bc$7Uѻec{ۋ=ޫgՏ~s]/ꒌ&A ,l"bDjrZ+SR]xn=ߪTӉ&3H?: q)vc#|~#rQuutJ.QΧ19~|CO'Qz ܯ;gz'o?'zhge*p(=ALxV*ENp3w߼wz;8__=.بrC40DI,\G+o0[}?~v_Ӈ^X9idSH53Y~Xxudtm*>]}|7ݽYU&q ܣq)Q Krڟ1_'w|kهO_S+Gggb\Np;k/4_}W?{+>_<{闟\A8f%Hb""N~g+Ż_{</ׯ}~ܿ?{/rM&t=~RJ*̍7f\(?{~}ǟ?k?ۏdgY z ;B -+KkiR'{+>|v'w2x0DR(lҳlA^V߿̓q߼w{?{_[Wwfs$R$h"B(\{Eďݟ~gۿի>_Gw^PdBhqTlKmͣĻ?~uO^?/?_̗ÿywv0([7:ZCb~b\OׯG_}o_???ieP c+aقЉ:>y۾ybG?{wVɭճ'_~zJeO:r/ETQ+/w?|~oo~ɵ߿9H,7>9i={ugo~ʯ{;Ťp$ᢢu#1-hbQ8K.XZ%MäABJmc$ +mS6S]>м{Vo?խ}ԥbIvDX`м^rdHgZB}quͶ??K]Y)<:_}jK\:3/tsb%e倷1AsBB2RT-j=va&{ط_?==?x8{Wv"۹},JJ'1: +l w@B+uzl{o?^O~ţjWdݏ0ʡ!? #,7zgŵqWޣO]xlg\ _ GSBmNtέ-3ǯݸ׿Z]>3 +zH1蠔1 D'Q#*H +ZJU_mFW7ZGU0L.MGRX}!H&jEB6^p޹|pgo_}p]^m^Y0R|<ac|MTIӱ9r4kXɝ/޾굅[N,bc-\AyI0jVcKUwAma`|=Oޝ0W8LŔR<?;:l42(r\q +2bҩ$㵸ٌB .%II'y1a0&%r2}~őpJ!YϷQy__-lץˋsәYՖ +Bު|hoUZC(qだYMh:RQf2jYǒZ]O)J)b|3=6R )afp(f>XC0$u99p%c\l5Vcq"(´#G*PlR!28m9VBT܇!&D9EDdzfE +)&G&|? h0qj$x|7 :[m/,y:`2J11QD#$#+0mS|&DD텕q N/J\@/,1]O c7O@MV)3JF]4-)FNxxDGRrQ^IvLCZ@:=3-kٕz| ;1 }M`h-)ޠ|_ (syO1F3Y>e/"RZJNcM\;8&݈FmMB.jF-x vN2fWF7sC5zfxeU U<iY3ZiS-Jxae2ZgCܠy $R!G .H#j oHa UZrCXq/DdN+2F^lX5*5T@c&!AP>Dw0j\)B|~$'0Bܨ rJTk 9Z)θ_ `vLA\0&!6yjCο +`D\,$cT`L/ . 983rvYJ-G,)C!a\@`HO+x)5Jo+V-KCs'W]}~7tD{۷< UI݋Vy=:Vv6iiޞ9XB.̍YZviX<82.H^8ɏJÃ. +0Cwx_Bm0L\o3@LrVڗcXQu:2E!QTxШHG.YU+<Yɚ]Zo NjG 㔛a1-!cZj^❩3ka!' g0blkdFVDe ) +. 17;`̯JmG 䁭QNL" O&I$R|VR PZ\lVn6"@LJszEKMQHɹtRoM?!M/_ 1+rig5hCf~ˬݠ*medTg3VeKt)6gX(;3Qv98S.efkwږ;;˳OLXtUr !>ZW_zK;k)qø{V/Hy-D\֤2QeV)g28'#Q#b/({څ iNgr'=a%DRk4aa.5U4R>4fbrYoG;uj +X V{g_+|闩)7TZ|.&gݰ--tFq?ھ^veX "Q]'=HHI>b7/JNlka>DΡ]a"=-ffO DIؗ] e>2ev.?&ZwDJr7 ][3Iɵ7_W?=bӀ"H7~$C>@8gު+ݞ}%5yxyaO{Ɠel5CiHu#hpNv6i [U +ėNX{tj[Coj%?{c[Ʈ;\{IaMH'@Xjw}HmkFij1 +R3ԹTm%ه iHʘ$b]`!EMz69u#p3; ̪̟y,΂0 xv姻ߩ,\6Rԙr_j~(RN5wkV.lW+ɥRJ\čy\iHERj}c}TTJL:'^~j{!I)9׻[wg_;¢^<":x{kcXUѱfyu R|DʄY>fWbtJVh2Zv:3{m7RjrO--6,gʩi$eKBbFv H,+3wT +ZWxz;=T=JLnp܈ )\^ffTg0iB2?lݯ.L]).#W2ϏJzN. yf`vNv xȍH IBipDڞx7@RPtCDrsj"# . ^ r33Ne-1RKT7>MWSM)b9csYZb-%VmWm1)L-˛rQ,97.\|ݼfܛИ@ksgۛݳ;wxI}8 ++[ y&Wݷ viMH-JdhFjn ܪ(&]>j#n;FsB\Fa'*%XR{@J2 A9.ǚ[&0q{za%@gַ 4*fe3:mfn;3Ũsמn4RBmzrP!JM%LgJJ$?Pf'=-o^xun5.uU2%g.>Nfd"?)1qIQ Vyh;Gfsnj;ʂQoL_baa e!jO ~`Z^2+.ǁR!*\.fur%?iBv܂z)H謒:ZNA@vs!ӹ:]Ȟ +>oU()UX]_1$7w6BL lc-1RZ3IwV5 $b,,Ս8 Ƭqf=KT8$bBOOBq HVJj>l ?(Llcvq^=۝ػ +J{]FzYi*ۮ6nz:劺Aq]B$@} H'ꊫ @S7Ldd\?F%u`zf87CO}dt +W)| OGѫ7nˠw 6]H7G~zgc>*Y򇷠B?}k0˴֗sp?{ښ&wZOj?~7 6x;qm4ڇo>'?NZzos_>Vg=g).bx/c3/;HG7 N\(+ln_J楚Z];O7WJ #]:ӏ8ky=S_nfo9.(OH:}h f;UW@R*~~3v_'݃wS:[~|; t2k+ޙ+>(gnp).4AS ٝK9ףɋOj0) P2#V?#ww[=Xxos%m6yFȆIʸ +Lbu':^~ɨP } Q2EgN<@ ^SJk(NZДݥ?xL^bBĪ7 y-ZN_W&%֟SJRBM؞WJvz~Dd1Z}1ZltۇyO~;]_})C[ۻQm6y6?&ފzGuw[=Y/}=#D51ζ79>Byn<_~I A-%\Lv'v6{ӋW0RX>1x7_`kav3G7ϟwpٗY8 7sgpb#Zs5:`1&%mph};#}YC%g/@99g{C}`U`v L"k%#ٝw 1@hN`!x.Xg0zSf + pi͌W8{"]lt6+m>-`A #T.P.0@~Wݫ zofvv6j߀ >O9}B$J{1z.8SuK9VTɎ|k;9t^kl~ޞ : o_~x{N6kM/׫g>Aٸtg{AZMξ +g6pK0 n4DF7`M8=5¡Eg +EsBAъY4QƓ.7݆L.@Dž`Kf2Yl3vG7Ͽ'wuOSdi5@ِR3/>xt^fA F_K`ӧ/ No"#JmڗALLUcsJ=DGaTj$X(0ug5$H5\iۼ;-^cZÏsXЀ~J,BkW#ͤwy +fb|Y3fï7%D]?.nćJj]g+Zh9sqrh Jh\KŐکsE|rORR~ms1LEu\Sf=Xvff +yA5xϾNu79P?y:yn2]0Qګa&ӨMlSn`B%ew +=d609;HP洒rHFZv{ӽ$a lOuojgpt]&[hZ<r7ן|)V/LUh[;;VktpQ[(ㆃїv YcXW#Qoq:y~7^FZK ׿Ϝ)$16N+ `H4|::~xtcq1L' k J=?/*${:BVd<"??ӣ <,WUk<޾Si\кV --!^~o]' +WA;g?֛G㯣ѭG0Zo]r"M/\J7ZBJh O>3nɋ_/ּq^|^:+NBAU2r(h͎hi6zv!%ofﺛOdoЖd_<.\FD +htuwPmN4G~ko5Ah~4 ytS;WQ@< j}gclYk8_|V g:nBFatʈ_>|+XE4tes"=LO` Jucd-p&1>C68OWz~ 3EƢ=#>&W?CSTuj8aҳEnKBITk5vKswdͪ-۫7=Go􊔊2к?f(i]&7f[AVx(݄+F0!UxᕕB}~eΙ{RluΦ?G7[zz(@ak l4MIQ[ cziw)o X%ׂ^]&a ZNJ֊)eN5Hd +*pP ]Ǒr/wZTQ۪S!!I\R9*BW{ ̨!䈗1R^$?o-~wOՋOQ֗!ϟNh$⍉/ꤳW˨)ߢDfu'39*ڃ~Rrљ)2_uB+:a6ڻ gMAၬ庙ٷ^ *Tz6 G1Ư7Ĩ/^!2Wi##FiUPUࢵz^ b\\cY]aL93ނ.-$(aPrfeb%NG1(J4Yc 6@`^~2="N +wm[<ꗝïPN\ [?|5:׃׳.x2} :n~xn)u$9GՒ=yk%Xjs}N pSj] ֟w} ᾙ JAfaԞP[Dt A<( yc3;? +uʆ_ŝcJƓwt_CoWՋ깠e>@m"SM + +Q}?S۬uBe +GoJi-RL ek՛W`x`80B(=+TP::S 7i毁 +n4 Zӛ|t"*Tj +&7;ZgڭƓ=F3je"6LJN{'C/#v2jԘ&='hwL껽2'x1Dgn тqkt#7gA5L F"l-8}3x+0-T5x6SV~ 2F#^iBqC~cNN$5[[3?uWjzLY:b 31Vmyt6=o5A/V2HJ"_hPeq֯b#`#yK}ω"1`v@D6X]w;;Og5-C fNx=/R)S%DmQ4Dx0>6p%ほc0Tp jVd} YCJ*]Ls"3QQ r!f Cidy-ea1rWg-7gpY|('8kRTqQiz-d \jh<2NHL"35A\u֯gFc!ҍXCɅ=^B`uEuꃊ>ǨHRgЉ@NrL6zΥӾ2AZ_ u st.I6PS5ב-odwhNQWh?]tR <v6D#/>4ǂ91\: o_ +XQM X@Tq[gxt#wק~yw˭*AyNL֠آĔX1-n`I)֨Je"kt.dP&q^UaNV)Z>HFROJ,K5ԄcO oߍל,Յq8Vnc+ )DŽ`]L+cxf\1py+ /%g8SrT|]Ǫ!7MUA9! 8)ꁊ{VzI +(a2%c$!'`XxwRuua~ 89ͳs#Ha\ જN᷊3Xcl۽5ғs.Z)ʺ S{#_cd5$e3J⧌) @nί.`1~0\$a8_~8L +,yo}з/$f;W!\ƚ3+/ ٴOX1@j\h;{Jܗiڭi܇n/̪TC!Ŧ߻oQ>17gDe6hoo@oοUc_Hԇ p΅dC`1x/Ž*SH\Ls nyR +&➷i2 a#(}0q9m_.s +Gr!xX}Y +C{uZh3-oF?~/ €> CZ y{ؠ*阒;=>.f2FsZl_1J 4!"BL` +5xEkPB^BanYcS$Slִ8_E{*Ą7 +&9oAt)X{ +lJ=`?\,\s3?|\!W6JiQk85c:_Ǎj)J[`(! ê=)Q5D-B jt޺3# Piŋtxq)&NH7@`*7D {z7sLhqTEXo&2]0zj9H +U +B{5Џ"p(s&c;>FXWfANCClZk4hmUFjqf_jS"kcu}! BDuگVmp _j|Q*Xqm TJ9! ڣdeJ$aa!fj}ANH)p(owŵJelP.FHo j$sO_×Zt L;'7**E:G#O['[3RM#Z_|wJ1"xjBL0^y0z\ЊS7K߲ Ğ2(>} )C?m Յ;Xɺ- +P©TM0-%mF&N4*j=DXA:iکW[ړ5*(>{jޭ`Kh ƜAߖPF {gٓn_e)!wp>!U}\ãI<ݘ3f6lpQ0+Ϋo5:(zZ| +HEhӾr:`: +aHioόO3BjاJ ED8kxss;=KG/d#mJoNY op;?zr*So~~YZ|+ )PY$pi Ltп2#FZUU{yIf׌fawfEӯ@.uUs2;uWEVl_ Jl +PTZzʛʼnH+Rʪ̧3f0#9֣UHsBi):c-\T+ +!#0yg,J%y;D{4XZiAcN\-`MJOfiMm `k'pؒ{'Aͽ +fw .FOJF/ jۊGzm%(lXgMzU>})U"=7i@l]fLW#6o0qN٤s{v? HQ`š7.&WIk {Tdߠ, );p[WftPADߝPjKk%XL1P͚øw16 ݒC'=DHW[NXO=!XNqap/HMȣ:D0bnNpֳ[oLo^Ebl[5oNp1у f0R$j# ZHy!ናKťMes4 (͹UHRLdstƪcI}LcuP%cI0~=pSޚ@BQ^\ˮs +͊kղs94nvv ,yk A|A~ch;[ #Nd` 5h|JpAI*pRt9fk o6FC(.WC} !/Nl=7E[ ˙=|~m:Ь4hZ)$5lwRh"JhBpJ.˫`d-y{"tj)ՙ +)Es_Vz P' ٙ(B>L_yw=NUܩwg 0{}++C!*EFMp@ tInrfWeRoּƹp*s`J9FiҺ%iHiK@C 澗_ TTBŤضc@jl-M᎞cb ?&1ZGNP$bQMk_ͯ~/>(,PZӠ*_|fH `}9#LJ+򉑝yRaj jMQcu:=D6Bj△~mLp@2}}WucDSZ`eoU:C-0PέR>}}spY!Bt9VLWJmk{mGeLٓJ9=cR.ǧ]saBVyٞeR]% тEq XݚZ%Tlf +Aڐ )W;2 y6{._p:W9L^]#܈tP%]|O_޲Z&;l_@ug7Aru-s Ys?yo`'5XMic֘CPR2zt2B'R2._jկMR3X 7=,No)Wsހ Tp~sk!)2Sp ʓE2yXA +HKԺ5ĽW궯Gr3n]‹k}㽺r L0hqjvVC5ApgVHcs5"d;G~y񩐒)L:=q-)Im 6tVZGR ,V,!d?gW|/kI buF-Y4yl\DEaupgmq5\hiE[*LA6\W@.aug +s%1fRx_Wߨk%_%̟2he;;jƸ-Wuk0N(CZt/MJ;Q'ΝN Mٻ~ 髓w;j_WҦw0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[BZ_H/<1O샮%':]^-/>>x2iWdvo!uxȖG{l(8XhYzTMyV_دvq}IfW''~S[k̎}o?0HO'r_zE#~}AfMNiϯ5qo:hϹ+=?h˛2Gl x8Mԣ# AaXTۿ)~2p)Juxta^MDhc%19 ʸU<+*]BSЇ٘;Vpf S 2DsԄ&T2PCNxCmL1A;r[։jk1>*7DrJp hk#ўΤxt(mbSvFv e70(: 8!^ N8޳,(>5oQ1(/3љjnUqUлzt(kژ1漸;g&Bj98":})A0xgn} E c^Q0.b&.dU*#:t6(&]\(k53Tdavv),χG_`JN9jW5g.6a&$*al^.cZlSFr\j +rP " IEU9#:n~ (>Kat&B @0XUޜTep6Pg.,!tp͛S#b|X"q6k'7DKDlȩ^2bV}+Zu(U2.Ygc[LB]"NIEs>W_,*3]dU,MhѾ`BD>ZkϝSV9aGF_T0ZbnN 3i0ԲcwYk 3;~fJJk$'ZvƚSoRjnT5XeH@Jꈔڬ2 ŬNYpf#Bii{m|hk񾒬dMS3`6_4=Xs)X6T\F@1YDQީpUTf-3"vpiH)5='nWEs/%ة0d(0Sp!J5D4 w&bjpn/UŽРޭr ܠ B6`宨hۜњxR:.}-\R^#-XG@EZtzSr.YrL@ڌ܌Wΐֻ1$.lpܗFv.Yk 5^K܎;j(*:@HZH|m77-`lHޔw&jt`BHGޱS+?/XMN~l.>NqkmS@ԝDpk?-Fi:QJV<2K@%s)Ŕ„Xs VGl>v9Tedc!% BVZ83R *Qm +EYq[#: +/jL`u_c|H7Μ:Zg)#I m 5* uL +XpEHP{^9t իSrOpLV* \;eŒURzUҁ@Y5Q&\u }SB@i]^ёVb˟wҰ֐5@YNhJz>iJ ɯ~Oۏ~ &Ŭ=xxCt('k5:SS/*Ut? +_ OW?/kj=3= G/p tͷoJ@1=)"C a- X`#T1 4'叫dDwi۩`@1庻/'uVwE]: KcTQT h/NP{5 R UjʈWW]E-- aYK[Fw}OXXe ; NPp퀎-jsɚW}ew?:P3KZ +7`DwPSTC ͙.!T`3]~Qcj_!}y=}LL/zQn]×JPy?T C[bP@W0dC84hHZjJ:a QA +*0.mӢ{C3DQЁ@r5*SA:Hn)D9E٤TW1&,5@51`Kؐ[@ +冴[fP4ۭHs@FUEy73! ̰Z$ +!:!jkS[x4RArL/CҐ|ېI9 "x-٫*}GtRrP fnvh7U1hU1(ϝ*ѸWx: +(w`! 'cH* qkZgajb!eáhgŹ FvoDw1&*J8P6y;a pcgVZ`h}+=;U#p< rkɹƌ666-Dt:թzxL+y2%w€SrRZ¸{ * T w^)ES1@h 5BYM@ErpiY'=Q\-r 0PAjxX]9:9 # .oW AXQmTxm W += XV=/Cph8xXl-ca\Wl +=*ky,­E]8ٙ (8`$ P)f{!+Za됛dQE2RN摙l5{!:cR3?/ 3l_> +m`N +@t-_=T 7c0Ϡ[(^sdx)%!`(Ƃ+ƝlpCRI@!@=k \xFCW `(BH)c<΃ P:`@&Y Ib& +3Pv"B@$Ar*d!L^aX +Z +zB9x5Tub +3/f5(#rSKRErPȧ2"0G +x-з;[j\J [/N ^@hAroEKaB,<%Q\@8W6 Pn+=p EJ2, _R (|tZ*/`V\XVYhTF + GYݫ0=}{{e ++Va%4ӗ,5 dQnGn3N:$ |?Z72v'%`hiA +Wck/cL3RV!UڲH:?#>wTq:HK%{ɪ"PTD21D̼ozcH?`7 +|*5MPI 6y(0jd"쇉@Cr9=<sk]hcBi˲Av*쓻׈~Ԍ +ɲ 8eCXn՝R Ytp195W@:PpsH>?^rZ.lO>I9Y2_V3qjrFmRFqz_iN̈S׀͹F{魠sJm4\9k4w+X>A@:iT\NUޢ^ q ?XzoIr}?T&9WWs>93sa`DPQP * A x~ oUk֚>]~+($[#$#e2n4gf/_ҍEw#Cv +X5!QhzHcQwrDk c>Ԁ ? +!;|blϬ]ɶn9¾ m IЇ\G`"Bv/ Z)[)&M2iV,f7T + +@;< Ā>U`ǜM!BIhpQpGc\Ӛ@I1*Ej/4rp2!"R-삳 mabq8ȹ^,-4l *\$VFG\TX4mT :3*iRń&HӃBhYN\Z2a!7G܂u~h,eI!!ʈqNHi6>6{@/3eClzΣbCcJ0&]=AA~W A{`ߨg u%3:Fnr8!2AoCP0r aB \&H$jy n +L,4vFa%"PD ѭp䇙4D-*~{*RjPzC~L#Jv5qAADBC1*^q8mڄ}s؈08_襬 准B#;:lw#%XqI\h79FPӃ +(ѢP5r a* E]~ٚpR~0A QFn|ӨH ,HhiG.xN Fptw86@P +ΐi9S.2cI clR洏Jtg0mAeÜ^'2NԏF$B#nLk( &"f}t +@d|h|54 4 @P'7V8 ]nD*D:DN:=$gsȎah8BFEk|֒MAֳ{C~ u 6l)N39+?`CƀD0p.,@P6+5%2BeHtI:O )o0Dh_iK_#v|Fl+z/o )_ Kicbn߰?Ўlft0lE_k`GM +;}"/0#@P(5q#b1Nf"p:!gI 9V/{"Z}` Xʈ+ K@}a1"B,jPZRc䨛FCU?W Vm1ul,$ۡjI:dkCt%K+\auBz'ANz} ]jIO9h@>7慀T%@,@ubs~Dp@.W]J v'S?P}i: >sq mp [!@#^l)e+e} szyOHDŽ:Ȋq#=Nrr`2y``>H(0Ձa7]@0=FnހvQÐ\4 )PX+PPF) p/^+8Ш;=h  XMA/ &yLҘv,Ba𸛅3  )UH"Q΀ R,Kj(ma>v` 78`+v/xҋl~#~".%NH Qw@ +aũ"N ! +pHj+l:Ra.!iIGjC!NIO;)pGrxe0qc.PI@bep0Y`HHLN#)P( NUF_o9 FM*@,v7G27Ѱ;Yjhw7=phZ3{tlOr/)ͳZV E?4|QZo@a#c@#~bd ʑG܇iY=@Xߘ{ب+HpVӼ9ṑNygҷ4Wc͎WZj3N?o-邚XydpAg–Sx<f)=L$@zF\㰋洦%w/{:,eźl ([7@atڋhvڅ`ʇ@E >SSBkIX2>JZ]#N, }c`6 +SN~ n :H#cǜ /| \^aNGzcos`yB +`Mτiow#EnjoiȈ 4 Db Aa#,Cc(\ `PU/?ЂXl|+6XK*tZ)^ڿ7skKUg!U#&J#@NpТQ* fPl@kP峔=u_ a!#@X0xR@~H ՋI!X7bj +XHyXaOX,ĥ~ qYR!\! pQS@*otP 0(|Pʨu +SIB`dxhC! G&HZS_ܯWvb81 %rb rFBJ5iIzPTR>&( +2'&AT"B[Bt?0 <,'D&[^ \@Neco&%m"Rs9Jv +9R!Hd/6l"&@TVkA +fZb Dtl + q Y0`ԁDz0tDKb +T j>DSiR(f[OJ.od[Bb=uT(C AĐj;A. R~]?(x֍QQO"Xh&e F7AƖSD''47hylXkhMЫ]Zo%W)&$'XKh52ZYZ1%SF)5 R raXMHc!ڀ~b:^: 2 +)bM}>=/mSkcbfΎHz^,riΜ@|{0A\4P[BDc=Z7J.t"Q@;*LBIDu/o 6-7;e3Tt%@㑂0 +,fOҒA0qHM66ZsqJ-%2֑sJad̞^YRr@ɘdsUMA乱> ŅE!ʴH(2rD;O^ρp` o2dkTjB\/,#tbD{4s||X^V ]Q\sۨ1˚rU!QY;RڢVRv<퓁db- +'!ڤ" T6ȱCVXi5>g! 5I3rӭ\rb,$Cܢ8ܸ\"e.>%u'"zx#hE^5B|5.4A @+𖖍RS, +TƦQ_ӫFu nj!>*e6c}-lC & h)P^߼hoSfK-5O'ۅŹSfkMHl9\<؁* +mth>BLh*/ PIxhS*H|~H-g& -?pCgR3ʋ֖F0T213ՅF|Ǧ/\VS|ou0h6.].΅|XH\$=.'3Q87{GqÑ06Rd2lj` G##y ĉDrDܜ?e6zmEΉY97lfNě.L r/e.Wr֡L8.I śA8*ze%;* R]R}%7X6[xZPz}UNCI;\]6jBrP>M2p.`Qk_Qҳ#dkciZ0 (=~uuVϪپ`5R㒓Kv{bXy(.ɹLP}luLi{ǤT/ħ)[-je5;}"-)~ N[O{?e[CSsD5"aTQHP6WoҢϫ~k]fRZe_ٽ!ᬲcΩ{|1;fyry|Jrudw{ }CX$+NfzS͕۪3Gg7-VZG%G\u rk֧d#%F9V2{cjq:cv!Y +ȇV򳭥k"4Qck>Ц3P-}!V 3ֆY_vj{'޾ʛNە #!ޜϟ_9HH%(LC/t׮Lmz'lFʂ/1wӗh+L%RJ#X}Y)a! + W㇒HI:{6kˉ:cLG,G3*gTSM%;lO[zi8عv3 pCW/2kCL=vts%D+rY/.ա;wI%=OYR\k]-^5:{F8[U&6|u,ReSS% +x)V ū(f\ZItS\ +)BLB-,f8?u:38hhy<[Ib%45泯&i&{V^mƷ3_/p^>7~Ƶmv7~U"gťtp{{+'&N>à=đ#wɵOљ^HUU_8{k̝_=tyv4 Ojy15 @?!h~wg`cmpA`fy3+13Ա?_>)•TPwZf[ dl11ffչ#7W.Pfskp~De1w>OO +@5(E 3^\AkܔQܼۘr;vF-Q6꥽r͵sw<pP`.&RŹ+Kơ'/ܙ,p1!$E ++νZIAO!k"U)5j^''&VR]h.=~;x6`Dg;Ito; LH)!H ]߭.]JOV7I>ߝ>dZ~J|V5fS'X"zKv@L(5#;bt0Z6Qk/\4gI&a)Z]Mަ  +y̽lNd[7ק'I,Nl:۽t5VZV%5IkMZdZQvXJy0ۚ;5y^3J<]=@U*B-Xepqr8|uvj +4cRC^C4N':ysaFjE%:$[Rq1(U %\8QECB6%pvķl{8Li-.a&5F(FyRƥԣNk(ΥbAWJ +`„IEP2Lbr=l[5;%?$* A%0j˳YWm!#%8cVyHJP +S;n~8GM1q530w8Q-ۋk'4pfeU/RmfM|!a)D!6=Λhs13e#֊r&"%a\Kg11 cnMr +@AQhBx5YfhOF(VR)GEqZga!@?Ts9T+ `\P1-ٮLQG;| T#AT + A*a2kdb4?Y܃kS}PeOD$;[YԜ;jnrO&`dz("ZezqƼ4ũh֋`ޔDF:+ey4!aFPSޠdsQ.?'gv;J >Fsj +qxluT@$$JNŊCbvb1pKݭbMe8&z;C\)ьlW/t=md3go}dvb;G9*VչM=eZ0X!,Lk#?}J.-#Y̧;sj:TcVj*g09 >\qaRrm`IA捴oSє,ʹ&/jM%3r8 X` #re8vY$oX墝HrҬDsbsޅlWv rVh-3`35t2qV>_EL84@UfeFLx!HI +Ԗ^%3j+.8MFtKBЈ{̆rh#W^16#.V^J_HQhRsylc+wГ>ϿO/_w_>ְOtk?yQ]??$JJY63<4L}ڛjMn>v#/~w>O~& ƙjo׫A25 FɃ Q/"l:QLN5gS|{?w[{ݏ/_}ؕ{LE&R86ҕ=LgW֎ջo?ŧ믟އ>+<M-;@ø,ELP0eБ4d7c7sWȓ?8r1Qo_'6>s-׮?'_z?>|O_oxW 3b|=|Kׯ\Ǿ+{W̏_y퍷_ſ/|_6[tw%-S+:Kkn|_{;{߽gz_|Ǿ^؋@42VwjmgCN]o|?|'~'_z{87~ ɵ1&/ws?}W~>x/۝皫B''h(`uiӗ=SϾ|ӟzPn[?o7":?X,6()&|G7?|O^>?}೿>/<ܛOr&=A&Lif;u{o_w~|O?/?}<՝;\n) 8jtSL<ӮVz3k/O~}Wx[zȌsjKcS˛GϞxkw}_篼峿>w~~}cgĊSDpH,a&#'>t,ODU)VTt5s-'\8qԝw?{]@ӟ?'~G}џ^~k#ˋ"Tiw_Oo~×~__y?w}?tmZChȉV0/&O7~K?[|~?>p7Ӟ qO@@XUU-{GO}o}7y|? 8Ň}~?郷z >ek'Hkz,H:G{౟Wo}? |O_y~߾7zǾ7߳t`6\dBa edًϽ/C5׿_[g׮o: JfN:Z}zqne{s~y;+o+ +b1Jh(V3BMMMO9rܹGCu̕ۦl%*1bdT9z-{˥xr՛ջӇ>{噕#SR5ZL1rR;XY_x3OWz>O^k?ɋ/>z<~xwrYuD +}kHw !lT1^xg?}g3]={`0Y . g 51 J:]t&ֶ]<O;/npZ%d<~h3f۝Ed#/nl:w-^~ws_?g}9{Dҥ%3@!l6k$fJ=|'ާo~Gz۷G|ɹ|m=wl.aq6-Rwhx_Ϟ|s}=wwl6;}!b5 F +4+GleЛ\[eT [A\<ԑwpv8Ql #9PIKfT 0K'YQOC<%Qta HJE1d9^npH|7s{.NPGwt wc?,7KzxS$x*T2Y*Rݛ\\2\vrbSU Dn (oC"RrFRLDUNMMdMHAIRLvy0 q86gƓL6RPZ1_(yĉv5?;6ӓSJ}pyȨ!uOiF% \QM %6*`yvj)*\4,>ܐj6X9&$ 9ȁ Frcbwv9h0i\ɈIZxX>}VIM;엾<`:a ,BYx}.+K4#sh5323Dh,?)cNØD(hJsq̽>2 +ޒUV RCb"C'p8el4ًuA.RcA  Q aR݋yQ֏8QL4 ^'"yƨJ&egax NL)V!gs7 A0 x$ q!\qI?B4ɚ^sjg -9:G(#q6I55@e +a2G.az qzQ42\֜~筯)o("BOTd@(1UjT(<.늘In8jgsa9ѯ42fGH&b2'JnTMv25-ً' m~zfC#^8*Vp@4;o#Oe; jn%Ff0BnhӤP 9rugg0ސSq%VI2!LCcT$' qF]1w +!TvUJ̧3U*(XkwzY[Gcm|ͤxīT#= R>U¤.GEH-Q]W RLg\!;(nPMhHze\cLK—?|.SJnԅ1]+%TԬzh7<8vNW#(6A Y2$}z>D$K p0Ў_BLVgQs̅6vCЈ{ 饆GN ы82sZ~9l$e\Îm6'el+i=|սӢ*rzVL Ip )ɓfe P ژbJZE8eYaIk=MJe91юͺ4݉00HrӚca%#GQx)M17 +s9U%=HRu@#0v732Qla:!FD؁Z0 5LJ)\P%DiBwi<ZsqMRJC04q +&UJ3-U#vAvP 6HuⲜ#\U{ 89 .)DFEpoH #FqoXPt?He*)1&  + _T +znEqhOJ‘5BL6^۞9@qQQ6 +((l$T E;,`yl!rZ oZ=!cWp#aM#6{A:vdɣ1l޵靫>ځDhG.CRZ`+a9@gPErfʼn [_ALFJ$GL FMZj),)!$;x$Oi5)3n +..Y\PbM9d5N Gڃ@_YKKYnW$wX[w6t:e@IXwJNtXaJ cLfm0?0hך@x3dԅ; U\*ȩ0`e)ݿiطV1.EY-ُt4c2Jr:CchDx~Bmqm "0F +#㛷0j!Lˍ( a*'nl$lzxo2[KDE4*R1g/$¢k={jhzzCZ0t>HM7H[WbB P_qD5{`Q2Y%>eLDcjE--Hcmo&"f0>I܂_HW^s$e=ˆ-G#sP&Tw' e'O)<y%AQ!:hXqU0^DQ1_@8.TPLFjjZN0eĨ.L&H'q>:-|kCԫfM#L7Z4!RG~ɏZs3TB4:J錐{r,Y + +.?'#d \R\Gʘ.?hQP&y1Q b1JzWNLF7x' n@Fn )CWodT ǜ`I>5¼!W˜R4եTg7p!LƜ#D䋂֓ ?pD2Cr.3 +~#j4;zG; ûrLN4DrM~{L&e=ĚR fgbxsW@V@!:l.b4Xy>XCujN־z3}<)E:Kjٍ&J{VOgB!6ItZr8ntX O(Ɗ2ƥlQ1 Fi-.d&h'&XR`LɉOaas"F5F*Ĉ=$jUA-'<8'RXeV m1J-rƓR bs5)ve”sX" +о*fˏi_762eZ, Ѻd#f!s2 >"HX[e|2RӋK3Z~F/sq1;)姍ڊw1߾ާ;A\B>jz ' rMqJFy>L4)9$k=ڨr쩅lk1}|zaL4ЊO}cLza6XQ Xa6wxѨ yF.&Z2} Ψ 6]1 ũۊ8gZ+ML]\k 3($F >䵊|⸂^Z\ro1!v9l+?}"?s~G}:-H6HFA7Hm=BuǍA& +q?nZϋ +J ήRBr3T5"xmò+Gh4l(H^oe4|0oW(E,w[[;V` w A$^mKknDZ鎓8Nngs8йʜ=XS,TUڴyE "NJeDZR1`P + XdW@ ) 6;2<V5dsxއjrPѱm=FZShm+q>&#R… !')xyac67(Y1[8*dVƻ|B(KƖUYI4--3't(h֨X{7VBɭs^2P(uCC."F*۝FjRKB V.[3QHjk7A +%BD#.lw/Nvra\\sQŪv8Irb*5y|Z{P]'d P JMI<>a{qdq||?;sn|QgIi<)@΁k}BWr}T3B%O@D +RƏN?x4}T߻2 >?6=C2(SJ.`8 x=3jn [.vÔx=x8/Tn RVcNcKիOn~6KiB$jɓjj +P +#E=5]9 խYX1JkJf@b%&\jTh3O\yٸjkgVaPVq˯N&tқaC!b3(7{a$k@yjRQX:}Ot!Hl}-͎ii:g#5j2xPtnmr iJW . +Wk g_?g#TLJtAE P\.qj;vZSZv3a1sppܫ/_3.<<`F+!@DhcPn$4d@RЋfq 1RD;^^A n j'adĆmSzb3Lx @F)B`d N-@ )\.4cĔ5RSRfiTad:vpF\{0[RS.26 +BxqyA R>2'h> =q%FE=;_8e0??zs!R ̉tsoS?(Ο +$P/67x8z߇Oˁ0\ *,>|WGb!pd X3N1jmÄ# ?b-X @@N8?dqeLUI<A[QA7 q#YYʋ/  PŧI?J;0pUCѣv^.H*HF(˪MLdC]ЋBj:Fy'p XȂ !o@qy/$y>`dT dž}Dz9?eJV5lǏ+VsήåxѤPLΝ3^ux-H>Zo\#9!:Z|er4j+_=~ŇdZp;/OyG>&kYEs׃T 7 ?l/y_16*#ʧ&)Devbkhaw eB+:!A n> oN"G(SMH} \X={훀UuCaUùy*6$Eh=)fediNY%3rٓO2gpd ѝcr4a]HċЉUvb`_#1.7q6BP㳔.4)#f!2 +y:To_ٹgY->>)eL޷)!La9̪e|ypw?96<{Do@èJ92JdP(?*''C=@ .Y5è9)0>B |t$rlʤQ-O탤D}`|Pڙ=F49zj$!dqrxwd6gqi{a 0V,\ 6 + 'p"-WpA  +9Aّ p*c"Vuj⤚iǯSX%i~wa#P(V -,0,0I_p@J#F*FB{?uynޭ WW_TB ZSx|tZzVn2^"ŸCQC59:Vh}3+loGrR3"ǛF N[o؍j5\Zjg <_.v+sg +fǯ=ؘHٔ/ZD<`YWfw驥?՟ԨGƥ\H6?;.n "DU~<J!;eiBhRuفPlρ:e#~~7EtUj1zGAu $\`Nّk+Za(.Z;rn!'vBZp~4JYF?Ew@pEO ōP\lF:u->DdSHue raIFbKj6YAis|RaBl>@9pC°?|KI:Tr{?OZ:E z~=mn6'N.J\1B#`z3 }lsb(Vf?zTKp*F+b +P-#(LFq&OeKCQ%1қm*0j #p6%#;-FJRJ3c}`Q2LpmM;T!HST⭡/0"mI@@J\@)+ƫ5NRbg:z璌69`b>j pN͂}^sBdEᆅ#}#}@BΆJ1F(EB.DjU>HwӧΙzB*I7X€ãԛUIg@0\ tp=Rck |Vy,᚞`Bu`P1BL!m'-usfB+ p̈_$7L ϯz9qqaZ:vvm1^ٍKI@~Lڹxa y  |4AAyc{u:F6 Drl2K[7JoQZ ,*GS+5 S8233fjS@vl^zpzQBT^T{^wq:640R)Sa;F1(]8Q_@A0 ~ڃN7K9AGU^NRW o=[;A4NJEU@!|@iF,1bQM!L"x%>ozQ? @& G܄ , F]rрe0'b[KF{^@ Ů)!6kN?;P4AZɑ:m?@)| _t5<;gK7,- +ئcm^cɜċvgMD hhW֩[lpmYLw)4}{zo `v{"S_bdaRВNO{aezC'CP]@^׊reI38.Zzn~mAiB}&\99qi3]holH8L6$%75{uh1 ˉ.c& JU%M( jzbԁ0\SsN/^H^`a9(C&RgA*3+bӻ/IN]^7ps~,BuBHA +P Pe# 9$%#/8`ERs4.# UH%FJjF/;ӛ?ş6N7kҼ;.Ʀ{7!2V.Ad9y'${=$gYڻ9%%=mfۧ[7O=>qlg4wU-1\' Dp!C9)6<ü>.AAB ǭRJAji`r 5Q.^i͜W chZR@`{ ' J{l AB< +a6٘mϝȠPVeERHV 38͗g%;8NpB `z4=>3/˙D,Bd|~?}&7ew3+H>+UNkZJ2Pt# u ,#5!D  FuOnabTgN?pdY</.]P {C#7BPNXqC\8\/&qĎ;<,,o5? cZ2rZeK[LJrDc jAZňMk|$)4pw{>ڌ'g4 axd8`nkrVήn^OmVEͤ'+s秏9J3œ|!>J^)匶`F0e'@dJ*1*@Qin SBkn +">ݘgU{- TPyA,(kB(oCN/R|OG}Yl1P.'>k)^T֗x~GTzֱw1Q/fHO]۽wõU1Ap M( +|xdD.7U 7AhFpg}Fp HpzENpeR8D(cfKOY>v56Sf 3!h) nkvǃ+@]. _rXB0W,6WO\19i kg-m_cZo?;r̲FZy祩mԅه[T'Ŧ|}SM\ jN x"36δW(1 zfBMζV7O?ܻ ׊ +pQ'^G@DŊFңmLx A;ETzpa91e⍝Dsdk\|׊*VJ+6 !W*STqq@`2Xݝw&{_\ᦏJqf+Zݜ}&[œn}uTOEvy(&p6 {:`%r|&=L޼<I7i8ep 3) ͺ )fG!_@hX/fp|\ywaԂlB^!Z'j3ÅE\.@ +aK9JkJp~3k~0>8&2%/rtjW6ssJ"Zu+9uc +egP kΠ2L=y+S]GQH Nj3?-ٹPe 7߽5e4Lek{y%^7?LxlV0Mzw#&ILjRsBNLfD:FО+|x\vpo=86k!iR(]T2EPsOzs`UP l!u endstream endobj 110 0 obj <>stream +^z/.lZt(  dz+Fz l'o^ ޏ Pa*tgWީ._Zk߹sxó7jo\ kӳgꆖ[ظqx\(<N8a52k2QJ+0FI/̘[7yl.fO'vF}p=^ 6Tŕ3 Dwݍ9.<YIcB R$Tx閧4/n< @3|J$%P>ȱy*AʸRD8%I&)Pݐ5Pt3eZ@[r:q٪ik}' +ZBl&Ћ[ܸpqubkЎ{` ҂rө=J_̕67C Dk7OwҺG?^߹0R, `k;氓 )0hQ3j˩ 7_Gd;8gn[;O*B +F}92rcw1~Dǹ;:R<3ts#(1L.H&%h#Mĕdʝ!({zqfv/qg'_ݾꗓD).xhd'mFtN-R<4"5kvv%bC&rrliitȇ5bcrnÆa9lcv|rŁD| +yDʒf7QLkU0AxH ^3^]ܺٹ_[܏pLO +fq}ÉI>RuaLkV$% c J.^XaL!E[>7aRsqoηV/oOo^ r(Ja;2gV3եHf z&z`l4LPѢA_W5ϙET(0+=}ozKBΏEr! =F%9R΋vhqR4ۏ޺rmVc_-LbPOMɸw]/Oal|І dVř(c>\_ڐ/ (x(5IN9>Yf`rt0Z6V +S噃UQ|k}v̶U^ 偒5c4-).!ͅC3R%]^ +*-91ve{sK+jv69q"\^O4v[wټ^ܾ|j~!>v/~kՉOÛ%:AϥTش//(͟OKb}t{.7yƓO7νR?o@AyeC.Du4"{&59"$Lo@pyyw@qâ72'/UfNYDSBpb-( #t;{wiAAsFN괜Ĺѣ]}#а{YbƆ1..̇K+I3͕rw/RAχXu1K׃ؖwfF X!;:)I31>lƘYY rg?;;kO<ؾ\sUUDX_<8@IMsU=7)*;oԌ .>MV:ݭ7←ɱ~cܽ~|?ɯNŅPqANj[7w7P+mΞ +fݰ؄_1rs(mt7([--M9V<cdxIK4P4upMͬ,4g{"tмƨ%lzlՊ^LÔ|kZq&k!R¥H( ao^`,Eks8V\ˎ-;0֨0e Djl.BTDȋk>k6I)KI$q9\>l'I!.*^9Ȁr?pzy`7Y&L{o6nH1_ťlr0jPz\INI,XcE\ظ b>I#Iߠ3Y 3ۛk +&W[L+vj,̚!.jfJ2ʌ9Y_1r V;[T=>}=5Z?8u^?=Kݾxzu^nϟ>yڭ; :&ĭD֓w6.1pI9Gna,dD54{c\;hc8-s̭_G PxD`Xm溧mxIerݯ@TE{SW+S@t6J|l,&(8 V˂s &D|8Ce59 a:P*$z +B8x=uf;g,&5֨a: Fj"f +\aȁSRc@.8 6. Ͽ9FZvV}U"MwPW4!F~aC hu#R`#UDM9^󡢞LJ)1NñO}ꝐHrI1|4 1N 7cx33Gʠ:QJ*Y a +oj~ݛMi%6Nf+KQ@.o% ΄4-Jq^KfҘY+wʙUO,MNz{b*8JDQPSݫƊ5hJI!ґBq|,XR SAA.;Y=yWKK|R('\Auh})Ϝ߽nK%Wg9q;irs_[ 27qr+X$\}#]]96 A67 eA]/~jLy7v? c+w]yN8|Ё HOPA بa;wƥk}wlG!U A.ֻ;^"cZ>7@' t0:G\s!!%ڑZ{0}CvJOLC^i͸[ +׋Ns XH{1Ps30ʷ@3hٹ]Z*m8lD !>lPa8ڄW`|B>>DES +.@Xiதh.^ڤvjZV'ntVf4;n(a1B #4 Q\ci>Ta\" *iH& 8d{7*H)FbɱbswCAykDɷ3+ =0#I8∓b(1! ʓ03HyY76'6q6Rsp5Y鸕I&ZYPpT"ƆAki3 cPXmtKkT׍z{69-/RL~fiPT?BԊN7t!tca`G,D)pG?=9֬^y^hQ! $د qY.ȏ-z ^[AuyPI@9|M*EZt{7|T٥ J1$~q!+d-ddVlml|0C  T0#6f{+1A #Ξ!(]n O3loNzl<)NAP`%)P$/*q͵( Ji(BE^͂qx٘q@00"r-`(io *'p!  ++Pt(78\(EqblqାaDob0!yR}ҌWS7@u1B!L(0MZ+zB H6#:҆Ӎa,Ҋ +ŅBT8Z[?ypɑb"+ +e%FQ:#fQT 陃 ц`ʀpa:A݉ H(&<!?E?nrY +X[AT3p ^xUéLeQ!ph)Б,Z0aDp 6\a^&#R)90|bI +cU䚞\F <^/92z+g8cN>q`LyI8KR@r %dFCQ(*PRN!-ha -C2p^}Ȉˎ9Ƞg1A.&hߋ}pPB#flE=^{IohE\D艃kO? Uo D)xV̓/Pa}ۻ.O0+$մ 'Y cB̳b)5Ex{=.I`d\0p"E%+2׀4h +(1u?jF=IZ`Z6sWpA[YKk݃{8dgƸx*E^za ߍdm D(!VhӓУALRP)TDF*$] < R) +n/Oe\Iadc^/r'D@ pv~_2r6^) #=>j=<ⷍQDA0qӼcTxưX.Adlѣ#}9>2iwF>'-y|&)iPnMadfGa2(P=>9yRR&h7iY DJˍH2CK*q4 G Hv $ /b45aqc*W/V#ق+܈5T=drlZ[޸u>0lC#GMMW@y ZMEdyF~3IRY:8]."QE ( ;~0OUizHEb V'$8J#jՑd*=i! G힠҉Q:ѴX֙[4  PBB)3^d8΅sծfU./h IKd|EE2) ,Oi*l@H4bDt ,'s\&/劉Q0P<=;LtWn'_]K#$ $ije't1Y -GN-Fo_/vgsv|d +pA-"RDnJW2KvΟZ}y_{VIFuEahF/{}OD-7DS dIZd4cC^#^E{31?v{ٵw_>ޝ?[/^&4y\n9" YJ5pvѸ]8?߼}z|u?;xׯ`>ϮO}zsv#㘀9K71VZLx,V<]JO.l՞=˷?݇o|XGG] 9UI5Y监vx|kO?~t^v;H2wF$ 1DWq{r+t͗|מY_}xO/ZEQDҒ{H8o~]x/3կ?{'wOg߽YuߙF.4afd^W]}tTG/ٟt;'OvQ  A8 <$dvqE衅y~%un-?:h=87ʉ^yэl"DyUlnPח8[Ͽy'|6*˂$dpp+/ʢ~'_z/?/|_?o]\^&@x,5֖K[g.~x?_z~~?W~?=g{|!p|Shʥ{ݯ??YW_}on|owo?}'FY `pB["7[Qo;l?ߥlY"/)`'?{uן^_>ϞOOt*M„ĪW:ijcw߻\/^{W~OKݩw%{#U9>{qs9R{6 +g[W//^'ɟ>RܜIi' !5-81\晅rKscGo3x7_^ǯ_gWy|?~ҟ|:xZφp#4EoÍ5NMk7ֵ;kgs?/{ǿ|ϿxmoxmVȜJ8U^:Q}W7WzԻw׷K))'$LHdË%\V^olGջ>NO~ѹϞ>Y?X,+ A.f*XQ#Ik^\޾廇OmzDFf vV451^̇#uJ1h2Xn?{yw?|y/?߼]߿~?~q P8!!NMeD"&ńa'Wwgك7dݥN !iTl$1n +]HۛWO>8ռq<}~ן̽~a|r%DdE=jd3#c瞌laR|pW^tc4Nt"hBQT>ᢜŤgu5^dQlrcS3]_Yg7Orvp+Q0IMD QG|qcUd~ _~7G{|R[NC5㱀}(X椵bJ^>=ƍ;ٚ):?(Db}JU4X +X^[f33ƣÉ^ru{axu;Lf#~4aV +%HECQ@#<]rTŅfptquvl%5ONf"iS<"-`QűBfS:=O>ޣ_^խ/^^ܑ,n@s e҄w{}MFddw}kO6!p8<1G:q0 菠?n@AZt 䇬BVfT^{W/rDYU8DFqcٮu^XYoEOW_}x|oU pnmRjhޢ?:(bu[v8iGp*&ѲLGVF.VtlJSYXV!Z;lƓf}VܱNkz`Uot5HJ%[1_KaXpQ5/G7W'[ׇԹ7pWZ9[I[ 6駛TEHCuIo9.~lI:#~lMQD^14ǵ\K3=˙ V0AKՁP \02e:#Q:jٲU];j5X !͚ѨݎД5CVP`I"38{כO`U׮̐c˭{aTUs(H*Yc8 fRyU zݪ Η{ћ޻۝׍ƵG;"Ln7 …n8>Wm%W6/QNsR %oV%D;yC~4yD[3ڜ"ϙ}5vE[=UrX3]Z #4ɝb:KbqVoLVetgЌwIjbuTk9{tmw{@n["٦v +)9ko|U]~ugGJ0&܁o@un;NѺmRi|T{HVlCVDC{uOΟ/SGӫ?_=Ń_Զ_tvV;|"cJRK&ǼW9oO(8vᒏtG?ߺ㗿UGZNVzۄ޾ֽh=%!`(DE)2Тc~nw}Ltp ЇɽGzF>u&Dy*y͉W;石j[hBrO`S[G^ *U\ DL=~%:X %. bmz^s~s1$U0~{Lα/ޟXɬ򝄄N|uϝ˿(D3_xDTYu)"nAbrG?4w^ 6;Νj[4W9 s|7O [۸6V`pq^|^k6fz)mmF?Iޞ~WerZnOl5v7*·4|w:zUmV"y/dz^>b)Q#>إyr~%S)m)ܦԾdN/wƸr tZ〱(m-v޺T\%e癊osKm\ 48Ҙh=/Z~,ۺ{5 +ۿs[EhRL@9;#\b:Wo.ߙoGO$o`Tn|?|O$wؚ]V/Ic!"1. Im Zv~Z{Ӡ:}+x ig u||RnGpx{g2Nv6]ֈ4иZsyλ3=nP5zLp^_CNcg`^.ZEP9FVjSڞ*> +RZj1mѱڼgw/9&$Y5'ta]8 „*݁gcqՏAfa0'ϵƑ,m%GۀXA5iݽxZƞ7?(xk =z9{X9x7w/geUj{Z Y#0ά9^ϑ2 嚜5W"Z+!lDSBڰ@x%2:۰w̆!Ɛ )G(m .}jY2;G/1!z8kL>_?ן>|:&GJ]>|S[n=G?kKq̞Rcߛ]GUm`~>9Լɛģ?zKkmBj-ޛi6hBo}#Ogo`/EmzU;:{5vkTsyA,fĭ㷿j/o RzջgwNhq?$BՁ/Egw=ߧ;h|zNb;'@*ў{/~ywhuή((K:E:1G =Zhm=Nl] pz1:֑g>3w@ +I. +L1k';|Jw>Jk!O،9 F&a'fl5 +"jpt;(AԀ%b)89awLL9 +OAvI 6sƵcNy{Dp~gi{S{\0EwE4}ܐoU{'ɹ&7xYע8MhF똳Ǵ/3 ~%OW*t,i=zvEn$Fƒnes|<_\=6kjF\kvp~nkTU}|ikcP0Gٺ\fcJgvjzx?:|[;A0l=/=B߿տƋWY5í'=~ ri}֙!Zakw3R"vC-7/H0;ur"fA4KNdRy>=%wx?goMn8\D{f#j Ϙ]0׫ _0;&x׀b AXbD*l] +VˌGp9|KJi6@Ko=2dw7GJeOO]͖5 [2mV1oGw5Y?#6_\(^$+^Ѭ^R)JO(fr&1.-` vL ]!-NoI&%w/z`kr\8G@wZ=b;/>4:TP_kp7Ǽ fgŘSDlo +P#a %s)\b6Z;>鯞9KBV~6}]7a*T!D9m!|̦zGx.84`wuhK(+o5ʣ/ +,tr9y,FPQr),~ ;x3oGJ;Y1P_ hZ^L{awjV8;rpZGzm B;I<}?%.ҘuRm %}}I`!Bjۭ+Qn7g,beLY厠tSšCwҨ ΋8''0kzo{uZ<[Xro48EuT&oʄtO}hn:`Y0[Q)ptu{-`sl^bTŠqr<>MCz1JL]~pVs5>~KB"7zgzyBm\j܍s vy{* 1ZZ7@K#ܺ*,f*bWtb RF$|<-6!|-Z{a^ad>%ki#͊YڂU9!٨kV4J ]4A|wVO@TEǕ>٭sP+WΜV=FAN0b5{)g5"v SBǐRE4~+Zut=KKfw-ruO{o~~ tǕ]@BvAHS[͡tۛdR MJ֦ƗKN')9.afaY1d '67TcF"1 "6Sڂ-kE6F |*[wtJUiIjm%ZYcJ +ErWW(m蛔`n܁L{7g<|K[PdwPIkգ{o;߂aUr &,X{Y_+cO`[}\}0+yY&a ]B$_$aʋe-"F(exx4;[kFJh\XQ7k|E+c.聆M 6BRƘ'1}L*gAo:Rn["&Sr9}w9o+ShFeQԛG8w;H h 9Q7 x40RhU"ØCw/ELVI槵`^ N +J;^$ʔ V&Ho>XQ^o6g(%^x$:r/K!XUv;Bgy?oo._a~簵2kxtNqֵr<$^5fdw3 d"=i֜Th4 EܩBCd@2hBANs swն8 +z+t&A[T:Fm{'A-DN1xU~[EHڬxa|7+" XШbY~i~-r_Vă`|#{c-*nWbwKת@ܡf1.)gr,8/{6 l c0ֈ{nugYI!6+ʚ$`?h]Tnmޜ +ފRG8خB;d,Eȕ(PuOvxk.3,bRP@CiL`4H!VmR4=D!7vF*tΞQ:xAs힋`}cz2^ + @Vyi*٪ 'rpY6X6*Uhj2`C!l9Hy\lKN8~uN 48"Wgq{fnbK|f1Qfd)ə=F!B˕=z'ܰA2E $ +,X@ZF׮F>ET&z=ҢS`D]3Xhś#Pj /'Xɺ{/Fg?ӛE]J +.Qmҫvk_&FT%yTdڸHn8qE_2a$犋JJ&KzL b|fE&.g/H}X ~>M*-Iւ/>,Jb#(y.jtN¸Za&SUR[{YG_BFPpUHVd#s"(%6 ]rf|˝;Yf cRC,:$ 5d"/%̕TIerE6Vt2eEw# 0Y'eBp4S$Ǡ 8W'F w#ќxǝLIWd-R-r;YVn7&W(y7-V*%uTu-͇oxu.\!HyD*f2"\-˹>)DPe3,=J!xd|з"bK2 DU4'3ĥ*)cՠ.v(m$[0.&Ws@kܗ ER Mg~F'4̐Mc]dGW놿BZfcB&h_ΰ| E>ô`hΛen= ^dgDUp=S O +-\h TQ +X.mL$"o%\z+yHn +6*4g+{PHIP>[AqJ!dfxۆ;Fz1)Ip6)`krj9ԾwWd62ZF(UQb'KE]4nf,:P1J{wSfM`)P dHv]˱يʩ}3!y\T\p=ܣ5^V?ff\"2T%vqIFdp<]!C*>emC7̩Z?/H0,e_a +>~oA^E Xm|rXu+Z|>z6$Rֽ`;%jofMHPtq{LІ` Ot^ʕ4BH K **T^*S` 1Jw7 nH>*/Dq;] "H"h2=oҌT=  DłolŀQa*1@l t͖)12iّEuAYkT:}}V5*@ice}Hc8s@Uxtn@:$_e؄&=0ԨXVr'RPyj~i-{IwZ?d C0yԦ!ć@co?$ʨaAQgh\ +Iө@QRm4o}|rR:U0ltHL3H>4P tI&#F +_ː9­-\]fId3֫:JYђ­J{0+(!-W8pe-aZ'y_KN *[#PکU^ e1_p6A-B'KT6OJط߄]DpJ E he,bj{{( a7&o,N!x1Վih͠LۨT@1gm cX'7~2C!01D䮶<?0v7flYTb]n!| Gӻ ) I- @ XNteaӾTJ=p@A*E4vsZ$l9XX ZȖD;|`-/,A[8 .W1Rz(9v=Mg +ʝMԯGeH%Y,jHpg$9̼d2bLp0ʃ 6j-͊3 V/A_C/yY?S dmBzA\+mcn 9_ހx)PQ'dU_gؘ-Z(߭4j<1a:mo>,w\ZJU`dm9ܗ=0 Y dLr&XQ@(銒t(pֈX4iFϔ"&Ԍv>SkS@B:"hZ6oEg3`/ X)>H|@ +T N0c(fRP p&AcDvR@<0κct֖AkSt;ӝ,6ׅ`h Pdî+!&ϝT6|S%HڞT;T#5HAQ} ¬"j@=E\+Hw>:%iMJw`_0!<&yE79 + +*{*q1-ڜƈbJOե7<}=>ZkFs$Bfb| \#1.C' .ҖV]JC[`?Gي-[7 $P,5ʰjZ#x;:!j%;[1-8{HeĻiWd҃:j#ɲ3vdsGTɛۇCkX(kU{41&>)ќll +ɕD uQ Rrk>5Jbk(y{Z0fUzi]/*.%4! G8?,qqN)5Dl(K['؆Z˲SUƺŽD͒{܏K(cT3e f(7YDWsZh14#q)1JW@y^k2TA]]bqg\][qrX@I-c\G88GBL2.ʚS-ջe9M:)ȇ*ƅ# TɼgdPt<1.2^: :+ +xFz(}@մjJoR8\AJ4Xr;z|Ȃ +' h̑zb6n|$+@kK!=Tj "wd2fFd L y->);yD83-<7;elQj6eNVРr3*%A :;Ofgf2SOcҡ-V=ZْLJ-SRmL# *,-APqg+\(5^ƏIkQQPGj2H\j$7 M9o!xj@d Gy3nΝQ$c3.ڷW%hE`9D&$|9Jx`4Q(UQn|ru'EgQtFo~W~˸;)ͼ|HA*R.&.&Wh$eZj+ά'YBoC=>ɓuP"apt\ym_KeMHYQsTu+]R4Qss1ڧUU.}rXỤė5cψݟm~ x .Yk, h9P窶9k s;.WE2Vrv U:wSԭX,2}\S\l?Mm31U9΅eT0B]poycrf  +iƃ&w";#*1gk@]ޙf?4:sƔA IF~ {B,X-[-BRG|O9W0(R +nwAqNyCN åsYN&WYw;W` Sji>b|uQtGbv)܏I)U #(kieFQ|OJSt6塅ކy_ W&.5ŌnfODzOSV0E#A)4h1dr/$4"t60yVBJTQHʄ\\S[@)VӴC51-dh?ܣ*րp|/%8(B>#,!i0`h%"-8=MeIFe-$p,Zk l6ӄdr;huc6ːE{KOf +Q0]\'1SFn{C͙)k42| nhyk%o'0%ʜZS˼=%>?5huB,(EDoi@J×C\,`|A5|@ 1nv)a|"R ~TD Ѵ +͆-*\[?. j>9;ԫ;uOYC ;TLςmuJ|z|/<\D},fP UQ=-;u!tڪ3R!.=Cb$ɪ-}Hcs@U4fT^PB[#LRv Ig fa&wd/%on=b^ϋ:ӏzqaJv}^,O7Q+nȪr D!ج˄r/SZOgNe[{hnkn+2kѢa|toEBsJM˯)H5?b HHuCZnB8$ ^A,&`xQVQr#)?S饝F_[)#]4ʛ7%hc\j T&ۑ8Fjr$)LʠєKkI(pONt㘝$^6n0UIRnr}*56$<"KqEh-"JCki2u'?5@:QGab`CNjsqH88JNTTDV)\ +!\(O !UƚC5bxAp9׀aj΁һ +[US`>#j[0z!-g'?ʕ^z /"rr݉lx\5[P@*KuΜ _p;5VrI҇P݉N9{g;W' ڦ^X'~B\=xIu'>X^k)JVRT6E҄9dN(]q'{^2CjD})GZ*Ldo]rIFgHBH:=>A IB"#ԂEBR#f6ܘKO)~Ԁܲ[߮x-L8#S_}p+T3$"1/VzNʧ<)7D';C +9ŵrPG~Qm<:@W~koed!8v +0$0@ÿc><$)iF5JneXFL @\-Yk) (R| ҆"BR\$*H,KfWHRF!I_5@b i .}R,(DS|ʐ.|L$%1H' ~6r0CB+Jh*,ViKdt~"EI8\V ?)1qTZBRP)Qತ\@T*0* z)K?Y _:*9+S̉8-o%^*z79N-h^ +]9;"$)n-# 57H&ȵBg7Af}Nm6pV2W6leRi ~ԏ{ MRaLFTvFu'Ŗ ԶӛQH4,nԦu쁸C +σَ{9ZIXć,r9aDH.{˜Eq?r@&Pr97fi¥2\BXH+Pt0U11 +g!ɃfĪbҖC(РO +U/Ða`ASb93;80pG6 #%Kix 4Dp-&K $Z3Rc`(6O^OZ4%FpSF[ñI3ƅ(&FCMbBF瀲|B,#߇^r#\V&•˪ ,7+(m=A4FR!+10s3ސow9iMTQ^G2D6RmJD ֥.2z> H0`&.ZҊ&-aIIUTJ)B. N*J Wy)3ĕ"\>\j|"Qkم]hBNfdD2AI Y))PɌ6%KqBH.T@R $)!φV +3YsPI^w 8pjk4Ꮄsatc 霬3\:sAl'p]F=`gFh%P|/Ȁl|S"$9 è¿@dxh +032iTXz8>0D6*nc-h 4aj! 2r>D)(Պl 4g(;4B~'Z 0cl5Dk7ep>0֔Ҳ .X8a@\.)E"$8+ZiwGX0U岬ٷjM!t`"'+1-H3YhS\ +1܈d 1HJyS\'H͞Yە ނ8iKN_' ڛK ^NkB)btإ8ua! !8GCIF$-'1gԐŹxSnAa +R* T i !ϳR@ ӄKqVR.x~ ALa6xXN6$#0p. ҆ +6cmB5>0OSArdFY1s12d ^8Rzv ` `k$ +H3@5w@06J  + GeYù>0 14Nz4*B 7yd *QǢ;!Y^N2fjM VqEg76(BJ!BoL,C+;3@*d4KVcH|)7 "UX.+D~bV.c4Qʷ|?;LАKe6Xe\*p#< %V|PbSDr Ke@0.f(¢,i>/C $>$`(Rc)i.ΧI>$e!` _)!tVq`,҄ђS1IЬX)'QpwN/@G Aעi1ȑѐJBc+? + (;G`$ JRgc>NINp l-aRw/n&f511PCpWsNR}rʚK1HvZǜ[>yyB:n В!T7^?I0:T7k糽+֨hVLf~Q K^7kH8EZm\;IsHRC;׍leOB@mͥ[;4^FҞO_XDofAL:pοAt"# 1Po!`h >=H \CAt`iC6ú $Fp" z՝[.'!#=: f60{[lޣ"$"Δp* ˊ9ŪZsk9ͨ95z#Xi/b'0ne] #1uNpQBRp" lqIqD#*Zh\&P:Hp +p6GyPt xu1`?'^S-f*!( ʍo*EP.3RU6Zvk3V'j^ 4F-{u\B1_JcPIҊl?P벻d2r %9 +0KIʜKRhjŕ!Ko~9#ɹvq"DjFaY 4p. +α񽏥\ӴO%q㨄>43qM{& + +.'T$PUJnT8`&3@,`#]΅3JGRHUQBpֳ*d^/H@ID5@pL#JvI* "XI!,x4vz&\a0BW\م8p{^)L@Y8m^6`I{aLɪ־y6I N )4NhdMN8鑒p06Q z ݂= WŖUv}\,2r +i rAVx* <|yW 1!3Rj.u-wڙlbR% Vp!J:4\ +.Rg@IQ{ 4T@UB h/Bal |5 #K:)k!b|8 b <7Xc@UJ=M!"Bj>A ^l!xZzMp`4E HI-^m#i%ZRbUu) \0Si1\.@.q `[7լ>U }RX<)@ʻ@%Kg$%ì!]PM,0f<#SISQA'Qj~n\B4 +~2 Ddeʼ2J!&-V@g*E:AULg$+;~/J8)f |8&[=əj3"Hly=AjqLATs+M[aaXU` S½p j0>-#N2\.( IE<= Rd>IvYR)r[D|*JZ$xsv7Ip +VS!s@_ gbB$XNRJ7õ%-@K y@Т#9 危FiZ-(8jJh B6;.rNA¹/7C8TCl4%GS +BdiY.A?&Hp }B:RnWlW 1Ɣ gIL{h')J2\j3@_ID50Ƞ)K FB9@ #b\N:&ix@R]Ȑ*P+j‰Ŕ"ie,>lFT$] %˅?#F3"2ZZKƝ $ۑ>TUkE,Bl r<%iXyыi[H$n2XJ6HC+QT0-[A2W $9rp^chO6/X>Aѩ&17Rqڏp/ i(\-xĤH +)TOЎ,5qi' 8z0Dt348S08 pa$R@ #T3 +qΜOiQJ8g US]Z n\dPD7 rw +T + h8e 3f3Lv.\aH H|}NUFpu!IΟ(1:Q +WpVh@d" o@+`P = {|Tn.@L'0R%.%8J&P2 8L\(Z8IXDl(.T e9VIgòB`vO:фh96F!έ/$8IvK/Ҡ³g/AbP8:uR"$z +JHHN(QB4 WbId4AT;Wg3sQf>do.a"-<{!zir|?SLp)G1+ $V8g|~(H-JX/Ax*^p5$7R,p0rۡ7`Hn)r|vNGB9o, +pi\M=XE3D" }[$8.SXz0_-Vp=\59_# 3LhP&0Kh:0P鉤%DžNZEc -.vn h%5;!:v.Di8NB`t8H W8Æo UJe0+LZz'V. 16dVЩhJeA9q>-@L D V" $ n @|cO`/g! Xu9̅\p<1BBh0vp"8j/Wo!ڃT]qD. |֦iz%dPqqЂl@fY;=`%[]/pvGMDCA I (~ 1g}d('I;)GD+LSr>)6:i+Mќr"44\:?GwC`!قbLW:˅EXRE]ۗх8 +@8`3!4`BIҨIrK dH}Q *%r, %΃! /,T@fًqp lZ`?.Χx&⹳gCրGN?g`?p!>H'p&9TO_x([ݑU 3=?6++b.Fiͪ:#Ln"BbI1Z .V2\ҪfoZ]tb j.֘7.#(9^+cA +T/&kvv3R/rL,v_';ƥZwCP&Z)`bE˯}h$I7VȻˠsᤥ Ew"9/Z[CUŹR`4a}Q <;*lJff&!)  )pG)i8M( YP^ [L>4$g 8D*-@;@tpr(HjZ"yAi)CAUӸ:"Z,{QwqDH"2d!4,Y%: bMpѠi&JBnfB>. ZͲjC/ڥ#:CHR9\(U`0»#F &׭ HDSYe5 T%dG֊ h_k +Ш纇ֶ^vU2{zVӗ~wȻJǂ,V8oJyCA(emH(Rѥ64d>$2gAkmZk!Mp![ (v@WipJu >\(`BxYmz~*]Fk +v B#2($`C R-Qj 7Ps$:&HaCr9vyk-:Mi@r@&lJN( zN@`r#UEeSnU⨾|(B]D Fnqi>/zBZJ%|ofhSp!%nVKj~UV wXH}x`l!dzyթoJNS F09U +S9;0rM97&%w`W`Ibv(W]6*VVep嵶L9{*X ~+fyY-,r%,a6`[/]h4o^cvl@eWwھVԂUhrr +F-+.gۻ>pr Rt-08(q_AoGjMNySN8ȷ˼„Zs5 +i0h7ے7V +5svyr+; NsmW%znc %صY (/ +6W8c`Vm/7V[W#ƀfF8!׻\}yݳGۼֵ^Z*NNeY\i0V1ݰ+Vu|پv{w 7׋3}ΔڦZY$|D RYW^XZW^wȪm[tgj~(9Ԡ^Za + +6K廼ݖU +pTU+rFevvgy|lmOP/NzpOΓ/m_~(&~g׬ڵ5ݻ><` WP Sp!vн Ù%m88ʬ9Ɲ7#t^in<,^_:{޸lD49ɨhګ; 'kw>_QsRok`D@Ó`tLimmoP+w_xk/|EJ쬾|s[/}R}|rr?KK'/Fk Zoy1[8 *gY2`ewQzlR*pSŠ^تV/or3{;ťP\{VW쨴x0VZ=:!BsFۥ%G76ﻵ .ZYtnn 7W +٥asv9S\3kٝؿ6roiisk|釾4f10k Nj`:;>yV0ڽէ[[:{SW?lW=  ܴ1Y^m>mo?+=ES]<ڝ;׏_BF'xs'z^\7+UʋnkG+Y{J\$xS*yme1r~8Z ->eޛF;Gn&˽n)tyoOoZ`}շXO/;;rƭS(壇ӭ{GϽylAnk_0ٯ~ɞvP56ޜ~جn[?yRXv3/sɕ>wεg8궷S|8ΟoE-jLKg7O_im?4ꫝkE)7C*FGɯx+r)zckӳWow. n=zgu=n%mV *^ڝZrba |[^~2=jI6Lu0Z7j\pkǧ>$8gsQۄC\*S vm9;2+kGz\eH 7W^b$$<^5"+WyLr˥)qR e[҃8f\)l7#i6J<{(z'^Oէ2mԠ0ʦSYZ +Eַ{[;`k4 KfuRo3ѫ~勉y7(֯zmxR/=X]n7w3FF1! pU֯xݏ~G z/܄KrK}P]\^vZ@i]ېAV>{^t2{ƢׅAk/8)nW +]Bts҉][$UouziApZiémBB@kt V k?l=mZ|擏 3Za,[;bI:m*״fy9ˬNӺW;ZYB+nOuza|2I!(9mHjZ&<#X)+K-zKILNbZwЙ,HGеr moAxq@^&Ւ]쾰xxqe|EtFXN 4sݕkoaP֊R#`j{XP߉"B,LWPҊ49Gn4 V6jP}?Լd8tzP{ Z%Kr*D~}uo{w/.]grͷ7ҬؐfH.t\{٪6zgo>.Th3ʎlvթNPmr|tnםyE"̂e{Yu8 +щsZFV) [)ͩNrxm}?m^k"#q`ݕYqztg& +딃L/T_.tZk7t8ݬjVWs3C) vgz ^/ݥ(-d׮R$K)La"WS +2]A(6 k/+ڷß?۟~es[/ Yh7<];=qo//=/<Pp2qkKKlO_z#/ ÷>'+{'wo?J]V!b}]vjwջ{7?|g?__|S*uuʣ؜UҙdVӄjae\9<{G>o~|Ƨm.B8eZnʎ,p?ۘl^>}x;/K_?_eQvX y(Hqf)!ҎVKƍx2ڸ҇>KW#?W?w>Ο|嗿>{wa !S+nv¤UƕxG'w|ѫy_g?|M~]^C; XٮbwiHyٮn_y'oww>_hRp镻?_ݟ?_~_ڷN^EJNʕBlWoy7_y||[???>G+_'_|>/}~~g#o?OnZk@Wjɵ~o __}׾_~??w엾'H3A}1)%^bwiyƝGo|}}'?gg_kj8W^׳|{+\YZ;>8ħ?ů}@#_w?ӿ(CIT 8/YM4n6n='?|[~Kr]wf.7Su13uW33ۗqAH4b0J&YLIV̱cN<+ӓws@'??z[=/v)10p+z陗>g?_v.EHt,X(V-4SΩKK'_\џ/g_~X+,ct'Ϝpyw?/ynn#݅I+(4#lZruo{=Ͼ?_>/k~o|6Uz$j?Yj%rչݽ7η?/~?`8>_Ꮮz#3ByHZ\i.n<{wM~o~_◿|^lT\"+W4w_|ⷿ~|??/?O>y|;{CP6%1\1RP192;rt+/_;>}/OAp~ҫv7!".Dy%W/۲>{ǿ_O.~?/?~ǿ/?Cp m^KxG(Vш"g_淿?o@d~o'?};M,1_PC</FRjtµϽo|h~'?~釟|_]~s}딑dۦ{ZP(7ffWn߹܃{n_t\3 +rrN7$!Bbjts{_}o޺~+7 +f<'=w IxYTN\=dZ?}Wկ󫷾XJ +2L*=`C(t3VF3 g^}?wO>/W?qެ Ɯ^st8ER,_Z]=yܕkOܼy{w>_׿fI ; 7zY6KPF8I@%[jׯz ,]O'2@Sb\t`90B8DT91z|ql1l L8PS).Z A+bn#m^,@~.nūrbz…+Lナnfϕ0634M !]~CQ©Y`9@M|ZJ72=߸ t0-\2J L fPV=>ql5(k 2ˆFaL,W^ɵơq bp)[ 0*)gGlt&\+rj7(14Xɋqއ+@8` =@ KVH&M IP#M\J>XC-j|ڋGP0($`c;dCN7Saq; ?64(ޏZ^KR<0nlr>HǴĤ)sh")aG;F nF!$<@fsC#^kPbJr kSbMTLyI&*V6h>66()kP-*'F\L,3:!rJ$~cfJ84a'pb$8` KE NAd"3 3< n "ش1F|Xp bux?y$zXNjS-ڂ URPB2 V/I( T@|JUC$ؔ_c:F)%g”*Ly|KN@w;DFC~:J5FFe '\`:)uZɌ؂a¹ ]*!|ch6tpNpZf2|BryIW>%FZ&%>|d1a:1qjӞdIJGt|41ꄒ]FAQ`(°j%k]#˵N wEq2'e_mP CX23 EpI)^sAZ|\~IP&ԄaQxqC$`A9 πqxp?wQ2@r})yJ> 993"8ox=`&"XM=1k&g#EC.f铼^:pQj\iEҭOFSsfi!Rߌ5wI&ED,z/Wς"OIlX +~ܰy ńFm>76%c>B$@ߜ^NVV9-oj -Fn3=' BMqxDf!U+e^``r;ND&2"=TXr)#P-\ W9 "PN| vҊm(qR A/Fv&Y;qy,Pf!͜.̞w )n\}΍@sjZG594wT=Bg(#~n꒚[QaԵX3>(MYAQ +_^u)y1@[]rjٍ0:rGyE?l5"!X,UR)0f]3Hub"pf@)KҲ>Deց!mԍ]1moԎ:}hBeRlЫLM fpՌ7{30Xg@:q?Y9 hw"4䦌\SRbT+TPB'{zaLumn{sC!B:`9x}4]AyAT2zvƪ+BnjQd+aggH5 $- +gXpŒQ-7JNDo +s +{>&&¬VJTV8Y\2M1ަl^qj,΢@,vk7ѢfvoꓟOTz3ȔQdeA`r@2JN4}Ʊh-37r!Ɩ.M-yHVƛQrTc &GY@B܇7!>va>|hȃz#\M)Re21RαFIb 9с `^*Tcq8Px(`y55gqI%!2> ,LPrU`:YpA Kޠ*PRQM:;q ;(FRRRg./h ܎å,cTU:9w_R]RŚ{F~tS3gcm;N)02!fA8('*({XVIPe]JpurܘʙejFk^g!E=ٱyz3Z5_ڽW"N/A5Ԁ0&!:2X0Ro3Sz.|dԍݭ+܉UQf1o!7 ":4)%䆁WSPc6ܘ7[_+N%|$X !Ҥ-({0p*XTϴ6.}DeZ>w <=VluV>6!!ZŕJiMh/|wƄrQINάy4sTGݼ ԰HFmsI~!$| 81y0LAy"%@ 5sAr7殄 ++ޠ Jmqr6jL`2a!(FXj QWe&0Ce70k|x#;no ѓGƾ_- e NPR\w^q=,is>$"˩<圞hHG!qlnזׯ3R1io8 ꫰(gIoNiiRh),33d1F<6njha9\\3jv֪5)~jS'ߺkZgڽ7Yݭ\}3ll6'= g⥵A ;av +&̡ dK~2R\5Z_Jw}R +hPJ2K-p>RࣝAW&H'OZ( Vmt̽ 3dQ1 <Ԩ e^?r\tZm +i1ڷyYB܏k\,{ 'l^Snq./%6$crqR,FK4ȏҬf<22 1VrcAAQ;!3{.5  15zn̠k"RեB@eEPq2 A*:1kܱ1T{?7s&\3+/N_Z8}~;=yt|MH9ڦ\.BL\2fe@(P4`>ÚՑ'Ղt];];jOo\n/"M-Sչ#1=6$O&JNrĆjEHwR^HƹD`P[,^tOAjK??;b0en}ywPZB@>h64d'UT`*@5HGu&RҦ^}Rr([W$B7n6_P${c~`dhT@||j4h-j&whQ2 lr"Gu9T·g"L\c$<\λO&pWIhnyr pFέ͋/\z_NZ҅g~Yyg>UT]әG!dR/ƺ2E 0u $`FLHlWr}*3Xqus*\Y[,&#vҋZVSXXw(֒= $~Jfv*-O\}a~Zs `:{(oxf>aUV }ie&]pjva«oggϣr F/+иs\C?^ݏW'aO|lh"hvCXGn,N *&m^ۿ/gL1pMuĔ]bO3%JN@*yF-F*ʨl9<=>lNU/t#Y2(T SC%5Mi@ 1E-N˲Z^Ĭ 0r8,!G1; +L 1iZ6P CDѬN3tyyiZ #ݏ5vic"!6 +6/:Aj&e")Q* v?^J6*-T>Z|LNe#+srQ+vwl6g@LKTDzpC(=B!BWz'y`|H1 ci;@h 1`BL$ +e*G h)Y) + 97:gֵB CRKjr)\ZBm_;6 +5:LJ]@f{PDN>4Dj#U?h GFǛEb\Ə>a!/ۡVq %^RU"RHuM7}P.D}l5$!h$Z^9 JnھYp =[\:Y$jDru +{b $= ¤dG$CXid"ρa&. uFI{뽕ݫ GwooYd5BP[\߹F)/*F Ƈz0!z׆G}uL|A)NÊY(SRB + @*aBu%,6?ˇ`GsrC9_'Z*, ff7aN"PZ^yosS[̙¹Vq zokq˃ b:BAH M@ 7zno~s35m*\WSK֙oxⳬ;> +ũvu14g@ +O9D@q\MvX# 0Nl. l*PMB 5+;D}M/Ιxg_/Pȕ}ZBN)ੁ F bWj--*t֧vH4W J:0Ejkg7Ll̍<ΥXJJYn>)hTicNMBRJ h/ N+b0!PWW?/Y,4 + ӹv{pvb$[+= C# ;bwiv4~ sf蘏X-Ǫ[R2Vsj'XE*P1M +ӹX`܆X"T7'M 3RFA`DRY6sRXVmv:GcE`a/PwJ-D&|!LKB#1e󭳗Hx Q;ТXn6BnԆKj>[98bͧPkNZ09f{tP^wA&4ALJpCI%*/ǚ I)kфd+;̞]9zϜ2iP xjbx7n zA"\H m YroⳭ>ZgMpTd&Yu#eC `0)=8C <)Ykz'-yx7I@+UdPsf"4&憸tD#՞ݺD>q~)Q唞R+S@pE g7.$>D0݇q +hT`eO8:cL#y+7ٕݛAPґz,åpy].Z!΅ӳVc16G'<>":Fm(4|qLFV+UPָ'bn?(!}Bm`9}ԘubL -EKPw'yQeRZbXy(XTrxz8P\ʬT(rIAb6fP& '<(D8*倣E(m%>Axu+TbSWr̉&pp-Q"esã^é0H+%`|#`I)~zkK7^,.d1`YL//R.m%&vBc#dž=Qjd EנLLl,HB_ŧޝݛB  gNfkz*Nz%p*B}OQCzIPy.$no>x~yRwvA%;yEA? qX1e5?=beƱa 00&$gXI,k Xg!B`|ahIe]>c|ds`>`%#c .1r@s[{kr?X7@A<˜ RL`ALA"4xGIN9E?:}xF!\p)>;Xć*_XQ1׸aAwᡕP3C@V}0W_~Kw_Q\)Jsrf%ލz'nqVMBTR˙D{_+m,y`vo5gxfb\lgOy+?*On^|ZΫd5()B̒B^u@Mxp/K0&ek!8<<` y|rAD$qܷ"Z+gɥ jb_̝*ԖELrzʈ6A˯!cZwp|TLk+jMNTe@5%Z%&h+TJqe\(wƳmhcvw̽sVKTƥwl~ax /2UYϟ %.1>14\B F̍۱zthE6In<+|Ts\>|/>33B.D@eU|lO 8 ^0 +&:hOY^ͼD˳.'Cdk5d_MPZQ49jƧ !ۜ!=6H1ϛ-0|0KQ1T)k])Z5sQu ϵ ;_>PLt:2kTL_fO QDR猊 R@d+`#,-W?<*@Th i1RA"1ך?b͢SP- 4`3Q<Fv̆V] ^rxkONtLOKM3D(Ƨ4g=9-uRop:V=&E)\43ɍk V<Ʃz34b&'a\Ms>F|2UY1c5 ' 062py?|xĎ Z$|Ƥp崲hI1 *εW.z~czk-]uDbbҤg P0s^TjNi2KR;fEs'=w=0iAO.]sfV{wӧ1MxPODCbPO1}e)9hDLuvOlhdZ p:Y>7 7i/ MI!mzB8QTp6K~}\s*_~aP*0 +jnFN\ӏ*QNSryl%(PI5:ٝٿ~ujp~:͇;Z3|7OPJdGޏ\,REW`PIuN8 GƔ\v'l_ylg+)Z̶63'>&Yp3E(jsDEQ-[XPGAg|>-ouI9{|!Z'8z7 c|jr@f~a1> qq7b~17ultо +DB4tȅXU1@hB6l^814NLxF|ϝէD= p#0rS/N'ݳTQ.z 㘐E3Hkǂ 78Ng.\KvgoM]S2Wxo>aTǪ0wê8%Opqa5* )G#. +(נ33~·A._`UwVO;dg40x8k~,hbd}U\&T E \h1)Om9dpNwJNJfmkQbMJfaij/_5)ڈZoҡPn.X f@PFnՃS%_txE?4|(]#m-vv|Z9W0.DT@cvZOLԣc#@8IW)W8#>ع537-9eX_?׶3^\[ DmCHALzIqC8h:Yz5Fq.\V( !ެT}cqƹ;m,\*)DJCG8>uj| => r";6 Ja&730-X+O"Ԛ.W'gew=-7}pKOm ;^xjdKK'6sSvH99D%O4}VzDP%aݼZ ;jKgHkG-2P>lon*Y/g!J/X߬TҕQ!Xp|^ z{Op89%D.m^@ qmDL >Del%:~2)h# +>)t/yʝgŋ jy85ָwX`lm%v^ &87 b*XaPzoҙgګ¥eL,0Sϼ3 X<*ǙpDjhZq2w8-ϩF9t{~rmn/ZYt5̡dՀ4b<#eh>M@ >r>Pv7]s⩅]{5)rIl=婽~[H݄ҽ峯yQ1GP Mk_7ˋgHc|v6^[-Nn_uE3} MQcPшT`F4gԕxR +YaV@=qf e>L¥3r+t*Du. H; r0;z8 +:)$e9q4 c&fz9jjmBB({8%RVMta2 n n2DfvrgjJuG,vjl%'Q& +cS&%{5X44=> +"M2%Ecǜ^p &q7q./ͩip>bDRl{2shd+^[`rZ+&&=ÒYV}́\ %6M!`q6Q>\ +٥So<3q8Kx2^53.5O\… 溑tqW~)D +WWμtt}?7xWL/\+/V\x7/}磗ɋ~߹Rk=xԪkϟ=FTLH^-^3 klFIv܌h1ɇ /fVOdgKOhٵ Ä壓^XRB9=laoڼ%2-N/pW 'Jdp dBxB~"ryOZ7=>B AQ&HG|N*Y)5lq6%9$X5SRAhp&PΒv hSN H?ԨEMQjSzn LW)Nτ2jjZT-ͳjT2cJDQ%>f$!F*X(v4 hat"04&ÜRD)Y *;g6X34.FL db"Q]OnVԊTLM]չPv҃*ƚY0|Mk;O_?b7_<'ʳo]~jvƽ珮|x7;V/Z&[|ue؁H)Y!Ҷ󴚕3/|AֽȠ}QXHuY?js6gO闿R9B,@xTZ>wi6^:kNP!:Kԙepՙӹ.kU!&e!(EE-=90RZIvZ>xs)TRSnBDXZQ0|mNJR1HO]̆d7e0]0˙U☓8>"\pAܴI>9P/aɉW +;b ̐R`P.r*,j[f6k+d7=h&Oj1.?pUuOwAg 6 +6.y#gHܖ]6\T!vLjF(LZCi1ϠG6-ex3ȗb@$X:Y&=iBsn_LTrd;B]L ퟹzw:UfJ*(`t}zL=֋fh`&DIM7wclRkzf)9;|jӀAZ/g^?uʑN{_8dqr%(\2=| OZf]%S[;>Av-|홷!q.R2˫g_9Vv[yg|Q'>IFkqyx'ʣl>nGdž!/ӒK0Y=Ә猲i2Z ra@0LȈU +bRN"Ս̉ZntyxɐWyXOPd{O#|3>pn}UXwPy`|"B(u%;ypIWC6M?dXыn/Dxy ]Y/2|| h(rQR0ZFU'Wo/v,7ifzᔤʳb'u ѼscN̏q 0Hjk +"0lT9Zj TV};cKLSs9 4r"$AH(A%9r8۲G{9|s:--|"誷~Өt[vY4rݼl"М\-1 +<':ٕ ekր\oU@Sh^r3qٹtY܊]ڔ+4#LCi/Mnffe$%mؾ,o@PT؅#1*%,{/aQOs11zַMpBd׹{. L `I`'(ٵ+VUӸ)mj[Fh Sɲ଒ /IQjݥvu"mp:Fy*Bi֔\"Ŧ=MGM`dr}SsiPcR RR;֩9+Znr}58aP2NJ( M#7JVoFN +gxXcFb8N((**EҼehDhY8囏TBI9^^JۀOxνL! +e2iQ|/f*"…$ekML _S YѴfO.FT׍Dˎ~J;vq٫c|V"dQ5OP hLEHm(8Cdx5!` | N30&MHf5$A8Ða7JA84v wˆ'fHZ!*XWZD`q#, f`{T4D CCȉ2#լ! N\,AI̧ACLrAw0~t X33{0%!88#QF.KvHv8O3s!IP) &rSkO60JOT(S,ɖ0)-_Zf"x +ǃ8Er^M;_c||*^oTb7p"D"ͥaQҊU( I"I pEHQ +Lۭ5ړJ{4-QdD!rz&JI)c,ّaL3޼,ڵXANa\jm(M$C +gPƝE8!%d0F$!"pC(WڼZAH3Ƞdtd!ʊAS49UV<F GW>Gv$% 8h.)`Š.Xx0&|04T :'̓O!<3S3p4rW&iNA m`%C;A5q8Dx"0?y2@1/cϧqLIYQ $8̉Sg"@T +kg/]kPJ@+,RJ(b+}kb_g $9Yy/ˊ}$1q.%hbwy59ْ5kJqZiD$ hU-0DҌZtGesH(di,l<)>"X90 e%b\`I@gQs`KCZ<)Dc @i +(рQ$ -Xm|4 +:Zk{AӬBwqs. fa$dlPž "QxNED.V}+ZfT20VP ssIM*bYwT 'X%ZBuT,FN)&>{"#`qT׳LH] +_gUJ{UŮrj> YMNp0L"iK) t%g*mh",*x5% Fh4 z$ R)E +PC +ɨ*jf5o]Zy핇o=fUq +39st$4C$L41 GMU!I&Ȓ1Z +fgfO>qD`BAԉqa \JXS4P SBa"xXdYUz+U}]?wxnsy<{qsW] +A4JReKZc 9nYCV湋?ڛx?w { SQqB`:@ywz4\_4[a.6+ۣw.ܾ3yk/ܿyv*AX*ņB3P8}2x|0(HU苝oJHV|D`ɓ3dI'3lhM_Y5_xwo{Ͼ~g~K<].}X:PUWKZ9ۆnnwjU><mko?\ō?WJuO#(IJ*jdb//7ėTxK[}vo+EE =îfAE]0W:&jg1sv9sO}_~xᚮRh(!\ Ğ|$)PYCy%:)wgp_yx_|W?ꛯ>2kkGSWD *:W&KWH|?;= k7W_{~v6#X4M4x(6޻_{wۯm7˷~ͻʿꅍj7+iL 觨A_Vs$@ {Ks#l_}z_~x7vޟ~~G^?<|p$cfA*$QƓ4$FN~t{ڍ~wͷ˟?yϿx/n{e2)4R>?|8{G_~?z/曷_OQ{姖$* +/SOpAF3ך=^_~?}}~㽧ֵ"Y4?Xbo7.U +zsB_W>~x~|?~~G-Snق!p+fuW~+}ݷ~w~헟=hUG9lAޘ^i~ß{W>?￰(؜@S)kfɴJ*|@҃Ǘ +?K_{-}z˰KV"'d5JRur'/Ok޻O?|w\޺9zJss#p +Rq +'7ff[Քk|'߻矽z\fKD"ZvXX4ȁG.:V.vo]xZo{?yOo;{/l,lfbF}Μf'l޹;|_^K//(6㸬 o`3 -IK|->5bs^\K7nL9M5%Y$dzYnRk[ۻGx|o_í:k[D‰,fzimrt\ܹٝ5)7VW-~{/Mo]\f@a87Yi|:ʘPr^($ +Lӛ{̵s 7:`mZj~\r$ +%((RtԸ??|w/_|߿za뽻;vNISHB4Ql`@.c)ia)[K>ti\m{?x?~?zOo=lm+F.P|\ :o:L󤕺7)eFϵm/2K!+<9$$X6]us^SNV(CE4E9K(#I:'1^hlL7+4٫)WVAخ5kD( :+ēOQ2xbH_ijkI׽wY҃O-_K'iWfmr$eU/҂"fjjiFQk}7@ P3J0h!l(Y2J u ^T W%A s) ӾSv;\ ++X )zye 6de0yjv>dTTڂVZP0вLzgkS?ZnV,](ORke]8 cf#؉\ƅJYmCU +MѨK<~`c.̒$ra\t$gGѵJJލф|RjTlEu$NaGffRa*1Ȍ5t L3iXBqa=ː&QN$pS6D>bo%aiF5A;x"5| Ҵ h#Kqp뿚GBǔkiAT嬦+8а#z(x EHceKF 2!x[g)8?o'Ӂ|[ˌ Ģ{+x;i07}( X;=q$Jp҄D ^%`JeUm}ix> D.5y%-ٞ1n+#t&(iP'[UA/V).ZEհ|I/‰X K,@k O&i aˢ3r0>ԁ(#!["YLjeʤI/j'#$LZ6iC /٥`$BF(pZֈ$K|P. vfs+zD~Zmhw GZibsQH!9xet.oeFew. b_vn6ւ:ZJvOk r$.>q"vfC-[Jf9ڡ6"q2x20;Pِ|(GaWR"HKP8~3*eF+m\Y bkJTB)%M3yY\|(<>UYg)܈@ʺ8{,X/NF=i!:hv"8=QujqEyW`{6gv;m2;XAtV"Bn6JR)ERk-n4@k.G\8fSl8Ť1U05ƅF<%&Ӣd}gY}k]\@6@A*fF8kRk b-6΄(B03֦45%*(SED&΄ gHguTmJC,rVyH`v/ճVv\F *% +`EhL,iObL2˘CB2;Om \;wH{C WmS"J8Fe\sO,qi6GNS27݅YX2Y\('I_M"x)IC.)?c5C@+-\27!H#v$oHt.ܑYv{Nm'ysc\HR~LTHYIYRoވqǤމzpDQcvrqBn1"˻c=㨞8_g_Ƅr +#F vmԺ2Cy'Dl:(iQ' +ǹhJ'I/AeRSɉ"m|眒[D>stream +[1:ƼEYq1^îfa.-Xke8ڹ>@4V? xj]tSB(>Qش˛{wk׎_ 4ݵVF +g6; 럎qBu[r[zemXSp;fRPZ~mȹU&i('jqV"a7-n"B Sc{ͬPP0 SLȅvVD.SY;Rw΄ٸuHhwԝ?ί31!،;*T^{F.EQ3LgI/$lX/Dj֧ʆ(tL@:i/]op3 8ꥧ3QMP99n7#Lq̆—9-`\kg&ϑF,3ݳCPTNcSbrntE/2V4;Zq\ uLi0-@0L YdTIjcf}4x"xoԻ?k]޹uE9?SS^$Uk_^mrclKsxwϭW~︿ysYos0i͍g=eh\(mBaRb֩,]3;g\2Qt; +cWֺIajjO108Ti#bs&gֽ_}fv.Ogwkkn}пMkW},Nb3Sr\^y_^=~UuG9dfi<<_[R[jw8QGǨXEPKJq=ۿ=: *3K(F_k }pr{U/&rfkVn쳻7^+{ҚZM5R+-nqz &W&PRm%PJahN.n` Bd+ al;5:9>; ;-ޚX+Vm bYreR^ve ALzeK/U7!ߑrk@fJQ*[R~UnmXNyc#Ziݽíov׵#?woD1UZmޮݮ^/L1ϼ=پ)ʓ:wS0% [+mA9ѬLhpgRm̈́(*-M(/cięxJjԈ"V.Vק0XTGL"B VzS˫~{ a;W_Ru),X,C' ΅Jwnvp*ӽ`v2rGjQꫣzniP#OQqpIRf7: X \ɷv2!¦ صwls0 &-/ǘ($1dflJr.vDj [pMqz`V3axb(L!S?,qF{j`fya@92hRXzcHA}jD11N{ϬmqX7[ݍY[nb4he;rfl7hPvy4d7tRR+v}뜛`2|{K/-fi,^I^$M`Jq[RKS`~xj57g¨D$iVj2EfhS^P[P_`*-MdOt!TQt-љ5g@ƥ|懅Zw_[Mʮ)-9;1.+{Ol+s ϲ_ +. Ǥz{a|bgFypomo~ỽk 7;Vuarɥ/~dOA?6Ϫ?8&SI5 +m-bfnqx +S*id5F{{ achv +M\R\Uh%VO65se7/\}tj&}z*WVEVKeBi"m93OôʞYP u{ eB8}j&$V[;R|J)e:,L<66|U1F4lP_:(4瘹.g5#jG1L_%LSji}ir ,Qܤr;:|.Iep ]JxksӮӴI^39-0aDl|Ip֥x[`zgJj8yY3:xBbp'8„[K[aXMVkr "DKS~sXu!gdΨ2v/ Oj{bcrY[R_+I& ] YŋF) unFL(!ak* Bvкfi:b]ٺPtK͂ٺ;}J@bN0y΅JiW͖$n$CxRX>Cjm\iA|JFiY^<` );.o8&QTO% K+ӛ4j>OEՍLPJ,-^*JiE)X >7Js9$ +kڢMvFIE@VgVɢJ#I_>lW?nߊ6k9{ y# \fr]sp&@ )*24Xd9gtn~%IYZ+uV 1Z3DfW&?0 #@} N Ķ  B2$Bix!dNQHMQ]=ZeN`J5?}ZB +B{TVU@ULJY1 eU9 'ƺ9u9LqzO Ju|8qeBW.VֶX)˛'I ZSrsP!G5J@j3NeݮfjVv&\wCI2)^)-]Y) F{g+4%7y8~|xͭ{|~d + +4-B)%N0_rͣړKZaZ(jBJ>wv/WA#ʝMP'XBp@%[L +w8wz +PBsWq{Ss` %$O *A?f 1~,#@KPJUmUpA$iL)q-eW%ŹgX 3aHO2R8;$0:[k`:L RJ5{Ej$vGn&0DHZ Z3s` ! pNO9'@zя]ZKqhؼ> +\$"$A[Fj>k_a 7Ofh!%جQ(mZcsX0d*kl %Ĺ0&}=4fEh(|:M1xʔL%PG]P@xoyHn O8[ ]S+|f)Fj 36YLe*V\a|лaHղSe|Vc ţ->j8/eƬ[lL& 'ܲݹ/q"84[LGrR]8cI'w: A(?R@ O:5Z]ˏ@k4GIA=P4?FI xwM01HʰP&AzqK/c!I"rc6ʞAXJyۘ VkB)Jԅ5PkQT݁:+#\lbəLʙUY,];zsˀnPO70 -V-INOΡ}.Pn V4ӂ<P% IP5tAZLᙹ I.927!#I.I0qoZTl H Rdpɘ@w°vjOVe|\*RIFZy:DC)7j Wݽյ |c4,vEkYgNutuۅkK1yjsz9M..\>Žk_,/F-3@1ƀԇ%-v[rVjE0QV?7(Z ^^IP.4E/=Jfy;pshջ 4&O:{3c o0=~Z:ME{]s!bK"4(!YoFt +7St>9v2*oC 3*քYϴ1L(/р!\%1Lsn⫥)a8!AB IQtrଂR2!fXm@` ++z#)87Eڰk{Fg ;1t 4%t>_;KzecOKQEЕHS%\XQeEilbb>>M%wtg>[;ۍ-'7g?W\Q^8zALRg;l?3)TEt)9MD{pL:Hi-DR Ԅ +8 &Q<[_`!e`@bQR_LRn ѧ{0ѣx׫ bs)&S, ̞r0j j3E&1x(WoB̙eq1QZl D17PAIMDdܧuzDIԞ'fRs );kG^|[ $L,f2(1jGOJ +S$.-ěɺ5' L*sBcU)KcqNwげr_\ŴP R2AE$9%N~SfJjqG-S"l4 %hJ#h^Oq;@ &U)sE^b0Ň3~{T+).q" Pxzrux!$Kv+%c +D03!Ru:npxӌޟnVﵗ㸍\l(DɯBwQZVe-A'CD6l t0Ҧ[10X'C MyNJyDZ~mw:'Ɵ8>5$p +Iܙ )Rsc 0pZK@fqNj$_5yd($`=BWR 뗳 W$ggN$΄蹤ꤽd7 䙄zWO>dLF[Ib hjINC0+ôGdpq",<q l5mglm1MāxZX/ hFZkr,fw.yU3f~-ӻimDnę@<<2Ht%C>L8 +б( ݵZ091'ۍ@ 3Prk E)- %fts ]Qt#N +0y0N ̡|T2.[ ,/2(<+dKӭRbd$a5!"I^Պb:S."H79b&D}d(za \͙>Pʡl>fRO {5Ga +Wة*zソPKJJBzԳ>]dH|P B&n{3\AJbZȊ0PPrQ;T,g%O^tJ̮nˈz}^ˊo\4= "iYf%=n >]dofGFنgWã/oVGZ#i!~V2 OW؝A&PѪ?+f?om]4)9)eQN 8 ZQ`r  o ĕM&jr˜ ߏw}g&xC-9cuϝlY6 BJ6aJ>HNAws +7Xq๛Ž)A℠Fn>;u/r/39\zG0h3%^ J@,PwBZTW={v o^c:J5T8Av4JjjhuFeȰzA7EK:Zxfdt N[ E`)1SA$0ZRڀBQVH!lmmeG+!!8Tqy|J`c+9G;5LܒN5T2J-Z+܈Vf" 'or"D]TA:'HRP:}pi!B.aXpYmF ? &uggNvh2n!̞W,p No`N1%ӾL7Tqpڛ]bN^J ' p L $)u('#O0)K5@\l߻F/pL!!I4}19JIa՟׿InVg} xa\wxus:z/ɻJSwٷB 5k-< 4Fi} (oqWX}kaS1zU+Cj76Oq1633' \O'{ly`73\R\3kd7==9F!j +1Z.AлvfZ8[O5oNuH}NԙR `Ad8C1Tr.t 5om벙ZAf +ï[/m$gxcWw;1|k##R7n +fCTg6i ̞,6wC-ySZɋ;)"TFψA3{vgC4}ij- sCkZjLϡـn.O@95GRW Cq'?ղPu 4/+pS*]d>$MQ٧} ](hNǵR!4JB RTVZ@+>YIOMVinUDi~x|.ܫ( Qi*a5@͇WfܩqqM08\^ß 4|xdJ +9 VXѡ_ w/xֺ?ipswurjX0z#ڸd `k1ZGk+?-N_Hzn pM0|#٨vߴ;n80v^''..ТSiPP7VvLghW:I #X57j8Mq* *jm[G(><澕»1"rӵWezjG>yV91v%ŹMJom>@Lխ.DG*&*;/䋗7j/;s՞ARd㥛#N(!LaZ*BYն.k\.[uw^E(Zy7,6ٞ(v+j &(Bi}r~_oǏHF̞: ê}dGfz &ب>TMhCȩ[..$}hB"Fm O/ )WiEL5}+:stjhm({'B@f1 +U©-FJÙJT4g ]|\ou{,v^7ђ OH.̴ҍۻ|=Fy{Ddo ]mw A;ͶIރ L3ۙ`v\ҰbB ZfJu8vZ8 h@g))bVпqZ_Jr؟] +)&7ү~vIn]2ЕJYզA0a)#m4{[9 li7VJJȲiFUHLz;1bw,_#]Ի(hCYުUƫ0MtEM!RŽC0+=;բC @ڕ{F6_|ǯpZ' "CFhtǿ'ad?D{}M9{ 1̑d%sn%WNe0|)X:㔚N{/{+;UmK;WHy|9!ps$hhvl{7jN(1L @QY4~̿WP`bLoq9Z!hdlHP|M:#0 1(tPTnh g F:R'Ln6ZaKRm1FBYVB#>Fјc=,|sI!Y<~aG{u5{ͿpaLuԭ!%=yk[1[ :ŮzO_t Y ֬)eƭҶl_Y{:I- b!2[@V! H(V{n~U=( +OqBH Ds|\B=}ݞZǪ;ȈfJ7rM__M<@J W99vヸw[L\gV~fƇ ),z ƇN&wND/4\nv!+.pp[`Mx5ܑi9)7zzȕak||%[֘Z ⽂E?g8+MhM.#H+V(I f־9qZvvji+xg + zKZF` 6x^|e'g OkD)"Bts}i#Fl&~KHF3N!RUG7B7Wi)fE +ԁ6lY3l :⮷z''5&| +t*z4L]|h#*|Pc ?Whւ Ƿe4y&C(R Z19@؊7=yӯ^Ut?S݅`{T 'jmZJ=hA.Ṣ5Ru8{edVz=է誻}/G/߱挔;0L.+ɃլZA(]x_s~3z<~i$| +P!޼%'AOeXq-ĞZ0d2g\yošm[JCS*d|G=4["$b3Ti49Yճ#X KEoL>Y 0BФ`Ni*mr\BFvb!5~QZWnZ V%U} ~w/ޢJ Ǫ=';iI pv|G9VHڰ`әC_Uś[# 'saD8]|S8x'&%0.Ap  +؉NGj&GKICDfzbzSmKŜ/G G/!=U=uۺ.1)M6|+&i~kXӪYOFj^/!{ .K Zd˿_\7pX:0"b{~'$.xX2zί/)ٙ M6vބҹևeba`c33. ak+\gˏ)Y%LC۴BP+k]/CbTtVNYq* h~oxgD$7ʬଵ:|98Ax1非LjyYЁC- P3%awUv~G،1Sg?Zn1;pUeXR*zNq' !i>\~ٯ*<6䡕dž<ؐVcCZylC+ yh!<6䡕dž<ؐVcCZylC+ yh!<6䡕dž<ؐVcCZylC+ yh!<6䡕dž<ؐVcCZylC+ yh!<6䡕dž<ؐVcCZylC+ yh!<6䡕dž<ؐVcCZylC+ yh!<6䡕dž<ؐVV&%{I/wvg}l|c;ۻϲvMswru~扄P>O +Ohԑ<)>H|s_"'lQlB w e K%XvbSss$[-X*ڄS^$;09n`#K5:"F5B9W{Z=;U,hB1whgA8m(5|}s[s(ؑKVFv(sT5:K~.;Uw.kDySJexM4yg'fr"SRJ^e1rk%wX M1mPCɝx՛3FeнaICL+Wg}RJtkFkB׽._lH%NJ1%fCj}[sޚVhET+]ŞIքs^bZ-I1-6V.N]ݭҪ/ޑч|dN+MeW(8!d>>#LL(94U PJdhNy}"[s_r.è]=w:'znr~%kh;(ˏds?? b_IX5T쑝wS|3.޶ZݽԓΝZ7Wo]a6$~{A)E SbLQSBDI)W없_uiSc +a8Z3fz77`Dz ^g?;2 .0ޚVZ8yqzi1!*A9oۜ3 h>AiBRr^l# ֯zwalHqHiR]Ԕ:iB{UNh,bUv7>cnM[g+ql2Y1 EI +VHD b^)OsAԤN tqT{fG{-EڧЀzu8@~Fju 1bO`чA Zώ7n~H+-%wf1b.#o{|xceQ:f!H|XM-;+#:R=%{S-ZN\t~띩xO,/5g BX|'\Qw^NJUЉ3b3' *a|ZjSR}JiGatl:\q˄]!](1` 5&i)>ҴӠ}*iņ:ט΄ V9]54.H7`5E 0rF t9NiZh G)8j!]&hɅ>V3smg8nMWnEZ7+v356@F-piA @3ψmNI8k$vvNTo)ozO@i5Fr +ldJ5ctH's[ZA޿ӟ墿PCs^ײ?CH!㴱ٵ^qW큕6xfnu1۾LCA__2R*kHՙB@ +V\SȚBNp)%,hN=5 +vX@9-@; L8US34SoW7X S#rc5Xh@'cNBtEMRC&W!RèQ~ZbXˤא?%jӤC`vj<%g9BAvB{pV) 0CHdJi4* Ɛ͢=pukt6 f7!g%Ā:ui ~5N~oGۏ_ϯc̎.HKap )y BNOdw[~69.B7'2}DPj.(콑*/>.iB L*@H )sX1ť!y/#N Q%*)bfDUu}S6-wGB 9rF.5ݚP%mHR[]b0)DЫ~  +&\%)T^E hW @FU ,h~CEs`@Qek$LՀBlR']N +*pZx4=R!~D}`'G &഼9FB) +D呪rY);~:W 50|hZ`uap3z;I{*kE+#\@Ekk"g5oOh9j/^ԅ"5bpϔ|'wpӐ;等׽o[-ܢJzvSHI`2:p7k}`w +hefEi /Y~ztsweϲK;Vej b\lXTgAYҨaFg/:Ffr8KM,0A.3r7ҽ0#XPݺV",$/I[! +eC*d<:c-C_ i`kCNc~oS'I +)vYhA +Kٙ#!PA!8 Ckz;Iy0Tohi!*cuHH lkxN;PąpQmY@y$Dc"|$cxcHʁi +I\P/"U4DGLoZLYq1WлFK5<5^K H7UͮN@ Jf)m^l=5CsedZ|,KJpI +  4(T@1ѣs?R$[wj2`cVXcJ&l!/=& 6qPlD%7qE1zZ!xrcZl3RrVMwNDs +uֵ3"̔cQm\{5aC!H>g?d\L4Xi"f)Dp_6RfVJ*˩mT iI+)V:0ъ(1;猪hlu`KcBȅT;kw.1z5:M9.mGw;3\V2_w[PࣦpFI VNojgM)C>^,vB72r7{gŰ'rSU?za/wZObKh^ř"x`C!vjAq|Ĉv{el0!+uX֔Bx 1!`X@A\R2 uRR6څ&8T gGKh~X*xЛL+|SDd\Ĺ5%ḱd ޶jӽ^zl2UJUtYsC/ީ + X7?aDu +7*xx'pRHӆϠ0Ao{`6Y9^- @UNV"dӛz>@rn2~LJg o 7bdnԊWZg>bNit6]g>z W(e5{dۚWiDڰl}JU\3tK75Z21v_{WpXF <B) _r6x%߭jC1J +%24/!NA&y0h A 0F&ziTЬ!B@) l/( !gYrqe-O[B 0Z*RQr]+DuB`N^mQMxSg +W)L5ҭ@>UN4"0ҳ=f£ns⃏hD#+M4m0 Nfw^hJ?qFGKaBNoU:ER|$N(@-$Tlٮ8Pn-?x*A1b )(w{V-N^S S99~5Y\׺.[}db+JI@hOBA/]>y_V83Ul!XJܰ0l-ΊYN{ $ [1?|7{j}MMp>#vʬw`p~v B ;X%}VJuN?bNoQv1,h to=̩:{n+CA:R[ r\"UIDr)|1hJdq ڛj]B%FL!@@\`v EV8A#ze=1u?߇VӶ̶Uj]ŤFhUqu&n65 doTeբbJftPp +X9?Z*jݨu/9#1(aVd}5%si=ZU뿵`.VnINvL_I6R18G54ZI|~29S!ҡ7Vve'5ihe +mJ. :in]4 +4regt?L*2+q=b海spJRh|@n]a2Z v{N6$FH[8AFJ΄uVJ]c[;kNMBh>2n mg[Am%C;e2|+iܿ0FWZ갇~k&9؉f"Q2WmPb>1p "'wTm V-$g +URMbsi|V`y`)'.V"+.S2Ýf-r%APZf?C yx)x/;àIˤWԟ>iVK0{;n)+iѺN~/߆f璱p.˴UmC T)}⵮EP뜃"y`ڻuiګ<ٹGϓqkr^(!2Q֘*e+P֒3'ĔW{hSTO&:7=iK5TuIZ0Cٛ7AdnjO!%kw1YjU'[.:`J}Y4 AҎ t tiGJHPL\Hrl).@Ӡr.YH ZdrQ=l"DLrO!bIwWl3ߩO>orqu>6 11`bңi|ak͝QP,Jj3@$J ?P# +Gɝ&j:ԙ!KɞRr[]H.՚JCmLySyhˆ׊9!/rz/(gNrJp tv*Lj_V)lx Wg{,Ft8ҫ1QUoϝ\&3* ZKuF@Qu9ӌ~@f4\#T1{I.-fYiZ3^!~y'?-Wr>ݡ<%5I T=WZ9uHFs +Dsi~{Zb;4k ʐ:؇&릗Q'MpA@:G2/C:NJُ{ P'ňݪҠYAi4k,0椾ӐK t/@sVZ)GbYƈVeB'S+4i'[->bIUzԑf%%7_\_. j ւ5TH ڵ=İVg 欘Շ7t?pâXț +m>7$4DSsg&D+p!4>ȡy! @"[hop!O0:ך6+5B-p %۫O8b&) 47)1BB& RM,4pa"$Fh6ՑbLT{!)&Y. Owq8Mڥ\A+5&$VN5Qj0p2jQ6D5#(=Qy9C@@8- PST( 7ZLY@Ѕqf䌔ݚ4 x>.]jAo[6 (LBt58ERȡ 81V39j->Û >θ;Ui۩K8U;1 >-wJ 5:9jݠw99A)j i]ӛA*bVS`zSX*4tq܃|t `UiPL*hbDdCתXRaqXcuH))h,0" M`̽ +gZSkRl$wU,uL=;S0?#w+^E"dVa>Z٥IJVKݦ6nvNM0\=C3ޒRW|^\@1n~jjHj"p`8zQRDsHi).Fִ`8+,@GPUG\PSrݟ69S:ڗ=rU:x.&K`UAHKh[SO:8ƃ7ͷ$b0htt=SŽv]F-a6`]-n,Z^D1ˋ*RaS.C;^Ӛ +W ܭ +bKICF+n5ip A"G)UZn+ {LfXK{$b +f!jpPtpadzf(J2q5b=#_:Eg'7>%v„PWO_$`xOLjte0z2ҊKH)H-8CNIh#:3 +RAX[;mJ9b׽;+gdpS<}h!dN)T 51#^rFZKx:?QSj3i]ēW7iqoZrg`bRDOxV(qΨ}љkaR_ +$nh;l~qg&cRSRAAQNq5Qψb΢KrΥ51-T+cX`@ + bUcXk &U@]VxA5¨Q,V%ظyE{׍5JkP&@=#bhE wp + '* Μh*d!wd@9Ld{/^У} !G*FO:@rv~L_vh=^N0R1304}+;P¹=_`tukTU|n.vQڴ o! ўL5^ZR3#?W#cK5gm0~-C9HRtct ՜=#Y>XR 6="1gkY#TP#s%ӫ`pvg=-aX`1 'Opp~w06)nkjp me'vJʤCPZ˶n"hjw:oۇm|̷90o9ҍx9>J >@4+U2f/H 6--t !3}LBiY 9yt/d3?A_WN\ޔ3.%jިx;"h-^ 3D &8߀Uihi:ߘ١-AL g5Pv_q՟n㹘7arv]z]<{gs^ǓKD:˛]<广~Yv} +@Vv'[vN%wЙ9r[ï_P#8S"]/?:9H!N_V)H(& +.ZLzz )` +̙;W!rgJZC{n:Y`R<ŭ;NVDd$چы>|?W-Yc|̾.cNɡo i7ĵֹ&7//BK&᭙V.9MC݃px΋;-=܉:"䌻\P6@,d1(n1U2@}:}9>_i_L=Xvu6_vG;psh{P۳/w9LMݯwl_N.>ape{f,_BrFZGF*y1Yht5=N/I{kuN[WÏxCkݨ9KN?]}o7w߻ ݹq{7^ﺳ|7M4} &l 27E0y,^o~?M6gpE˭BcCGeit۽J,[({S`B87/ӟ;~nzw8wR0Ny0};y:_Ο/K)UK.|in^rV!8z8 .~_wClfW%yo;tM^/~i9$|Y:#0x<~=:xt:|vpG/~sjKx1_n?\]+=H`|4GW=oTWI9T9J*C+uy{rΙLN61ـm؀ clpkwp5>OJU { VA^FG-Pz+9E@Kodr-KӛD2pFzu\wā+BNiPaT~>GSpe<}Kl~ NqQ]ONIOl3᚛ U-Bf. WAt7)&$(%"ڕŅCw_{ ,T,f!ĉ'b'+E'T"Z{⇿RS#RKǸ4*|j0e/69򶲊ֶc꡻7>i-=S=X>[_<8X]ںQ|7&eJZk*No7=U-&1 b}1 ff-$dzUC]1+M_Yc#U2}Lj lr]L4SKZ~.V[u6^﬜# +!ՕLw2{"ٍ55Rk'6θP %FmBul{+O{DOҳtlOo$;HEt0 +]%3hS:`1xcM/̱!Ob_l̈́J R +gxƻz/꫑ƆZXL 56$i:~kOpڰ-@\ tnHԛ?O-Ofʹ7w6-{r +6u_mD+Fadw 1z +SR%ef\=}_~;}`>x\Ċ/ڸQZfƢ1' 55=`Q@HeNR&"$H/}X@Gz0bUS]:j2wL-.@B ʙϰF(ԗdz4(gH}\r.䄇(-M!1֊p7{psfmdy$(rwC5xe+p mZiOLˏ|ﹷRIOAkMtf/ӑ.y 3yxWż8*-'^xrrC5Qez;@&ƷUTL}."U`=s5A'~&e{@W:73br2u6;LEG`e4rwA,|*7KcsSwO]׷BEVmYnX!&@n#">9c4Dq>Q)DžQ` D'A8-!%"eQ7;A)B@9J`u2:BlށFk"k4J:ugz2R +Ӈ>2@VC-P=BNpg"!6[`19G^y +`Q5 s@&`n`R +.ʏIQRM)-"xrlxTɣr +VHԜKB} JtvPEE@)7.}(> p=p!*D"JɯԀC<UpeZ/ ގ#*8rSO5Ǽ ׶]SeV9rw4hia|L灧[}xDw7 jqT,b(͑J&'D?\@H%u'|R˔VQ3ɓbg{峠F5rUPKgBE`]D +URkة;:ܰf߈  'c4eE{(&p&+ S1%S>*<;B¸p8ʄ4l#zb|yBg8,sS#SV木 + W9r2}bn瞩;kE+sn? ]t0 .WP.U$$ 勥#^|>{.ͮ-O",`Ņ`gsv/c1(kz 2r1ے*„t@EXܔ0f J-&@42ͭqP}t+RYra.4Ĥ`>/%R B,8! "jx"@6hsހq2?syi-]-\mí9GyPR|.G=^ zyĊlJHv ƄN ]۫<=C6EFˋv#"PZfNṄk`b6/F75Nj9)R]=i4gl8"bxD$,C#`f `ۃtb값qQPΨ-zɇM՗y.\vꈋe55EZEXu5*.\uVk"jsF![@pqNΪzihw|md{@7C7q~:Iu:R$T #TMhEre4{HAS=BJ:` + Τ26|*c|7S3@dž3򒐙a<*Lsaccvt̎|[t&&]HhĆ^0&&xr|\ĥ~eTzI݅h/7q2s?..\ȀHwGh^oӘ"H)TNƇzz&c"亻)T"|HaZOr"L)zcf~Pܴ-1փv^6 'Y |\E}ekd(aE;.j*0)9L4872k&BD]:-C%Ƹ)546Lv̇!2brl^*>efXV/Oo'!>2\jh0oCyTD R &Ϟɉ…ҡhĆlh-%rgzn.R\Rc[wݵ߁ 5pɽ-#cR/b\v̆!?J178P 6CpbT dP"L +dؚ\[?xԥ~⷟qcI&O!V":DNern|qvhȹxw|~sͩpfna"Iu3%8#kkr>.㍙Cxƃ}ᵟ_{{Υǫ$f4#Ox`ZגU#ڥBoɛ?CO>_O_<͑r.Hqfx$ȴ^9}~tGn<[G~=+Wyd N?vϪH+TZ\9ӛ9~ȹgWo>Gb<@ѩx~d-6 qش ze#8g7vtyp|w|ǝ 7Ӌ;9cG싿|g|_oꉧ_\=lm?᪪&l[>y峗o>w_{W`}'}ͷ}/_|oW~G~[\/YLl$ӢK* Μo?r}>{xcϼ}_߾ǟ?}^=x%VR^Ivxښ^>po?O?ܫ !?`(j|_˳=fC^:XY L\?v>7[Pb?|?>Ͼ8rxa ""-sW~G??Żλ_|/?o}٭e>txlO B17F9Wuço pG__Ͽ}>u E񙥥Gpyw~xՍD&~L@"AYV izX:x}=3oƋuSK^ˆT/4bɛogoO>W?_YM6eԤ Gcw=tW_{㣏@6|;'嗟}?'~kor_5:8$LOtba=S)7~7~ӷo?諿}O?ꫯ>_zG/u(Q +\&Dm|barzaǞ?_zWͿGW|ן G~EV'esN/Fsl8{慗{>?]p>/_}ç>sWnEsMF9|Յz^±֭}_? ?@f~/oy~_G;)8l]>e0p.5:sGOu#/拯ho_}?~./VcTu]SjTirTveibfb}}3?xճ/3jH) ~Qq8 `"*7jv17?v|֭s+:rR{fAfX5$.}O#IϯlNRBf{}ܙc~>Nwgg#!s(={bk:_mMv 3'<۟|__y>Cwmg{:>#*NS!7"ځ-N%^ɧbVy_~퍟s{?zKZnƳz`.cBpŏ+* '>?x7_飏>/y滏]xZ/A(*BV'wux;j# F8311=x/^|_~/>SƒnMe(9d\4)zAبZ_߹vO>kW~?K{ާyxS(ֈ9`@ D͵kW+wc><_Q)V0 RGa +9IE3\nD%hqɠM;f@P@Dp1L&O1ͫ $#Lj;"9 ndjw`Dq)G(^Qd@`!ShM7]]$ <Xܘ/8E$#'n\&$hPºJT\Zx,:lV o &'caE *T&áNXEf4YIaIjCV3FL۝4Mr.WH$JTkwwxQSv-.!tѡطߺalN8LHX +d2vkמ>KjJR(h {yŀ̲b-_hNs銒)ÍRKQ>1?yr 2 "Ǣd2bJRRr^ҌCQIZλ,w3 TbE 1T&A{|tZ {@r"6eC->:ʯE˫ !gr]@AG I  076  lnBZ1rsĤN 9`Xrn h~<`ЈosFn32$B#n0 tW@Uw3d(&)d`2}.D4b )71!=d3fy`1]Lsq#Ub⢝{3j(n@ ,~ ",.bslaf'ҏi{1 /ɘ#|lqe.$H8[Sci^5V{C(! +IGsߠ;;^B !"*p{F}lCٞ׆M[́}{ǐQ+E^(4ba!&;6"=:rZ?e!2V8lr;C{t eR@Q3|]i̤x8JI7P2&Ȩ19rW!a%!Nv"+~.LcBP +#-6҆ [!mȌ_<R d(BkMS"evXPfZ3\hfD `'PX#PrfiuSv7N+d%1QQh f 0#7Иq`Z`ldž˃EsV'ef'eqހfCZQS礤'LىLnǂ@0IRtg +cS)$A.D(|}TF܀u +1V)&kjz"^:xDZ.LM67"Q>joo@RVjRK!XK7=x=DpFgLs!?FǏ)AZ  rsWl-)Hi.9Cmrbi!BCۯٝE{ HY%d'Q +KsVeTs3\^a@3A ΆZa^o@Jת@^fqnDBPjrJOioXbPS)T)&V|T ;Be-ZLlqeVaL +$ذ%MYJHo4[!3]5Ӄ,bR sRr۝¾φ0 ;!"ƫhvE+1SpI\َZC.C%̆*AfKapSe>Kө1ޕDAGǙxGq.w?X8o8/x +`!E:]D|¨uA<&^Z +.LwUEK˅Nkҡ{1)Ay9g(|{Œ"r歐_M'S'{.2nGC\h + iDL2u.$<ojN'@,K a湛OJ@#Ab3@b}1955pv֎2Nwg%xg7=\[?P䢌2 +P<uMZ/ݬx"W 耴AhAR:%4>\&"1LPj5FuEN|O@rʈ18P1RbBI"b ll.,/ÅRd\Q`(g2 \rDOރy8cl J؜l4*fs(=Oj)RZԋSG/hcRƨo:*wT'u3$鎲 0f"ʥA:p^J:jvPᣃ2 [a֊zq9،ͭXcSIO{0Jerk&r0ݼ>V'3Ơc^"˵ڢD<{r0lPssV$wK pqu(Z^["*'4P&`A-9V#}%F\grR/Q7"s1wkߙ9xx^LQ}ȂS7MN·QG +@ԑbIVJoַF,,UZX V lоAAa3f~4dvPaփAnpiaP QĦ)[a"BFddvUD4c̗Ԟ@D@fhg/r`r(?]X?\;[?O6L4 1H^2tnZia #@"B&QgR6XHYL)@ +IFJ:ũ#ÉrLs8vnvdߎGM^P B0:+,[!LH%6I6jŝ^cA J jf4{&>*|/rq S͝cLaH] f=\`}&dxyvd=XhĎ!0`~aKtsjyu#R H(f\i N+&f`{{H( +ՉznJJϢj3  ^*evB $mfLN Vb(ADyKw9tvE&6k@FHW5bBXo*{%@GD"eij} +9qp jaKӑVZgC ˀA'9<+8=fg{ȑ'u@\`RH%h7HSs6BGnLw!XAM΄&ŝTxmi )ں}~rT U{'ۋDa>SG%X3l#^ I|t0#&T|u,VR1#8X¹rS +6/'+̘3r uQ}+@ˑ֡d!2ggùeBnbvco hrP/-pMOۼCK陥O~|5=y" qԣ;u@؅ЋD;[na}c>19' p>6M(i̊X7`.Gk.=PYSqT&T +y &z8 1/"QbrZpn8lro?;xOA( ~s`n*XMwD @¬p鴜nhI7ryYC!4¤A NK؁  <`?&#ZWQR!nmD,ϭO`.&{Fm[jf.\`)"V+hr6 F@锞|ug~~; JFGKkݭ[\. [$@O\ك1&ŻP$EuaӒ(=ٽ(=TqATΖ:'V`\,4趀b `(LǔUJ]Pt/w6rV;t +UL0 +ɁsR|.TXM[3_Tk-fo2P@˫aFH% +Q=B&:. ݐT6X|2,'N|$1\)w9#vf*vp( ;b ܹ6y=J$!$bp_8 +q1\NnZ?ƅ1IEJ03;;p Voq!, LqJLxգ Y1VИwCuR@tԃ)w; Sfv\]9zxZX2qGy&D + R|/noG @AR\R89/B``Hh󍕝12=,pja\fCFČyMV"1Vz@ޛ8zn0qDmSr ÏQ:hE-3 Ttњu 9% +9lldd!2DI-Zq5m;}GBFK۱ʶi``3&4{]AǹtKګw3ưe `vͫTFM!gk&fy`(<&ùi9r2o$:ۥc מ]> .LAt/<55j96a cN +kE "ZO;kۧk,q +J4 +K^Um*Xv 擃+DTb|Rvs"   zΌyd[px{ۿpj9vfTsyjʑk|L %c鵳@zQ gWN}zaݏFq/cvN7j$pvZLJzarc#Dp:T\ft` +eT(9;f9lqǘEd{=ÖaSP`ɘE@KS/DeEDO#VQnr#89t Y1 ++'>LvN]}j g@ Z*F(.`"VX*NQ| J;JѠQr5 Te cnBp4P80-EkQX9|z6XNwH b >\txi?a +#xQR6QqTܳuK9 pȧ&8umr2)zuҵ%%H仜9Qlf5%8 ` ս.U +b ƪÙq~s[1:ҶTfйLhq!aC e6/k$LUT `&qU0@0#gm."]^d]C/ |O +q,OM,ց$1_9x00.1byQL;5Àk;upnH,I|8ն;PQ:a t!%Rnd}`zr~v:l.Ϊ)p|tr/ Rltfvln81Xdd 22ШvVTg/\}Ǥd sr(iؼp>sR#+,0^< Y>ܦu"8a佚m\Ol1zQJuzsxy=WwN#Xk8PaKclV@9g@: z!?8_!kX^Wq6\D9)0`A\e>_$H `3fsnFTlr LkUJh;3@R" ʊj|i4rBm"n~ JlA@ht4Mn|bz.xlvo- + +MRQRsBY%h`isc>v8?$`YV(Tˌcxd Xu9?-T4\) +0LБt7Xizzn'^MlηwG H-L ettH??˭Wm2r9|/ps,*gVbC9A"@IVm(۲[ng̼ykz_ށ += 9{?sQ`GƱ ?Vs~#ީ U S-4SNWQ1ak4DON Fnnrva_@AoZq8c&X( +GƀޙTHٵ͛mh~eֽ/Ovtởw:"UtOYÛ)^.w @j2%pØ )r$ bRZ̯zyƩvl">ӜۧVz(èVvhobviZ#S!*bkCO5 Aؔ&9v/% ʸfcV̂jߜ?py /鯑AtMDQ5lBTt3z}xRP`ם *Κ-<R@2Jr'aRǸL@+\xT_aAeWH BL +rۚc2FC/$z?̄!X\; R> +`vp̩_޹B(nn/ͬ^73s^f|~flԋ`)9FrAD]yNIu D4jN x"3\I6 ZfJI4Ng[kX-D,p+:(hPDT//QHRZIƩq8@T&[RbZ/Yދ{A)x]پ\czR\$@ aHN{{1˚ )lŪ3g+V{Tzg}?(mSx?1 qQ-TOaa)$w6ض3Sٳs{7n+dׇ3͍R 8StPOohV2y٬}p0T FD +{ވWÁN,!,쉠7ʅq5Lgj޼J:]ʪd{b\ܒ[FÌ=`=?ȇ⸗8vzо +DBCA(9>YE,6n&&RBo/"PD3 qQ%4eK7_uiuvt0t/eSʖ:[.0|p"'z~AXnjzAv.Uۗ=?{`'=ɪQ?w|;1Fa6gfzwa qT +aTȃ+KZqKj ŒRk7G4Z`2>Pq#@@AD/"1f5*M,>]4n~}U뮏yR(*Q2ްH9 h BP+^DeyudnJoK7 zKO՗ L^FHB~4,gFO$(kwX,/fž1 +Ni;9`Pg*KW~P_iqnI_zy'RmWv=! 0SCx zglnri nߺhmz-ʸ/Dq5 bPJ9_b0Ht> )aT #BT'_ch(AB+g`,RANV;fn>^]ukSw݋w綎"adgU#Bh5OTb0*p/S]~>x +gy=72d:޻ǝG05.=4DZn<{|uENQ7͝ɑ!@ iBFHM+ֵzco1~aҒ#? +!=02(h?4F4X)C&p .8"mI{On~r`E;Ńꜹfj+WsGj_`S7DgK+Ag\ml<3;g|{e,&gRzEp +Fbc,PaDG$_X [A43L}2@{A2aUx\랹֣~G[A;,R%9?qWoR>=!bӼӱJaGO/|4Âsp{Zi#YO7voL#0ЄBgW tj M67=PAF-3w{c#ى`WLsWY^oz#‰ෞ9~?C_x/nfcGF+ߴaU +0ab5ӭ\&WET;|xJ%;}Wp~=sOpZz;|*%Ft#t#RncK_ ccMSWdc~juЙܴ[Rv@f!fI eb=*r % +nM"bR`'a֏!C#L~BmzsVL?P 3fq]ήǺqԉ0+.)d+lL7I(ɴIψVցL2IP=!,򭵫߹~͛¼QF5B r"(e˒]3p)lV X\.'o|6#Q@n0RQ.ÕP==D$'>?n/GE!m#5o' g9=DuTvls0_=Wn;Y9VϷ6^8%#<6=iDI9JH1/EpS Uɩ;]pa~~SJv.9u*o$nۼSy{\,%,|FsNuj/ 2ƣJMi شڵ/-[Z8wK v}tYz+Wڛ'g.\]ڼ2F kFĠ3L&['6iƕ +c69Ur,rkѭ,6  ^ Cf= `EPMHpfIA@ vcBwQLǾq#Lؤݩ(n"7"7{Tiou7Wfk9i'%+ц)?B%6+[ K! @gpJ+UN +8?~7hQRcǎMHxKdX(k[Iv<\-]5㵼hƫdM؁[7yJCȨ$5O@x00(m#ÚE0kmw7.y_?(v_}ss&הxUOLK^Iy!QR|kV^[^\4Rj.^۞Z{gξ+NN]4rs>HB2¹&! 7<ƚ3Vs$(.l^~3[RMҨkj"\^L̰N$# S1oD DoZ~F-Př |bu&&DLBX~cbF9_elcexej}: kZj7K!O4sdAJVD8AIyRAOC)"%!&&/$LwKG=ya=J9I59j H.t[NN NqAI";R-gX%-w#aƵ04 wz$t5 3@t;;k7ui=e+Ni:SNj=@fMz[Yȵy+~*&DWeȴ}joMU;/[SbsvmPOۯ|xwv0w+_,^ʻNy駽3O` )ٓVla戔3zꇪSC1Z~>:;d=V͜t|RB <,WPQy\kwVc!~xa2 +R| |jfo̭JbM[0Rz7ҝB/a^EO0j0 ʵO Ĺ`d7jaDXhmJ2\mwIHΡB!O]c`׀eSSV~+F )a* Fب N E%SjvN|UI_TS4.&B bz.a*gbIɭAKLeιͳ9R.P=nxNO`t2&Y-Hno +),HdGHH֝jt-B=I!-Fv3/ŀ*;I0PX*QJۜL9ߘ]/rOtRTSSkmSޞ:s ̤l(. X0U[?{+\ 89=f#0B;\UӋ +A.*_u}L)ٵam+>]|lo~yoTj}ig^O C Zm=8ړȷ6  K_K7̥[oLJ§c>'R'JKݵv?P&K+oq}B޽V:%Q&85F{^J}lώƎ Xbfeo7(|nJN&(L|BLtznv箒ä*k7|0н⨏Exs$5@fXDJ4B\%D#QTQ8 N&P }OHFPa&; Gh#R b(F}^hxd, +!fd 3f>{)! { K<>mNPRDRbV0kZif:U05<ye 9 o}7?%PQbh J23#㡑QؘZ',z?x1ɷyم1>njN 0Q4'@ GyAIF!' Y{ MPsiQ4;Cp?""IР'CBs(,Z-5ޑjtfaP*mqFJu3%1HΡLك^~t`ń@xa! EىhTY9zA,0V%RilF7(BC:_V]Nx=p`"(0 +K .Ѽ $'qAy<P2`(ԳώxQ9?}bbb$D3nIKgo $m"B4S v!X(+GǠgQXAiϏx{t4"%p\XjHc:6|ldhNk[( +瓤TD2s_7^D>qHA+Frdp}yj¾ ~i Q1d' Ai# q``2$(h')rk$o!,fd +@fC $QAX8BRnv&)Ib妝PXҶ aZUJ,m)lZ\[o!pZ<>v؈/@P|L\]0yOV +&c a==P"`/4n7vwozot:Mgrt6e}ђ~up? IL$TDiѷXn%x𫟾w\~᥿/?O?s{ RI]Of&*ss=͹'+/~ޕ?w'?ǟ٘DCYVE~"a&qe5uy=?c\Zr]{>x|l"E8 \iwVoxo|{7oݟޯ?:^?k;slLxɶM,Ԋa+EG\R_OƗw>{mW\zG{[_7 @,!@"W,u9Ky|zǯ,+߾ڿ|=;oݻ E( +z3w)__5?~.~ʧOţ/>7on|޿ݏ1(1C0\QkJ|۶_Tյ~r?_~/?}pn:J]WX\&wj(xw?o;_|>7w~7g*^ U$x4H tX߽/y??,{xy^ A3k\^G}w?ys^??|vOo_Oo[G zֈFhh>Z3o5d7^Qnv׏r_w~Ƿw8F6iNY-˟Oz߽ÍRd8pQ3D\bT3wR䅿A璘˟{BRQhfFP28eZ&sq.vmyzWG/ݣ~ϼzy|̙`cҜĈ^4銁/^Z{?}_~ʿ|Xk^(<>^,a,SS8>SVd)9Ͻ|{JW?{O7}KIs6AbJi)d1:צo_}tqV۽oW>~0ӗKeaHBɑa i $X_7\l/}uBk7n-~kBϼj,! +o ce5ŭd2Z6ٵFl~+_z{G~^ޱhgjR(**i͙BrpeBM ݨ:ԃ3K/|xW.-"ADQi(hxqRj^{|7.٭L|F|,)םdGL!)jR?_՟L}[{k[ە3ng,CFY *L"Ո1 Gl*:j9&\~m2vXvuVs;WI݌6ƢG2)W#0 , +qXWlJ s?{|n<\zE3! (ZV:QLd; (Gseǯǟ>׿}w+\_UYmKoll%,r[˗ 3EBbeVd)q`+QDsPHƐRn5'fhrMIR4ŋq `1)`?DHSBc=3WvCT6^S▞pt;39kM)%Osr1шe2`&53IRC^W2eυ1+AXcA ?'"L]ܦbTx6xRʬ^̊xW^P0#Bda\#xG4I.Rfh3x%g֢\ƩDX,o8TQF!\la`C V'=x78/orYt=333c?$`\Պ>yj5Y(%OPOVx3Q:9~F]IMO%e_z5Q2:H8㔦vh1 RV1(q/YeTʦ +}E`&;Ff]M`s<'<~b<;P@+zIcA7(X8(UQD܏ֈY,V6Uf"|S foTw2sދ~D"SIƚʷϟvbI/E66hk!TD8 -B:Q:Ř]11GMެ1j  .Aj@LBKv5V- +V ݲg_FQmnk> Aޅ٭>H&b!.Hav=;-nz3ʕ`F^+G=ˆi%\a^+:8MT7Qʵr$ȵR.螰F+%/Sƹ~ AX1ZRJ`M1!O+1!̉i+ƤĦNCc7=a\b*̺e3Ճ!6+wVέH#%! qta%W>50NmŪG`ihzot`Dq7s8::i[v"`i:6 SC7 je;OrM?iDdq39lSѳ=/ G8p\OO]J&uJq,j͂@D׏>X)-WIs0_[{pr^Ffo3%@hFuIYMR"`6iў=XB̋YZnŝ<Pyp> d\NpR] a*r ʉ8'D;`f6@lr֘ޗS>X Q ڞ&r(5i(4"efV&"Of[A18X\,b|~ȃE8VhC]\y`ՏY;aRcf=*aLrYh8kwhjHlZ;p0>^!D̉c#oP(iJtR3ސ ~*q'@BId팔$t?̻VI.>XM+?"6lN"RC\58g(u|wrqVIJfV.8̕،U߳&XSvJfa+ӤmeWZX~;8k(yxBgNH,5uήu)!3}T]mW7lv"紃Meڞ}9H93dpMs;SKq>*‘]GfUpꦑꏄ(S+JavfX"9xZ&!E@huwuJ]~qIٝ ٹbj +@xj龎OPF!uǍDTܜӫgNƠnQ`'n<rKZjқ?,w|ix\~zeVrrbc# 1T&RS)3=$z0~sVWIH#?er3QVqeqރ^AJ{7gTiR֣d`&I6~K?ʧݽGlrPd^~J;CdsݗSi̞KTQ<__a&xm(?b%.*7~sjLlUvK;-n!|Q ;Cj(2KdSPiJzzvRڙT{ǹ 7o'(_>aTWG5xӫkJ5waͷtH +m*D!"Ƣdײ(m(Jɶ 3tg泤Y$U0}Ē7w4eN:s雹[a֬Dgfi`#;g<ݽNu7VbT +3Gvm;=]z%:SnO-LR" nL.JSJ-z]kP1)9#Xpzk@LJ9ݺ?ӹh,mm%[kZ#S6+gxhN .ۓ]!e5j"ԠU,r3ٹCdZPA\Z-Y=%䊐0+gG"yAT2rnY,֠4+`sz|p 3.WNOC^ DZHJnS J5+B ~Y{b0hDGC\(.%2#ggD[]Oֶg6d9P9[?Dpn+^-o'fy7@[]$1l69Gl\ќsqw󮚝Jobs"^<|ꞓO”|UؔS+$1mfPtBzIʯzGkWl>05nVU)2%5p7&) DFyYhl_m-_e-$XYsB|r&njO/?6 Fլn[bpGptF +qT(L *DP\] 9`v23Nj[w_Vsrg\Z#c]zLy. ɜQNO N&𓒳aUSydN;gaF`43)FE(aBcvHBS#H1&&h`(E`W*q`tJ׀9`n_fS+\Hnu|zlQ޲{J~Yko| He.fVk/r[wo2͍ iF?ӿipS"沴Zs {qC5#4@ÚL +=\-[7 +B%++Vvljڵ6DM`̦G}7"0ze_/maRaVweNy)br?pN`n *5OOЀCjJŊ[5RAm_XFMŘm= +Qi pab.,nc](yKVuM/,rX?{oI W ;ݝtkG{eUeUwTZhz3 ]Hs! ]cl\0D 'A9bnnOr!4[+\$o6MO׽A<?3&g_Ogݗw88C;߸Aw~;{L.Q12a69ݦ &l8ѓ.hf~KӚ7Wϧ_e0HdOO?_\~>; _|Ѻt}Ꮫ۟5ot+^Lъ?l0F4<o/_\߻ /w b ^pg106Y7B?}ӃW`i/fѧ5Mo[_>|՜"/oG@lwB]M48?ÏDky*y+Ͼgk9f>~5gV9F5 +սyqꃙƴ?ov*\v{$egI>?Tgtx-Gz~K٭u6Q EgD݌wj}/<`6J_*L0Iw-%T4Vo'-o~z t:Sۂ5T̕`R[`c7WrBnvBvhӿp[k5S@(LWg]F \Fk FmqF<#YdÓwช[eFTp&QBںދ?~P } Q2EgN rNz)5kU'-\hjs} HD^oր! hcA:ejgh4~,92?&=g֧_V/A8y?|/B颴N֗_JPf~xMngQo_.y>k^dOH>Q͡j 0&&6EǫMN4P>˗oqBPCjyg&trwN:{{_0RX>x׿_`jav3ۇ7ϟu7p6\38tE Ι|TMk6{Rd茝֡>ᬡOtq(g;?;gYo8t+ukvPV~dwO$F[r;I{c YA V炥Qe/ޝ~M%).73^e|v>ڜb\|D1FRu:@ _ fw&|]}?ݛBQ|:&P4:? ۳K fLQ:~.@0J[ϭ5vrǼֶ7=-$u ޼l֚6V?l\Ft gj \-ZfO&_SVJ%flV"#a~/.ENOpcBǜG~FŠ5wfW56xe&vlLfӃ78Øm޳n)xl0(Rj_pfgܻ2o!eHג}o%gbsśR[nE9UqSof$v꜐FB@U>(0>dm !Rv7Wu6.xX4`x=KƟp5ƫf;ҼI31>XWFov6SCBL%a΁^E3KZh9sqrh Jh\KECJԹO>'O))]?& +:F3CSB,;33䠚QkۯͭteNYlk frJ(0RiԿ&^x4EcpJL;3d609;H/@洒rHFZv{7ӽ a lOuojgpto .T F4m-g9\g? +m޼9}mg~jm|NW1j epp?nB5f܁Nx5?O5]0_j77uZ'Phl8$!Ưg=0/(d>w`ӳOML 9XJ/;yrE~~G{WJNETxV ޖsAZJr'ڮ3#G77{=H\7?Sut+\UhV ong<|G2 ApGo] (Hnc͟a\ + ]>R=9qћ+RC}C K58o#q 5l-JhXGtMw8?SXRjj +\$wpef/{ NCT;$vܗ*4#Kz 7j~ښoff(yv?{9?`ܳ͡)z7>^Pø{䴏DggGZr2>;AxasNcy88:|>6%g!IZ{_ג_߁ͥtOKkdgf\]\9yWۚ7΋k^eE3ޚpR(HV8cJCk[ّa|:JPΒp{Oݷݽ7FhK{/ PF_t B"]TMщZk` mM|\+XE4tes"=LO` Jumd-p&{b 5<=^%"wd;wM.֛)+vp2='gœܖb^j|<F{t/Ι=6jlo._KR*@Q&3_Ig&Q-j_Q"Epz{?aD<}(%-U8v[ǴҮF9lnhqZyNo'FMPңa8z1~!Fux<lH+1JjҌ,Dsqq fw1Mz׺]Cu˙uFuT|m8YIƠh[ھ~o:_ X X3cRk>ug_s\De/7oAm"SW5'v*YKfZ֪7-T.qj `PzWttT,o>m_3J"Qh%^:o[|t"*Tj +&7;ZڭƓFbˈU\&%'׽o LޗW[t5jLڻZ~]xqpN׌\xhA8͵ŽQbwO@W xt#ZAzQFyK0-P5x6᤬0ܪ2F#^i<\k٦E5ʑ~?U6|-{bA|̃?qvhlJ0F1U%V.Rd@<5C3@l$Ca{ qRg.x*` +&B +iW{R$#/zu\ݍ4]`=x}6{ae{ +aBD`5@UrqVħ{NF8_tQR8QRTSCBպJ a4kb3B1::?9㤨&Dw/5lnA(Z|j}VJ Zh5ho`7@0tAD)P[œц5fUTk-4kq-J/Boui!%d;69{\HǙArޡ4g2{-]ٞr0ӟ϶Jf6MKQE)mv0\2;PeZP3lFsCǃk IO8=|#W3D<qYj.nt)]CA`Meee x kt/[*Z@ڊ/έ&<k:N +a~@Jk}1'1o/eй @ղO4^G +6g&kshDsJjFQ/C2 Ɍ#!yΠ92fI_0~܌V`NJnJu6ۂ=k_ǣk=y3,X}Ȼ3\nUi ` Ppsڧ%-'%TuwƊi%6PFUXF(\u uoTkVjjˈIОdk6ĂXCM8|%vx)R]Z7!dřrh- 珹"rLHF)ƴ2{n&K^qE+7`Br3iI/! +'>!zrj +U)y3)T€bM^oݰwfPB +&Srk:Fr w'U\'X S<+G;hf!%8~8#163њwOPkЄ & 08`$Q.Q?eDOEgڠ|=>r;7v~udw.'˄lG(% `R(`{ 胾x!X6FX5s 2֜Y^nȦ5X|``p7'@cT( j_ro" jrN:h\{0R m`~2n6Fb@2S\rN99x6-pMu$jur.{PbYCHAڀ.W]'1%ff;M{6;(ߢ~P&`4C= Fb] * .8 RCiWCV*hWN稻zL?mib4י^ē5İbvA(5݁b65:91uhW4T26sF 5g p!.pPn밠ZA+MRs\J Z|$Kh=ss-4`ܯ (1 `G_b)E +4hj ~/> }$U0xq5 *X AVH+c> GU+#Ń$W eDČ1ƂtBS(7$ XHa4OrcjC#ܨ\k d + u$h"8{~We}x +q#YegF5Z}@YlFh=}|1K)xGfAF +N1$Dy+#>Z Nd{qykagfr`b`+܌7֖H%'LFhsE3hZNplfg9;WT=3ݶtn-NZ(>0>:<39BiqK5'h mAk~8zEG 1S\luN۠dO`\hBtu6=Puh QfSp%I z`|zcVKeohŅlOGנ7Vg_[/xc$CE8BČW`!O0}xNJ).97A)IN\j[4Jv>Cdj_~/dxev#<>,ހz!t{uRh3-G??B0`@'ȐbFV]6hJzu:hy‡% -@MZas3Xph \kCZH.-k`Dxcmޚ[ ZG`JLipw!TPA2ڜڄ?17w>rB-ZI8k=>P SpnGO>ڜYF)-#=lbTqm6Ei L<`Ar}X'%H`1@h]ZM`N^ysj$sp@*x1#ih- ,`laލZeܮfU۪ L@FewiNM#+ڜI؎P.╙m@`|PvVǚ? Z{A{UFjqf_vj"kHcuGs! BDuگVmp _hzQ*Xqo D6J9! ڣdeJ"x0jb߼S _a'rZ 8;pŽJalP.FH5j$sO_Zt L;Ǻ7**y:K#O'[3RM#ZwJ1"xjBL0^Y0z'v\ЊK7K߰ Ğ2(>y=R!1T + +Vc%ާhQENTlIh(i4J5@ ,JtVqWWW 2B mIVE,40ڂ$hԞw>QA!߻RvM[ EOL0|5BN[;4Ȟtt} cM )4+Zi. 'tcΘ1ڰEe¬:[gogO蠄Ej) uhsN\*j"Ż=3>)9( +`*a4QYstWϽ \4==lSxCws_x/%E`jLEq:hꯀ@eU'l0AHBm`Fk RlrWW$!i1̮\V'_O}\N$ g/Ie(;3w +ꮋ"~k'(*@S^i oFH)b0*θH63W  +=ZlW?茵p)sX\`Ph4g7z@(uN`mhU9mr*51C+=C524D!`KBr 5w*<ǚ.Ի[>9'm+~uN P H#a5aJ;띴ƗWܠC@TnMuNSs>(SGHmu&ܟۻ{^)5^NE ++-o ycb}9aOZL;w"-  endstream endobj 112 0 obj <>stream +eIۺ4 +"BRsxO gQ!X](nKp%}فIsb?:D L"d&otxsEG:Ũ +%%N'6ОQ=Jmy+Q: +AYP0rF[rjiɆ').2E uԜZFqҽ-W5KH |t֙ 0&z}1:0R Fj;R^HRqkS8y\Rf=&9w +"B lX5՗`,)Y v06z5"d3 ƯF~[(2bkk%cNQYYqZvb~.Fj->ގ%o\6_wַz:f>Ӿ2L: 0Qv $'IzП}a Ơ9n#L`$k[8ċ}5=ۗJq"pbgc=nc-ZycX*bL-ٚ8nWppRd~;nvRZPł # :pF1),>>-[ӫ3LlDPV 3F_*D,ix39Z[6 %wYk_Ϭ! O8gIiWQ>1c#O*NMd@ wo59"59{lNYgFBV@@rd7;Ww]hJˑց͔pJ;*ez駛52DctpYIнWfzX_=#c8:&r| 6W_&\vx` Q/X2Y-X I:uٮU2@j֩ Rܝr)P-IIg7'sD5@?R̍hAU‘W; -˨Uk3φazտ*?ޢTǷ= H0;Sn eȚ{óo{}#8>mJjn}Vz?Hʸ PO"n_g )\q;{ $Pџ͍.k\C7VO}4(O5`e*_#-Qbw&_۾ +θu /w +%3/k6aXrOmgkDxwn]!%/Svt{R(ۼ1 +{A6tVZ[R ,V,!d?gW|&-$=wldqVuI)ׄr]AoP֫`2A~ r]i4\*ċ %؏K$c̤jQ#3V _KNJ*qeCPvvԌq[|X `P,?_ZN;-w):$ӗowվ_Ș}_@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@x侍@ۘo!~<5fGOT'z~i/.Og総8RLjGl9;|[>cas1;\UaSy>B׽F3S@MDBGG1x$GF4`Y "`#XY_6??GG죝ңnR"?-aFɄ ?j2G,P΅!S$ hCG(B/G8#Jߝ.n=yrws(Џ(E\ 9#=h&6OgEomKəR Ȼfw}glZ9s"zk XEx29=F3լθV2W1%7UoiN뜳p>Ah.<<$-NQ<;:UH%#䘳[5fͶ:Ok9;&." .tݻg^3JYUL#xBhqfkw 6l*$p9Ek_)lX&i\`K՛!Pl"E?# kw/1{jSبxq oL`NhmDk2n)&!q6†܀eâC5ќ9%5a*>[Uj5T3vAq~!<)eLm9Dܥuh} 8rC%U絑hdg_<6) #ۗYN' 8!^ b'AY CJy5QЪ*]=:5ms^<J!MJNd\c9ا":]svK)!j ZFcB룬W4g<  Yʈ  ..eQõ{ޚE *x0;{8 *}pҬSng%ckMɻN: JuA8WKeDV;0۔ä8ܥvhԇ quҮ r\U!@h(_',H$y:٩ PCu8v& ʛsRBW6Άڅ%#.ysjDBLטK$F1ҽ]YB(Uޡ:l}RAaLĩ#V(f*;OKmvLhІE* J uaVЌ6k'u;՗.!5҂uTUy3әN78>%>!w$Hx iKCRz!m }adk'_钵POsƋdi;5ʁ‡k6{Iycxk@ٜMygF&tzH;?џGvrcs:5ƭQNQ+h fO D)Z,6ΥSr `=D1XyKy `dfrW!QQXr p>L [ +n5ps1#) uF)qZthJ5­`TV5Ƈr9#@:uq֮z >@PPJ Τ0]%k;CJP;UlP.)Nh{۪庸U&!X)E+.W% \cPO HmRUʧ:%Zɾh)!y> ( k U=9t܎)dۨ +#ɚp7nw7`Rc_iн7=J@@zVS%<\Z3q+!U%k]zEuYgE8yN^Dn~41X(Fg EDc0!L`b +16&qbNtW +4\;zRK0M٨lk~%4FKuX NGq]^.Ph;uUԂ˜uW[(h*j4p~ K :a!QPq0i1RSAyR\@$8'eh ;B@7]xNm^q4;UQ6+eLBƫu@&f8S߹ 7 d=MsRz Ym{ i_uGw_бE[.#Y3߻._Gj&c)\KXѝP`Dkxs&KH=؛?o1IIh/S[PޮRK/B +(p<1҃ +iТL#7i]sp$)5Dў+5=b!ORnUiWfr"A +O`@A=2`0ڃz&ؙ:mN$LU +4 <`.R2 +*Bjy^Kt + ]0eUb7B> ¥f0~Fq/Z@aBAvIpx۝Tŭ?߮ohP ¢j;n]hfT_`Ҕ!x DUbۥvC (bCP@`@Vq]^˫dqn/ZΔYEM f>#YJt4s_Rn]$ur4dSC>H!LlaY8~A-fvQp\h;pzӄhYe +n:X6'='z@0V ʼng pIR2+r ֎k,x=b9'? AQa!ړZj4Tz"2<i dR Z4 ``(0c e*"4, DBq0! N!WF8l.ց@1*DΡTcy9'jptNZLaeԬFeD`j QY.*TF&]oeΖZ;8w!CbEv||]B-HP4лl)L哧b]@2*kxB5™犞-z۽'H A=;xm\ŃآRKS;{JP *=+9M_jѫh#؀\6{7oy|Ɗ- DhhX[ԣ^l 7'vY4a?}- ˛ΎWWȓM@0pveA +Sck/cL3RmW!UڲH:?!>ƷTq9HK%{ɪ"wPTD21B̼ozc( hoTj.RIl 2Q>f&8HE8XszxZw*ZQ pyM*5e*"mU'w'_#\h3^*$˚㔱UfaUwFJmLbf‰|ȩbҁC1-'!RVjz'K-IU'ʄ:ʹBWuu9'|fΙ3 A* +*"A1$~᭹jZ3]]}޻~2z?P4a8]d iRB1LD"D'dnru&FJBvbX*A"\MI?NP,6Tè4#(Xl_c2Kn X2^L[)@!ot!,p^?Pf0{n,ĔH$ߧU @C(8-#ZsW]xt/lQ#f{fJuӐgHh[H><r>"98#`|!ך(~HpUޠL1iIbI6C-WP?qxh_Pb&c m>$lnOE,' <8sຝJ̏Q).Rd~馑# 9@UGla Xh,8l Cb h!`cPy$qԀ2b< +&h3@jйPAL*&0@B@˂tҒ 8 `DsDŽgQ.KjMYWFszW/DJk9tZ,xQ/b`Ct[2'S110nkvgF=C`(51r ɔv|c +[P sE7ؼ0!G%ٜVkpS`bö-4b;,! +E5 :@(`T|n&?̔x}OA, jT=NWRd t_"˅P( +`@!Ws +"r0P$5cnk& ;hFt؆a8/e%n,?4"a; ,|ŊNFC_12ZT@: coPSyO(֤JP&65r p,FE +a=x܍dA/FK;bvOtO\H0 6<#ñx:Pp$O|IvѐClN}Ms\f2}T @ yHN +'~FndJK\ H2:kVQ5Ձ ` Y%Ai]?X dhB-;3&'A棠>Jy/38*֭~ D2mp c +bLR4ܘ>($.|>yP4=}2@ca6AA&0ΪAQtR{<!WHRlWė's +@_D +5<"$ +ټ/Zk=n泖lh #mnܨ[dOpx\-(2D%Bs`QJͶ8]x/*ENzxQOy FMc_Ȩx5b#^T\>p}#HO¦/ `8]O#50uv\>`3#a(bP- 6?nTA|zE`Ĭُ#aGpp0Ȑ4CL`&8a7 9KOzQ_ [`%WF\aoX `-bU`֒ӭ&G$42ZDIjۍccA y(-UCLXèwPQ X$ 4,^ 782Vҍ,'lnOHĴG8!LqN܎ic؆X +ewPU`TgKa,_/$;g`N {B:&AVl1Hv␓ 7XcA@ p%XD`?xA4 +M4tc@nNjF*X4jMY{ZهFA[xHJnz)7ad:̗#d9" 7,!d@HB QGBvTwHo@$2`XFVFiMOCTcȾ{^{Aē^`τq)1uvUG@ +XR(N0N{v@74EnN²4CF $ _E ύLtR;%$8̤ lv, R3(qykI*# 8LA&H0K1t`f"3⢀]005=(|֡eq}7,D.eE2ܾhg:^D.KlP>*J9h=?˜jX3WNZIVApbXfmmC˰ eQucnpkA ÆG-<me~XpP#v$ >C0{ .Rnz|&L_7}#N l9,BpsP;xMFFlY +пXkPhR eAvCj]dD$"Е~aA/b` \<ZRJT1,R5Ƽw$ikA#XjpCa̓- .)%VU 9cLdT5%s A 30E3J#"? {X@#`-蓑&7tP8!bp SY\QQҏACt~꘏oNvI3(!yp~.íu>mE^lx|뮰eMX]ҬR> +@xp,%v4wtMam5qTWqrBܼT/1b?=ZӀ/ 塛GU9<0\8 5Dkྱ)' 6  Z@RoL_^4N* )=zSP@2.7߅@˅wXsG~2b!. t7[@˒r +a+ą,Vy +\( 8FUFPЦ蠟J 3#E ^H>2G"~&LgL(Šs oސ4jWIK҃Z'\XI+KUӑܻHB Q9{Psc$~l`pc#%ddUNp,^K^57&V0Z֪4Ç0 Fgq*ms +N< +b}h܏y&Am.7x!d2yl Y@AP(W QDA]a:aK:[ƍa +|Z2p.249>6IX)!Gx<GH"5Rm%!3 &&q泬R f됔_ZJQUNM +:l )DX;a/Z]Lڗ'亐,ЖUJ(_B<)Wi,JM&4 O@Ժ +0I15+eP4*Bp>ʄÍA1AU91 *<  d1dof`1/p>8!0ޒb:rn-C|Dx4Q(}hr=Tr,Qq +A5@'C|!$x?,>d!6Zc*V6lGH@ G {gs8W`И[΂$jփ#_mTz9wP!zJBA4j~RJux#Bbx"TTc % rYnj 3&e`DnD䍊b|B3.kL08dO)>< +0"M>9!g)A\γflZLMGk^-Mz3H(J)5!9]B:TBIE/4JIZ "mB  }6)fQxM myh3Z+3svTPERfKLs"t܃⢁B(-$QZNvaQfGN: {yOi(!-L.d|A(U`95{|rܬJa4EJmqӚSj0,S + 'cʒH,O'Jn +"ύY(.e.ZQFB )&!&|:o|>3Hgxim'[h +T~/}a|k&[;Ě +t4=`"BFe@t\քŨíf\`at$}Am(h \$kQiRflz[\Ι%?r֡fDG-2.jbhwV[Kb>9k B\ + >1&H oAJSA79iIn-c! +,2)sq/;+tG+Zsv \l$bQz-h66^]6K0\pV YT)蛵ulfRO4!H@K]LLA2D{2[jy:.̝.Ν2[kBeTThCFbG+TymJ3FRAJGm93mh=̞Q^6ԼD\NGY_.\66幝bbXsOL )Z>#@/F4.TERnF--O%Z TaylP[,LHVWD*V~{7<6~if粒xkl˅Dstqrq.,B"q)=&jŹ;3d)W&fSc8B&N$'O''') k+RvNʹdc4s"dwaj~)s6(MeqH*) 2Qi.++TPip=p+yG:Q#5gRvDLE&A2̴Q[IVo"sIZ;͟OɌ&[K{ע9 dHFݭ3G}zVhAwÔ-\*NHuKB΋EI MYjW+nटOHӔ\Hwwznܺ~;(oe•' F}HχB~m~^M[쒘]6;ǔ(p gˍ̟/ vNݻw1[W'۷[8w?͌"Xq2-L,Ϝj\V9:ynLҚ?:8t-?*檋GO\3]>'!.ɀ5iuMSBƈV@>⌖m-]4mTcԸXO6ܜQ(Lh Z6jS[?yUpz=ݮ̜\LȍDA:F*yDaDwzvejs?U=g3RT~ `-[G[a* %ROJaƨ >P(\p?lFOr/ٳ ^[Nd;Ze<)ONW9m*dc>"K3εIvOx!?lVYb ++!Z`~u5ݹSLN*yʚ@=ZszmJy8ً56Bg2#4c*-qUVHzmp(^]D95շJmTBDTHbjdg6әID3DJ/饩7}4`L0[zGgZoh}6w~˅Cw6Vfv66o {c259-.{kO[=1toŬL g&-Oʨlfά_d:oEͭ_[De˳id~R+͋Hf0S F|CE8kr[4@8_4]L)Φ:23ܺ] #e300 V&wr2[cV/%*3S|zRu0Fi.Z +*X;ঌמhΟ^߹{7jtvW/]~mmu.p9.6j,])]f6?yd ! Vv.RXU7&vVBL +z +YY-JTs=8yOǀ?1?BsWsm$:۱N{~+ءe`B:HE]nuRzLII%S͵`1W_>jI|X*&f汋_[<~\'=kW.&ₜ:Ջw>!zcA@RmL9v?}xZ2W/>߽kzsgwo?߀vncbq4={%R+;heŨ=P_U+,N^µʰG]\`J7'3lu:I)Q +s\rbeP""B-U/ + J-J>m1~%ccK3J|XsW[P.oL+^o\=rWkpFqLʙ 5;d ^SٕSs8V]l\n2?+~oun`b5&>jv"!^ϾZj-PJ Unla|cz{.1=6or0'3GkxzqdOZ|E{h=ˇozub+]EZktva1yT̐j T,IFѲ\{;S JA℘Pxm=+߼|~8;ĭYMkBu.D(`R,M'|nNS7:W +Di|ߡ* +%W[kzeV)lF=ެ-k^]ܽwDc#흹9U$RlSpR\Όgαk91&'RwOO]LԌe(vYuaߐ?D&#jR0<{0ZMR+k;׌֢!hHjZN ()$Q3=d| r)1#%FNLVY)MS޵TY8[ll:+ޛܾtaWÙjs;UkNu-/frac^"d[[ g ^|r5U]پ^8ƚZFI()6R%/*ёL$]AI Ԗ0 +RGb1A@`KMNvB^F#E«Z4E~2 FrJap8B/:8$5MˉZYB$iveb>chIRo7VXR ]5<$\.} G*|2&"Ts~2#Er^/Ϗ/ӋKL6.NEK^$&te5Y)kQ144%r9٨8sW.߷QZ@1ZSTxfLF !Qr*V@o, #O]nm,)5ыH₄Lf$Vfz/l#Ӟ9{#9BQbܯmjy/-ӂYl]` )g! eZSri)Ɋf>ݙS=ԡ⅀#LRknWQ=iN\ʈ (JԖk3'3O +2o|dQ5x(ǗwfTh*ŹQ` IזyF=7NxA!I-X +]B*|<d^LsRgL?Q9$ڥyLp||ԭ G.k(B %s`F11(ς$y*Dfe%cח.d #Lӥ\׽BklwCK-jfZ7+3bƛ lEHUlb/YIVXqo80#Xz<Fc6#F761ΨpqaL5uVB@c{O_|g~埿?G◿{}O5/8}ͥZc[hOo 6VrQJQ`l']t_\<|ffxgaurcwЩ3Wy?_M,*T\*]t7)1 +jn˩\~|y~˿o_ =G!QRR)ߘ!ŤYfTkz}v<w?7aX6T{^ 1Jlz`Ӊ|ep9jL|{oOzW~G~?<Ǯ %`r ,2bűHf4h66_>o?_i/1hXn1_"n/e)Zf"e)Y%Nm۾Gg܏:}R$5>uovo<˯ݏ?o|_G~WoZFT7+c^~=<_ 3/g~koW/Ǟ~Rbg3[/iZYZ[tS3?[|/ӿ<^0¤y-)Sk;p:v} ?s/>ҫo{׿|i_hG'L1 Tx۟;|mw=p߾g{/߽|~/އϟ=\M=9GFqȏwKǎt~艧z%|Ο~t~ofAIy5,67Nw= 7|o~-ǟ铿?'yl}0 2aJ|4xة+~녟WoO|}{BwKIMQkdvқ]=}/~/cOzFfS[\; V˜$kDb 3n9y~x߽oxW~~K|C;[ۊYM{l1vvW^~? x?_>g7>fy"J񅕝Sn9q‰^ٻ۷?x>?Wo>X$d7^^ŜIN{~~߿gϻg#nӲBHFCNbx79~ǿg~_O>~߼)GN{r4$RBl;zO|Ͻ싯_o)>賿ӿ~;O[YWo/[=AZKcF*Y]?rgz^O@߿<9" +K)$FǧW^}W7~ֿO7z<]v}XnP6cnwՙӋs+ۛq>|w\||]%4V$QG{|?@1xojjzzȑCGvWΝ?r}Wzkov}g6nf+X(nP1#3'o;].cׯ|x?罏>O W/ϬbTd-}ĕnsǟykǟ|_O^|<#ķ~7_>۾O=vLNkFv`s.ihQ.C{w~ /O~SO>ן|ﹻn{g{ gAh0RY9e+.jR 塎$C bc0Y"HZ2[JNq%h^8Y͊~ .r+D ;=AR* %0tHEKlY;uaepX:OCSa!^ ["Sl0s"$ +DAT;gQR䴚mGB&HDuu8(+f^D rrv20fJ ^̋~\Ib!L"<3FUJ4A(C8 k8pdJr5܈@9i5eɘ5]T$EO OITHS8ch'mQ?E)IZR,T #͉~妑1;B2 w F99oP:fwji^]5௬RA$ZӃD,ZZ788kh&%^|\GAoY&uIN'6<Ѝ8(BjZX=VgJ==A1pٌ|l<!"_X@χv|ed:d.̰I F0\O8N/5<pXȌ^LLg#-'ռvt4hs$9)cX!ͨM{Uӳbb$MK@H)O4+k8_ ƜWgϠTsTՊn.G/̲6KZ iR*ˉT}Gvn奁dNf1]GӜ #.9ZϏOmQO55 F*A$=Eu樋q1b38 1Z$ԂabVLZͅ*!JKx՚kclP"1~إS0RBh"ќ rH4LV&\T@ wق!<}b̡'}x̏|)W@AhtTHwd%-_(a{;f 9Д6֒mx#`ת >D: So$ ҙ{%O'`#wM\$BF;BvQoJvwS_y$$e :rE.ڗ3+NTN@pe"%6R"pc# !dXu5{cL?Z m/Q:9}!!^كVCc]~҂aa"A2uMn:AںPBB\-IǏ5hl,;nnp,;yOM\0c?8-  + FkƊ"r9BŁvpe2RWSjvڇ)c Fp`2A:yoh[^53hnaъdD>H'0H~`՚ᤢ(FQJg4C8.fI5`WPpp`>(%%3(/^@ +:BPty@06٤1pЎ}\Qb]ԻrbB0Ѧ{H0헃dBuby&hkmng|0)U&ĕM1;+/7f5/śZJJ2[- щ`sYQf5k^{괒Lm]}G`hC4zfuvxC4=ΕXc.jM`g=8Bhkg*`ۼz7W(dF$ \XVtuC (Li.bԁ>XڌVn$5QK| +8 +AHk6֒qÚ]~:D`$X7V\L1.=d :oO0H5Nkq&0Dm>1:`BHNlz~c A051R 6&F!Q +j>91*dfhQjK7dB-MH;\N%V.# \g$W]>V1[~L򾱑Ѡ?(bI%It0 TmhA*C0^\*M3zyKI)?mV$>=~~r6Q99p@#Un:+V2fNi%YFՅdO-f[[ gyVx,f ƚ +˵ŋF}^脠7ru1%2yk_NpF]O̎Y_ ,NoV9:\ambz=OZK@ G&7exe  UTc?Ky+{ǖN{/XBH{'.[dFv;N8$;{=wsθ_ I߃9/j3nQ2D{?1yX_1jl ࢊsJ< +0_Hv/3YD^$䆍^h AfKs~6Qz !eGښoq hl +8~Dڐ0 8PgJe1E>2jJ6|DIQA*  +QrApqK +Ƞ!ł{ynfGGJ8=l' )1&-:`zU^g𡚜 ltl[-Vet{&Z۴ +@wO@p!iIz.^Gؘ0JVʫb#P5JjeUVxcK 7 +Z5֞MPnir^a8<E{PHvg㞑Ԓm".8H;Ve,i-rq )/QHi1' %9yhF݅jfj+^;/:#h@rj}0V_vlUk3=@%J/x5o8mjVlLl,}Ctx".\),]k.2Xշ>' pQNL&^+v/J!*T) 06q/n,ggΏ\@JPsvU\yP~P<¬#MLBh A0xm$8JT: 5G̤9H~喋#`0!4^qpe. G$`9բu?xq"furm-&[溟 cRj*f~PMMJb$F+;^QZ8>D񡺕_4 +FiM"\UĄ^PRm?yO:15Sm-_*LʊU6νq6_d.>I.+hP0 A&.&n^.@X#"6Z-P^ڪk'Vμ Zc̋ +sQLW6=fG4ssgzS|<(:l6bppXKLGޯΟ*&%"BxQ`A.85_`)-[S0nSX8{w^/_3.<<`F{+!@DhcPn$4d@RЋfq 1RD;^^A n j'adĆmSzb3Lx @F)B`d p"FFDJ6'AlgWLRVFf.\\^yuvyj:enXpn$J !67IpQZ@G`bDʫpyG~V̭squvf" PK! 1RXuqZWbE)^0*St}-UZ\ظ/B\Ou-*ҳ I>:fF⨇vof 5d<2~hH-$껓Ș*.nߔ3@xՏ.k$&́gYD+e=>-K H= Hٚ%C1L(˜ +Z+іD/5\|RjnZt(A(&*Lq Aq.h+&sƠ ,^zU9'dLVOM\OnX88 !lLcԍ⪚]$B$?[nZd{<}fiS9{ӏI%0 Cxwx4z0> H#kΔ^j,RcJ6O1\L*z[8#ղbEn BSr6zA 5AO67.-\O7Wgέ#+ғr5q=d̯0pG#m;Wch40lN$7vY-u %2\4Kr9r1X2)33c9dGq{Y .8>hE HE5uN/;`KS/ +=c݅D$WȨ=t?;t~T$/Ey5IP}ӵ{DC$Th;ZZ2͇~T= P(f#$.Wbhب5d~MoԅP* H.\n+sqB)*-_66j݃:ppJ/vH A\sA݁b J%onȰ-BLYեU_IϠ5==?WZ%gfi9Uhn6 mK$L%p?\%v/8{m$JF{_FwN~g;kbK;[7ykSk$ tzp| 6/zPĘ;E_.tN eƻ*vcv1 +nTB0 RA O@8C C 9i.2^klK ?fn`B%xR[_JS QNZޝkD #=1vunÇkU1Ap M( +|xdD.7U 7AhFpg}Fp HpzENpeR8D(cfKO]>|P_@e (Tlse5 . /|b!+zM‚owm(Z1-Hg7Aϟ^lffYRͼ>ounDV(9UhI)-mRS!%zZSuss>JĝPc@3n<ŵbIT*pQ0,Qb侑h&0CvzNzQ ^~XNLŵxc'9g;^Jq7|,J4)z.}0P'!L(Dwڽޗc+CQ.8lo^I:\3-3sFna!6a/;=>Ivy|7 +DB0Tȉ* [!YG$,4V&'Sc^)Ff{ (Ǹ8)9=[_9{P;Qڒ8~"z$6OJPDhɣfbͻ+/o.ϟPd%[o~MOMR}9ڰMNˏzx0>A\87sW?Eh睘uƷRgbD]i C4(m>Zx=E#^l-0e(QH 3QȬYM4NwnM\)+_'&lKTJ Y9aಃ"AZ%>LTV֎G:'_ywguv/}՟)Bd,c>X8PǛQƉA7J^D>"E\,/ +fTj:Ym19 l[`6*&Nޚغ[_exJuO}e 'Rn0YJ!' lׇr`vŌ/R grť;ˇ<ꞼhmF-Ɵ/ 5j}6s!\Xټp񨘣[W96~chRJѱhq.S_"GHJ:{m37k+U7gO PPv&Q_ YH *#.ۙ'=BD +x}|mbn׻1Ie:TKKpv +f4#!'50\J{KMYD)\LZ6@r-;6sȆJ` I>=Ko9verCO![0kh?d8~$LHeSM; gNu*Њ\ݣm/V{R6_[=U7ͣo/_uFxu@tjāpCєLRZ1Jza,L>&ds4{:=kU7r& e*踔a\ &ʤ}n ̑w"L2NXEZ TL<}|D>NզwciL޸wWB%)1!FuW.V *Tƕ"))M2Li,Ꞁw~؇f/r7BpE3ɍ+Vm-H[kg>ЈW0*u:Rm59瀄^+[vk0vIQBg>qj'\u'}xw?$ hȮbi_I66$ `HAcUS]N\? +%<U-5o8{RBV07α#:܁б>EarA t4))%DvnWY*w*Gd읹wǥڽŇYs/'7nV+S\X?N ލZbx]iDj,>0J!*ĆѱM+ɋՅ3Vs38)gHkܴ rghǨ% +nR֪Do%aփ@af:usp9;᪙n-\{'&H8օ09 6ZZbSF$\T5(x;0{aQ3m`R(ބIǽA:Zx绗=y5VS7ȡ*9ආS[T"):1{ap0>J2BuFm~9\ko\]8z|,.BY9 4)X(c[#!>[q"BF(1' ./(.~XFf)=;vJN#$Uc$2ag.-(@}}}ި I8;~2v|ovQv/P0E…pi#tR%[;Z#p1FVt)Zz0LѨ>dGG %&‡m0A93\^<~xƋݵrgg̣X>x!\UcU#,.:wo>ٟ^W.~όB fc[Wߛ}D^6gOrnXs +lBLU96^&I+u7Ͽ-^ *T+M-\W3+*y)1Y㞠(u4o0l1aI1`0%Z^>d"DJ Қp! hrٱaf V Eyq3bg&)ey)$. ڇ$)$E2+PN/L&K„i&>I6ksv71tTԒTc0X"U&Y-J+))Q¼UeK4r W2s|t!ŻSv7x!0 ?8c&+{@Wg cBɕ Vi*SƊK$DFExe>7&KZYৢR`̄2nDNW4ȂsVw/ݟ^ݻqg\Z=}|1XDŽh~~; )gH3\-L^|ͪy=?lzͱۜ9u˯Z#b(6noFɃjeSrXt0(=HbuQ :@lbr xk0{X#5OFfb0O ))1H@QesCgߜX}K -;*l ;F?! B)o`d٦PQOLd&v'fXG|>@NH$ Τ>SĄgubj1 r#ePz (b֬I0eqMH5?ȦĴ ex A(gBM%J8%t3Si̍ͬ;rGWL˪'&V{'fvn=q I%\(BtcŋZmgĤnH!T8we,RjLkof釠 Y=HdlLm vBa|)?~ͣ\Auh})\ؽnK^xKXsc!FΞ{{w? +Koomb2WxUINFrbln%+tŏ 0&ӋgؽQfW>pvP ZQvb؎C4&]>wwX$Dh|nN: atHBBJ#j`f"*陮Ҩqd-Ya9C> +bf`oA gxsx%Tp ֻCi} ٠H9p 9$zm&PɃF}3|\*H]I+\' +1˵I1!մO-^hvHQ6 )cFh 9P|&øD@T gLq.n7TR-)ĒccJR׈~;o fVz8aFq'JiA+PbCSA'3aMg@5soMm^MOllZ4q+? BMxX%E {dffA21R֨L\s:Z^0r3$HqiuN/;~vۅnCf_}+'nXR).ӏ~£. +Zj{nHz)NFh>`jw.e96t*?A3xJnyKA?@%IcDb|OLN6i!n4]>RglP(?adcc\ qI(ZAVy A& *V\l3/DRÌPu0"8-%))L5y#d#47BE%6Yn aEo@~0k +$sZuHV盂rZ_!&&hlZZ5I. K@p(Hh-`/8{4v 7`T?ͰO>8 t8a@#ggCĽ~R6 +4(LX +y5 ve~gc~D!ˆ(J%$ (KRC9|xrAr U9!<KtUKI3^BNMLόX ID #D|3dH6i1 5"c +lBJN728J+B/* +e[ PFjm]%#D$7W?,·'<<Kh2A >uF̢3;?| /"t49ryqy~Xc:,$fĤhBtu>Q] tWiF(Z7 W6SV~j lA>ď9cWe4-g=A-@DA!Fa9:ADj[ LFC┉QRJȌPT^q;8CZZLd>رs:ёA`cxp֒T{k6>G1? M8m0tFmlN* O!i/ cB*| 1\Lj#l9>7:2 GKzd Њ!$)rI iSן|+8@"RL %$/Pa}ۻ.O0+$մ 'Y cB̳b)5Ex{=.I`d\0p"E%+2׀4h +(1u?jF=IZ`Z6sWpA[YKk݃{8dgƸx*E^za ߍdm D(!VhӓУALRP)TDF*$] < R) +n/Oe^Iadc^/r'D@ pv~_2r6^) #=>j=<ⷍQDA燎?7qӼcTxưX.Adl#}9>2iuF>'-y|&)iPnMadfGa2(P=>9yRR&h7iY DJˍH2CK*q4 G Hv $ /b45aqc*W/V#ق+܈5T=drlZ[޼}>0lC#GMMW@y ZMEdyF~3IR,ORtQd blxا@4=$"1 +zق%Bf2oE4vOPF( ǃhZRL-h P(i/2J¹jWe3*I4b%Y2X>"AKUrP4Y6uUQA$lۂ(a +b@~? 2 >7w}"7z|{ti/ZJZaQjK 󝁾~M AJب5P& DQDEgiIF2Cc8>:< 6D 0z(;D*cCt4~ BXhoLrl+8Wsymn7n_=1٬ZrB1Or\(IrBd^gR(d6j%uy2⍝}iՍr%;<Bq]" + wTSU))۳olxs߽_~~wm,R VVy(E%íj;42q&,Q> X5?[Y[TG>dd;0qYl|fpwC hV*r1 A86*g϶&'CQkec)8 A!J4(A'r2ebRX +c; ۳3t+nOg_ʝw_x|ԍK cxa>$MQͲ.?U5&+7?|񣃿|~oΎ YR>U"V$\ȍQ3Tf~"wr}΅Ӌwlv;8lUkdTWX4vݎĨm"gd>MrqC4OV +OF38ʞ81:8y125(_7cЩص;g&{gOvGw>zT6irCLͺWs™杣֣kOnN?/)Zt L"Jx' T+oݚ~Aӿ?~׷'Vm7r8 ht3S9aeτb̑ѵTVݿ|}YM!].χ0ip} 5Y5X ɞ]yYngm̋7w?~~n+ngq])RΈdՇgXT?8*KI+-͓//ŷoM~/?8^K_wv[|>nRIHfOZ L&*{u-OW. ?o>~^_zn6a?(ln2=P"/ίCg'_9x3HQGe&+&3ŷԍe_y7?osui{6ʲ G" !#܊ELן;>{/?Ͽ{/oG׾+W P9!o qͨ,Җ˅>Z/ן_?{G~~_~~~wv~oӽ[z>8@کlk ݯ??^W_}on|owoo?}'FY `pB["7[Qo;lХnY"/-`'O?{uן^_>OO݃t*M„ĪW:ijsw߻\/^{~O˟ݭw5{oq=?)=ܕã޿+K?\K?_z7>_t';wbE73!h%3L%+jD7ItӳKKۗ|_s_ k?:UhM xLH]fR(L%D,;;^^݃op_?os_}w_xx^HYN&tٲxib}u(B+?r'eLY*BX7.&n<z>On~Gw^8u~>XV""E52 Й1osOƉqkI_\)>8vƵ׮-vӓƩNdM( \T+L9Mnu,vz&wkv+~ܿ^Ot^َ[n7jrr&iݚ(8J/al*/~|{Ξ[u U1|`<1/ݜ6:Z^Xݫ~`'߸xc6[3^h]Yɶ*K5RS+݋{,qvcw$ɲ47Y]"keZk͵UFDFjUJWgOwMOun.w٥X,HCc X HDp{>{w|x(@#H!By(,e,Tzs^K0Q՘|ՃSۓqk-_SD2&,kceB`,o7?_O7~oZ~y #ʪꠤʼn5F_&r0vcz{/?_G{Z؆vk;\啐UCiבG0Ց'#h:&ѲLGVF.VtlJSYXV!Z;lƓf}VܱNkz`Uot5HJ%[3_KaXluW#Qz8u ~0U,QVp>A ,v&U`4Ů-ccz}qoՇ>;xy8ikΈs/)vS,W q-Lrf bckRu $TLNHNaZ, jU׎Z~3aHf4j#'4e͐U0*``RȦ A^8vEXյ,-3j~v{o9;j{^;[\E@:kLgbzcAR[L*ޱj[ܰ[bxs9x>スܹ9yh\ q."ɲ [yfqJ=/;H5VClɺۯ۷-&-Eep. izm].^5[G_{+JYDNnwaw֪uM&J4s\ +[D- q#I\k$b$JUʅ +("#"1TWqeaJ͉q`F% +v>^"#XV2ksj(eEL|$pj{=n(h^SUbnrbOv5!56RrgJJ$_M4:r)F*F%Jϳ8)6qʸ2GWB4F§n#/[c+Z:/2J1ydTQ-$C 7VrUk>z3X)>zvw.{ڷ3̝4U&lA?ʐEFZTϗOn7)k7EϢf˗xA}wxR, ;ԍF6S)p6֦pczTfZ>#`5/o=:c %yC5U5Km2_CV}w僻@Er>Z!R %{.6%OB+vQ.`$9R9!՝ƺ>LY/;3zh.pr*-x͹SLZ/{_J} 3J2tLvp \Tt +DGD9D!J3=Z;_!mhs@3>g!0nrf!S%.J:OUH嫢5ጾ` 2ZOzua|P0Ì1$F #iHcVw%oBq2r;yGٻ/fhݻbS3,5T\&k%vԶU?CTQacwe34'w,S,LZe2霕4Ί%7(]p$>yapJ:Z'/Gf/6欵uUu2+S˜r߀<IG vcuŻ;FDotlCTDImEӋg v֏|yݛǿ(r>!Y0y{o09歾,x{B W|ŋ߉N)0ӽog<u6Ψv҅,$t*ll D0Yw%BP1"™0kEMeD\ 8{Jf8բQ) A2Wew){S[FA)35}Ψ<5ZX{'&u-1㭊LMtE.65hy :;z|@)MWA!PMZ\Y\(Vu;ɝܭSLJCJRѤRנFe$SW]]5OF}34Z @ J@ +A碌~e!dz2ANQյx?pPwv_+Ѫ‡7]qh΅(O%9zsVmq "͞#.:$ jkkZeK]yiqW'OE6rVI#:y_/Қ^o, y_tNћ'ҭ.A2e}#br!~jv2_1+(e +4hݢlU[W'VXFQYQ 2W&D-Q>. bz^3~sU0 {_/avj zы?}㷝|#՚÷O}|9<5R%0Vg\, +!=&Auff*0i(䬅'\QF a#@ ژJֆ+߅d5 1HH=BiqYs ˒9>{ON1YcOE3}xѳͻ?>ͽf{o +QhWk3$ycht_k]_^o`b舘kMq{oŗ 昲f7=oLw^>r LR!%%{oiC+q4<-`v+DTaB*\{Yuw j6jMV@Y_~yxe?UW촏Zˇ{=Y~ksxWh oۣ0oML3Ǭ%TP E|̞p~dj|qZ0(@d@}_U<ə\m#'c}t\fh+-Lhk`.XPΕN1$ NE{ od_wx;Y;<^P`G?̯=xG~%TT6!UڜfZ k+rk,μ5"~ǹJUp'V@=w&17ыtV\֦WZu{_j8zL>9bFZ?zV 7z.[{v4_D:޾]5ۋ0aOw[97R,{{>D[j ,hUw@X{8=|sw 20ZGnF +V.H. +L1k;|J=J!O،9 'F0OܰwBLỈP QkFre<谈=,!@%pazR5z0j1Ôn Lް@Y; &nNzgqZ0O9^sZg="8~}."Z׻2>HAnHLicra K(lֵhN:1mLȓygW WكD*oN;OO{Okɓ +.K`EjvZ( :+0e6A}to':ßћر7E0^x{P;|7GP|/_f} ׏?S{wT^kFw/^lw`2:QZC0f#W6yB҉w꺘ai0^~xF#0?..ĄsF:2~z=e8};%3zPLAvyS]Ui3N6P &(Qnc5}`wF^.xCNhR\,N/>*T_ w. p:g/ Pj7Xo$b(eOE7Dĸ(?G7m`]uw%kTך1Y3[ C,HcXacBnB +WؠO?/1>otg@ΒԢ=MCA؁ +D)Uw$"|H*)ENmǮ/s)  D):}U<Ҡ +`򨦺}{hK+ +oNKakaԁ`J?< _B6^LjRNV &W:y*`G19W }^=`.,ֱ^ȩNmxOpE4bl]犿w{{[{0,DHmu8x3߽v^}v5:}X<"F˔u^J&.(9t{ڻ/.B:鼈qrl +n^ +@oc69!9P!ԣW~9*z=+elE*yPW ȒL +v3]@Ũ")ً}/Gʍcn4 Y(11.w_M[ v Tc֞f:ߐr[9 qYbp7jG1.hUknp~7U]TlEp DF7> ReIxZFm^CZ!{a^ad=%kic튺]ڒUۛ9!٨kV]|wN7ε.dw+L(F>ϥ`-*R6ƘHi_?RE`9R + b /6h8n4֐ѓ]?mB9ܓAqgIUt\S|ݺ;DoBpu ! +M[ ctަ|ֈT&LU +e@HK ! iu**7,-ݍN˱=y?,n~ tǕƮ~ltqx.izպ9ԁ +~{L\-nє7 \ܧwJ?4-cRB`PAi[DveŐL&RQT4$wLjk[$=,sm4>u2ZJ:'7%Z,郯W/g׿|QP7)2ܖwU/1֯yPdwPIkw{o;߂aUr$&Ğ,Y{U<g_+cO`[}\}0KyY&Lx̅P.QAL9kRingw3a=Ҟ~V^Srݭ-;OoDGO`d?YjbU[~rMN1 m;C(_E*4UGIsLeҙTJT'()T=8'vZvTPB5*d%QL2fczNRG!"u%ynO.p'-1[o tEpYkQ>߿pN!-?^\} CtIp꼷zYcR.p ZtS!XqڙĪ7Q{ܪpa"Y#A89zJ:BStAH4Ǵ?) +,+ÇrQnj\ +V)-JF +4%3)v)V=s8QE1Md;@Zd!4r]AfieXU{t<V˸-HYNQs?%>}&דVɺ]a<T]oQgjƶN>t/P'OuDEGk\ޱ\_v/^W 1!U w}8z7PSR%*$*kѓ-0.@{ 0[g~}:}I(2s@p7' &=t?>PK,z~+\mTIYѲDǘY?MY#ţxt8fh{YԸ!)d;mf +DhK{B'ˬ9S5h0 k#^3j'S;2HeЄ +6.mqWMuڬNΑ߻sDN1xYy"tmY>Ȱ?U d +eFYw6}G* @X P+(+4;% ~ʘce05b>b6jndRxWrFn:IYBz|̃EvYͩ)uMo*$!b.2ED{[ Af"Hc" e3G@jj9' +S7Tp#nBt'ד͂Tm(LS^e(|>ǒ +Z#[dJT! +UZp#Uq-9+P\A\5JI7hf1Qfd)ə=A!B˕=z'ܰA2E $ +,Xe:)6J{gv|h +YouyuXc< 0dZn#T<ԗ S(mP dHvȱيʩ}3!y\T\Ҹ܃n)hC@O(Wń@cYI]\jj:܄7Od +8)D8QFm-:SHRP!~IPk"ކÂ)Jn1Jj"9D!{TOxgGք&Xe ͈0acQypbD8WHfQ7 +aS8BCM4Z*щCJQ! +S6 +,"wӸh0""(2}oŒT= 7z|Rf"bA jb N|v ?[]F |kf]Ѳ:z`w۠O5VE>MP BTP౲>1F9 *a:Be7klBjTq+@C^(")ZLږY;s}֏XkI(|{:ڔ:d0hM}pen 734.ųE!) ෾}6.q +! 0*)1Vq&d Շ*p62Bs$WJ2GC'=4B6( MHemƌ)l;M&yDj}u7/k_ e ^)fMdRlhtzy| +Pܭ;;g 0[a.v '^,$ xk P ӥ-҈}Z nbWSO=lH Ji@T'5)A-B'-*Pc'-7a.V);?Q& "pWz 1{;ofqQƃ?V;qboaxR72mR 7Ɯ5GưFOcoWe.Dab +]m%:E0~N `n +KflYTb]@n>vˏ$[AqX鴯vhJ; [ּ3&%~z+''{9 fLәrg+fѤɵ$kE- $TfZуN63FyP4FmdYb$jhkc98Pe.=g +|0MTY,` !ڍ$s3G,^QTGp @]K_ tY-Q!)%kV(+%R+}L"/ +79YV{Wx"l5"^*b҈))D*P+9 +[.w()Εո`yhЉv8eswS4Odw\!uxs8{6c2 ń v78gN +M TRm'#B!b`OP[H:KL)O Q ȂE{\<͞«րE@u!TN*TWh']n孻4WXm }'CAA-SSE&00$>,@aj<]tZ1Ʒ)vlc,]`(6[wʀ=NhyTN]=]$]})f^AcHk|6ҨQ6ƄA묽YgtrIha(UBv@td%`2ޚ`3BDg+JY#BcגkPP/9N\'VJmh=LyEM0\Yi6ĵ9c9HevTA3&oVغ`IJ+PUZa˄I +UY08gijv2^)H.FvGanPr[GE4?5whNU5^ +#VE|2Br`wKΜr4/WٲZ&<[1\P?eF`P#0N,~1Ɍfɝ2X2rA{74.yk!:;4.`ahL VbppgC1X|'yx=wRFO"iSjRH0.N"EekLj9\÷?j x*RK")SnfVWbzk}^dY&tXsi֏` %0@H[vZu%7n}xvRbJkij+Ze+VlA 6@ T(êhV8@5Kn\v晢1-9{HodĻiWAy 5`dٙT9?#)@! ,]`ͪNqh.6@Fs|@J"ۄ(hrr)h_xHN%5=.#:D^w7JwrK M(gcѧ1KDAtEc| E6."U1&!6lToAEdq/Q^5ce`A%y=SA ,1irAx|O9H1@1Btf,OI I8 +(5*wτ`Qɓy)Sy{L}|\ fyB FmmqFxІJLVSV$#B OrjrLY1iO0:P9K#6cLCh*%܃$)1PS RbҐ5wRrp@uF!4H0g H> +<%KfA)s {pvoCH[[ĭMc. _ He 3ʲwRD=$p@6+mTXr9WRyLI[>[qrX@I-c\G[88GCL2.ʚS+ջe9M:)ȇ,ƅ# TɼgdPt<1.2^: 7ϕYs`[a#(=XI7m>"[g9'lDP \)FĎ_'b(  *7sgͻ; #n"wI +R#gHZBȝ;L)A@ܢbGO|NNL ?vtfL49vicU6dETBnfQe$ἳxv^o!B8::&*JjCYl䘟}-ɤԂOϑ>eƍ7zɘcp0Jj|#hwS42YV' b8r{*Y"R%VIN9 6onLZ޷{/h?x{ϭLԝ W$|ޜVA&ыFVLs0l|r :u @OPKRiJJ@zt) H/Dž +Kl {;%2T) +*`E+xWg#nUE,z )+Rqm1MAskz(u4o&8mԹS0d,f|Y+pJ}} ZQꛈ] C;iNQCqGr;E{};):ڠ3z^Cm #R,ַ8"ĪHEm4}]LiY->K +FI(ʴVYOijH4jGz|'6yq KdacV]NUG .eܦu\+-5Z|E)f3d<"+6"ˤ',n"<]7R4Qss1:ỦjU >[]Up1g[gI9*?neZ-KJs5乪phU >pBu. Kx w q۝˝柉fuށc~ȏmi ?ضc~ȏmi ?ضc~ȏmi ?ضc~ȏmi ?ضc~ȏmi ?ضc~ȏmi ?aM8tx^ (cʡKl_ٺo^haA #22(V"P +^vy/d~ ٵBvg]/d~ ٵBvg]/d~ ٵBvg]/d~ ٵBvg]/d~ ٵBvg]/d~ ٵBvg]/d~ ٵBvg]#_|gܞ||ӷ/O^ݞo?뫓_V&_\>'W7ߟ_ ӓV*~"=hVn?rp; +>~ (&ФƇ%Q}]>t:a.mG 놦6zh~pu ?Z}~}oOn^zɭlUor} +~r&[U//蟾O<|\~Ϗr NdϗWCwo^l\oNfO8xvsv%O/_|>Z}SW~tml_vzo9j?:\J~:vb;g߿xI`B&==}˹[Ols2s~MWws{rԤMɫ?ޜgW٨{9MשC7\^oח==q[VلaW^<䍳mxl pί6=g7'78Q7g9ytcQ-[QKW;Nϯr&xy^_~u~y>W^ܫ ++ګ{pGU S|~s"__=*pcadu:?>9'ϮzCXmV*R|t*+Hln}v &rT'逖"|w-7PIBWOu(`os2eSgg6_ų)?uvpo_‡w]1 }yv?:l^lvO^ݞ"ǁwȍ#O^y~rzf.p2h%]O{z}q}o?xYd;_!n__ :+Jl!^}6kqcGb)[Z;Ix*Ͼ2xlIG%uuvNv}FM]zwʮЄoQ߫wb'7/.n7w=>$"C½G$qOwl~o6_/NfٳN`WI=g7ߟa'HU{G<^__<9;;u;?9"em/d>QW=;870m~s??~&ǖ9=ٞݧ|}Q[/uӴݥi.ql=Mۡh_ؤ`nvZ?_#` \qپSQqkA k^Wggˁw_nlE.]yKZ%ms_9>H(JzyqrzvyvuˇǓ8d*gM~tms(?~jcC!'򪍃7]q@"[ jR4هB6_{r6ރ}["T^ͫw/?mWks>} Wg'ŋwՀ;_uMv/mpm␟_\l{q+:䗍ۓ>뺺OO__~{tQՐMz~s}9OX,/g6uOrTxǢ@%lхlbهj<.5nfs\~g?gK~J9}t3表J>pf#qJhG8s}c8KdQlk;NO]+z(t7v=-rkvOGn?[1*ȂXoGYb}sN/ym#۞=1۞Fo [n=uے=u{Hm/ԭv}spDm%_EJ겿"&qЇ/>oKRܖlpۼɾ˝0xj.i_e'jܜ]^mZ.Z.wmWΞ_1t}n/Nn?ۂW#>x37ry>%f%D~Dzy)l]fWDU):e~E.͚~ wΈ?j+;> ?[+?{o}/yam{&<оd+ss}{.T{c湈_mWz2hmi2fwׯΞ^_~9[%rvqqӦ8ŭp7^|؝q-};߷foW7Mp#؛&ICé7ggWtןx~}qvٳOoNgӳ Vjݫw ;׷oZߵY>;Jy sϱ3rl]1٩ʛ?R߆<٭ˁwʽaExv|v#ewޘ79{cޘ79k9fQcYvhsv[sc}PCLzY]f<ݲ_/ϱ/ϱ+Ǵ9e+@x}mwl~ov6'osY螅Y?KwnK +v{>V螺:}4խWzT>}UwT~OC}}ڸ׾pNwR8NLa6}Z. ٸE0{n[܌g[QFʕtw?G,܍G^{0Jܾx?R]`m.܇J6C|tx%??"ӞWlC2{?'찒cW,7؛?]{'[ ڃ}u[TZ;"Qw2J6H>Ƶ;yuǛtsq{6/] uNR-pcvZ^ k{-pq>mWj?oN6{uCXmVz`ztz+ &#r'U)vxMk߾Ʈܘ}_[ƽѴ߬^]/D!.t°oQ\PJ=Nvr?Sh;1=~ >}$78'g_l#-Lof۝d.:>zu{N8wK07*|[6~(k۾ɿ=fn\,Biq(lOn/i'QsmYZgJ>w րg{J~\~qr6SϞY螅DzY趤`׹gǹ;iA76{h81UJd997#lɾi5>N;\i{$ЭϺ +d2?~ }(G/OUy'xo,o 0ʣ 4..)r'摻hjn~zq}j=уZqn-:q{%)EGk%wQ~ujQi4ʇv8pg7~~9;x}0|/%Vq?Y=_z4.|8jׯ.[r\ }P6׃Mj6oڐVQ'?2Ƶi]jC^ M㚡o]V !!:׉fxBS7M'HVߜtԹ iR3KtsSׯ֧A~SnH60šk7]/ģ'(~X=/GΧa8;]8 +MiC !%t-^B\air,Q^7}kVVAa|M]L(6Fܤص[B: cKF&{u+X^&^Â,?>t%@?S6ѻA 򥡓g Wz1`k/ʊZƦ-Kpe8Æ$/ ` #Hc+>)EIZx\/ӑz\#8yIiNB}E +%x@Z,KD!~EC[#,)p M3(A'qh[`0I P\AAS?6=}$xF66zJ^#x):`pZ!mA1@0r;dZNS &rO .Fy"Z¥ F Xeeff2ʌ9Ch7J۞HvKP|S =9)2 B}PHRoyYdX\^]6aX +ФN?7nLytْ:R:AA #qX`HD D2Hb7yV .39{{h{Op;`vr5|z(5;T'q)nb={?`@Dz0=u(@?CGR>p#ˠa.*)v1˩!'(롂) +l% BOW=S@:+FXTjoZ<HQM>aJ|6/1(q6ok .1yؾ(z6!O+!ccV~xGh?x?L$j) qrCTr`6P::یv)b2L t_}ڡc .!P3 gAs[<=f:pՁLZw;A;DWJ= R i@ EjT(`=b;A<2$M9[N+'# SVkilTuH_2p:)N4!{y Es|SXcөamy,l2zȬ{~ ˄eӆ+Z#Hub2 ZbE# <w&>M"ܷ{MM,vA[=`DFxOS\#pJ-Z@Dۆe]^{g2o590kHC 5[|OxBhɆۊN>y?Rcuɿh1Sv*vjO*xHM% +tfBMт́ˉޫPI9lA%.E,#e`[8N, &YUGVpk\\Kbk@VӜ#u4~֘D#PpC +ArDLgbm)Qo DX8fZOرŮ.}/AF" Hd +!0XM@r ҉ǃKl1[zՌAȂ2Tvp}]+b?TY4+m^ ӝ9!.੢%ؔ} B%95ܽliA3trqSQ#QX Y|kO|';҇r=D, +>Msj Qa?:@V{I҇ s\8BI==ur5И e.j|G00EԏyR>٩GMv$~5wEnutD^jsg !Gk<9$ǐ_ u鷀_XlNΌ^ ^fYdJY`?1``h ٩ #<4q q.t'DkԢ;gT| M|l$ʢgk_zyo!\y:(e4T:%P̅u*Q'IFMP#L I-|L{u%uxJ脁)JF~PE?!Pw:Lr؛I}T9-8rihLJ q.g>&cr1 e 5u lxwXwz^OiЋeO:qzNa.՞'R, -^DbC}hyʚ؏u"0h Ff~s_ZzHrR*Bb|ڨe,TYc +Қs4kY'y3!#Й hZzrJq 3\, B7"!e`,hiHď0621J#/<ް xޚx yuPWa!4fSAʇ{DB< +tY9ԚQc 1^@Kg|@UŁ_'iO(UsMR+%EƳ_ rO?Z'fEicmgR Pӈ]Ś.3ߙ-h8GHF/SOCCaPP4ĝT m2v@^&qGvAB}W?PbzkTvB' M)vu%l=S/`26Ac(֐&BT]˼jƙ' ;`/RӃ5\_`M:BӃ_d`ږڔ">D#R {Bg$<֩3\xv|J-'9h,o#!wdi[DXѥA" >stream +Hd͎%;)oi+X-`s2/E~5TNGDFcG+n%Pr-듟cc¬}n)`K?|chozLvcѣDS)c!kH}lfzs,Vzl-䪵r=J )53azͿ5L6 ~᩠'3[ +\{hs59j 1hF|NɡPN5hBi!,3rh;\oM Y:Rx-!Fl9\53YJ08V”k Do3{E,hfHjNKǴYrD8;EHZ+m80jmIFCkw5~"w `[`1]]Tlo#ߕ(iЪ]i!s˷, }SH}qf&wPK5M%TXl+$S-Ծq>Aq^1q, )}c)uc1NRQYK8OEq*E3 +"줣b^?ovPI1. +*Iasx8H^)Kpȓ6.x/%vLGpb$;hI9lgsQ˻UH6GX9XKu~p, ٱD> o\:F0`$2X60.f8HY2<[$Qbv3|`09P)de]SZo"r/;4?v/7ʢ+c:&#cpkHpi^w|'B)=9_RyʌU~P5pd C[jQ0 +JS(0\ue ;dnodJۈK9F*shb9MP]s4YfA#[ +1dY啩y!v27tp1n)&]LV͘xapRYíЭD>nYnAue@x=eӪ4jk_k +eOz9[h gV6M׍+v5pgs9 +7*QfR^jO^$߽l^-01笓Ũp*w?a &~1ĹftwVv u;7y}rl]S#vY=U@6*h<>pٓ\䇭%'?C{i:FN~:S]IWVwwΣ8 \t|J,j]j~8߸X9LCRigH^M%u]uOz}W*j$,Ըs eoK$|/zn +=@"T' WS  +C5H +e m"$D[s]&7}XYQ0\}]ҝ觵HH8n{63~-Ag .mW69hފRït7\Z52\eF Ȥz"K.SO}`o{4|[*[U;;Q#6PXOqJWN3]m(k膁hK9**ƑzKEO]I[}#9QuV[w&,UgM@Qs+I׳[p.rgF^Iv׸Z +x5YG7rmvrJzQ..KpyW"I7뮤z5?_~>6`i endstream endobj 89 0 obj <>stream +HdIIDqyضU$ +~FzLpӌF߷o}ۿ}{ +[ml)Ϛa翯?^߾_[C_~߯f-TJ[OiO?_o oz̺Cѣi)c{.mccڛ~aejql{+gv {m.z{oA l/YZ:-?_ZaI ,֔W_^XNugi{.YyaMLf#+y$ЌƔ]@Ѯ][4-X59V/RXޫ{Ϭe +q{m D̀x7BT<آjႭw +'iU'E{q^uH6?nΈ7eE9x@Q _08w$CپEޭƋ`|ē80XYڧbf&\JN¦CROA@7>W V?`}grfXlaWk"b`SiՐ!V-l0[]JeV:>oܥvɉ1.$no$@+Lljے̍70IēR~p`"3"("XXq^+1S/D:о)8`oQ,a,*;r%qG;F.{ġC:,I +K0lIxY&a CUD-Vh-xbB` "gI&rfáK>ޠl;\ Jv-Z&K + vTVw7%: 'w!ʞ00S[ˑ0HJlҬtAէ˞/+7D_RQT=UF٪Rɶ~p?&قFE'y¹S\A P +4ueK 81YljiXŵsXL'Ĺ +hDq6 ',Xot Hp(u +$*k0'ho~K[,<]ydXf\ȫ.!!GUU"DS0# ++V=yfH֙flEUwȤ7OÛX/rz$U$ULa`NWY3{]rS:۔d +ʈyDSv֙%QLo[oWAU%B!@gDůK)7Dq;}{vN@X;w5'u07eA܌mZv/Za5T8O*aZuЖSmڞ#z}NY +T'c]{9ZdO0ʥ.TbJۍpGXs +7KPeK?p|='000Պeys:Q[Y.\"危!'SdȚ KP]L[m۩%H]IwWF}~CEk/cՅOU/8+x}POP ֗ tXNv$D+ޝ|˒S)]ԇo6k͛IL?Rf^LcPCkĎԽAXi_Ed05geH5H],&ҵҽ$t/y +U$OMrT'/39GH6DpX3fÊkg`ZHnAZҝ`nSt[5k:K!XJ(s߾ ˦F154]@7Z{~Jʳq#9a+7Iwy9FgtG^Ab"vel]F(i6,N~s4+FjEg)d7v[T.OƪHRFGҲLЫ2yV[еz%TrsbAC5'!9Ijlh W˨c'FbUjr "F +~HR)%5WhlꀲgU6pNB?4;ٽeIs':,i7F`#ZӢ* FƻK)FD u-}c܆_PdY~t`NiVt >gԣk [Y>5 m济G2C +_ ] Txtvxj3z//!G1}1Ø5ޥ( `*f0N`a2\S,UIF6I}fqNb`w iFf1LiyفFA؝_*x|$S7a1*vdYz:w Ϊ&!S5F +ScFLi\ݳl~Vb|:.}fPi1Ț;J7YR(Wҿ +2B YTVZ8_qmj*f3 a(_`R}j WjU󞶫؀}neU`h():[E@.9DȊ4*KVվeтc|X3tJ>B%Wia*2@F8/^bkZoџxVljIhPY'n:ֵъ0x_r7^X`;aeYL˫ XO$Lu{݂ɥ#+3 +_wHh.H Io5`,;'s2D$xPjԖDT3pWUEToV +Cp8\ + 'U la^.eʆ1oYl=q.gzq*!YMd^\^d:4~60 I] Ǡ8dm᥊JPBw˂G4rTi>2F<.VD,<5L*l=$9\Sh=kaa11[zuőrg/z*lC5/gKy#^xa0$nu+ + 4r&-󽢜Jy6UZ_}A"'uy=d1)@Gpa4:4V]yj@㼰YR~Jl[^e d^W t^1zb2fL5*C~B5a1ٸ>#}`heuX,3JB>N3Q\a^3ݜ/6&R#ڌ` +%I#, l8GpIBq$ 7Z㍂Ԅ` ldQǕ[%تu2,ͬѹjLEuSF UɵګHU4AH(Zd(ɪT}h +|Ѳz\VGҧM'Nފ]龀݁խnJS`Q[uM6C8ʩٹJ_ D =]R <6]7E6э}JPâ8As9ԘmfsН '=emLYᶲP[N&S˄NPnBj4T#x}eW +vɥˋH7pp*z^m}Mt~wc\֜8iLv̆fU P&NK_(&M/іoDu<7O񐩗Є̔a$QPd(< O} G?L^1DbS 't[K7,30Hl9vHDu`? vXW 3gBK-E7˜uZ)f s5iAGc!NSqâ$!t$k;瞁~1(1\!H@sBw{ke7+oSYclZIӸ{FLxϱ;gffjqCৎb1.xt8F\[N`Ϭ]Z^Z)%`b6vm=t3M(la6I +_1/,)F)\ncyȝ+>P~&Tt4KY*9ij`7^o7op!5v +\uZ 5ZP7^ʧG^KPsdtϕc:} #4ݡ?_| gAq XDGK@. |~n/`UIL!yF U(${Ѓm{j2 V@ædإO{Ѹ{Vm]OWF/,O 2ȷԲ+8߸JW r6i^afy_kӄVR@ϳX|Xq홶a)i.W@ao6-c\7"L}^`JzbHYI䌘Lp g~PglI/h{յih[ڒ$١c^/*!31D%T !3iITĭ $L`P6t& 2`, |V]eX_GUcb&F;#|s_N x\9B0[vVS[yʵiɩ1$N5z;a(ݤ ECpN^;ۡ# ir5h20(4j&m+Ww2ra6llOMyi }*%r_V$ k# q_ ^Ơq|5f$ >'~90ӢY,Hp)G +x5Oga>~؜lĢ m ;XۍV g KޥODC.t I_8>hSALd9z0O^:{u)ܼYJCc%{ )?gSNm=Mru3QgM.ws Z~P Cxf%$a!NJ/`BR߃vndCdo[| _v=2=&A`Xç(팄Q9غb>MƑ}4Yh> {9(XfGfKJ(\վE +9@AELW?RmgCSm G0IEK+Ot|6FIgTϮ +4=ؙ^FK^|yz|n_`|GcށzTgޫRב6*M©"~]/:~V戼Vhj_ fA=i WBtrEcET)a$)]dh9L&V |Lb9h -|uΒ_S_d`*&Seb{Ū_+A/%,*Bu>5 dP)־*vv7d/@53-=ll(u㻱2[|w̭7)+ +w 1 6IP@3C W䁘lyWz^.省H9ۈ +u$wAUr̽%m=[ke<_q~'.ltpν}%C;Y4DSuc + 8 >>{[pzi؜MAD>}u(Uf}7NBM5,G> {qY3HiG[#3考\#)Z~@@,{`|^=ֳ'0O}UŲEyL-f4:Zor-w _&S![{|I Oi}dml[@|\K>cm{:[ۯ>2𐉾1?g!G3m+ *T a5KAc7FɄx}O?+{^9+䞶Y&iT !^M cbtW}He6**K X[oe*=cElG [Gk^eYLGvw-O!gcGF :Wgi.:Vԏc&:ar02ד0-4rXZPj+uz`-'WDL#mNdGvCrXC>yl8r +U2FjN̋7{?Z7ݘ7O!t  o.]YH$3*"lx@*cl:c 1[-AXņ#+/PIF8h3'^TNg<4P`cԠBuϚM³\Uu|bz AB93'dؚLb@ͱ{(N"@16hTD9La`g, =|)nR[]I2AR\c&=gBxYɔ9+ayuq TMь37Z^nQ(n}ӷ%Gi,%PsڳۄI)c(/&K7mUOZvZaph +*3gע-e_%of r-Y%XEiчo*X_&\Y4Wb]7 +WjF{ᒥ/\_E4oM>6+1 k#[.z { &vap\tU>b޲m[K[I&˽1_0f̛pju=W^]"/o|(i/x8+xot3_ +hZ+/ PcJR6B_v{,|ޗ$[]#˷R|ZRؽ)?Qљ#0C8jbZ#v`ujv.e$;Fp>stream +HdM gi:AFAAH2y7?(?h%*~?c{ +[}cl)=ײ׏4~G'z?R,jiJ>ۦ$SHzdCy|˞rxַwG^b{*'~ǰd"ϘFgU"}i/s獾=Zgh9jmMįgƷ_^gּc-u#46'תFzc/c]ynAyJbQ@-@1ec⥸I +/Y͜fanPd=(؍@j X*Nb7!keNeI-U;gI]'{'ƽI>9s}Њ3c;e.~Tb9c mF`>ɇm&L2>V,ƌMq2&3Jr2ɲCfhV8k\p7F[:GC \17rRzG+ra_ 'کqs;O=c.{|a>g+6\).9%6!sh *eT_bøx$4Lx; +92).kL"}"^&Rfǯz~ +c+ʍd"$cfGW=Ve @ۻTXr98uv֔ fЪ*j0XRDt㭸6ap (>P%Mx$Acw8C `67;7KK dTBpB+CTt}TA~ `6-mg$=WH$}LSs2ȋ,EkWiV$r'J聃DMG\|Os34H3҇ڔ*iS^Խ{% Gi%¬8%\fr4h6^P*-;#cdR\ @mU8Ů?cF*Ҫ(~bk9]+B4dSnc(n#Ȣ#:{}|֎C&5ž+*Xپ%I? 2v${U|/Js*MJ6嫒ĈƘ \=O8AG)z8ˍ*㿿HhKn9?h+ ٸfV-㔃tm,֖6#X@~,I٩-/fXl \V2=D QjvxNQYk.Ey) +d)>{7/['0Wc̹FMep1 +\.'S2dMBcj傦+&୞4.%wWip3A_TcZuS ;>l%O*]l? P}^s P<BlN`z_LO<$_KIָI~3)"H + yĩٸNluFO.G7^QB )RK%R7Xfi h .Y +E$O]#d*hw! jƘ]B+UfE: @,QdAt~KOʙn;G@jr-4wovp Mμ+g*?  tv/=75+5tRF<ʬ">stream +HdI$ Du@F[ml)Ϛi߿?2#kMHƏ[Nm-LJ~aMYWs(z1큵z̲}~Kx>g#&^Ƕ窽{fy{O_Vh,qToátW{h|R͒9g%7K}y?V "M}(_M9M%HHrl.YJ<Ђ+8ؚ芋_oWD#Rvja^8( igq*ۍ2a^q?o\v"I1nd/;ÚSۖ8%4$KDbCbc!ѕ)ޗa Lߚ~'\1!lβ=VeH"%gol:? +C^$7qcQ*tqݰ\,-HVaыzn*+à#b8I-EIe." {$v "HKPCbK>0u%QOK J|LD%q i.;G Gl!̑E\ozZ +.ܞy`81UUO|hQ +tU'RGƣ\ٕI桘4ueI#w8>LQ,0. ˳0-SzUY%Yfă<]g݅&F)`ErSmuPWq j$+tvMPtl_"`0~E߁SRIs.P8b}cnF{o!퍶^mPxB{[zrv@iExrE٥콜-.Y H)hnpbĔe /s-( oA!q7X : Ѽ Z.ȬkayZuᢾܰD՛6*Z'0LNsIPSL[]ۥ%HSI zĆ"Ʀ5Iݷ>,o蜫nxZ􄇈w[DGw%>CC27|U> Y=WVowσD|*,Mշ&CX)L;Rif^LYcP7k^GʞlzW*j#Ƭ1;+AQʞ,^8Z.}{%O9BPhTjL͹zӚWVt6 +ԛšvq7Fz2a(Tw;tj1bYU9<|ĥr6i_G4м>|fv4aa-LTi5^JvSQY-0py5,s&nRrmŚV7B5w\?U88H$רIiiפz5/,n Sj$ur\h#[1E7Jɻ +[i5_ik︣ϟ4z7MU ;Mm{냦.+*/ (Xw9sJwk* 5vFRY13M&l +w)hQ2dW#X_!pnӯe*-ޟH0xУI7ٔd( Wk݃?T^$ZH5Ct[u?4I:jYD4YIfrȤa]˱d*ETvBх*\*N+_o!k@Q疣?:Md%UB8uS'wJiI@1%-f7!A8K:K = &9̿#. I[s/ƪ|;myY$y bC\4M=*X~xZ Dl&<^m`n&vkou\J _g|-T7|ى-%0&HO04S5{n&Ih&+.Q{]7+ uL0hCc.έ&\ӌn'>l/ U`S:Xm*]ziAj 6h֑Ĥ$* +k r#4H %ItYM;Q!ݯ +$͵N~mLɈc<"R]iF&Ax؟\|"X|$T7aDQZ%ӂ3ݬJpjB? ;ZjD=͜)+*VA^ɀuba gKIϊ ڼBtqJ8 H54gQYG]=WME-H9@XS@x1>Iőʨ}Rv9ܮRDL]!NH}>|pN` *Ng?6*UUOp +rw`,˙7ʶ&Oi*2cbfYtà&џxV0R3P#>Иc^c˭+ ij+MaH +nE#+[3wXhH r?b4k0B$5EB =L'Xʄ|"]hɹ+bk wR O,9^/eʈnNlrfc TNUPȚ3*RA# 93tZlzzR9MM"=*fAB@kg՘6smv)%(Yall:.z%"cU v Xr`^Np c3e3ZMV!ֵk&Ai38-;O(J313Uhz|-Fv'=kTج0OWԮ0ؒGCʝV/ڿV\yr1`ςs8"-pҚWkGKq[Ѡs΋ +Hc]#ie1U z.#(N6jVKcCP#3 اqJ="hECхLj5c <\rv۶gn#! LY;r6oW1!JއRn/!60Qxk,= y (Cw$>"1RTA +Q&yNLI1qaf2z}(C+BXkSʊӲϰhF QV{r]! @<'[0/ 3TB sB6 (L.Cv;xk}kT>﵏b8!}q/H-Jȶg^b4]zƏU[y$b[1mQ?e$Hmw/"cc9RC/,@l^-2O21E ++CiAY/;~2KcI83eAhʚ:^ibJE$=+&ˌZ3@ +7Q1^'zLKaRc\^dZeG1B[A:{hh64]| ;NOeI|?gv}j#U&S[y|n)$*{@&XbdtO&{ 0†罘<{MFRvF-}I=?+㐖;(^nYX&:F\:+Y/^ps[_Ԇլl| 20K/u䍯 .6AW@m蕫zj[WVjq6|ɧ/dUl mT&K7Kf/͖u]Mio]+gq>T$e$ZI>j".w,OdhcJY3&MlHn0X|Gŧ>"9_߶B̘LDˠo1eUQ?'+~C6q Nte-Xu$2Ǻn*X\w(şpO4Gn5v,8l7o:&S)!y)H;A-aVW>d}Poq^e%9DA=O~ؗ2B1sQ*H_zr(œ$ާ:%/8]n1%ͫ1IJZIe#t<Z8vDn ,@`=#)+lb +j911}g>e_@\[VHD3l2+{Y%3J 3K' |<؞΢9k]/sE95 r3WrN{r%!iנPhA@Ks13z}!qc6~E*ЯE:QskenW[3}Ymtv؈}-CWix9jUn0-:g2L]FzLHW6 T6-Έ;5?E[ȁT/Z0h|PC:~]DL["DvXݺnV%V0 $=6\N6mOȀ#4%" ++bMbgATե`z{8 cV '.;5ס<ٛaR}!508qbk~fohf6$k+܈]  v~1zl牋:Un0^2^*ÚmU.$I +n($㜜`ބ"vf˕9zrQa9/#! ;S!̿0"iA)0_ȴpTո%TSBpktұH:m[SrEjnj>-7.C5% +ӱ%Ɓ$9g: YM)@7fAqlh>]omĭf+(=ɰ zyʻ4՗P5ELʟqVQ +W-3+`:E(a+6:*՚rMOUgд]3:@aiEiDqU2w|tѯgRiمށ-a bsZvX*9CLi{rp]ZvIpMr(,8ݍ#{H)sH lW\=0^ITDOI"/ode?z®zl;N[AG mNlFm֙>}z.:hݼ2l4@)\3Mس]qyeF/#"9<GM8}(,Xo:om԰7 +] <*-Ǽ'`sV9'G@oƈ +5'OVdſYH +5Kv2n.d?K$l^QpXX7a K5ܑK}S o+pOZEi?ѐTluɊ54%K9ewvd6`Z=`U=d -};9L:!DŽX߿rܯ+W-SbHy厯U(,#]lvgz=yd둆W`;ka#Whqܿ Gi.R9CEur`k`P +y9[v~`aF IV$HK4ըi e_a"PC9 S_`meMx DŽ^#x-8(* HgĊNY * 8aƖOeOAzJr&:"Fky3'gKJr{Bu[@d.ׯchp]ksl(ty_UR2ni;T)eHaBٌW(bҜT3c]J(^]s?u8/xۯ>،UHfHyt (|qfl_9Q:gG&CtCH +*B-We]!1Xv`U@%2U,1W~V1sb)ZUD][G"w9Ej%N#by tyv_>+m܆`}~>C}z%Їyѥ>W)--ot hPj %֏SQ `U%!c0_J^cl<ﳆ#<#g1y#F iwMT%q a wwvU36T5*y](>,ʓiis(u2-Ԉ){ld;69\`D#v9t3l#?II_q@DDS-nr"SR5 ͦ?i6'xvՊ/6DƯYnlg&à |LV8''~C/Ǡ~W[vT:ٗtlǂY;r^W҂XQkZ(os" N + (u_n32}ht<YtA /4Hrbk.+.L)DKb10VKRdo灲TBg}Y"He_ pX +p]#Gr+r N;Sr4_ӳ+ I7Tbs:&>*(&?(+K W n:G i$bCXe#%!Qsfà'^T]'nO yHUh1[Bk.; $}(02Yaf{X \}PC);Bd,Ȱ5[ aA7|ɜG5(% %VB-TCjJ^b{a[ pBxi42~q QI~0cg >8NQ$l+MH(I-u yIvMNڄά;J(T;͒TTꡤ=1',a֊u1kɗCD3WIk +>Pe9-J=kDe0q\R[%Y/|'鵺h;'+:)xvg ;E>rdQ:RQ!^):jW\0~dzia;pࡓ\ ޛ#KqF񅉅cIףwcITVͱdɇ|)۫Kޕ51#d%5g>&cYOto-8ݴmg Z X>sV)"lJ-}~C`+vMAs7%lp,젬=0wQ7Ai,EÁ߰lo\`|ԺqAf=+cΕ.o7Z z&#r!Uskڕdydž!cg`SS$ss +;|ٖt}2>BJx x~[y_H܂z |˕_56?{wPtfȅK0jNܬy{}")U# QNi/Gtb`NT \:)_*G訠5)ʙCTh3_f9^>t6 +ua];7F<Џ*:wSDee1AbR:=ڤ}M4`JuvvV$[VAB +IeLD=(("JĵO]f%?; GLB . (n{%Lr'n&ݠbىDFÖM**ƕZ=_ +Sg\޳Zgٺ՜PF(!b&iQ0cgUR:V>HU#xqZ*LqW%,0py׀ԃ}eӏ&PֳzlVzSYO"fn8ÇD2H(=I47?㓟mW endstream endobj 86 0 obj <>stream +HdKe DowO%ꯩӆG H؞th7R|~?c{[I#9{(nq~}b+z!϶Z-,ֶ}|駟w mMdw 9 %bL!,]C.mcH}lfXc)4f12ZU{{fR65Ę +`z/r 3Gʡ5,_deK!ٚu,N=j aH_ -הjgߚCa;`f[/5: 2#Ίz1@M:8Mxb]HaQ} 3CfT~d NsVLm Jͱ|7~z#롃9ŊTVn\0',{|je$ %}Bw&:D"_VbC~~B)1Q6n5jA i͂ s,-|_qPf&|J2Pԋ28M%(FJfW%@7`A}d]؊]Qo7"RG3G+J b_ کŹs/=S.;DҴ_87R[;$d"Tf@-\oб$!7̫ #tD]hQEĉVHr%}t2\e뛴I28~l.X[Urd#q7;>ZM2XahRrSVMYZT$㭸vat(ȱ$P!BcKf+0 ;ʽw'tE%J/%W.j+AKMOKAxd848{sR3{biZ"ϓQ*u\ m=l$ X{%[9DX@\Rb=Y#Y=ӸW׆_baqLK#U&GK&rӴ)iR~'pq>I6d[mp'fr֬ngƵ"K౹$Es*Vh*.CD5HPU#Ygr|WC*užy(XݾEI#yE &dl}/J.00* i^)}JfUY^dăյjHݵdG.j8& + f!u]{<9V]T!_ Sj=B{O8{kr4&\u)j#OPڻ!)%SfWRC5oJʯgZJCCpڢZ'QDhwz x寢NR̊/geHu?, ڿI/z~j }@BGN{=`\N2!!WA{IUTjN͹ڄNkNʹz3\`\chkZi/CFBE~}N6S Y_-m&qiMg}o4z"(VIZIdjS"^ 4y>J $5)JW_!Jmc)nU-ěGu(AzÇe+[KyU͍ m0ljw֋h 1=GVYڸRo鑠IO+?Iby9Vg5vGnAK X|=(;Qler&Y1R+/JK%3ܣ +`kRoZ&>hI1l,tDq\V9(]%sz,!ͻXR/}l ` endstream endobj 82 0 obj <>stream +HdK% D絊͖m#I?Ͻ'*4Yɫ(F0H/}Z,f?{ooO y+iumVއLJ~aMնWK*zԄZ=V>?^m/o8Ź?_eJxZe5;_/ry[ Yz,=Z{[7eo}[+k^\x־۪~:%ƓE\YP=10G tQ`Ѷqo=VX )L}_mF kG4g%gRw??>04+qg"|=tS$v|Q"Um\2G'geHR`P%}BW!:D&_Qz$NռќRnǝMNJ9 rY vf5/BoXqRf>YP>-Ȝ& }1o|%bqU PXP?p}fYg7bbjDWԛe`Qp䁰bXkցΝ|8{[n{O|z y R|ٸJĻsrSȊ= +oiMɩy Sņ't<#.4Dyz81W\IOtiRҚF$+`+`=7%Gb$8{ M޳EJ)\(MW^꓂4U)=:E#gH +LS$h]2 +@p{"wV +-(Q:^PBHs-w]: ڇ vcxi6d)%y& ^q\AWR3GbTiڸ!ϓY&u\NmRUIp\e)Lv)Wgʬwɮp.39K+_j]/.,WEU)DrFOEpH% +Gq'G .NF]8 Ok.2K퍺oąY7RGoZ[ߓ yxZĽW%)q'aQiNڶ=iB$-*^peeӛ SD%I7s-)T$'oI!y7\$ >l ayZu޸dJԛ6+\'2dMq#byB3y{ xkzjɁSռq8oNnpzAay\uBX"u ڿI׎/y~>Ѫ^o~S0nj'yj=U*âH.5֊6|ԴCՋĸH.ah[DH_"̴BU~}NE)kDVm $.}իI8M#beg8Nb%ʪFc@D%5%d| +ex\ +]}#(ytLӏ5 @&8 " m4~g%*q̅6X7;1јM OW+G+c +q # 40@E%BXW!d˻L!z +I.g2"f]_a=ߟ!ht + /G3q1LN8.ЊIc446%")"ż1igs oI܂DqȌMې_%/Jѥ> D%w 2 sjelӇ\`AAP4w+?:MtG|t3(w\ۚZDKWHJj5J@1%1pBp.(-N4 \B4kJqNW-%iK.6$iyCFBi%ZspOX+ yj EP}=쳾<L`@"5PM?zeOB|KhYK hZ\Յ˯dbR{(KAT1O6tMvqz<-RbQKg"Ӌ$*愴FȴHtvy@Qp.+1(<]WzhHna#|lV6YIVfD,3!].` +*6(QX,TJS-;ԡw!ar[ ~o`#GFi ӌKr65</dSatt?i5j 6xABh:W9IL;|Y3 ˧A[ fbVy0WUR2Y芀\rXq9F3骇OVu{3Pye{?,f^tJ>A#TDjǢ?oY#6џHVvdX(\főimxmEc|Q͂]xn;w{˚Q~n[\DdXFS0 R$G ( +ǟOaehHq!z-22f(f߯䪊ɭ BTN 31^@-eʂ'(@rvXo03Swm*yDB'c0I>^>AA$WdeaQE#(:˂G.yZsgK|e35w Xni+N +Vhg0Fn}ZQB\<[*udhPgS r.#P:Ш++[Sfy7Ȣ㈰͓.PB_g8f?LC}"GE>c?ALK6.Oy_x}vYM^3X;r6m"!FއQn< + +)ՑwF/ރ5\"hD>kF` z4 ) +AhK7Q"Q0$Ed39o [DZnXXVzBոCf^k#\3yA@(HM= !rbx%ױ{ЏhݶJ1pegbů B]Rms5}сn3?]Xt]S Arj|nA~CE}jÂpJA#Q|YN|:w!<Zwzz[Ʀ@EIʊlI1~AWAcD>QeȪVZx1M{5^3Pa5ȴiٔD +oáUecNKx AT|ۜpCHܴUЦr]BZmX8f>Kݯҹy<T(!ڲuJva>OI:mmG?#݊5<( T*?kNFec +Ԝb5}y-#z=F*ǁu]dzhs ;L'ayL++ޞ_ܢNjNUYe_Oۙ4Br}4eR6dZ +Ԣr{kÈc 2b>X9,uz*CwkHEZo5Hw][ +zy +WɅ*5^MbvE^rq0ШyJϑ"ֱSU%̱5@/@e(Mir5J_1y+Wj|M0s;ȷ 4ydRJ7yf(vpˆmK84c&:sa)tl:[Joo}}s =#"z&uTay~J0Dn |/ZpW!Kr#j=A9J,j wpH=]E !2(cT,-ך;YYr(q7z&@;y}%B=k}Rp(V51C3f'07q̳?ɌAw; ]ef5=JS7Vy70/<(uA#BXggě"mj8N㐐g}մD/{՝$[jF-H7E]*؅vNJ 9Ǻx ^lx8d(dL X':C c>H~XW}Bo.3>r |I f5uq +!NlbU;L|BHђjaFj8;a/<ѹV0yzeZT3ɸ6j4o5Pd`&'sQ( >Z=|#pwGʱll/xM4kBJ +ߐN6#_WlaO6z0dG"%pSR;EKřg`)Ber8waE܎qӨ;aID#` @c;;Θ0J5X0SGšl#!ٞ׉A]y*[PLjyLs`x/-jK5K$Zkx@gbxo5K+Jր8KtSBMm8/C0uI?_^NWXe~0p] +aI؀()_Tc^k3f tWګ_J4 +BԲ^;n4mŇQF|[0O +bT+$%iœጯgloP!C;gG(x,;?VzRSbzG$Bk>mJAZ2*c89: +1ܩFn?L9;~`˶[Xdžx *W?Uю=V`7{v[9ٷA6zT /\iM#}xh{U9NaJ)ssO +wux7iET%n`xd}P qƊ$v2,[(g B 7e)Ҭ۽x)&%Q-' 5 bZ>"wa_{)FÚD9bؼGUjR~"`6:9؋_Cj^"w;VG5Ċ|&%BW"~VjUKݝhGG8Q`&( Y?75CZ WWIN;/R`X%+XLD13$U͂*|ЮtWuDx%]}["!`,_XJ>~V~+O~1[cO2jsŒ;|_KPY Y7[( GF.2gyPꞜҎl5zl62FY0t.$;kj!qÓ)]r@el9+s= Je9/F~|oErg{V/E ZrܒҶ]-c̱=8θ+SZzLtP)TޡlD +#OXhD1sG,j^i{{`6֕p8%Ig߿!!:t,hMލ B'B@!qs/cSѦ\u>+:vmIҏA)N!l~.Amr ЊuB)QnI̭<ĽW._xXUv❾5Acgo.{Z:u;GC}W3+dM.~"=pXiRqPE5O@F\c|Ϭ1#^ WY͕t,/~V=]7Vvԫtp'pi{fƟfuF,dkk~s0u(R" 崕ʢ:pA.w$m sćD2v9t3ʑ}$%8lрM=5b.%1(]p|`h8؞pSI9aWoKkYh.L|d +\"1M]>)-G;M)Pꋮ,ױdҎRAJZ`_Vu]迬T\sǢ N ҙ,o(o.BZWTy.`A}VNdq؊3+u9 XFY(7XoB<r \/2&5W -7H| E5Bo4DtF-3 TIZ#I-4DyTzL^P.[E&cm:/i ֤$VVwF*7p90sf'wVANv@`n l~YfC*I{D V*G/f#Gx=,>CR(塄ęŞz+<0l>(P6հB wRBxeBH"A`:I[p@A>yitNnYJunAQWPg +>B*43J(gƑ>QP:; *)t ߭TBy¥@`䐢ZTG-=L9]1sV,94bB5Tsxn+mB9AS1u2 ;VIK|)y6gy$VMo>\I wƽKk%]'KґWՊ H}i!K' fKná[cVj-8"'(m%]o%eS6|O%9R}Xۧ\,yW}(m)p=fR:dAǣJ{prMTl\ɸl?M\?*0>{? JKҨMdڳۄJ{pSt[tąY\/2[/ +n뻈 +*g\+O޻q)$.:m޶fі.ڢ?IDvnΆ[=RK<0ꦗ [{r=n OT֞[RIi.Uo\D8<60(}̹fWĈS} + +{ʵkJn72l! 秜\VD%˼8 +E=W^]7>@~CISY)[ͮlGħ+>Zywm#T6r#ְw!~-H&3F=_/r;lMΌ%914i;~s9dhM}U9ÇWH.gui%RmeƷtmھ][|@FG{Υ);O TCT>h !]f"//VC<"t#s]XaaM_"c}Aq:}(l@QYpe35nRԦD0pU8>숝 JvI@D%4RaGlIr"t |阺?p;eiT N(yûeO}-N6\%Ϫ(-lf> endobj 46 0 obj <> endobj 64 0 obj [/View/Design] endobj 65 0 obj <>>> endobj 30 0 obj [/View/Design] endobj 31 0 obj <>>> endobj 81 0 obj [80 0 R] endobj 113 0 obj <> endobj xref +0 114 +0000000004 65535 f +0000000016 00000 n +0000000175 00000 n +0000015977 00000 n +0000000012 00000 f +0000016066 00000 n +0000016457 00000 n +0000016844 00000 n +0000017235 00000 n +0000017622 00000 n +0000018013 00000 n +0000713033 00000 n +0000000014 00000 f +0000018401 00000 n +0000000015 00000 f +0000000016 00000 f +0000000017 00000 f +0000000018 00000 f +0000000019 00000 f +0000000020 00000 f +0000000021 00000 f +0000000022 00000 f +0000000023 00000 f +0000000024 00000 f +0000000025 00000 f +0000000026 00000 f +0000000027 00000 f +0000000028 00000 f +0000000029 00000 f +0000000032 00000 f +0000713289 00000 n +0000713320 00000 n +0000000033 00000 f +0000000034 00000 f +0000000035 00000 f +0000000036 00000 f +0000000037 00000 f +0000000038 00000 f +0000000039 00000 f +0000000040 00000 f +0000000041 00000 f +0000000042 00000 f +0000000043 00000 f +0000000044 00000 f +0000000045 00000 f +0000000000 00000 f +0000713103 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000713173 00000 n +0000713204 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000024785 00000 n +0000713405 00000 n +0000702478 00000 n +0000025084 00000 n +0000021596 00000 n +0000024971 00000 n +0000700331 00000 n +0000689764 00000 n +0000687613 00000 n +0000677060 00000 n +0000674909 00000 n +0000018812 00000 n +0000021453 00000 n +0000021631 00000 n +0000022137 00000 n +0000021773 00000 n +0000021893 00000 n +0000022017 00000 n +0000024855 00000 n +0000024886 00000 n +0000025159 00000 n +0000025547 00000 n +0000027226 00000 n +0000030466 00000 n +0000096055 00000 n +0000150197 00000 n +0000215786 00000 n +0000281375 00000 n +0000346964 00000 n +0000412553 00000 n +0000478142 00000 n +0000543731 00000 n +0000609320 00000 n +0000713430 00000 n +trailer <<17C35920048B40DD89DC288B14F36207>]>> startxref 713651 %%EOF \ No newline at end of file diff --git a/microsite/static/logo_assets/jpeg/Backstage_Identity_Assets_Artwork_RGB_05 Logo_Black.jpg b/microsite/static/logo_assets/jpeg/Backstage_Identity_Assets_Artwork_RGB_05 Logo_Black.jpg new file mode 100644 index 0000000000..cb0b6c7959 Binary files /dev/null and b/microsite/static/logo_assets/jpeg/Backstage_Identity_Assets_Artwork_RGB_05 Logo_Black.jpg differ diff --git a/microsite/static/logo_assets/jpeg/Backstage_Identity_Assets_Artwork_RGB_06_Icon_Black.jpg b/microsite/static/logo_assets/jpeg/Backstage_Identity_Assets_Artwork_RGB_06_Icon_Black.jpg new file mode 100644 index 0000000000..cbd97e78ea Binary files /dev/null and b/microsite/static/logo_assets/jpeg/Backstage_Identity_Assets_Artwork_RGB_06_Icon_Black.jpg differ diff --git a/microsite/static/logo_assets/pdf/Backstage_Identity_Assets_Artwork_RGB.pdf b/microsite/static/logo_assets/pdf/Backstage_Identity_Assets_Artwork_RGB.pdf new file mode 100644 index 0000000000..6af1569ec1 --- /dev/null +++ b/microsite/static/logo_assets/pdf/Backstage_Identity_Assets_Artwork_RGB.pdf @@ -0,0 +1,2922 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[11 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + application/pdf + + + Backstage Identity_Assets_Artwork_RGB + + + 2020-04-27T17:09:22+01:00 + 2020-04-27T17:09:22+01:00 + 2020-04-27T17:09:22+01:00 + Adobe Illustrator CC 23.1 (Macintosh) + + + + 256 + 108 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAbAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FULqd99TtTNx5EkKvgCe5yUY2XF1mp8GHEk0N7xvoRDIJmklQS3ALLzD1HFkO23bLD HZ0+PU1ljwniuQuW4u+hHkmN5qNxDNMqAFYgrU9N2ry61cHiv05ARBdjqNXOEpAco1/CT9vIfFVb VoBM8XBiy1C04ksQwWlK1FSwpXBwNh10RIxo7e7vA7/Pq46lxuEieNkaQUWMgci1ada8aU3x4dlO rqYiQRfTrf3UtXVVkYLHExPNUYErUBq9RyqDt3w8CBrhI0AeYHT9baavC5KpGxckKigqSS1ffb7J rXHgWOvjLYA38PPz8urhrFsZETi4ZqAg8aqSxUVFfEdseAqNfAkCjv7tt67/ALkdkHOdirsVdirG /wAxvOcXkvyVqnmaS2a8GnohW2Vghd5ZUhQFj0XlICx8MVfM+ofmjKms22t6TqsOueYrx7W8n1qE 3dk1pE08UUmlNaSFoprernj06lvtipVe4/mL+YXmXQfMM2naUIzFBpP6TCfoq/1SSWX1ZI/TLWc0 S26UQfHIKYq4/nr5btrqG1v7aVZHszcvLbSW86l0sf0g6RxrL67IYgQkhjCs2wOKq+sfm02j6lpk Gr6Nd6WL5p7dbK4WF7ie5rbC1S2lima2YSfWSG5P8JG5WlSqp6j+c9sl1qdhYaPdTahplxHBJBJJ aIxU3sdm7mI3CyorNL+6Zlo+xrSuKqj/AJ2eX01a+0o2F215as0VtCj2jyXEy3kNh6QjWctEzT3K cPW41X4umKqOofnv5Z02Vbe/0++tr2N5lvrR/qvqQLbyCJ32nIlBY/CIuTMATToCq9KxV2KuxV2K uxV2KuxV2KuxV2KuxV2KqF7Zw3kBhlrxJqCDQgjvhjKmjUaeOWPDJCabocFnI0hb1mNOBKgcad++ +SlO3E0nZscJJviPu5IuWxtpXZ3ViXADgO4DAdAVBAOREi5c9NCRJN7+Z+61h0yyJJKHetBzag5H kaCu2++2HiLA6LH3faeu/wAN91w0+0404E16sWYtWvKta1rXvjxFl+Vx1y+0+9pdOtFNQrV2oebV HE1AG+wx4igaTGOn2nopyaTBwAhJjZacSWdgAvQD4gR9BGHja5aGNenY+8nl8dvgQvh023jSMblk pvVgDQlhUV3oT3wGRZ49HCIHl7/f+LRWRcp2KuxV2KpR5s8raP5r8vXvl/WY2l06+VVmVHMbAo6y IysvQq6Kw7bb1GKvMfy5/wCcZfLPk7zLNrM98dajCcLGzureMLCRIsiyO1XEkiMg4sFWnhXFXo2u +RPLeuX/ANf1CO6F2bf6m8lrfXtnzt+Rf0pFtZoVdeTn7QOKpW/5Pfl68lTpri3qxWyW6ultVL2p s3K26yCIc7c8Gou4xVEr+V/kn6vPDNYPdfWUliuZrq5uriaRZ0ijcPNNK8hotvGEPKqcfhpiqxvy r8lO8zyWtxIZldBzvr1vSEs6XMhtyZqws80KOWjINRiqX61+Tnli8tbkae09lfyh/q88tzeXMMJl uo7yXhAbhAnOeIOTGyMG+JWVgpCq7Rfyf8tWenJb6g019dmW4lubqO4vLf1hdSiaSKX/AEiSSaLk q/DNJJXuTU1VZ3irsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdir sVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirs VdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdiqld3UVrA00poq9vEno MIFtOfNHFEylySs6ndRXcSzVDzOq+gACgR9lZXG9fnlnCKdadZOOQCXORG3SjyIPenOVO4dirsVd irsVdirsVdirsVdiqXeYvMGleXdDvNb1ab0NOsIzLcS0LEAbABRuSxIAHjirwrzN+d/mzRLqDX70 PbQ6gLebQvL8S295Y3WmvIiTSzXkLtJFdAy9R+7B4qA9SQq+hsVdirsVdirsVdirsVdirsVdirsV dirsVdirsVdirsVdiqF1OyN7aNAG4EkEEioqMlGVFxdZpvGxmN0lel6BLFMXuqcUZWjCnqyk0J26 b5ZLJ3Os0XZcoyvJ0Nj3hPspd67FXYq7FXYq7FXYq7FXYq7FWO/mH5R/xf5M1Xy39Z+pnUYhGtzw 9TgyusgJSq1FU8cVfPv5c/8AOK2v2fme5Xze0Enl9I+KtaTnncOk0cqCnDkEPp/FyofDxxV9SYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq0WUMFJAZug7mmKDIXTeKXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYqhdQ1GCy h5yGrn7EY6sclGNuLqtXDDGzz6BK4NKutQBvbuVopXANuF/ZHUHLDMDYOsx6Keo/eZDwyP010VU1 G90+VINRAeJjSO5X/jbBwg8m2OryYJCGbeJ5S/H496c5U7h2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KoXUr9LG2MzKWPRQOlT4nsMlGNlxdXqRhhxVaWa bYpqJa+vXWYv8KxKdkHvTpk5S4dg63SaYai8uU8V9O5u4gvdHQzWsnq2gPxQyb8amm304giXPmnL jy6QcUDxY+49EDe3c99LELgoqKAywpU7MAas3QbdfDJxFcnB1OeWaQ46rnQ/Sen6GVZjvUuxV2Ku xV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVIPN03pw21Ptl2C 8W4v0/Yr8Lf6vftlmN1Pav0x77+Pw7/d1Y3BqLwOZ4JfRddnlRTwG/SWLcp9xHhlp3dLCZgeKJ4T 3jl/nR6fd3ImfXbm/wCMMtykiVr6Vurcmp3+IAD6T9GARAbM2qnmqMpAjuiDv+PwEVPccZ4xRvSK RcaCkZPBacD1mPh/TEM8u0h3VH3chy/n+X6mYZjvUuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2K uxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxVJvNOi3Wq2SR20kayRMW9KZeUclRTiSPiX/WG+SjKnC1 2mlmhQI27+Red3T3ljdCC7jkt7tB8CSSCKWg2rDc/YkX2bfsMuBecyQlCVSBEvfR+Euo9/uDZvZw tLgzpEev1pxFH/wK/FL8lxYkn+Lir+lsP1y+D0XSdGseMGoSws168UZZ5ftAhAB8FeKnbt0ykyPJ 6TT6THtkI9dDn7u7om+Rc52KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Kux V2KuxV2KuxV2KuxVLfMH6A+oH9Oej9Urt61Ptf5H7Vf9XfDG+jjarwuD97XD5sa0H/lVv6QT9G+j 9cqPS9b1vtV24ev8PLwpvkzxOu035Hj9FcXnf++ZvlbunYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FX/9k= + + + + uuid:b8085143-1ae7-d842-9317-fa53117c7911 + xmp.did:d354581b-a69f-4849-8caf-9529a577eab9 + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + uuid:57813b81-bfa2-924f-b938-442e8fca58d1 + xmp.did:17c4aec8-eddf-4473-bdc7-9dbc4289c51b + uuid:5D20892493BFDB11914A8590D31508C8 + proof:pdf + + + + + saved + xmp.iid:96cc7365-26ab-46ae-a826-605707e77cc1 + 2020-04-20T16:59:06+01:00 + Adobe Illustrator CC 23.1 (Macintosh) + / + + + saved + xmp.iid:d354581b-a69f-4849-8caf-9529a577eab9 + 2020-04-27T17:09:20+01:00 + Adobe Illustrator CC 23.1 (Macintosh) + / + + + + Print + Adobe PDF library 15.00 + 1 + False + False + + 733.760931 + 160.885798 + Millimeters + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + White + RGB + PROCESS + 255 + 255 + 255 + + + Black + RGB + PROCESS + 29 + 29 + 27 + + + + + + Backstage RGB + 1 + + + + 121212 + PROCESS + 100.000000 + RGB + 18 + 18 + 18 + + + 404040 + PROCESS + 100.000000 + RGB + 64 + 64 + 64 + + + Teal 01 + PROCESS + 100.000000 + RGB + 53 + 185 + 162 + + + Teal 02 + PROCESS + 100.000000 + RGB + 125 + 242 + 224 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 5 0 obj <>/Resources<>/Properties<>>>/Thumb 17 0 R/TrimBox[0.0 0.0 2079.95 456.054]/Type/Page>> endobj 6 0 obj <>/Resources<>/Properties<>>>/Thumb 19 0 R/TrimBox[0.0 0.0 337.465 428.499]/Type/Page>> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 21 0 R/TrimBox[0.0 0.0 2079.95 456.054]/Type/Page>> endobj 8 0 obj <>/Resources<>/Properties<>>>/Thumb 23 0 R/TrimBox[0.0 0.0 337.465 428.499]/Type/Page>> endobj 9 0 obj <>/Resources<>/Properties<>>>/Thumb 25 0 R/TrimBox[0.0 0.0 2079.95 456.054]/Type/Page>> endobj 10 0 obj <>/Resources<>/Properties<>>>/Thumb 27 0 R/TrimBox[0.0 0.0 337.465 428.499]/Type/Page>> endobj 13 0 obj <>/Resources<>/Properties<>/Shading<>>>/Thumb 30 0 R/TrimBox[0.0 0.0 982.381 1247.39]/Type/Page>> endobj 28 0 obj <>stream +Hd6y +dFpO.`%Ͱf"}ϗնJs+T-mWؼݼ=Gc)נ_=Y +Vx{ߊǴVԮ뉼_f\Oēl+m^ɧ{x"Wy/7kqs>sƺ[,[ mDyhbWbi?ne.Ǧm|{ Vae#{6ֹv@a:cC>_'B r܎ +i2lb{ʄxWʎ޶VR+#Myfڬ|yoi{pv +)6≼A]gN:57gS+g aI>"dðu3^aG5rDam9QVP;cWv_34~-dak=u2FjQBg,0ȹ"1QoA{KH̸!֍qT(6FBDB n@(k@-N: ={L1DHZH{X|!y#J@6}q~du{ n7:xE1| ְ=4j +⅔@*5Q fbJQUP\k?dqk![#5L%Aa$l~6 TDCkq, +#d@I]E2$-|"+@.c=EHZ%IFU6LazE%AC4N@0I癌ewSȸȌ6'ŨULqwF7I;p~xb4 bHZu5R5v'B عȊrἫ Fyv5EqqDJNDU "j&&0ZyO) 9 ᜨ;)Ea^]d{Yhx5!%rx47D:V'ht9ZKj,.M~k5 X CfIAS=z4m=W&U))S!oSI5ym<6o,ܑߨ:]dj#T]ijtj7{6 )fѢ +Gk$ue(-뎼/51~ $ u4Z4v#*ÚYaC +fEPHq" $7!BJ?pnUtnEwxwVB*7ZXj7L<+at~%#?W]ʹeW7Mq3ej?fNے+mD3=az1-ODqD"?](;K&*Ʌ\T-DLxz>Ei4`7M%I] +CJYe7I.䒤3RzKr%LM&Ʌ\tF&]d=%);Vn\%Io8KS֛$!K}9ˁ-%o[ȥC}qG_Էޝ}-% 1Է鞆–ȮzUբ>SCk2*n gL^=xEz*\TYٌvWEoe :GUU\EK;XE80WW**\bѶYwjEغZg׷JT .Ф:aZ>MCH%]߷o~}/߷ׯ 0c endstream endobj 30 0 obj <>stream +8;XF7fm2p,%#+$tPDK.?n' +qcGkVl>MWtq&Mo3CAMMmVnXt+Ue?Y=Z.\db72He!'j^FfN^m1.^94A3C&%*O;1+_8 +*_W"qTijkPd5MmOB7/P1D'A#ZRpYP<_gB:,AtF%9r0M3nJF_H#VQ]o:QPj?#hfTf$ +0(1ROHb=Z_Utn,L[;SL]m[Dh.n?hofX*rO<]1i7YOJGN1dX![L7pe\gko@I_AW1kC +k7X]c@sE+01%e/cWj"IPkD]%_dJ@03<"]r'@%<>,[:4M@8_?tKLcgU->Kg721JB=V +2VX0WqJCcfS4tIJjan0-afTZ]-!# +e?b$%Ur(%/Il44(p0_1eog'M<9n!np9 +p0$>aj+Z$#hLmCBVd"l22]/Y,jB#$BEhNCZL +l+SD(W\+KR1khp$8b$9IB/tCBrOQtT,"l)9kP__"@W:^=,Z052e99!>*]1/fd@o1B +]pS=5I$1"oks"WYTL2Jq@N>OT89lMjFsOC4#j7@lK'QuQCEP9P=8Q3J=K@_V(-bu& +'f1+j/*oc'cQ#aA1E@K)"g'uoTm5KZlg1>\(,M/+Wig+Ha$YYnBjPT<&#KreN1BM7_CKk!T992PngoqPqOg&Rc:? +%4IDabEgYYb\+eOTI)OqmSWe4#F(#(@pEfo@_LVoMNk7:#o-4rJQ&S-*er@s:R\43 +:hsDQ?_r=BW$"%R([<'$++-1CfkQRFr$i:4N[ZQZk^10M`(/Wd7e1sH)*F6Zq-!DUO'sp/9&%HiN1t<.Am?J7 +cPS&KWk3QK)8FEu@'tDM7=FN endstream endobj 31 0 obj [/Indexed/DeviceRGB 255 32 0 R] endobj 32 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 29 0 obj <> endobj 33 0 obj <> endobj 34 0 obj <> endobj 35 0 obj <> endobj 36 0 obj <> endobj 11 0 obj <> endobj 37 0 obj [/View/Design] endobj 38 0 obj <>>> endobj 16 0 obj <> endobj 15 0 obj <> endobj 39 0 obj <> endobj 40 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 23.1.1 %%For: (Natalie Strange) () %%Title: (Backstage Identity_Assets_Artwork_RGB.ai) %%CreationDate: 27/04/2020 17:09 %%Canvassize: 16383 %%BoundingBox: -5080 1539 4131 5351 %%HiResBoundingBox: -5079.08096277355 1539.48247256369 4130.81283900864 5350.91952314631 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 673 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0.070618383586407 0.070618391036987 0.070618383586407 (121212) %%+ 0.250980406999588 0.250980406999588 0.250980406999588 (404040) %%+ 0.211763471364975 0.729411721229553 0.635294198989868 (Teal 01) %%+ 0.49064376950264 0.95199066400528 0.881853818893433 (Teal 02) %%+ 0 0 0 ([Registration]) %AI3_Cropmarks: -1429.73576009201 4908.85389023608 650.216486487336 5364.90811938603 %AI3_TemplateBox: 306.5 -396.5 306.5 -396.5 %AI3_TileBox: -792.759636802337 4857.38100481106 -9.7596368023369 5416.38100481106 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 1 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: -3450 7755 0.09852450408425 1242 674 18 0 0 11 51 0 0 0 1 1 0 1 1 0 0 %AI5_OpenViewLayers: 7 %%PageOrigin:0 -792 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 41 0 obj <>stream +%%BoundingBox: -5080 1539 4131 5351 %%HiResBoundingBox: -5079.08096277355 1539.48247256369 4130.81283900864 5350.91952314631 %AI7_Thumbnail: 128 56 8 %%BeginData: 3000 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD35FF8BAFFD2EFF5252A8FD4CFF60AF8AAFFFAFAEAFFD06FFAFFD %21FF277D7D52FFA87D7DA8FD05FFA8FD40FF8AFF8A8BAFFF8AAF8BFFAEFF %FD09AFFFAFFFFD04AFFD14FF277D7D2727FF7D7D52A87DA8A87D7D7DA8A8 %7DA852A87DFF7D7DA8A87DFD32FF848B848B60AFFFAF84AF8A8B84AFAFAF %60AF8A8B84AF8A8B84AF8A8B84AFFD12FFA8272727F827FF7D527D527D27 %527D7D27527D52527D7D52277D7D522752FD33FF668B66AFAFFF8AFFAFAF %8AFD07AF8AAFAFAF8AAFAFAF8BAFAFFD13FFF8F8F8277DFF7D7D7DFD0452 %FD057D527D7D7D52527D7D527D52FD32FFAFAF608BAFFFFFFFAEFFAFAFAF %FFAFFFFFFFAFFFAFFFAFFFAE8B8AFFAEFD14FFA827F852FFFFFF7DFD04A8 %FF7DFFFFFFA8A8A8FFA8A8A85227A8A8A8FD4BFFAFFD19FFA8FD15FFA8FD %FCFFFDFCFFFDFCFFFDFCFFFDFCFFFD59FFAFAFFD2EFFA87DFD4DFFAF8AAF %AFFD2CFF7D277D52FD4BFFAF8AAF60AFFD2BFFA8527D5227A8FD4AFF66FF %8A8B8BFD2BFF277D7D2727FD4AFFAE8B608B60AFFD2BFF27F8F82752FD4B %FF8A8B66AFFD2CFF52F8F852A8FD4CFF84AFFD2EFF7D52A8FDFCFFFDFCFF %FDFCFFFDFCFFFDFCFFFDFCFFFDE6FFAF60AFFD7DFF668B608BAFFD79FFAF %608BFFAF60678AFD77FFAF66AFFD04FFAF8B8AFD75FFAF606684FD05FF8A %66AFFD73FFAF60AFAF8B60AFFFFFAF8B8AFD73FFAF608BAFFFAF8B608B84 %8A60AFFD73FF668BFD06FF668B8AAF8BFD72FF848B608BAFFD04FF8B8A8B %84AFFD72FFAF848B668BAEFFFF8B60AF8B8B8AFD72FF848A608A8466608A %608A848B848BAFFD71FFAF608B848B848B8A8B84AF8A8B8AFD72FF846060 %8A6084608A608A848B608AFD72FFAF6084608A608A608A60AF608BFD73FF %84605F605F8460605F6084FD76FFA8605F8A6060608A60AFFD77FFAF8435 %605F605F60A8FD79FFAF5F605F60A8FD7CFFA8FD3EFFFF %%EndData endstream endobj 42 0 obj <>stream +5{ǀ(tFB: Op'80孄#, w>#4(S$BT*F%NG:s .*⋆;@҃(z7 X$2&FZp/:N]tP7F R xrfm+ 6bqR2rg9 +T3 + lbF_51`ѐEƈs4kiWBTeTm i(&?%K=#A\ iǨ1eqS$"pH8n7B\XGSGlIVDvɨQN:Y.vux똻*4 +G;cUBxlfp_vTFH1ƚ^,&n8oj(t:YAij"du.G@Wpf{c!m̈y0%eUcWI9Dg8u;Z '|ԺWn8= &j`S!3%1EdfX)!bݒ@6GpaS!+DQ 9 JH<5k2/ӷ7dy&x&z=BhX{ +.dR0: WiQ2EgS/,4&v !N,bNUS>߆Ű z^Lsb,* +BY'ѮxqYo4Cݑ6*[/꼩~*=F j%l6X9+zud@&'6Dΐ!*42$A@]fNm(S n2M3^ +fƸFtY +1Y;&#-~4yx][qZJZPݞQQt :]E6Sl +jCg2 aEQ +7$`S8*>DVHD-qWBZI֬i91B DR#6 M3LbA*1hﳃq<8\|N~ƖaFBVrN|@la +O Z2fP0*{=&P+o#cGbQXpV 5j +A<`}8o,2Ǒ/P+ +u.XH)tGA<]ci@aPElm +1UjZS+yEQa(4xH\dHfKVibF,IN!m6˝ +*/cл #чQ25t6ąYL&sfT8^tM\Y},Q6{.4' +I4\Dba-EBP nׯ.nZtc*e8Tv1v0 y?{]I$ jwg 9 +FMIH(qIcN6;=C0ҍI$#;N!7Ln +_6Muɋ~" .Jq,4jzbR>pw a;=If&2+*zj3]ipț1#ϒFgss%rKšvQr_qEzȉre\g#_tdO4zؗ3v AG&0LkTM`~\Ck7oR|%alcbH7f0&f*0.L?1s`#Ff&X Izrq:3L; +c}(R@E&7%VS/ǩMQxФ E9yˤp縲P>BT?95wqFJPы%V#)!YUN\6]~a@:E%7y 18*Sj2 !cD6P2&u'tt=#Í'1 y>j HfP5}^(r͚zEĺ9mS#P= /ha:a콥UE˩Anv{Fk%CPqvj͑HP 3bNr@'=]vQ&<SPM=?-^EYxgGacl4)0j9,;UndYet}4͐DZ#(K= ~ _\\A$+vX['t rh{2. " 4Q9 ^W)2M#*`.vvFmu#*Zjz{E߀J +bHg"@$SXQ/Q "Ko=+ MBv)~6Z:ઇH\Gw!A(6wyMzJE+ϱb|D O pOf+:`A "Dw'D@V覜%[9x.6v* >fijZp4i#}&fx!=%UN$Q'YrhbV| ʠ4ќT~AwH P9/JI$*+:Jō qw4(r!&ztbzACB5>ߥ3%g]ZU S9xU hjh'7Ц1t\b +2LW>ܚ:KqQ0u-'1D,j$H +c#}'u0Qjv0KL N6DyBftJL@Z[4] WLXvip(׃ϊBR +j$NJYܘ*ϓqsؒ2 +є 5zUz\j֌LFtA +?r1S1Vܗ.JO?0,[Li:xv̆'U>@cXȆ;e'w*a=bzӴ2%MF>;,0)!pk:U6 =a,5x+O| P=t˧{.}6`u֫jbBIi?xH +U'ީd?Zooˢ U6Xӫ֛ba@:V;$H(\h s #p|t{%T_hAlzͣoe=ZLN HThܴ=FP {|󖑜E zNVQp[?LHK +p[5:h6r9/QKħZ-tD!-"wyd2_u@F$=_ta 76Dv*+c;-鶍i d"Rіϔ? +\q^>V5w.)q CSV#n›_Vcd_x/3;4V%S&LH?k'C 6dvB'syM;߼]7o|s/)Gr'}qz{ +}V7-Ywڿ>[xr}v+:ūjgM:Dt]@TZZNU6WdE[B TMC^!SU|x0kmus\r R֤ZckNx RW+c ^Sx` +lfNvs2`+G{RD>@)sDCTW5%@ cE&9 uU@y$ZyWhiN a_gb$|i4 oy8<1jVt p CVvTkI[1\t^H \AHd2 +eEB^jBJE|뤫8J#\(Ľ-풲dzlt׽Wشz&h +~XoDh ҪYHڐS[@-ϗ r7,GzgnZ+nLF~8Eo:O +X<4\#kjT h]1^^t5bkf'-DfyHk-Brg&ˍmk)$VL|j_C5̎%Eg=X%~=~ӋV]]z$ fB'?CTRq{&0ajyӽ)VZ75 Moǰ~XϛtsAwz6woۛV>z/oOqwkqg׏.WO*,K,ayކoL`o&|àg8`QXY\%"'IK:`w-Co"J{ v"?b+F:aF#Z؝ ɥ !_{;BԘ͊k[S 'OąB ޅ:F.73 L{-R+6apVB򴶊5!.OP^Z +H%;d!j#%z-DbTƱ,g]Hol6sv` GF ( JY֎t%dkE4 &; +DM&x"k7PXlb }Z&X(ga8,WXUb2! ,ulEDn 뮠؆gSSJfY;c QEEtwZqa@Z^CON3RvQ$WN1@9aNJjTZ:Z4QӼZYTEglK);5;YY*y%dh֚Q"5.}MiR &z6n"qd=$iuhoٮа)5yshopV𔵞%M) V@*uD"fKi%@ KqZei’f=G<;&'s6eyG#6F>|KtiPA)VyXO1c-amPc 8Q?|zɎm>9;M]8u*'ts~}g_ߛ cNض'jձuv*~J_aL_zpP %m Md }SP5!Su5i q|? ? ŠL7ڏO^HG^/Zu;Y2u^NDƀjdtaA7 +naʘUC̣aL}]:Ñ/y` GՈN.6Pޱ}˨ 8tzGUg"4oy`BtGՕEr0ӷBjl(ի@lF/WP!u f %cйvPj_FQE#!&<"^P|b.Ҽ}nϠI"@_"o9"n]*4mDAmDx#ٔ=!E2$O=s W7e ۃ<;[34AP sLH cz' +1 0+z3(*u(mi +XѪѱi3 +hP8\@G%$t@Gt#H- +cKt^ h1u匧iOV\8*B>D5@nHZaiy;}dq1IRzd2Z5E2d]O9v%JF4}l_ֲ~PK]3(a!*ׅ3쓤Hn*;D[݆,A4[#0jG}O]& "rԣSci%#AgX\3C +"vyM(SWy6=i0'VȐȒ#7uC!@F$/ynJPJ%02/<,.1BBlQrL&[B<9'{ ެH<H^R,_?Pz9)wV"˖-+]Ij@}`^ଛ,E! o׺Gsޫ!0&ɛ*&4ֱo +Y3ٚH! f`նIiM'yRjdž +btz6I`J^ץc+i b>ż +)ӝai-=;bk4#ܸTrM4~o2:HJ(Y)MSN +v+cTo +6=)f.FH)lZ` t6Z֞'5Gu^}8Dl^'8L*c\p1ڊXl0ʆG=EcI$nJ ;:IҒٱ P,I *u ̔HPӑ'*v W6@pO ݒUDsY +WS *֤K8܈<]Cl*^bI`{:6blY獌P%Ţ S;Ge eʠXvU`cӍIMz1/Ee|.Qyj;|§A Xt)G.E +.E4.`h@. Mr0.Gf*-iPjOH͔t6 U|݊%({ N}@zbr݋֬K{ht&K4݋I`r/b*]*+J/]7>/1]Dau:]g2mɻNwi';{M'ar%o ?N۟""t`uq6`̠p0`N!KŘ`/F.Ao4AN /ӆ +Җ&d b9sLʎj[&őq:޻lCda:V#C:ߤEW>\&]t//^,@{1^ ё^ Qvx:EmEaAJ"yVP&܌ WfT&:tj|zKj䐡]Ʌ,g#* ZwJ 9$V(d@P!pWU4qj/-@efӘ%_Lek8(fxgb=I~. 0Vj7鍍|'`"O&K" +vMuwڝiTωɦj) + +.Q߬RՀ U S %$tL*HYL&(m9 Fѯfr};pXU+Ɨ"E/pʮ5%kue9VrYePRdkV7Hm2=K*!+1}t.FPNNw:ZA +JC zz:bd[ P)EC>i&ַ$@NS9i6I^h!5Mb%0 yCږFă +J~&U *0*{S":Ϻ(񘅃d<ΧBR'Gm`p擖7dA ϶zJn)V; w+HX)JDy,֎Z 4J xV + +׼+V=d`6*ğza% +KޜN7%a]ys,6dZb$&4d=BGc\ ŘojDf ]'WMhA+AY"c; 9+-7r)E,S6Bd+.`E eKջ{<{R.$\'#`670qCڰ@.Wm9 P>,(AYecʹfE۸͎e"BhfpLr:,>Kġf"K%J 4ᦠ[XISP7{H%fOXl b3: 0@29w&"wzchK( )M&k>@>lֱMKMyx]攮!6!H [2k +qP +?x-y ćd`r^ԡK˖WDdP20ߍ^:iM$W­Zn'- 9I!]uQ .AU4 +Pӣڈ·޴UqѩыsԠLzhVx`)Q<Ŏ#~'濺cT d sb& 1-@Qյ#T;12\׊IiTlM#hь..3ZViy$ 2&"U[ Ȧ?VՃBpTH5Z(8+Ǽ_RIQrx #];8.wZ <.xN6Š(%0#iKR[ᢱزdi*6A@p z:[NKfdjb&%A\1k.a#gkkӌ֤kvMOsK+`ge].X2u kt?D+ՙU6UzwפfBxg~06I!%:/Q/XҲwyS#kWUM#:t(JcmŖ,QHq-׼P1ց(C{\oq}My_|uY-` džid &=6lac$dž =4ad "{lD0aCd Ƒ=P>RF#{l_8 E0aCd Ƒ=tlF0acÆȞuu\qdCK(džId 6D0acÆ&=6L"{l3N#{lDذ!džId 7DX?~c'=O"{(e)Id-+'=O"{ٓMnH-?~c$IdOeįuٓMidǑ=o~c$5Id&g0v =O"{DX!Idu6D S?Ȟ\Sd'=oac$dž =6L"{lDذ!džId 6D0acë#{(TYdVγ<4 @򭟘 cd`S1&7  CA L 80 nVj2 EbPLMM: kL$`d@ .0Ni2H` l l l`2pd2 h  x*&&& +qCd@gE @e@ab2k&ol24&Nvh2,J  %N&V$AedPll2$Pa2D4dML U8$ab2M&l0X41p&dT`y +cd0@4My&I}F&zS@O%hb2(֮d0؇blcAS%:1pb2Hl2[6(L տ,jVZdAiJθ +p%4%M.4._)_"9jL_QSg@q~ޛ6c!0‘6. l>F(lMyiҬ+AN)>,:TZOHdpq|]rl>(>;l2D|4AvB2M(_8!20$wq|I`!N`l]Uߍm0l>PLփlqz Azb8{}QǨqz ֧փslN+uJAw H_lVqdAh˺wS۱nxA0d"t&+iLe5sSVfX.f2{Pvsѷ(bW.\eK-`侯b ,b66eBPMVG[=Q/)hlRM]@Eteڤ;sCZtɗ3B]\#'+MĎ"Ҥ5*+5oǔ4}Ȕ%2 )RGcJ0v\i+eXEQ,c+K (eg![`Psؔ%|lGkP\m쟦]Ͱ]dѩϔR堚]$rUڌ/ v +Hޏ("VK—W'l!@ Q/)&?@dt!|9 9Tv"+MGVG%GVR'M̠2& /uYi"HH7G +V[+T!Ǿг 4&6(Kl 6%WTf`42"ސ1u]2PۨsȪvq +ikq3J< [/R% 3J Ob'@+>h;H'a !GRI2~9Q .91l.tG:Sg:yT8~a4@v0lG0_&)kdSXE ұk%ֲ ɗ&o]F2+*3τ$AG*)9!uHbeo1}j:]r?592PkCD1GH{c ] T;`n®4,5Ae,IҲ#YO(Sԟg YͰLS־Uj%݂(7G|iѬ32MA3Q!cJ9POƔ'a>E/J +3Dvڎx`y9~c CrGط[u;tdTA EKM2(U+Afl"f;8Lq^ĮeʒES.E'ƀm]r y_ǨLOJj藒zR`rircB\b48P."&aWpw"F9=D&tPӡk}z6hh" +0$iibLHaE,*[i آm(XJJ +cf*P4m8ˇm^S]L&P]=fNc0-$+D@E~<ѫlT5UyŻB4q,jr%ڗ)JsN vP[F}*$_1E?]:[2͠2א|WI`D]#e{nʯ>=O=c31ZN  fk= gqT*.?L<K[e{LYU-+pᄀoEP2]S.77B~&[_ 'P*>r:ӫțfy{^ hd +8@bɆ7țbߌUF\*j]ypyn`gywN~rt `R}Luؚ (2ӈlZ4K;蕞KdMd%pm8I.p_y_Dښl+NDp3UF !+Iot7۽?ɚɺ{ m9ǿ9~CM;*|rW2?~t~/V~ _b}t}vo/>:bVOnyv}sUNO??_녦k]*#`TkVUӋOOoo;_^_}Ǜ'5NW`Ej<ޏz~}sۏ[#V||DgϿ7dWW67+=Aɿ_P/aQ;|_տ[z"/!w$ɶWKs)QmbY- c4=cS1D`CӰێ@>j­[K6p JE؈(DC+ \A %G7t]򿌨aUe'#u"LmC":ǚWG.-z:~9FS >jA.$[ż๬4ԠKPJ]5ѴW$p +ݡj]bu|V]@:J +96xt 95KwTc.N5ɚjWTmYVnc,OS.-" ߷솋*X']wr9;[#x%ޢm#SrXe "3x_a(]IǾ[!E61QdAr x_>=b4d[u1˘M]T{$M!diѷ[yPK'V2\pcԲ, S罍`-Bd}J|觋3-i59ͧ>e 5|px3PO2Ա}5j1BKm3&~9NMCx թQ) g?4^3ùYN%2uqqabӒghLc҅n#}G+XVMޏRjk܂ nm%"\Y %#*({0[̑٘fZ@fL{Z ڲW!V  O!w4~EQC@Zz@,=T*dԅFUf5 զO5hi蠍^lxoN7>V-NHW%*&X׀,&clpޤ5kWgS#lod1V/쁰R8,_vq!% +D4Ԭb%~6xhHұ}sf]! +zX^1S!Z^ eF2Zf"C PI=ҡ9Z;.4c5D}IfF<H-bb:R +%;nfGB4|yX |bYyFcV6%  MIL ,HWQ?fBP!D7!{A Uw:4 \JoA.sbH j?9Z(װQ!hUjyLmנ ^LD(=!"G!VG<}zqúJ+M@Ƀ)nYZ{B{QKskv b{gdc@:Qo?N{ڀ"jQAc#I`lJ(8q8G 6Ʉٝp[խ$D8;3;kVJ]B I +D󏴙ViW@ MڬJEr9Q"*ABq(E2LX  TX1;U+E56 d OS fHnMY4xb/JBJߐ|OgɫuXw3VQ$h"UpA섔D ]*C(PR"ACb#>2@#rO(ĦNrGKRnT5B^H(47*VCbCwE1'9HP6Ip@dtnW $c&RqBNS6/*4)QnQA"\'-@E' +e{ +J.[ +ñ2CRӉ'j0"5I4$aL LNI'mI. HSNoDRL$c`w$Aƈl<=J+/Ql cbBL6 ˘M|2 eWƉQ1KF$SΩjGS+*m#KЈ#)ʵMXO@[8-跞ԩG1CY ɒ,SE$ƲfKO9jyoNC$f*&'A&L0GlA +{Ej̒$1޼üx 4$KLrZZjN h|b$40#*j*isVi 8Vo1 HKRl(MA +t'd$szhڐd00Q5YW AB9B6emUʴB3#װby, +$*@ S xWԺ# mC(8GS$%E ,b*a2%9iI*7cC$!ҴOYVM]Sh6duL *jLhQ!`уFc2C%sC3E:Hx-!j5_p$Ce5=:j2Z^IaWlp*Ё 1P|U +?5<#A@SDOqh-S#R ñZMɊ=x5~DKT`DMeULƣL 0 +zT8+Y$J_v'A1iAM+yT,TI@_6z34RrEHӲSO'RMP++4e+Jd$9-F)f,C;fI*ɪ)b &a{rhcs'DKX6 Gs@GI:ZW5VVH\Ҋ>8Su&By$Zbf6D¤5ISr% + GL92|CBkx]Yj?V˨q;VP4!)Do+ +ԴMNA!ShV#P!f:>FCRJ^pĜDL$ DT74b^i ?{% +>d)SIC +&`GbRR&!U![L<|i:z^UA*TaTn{S̩Ijx!"$9TQ!cXCD+1ɍBW"99<BRud 0$^M:$p*0] b"HuENm$_2abEI]JQ'i-=bR-+jt2,ѻc4* qeh+Zj$L`Up:uѲQÿBbƨr D ScjVPwKD05јDDx dU9K'G2)Rh,%'%9)BGCچd_)Ktg^(jtD H!$U)J(4 !9*.HɥZ:HP 1+!M$@kVPHAe": V ńo`Bq9hv2D6[ + +j&5=²惊 z䬢&lx?,ku;j`4JT#U v,#fRm‹HThtiR2jDDk= 0PHh7 +w DN"=jE.X;ANbARisTX"UA`II &z%&P 6nK(si?[d"uAP$o4$ +&@ yD%Z©dt@ Cw 1BƟ7G51LZ0OtOgbRm8i`6P.MjR̀ȘI:()ti'D\} IԍQUϢt?3u@F@-fC`F@$BT_KNVM4W95q?I(׃ 7 ^!E +Z'ђZ6<^M:I7IO(h]z$s?wPD@~!$G%jyn/ +̈́%~N"eEtDMD)f z"WcTDwMRƍ aH +,. ?ސh:+͊U U 9WM,"Hh:iXr #aDC ZdFZ,C8B4 L'3\-FoIc\ᑻ+jEiO:tP PZDQS/4(9D\'!J51OPe ^IUVdLF(d5CUJx6k<:o?$)9(j{^ + bej +%?A5pq4Xë|H7xg+XM̖Ib~ҥL- +-\:viC/tr R(SD@3yRE*#ɂ2Gv ,"2rJCze(Ky|k>LmN-8h{`[3Ew}ƑcZw @y4vX)iP™{oy'Ysov0X>&>雋=|Tt[3Ѡ<-wʟ~_ej5?^YU[``2ƃW`,~zam{ rkb{ڷ)£}UNt?GՆCk@s2JQWr+ Т(HoTw knOkS_Nۉh0Nqʂ! ƴ@ +2A{8$_ `-Ӈݪ/Ookh|C! ʝJA7ռ &7N]DPLJ%$d ACd6 +}dzg>$;u1#NxD 2Y4ȟԵ*-!z (&$n&xxr{2Aj@S5~>Сa]? hG.ȃ5|Ip xPs9gA@U9f\p(AB.eb0fǸds]aܠr܉A[f$ V5X^# #($+;?ض+0Ja5"N/@(NU X: SARs8nG;&sp N zg!Lu!6.OGz.}NתMy miAWtf,9T󛚗ie ];A€й{8F$@-F4 xMYZ3)Ld}9 ~)0D5m;-, N@ w:9['0* ru|4Ev!@IWH*=GV$3 򼀑yJ`*B+egD#T󷖍4b[2|S-FhX/JԤ؂6;$$?(4roY 3ҙu%Lͣtzj+f.H"y41)+@n`K5?3xZ|/Jn -Ԭ+\4FB梋S5E],,]j1F) ?_a&UX,W`sn/x(׺aitg/ ^  +LK|0(ԮWtm?h&1TWJS3U/+?-7`Pm-klt\M҂ZTZhP>ɨQ+r;_IG(\T1`RqO0fQEQ_ ٌ,^n:SG>Fr~V(cjwm ysАqF@%X9xI UoցZ{AeYf{&:vkiNs~ve_֭mYjgwXCm'T'_7]7BFg:zI/|~3 ̑b 瓴bfo!ǿwQ7kD%qdVRba֍S&),l1L-qTzt9oK 㯣-hMV%oL7K"_" o&(]g"X$ "A1?rϨ[ARbm5˟e_Hu֠hΩ).2/b|V\K P"+<+q2qނe! ~Ǵ`55KFi)Ћ71\ 1$WT & ?s:QmVvJ?DHgˬpw6L3J2ɜߕnwgRcCH&9-)kr<l!%|hyA> &$7o$@TL~K d$b0wA ~iԫLf¢mNyY38l-qϒCGmd Gዉ]7۽N\6ut(\@AR;5#,GrQ XILrˢ,Xk^,ݣNh&Kw."O/Q5:}r SaS Av38NQIrr!pDВ`˒IXT)YȢ(,ËcRNw@Ma'&%DE h2Xže`x. wSJ2IQHҲI,&I"1BLD3V$ó25d"+07 J"9XHyyQPH~ ,68~)2'% k =c` ,I:/H2?Yp> +#XeUH_8Kr0XVJb絑9t7.2N4OИI5Q3Z} 1aI̒e+Z(`~Z `a ?!+X7vS9C#|Xr{|9l|E@4+n(z)B|[a<,cY7ca[;Fnuu T~2jW~bZUV_6Z-3kDV;?)Hk.@3X~CSivjTpd[okt;nS6խ~k~֦\ϹzsŘ ĝ'?|ulc1.: :<Q_B/:sq{6S_8_| (LwM +)\ +:ڣfu[~vϿǒQDTdrҲ yea8h2J2Nܬ5k$ĕ ՁAfLFC5UCN~TK?Ko x r_=v}X4<9\S ~X-KdU׮P]DVʭzoٿ-u{/>ԮC9WBg~̠J\Pdj8C FFI9BE79y6:A†gZϴ9T4ݘnT$/j#ʵYD/k< Gn</0; 5xuYexƨ] vjÿ:3|V`ޮaun?j *AOp>E?}2V~#s+W $Jjώvgr&V 4< ]\쎆f[zuGc3l`e"X>ΘNw0j4US[g|z=> >9;(K`k}*o +@Q|A=@i &qUԉBY"]3W:~o=N@'xUf"l@cY(r]4;دT,% ^oOċ $9 (' [#Ʌ$=(ԇq]$cּ6:I8lRo%,#f9AN~s2ז̲% +ǙfJ<'&rz|L$⌠r=p3?Sj(gOIY;SR18q=ZW9d1. +䴻2xiZY-otݡydVLr'e h-P8`E7npf$ַW;?uub}mfCKhɺ7A$t{XD5VrA=j mc> c~Z VM%}w.Kv]Z^h{a0_kΡ6yקyro#"m&1MxaEx75IwhM4GJFB+9wRN%3\2_jo +xa}:'>$WtSCؑjӸ}:lCUUNU5=Yp `/@xod }{y%&$'u)fU(ak=ux[72Y!/acٌ9j 2[{V v.;#'.W#zGXL4fCM&[GJAIf5ƫƅҶw}.|N&z |M7d +r lhk^rdЩ<-Wx+4+xb]Scz#T?@.3)MKrg˶6]R}QgdaS0yMrB"N&7{jkwTpmJm4YmEJd=2._#0l+?~vN0ԡ^;N/ n0_yZ1^h$xhjr˼t_S츩]p̺S e}]Lx2Ov;]wL`O/h]}^\L 1 FNKkLWyعu›{V2_S}.6, 3'0ʎ.Fn3<*DCRZKg﫹rxW~=YU@BbER>˧t)b4{3l +V +Q龳Dh<<6:3>^yu.#<`_0صWZuR.(>^}]R.ʡ4-usw ~򙋆oC.Wϳ8g˟05,|lH!mKF.߸$K_qBjB9ܗCQ-v8}Iك[X ;;HI!-dKe9߾^V2rT<%;헫% _\n 6A*>a/~[ي0\NmKሌB:c#WI^aGegUm|gd-װaiSxNi}o*Ɣ1#aQ8g0Q#_`<JO>riuFy▖ڥ?1{_1QymzzJV^)xA|d8}ݓt;꯿;0u`n~Tʹ˻tq+>}dZF%``N>U~whi*i1G8\RuFJ>2l-Gj8G + d +L@- +0W&ӖYm_&!͞Nt5@& +Jv61u:v&%/^%GJ<6HW[4Pqbo o۸dD4ex6,\ľ X%؊gu(}4Gsgrv-dG z?3eϼWy_ KYn`jwBLUNwO/[D贩8v*-=ol9Bt2A-s|l3bEF㶩`'먿|7+[ ikl[ޢZ.q뺂]x;δYF>)*VN&pһڃ1UU/DmX-6c3ƴ T w=28 + b%ݝ+GvOv_meuԉ˳[< tW{T`NzVqp^F^mf=fz93}dQa7o!ADؤ.W@hy Œ OJuX"{u暹N" hL&ELWdܗA3u_$ J艹T M*q;WFbuq-$N HR!c:/R#=Szъڌ* Ö(K qv :r +锂Yc&Ic(}qxjD7&@9YH~ڀ\S?պ +^JSri'Vt[99t#N,iܗGqo!S-I;I{7٪*?&! }NtA~>{Ea]0fF-UZ*i+6J^jqop]xhUţX=ťGϻ՞r|;-MKiI/jnEU)iu/!-!{g;髏Ŏx(FvsIqigs~åchφ&N4^JZ+ w|kݝbo5fh VK[\y"ӊ}a0&keTx5r5ruנ^ +)fXN˱R#Z{Iw*ݣ#ӠW O(6`knoڇ0ڬo@ J@nY5=k1;g=dvJf +q:Lw&Vk^bL5}~|PƫgRP.urH +Jo܀{EV +y+c#ʂH0 F2"fAGRp(Mp-_- G$5Yxv`6鯥鏈Ɔ|z/*ͺnn.K\k5 }V}wNr9__M)Mn@V񳐾>^g/@ sǙJmTX:oϗP~nW= Io:%sheLh(elsgj+,kN +J}(w}X&̰fi E'Ǭ:Y+u9?c'^ZodzƷ$1R L>O.{_ WWO;0,ˑ<2)7nQܖJ4@PWԐ,J#Y skD ~5y,^;)s/8g+Ze?8A7G'ZצI٫Z0[3  v[wW:P}k$qG@6S AVA3{zV\<<<{֎6Jj<5y97Wc 5X8Sb^:ќ/-4Wc:K?Zg0o5m{d&$]y7yiċVؖ{3P}έ9 v_|[> >K#n lҝ v4dL+@5sgWbg[ɰޛQ1w9j%:~#zt:6y=6BB`zx d_?}@fb?V5]4g;^`֚=#M3kƬ~Xa{MjFBɡi +wnVw="i7Oд2!bh'1>sh^usDڶ1T}|z6ѱ[+i&0` g/tl?:xs;/xDE? -ΜFrAD^_(02 `Vn265^l17w7KA]Kea.sd4 =C݋:i/ucX# : ro0Hlء7p\uNnݨ ʃ}?v\qi8J͎:C35LT斠1hFh5P`dpUYUD1 ZNɤ8o/Tz~W(V9a 0Agu~2MslmB`0z/#">0\]P/Y<#[5Gk{\7j[+"c/R2~ Xȍ仴[I0~c_s/.ȋm~4>7zasÞؽ(%֮N(z6MxmCP9C e€ryY|ۏ$oz6v+QX;wBQcTMVQGW.7+Dt[.]P?QV0jdoJ0!2 {~2U|nta;з<+Vɾ㉁\/Yl9KAkr58I lTl΃";z> Kֺ1h l ;X< lDkyAҥ«/Z'Nke +ˠJu)|]Hb}bhg=z+9Zɠ^}}+n(8,tݾ}AwuWta[ifC+!nB0 + J1V4;#K"t=fO8_Aquؕ~\ࠌm~?]j{ :H~mf2nR^ +C&Z'upr}pɶo6x;FV]=XjK̾ԷoyTҽ{J/]ջFuM4Xu}{V?6Kʁ̀XQll45]MRw]}mjsx~V\~ /zoo̥v bޫ0#NػwXک\}Z=|^w}OVo%bry<`ښ"۶6߱ʃ{q=mU2J-|S[LwpF1nf6;R@*?q|Vm殲tuUF|%nm"ss,2@Mt"rg ֥UcGo9ܭD:-xBnK1,t\QyrTxxtkk%ñ +נ#2צAkƠDmE__ie4@WrePA5X:(x ҿ렁0 ^Jd +cPmd>$\X,16sqG)~ڔ`7`Ѻ*شU+uL9JD;4o6)Fk>ć@-_FI@Sea}k! +?;[׷ +QxO`ytƮg +]Te#S*>LyGpbܐ2ʑ78y[IJzP7|7P852 +`l7?*؎3b!Wv*=qiK/$PWlj6l2s1ӪUuhFN ' +ܽ 14{t&ws٦[^Y; svøsFwcW&sgΜ"p7򬏟r>u+K#Ͻ\f7oMitI1@#c7 5 ө8n_S2͋eXt^2p[docRԊ0[®ɇh4iiʖi09^zr:N;k0^) \y:?"L]Ӷ.{ +d~vžWh]QL뎏yՙL;/W[ffnn1+Er^=])ýұs 7BIv>t2291`yXZ|貥:{-O4#8 6x^&o[ųMDL&b-gɄcoՑ7\X饤H^ɠ "Ũ`Cq$.[J-Ƚ l/84_}}}k>@t0ٞa [!^-rC62( /~7V^]%<`G|( ?"Y6-GQl]]g!%MxdmUwQ'daif#K8kе$TFVg} M <%5oݏUn68gH{ѵI&O|O:NDkD،X%,qS] C8“vq\\Jcbv6QEsd0y)ڍA4u dyNSY.9Q>3=E]~hw۠LDINҀ v4hա"l^Y-Ay/`5N|JfY8CL-ӑY64 ]|Kti&>fsjr0'ڻB0.v>륻Omlj a}(]X!<#ߛt5[㻿k2.\T ;_qr1ܵMZ\ G7ٹAwE^] y!0?ssC /|QBܑ8ǎJ2X-tzw[{:Cg",$1i:w-K;s9η#פ|bR92=?Kv5 uH3\6o_XŸS2 G"f#4y1t:h)c#тyGY9b#,тsyGyD NCAGCN;nZ"tb::"M8${D]mwxH )9ZzsKl:ΰ9`k}Yt[g6f]: o'Qw|^ya[M>jzb)D>N\yM)d2UМ/Z=P rc ӛ݌$3ز>ݬ &Þk1nn6V-iR~}`yOgj:I ۢ,:`76gR?U.LSVxwʩBLI۩Ϩɺ=.[Mg rf&oofg*]Q`&I6Q7?E_eR˲h-J6&r +t߿>jEqI11^`N!7n>"Sl2:'&_AfebVGcC$?Yv;fGn/g¥%+Gv{ew}C5 oeϭ ]LJg*71&8 qldx1*EC{0gWdA)Ocꕇ5s>@nq;&ȍQ#7A;{*}Ngq{ KCJ˔,0)nǔy2wJ铃⼦diH",2G"3H+>,2߄𜕭<4E:xxwL6Ef,Zp~ ,2n,2v#9s0DdL羇:|l~~e~fc2x$ɀu,m+2Oڌfd֥)\'M4;J|yՙBG="'A=TNItջE|2:-1i1p8"|?6K<E{psYL塺x8Zy}9du = }x8{QxYgj9[<]sH#-'Dɖ~|"o|"'7?%G~6'~đB1"<<|'S4 s7;jٸxP8g:P8ѳP8}Yx(vK+ļu)9B9H0/ s*P8gOK04sdVy,u®,> ؙ{f)e$^.|^xeRQ&7]ؙfu`ŪqN{@J\7[n6kwO%k@ }達 =X:fl68"=[)'k,SjIjғ{ܙ|uaF/kvl|6 lwB];+حp)2^vimwA14=kkc`ك݄Ɖ^ +vcAnv8zv v{:k{GuK%AWOꍚ۠uz|Ϟ]on^Z#ȮUWMR|gmvԪ`i)4M*6w}k :#\jsԏ^uBD~ y[zg3m4\\40sF9eh:XY#ݣlΞDYYcsE9u5!C t3r)it^h:X:h:X:=SD9ڵ +싋s]b]h4pc]L4S,K9ƧXvfsNEG9ퟃ7Ԝt&)M\l4Mg~'h 6u4g¢cMh:ȃU{]D4݄EM/s!/*nR$bb\ͯ R_lMUƋTks |p-nlfW76!,^tNÍd@ 1 (` PpzvmJ~Ir֋IMUvkJΎNe]H&r1F l&6ղ +]ΔʧH>K;rǾb|sHA?(t7^z~xZ|hQD]Na ]ƾM(tw&a|c8tyH?3ͱB9O~camALIi&Hi۝̷H 6ǎVdFkiu|1 bZ}k&.'ɺ S+}_\Ø""=vTnEJ?ALk=^y?UN j YmCZb1ٸ{V1_H7UGJwyaqۂb\\SSM/TS{P)/1c|n>'Ǹ”|G={Ÿ ܈yjqwSWYtҘT^ZפM :1X?[/5SfS%C'`_J p#Ӽ5?O&Z#&q,eLnWS~hYf(y:sPcV+raz0\SYoi9&7VYffO6ّz|Vǵ[O/~Z۽w.leټ#Rs`-VO-S2꫷զS;e(PNs+PI%'q^+N ƎUflR5{tGg62&_rNM3Ng…Cb3F-@W w(@1i3N7Xgi. +o Bl(@tc5m@]G) +eJc1J:U_Ey Y~IQISƌx ( …+G^dQ>_+)g*DI ^oPG 峮Ps3-mM4k]?~3rmrħ|f7Q3D\YoR$ׂ U uf]\2~3Tq 'Y9#ze5ߑgK'.~f2PyVug&i- }~޽u/T':k]?QT\2֪~]S0z]q ]O9y;\"Rgo9-uH$8ko~Aֽ{]oB99x|0۶>m]?oI3,I-~ˇ8$N:y7[fg][tNp|~4){øtǪшR^uE-u͝I7g]?q ]oz|3Eڨx]كMULUoܔllں~]6.6s]?oG'Mi~b]VMWQ \NUfSy T{w@ʑg]ߘ<;De |%]ϼ8ѵ.ӹ7s\X@, %8{|J5hFE]o{[آ43nov{8xjRX8dkIEgMdoܠrx:[amTӽ8էG֋ryk sy^es_pR>X==J|?<R2.T}8%O{fv}*5Jmr +Vk[ߏt~ޤp?Bwgk+|(?}ogvݔoCTRL!sa +#(^J?˯be<]葖D.Ο(KZW?xb9eVK|ɛ^PK@b=;^ONE+!׵Hy~|X[UN-jFifO8CI RY׈ѵ=]dMAsմ4 kNpQ {,IK^<֖RQ*1m]u@??Z|f05}U]F_IChNLbAo!ĉd|M1@DOiD9MBa׀=A6}XHܩ 098o-ml-,  f'XލQc,(n}vn +;y,jNa'_ s?au-mn>#v5mLK^M:^f.ކ18q}>UY [dSj8W06ۖncKaw5ï $樸zUs,O ~eİx_ +f>ym݇gP,zuL /^(ֹ|mT +UjAnD #iG6*4j)D j5t9&LKw% '%w ;R(om]-+=, 6f=.J%gl&qBNh:!ï{kJu/:ol{YKU%i޼~o[H Ńa=Ap)Tz_~suK_wo^JrxF,~oNVr'-d,Q>o1x<7m9n{~ZmtM~ =e;}}wwOo߽;~9+?OS ~~O8?Qۍ3m?{JG|v\ ?_?N[^ go|{;_ӽQ~ſ)?W79a#Ց1nWh3_Hn8][UN"7{E?}'ḾOk/_t7V+<?:=1ӍL^f})[Qsw o7ۤ!/Y/}>~kYɳ\{"W޾~,/UCY'[R/> ;onY{~dd^>o']o9M&(`&7|;WE7nd>c{~gHws^,RϸݍsE^vc;㬄M.e3s|7OBJ<`}˅vO)S{{?9l:ggLF3g!ۮO?c {kuzwx,o2Eç)ϬJ<ڡ|J8QvGі?tonɏv;%ű = >$O\vtqbn-I7^\3n󤊪79O-S:"lI̱'?'ßv[pC &:OJc/yo/M79{}T!\˯(};?=>ukO_Y~S/尼i }rq}jWO>WEC׏ʌ=x-hOt M#nL!O_S +1N֟~o_g=֫o:w_>|?~x֫y>|ϯ^$cgG\B=/YewǓr]?ݲo^3`?s{Y}4?)s?=V!֝ZԔ ?W\wG>nYs-jDT\מ5JR\ryke͵8ߗ5ע7ʚkQs#/˚kQSZԔ5Wgeib/5Wgm*k5NYsuV,9xpW~ ףGo|=b8{[w?;VFc^ot,*eZ^5pjiXjoR*9ULǺޫ8JߔLO]tO~#jom&po D[^z5s8h/9?[{뻛;;r;HUuh*,_TCi]{P[U;ZPv]uZX֩,G%Izzj?}TaQٲeC ϶1aIcTC%c]<7zn<vCST3 ?=w?MR3Lg{N`?c/ /jM3SqWWk{{l~OO pnR/ G/ٗG}ƽ3٨al{OK"~`>oܿo%g+k/!!׾y/\+G/7>}{_=k1R eAj*Gsv׿12͐AZW>wDݖл~CƢ0}|mPʗ?,̻GV:}YXblמzfFw?p_zoë񓯮G<1g#?^h?}R|v[ۼ"~R͜I>x㽾駏?4Hڍ/>+&~[+g??r>6|W_aX_FUcOo.Onjo8?b)~>x߾z|wݿ//_yT &\z?kTZ/+? [ӷ:+g*w)}bS%9'-vAjP1,Vŭ7SlI+^5`) (dn[ꊥ>ix(fje_n4beu2w _V~w_m+מzJ?y?w_s:ӅE/]Í].^}Szw_|?~7^ '~'u]Ǿ<ȏxxtrݑiWOIˡ!S)Fި w) rFGoG{T?4 cʯ3MZQ8z}Գ}J0{7Kx> 扁֐y&}ԪGS1 N軱ʽ;OCp=mZE*;%zЗDѾf5RQ> +:fMеf)I;KEОZ8+hic$nj!ҏA&="fUSuF;l _Ym+͈Q`y2ELNc#FQa*v~hEq\wN.ԐԸwgO#-գg{;rKWlL?owB@'Y iWؕ9IXˬ<`g Z5YB^#+irN_7|)]"V[n 'WҦJ@nүMtia>hμeVR:0rԶQNSe0Fܶ4-s=Oeߒ(+eZYWd-lGz1 #"tFyvVі.s +-J8oHܹVi]C+gr*/_m-'${9#$Y$"z #E'4G.$6}>;ٵOZ>iW㐦TԂs\"Ly-8R/"\'-82,2RI1i:\2>[hKdYgNoCCrL(؄7%0-9wy=:DBw$iY|apʦ 1Ϥ- l~ Ƀ [t3DA&yŸ>LHe3H^-`Ѽ]AX" +$M<ɸL7W(9:yoߟqh,T ܦb1Fi4tn>gS%;C+&CL5O8)B3ЪvBq8rɳk>R1&rqN5rrMɼ;Cل6Z$kGI(ZY%E -ؘ{m2JO&NB!`6~ .M㲣[2COqiWN֗^ѓ&HJ/ތ+Hú~%lho0(ɑ4q\#會+UiN皇vTYɶZVա&.wG1b)h8${K`<'&,3z9Bu-_9̭uG+W6])=}_bB)͠;15\pLڳ <]'4]4Fq1MN/8cܓOcʁ唆}C*cnXC愫CL%,Sm8Evqp tN7'4`7}cLLK)9%@ŠE,E.IiyKmJ'Jgv׆{ VmPFc? Ըz+;=˕]˜I{mo)JmUaeo;4v^-O :h:9AHbѩ@jTV>ܐSJ|0dj.YG-R%Ibyd6IMKKW=zM1kueId5b]ȰkFoXbtC7W^ nGro[fRoV|T,%.->scnZY TI n=GNVDJW2Iq}9kQxtƹAwA=3њ +̪drN.7B9IҭB< )" jRpw!% K6u4o{}phkj$9I[C}:i]3LwCX>?>]C +ETD?CP=x+bQMsa\ʯL\&բJLz~dQP|qMEx]/k''WsjrF($"ӟͩJ@9$ |A<` Ϡv̲]#{oC4<)=XdgeB`rP!V*7m14}9 WIEmu_.Mma9X޸m<VY嚀q ;Rcyo +k:ԛrXȹbXp|u*/jC=9܋jҬ3JZ:^4Ko +j> H`[XW8sXW]?u5eBKxQc]QQm\5F)B_^u%qIP7,^u5/%ƺeRܪlb]R8qZՆȶM>]855ǃ妦>Ք75 ēM>T;CQwS`)sbx'ɭ^1/sڙ嗅nB]= \>5Ukۜ5DHiaCȍdVX2 lժGUPWKR*Gvm+iM lη +5PM EJ8t5eH髐zvA:Ůt%q#^HWއtLx@2N.j)_dtA>)YayGNAf{r*@f5qo#o0s6jt5/C"~ $ yqHW@#'Wm!v#K +UѮ&z 98ѮԑwZįB"9vghWRrH +:~Ů5Ю +=V]Iwj1,\4X;WZ3بo]^\m:KB{Ok];;1E_]\е.՜HGT+π]m z +]l] <QbL|gJQfl +;LwC +z`Wkmfl]]\!F9If;T}˰a!; TDm5ђ$65 +mNr̻i]k[]c`aj=5svsRmavs5{4{oU9l`W +t)`W3uZ=tP뚇hɗYX <<~٬#֕$h`]a k%7ֵ=F)7!MisZMڐ +NmZMuQmMumMfumMz=Ե-6ԵZMZMtB^)䦁ttmMP妁t妞#ҵڈ*kcLZMZǂҵHF,X#fXBbS#]+T@Jljk-6 kMnƹȹd-̫pWCd3u +>ǡ sD's +JjPGRTz s=3h`̓ I! iT)UғQu_ҜGAxhpG[HW_(Fv@Wj֘tBzptZc}"uGhA;k؟ K@:gIY<CdQN*DЯ%c6ٮpA(FŻ`T2X ګ T]h{|8YOFp(k>9)8%IˎИck3PSSz莄MjjI.*PzMN:%:CqńGbߢiX l.V7ƶi`5r>L9jCb83c$y*&a4j{pcS^}#CM8)@<;>㼍ZX(!5HRbty3ל&RE~>m7(6e.ۣot@#()@!M(@%g#P33\3R7 +H]ȳv]ĻDiCr"`}[~"DMX-{LcA +r˵,x'sB ^\#w#szG1R!(xӥnj֡@JF#tNw+p9lY2i +j2 :#Y`nZMR%ڪ@S@aRE+f±NfCo/BSRqp>wN_pl̕ a*\2d@Ght iDlA2, ԓm`d 4בEI +\iЀÅCt?dF +Q~EjuZNsJN>p +t^i7 RN4HeOȅ+:78Ѓ["BKڅt&7 TtB!шI%h%}9z:@?"lJ0LA~$N>JoP`* tYqy4Y(6'ЕI˥o;SC3I⊶Nr0z ICNj#Hlɑ`]<#M4K`< wZEf@:'7ZQh9;Z%eI!MHa#9shAOH7!IRz!oЫA^rDcƑYkxɛ4b@ Kx tH[`#9piu }LI$8OIh+32 5umL4&[`-&GGgJ%`!ui7}79FrRͪA,``$Ҥ*߿'uC7g4eAaɑ +ruBgL&2ԤyR n$><%]jvPղ1'SW0˵4FR,:pN0]m^Zο%ūVa hQ f X ֠ck+QG\0?f/bZac.8QיZRO +Kh!js YpQ G {O[-oP}<l|ĠDU3֩8P0*TL +'VG0 2.H!`Uʅ$~W$=&c4ކkHrM-7> VCDCtJSoaŖYdz@ȅ ٩ƌ$e1ArY >_w2X@82YAxdTIS S٧񥛒̲V&+/ӌ (CUǚ .r7, +vUT<^#A}Rv{a&j\>o[Vhwt*)FZTtJ6DjxNP+' .p||lލ`eŇrg "wx٢,S6egȑzLeif''MIz"jMn^hMNUT4Dh›8*o[ZW}CWgW^i?:lpfXI!#-MMF v ]C"PrL,1Ё?#d`]$doȰg]E=FڱodbcLR!G4ih$*I2Q*WTvW.xE4h)r Z $)MdR,BeqC +'`"re@ֿ\Cn5K_`Z63HS$X`#e~yw,phmD,WG@!УprƑcgKVA6quE4!ܫL#IXѣ?0j,93bj ɨT)F@F4{ ~d/`5,@0ŭYU(b :|Q:|ZIFV(#t@ޙ~6Qc6_j :MЕȶ`hΰe;Y c2u}WGsu^ۘ `+zZrGbEeQr 6ERjs\fFKi u0Ս{#*\;4@@Yf`"[I%_!@o2֦dfŋ dCH\pP  ԟ"ѣ ;ɚ1`Y]iP֯l&\nB:}7s*`L94A*n_9ˀKgdLh]&UtO3&2V3=4IPȂp1ks q< 9 9O*q3Ϥ#~˛|q:/mDРd)uwZs +8[فtpIS|2`0̐8z` +`0Y EfL}#Js6.u5+ #R4+p9eOMf1}onoDDJ:.vHkC" tr+QB`@ (ck.w_|𫋯⫿=G=ÚXo}M+Ǔp`%gi1'Oe2esݔ\\")ɲ!Q%aM|{͑23*;ݹ 1k* }G bkpˢuv!xq#M-|Ћ(8$2 =gq.+h&Z*W{N?4Ȧ(vn߾޵iIHW˂0_B4E2d`gtN8<,P2쉟'w6?SsujagoyA{p|`l^.\8 *8Ǟ ݑw Ay~F{q *];Bߑ9$<cm^=u=h0\[F }JcHtn':FqqcȠO')oc4mh</n0yNP9ci\PrgawkC>.`H;3AFx֋踶"%=fQIK:<.d^9 +pLX/bߑM7iI`@(izQQI_u`jq$zmI2BWB8yGMۺm=74{jޱaZ z2$iݳ Ӻ'Ջt˦uO;e{9;۽vGNb 1ufl ,;N,F%evX->ŕ'?=oK<$ 8hG=A<cmǞ|5cϾ۔ dV%;ݾ-;ؖؒnjc36{ݦ|rCC>QMrnߒn[>tmcG{&4qVhvȭ"mfIlGZcu-ؑƖxHvψǎdwXcsY;r]o暻bC8j4.-֞WwI 8iuF&fӖ=nM}slϩT;J]5f˨-Qqu-6Sۮ8*M}gm#{6ݩoHpQsU?Lptw -M[6Դ[ܡsC1R`{ۖ~C~Ȗ5fggnh=en sM=m{ܖgm/zvمRQYXdh(X;ܐEmB=Wo+wSx@J|m3][\$$B?--Qn$'+_r-p^xixrI֋Y4qIx< Ǟ%)H70IˆnIr9o5];I'8"l]NNGΚr9(i g>̱2l%1ǵ)-Gyn1[zܜ rS(8b'4}eqn)zqbԝ#rzGz۷ vku\OriSIf.miqqLjvNJLHq-'n.Y%Ovvy#njUvUƹGPj%n*b?2dڑyD,K!O qIpCY`pSE5_Jm!= /

H4 -=4m>%Z֗EYyoD +Ӥ)(4{[q ],-U_g{z0m{xg;KS.gn6d#l&S;#7%'%ޱiuqӎ/*pRE΍ $і`e<1mpnmvMߘvnڎ.cr㌩50sJen*;r۱TvԶM=Tv̶CClymLV +cGkێ7TmwCj;ee ns>POٗqڮZŬxQWt0);;FJ*{æVsa+e{/[;*36Q芯%M}'.vD˻ß,lylu}}mFpVE@qv$u:_S]9ljrONI"9r3k&Or9]yfVk1d7Kwȃ%k}KQ-/q\N⎶6 kmV#-'qYvw$kcI֞w|CKj +}GW{Fj[^↫٣Q՞wTg66v`ZoyjCShjSЏ" +ޗ qj'U@?ޅ2# +u|!6nN2<4ؤi!:q6=P~ydA{FEk5gMfV|bOc,C721?:Ikxhr84? @BJǓY S"*F8C\3 I]3:$7D$4e%_ȳv-:a Fs葕I@5S~$" +/ )M k$#{[8,EGS)z2C&+ml-3c^ $h./)tcbVFr*gӆK^<dcp;Hxh meDr"ܞyPqV ACʢpq=y;ҳf]\AkRty6VkЍ'X +?SS /\:ܗ uUAAaKeslj؄ߛ͹gF 1S#N$y +qLy(zo~L:PhZG:7pa  +1XBR%+eFÇEm\3%D_=v2kDA<|QyNCx9GkC~֤6{VakS֚k?#bX*WD>]t:D6+PZ 4i!A%8$_Y5O*sqR^Yhc.1}/~Zc#Z1@RK͏x %# |P@S}1<֚nwtCs%-=ca6 7QI|:=:d;BY|cQ=j, )p^IA.E(/~V&Cּ+dh@%`X4AKbhkӮ8G10ViHL5%1ie#ߔzh#CӖ6r*'p8gWՀ\.;m* -H;bK`Pg/ZÈZMSrq Hph vk:@ kGjq 0A 2yC\}% zF^5K$$ y}Ht8΄ګdS2tSxMѵmL0Tw Xh٘jD[biC!#g<c'pظ+bpAVUS8 &$SHcW ֲ U$m hLsZ vķ\2@& sE3t}IaΞS$ʗV&eɽKQ9¶s鑋m7ߚ\jf%uh˱Z@ԊɊ,ta1>Y,Jd݁TuZ@9IFPKM2) 9g 9U91'- K֘8uZ{Zg$F1Gl lKndVge)=gܰs=3_0C&ZfIGZg۱'P245BdOVByÌK 9W5eӳDl|k>sW襻6_<{%Z?i.Y1U endstream endobj 43 0 obj <>stream +7;UBff" ULjR y_ NŢ[M!@Zѕ=F/CyЃ9aBAADb'>r:r]7f1qɂZW;E +t-O0j9!t8;fF6\!i;%tM(U0:!"p46~ +KHtzE\Jkꬭm:oqWh:mHqk mb;4@mh.5 h%k#tsM_ƝPwQBGX;jϴL9]No> e 6OSxcRժoe0-1F4$fc](emYq@e+hv, v)ג'q"Q Yft- 2cPD Wk${P!WѴgG/R @a ٝ0FH]=6XY0nE;@Of owv /4hɖEu,7̒^_gl5 HCv:rl Բ#uHZfF]<>A%3v0 ,89**Qk1 @Gtt< ?j̴&1"WOr{Ų=P肫2?J21e>`GLH}U#X{kyE9hU +͛*z7c\~2xC6܌dw1=fi8,ٛ!AG[;MC9^b{=+k$je qbqX9tysNvbNr-C6̔]>4'^a!/YKrCfA@dG5 k$fЁdt%b@F`Cn}R9V"iUEpDřˋGC`5X0R;4 !\Sa<W&М*bXmQ00yhIK4R*҈..ꍎn j[ #* +9oak@/W$) FpPLd= DyI;Jk|}5|fh䪼Ē!S­>meFdAz=B0OZ1bsMtv *ۑr2 COŨ#?|T"s./W>M%@!QhG$Jf%F2= |8d-A+7ܪ^\uU\( ܏Z6bJF%H<k踄p(PAAzػ߲[PK8K ԓ:[^F Ŵy2pWIFHj= +xn ƤM(.iJPR q-\w/?; Cj)D՜j3L,TAͥC/LȮq <gS_%kÕQETYt)n]Zkn+R7avs{0B8e]3p%0sl~1n"aK 䨻&GP%z.aQitijTJͲ>4^Vd~5a!vIܧ|Ofks'oAyl44gny룀** +,*(D[:UvfBO %Zϒ1 ywG*]H ~1#_BY*1di KqeYkTuBR:|8@M8;1$vS0@ zA`j/AlEFubȟNЗY@Gְ0G\ȟΥ$~Mx.?v$K4@xGi-T_n-4fP dGY C8e5&\B=A`!>.zI,ЮA~fmW-{TxnHM>K/kLI԰D߄JTDjÿq|,ydԵ"h,E̹QjaUQ:c]w% +αѺahCWN^υ4H%RMAz.'oMq/K +`u\ 8PN۵*c G DQx€]Ht֢]QeͩZpHtd3Ā5ǽxiMJ42mn7= o.@>DtmgX@s%q$C&5?+$ +5?r-{җN7YSq`q1ԫp5vKr!?f  ~a# +8`Kʛ©嚎 '5"it,浅-,s[^-&W2 aps3YLDAMjԭ1-֌.i*"BhrѾC b (jĘ]*ZV(pQx(19jݚs=Oحx&#WMTrr2.yGl +dʁ NO$1ov +&}qFK8RcE@9I0\8kh%خY,q32Q[n;T_D=L}i% aء1pšn/)+"ѐfe8+%^ԥ;T#vTc&@_g~ +UK]/ ˷'ǻsyaGR#7QА%˱lI>xGpC>N~LoS v7uI@+s8#<e#kYQkok,P7-N"XZX8]DG0`:g +!,0H-A2L1Y]{ wCn~~RXNXRv?3x_jsn54F XJte^7)ܘn-T1D;+ǗR0IkgXg 1ڄ5\w:n%yC7g։n!u% X bcQ3uT-mrRyۜ}j&G61SBf^]I{O6!6uNJ}iV|Z5#kQ˸C?t¬ gu^$EX=h%3f;n>‚ Z,,Y/aO"ۖcy;b`EaG }i! v>OöFn %*[7m.N=Jdvюe~c!JmE3!4Q~T5P"!z^B6"J]R#>,juLf5_*{!U{h$::+&|-c='X8 r9R2G fޕ>Gɂ 3rldᕊÞAKn"@ +Nd-2071OEmqY)-'#I t--h8J.L~FbĜi2bNZQAq |ad 5Ԓ.^hv˦0vb dPs;Я?)j4ɇDO4emXg#K<&uiC&cG˓hق:9,=qp;wۭݙ@n",dCwvcp`@]xJ9n\u\qFDKJJ5 t@pseKկU03EޚC, \֦d7A"[j׽HҨE;50Fm\d<.Q[P].Gwey!Ţt̐cg'/M:='+bV{F +6 jX$n6@"RzWWg)oI}c1#7:au? D2~O鷦p h-24|^N;v 4bOK`9881ZjC3œHjQy^RH,fl-FdK6'PlijBp?ڒ_a +\jQw55Ueеxca3ȮFD$lK<Ɛ֣Tg msw_, `4[=,yoiA}ȥ-e@2qh;qɸ;W5̛: W".Tc ҞlWoBމle\6A4<\K +&"n/[kWo(y/}X DhVPS$zB5za%`ɵ  8vdT|X|c,$V6c,A.rSڍWrnGXt R56`mv~NWMn؞ϺVkC'cЌT )N@v D(l0fXK[ʱ;%S$Nֺ x'`fTW+ +%:Gu,,`nHW'rpNU+wͮ8{y{h7")QԸ9OG>5xVDvLW"wZ(nܵ+ҡ8Hq,iⳎ4 T|֑W[Wfi4TbƜoX88 Msx d{slq~bb5A +Uʣ/9ͽڒ? Ƙi?%,;^ß;(:\j %oN`9Lj6=J:]N<ʨzt;l}],_EŢqUKv5vc5p~%}%"YJ +q2g\t#྆'<:fˬ臬Ͼ"8 +Bw\iU~5hPaUS"K4N&:(䫜aVu25;b7NB͠Y1'_m)|_YIΆW;ݳk5wS{(kWXD89Ы8-D>{{z+@2L{-4Z2N.֌S[C`f͇W0qGB~wO3 Ы<(0pc{z7foqUzbƩWCX06qU(6nGмHwFL3rׅ^NCC=h[SJ{5ԫu> 1~ZǙW|FG KWY(zyUy&%돦k} [m@7.e+c6H3>,ፙ[;_"}|3،ЊIb8: $m;5md|WL +)]U +>L1ru S78$e5lER$CN])H؞ +_{RdWB@w׿fߟ69UCj[vWF&@i͟rV-@qj;0pϴq=:rʠ(-r3\(Ce-#XC6:hw#~c}R0Q-B*TDNJVIFsHsT-:\s:c1fy% +nuj쐵!ѣj1ViO} k$mX}{+j"A%{Z͖gX9~HS8kԉPTsst gv900ěym +ٖsH f + Xeo1?s8>ׯ"^}4/j`u3ydE (;R;r| U:vэlZMy`9A)Xd Kt+ow3wHKϲ=oTɭ|Oۏy1ow3:1MP-߾s}bZM+2꺱U8 BnGNU Ai 9G(, D!Mfy,̏M%, lY ;|>FdbY e6֚eB&b,Mr$%2l=W(i\dȵm +WSwEhүEP/jQ!?skpX܉t}kH*-w,?K^2: +d ΠpK#ҍRW|4p[IaihPpsV,up({f^bw tkIMW-IWxU1LP ):WZP+ cub9t" J&+B(ʣgno9᾽5!QPzA(J.0KZX&[SMS ㉚2 rJ. N5FbiKm*[Unq/=>ÓS'=ڵ&$J9S P?P*rUJ干w#lKvŭ8<|vZ~ g~a `@Df{Vnbµ=$ în!Jݘ8{>AbU9szm-Y۞WNmltP{A4O?fwt.85Δ?1"fCRS{AyCv:oJH|* bv>;րUucHⳋhRGh'r^swO+,}Htb$Y|j״ŘgAlmJ%uܾ(R^xb1&WFJ]oGOhBWy/qџͺAcPXG0lG33D'B=aSOţ)t5TJ{#}c'mQA,<ɿx]GGm<S\0H?7ACzcb!yPL3N!`x39ފ1J^J~ DCtσo:ύKg.5栰0j_; u=31EܙC^yQP]zMGPlO/ʃDg$ʄ`Bs ʰq7dԗq?d;jCylg/(޼I0=gUr.stt,<&G|j D+K㋑c}pTKyN$@|5ѩ}_:DQ!8=qaK(S7;xuPƒ[L; (Bu|F!W~gr`zӢ?uQO>1j_=.oKBȬU9r {Yu:]wQ `TH&`} EƮdehD?xƒiAPDg)ӈ/d?t7.wqWv||Q˩m2kGzh l%Ӫી D!>&4~} +_c_]fILtA2ˑH$|ћѻ-eس2`-u'Xz琗Gb|,G'G7H|Fav G\8R.?\%b5-d5hB婈} hW73֎7TB!*}2i tZqi4.OhRͱpķW8'j3UdKxt?:_m)ڀa۔f(Eu y'&lKg?UA.׺=%!7C4uϗ]lŸ/.U=K"9\^e>!QwSxA=1r/?"@cMۓ|f`e2滺 +wӔ=NhZYY/BS*omhWXzcuxE [ ӐΎp0vzWz=w>2E hoب^p`\.Wmƍ*Lbn0$f0JH mS;aH'wMe'0@}O5ZBIoCd)nz<0}oL2OgOa=fWWe2MB*^+q>.JPma#{IY;g~Ap0F.dZ>*LE2{p,/CYM)'^I&NQ`BPPqdj}~HAҧ ?/ $aگBN*N@;E2bcubє4Eq^_ÊՉY]}b/!1`pbi79|80%:j21~`Bu +k0ǯ *߰bNWƮPUlo&b:.ΆD#q93^]az~8/-eSEՁ!i̕!SYpbȩAXh>F]8lub@i K3X2[eNx#}u.FZ:(Ī{'nݞ,Q0!>qybY +'f|bd!ŨaGl.NՑQD2n< EƃZdN̻zitXN c#а3?0,'`?T.۩{h}oªEYvD/;_/os30קѻYA^k^hm-y!Og8AeMf_x3qՊLKUmq|u7>Aa'^"Vo 'bLvQj[n̗d'ҥW ewEP Cnqe/n +\jU9^UVq,1h&|ߧ6{X)ꮦQխW!bϗc~ưh]q.FK1| +;tTtS9&ABzb~zS +v62VC2s2d/}C PH3M xP`Kq_c!tL2"k al^aە ߻Tft=F[Z+`?uЋ?N=IN:E=U?jq?̽5kB:`j-G1H4Eނ^dULMJ#AA4NI;rk(D%mڦ8ŏ^[kGZcpAU"ۗg@1dW7q{vխpNd\uxEݔk1O;42`ѩhGRkK`8U9Mq#0_w{s=:> nPktSp'4 Ӻ> 5Շw a=> pamchh}bbZZuSQ0YH6mu7#ط,̥v/f?m1S]&ysrb;acwwzD3B h?.Uf.sLrIV#bF KK9eg<ҟ3vUwٻtb|NcXيϒ-B GV\v@HQ\ kpgHO5[zvǨY.P.#KZ4λ_n/XDfj7^/~z+ϻiZGn]LI~"wIH5~4rG_V_Д fsȯ>vt'LY( oX7ebQ,W欐^fz#=C &E3(i9`rj"H9̻ xtDZs0ϵGX]fN2{xNUd7.>"E!D"_[K0w` y;.Qk.Fi?Mn hkz6Tڄ_`mf|՚'kNM3Y-)yM~aAfkELٛ,7 k}$dgKa,W NTE2"0w +0>GfJٔ|08`G)]"3C/4˗ l8L%d,i eCF}tlHW@;FDOz +CLRmzl)(߳})[Z8a)h'<5@kz<%qĶmo]'J4}D8m wSZib˸nm*m%]/iDy%6q 0e#H5PJ3G۫.eu+ q0PoYa͢y|)ĄA +?sɎ*n +1#A>Fҍ1&Pߟ2dCNjpJ|QLfJEyi,Oe/GpY3R~AGHnu%ْ1}lI(HL6[1e}2Cޟ^-m>͐6nW_CW6>_>Ұ⏯kv g;<( +Ѹmm_֋l-_[~AɼԻig+_Y`+M+2xgm~p׀7ܒq5{yD߅fx &+գoE[x1y}.<^#<2x iۛ Nm}x#ɒ}5(]?5 % $썮 B' my ;3vf+QB>C^Qf>!jDZξ/1PtƼ2:WX.v7z \p/:UvQ][ͨWı(:5]Z^o5^]J}Bj"}BL#;YSj Ԓjw|L=!r:RNUCYn#U[&3컯("_fkVrjQ KXՒr|eᐽu|+AAFKt՗3"_\͕+ ~Wou15"4jGFҦ.v.雐:v;I~W h*VU1A_Lj,jf+!uo$5C_3JuW[Վx4?w< o)~ۙ +-YF>n} DO$s=_9ZWm 5_ jnt~ tt"G\4~)ѯ?Ž~E96W0.Ahj@:>,MT̬:P]'Ӂ-zm+/ߝ53v+gg73;6`1 3VlSxY)[ fTaĿh#Vj^6`s3`s3W،:㹙as3`]ig"qv.^ ]uv! ]84vqjf Ԍ@ű?Of.]ú3vqnf. ] X3afF.͈]ƺx3vqnLf.]88#v>8v>7 8Wuisp>+yF*BXaє&<#K2 MQ$uϐO^pW_DâוfP,Vxm Z#(v-@ m~ &(V(MBah^UdŮMn(xVA*mRwyM +HFT"ᬋ0v.R:s*0b'Ӽ.•X4b ]0v +L`Δ E&0#cl󄌝L +;2v +jFdL؟C3Q3klƪ&4V%J3bc烼ƪ@-NHfllmW Z|V<[sт!PKz |R#  V9acߪ̈Uy% VALxS?{DǢË@t #:6eljuE`6c1@hP'Wk,a:jh@}v]ԑ'좎<"du!#ڭ=]+G]9#d_ \iGaȺ(Y?t#DVK=V155cda phYGv+ͤBCqz\(K$n%ɭ$J`R @a S YoV[pA`^@ZbܻuF(y%_e;ٞ&% az{]ma=cH39i*s^8M8ٟ98e=:#R3ڼ/3Bey$8KZ|CekakK"g@4vfJzN4AX3MxOk M ]$`v΀Y/2Mlf 3fg.,]X0<#`vayF̈բ 1xGĬQ6;"f$@CoF̺QFĬ۞~fLٟ'3cfgV%5fg.R4ǖsXpzjznQy`GhȞ>Y +_̠Yٙ5\AA!/0B=]ĥ3jj5fE`LC`Zuk^p~Zd+GJK-}]3pvxE9"g ]D#tvyE9Ag爝]Ğ#vvfمxcg`.]8<#xvd.]<03xvaGٟDĭQ?N3yٺnhlò©=kl{@b..HWq.YZ1_[(4Z{ r1ۙ"\{QŬ8dM٘ dJ/Rn䧪Htx\߹>vUy1aiߠeIS[BE}=o0DSuA̛u + [q-yf32Usv!,®f*dټ90ȷ͎H@I2Z2d`w*Z +9EonE15 GU̜WϤ%j.e'v?ߪJ\~ȅR`g( tZsXo>ˈl~bo7y$\^tҐ|¾&ׯ՚(N#nU +ͻؖDW_2ZC;b?3gKj̈H`L$: ?π<bjß]Gd^*^pLOke̽mKmH a,6 >9ؙQ~FRP$AAl"[5n1~ E]쫡GRXao魝@MB[< 1 0A yZ$kys@6[‰ltU{ov +N lS"kqe y͟yd a + xE- b(#%xe%"lwbLy]ȩ90yG1(T_t[+,VWD1}5.E!g fn}k].(BYsH̦ sG<*zxi˶"a v›A]qC.j-@zBwHĽ+U* ocǪث)k.7_)7)AX;L M4K륈]C+6k:oqj͏k, {V~Ajql|3HD +v0-#W䟮z]ް>-pVQ엄}oC-Oj2>&WAEƒzdU;MN)eǘӡYepQ 3!\iHL?avS$:]9}+ ( nwnz.=ۍ1M8./b oR;Gxh"N%hUozc7SG ԋ^, !`qޯE;L,^ 9 緛 N-#efm#)@3y yA[ Y$GT_n$=0gEBuk&PCM/dimKe&:3ߚn>'W\/dC6zm{]TCls㬩gb؞3 ·CK Jy]R딮.BG&K.= QfFAk%4W/a:͌RѝgD8kƷ>͞KaƸU*iŲ#̣hުbӜ˷g& RpVDzZ=)T uÙ{DR/m R_)fb DR^pNmI30]jŨXcod xQ$U:;Tg{Jgrc^Zvٓ +WyP)`ӭڢBAߞ߫);5&f[k""a:RQ~5|F-RdoLkD( jTjF *h&Z͚S_HeU, %vdڮ8͢`Shu8z̫ ܲ"f#;:M6e2(ы(hcHce̠ibӏ揯A/-︐O.6sZv%)V|TWޛI؝Q(1'Z~\)D0sݶ%>ҬӼ:RZT͎"/hu"jbV/O6AvWKO2YȠ@&*I]O~lY|giWAxPfޜm d7,C' +d^>8F`F(}{\zO]tEd[=Ɯxv B5xؼI5$P)+=D#+S< +wT9g;dӚMgn;dV ZAٜ4g>)=B2 C_\(؈҃6 nn'bf/l=X +nd2{Vd}]C5D=v.XkJW ЏeI^[zG+wij~:pr{yhns5@Lkjgqor/n +=Ԅ`aWKK jIB;,#6&m3.T&2^=u.o>"OGwpv_ <Xf;+en~] o +s5;;d5r0U!\r+'\ +ҽCӵ;8tP~F/='ZЏn#5c;mM& =lڦΧ斸R`KCX +^Ҩ+͈K).֨ Df>A];x-a/sh^xы@8ݔԬ2&BJt +(Y)ہy*h3;eHAѣtZ(DNbͩ ,`TRG A,F%i7fʹmǫvFCBaL4p'# >m?hh'`~ /nB%L=Szv`CBD32 grH5Ȅ~P,uC^FYPs} DʢEQHdAvYv0+r- +0|r!;Av +B>_b{=H{yaqvZjtԭ+v@f 왑DgRf/S}/f>?㆛4UXVG&%r[H2E:9p6&!%`Kld{Wy[-V +!,`jg^*Ga7Jػl. bLUÙ9>[laFP^(շsɷz :zlU\CNeW9.wf!-JͩRR52NiьEH 5bx:W +,US`(ջ;yGy ڙYu+h׷=wP(P5Ʋ4:?8D{5HPPGݹӒ\+ -AKq%"KX\Do.B.X}Oa߫jHk"a(-_H} 8y])!fGO,atJ{Э=EuhX r8׶/û?oDi榫E%{꒷q +g[fHe~W/Ձ|ډ [*m;x,܍% +*҈Mǣ.L] ϩʰm<'3ԖeD֔{E9%#3 ݨL1l2q<24BB :2LfDZy]]<P,!ıኁ N)}տQrl38_Q>cn.♍ ?O;CMy lj.)MP/r tJ bF{m{kKvrnK;/ĩ]rEORr_A)E5b&yZUo6wj)hsVq/~+s"z+-UUI¯{fQ'0xu`at-9逊Ș hm- Z0 dsPkd)rZV憊FSV]\}af. 3rj 7˙KNAZ~,!x1BAFY#zZa$.=gӍ5DPMRAv7~+NC"΍ '׭Bu~W[s5&l}v3vN)t>ު(Mz!^;U `VG"%; bcT UN!q{TT0< +$sO4Iڼl#J1ܶԮˎ([E` #C|%Ѽ0:)2ۗg9db0 vA]ӟw AvQ Wo(hiZ?(Zb/NPޜݙ&o"12w:.C[Y-&-a\D`{9['C /&A>I3e}%>Mր!n^*;dB½9d +Cи=j'?؛-cC3]`0Vn\ퟺ4WdPDtj-c[lPT)LQ{ۣ3!nm0P3F*ZCq㿝eXO1{81F`nSO!'G$٥-

UY-AռhEQjm}"^m\d7U7x~ţCtd6_;Nț"\ +׍-()+ ̢A`?|"QGȭiQ-ezHzNHiߥj@"cj(L@5=3;ë]dp?Ƶ we('hS\RBl +%W3)P^>gf*œaE} .QjTI^\Qp©b{vtECv6z/ScQzSPj f 9mwe&r; } G6oar%dpNE/@dOxўHaO@HcJ6ǣc%(so1@rn#EjRs?r/wwZ8bk 8>B71-˫ή3r?5TU5:~2~'j&"^0Z.pt8=;'B6^I#6j h^T-l?ۇW0QBM,6^)WsI P + IGS6u\3(}^!T5@ "ybF|NoWxk551LgBiY[cŜzo-wm! JHb;(~4Fhdy ܭi[ 皿YFb8K"%L<~FZ^2dFN(xȶUi` U.>;.3h) 7^*_%okL,+~^%8ɔbq@Q)Xv03L"bj|$b] qݱ +&-=ki ȦO~{C_gNjv޳;"R#5\Nzz_EN_30-{5O3_B,p.ٿ0}J&jr,Sziz{ç(;nO%f:>U^>E +Gޕ[*NQ`86x<*&9k3LV5ܩqi)c~[~miTl8v֧S}"V oQnov: $^u0s$f>`)s4h'}9D0r +ҹ?mIS +#vi4hS4oJORm9^0n*L#9ӦAq o3Mð-2;0l*{[h5JO6^>'MQmG΃QS|m8g(o3]-LK!50,͈NC![ F)`կ2뛷ep0dʋ't3SN r[)Hr?R3#;FH kH)[~T&3򕴾H%'CNQM4wFt; @ρ=='N8{h8M"C2LX̺>kx4*+TTw +c8hkNdч;Gɇ.Fw]F4FwX5Ξ{H.ZϯMH1<&0n#=A@QW+1qAv&fP)^w> c~F[(BfGZ,[})B VL's?Av&iȼrhoϡٽ2VJ`'ؐ{ ܘ1F{O/=/x4QqZa,$+ƔE(N^[1J^Ȇ,с{b պd!ul.>jZBܬc "˒D.vQV'r b7vNb$?sV,("*fҏAi:l9D㏻&5`AӦQ8٩7EJHio\ 0HWMRx'fuɋ8CڜTaa/tD6|&^j5EY 5Io2fO_8jǃ3W>9hL'B߻1(9hf^HhGO{ELDo6Dq6gٻtO5)I_VcGYJޓJE V7#S'(1]IӣhObL5D1׷VK$w +6{g}!X%k,>4 db* {2AvBf/h>2(o+O!"g[uʊzn"pAȒoDWn l4,VLb5f~FNL ( CMԦs*z Sr(ޯ ]5mQfAӛKFx}iL O{m)敔@sR;F60QE^|ppּSuAM^\ S;rJ[p ?%`'4/U`&nLBbl.f52ScAc⦋ʾ\ΞƏW!G I:/u9;?_]2 KCS. b9ee^ҳX0.w`w90yuI- nod+Oo9tCd1E3iKϴ-ʓo dSZY̳VUA#D##ңGs{joeC; +:AMGk_Gu*Xe@ԁl- +DܞiScy +-j]Sx5#Pʎ~)m[~r:+;]Qܮp]'% 6@_x齲k#Wh(>9H!Lz-˩w'aX?=Ѻw-T/3߻j.Z!)B2v@3_5`aO 5: /5yv[^Gkl'áPhא` fZM(9w`v`K Gq';! 7S3C"(V`oJvT`_+-= 0{3,x$aNC%[;~*}ewpئ,k^$`w9#G麮M'D)h)sV>JA`9؀>'eQA9-F 7D+11KDm }-4kުEpt@wg@:;k貍bYW N)eBPÙL|&p'=e)P{q1z;֭ <: (d[ױpP5)ltp{]"؅v +jzA U^ ;@";$@%HA#*fLD:՝ʴD~!K5\] tż,L &£DA(PCai_+KRDpdet`W '<ou%*}3RB߀+<-YulLgux2f>e2OY4Wԭu[Z@յD8pZR*ܨvL M6]kaաq!.lO­Լ XeܻEXwcunc4\+*:Qz ucxrpl T̟CZ¡paD5yCZZ % 1 +%vnWz\\@wc1TX'ug)ӡ`YthDé+pj&18Xtf;OL: 6HG{OF\lun@Qk3-Y:eadžCSд܍H)za +x ++lܠmW"MIEsKZ$ݍ˨\CKftn?΂Q#/emRUמoS`&>x1ukoZ?7b)^ڜOyP +OW,EUX&JͿ0BbPˁ,M;Zˮ(bO~0wQMFY/ö{aQb?խu%9X-ڳuD־+mۼodd{Tþ"4ͬot|[+0M&y{Q% ;&N(Zd+:KZsdQMKv?ʝK2yC=DR:2ŸRbНud$]K鑋udؾA߽[I3=10D-'ajWZʩ]IyYz َ߱KVb{L3 ^fo"sORfԬ`A]+-oҢXr^͎[9rIy>;P]wsjF`nt{__¸;_RH/:A?M3N_kݦ 8^4L~'յxp:娉En&/&{sӾԳW!Ҍ➡}J?dN=g;!v_VukvQaV  -ޫYs[2Nji3{S;דqY|D-^7Z|^|&-B Z3\hJ@52IJ@o\&wWG;F`nL.Tbd2ihy }֖g/̖tZ,05R?ZFlyLd ?,E `^7hl)#}c}ީ>.)L#Ti͇] wۣ>6P Cxb:xjj_Ooի6!0H Jo}l{v[[SaeS(0H̶Xc @f`RW;6BLRC2 2 +{E!W 1h +L *T!# TH B^"`u(R\NQ=S\Z3.,׎:wil{U?yBQt^q:d~ɫ( v_h%^;Cs]9/`[́goUn/t +Z8p4ѧ&;[+͑'B(㪠)7aد(o =Stjx 1=`''H!گ=WD=2!9:؃]֡'3/ `|Ulq!F柄B5;h<,Ѯc_z(J ^ 0yg;lj^`` |qvw4͔/p.K4r qŚ&H_W_=jOо(='>eZzk)ہںZF;쐀BkF? %FjCkFV_q@&?2jԾ+]3VGhgqAsQ*GFLm'Q/mFyP(늞uB"LeqF c58g3Ҭ"N[> *}h xdy[`im`OYFA?xFDyQ}fU;6eĦ/3'X(=R<)zhpHgFuIvyM4DguKW +WWA vXL@kF[5gt=~OQ1fYX)du< 5t Jk VyI"ɝqتF+}uׄ/h 53S3 pOTW`K~ +ŔRZSv0CݧlB +r~8h$,̲'0^POZf愷B˚/OI+sX$ *Z{*PѲ&Īp/Gvhd6ƫ r] 8#udB. | `77[ct>l|2[2Z񆵦~>^u5a)<:oP_ǃKA9+H+IpD`Dkq eo@i+U45u^kRUP~$B.3aY#LqDWPVLɺ*Hgo`_Ȫ + +g#U+!!`5#&֫Q5Bh6Xs#ͲboLE>Nq^]U] ]`W]]}.b7nuː}X ٧L!Y]du掀.˘}@N!V]֯6n*YMXU>z{ڊ7R5.ZZU>1 ;\Tk__{PGm콢8T9T#q7HjYDUu@J4z4#TcG&:o|* BP?*oxj\}{_TWZKr Pjm5ᮻHF} =/e[>{oXjpͮD3x~MTwQ$N4NgXwy, yHjC:ׄH]TiG@J£./8J;QkwOt}hーyޛgjD=!#6I_5yqْX' r H2om,퇜 2i ӟkyv֒Ty/K^6n~Zdi8E8H ?rW8G =z<:/h\#rt/*^p >F6M+.LM 1 \xŊ .0Zta_`se'l ʠ/p]k#0eIP; 'FGRZ*X8vK렅zu0UMT5du$9{ubHM*$T?] !gǟFR¡R;POuqRɘL{Ґg-<:r"]5h Un^n;:vBL7 .Xpί-y Zd:̌:.`в@lIHFurHMV6FE +:a؜F[`ưb۞htmF]d"6, h,/ 1> ΂@!I}HEM0cr%@Fd.}c_U)~ 2_g^kL +x a;fz z`5^c` d ԗdp'Mﮖ E-)DJ"r6hY@3cJo^c: q%a*v&xL4SEg #(o2A +ziOT[ +E#Yk2@iWȓBcs֞$kԭb{{А>点!ѼU$.pPq`'iN] Z o>J{WI%“EgM+lGJ K"`55/Ɵl\$`9ˣW ;)akdp$g?BSNѪMU)[t`VXK8<Sx=Vtݎyw~޴l&[@Vh<LTDTr *nc7Y,T,+/͊nj:_T],]u0Ht"= ^]'@r\Ů6⟟OkLZIV$WW#SE]e%j7 JYaRuӨ'Pbd@\|fkc  =w}R_wE'` +(Zo44TEǨ Y(f|q| m bG_bfJ8r@╢ț:CȺQB(q"7E=k2kÜrE$ڕH8jJ@>%$$bd^>cIMN6CO4LP<^N] 5gA,,P" +R Fک$: 1`=/[9fNiQo^0@;(3%g?ȁ z=k'uc] MyGMl^+..vLrm1L6%[ȑ`Kyn*#hi&Q(ϙݣFj G'h9=xPu3($kK;&N ;:|vρ@2g4CUg _n.2TKK?GO.ș]FB'L" V5bm>ᯝ>Ձ,}0DE %3V-[#5uޠZ[71'bnȼ.Òhz PpI@fġmD}ZбOz!GMߢS|Ly\ v!)c(,SUI0z6 ykp]*o%0ɴ6)Ԛ@ehgdT\.i%,ԡ@[uŇIۚwVspuk +Չ\TãT"$vY`moD4^@zq@%8~V7 ~6AyjBƭ{g5d$jDRfV{rroaE-"]\ F +^;^c(0^Y]h +(]c2+J^ }S^-ԭ]PJ[+i"b$μg;z*A }[%eʷsd] *a zu<)\r{X&:/ڸi&ǀޟ՚L0|p'x,V?.Ԋ3Q7zweUb +.FM & ImGiA 7:hgZ5,}/.>+Hktny`lЃ![.?$xm-0)ꏺhAYC5V&r=gxy8o&+w-b Ͷ8V<1`bp¤RYS5b<Âb +h.-.PEoxbEl,eZ;tjV!a^) +BgYrdP&Dgi43؈vzOԯrl2 ڪ+C[(518{?r&z @'BtN0,ESzm=ƪX/$!oR +p6hl/Guѫ ?I='l +SsEҏRhW)aE{~¾疒pV"䆩c粫9e'w84HQN{l$҉jΪFV[dA DZkѼhM9fm}|~@M0kG1n,`!X2\ +3VK؃nA1fD>xm@(Ēb)?$cWa=gx ;|K\idjT ^#hؓ9\u|>ce Ra ۙg?u^sT瑱IgV}W=׃HN|0Bi(kSjm(>'ߵ+G=7 pٳںPnj-C,D+T29xl=S iuy%uRU{LZ#԰74. 6ciI];be<ix;ͱX`FZj2%=d'lhdx(UCH/s=ՒZzLgJ7UFt/lT$83%x@$Q*2B3hU}\>TQjf M7ڇ07wj?D>TY2Oy MK"}ފCco+x ky),߼Y;jZlij]aZ`c쁗¹gOЎv%1ߔ=,!,N٨(/U]T7-!UDM>EVt;ۑ~LN=ڒtρzC HN V<" +xB6l=]Q_mn>Pc%Cy(q@,eK?$|~SݳQf&i7Qۀ kՄzԃ#WrޥXdb7  ^ȁ& 2A +k2~PXMͿ5nTW*S CEsEg]X*7N +:exɆy@=  텮U+QK1߇_ Ry 'eFab x^*;lBtZlm#Q 3yQ$k$ :{@, b.6 iLs#Uv,@gG4^iô{^CxcHBISj6W% o ly5"3|^2)4ʲCLK BP!pl1 T2+$*iI:Q)(7v]N+Zk"Va&狰}ɬ <ʞ5؊'*yGҧgx hâS8o:[h Bc=qkITBgAz"h{UF6+&nys +[x*<늵QvTq3r5I/ E*Rp=BN(ާ}t\>Iz+N4U(RфP %Q557{@܎JA Xy*(O }@:[C蒰I`,wx`+=<hutᄿ<U\I%B8P J\(sDkx#w6>zDg+ qfd|L]Cku9#u.,k`ъߓ{F'wX[4BOD !%%߹Ac^C3l -+ƾ[m#PZK@d:u{9 7j(ȭyP Gat +Lm3788? Ip]5\\D u*044IX+AgS'W:mR7;d. .)q[ +Sf1yyAssm1>?A0L,9S?xUÞJ5/SsJpm*O9&ձҎcIӽ8PPO9|L&Rl^QVƭwk#bq ! <ٟXCaʱدq4; PC !r  (mⷶ=I*m'8ZÜCR̕ZQXAֻ֌4n)MxZ@M=\pwaR\Ponc^5Ա+RSv /_>b.Mtr3LLWP<"4oSSeIJIJ +^fsCf/5kcןXsJixe3k6b[ 4ʩ 6`l$ąS !U\h$ +$thd{ n!rd>mpCRw3ѣآW9'FfłMDŽ,WMP ;q~:iИpWe-42mޫHGl:Э\)ϠE~J\ a?ݎXO f%st\ԡ>M/J[k6qYfV +!; +ͬ vds/J4g4,Z X9M݊ZY3Q+K2̭4nȅ[io"33ܪS~"׊{3Ҿ 'vB5[5+mxF]KLJOJ̹7^ؕ@,LJӁ6L®PK+=}h&zGP:SaJu;ӽT+kt!;>Fl75􎱺33,$$CuMdDʤ}K4W%xh!g%|\WjX3rfY܍T>%HX Rnl8³d|³ԻG4}lxr.g%ظ#c1R-k0t0ϗBo3%jm_`U9=@rV%f^H4BӭLG"j56+/ʭ+]kJ +qb؟XBڗa$dznL1-rv_,+4y8nVA$`_vIIH,A U7>=;kˋn7ܘEQh}K*7$4<+ݣW2?`+RzW&)|%EmZ=1svԀ=c:ӻ=+jIShb+zhnE'ExIKx +Zp϶ +\1([_%J[:Zی`wOD0Xb/$g}4үlE4f:v:J7P~ +m(dT[AZ.t@>V4L=J.@BHt׾]s|iYC5GpRl럿m֜0qB0PYQ%֝ TP5s= +ȵUf 0AW{P?JXr*emqA >Ҵ[t +ez4Av$Xq*[ϼ36Ľl!w>=PG2ݳw-1][fWF~˸ Ӱ>x#) 87s +]a$! +M%]ͦ': $艺-^mzۯ.ՔgYIBmǣ4/WatCoP%`)V852)> ,Oui \*pŠ^(DžPґ?xNk& 3t!~%KCViITE͞RWmwPLf+#S=z|;()5RTA|"ԯ>|x iYgo q8XSFԷ#4MgGN5B*HR-n虝WAF:Z%$hP;=8֡7l +q dZڟ*ǎQ1k^<Y0n 9 PpX,5ƒ(u>@Pf-CA$_?gB{^y;DE[ꌽӄ4=F*'<`A3:XiyW7Ϡn_vꩉ'*gw3"bLy`yi;,f3™ՃCRYyyyJ }꥝. nΌpf\2gD8:egC1x1jSM4z]gIon`JWe;xqڄer_v}*1>9i,Z`K9vXK*k!_1:E8in5ۧX9EGe? 6ҦbzB4|~wq0!X(/^1$pWK_/&E Yy UM{X +Csۇal1|Q?#8c ohf{TvgZ+}&0Sz SʫBr5)A3lT}hExH6lW&-ߥa$ajbj3Q:))Z;7rLyijO|K[#=Ƴ(j 5j5Zh{u쥼nqޑ +CLYwz`k/gV.8FSZnn^_ <Rb($UgfygֻLYmd^;s{cߺM)y,p)sj,R9(?*SF@㓘US=e͉Gv ݬ H82fk~)0<I܅U` 򳤗Ȣ%GqT3}>MQt p.;BPO&o>u31=B +~'4`7W.yO5eF"^IٍlK +tQ1'=)i3 ĝ9(u$Y~6Cq\gSf>詒K,9vd1g)CeAȧTAFFhۦ&\<ŲW^qJ6q*8I ?KB5)0WCr#w~NJC`XjdIɤfc0;Yz{^WN.Lgev=c`_D\W78U&'``!Ãd+%G_["hO +ۄ,gw$@;>͎V21/.4ʊ#kxPTp壈$ Z>vS;~ ZV]2̯D^@pmHnx1b⬡Դbs@֫D!Or{@(gM$W!#rΌ-10t#mnc5%dN̈́뛛Vl*Kz< + nGc`cӑy(-Lb9H8ԆvC)Gǃx̾v2ll;bB7}@ \6xG:e|WY|߃hl=MZZ2mţzaHt{>B`N dw@j-onZ=UA/ +ЕCJa@Oʇ"Cq+B=tNԑ4uCoDӮY' IV8̤eccx/51=hn&>x%˸=y<,)Kk꩝(2s1Do䥚{^ +kړ` '_i"TK4J pzg%>B8խkiBrfC/UDF Ӟ(iW,{WekqmGwG[ T(BvKI <wN+!|5dw""\Mn`81mȮ S)6&9$.{C#*lcvTh!mbb akl;W7؆U u[T֐l&y[nC6"[V 7_ΰ\\ +RQ>Cs\$ DqnBe{NkU jT +WPA9F\}t0OБT2K$S*IZu˛f@N.Dnu#.A~xZ!R[TppY8s^k:.iI zXCHooLeK-M0#sM|g8iݝ #*-#) n2Wr -UڠE=cXA5>۪Ηn`X@UtĖt@Q'{4)ϺZ9iu_QS#t'vUOc7ZP%3r0@w=ˇco7kC>3 OˏC-P@ޠ,&1{CnNS .B-jrWtS+|};he +0!{rʟSNw,;!"-a s;AԩX9|kK?X w!ׇ7xg{]fߥWo' v C."O=sJ@^rP@Z}8KjClojA="kK ZNXM|7?+.P]%t\ϯ5Bb$UQS(5f0 J.y z(٦PZ@2)@?u3-^1åU9xޗC 9pƴwAWM=G`WZ +"j0VJCreD{K^WY le4*KB@J˵^YE\Mܕ.:t +rpѱ-#bٿ.Bj_B +B-]O-";9xџY'_>stream +%AI12_CompressedDataxku- ?`@3*gd5Ϋ<ȶ _\\4nZ5lh~vD>b[EɈ\{_/W/_0_߽|_t_wÈFǿ-7޾a߿x7x/~߿z%jO/o޿n7_oyϏw/)z뱲7|7_Tǵo|No_~ǂCp|^~s04iǨ/=2<:XR`gCu5Nޅ~_o}O//}8^c$ h^?8a>>?}Weo߼?ۯp峗pCNq01qx1/W%X8+821Zc)uadp.')q%O5"n3=$y.~z)j'L!kx1N|R\"*o{WZXfm߽+8itܸ<:N>"(V',ʹKۼW_:jcz_Z[[N9V|%8`L_u,\Z.^ǯK[}w +-9Y͗xϾ}~5g뗚9ך?W;ެ߼{+0>h͋@.a*t8}9Nɝx|<^x:X%1=ʄPXrF9գl50TPrE9PeQR%@̞PʘQ*'0)s!xtBBEh W .є?#C}{F5u9xxĺGޮNyE4 l VqFOnr#HȅN;و^ht(b/GJj_vC)8d37U֞[Z?zo ?}2[ s?2J˱S+\ZK VVB+zQcLx͂/  x=K3*d将*arv8c[\#ѭ-)3W\5G윾}zԞث156kݪֵԻov%4aLw-O,76b&UL*n䊅'ܝp;8k: m5& 1^x+`ѳ V;"|Is˦;o=$R$P &gf{+wer0BϓG [6[TS2Ad tB٠UkRm YBG.S~X<4N) FȊG2`|ΛgO&'HC_g} +H8<\S^"5qa*iA +pi&F;:OyW'$zd9 #{K#V6Ч֕ y.Dwx(J3ygeʐ9nH'=]L/'+re( 6l?mʠVϸ*n|)u̥P$u%)4 d]br\/q%%IaGA]2mFZIIm$I%PM5c3\$TX-SM. "d=\CY٦njB"Uw XkϳG 0KD ͐40͔CCY*CL9l9QHXL-$b}Cx ށ?dBQ2@J:K-Hd;_1 WWIԞR +mEE;>JSuulK$CCnQ Wxx:x^/Nа +xj^!T!c!kq392BFP :zSguTTDOPYĮQZkۡYl8j-^J\7^gUkm1 0xi+Fm)0 glJ9/'}·ЖEY[43Ϲ4gMMxT4,nJfeߡB96exw=~DjFtc⪸M6oJؖ7%mJޔ)uS H.Mlq[;_u2mߔ)q]Ǵ)ySʦM9ޔqޔ˦ܼhF;G/4$GGijQ4,e_Q O6%FJ<5;ES(kZ/@gLr۔<)]7kAWfVvЕ|a@EqlUlTŸf*Ќ4CΫ6ogsFj[ۿYhcю~7YAM=5PlpPM s]ќNRI-nMhtRĢS$ Ļfvr7l;xClKx Vm_!oΕU^rzgM5IKqA+*QV˲N}x <@?y϶,wlWf!1s.ktȶ3E轔ITG-׶R`NZ_Lm-F)4Tish8 N]Z`FX Lhꄭ[ǭ%-wg7~Lhc6YM 4S%*c{BU#/îKBTܙ=g4 O̞Kc 2JTG +{xFjޯ h[ic-LymsӮuo|gusz([Qr F<2N9Gl7*Z9U3u#_q⧬'`x%X@-b(g;f༘A%:+,&˚ٵDk&R%@m0ˉ|D[Zor! Xrmi! M($Sn]g$WX @O1,lL$6Ʉ i*,P/tTg!ſCk2 Q.t&z7EC^gW;+|ys{^W+U@EXDU3 `҃Mzcq1{9|<|<͂|n(4Seľ4GsОdC4e8،:Jz#ws[0 f ) 5ѤQ4D UPf<(9t4clm?dsiyhS66k{o|3?~Xhİ&Yb$,F,B"@,CY^XĄE0Xؿmjpf +?}OfFv/U˭ٷݵ_7ݍWnb0Kk`Zs[E1^ccG `xq4Lr 6=F2Iˀi$kG RJz32+ړgӒX _t{UI<[r6Vifs4Q)\7.{Ek0ɴqtw@+pr1.:YWfے͓?^7X)uΚ {\aȸvS'L,nT/#4\74U$&d1biA +蜁NTGqŻj1I>6|A-!VV[Py!'2G\3]h]ٜ?HF]gtuRߥ3Q˙%ƒЅ`m!?ǎcAO .?Ch*LNyELhu3\a5_kB|0*ĥC ++O~g{ l,WEVsG+|iRkC9f`O7τi_ğ30Iu$Edvp+@d_6qi,2baË#Z]~Kbdԙ:ׁ9S), lj>Hq34 q +3kwU ı r6`]luU}:k0&Xo"? 0Tװ=N;Ƹ`.;k*^vʓ(mGT6>Usexw+v0VhϓVLq]d Md4Ml;`1Pd m#C$-ѻة$qlչ&=CcR\2xEK]f^2CBmO-ifnD7JKY }m垍t[$SneX}Y҇MSk/õ>nT`:d+eY/ 14dWz8e>_?qhA;7ͦYWўCqgוw~bf(u6xvu6|z.Fӝgwq_To]kFڢ eՐӲ[4|s}ݽ! ;e]_n_Nw+u}|p_ DײBG^2,FE2qEe-$%f6D7>VDœJdmtM{M~sUQY,8zsovul34ic1bl`qȚ34ټ>8:*yU΃lxSN2? ͏)Oqxj7Y`8_df`WqGti׶3='i恮;΃&8ǟ mol&Qݭp;cۍ߶u05lȽne`rgF@H R,"9 NX Vz6eCX ]l1> 2|zSNSk/EЇpy!Zuig_)W%YHRM w v|tϔYl~q0yqcu*T4n{s! NDyJ ,l(:TQGZR܎Kg8~Ƈ8}3X.tpfboM$)N)Sɧ8Oq$H>ő|#G)Sɧ8Oq$HOq$H>őq$k椘ixnԲ sMU·:?7׋B16x%96GIɖƚg#Hy'`15K2@QnFG %'"BA 4)c>* ++l݅{*΍ldYY|>](n2?KJmf + jYn߅\|Ʒ㽰Ma'U*vyt,Gh,y/Fݞ6[J; ͚g6>Λ#9~ueQTLQ,IrQrݏ" mHgi?K5qJ~0l cXƛG<ςY`~< v_@2yoD#wܹqu;%Tz懫~Km[LŦzbz\}={k$ʿ + 3| mJnes\aCSSΖK>7Vv&b 朷>oǞWs%k.*X7|~ kC|be9ÎLbbb LϱԖxhv^l]]2tO 5S32ہ< a4d\_)9nRYk,/%dGZ9vltoCidCu[?8Ϲ0'6ߥ {j͛g@ۙ14L,{\gwWƽzW.k +`k?囒6%nJXzlh0ꏋ7|Z??7uNYy͇]Xy|6T9ڭT:xhK(!PڨiF7s T>n@\:OyS;D@oqqdq L,Bt NVy&I9ۄ:7G\35ZĄLgEO0̀I+WJ.9ܥ)7e}kwkM7"g0 le}֧]H9O{9@I@=q B؁!.(Sv:44$rwA_5E4FsґN<,$i(NL()UyCxe%e+c]N:8)#YIveL^C;Q>n8n^!#Y,M0%=:qoa{105٢-DݟiKLgG7>tQxܒ085mm*aHZUݝj':R̒}d19PO Q|]6rItxOjemt3Ab^k}imVڅqt-P\>PfZv:lGXi\{プ~S2M5T<V~tl[.u|n:qEVVH8U:}#ʟ768{0^y=\)텆Z9Nf?Fpau:rbrfrjM?'7*NSpvrnX߶sQ*:KrXsEZK?G|K"7Oi'Qou{Ewþ={rtfZT͝,T(ˇdM9˰Bb.'t_sT (~ m4)py6};"'L2 z@yWx3i9QY^|;'$gc[sZ\o +<`BCrnwzݺn_ȤžBG=MM8; +{Ui⧼x͢n(.vg-Q{qbwD' f9>LpS)|s>!Wc1*< +C>:͡)pcQӃF0eDtwNyj24hH?Ȋ WO]?5u\[UedXXssc1dZ˅DEoNclog7tnVx Vbb:FrT-z㰔:oaZ3>k6bk4y%qA/0sXI}ނH]A~»{DYx YgA~nmy/uQhw/klZ] +m +ݰ9zVQ{B܉՜_ߢBH%>Vlf=>sGgNmC;PdI7 w^fm.`W쵎mfPZHa/q+~5~џXvNm?67yx,mb0(1^7^:nkOǥ>&EZ$qcQ9E9qm#i9x6eǽ\#ӊ{\Wjpw]EXث2"Ƽ}8msj3c޶nqnMt*m6ٶQlk@v琇 oմ~aw#rsO>؃16{0'W+OPZl6'\a{n.`K7@UU↯.QSCş֣nCh»}={}0ҰvIcQ ^SɨcJ&?0NU]V Q64z<ۡ:@wyosoຫs˾;}@M\/D6~rq̛:u3+ޕ= rg8-zp{gb[|Ɩ\,>Gڴp)JP%*wS*lSvmfY˃'"o19=U3%M~,GrX0|"@2D{"L%՘h )4xL1.O|֢@09X| K!Ħ]4 zcɻ,= ^'8"\¢{p6 XɰyY߭M$Ю 8)ݧ4v}Jc)ݧ4v}Jc)ݧ4v}Jc))ݧ4v}Jc)ݧ4v}Jc)ݧ4vOEuK?/?ħDv?{Ƹ.0M2;GPO}]sw.b|n`KK?qmL%pM'h֓nA$e$XnLtc+t+J4L7&f2ܒnپ2n}~kLO'|K@t9Jϴly9]/ưNئ[(~]B.~vӼH=K lUsbMB_kk 䊵 m&YI|s-/ ; &,nbdIY,s9mf?gzEDB%P,.UFEc`w$t&!W Wϳ=TSs.a+Y36݋kt<@h!gtB0Vulϰ-L`!e& !xm`lB +"$:uv;îgq2וb8v7֖b1Dsap16ز.{Y퇕*Swfw[~<kvr݉V\3=n⏘96p}rm߼ogn"s{0d;2@ї=@ZJu + p5fMZb\HZ:sw@2d +(<: ^X)zw+7U{g2$?C0 |7W}nZg8ygJ=|PϾ-tiohM8g6]mt(E=&gS;arnM`F,薝p׏Q͟Uo˰R~hו~] +_![wfѿ'oYTp]jФǶ,{dljZmnÝ{QķVD<>FgVGUЇ~vu5칫M1̧;<5Q̇'5s7eSо~2Cp% ΍|\g8gZPMVC%[O:Ch^;\/_>|~oܠ+}Sگs8ֈr ?D:l{\7]YVwQ0}]+h@}x;aNf&΄syn҇''A7ITM8D,>|$JcRB +7)w} [d1)).J 6܄[sKƲs \f ?`~d0({BsA܄.ZYRfOK..mijE.rs;ýMT*{ˑsRdMR;~Oߩ=v'|ýqȲ?)pQ#юe)8isS嚜(m?.: Ƀ(Zz4Q8qDc[}YS"=rue0 A=:%>fc>dcNP` ;T7Gj5t:1:{lJ@?'fτF/m'_ʓ?εCv/ߞ^Cþᝂe͎q9.jytUoyaǼ@Gflfj?Wf@>~{[_3rmi1IHUپ-n"7vcO<*vlgJ!%~uH$=ԍv bACZtg/=r*xS;>o>_ѳs^ ?_^}7/kq>}߶o}~zſc>/?/ ;~oP@x%mI[.2^.<3-L:`b  _xi#R?1?t9p3pUZ 5P0W*TbhseEHeXAOT +8/[}P#rpnz3[FpN*( *G|[ ZlCC-=hd̼y { + +Ѭ~d\XzG=;5u)S!"$s\ _X'Đ! a@3',`tzA[ϕѾـ'cn \v[rHLy܋9yK<և 6L$ ߓCsoa/R(6]?1i?d/ChZd ɺa"` F26aYIԊ$^`T +[04QkKj "h䱒S/D1O$cbb3ꁉa8,5Ϟ"fy!lNpAw:hLXFe++wW}Y nL"N)'&߈!W?ÓWIv $Р?C!R-UA(d'A(d$J )./BP!ivK*5!|E&14Sgo_4FEg[`9A⸋J=V!6,vuVc$1F9NmqT(K>|L TkߪP+pWvS 2QC*{]ȚoMj]\a:e8kL_)Cv$, +Vb6GE| RAܦ+`,P@`l 1G#l)i3:eY&ƏJgo`9u]g9= WA\!4ֲP-RC%UJJ<\':u٣IqW1՞ڈnQx)+h+ d2aVh lɊRG5#ս [dA/ JiT =5JzJV(+n!E9` guq2BLdUoEia g9ل6mfk*K\)ceU3\FX̲ +L :DzK2YGJOӊz2ow%?U@>uq_J'VXDxXV B}TEЮbN0P#!Zٷ4IalGVd-S)Kl?j!J., + h&7贾ȣ4>\:{^ ԧP,ht>%DәB˗$%D+m$wVfpgԐA!"CnJvBX\ޗ.~LHx$ +TjoM-B=yÃba@*(=& +{=tͽ%hKMjªdiO1 O*ϣY1M`"$W aߠۻto9rѨ6 VEH!i4Ti9gʃHɵ&U!8jܝ"n  ̟ Ķ&HxmOS#*CEY0]蜘J̸DE{ u=PuY=+ n*9h:z64+R ,B{<\͂`I2L J1 ==4Mxٝ +2Κn+d"2g ;Mi!i5"<ܔ2 +q&GrIr"x +FFχ)|i-eIT:ftuh M,_M! !.HH3a_w 3wB +&S;t &{kQ2lQihv,/AJjw r^“"F? E 4 l~RG<4Q\ߡA#zhGi4rTo Tu$˾ +구J YE +75bDs{}ICM|XcM")*XY%tn>L *f${/ćTZQAJ=<K^|3>D9o +fFLb-:5U, +@ZYFU$j4Iq$ENL}6JX }ٺaE ;9K>rv(wLDPX/oW<3XG""yCF2aZn1BKs dMZ8f໩t|F0ι3 (8$HOlTl?O=5$K!N0eTfԠ+[ RexTmը)9_6 Ш FA{}P eu8_^v A?d}UwP;E)ޓqNփl"aCH0ٽAyPoCMx0A\VB2Ɂ7FT}a/6#]($#뇭@!z+nL4CфS &ō1GG "zТ}Q `+[2<0Yx'i\e^EZ42yR*H)4ىJ,]^)I؏tzb$(mAPV;6H#ߔ ؙ1 +f~e"go%Kq4gmI^01Z9tæP= +Gq0uL Pl[ߴ$Rsd泼Ww:jĝ|5R(kA!Rel[h>O2[S5݂'fRU:y @eBUcIIkD듧;٫aʭ=0j4oNְLzВDq@Ћ2РDj@#E 9O{bN:a|R*]rk1Cc +'cpZ J)+D+u ZX"(F:dE0ҌD20 -Z<91rH˦ ;[$*ewRT"1D4!44Sڝ + ɢ @o9!bC"En$ /fE-!VYHY݈yWZ@"J(^aX'MZ)ݷpmXsZs(X&K^Is&Ӎ^$0-@Scnַ8ljK A˞އ6V,|kڰ Y!2pb1oi-@?,_ae<1K/ UIK$CM%x" 3\j\S龅yHUwmE0:RT 5NAx(vZԆ-t_m+„3yjQ:PXU*AW!nF]PUHU +57l>EBl64+̥jQqp$ qR?bZ[? [*xh- Eo8ɼz<㤱-!<֕ ]K +L#Sm%p4;JdN3 #vm\wؖ2\|;YT\rfGPh86yxt16(u.ViA *Z?l<)L J J j GI/[P'E͂a,VMBhTer745d!I DS.( k*hPSZLf\,Ŵ$fz +KDVL 2V oI݋QDLOWZɪ͙&XEYiJItFYp-&yl!*UNCɒ y AXJ4"uOHšC3w_/ˑ0[:EFm*#z!IΉ;Ix&YQ9P +%яmI=^h&L ' d:qtׂFlZ]%9?DR`\)|ohhcɭ횽H:t!ZKȶB 6]-A LObc:xpGp6:Q6vB7]MmCk7D@*4%qcW=T؍WnZ:Z(( +60{V=` ZLi-L.22lPD uQe L2w-@ + ϴKB0}, OևhU5Jz +G[f9U&؂pд)}ү`v6W6V;قB$īM +L66x_AFW7(WR׌/LrfDLn݁XDG1A/X [N)ISTA32]YC?KK.XܰHeN3՝dcPbv@ Ih'BȰ iK5RR +Q5@a[iZјHͯPAO+A(hNP.xu JlCZsUY/o },E!ZblTB3\|Ѵ8=HErc ,BW]ۦ'Ua; ZRҭ7'a! +0J小4  ewB̭ R}N-A})+$B|TAet!3QDwmr 9n"!f#5 +\v ${BLL߰,Y+Y)]14[ Z؂[-)- h \Nӱ/0Q*Q dÊEip$p-Gq- :YvSY\:b~-hF}I ͝Xvh-`$2\fbL4er(Mqm(Y+aHy r-y4~ž$:AbdlT0A ibtM+&Js:{en*d "dTǰzi;/z0)ZC* +1jLMY mtlhI䁹*lƒ_蒟(4 r>M>[ђ&̠@=`ѹ)F.\n"d5U3ЊȨ0ا|d5Md!gBfDZ-ZǦl-F>Qo"T4z<(Iz` +Cm +LKu4HO(3w?JKH䂄VH2jqDНa=$p Pt9PG*Rh̘1SsS +@ȥMDUXg\ |%pYDpf7 Z`KЧ^I XA+h˳ +dD]a@ӖKX'ow, b3:x:vdf, 0Ї.!S:h:Á|bĵL[J&RNY +g^Jge]*Q@+E֊sV`@d 7]%lцCeSj)5VF19Eh0Y-0T@-8l{4H o򊦁,k4AK 2;zXOEYĪ>)5+D!ɌʠL- {fSt~A m.j6Oh:2J{6hì~K0)|0x\29,LEiʼ;^{o]b+ +DCHJ%&~GsQڥB̽ơ590\fH2 [ +4DC9qL,j1L*w퀵3VT٪зXb &QѣCw[0BŅ,tTyQ4Y(6WΡHG=ѫQ bFf>7C?ś>wSdJ3>j yy%l:LQe3fƾz*||4% &ah2U4HV!B>n!pp Qj`j)ŷ{eVF)7*sɘ +`̀`,'Ã-1T~G%ԛ\0~-AP2s<}mg&s)t(5Ke -!JJ?|9UCtAL!2Z&.!j~41! +ݢnͣ-T J[* kfKAMpUaO9^#Ԉyz651Eۣ)n:bØJ&gSShFE`j6i U$ D8ZO)?K D/ +mPHUrK4e-X!- FhBۧ;B`X)޴[u,(Y),Ըfyr+S5Aa$+'F^gyTI{ fW J;NLb,Q.UT& T*jč{+Τ +EQ8H_\,H +e#EJs8}Ka\eB=Lz?Fgi2*-KPZAfMT+" s E Pd2 3L`add0"uc<=X@@"-6ID 378P,.+dKOdI=euY t0Be I/~'< Hyyz O[X6|lY`j4W.O ,Y Y`ręL 1 k*̯UJf)J:QJ!\6yq$1QI?I ;Tek'LBMhG'kYz䁕U7W!>Z + +nNqRH9Mw2|=,AX³(w/kٚjksMA[ۤ| I! L_V:[6K#E0:Q!+ +^e`R,i!x=䜲:Gb /. ,D4&^ +f" pٛ0 Hfa(hpJ 3}LfBbs4f:B :[DdRdJB#XR|b $`@ +ALʼuWJ)!ƈV(%*U: +z] PpnT:"*9D FbU0j;&䈡EPD08U(x`3 :l (+ MNm]Jb#LR1X27%1Ԃ8QrOF@SѨF95&j,L2 (OJaVVb\w23]tiT/2Z4̵3'ˆA8Qew!Sеԇ0ceV0o"زJa^KE$'B`=HX'eQuT=hYLHsdrn +`Z4FN< c+3;j*|ك.C`h rgh;cm+=>6ɢ=[ўhbT + E.D%T;1:c5 r3aV9' bK)rt;h*S,2 B35 ɒ2Eh9Z(d0:3(x)**0!B3[`Dh:0hLXTmE*tPAJGA4d+"Wz7"VhfmI1Mw<I@G r@BC{8HAZftfҫrEѣvR;e"Ymθb4[nE)-SrC&WbJD,"tW(FhBv'N7e$Vм*1 [HK!$l +(NT'?2`,dQ(cq͟\vd,9k|LQݸVCA-Q #ݷN =Wpjan/GT ,VPbEa([%4ȶv U; @!kl3ddEd ( GDbک$ +^ +ltP/Ng"NUrBE~2 QO(*Z"&ň+7bhP[ T4epf#գ)ky1Hl 5Ć(cRI v\kX` Q42Iu{d_mbztKpV +4ELAܥruXFSmR3IJBA(S~_0=(?7ɵ*ȈElaVHmKP/F>;1Ɋ6? %`9*L6GmRBdz`a *\y򒒞Y +Fڔ5󨏞^3tKҡwfn 60W1ӛ,$Fg%RD?* @LK82(ˉLGJKB@[|2h `MfhƑ2,$7s1IY xKaBS89 9r1SIBXeJO# 6osdZif +B%"Un:kHDyG  +ZDSs|O8kveA"2cLS<1-$~=,;h +6fJAIQSzZS#)ǐR,Sb|(M[@F%x`^LT%$C(F 8%y ^YT,;7fenoRœffVFiQ7h!WD)ڂ&dwvpdc尡DBx mPAэ::(2! )J1u@tܘ6*S5Ր_,!2D$Ԍ)JnQzP DUPk +s2Z-%r4n"(mĂd#2M(L* pkrJN~i#@lZ|yC&dQ^@p ^ZPҧD驴NQ#NA0Ae 5y;,DRĊ:6:aO/RXVΐX +LKw(UdTA?J BAH*=[(dz .4śIg>C enGiUUfZ +ô]U+#1cp`a NVLV.Ũ~-s7s +b?$\X##6(o[J?# +I3j?9'@Gf\TJ72&[SAQ5 I'shUAFסwK[eɠ{4JSk32*P+Y'LC-JB3UN6EY3qPC$XDJ i,N^f=ݖ!_KyJt*iaRS`AHigBPtyfɿg{X>ҍ")56m4ӃR#؆8\rQ;1[@eJC$m`T ѫh~Xee9P5y>7 y1߬ϊ[< r14 +1:zŋTtͱ,rJ"}A{YݝH5}+J,B OnZmu|Ғ}ͮ,9v}31`Æ'FFu`r[,2*v zE=UVZ~5iH+ Ƙ (&VB}N z!\X"=mCS M1WMSk@=EUh]pixN[2_,J}erkWb3|#662Cx[f`/dֻBЂ${{{\ ]m#=4.>?N#윖4l=Gl +dv_BV6pӣŵdHM6O(>vQ@ZBqFm"j(H-~nm-Tn871c + uDBL4i3츟{0Pn֜*ͼ %HO79!ei #~@<&o^fnxPCVt@4yq*;z648໤9O=F :Ty=r ?OQ|jd;Mu1_h&5 BXjln; bYIN78AwYe\9r4 rr@,e "|&TĿim22uGmُtbfBQP|.q^K*@r;R{W)=F(#oNەOEjJ PgyЩxXs(TQ1pvLU59ER#jUv ]<}-7dI2␼GO>hgU]Y +^wxtZ؄$/$9CIw2A/t=zObWG 0 ܸ̬Tqoaa< ץ` y-_j+eQSb n=q$Q0L\IRE ";A @( F`:.KJ'Uٰwk5vy5S,x 0O*׬ri݄q{_N58$cw$]" F%{ܘ8=.\q8^cg"󞠅#Rd.YCT'zoPp=᭪!n]'E$J.Z@DzvEㄷ dBarzBJVId {uF޾yGPPR5rb u5,l-S<7<ClZr{#,80M1Y]`6J{zJ +ײ~=_4P9jY]e^͸>Atr.? [pcbq9!)QǟYDi5KjPC2tѹWޞ}P7Tyk/z +R5| +T!?GCZލE愠K豰GDw 0h6 JH [b.+䮨rKo&>"5AC|>9( Fu/ ,Y +r +%Wz%>SJ7xZr=֊8h!5jdP13Pb`&UR8 9Fkn+SCg\HHJ$D& +C^u{/c.,m9V+A(Q|e5*Ҷ^,{Zj9${?q"9jkthwErS<0NMt}OjKŲ$$m_*F +UK],BP?b l1;U,?I%H/U_>/ƒ6XEkE7Rz‡uXaf+BYozV&)=YͲWnTa c]ew,qD/Uڌ~XVxAy@۩)={=.h.kMx&[j "h;Lߘs&N+@A07x?ԢrN$AIU[oo*0h/Azt rA*gF̪%X 0fA&!'m?FđIcCgB2p%8!cr>ӗYibAe 3za\_j>Or3!T0;Jr D/_A"PI.,bJuEhY* ZzjgDOu]hΗ"=F{m mk:ؼb(c`^<:iriDZB!8{x-L9(fsNTX>PH/:ǁo{ϝ:0:E場-,=\ߥ\^Jݗr0W +1)cnu Ӗq0'ӲGy ;#Lܔ:?cAIBN$xШr Ql(3 OZ=N&pH{h2.ʪyc3 6I!Nk$XD1U AcW YAidH)1eQ{5^""d5P/ծr㨉@v!I. +!i yZvȞ$=i 6,:SuI4W<K:gڸ'1H&墇-qϺ~TQE; =A(A8/zٓ-2/Ss/%zHaR-{S/,`76; a3^V0\_Q|"387bt4sBoXM:n0*n 0LwYV%Iz]m=)7o*i:ݭmIm5)J.[Br! |uxe ?K +|W*^ެՎK{Vc%!U` %}ssNAcBD[|=jhU:FH|ڄZ~3`tbpSLu\n`nHBF<}w*'aq$U [PWً߆юWS[ڍĺR^5b;L{≕98d8&94:<ȁƃZ|dNWٗ+$bD(ؑT(gX1ǷQz.0D>7C.}n&(,Huehv(3ȏ xZ>0LV +2%ρZ0%O6w_l}:=s<5+Hg)\5a' )PF)p30l:{0pykc5g5:X}BZklÐvp%VpJFrZsUK`tm8=dT:ydKpуG%jT2C"4;ehbgc' $E!b%;Fdr Ǵd^9 dR[~BЎs>U$K/ yDH^v* nX0sw _W[aUѐ+D,q'ɷ4TdM*(H%݆pr>C /Y'M~Co PU"n(W?SWؓ[CK'c*_+xԬdm#7B*(B+. 2 lW/AZ9W,a1Ϳ?o,wݟǟ? q?~?Ou_wħ213&oD^G!mO._q$^T;o D=!jA +.|3l`8MQDh0h?p"PM2){=w~Fώ =PE =P@3L>!Fpq|JVUzCa!1w{d*Bѣ5D7oO3)ѣP5?C@,(C}OBDY#O⼐Ta2i`CU +c&;r ^14KjXȕx:_p pOXp4có+0t;y:!HPF0e@ +pGy4Rv1iϊsbmJFyv;Ǒ_^I~S!`3tfRdΞaݥSPU]FD32gR8f~@YnC:^Ivny# '%EΒT+2_W$3y#=4{Sƌt.JR@M,B>Ս@2nW9Fh@NlT*1-@RΫinvl7(D?J( J0vU{~㫑 WN 7z{FBt0O"v=Pcj=XmPxF.*w!ߚaSA/* +3>٪;q1΁xH/ 4e:xZ2Wlh=uzIOۘ Ce=D>;Ҩv{(b .yLPMaX3@K.A{8&ERcjm{18r]LGFE0_3uU+ogQ}"rtϲ e-G˃H#Z;5z~%hC9R.jM)!25cv, i1pQ1,膎]/s'Dݽ -s&L<)!wmPq͚`Sdh- +d%xj һǐ.&rQ^tV#a;J\(';0vP yչOϬjV*`O8N\d=_<0 ¾=%} =.l$id`Kțz0G)B%O̔BH9h;dg@!kaq6>t_z~:NE=50Y&J:5dVz+aIIAaC%4vh67ڍVB@i3 3=(ˢftb,.*@Vd16G- d9=חo:=rHWgĀ>p+X ј |]%4(~/_FY4RAFLtfY< y8| Tv$P'6O~ +07P8 #.o0uЭE\s2|$dE2[v|l>օύ:Wh Cb] &SWVIO|4$tTqomM^{p]C @(emQa Yl}m6xzHǷ{Dϑ`Kɻ3O|I>jR&晜$wVYdd_DK`PTo,a:a :s o jO[F~7GZ2ŎvaEKBlEiE<tWTt> XY«:9'=k%˰;x'%dз2, qˆD?{!J/ewJRI3ew˼;`a:3l^aq>i@jI{Ba@* #DM@GThŁ[ +br$L/T0з&7UKYۛ#P@&8ZN:A/C{K2u5 Cҥ-Nу0!N8OFK4.wc%oWn\qߪބ{#˒:ab sUMnt= 11v{gD|a& +2{+K穔 6iy-…,$=b}?.BQ\EHS1,0 ݓf-J3؅ܐc154P!>C0؋K XMJK[Jټz\riƌܻڟҮCL(f^{!." +˂ʽ2,T(M 9l93E( W8p}|]}?}~tw,ئ,Q -ڠ-7Cv|rI9S؃gr7PAo Trܸ9SIB#bt*XNqU>.`VE[ 0%fR!ݲeoF)VTQsJxYoxBa\^]#')`#p4ˤ/ Td]|岶Zjw[)Hai,{}/zOnCܹQ$÷2hH.`K*ŪhhZi](I&'05 _S#kah3.Mj?ksxQO&(ܨ6 XOW)1/,vES0R{5\Jԡx}kjcĪK]5N#h5YS5/JpRdSٍ l[·=̓owV>{p~SK/R:s..l=qt(Ku틍A!w}!m"RGU5N83臚o<(TF}o[I"\ctSu[bF1ף! +i5MǠ[* ?! y7pějlzDo +A)ºMf^-t}"~K3<!'G q>uj8d,&e%CmLD!ꯆ_nw&@s +/s#0:C![Ts8W`@FszvS5͛v8(0$PH(+ b4׋ِ] Xk m@P/{?;18=3lWAiC"{P-8:D6HbZb W +H`eڱEEnqeҬ*"#k7s eI6'LH8\{#g6|>LT+B+@'G1vP<!c,A%z0U8:q@ *;)_L.-46d_ÖxxvTzVMH9@q7pJnŅϸ0 aKW2ͧk!ŖX8l +vL!x@{ApcI|`N_sjh`#oiC 0s{ U`V<)HYF&졃0:l:z;0sIG %u@jdh'LQnKCMd(mjͽ&QǸ( +DEC۫z*i0q֞6d;2 +".oE !kgn/`}E[CfBq&2Mn .QjC)8a;;(!TP\+:@H)~#f1>m1:\۾pĘdjZ!/6D:,dy jd:fR M[/H&5Ԃl x?'9xLqD췊QGCLֿ!#aE&l\AQ-M)Hqs5Dڜ#@yCz %qw +H6W`:g*ah&u&c8ƈ F8 +2Pؾٮ_eTO[0S`%OlO]ov2$ |5ܼ @'C`sCzHL~,yKh*P +_Gn.:u؟E5-gyȲ _u bJT7r"+7;﷯s:;%lԹ!#],{rq5.N +ޟgqeٹ#q&}r5l}OZD<40 Za4T!BHuR# g!ƌ۳c7QD-Ht !G|u<>SJ@B`7ל (Sx `Ul! +ܸL5oQ dm2d9ZMgeNڞɳQC @z8tGu>"\M49Hv {V^$1uZ&)f07^<_BH's +7!gQ&HD +r&%d?,gWm̈GbG܋=DY}(X)帜*| -M!;Ҟڗ=XSc\˅4n_~UrW_F{ѣS#.eF&{CX(^\Ec (E]|gn ҕ#PAijs!9{Ae#̋ DBLkgXY,*eHe#5/sCX"!_:|^q# +2ć^aG} i9Ўd?2 +hz6B4x㹬J@wWوpOaaS D>z*hSjw\C1}*!( { 8a@9O$uDDb[0$gCxj9_`M㪱}j!H! +feu3T+zqE=&B"IՂYoBb.fFZ;9/ÖW!uG0ۀN¢J2)XP%DU6>k^hQx!yөE(H88wk9Pڝ(!Zpp(Iz&m2VNS"mP1b$唦*T@UN$@̏@sW A.. &:F6վ/= u9?HV17!E߫ftz!Y+|ֿ"fWEs- pu1)R򼰏S!rQpdO+ϾQ Q=d;`PJ-b5!ASAJ^Y3O$·UVy~Ys0MZN:t-{;qs>0ATӒL%m&y5b'xgS`Hv3:2fXPe .jKWukH*ξ\AfD\"=36Չ-˙ނY$︃6uR{9_q43ڏښ]Fw<U,'',ϰ6YC)u +Y/lʡ zVqfҰЃ=(B#+PRux(NQ%1(=^Sv(cĠGűZ EЫx'bGcNcnVӎdX?3VHXbb3SOfdXRX#2Sβ[~ۀ@65`cɉDs3AkY\H5Q(hxt?t ˋm!9 :z%uӗ%d5u#R-|T#fe4DL/9[z ӫz;<EɌҢ=ĚDG ~f:ez1t@aO_yq +zXc {JgAYHܷ>^|4@lŨ#_k8pS{L(tpd?AXzSңe5V$}a!7 Y9QoC={Ft C2Ƭi?{/ )A$]1Cf7ϛ` u׸v`kóBay3F܀% URL<tzd~q`X/+^ʀ!UGVǜ+ͺ@)ᚮjgQGz!j)tkp> v';Yp"L RkϺ~Umԙ.8pjBʤ;= @ _MRCH^G=d;VG}= 0᜽H^ 4^ zBo34iD!havXxU+UZ!q1Wmx{FMW`̜)$ S;PʡU!h͗v=^t &86>t==ӂGoEǚI_^x!]َ(ԣgu LЀ[ǎKG&9t7 L#z8?uz4ڽm= | B6 +cQЃLA)TFG'w_ [l={9JޢQ=ʓLIT7f)2S.E_?U]C{-$(O7lf 6GSyy (;(od^NT*{U*nd̨*FU<J(45E 09YO1d%!$TAXٳVfΏhmrKs*UIQDדH5 Q-NT:%.h7!J^O1o_'_хxojFp}KQf&IJ$ZɃ- +rתpPoY/pgNB̒>``BuO%̎bUDdz'q3D!*8 +h4R.Ac*:z2<ecYO`Ȑߗ=4Č{yPKXe:O$jشAB_Ý6*BdGS_Eh JRl튎[yϠ^#X@ P<~?r䥆eTݢjH@Y)6vV-B" ywCht& 6D0{Oδ5t :p2q, i}>*O_`U&஠XPjJ]nUh>5r0}eA6h?rF {3ϰx ;&RmC2nC ˘6" & BKEq,E6⹰vE= #=`ZHb9ףpAVʋc6~s_Ur{ =Cmٓn9o~ XP0EBQO1*P;gGs'΄Y[@ywL7qXWp*Ha Ir@Cr.H +=}بb0̐ĐmC8 +,Y:`]Y׎6HBjS@5`!Y]x,7"2H +@Frw?AA j7N{ڕ@"r`Oz %ekㄗjK?':< xYESJ"i彄ʱRAIg.u3\tP4Ƥ +L侅ov" 642=6P+G $IFyh  Ȏ]}Ӳ8Ou:fd=JT*H#ddӨqUFK|8[{Y)}{9X255jx?fC)i}8vJ}IJ8u_F.0sh(pQoE`>6N8qW^ApatS'E*dE φy7IӥAiC~SmnG`fxAƚ)K O\3v* SYѨ[R)"ziА^LhBBD޲$a4<N,fj(h'QV@eCdXQ@rRYˑ] $$fOG+y8:䮇):6EjC& yPkq-aY;<_=^f[!{fY` e㛂Et+CW{<ٿ =x8kq{mICV2@ZQ} VJG40D;a}oxN(X=8FH99R30V7 W6Ep7%mTIt`CǩA~sL\#ðV`:1w@?.OX$Cpt8 &$(4uGs =/ }SVTcdo CWޅp}V+/h.wÜE> c(_'aɞe"Ge/LabV1ok e,5 nAx4I(M( .g+c ‘X%\?$VBā:|9dz&lfnI^gFID3JQvLy1mUO0ڃ^n#.{َ{CO'ia4?5kSS.A#FV7oj^ +\ZXèf;(FX$ iC7eT9HRR* ˛]8LnQF-nR$ }+RrX%:yA2:B o PJ^P(Q#j%{(fb;KSzU֛pqg +ɬJSC +ߩiVȋUW&؎z%1:HH"),H]-B}R $%x2)HVew)#I-eaE-R7.GXƻy(w +/O-cs$oà-w`cׅxCcivoCcBēIIraۡe$r2ee.8C:tlz!,ϙC7WP'$<2["dGrׂƙ2ɦIe0݇r +(@/d(}a\zieW.s;#\֌@!Q9G"F ̜(LSP7ReoS'yzd\0d @] '6Gw$=H X=)W4IaZB,ɑQe JGm8HY0eCXsЩx{}2fHQ&hpD?-Py#04'Vjw#>~!]:$ YW&iфu/ʌr}T2)$rI/9w>޷Q$`J_O'ыoβ[,Z5[^^!K4$X 0t[a+Xl:5IJ[[Iɴ_+~4le!+rI 1M\VD!{@a 6uQPM1F6O38@]ov%. +hWU!*[nr{2 +[ +䫒)U^bg*;ZVP8 Nf&Q)XAJZ,'z ȶI`.%P+{}eyXƃեl` P 2TԔI=EݯMsF_f:3)0kĭ +m@iOC7!3" 6<'6y0ӟQ& 0xPP\?w[ f S.* : 6 3kքyLM!Crb@6 gBV4HEcCEI5Q.%d팥qFGQVoV2+r}d,{O=weO4GCpϫY==a C# + b@|S%Pt=,cJÀx~A=E:h.Mb%lUe% !QGTf;xgA)PP'ż(*Vpn ڼ"}ղl"蹲|9л/ǟ V'qi=U{Esm H97s u$=q_^L;RAIŽu2\LgO!@SA(A$%%VqMQ4溂(z6=2ZBO"rO$)  <1*f XVg 6p51%:]8L%j1ykttFV <U/[ YG^ (Zp; +@JY Q@@wg'fHh|r ?j 07B>g3D?Cƺ%IQ =,'\p8gBE~ awuaHKMv@~BzpS[ +[寉~_y`dP^ GI,$Y&0=7;N7Xhql - Yk }%R{"dYl'o:k\)]\6* +KYO6.$>Y|4PUTsRp[#V{)mDmٯ're.\P9A[$G-I~hr!îfbpk pbdYV`C Vg\TuMAB8t%y1|_z\HC뒲?  >f'lmC%T>ۘ*k s!ƽ\Տ/|2t9rxoha9kb` L@v?kK:F86z}2bږ×EC$-ס1!ڒ`+p->b{Hm~h$@VQD~~IxvEQȏ"d`=>OQ |j=^ZCXpl^CyFZC`hX[ï& V$)2 GU-AiZ x2a14J$P7yV4F4A~n SBr T.|7Um993s0E9;\6uസK10IFS7kd:#pbg9}m?|-ڮ4z*-/ِ;ɡ7*W2Ӄفɳ8dQ=j&PTje_=vAHkDB)ySܳgBDH)jT: ?"'U&\z`m ;8I8é"}WCpob=2`]R-X\DXg[RҴ}w ĕ A&NI%L"!X!g iF:̠B,3 +qK6{5޻&:EsP rW(*%:T@P>D鄋YV:+B|21RM=HlUƫr L><%IV"c#q|Et,9,{=dTC&yeR8AD dV&bԍ34yfK7j+{TYP!@fM`&+x̀ +[,>?  \;>NF!iif3/sO%Qpue"=(eQoGQ{rRR@@~q 6w L}FN*7Q HA'+G "<ɘ3v LW 2U'If3>@BJXޑE"?,<ѩTm0ze0raOʲ?/2TF(r4!Tj+7٧0؜;RlA=G [jV/^esfӑilG%F ~x"80 +DQʖ$d׼5iKy`.F`=xW/aD<˷*!&г꺂mApV,ֆb5CV_^ {{A3a7(ְ:@,TN!EJL'(a +DY?]F$)it= ^Zs2|كvwƟg$ y:5{S$iG=tdJ}K +{][_~U~T{M"eͣ%ձ5`[kRl^acC{Gx\5zHy|g#>NK#;8|LˁLWEpm(1cYPWPE堥3%T;z8t\G+ojK-v1wأ}" ! 8.s/搇W=ZH׷Nإ) `"a7y)@1TςK &Ӵ 8P˩/=~*f01W9"zt į QM8E谗:Q(y 5FkȧEKզF:l<v[Pirb9=׈[AXFt|(y&7z<"[(s3}Y)VqX|!r_Z`vPC {G6>Ҹljb[NY05WZ03ͥM +j'ՓLiH-X꬧Q ȬR:d@vH䕌|g]ڽ*)_.oŒkHf(,YrXr@d+ap/8^~ aA%T!&s[:ܾ;)! 92p\F"U3)SO +5I%Eki_|] 1 QdCʠl\#KTAM +lN8ق$tza?zӣwDTy"osI"W" Ր +?zƽe&AU' ,Ao%5Ҍ!l)KB*mCëZЯ-D(n+ƶ*cDX6;Uz>^q'<` `L\ L}q2X{%fG?wc5m_^_ rUy1BHF*Re\*XH@u):NH5"98ZkĂÒuxSTPb ԧ|3ʤ%Clٔz)Vɜœ^WѼ2s3pBŵJ6db}Os ! +Hi:N %i@: $ZBhلhm"< ; ~4;#9> $eVBN -S,%G ǷS*M0a Goae㰱y*7\R9JovV@|ē xo}vuھASUc+bC@'oZ9oߒ+5u?!AK̓7Êړ~;d5 3$ 6`'ݮUu[aQ)&U"s *``x}G#M\>5q` xbZ B|^Ž?釛+B5m- 'k(MkΚcLH Xn1GXA䢘ƽ5¾i;Sxs'{Tbb Tp~#n܉+޾3󤆙R!taUN:F~qY-.kOnA$[l ?},7{IA3_^H?؝Dv[Vيٸu'ġz92 ETr%5L[` hUs@e[H*եAA`{PD=Q=lcƍIno`I|w zķ0W]DhRK̂!X>W0Ǽ~32>5H IěsC;ܣ8bR҂q/v ǁ(i@.#o#jN˄N Sfp Ed1!bTvCJ'**tANxUiBR M[|Ŝ5ZP +񙒙3׉=,0;yL?aORQ>Seiܣ;r2{=o泂;@1diȳ6I@Rdl?Y!V;]Pq֚ wD%*|Ȅ!GqRդ"V3?{*#o@J3ԡQG @FH!K[ceuo*q +71cXvY ;$U< Nj  +nJϐ︒x{ ͨf-[ +ήZpr)KЕxpQ.'9E apaACGWbe LQ]gb Dʤq )i$ԇQ˚ab_}'A_7$I`$؛Hc*:گCo%21+| +c;3`ف#w`z8"֥lcSSK1EèU+W-GyWW>6YgŒN631PM3N %Il_enѮ{^yfI)}`#qP/ +YQTJ$>c^-#I#x-7<),<_ց+x1ʲ,!|c6ee-ڭ~Itf +Lx96:[ ζ6tC^8;fWfz%jpБq\q vTk9H?\g9S +C! {u %a.2/$?w(F4aoDk`-YOVT 5Dž]4{->=>5}l :@[VVg,;Ъ̵hEN6vy>@ڸbXXIoKf(6q")a`]`8(]c%ڃ\Cx HAH*T l +q NlXtk'@XN@ +wbqt)p[$![T^`Gl`%C NA=B=:| 5^>,q3%;oRH`wʾ]+Z!;L9Z&LK*t(Z<'5݉M&7F P*Z ,rL#@awƤ%q/ +h'LsƉ(܋⍤9 +ώ!ZPK1Hf`[}x>SMp~k+t!6F%fG?J:ZB )1U@^rO-&/MaЈ% +x"JjByYfT VI#fjEPyQSU=mɈQC؎1?WL@¢®bÚVU,BaK=,| [x$Q$S0k}>̆BNY~qx`$'U.掅_5&sRK8 -}^ ^&?mT7|ur3ki:#{; Y9Z!$)'Zֳ(nQywdYߊݐyI4MÕx7x6PhhbF7˫|:>74,YWBt!'3( 5`b-^/ȼ-|4_Qe@uѲQGl*sQolVV ^FXKWܫ!~#!ýBs\(bj{k)R|jDbY3nF`}GhlљM@on?5*+c] +rx+ NGSqvB +:S->&XpAk4_h/oDURс!yj .s@3Ee ͞Tykj :& 3O3;j?:g![ɼ s# .L(k×i |׽tVX S4'VG>i(|)&hbk1}4ꡍ~nsnx8Պ%/w np#uEa!q/'dUch  k/FKuxFuO\Z5>s9y/a5l*]=Z^g7biOm~5rE%_ǷW{߅R-s#7ѐgÍ"P#RޭPK7Ձo-)fճ8ifRz_( +'0Y9!J]7H2ֶ~n +wM~aLM6{z`;fH~4G#GvS +>ݻmoUH{dO98=w*kȞ7nd-z<+ÙC8?r. <`&{Ci-hޕXia17؈t6 +K! /^1ֶ=&1}~r+p&)qR3C%XJgEY-4If<&XQP0g(xFv+aLYI*AՎ0y<"di)6+4]l!3fsWut8RYw%OD 99,7RL(E E!T8aCHRD!0bj9{Ԓcnd^i~IzܐL} P 81lJp^1\&Xg=Z6ltSp}ua'~ÎnI/~W(Wwu)0O9IA.jH|q7梗L#|m,2;c$->h(VkШ-#ʑQ}>7,yufa? MF!NݾfZ5jČ/n-R̭-r{WyD+k}<8hs=ȸM<\$Sv0^s x>@:4:DF9G@mwT +#bMNS3p{roLp&.Zm(U-l#_ݡ f__hpϽ^0LO6O;Hh O]]%=t9C5 g#ⱷT (Sml0 rV! q a|"Ah Qêe:q7kpF)joEtERmhxg=F@u +1e"b3,rO$62Fl,\9=A +JPFBŜ5#D>\VCwCTH5z Z(A wٕ@pHЌC)(A&RЀ*}o}}g +Nq6N'忠= Ԧ]Y6M* +Gq}WKD\?GL>"3D pTU)P8Bl}\YIe 3`.Ȏf;?v#N_g ^&{8۫ĿSC5Iw SvMۑg]Do+i^GD .1o8uJ?oSXu%5{YuFku{;-m \}FO)AwLVAVN\?v&5l$"Э#);R\7]lEmcJPDb?!7ӝL{ZGj]Lqcm"rnF0B#fvp%=Es>IU[0In8o +E 1ĎOz3 *4K9LP_xʶg*ѓDYhuLPw`k)\ _0G`HœEve58Aԕ<H`T{q25@V+t.Q!`B[{`:,p _ZG2Q T:e@v* FڼX/hI:=n₹z32a5n UWj0yqPpٷQ2׈,*Gc%@Fv2s!W9sEIl_ JVz>YY?QkHK2bsv:=zs3ȕE!?qoptIҟAQ&ЏvUSm}zK2#|6v:6SYqVxN}ޡ:n9BKyJoTꝬnFǟd)ڑϽ6AWWӣVP@ +oN_`&QT5 QZ[ƹfc*@hμ] "5*1ouT{h DasHpC3VN!<[gbRo 9AACza;#J^F7FI^|-x ɕU\F؟0>YJke*G5`Ԉʕ@`]VAks`;JD"e?WIIdƇ"]E m cT~uz"gj[!߂Cz +@6Ef2c^7IוPAP!(5E\[ H_1Vt)t*.J +^;}\:ꢁ{h#9쳤v/+1cZ[v*z޼+{О.vȆw;ozcw`JiH烈OGCj&TQː +F8濶MTen{/tDR#gSkH"$V?[% P[Gcv_Jt_p@N./Xڝ=^*A<"vtQt7#0 ndzf3}q${cPC=Ν(mfW&W=)aI5cMiY_vz +2L|e)W}hJ X*Fu e_?r ևAPGp=09 +W=EVҢYp&T@t^]7GżRəkuIL::O@݉,@ߛ?M^$|G@̠ PS^ncC6Gvxe% E3M\_2Ů==Xdz/Sb 󸢪Ä3$$L3툫oo_$K K]-XupBח@eI6ҸSꪧ}1Afh{^` +.9c%ec/2T]P\0w qEc?3fpdc=ȩ~@[7S.@Da/A:A4dYb}Km>D2v`׋"Bnrx}f3R(]8p +hл }·!E߻:2 U0 Q_;[ědmŪ/q?P<Q*o8n{9zNAΞ70r<yZDijx=Qg!7M%p}C3R[ֲ~oP"kZgm KBQPUm X"0C阁 B_E-ntq*0씺˻Z-7Hb]I6/O爖~PwPsWʰvGlkhBqEzph=N= å?LTyw){nȓ+@SWMqOHx@gq27QO1YʌŦ~++2]z~~Sd4e!lvly-jaM/y:_1.?ac(uID TT G⣰q+oAM}VR_M1.%/눅7EpLyD 蠟*%_rɛ7č_? 8GyL;7_gKvehf9SwVe^Ѥ+#c<,:QK9!Eu{J>JV0>(@q'k3ʼnp}* 4:1FOݑ!eЗ6`C+P|B(}O9ҏcZ^ފӕj́@$cŒ"qAc\v]%*00.}Qbw^B[e@,nٳ>{w9NGD(`0 0:Ԉj"?'MD%a3>vJ"\q +l* 6~2i<5yM uS@# PTGwE|kk^[}IcKLvB&c|_Qs/^U0Sᓨ Uԟ,+VRE+F=ETݧס0v@; oFlz/,zCB.#*{_0Jm GZRgyPvxjBVDO>@ v=ڍUi"'ƌa-vy FՀ`!Y UR]\н $Yb[ /6[Lzlݑ=w)\cЭ3|ӨW@ڮҷz|<>N]A_gI1*TJfÈ7voyWHd62ʞn[dY,I:v{^ޑDd4bf_ۖ<Y7+- ^ZϜA婦p1r$~w欚eOJǤt;w&~P7]Q 0o}|{qnMxpV$kA;CX +AB_kn2*PsIM⇪Ez2?&i5HV-=(atl&$3v}Wlqm8^)tO$䗼v |choOFt"l!(A m{])Y743tۘN5^Lj݆Xmۏ}!AWQ C'm^:r6&D vm⪅de'鴢NMභqBF.|wJq!@]bHl +VCmwipz2q+![qzDYQ%uS=q\^] x5(>:Gm޼J7:@ -[!-W[)a׸~ઽh.L6oh a`pB#ujQt5@{$BOy|Y h8BQ + m}^]-#\B̍Nߎ&b@ ZMO@zӁa~/Mu% FjС&^8%?ɕlu?AAajdzTa_BEvpeKEv|Op}X7xH^jd[(ꤕ#q޲)χQ+-"h'ڂ)ul;*gd>Ma_{ka/s̔o_WDV)u|(Vgt~O00`dn$OWrdR>bk;5'34ut#>WVkG =T+/WĄrEן Bg aꧼOwlmAX##2 Z5\j畳^+WwKս1# Da%JI WFubLByS +{/x(<Џ#*\Ud{__O+06+$ZHy-!A۴nZ +:=s+ _묧9xZ(qAܠS l(=Ӻ^ `Ԗ x kg͖}•}R֋tӕ38%zݙzC'XکPa1@TB;+4'gs@%4|FrxP*M φzyl?"/i)#8Csl5i-BԺ塾x:Uo0+_-T-Q8Btf1UM + )/n@|E3N :~F~WCъrϏ:-խcy9}=|F n YÿY4(^ZҘV4g{&P-x uwfL{~˝ `ݦEH{4~c&HstGR߶Όc*TzUDvЬ|?`B +mUDJcGz ^HGD΅ #*Bo 2"x@Βd C^ȄˣP1GDݤ']R]e9tGJl^W@ĈNW'ynky.|"ybup=xDuY/K[)L2F,5fhEsƿnK{bFm_;&q[ EIGovOQ\r!)x*S/t+Xne刊Red_ws "#47ʙGo8eIH$z@fKeQUIMIXL1]JcӂJQeRH&ZhO:G5:2AYplΘieIAA /++G -Q8gQjqA D`-w?H.8S>=qA|+2|83 Cs?օ +hvPFE[7$5[|ȑ.,w?82lir='4xF%?}Ѷ3E3ek1Tݕ{J{xbv_ސL~l?#nM>>$%KgrQV +frH[!p+ZI qM%G;ېSoC<牒P"TQ? +@MsE' gΣ();@/5&t,er3P.x&]bOI g2yN&tN_#,7b`fQ}aBn\&z(Q[/Xx;>W8[C9ufL@|8oq{nrgT߅s Bnil&!?RE;鴿6mWf*2U7ݜP oRm4ӽ_pW|\j.uɯeHtaz]iyGQ˽ŽaCr/9r RaùEppmskrX1m_BR6恚u#" vQ*R&%QHDn2-{[D{JWz)̨˥$F/\9*dICvoT-iE?, Y Yaӌd._VZYk?菬*Ö}7Ɩ(ʰ v$U:…eOǒfݽ%6O'AEKPRN:)C֧+maTuiYZ|L_Imx@e7NDmr%KƄ-D|W}>stream +v#;v;JDw=; Xeoٓ)KXR<=z7v=W2=@姻s=Iy%5j|xT5Zdž+<=vC*3ZZEr%[}mBd "80 [R삘>eߐ=+Jg}}oo %IF ]dIaH2YץgTEЭrh~P h[*1&غs"y^.24f~?]XŐ-ٛFxoESc@,/#V'ǥhЄ^uԘ5|\ Kٶ:PWY I/%9ӕ=%H}L<]GQ^,IW})^~ Y9n|n\/shnTvEtGۺ_ߠ@2ba\u$j><8( )ݪ`Ξ4(([-e)nD(~FN ++L7M:>x 2(vqnQI؝Ð5$MޕQi{G!OK\^qT/"ŐfbTH]r<^'⵹8D?[;411Ǡm56O-4][u =ZRB&p]y>`[G3rkucXjڹ7t&I}èsywL# K)OdxNgv;9[t):~`8ssW2w6ׁ_*נI*-lQ`a4z;<=[ Ϧc*(`]8xlnt_3.j]s PFEצ7R~KeT!8 f'G/vOVu[Q|FAcg-z;h^6r훈(hV_^ X^(#~#gZN(st!M-Z +lz~a7`;(zRk۵Fcz}cdԷ5y?yyF+DۮnFϯGQ6ъpH\.Αԥ"7FUJ@`o -']Qk|SjYit/g=:__xƱexT՝UGX(kqyN9&uبGd>K9iŎ&E7d e ){#=Fu V6@_Aq[Zz- 軈ÃEr޾fh;8K$8%-ö!`A_YJ\ni,$$z?FGLY[,I/[ݳ>h'=tu%ɰ5P8be Ub*γvI:&M5 ?*'}-Řj2.[9 hHMOc^1AKYu!zZE@ ~`򔰺8;p$ZJ4PK[_^:IS%zA_[ޮ.}ߞ1Ps#OzfXzYO(~VqJ}8(hJo{ @FDnR_I*QO~؞f/!ks=WAM&l6x1_AQjYyOFr@-ZR3.طh6G+|Z ѫJ-:kߢuȎp|krt{S +8۱ 4lVg5v'U׸o nGzZPcJVcum3*gv=j@n{CǾA$'+# w\c57ŵ^PI/i e +P^>uÚqh7jY%ޣ?17 :myM׍'xtT-!֦##v*R:]ZzIWwC=TESQű 9L,wn0iwުՠu`fw4I[SY:>ۿ!h?o>޶SV{bv+N:J+Hv;%HKI>>ζ ~sb$Cw_Ԝc}p'M=ρ3(4f 7mp&|JR"#X9ar B[0Lf]j J/~K0`ξ,]nUc90I܃y~չ)oS~{ۄ@ߎըXo3 Ώ*b;P*O;7(۔ $)s(Țt<:l"zDk}ύ(Rqrz8}1Uz06=8W[ Xߪ~D|H37 I¿E%g6RM@8\Ǜ'm=k5m%~].Co q|?+5wwq?Y|ZK@~x!꬯ze3t2rn|zyJwZ5?_QwKڰQ&{u)_%XGJwx 8$_!#s!maB`C;T@'i=x7 bkdXgwon>%tLW:}/e#W[/2Zp-NB.0K( V9,W5 rubr!QV+ +K3VP 0 XжOpXF&58z$+ezl'=lS{|^N74{ўE$SԮ7u&ŅkHO|rE͖GvÚAjoq}?΃+Vqz֮@mrq;V5ߎ,` EqJ+9^o +~}' [B" VGG-b  +tt\Uvia"j>!8Yz:_򈅿.3-| ~D֐sqŸ L2r +%(œx(0ӅWYϓ0[?6 U'44ψ܏zMH[Iq[z]iV mZ!S{]uguu\ +oҁTgDkClLHcg\Pͪma^Ks(]]}!/^g(Y q2"F u".@^ (T< (CI-0B3 ig)Tփq/0IIϛJ<4Q)^w!)9$e9L{ζA$FsYIlt#.@ߑ>Ql>oaOr\c\Gu?_56|dm4 t PG0ڏ'#v2*kuY.i>O{'򟠬 XF?Ո QQOMPDF@p=g܍62cDZe`EAJ҉l"dꕨz3kD! IG%\a99ywzGf.!@seU)j@Ϲ3ﲂ3jT|nemd|~*ZIK+bbbMU{ 8dzџ!;:_WJ̺|#<񍘐Ō # "֧Xw] 1,JRhsKbbKceǜצ!P)f/A<<` ˎji-[/Bgi2)*3Nmނ/P!UUB|(z)ɜn^Z&#)Q[/5#ҴV_s7yڝ)Jd,!1@󱔝B:^ +CrVgfO@py:4ܨ0rz)+:6*~F6<ܬ=m +pֆp/)U Zh4MĈ,ΪG{ݏ(RPZ>P3G랭Q ?"0c=YWߜK&{W?ǐ@#D\@|ռMF7&.AGS=#6wOp. +}dQD)yށb`Ы3@@k{}3ÃϮhU UPSfx:rf3lMA]sz8S6䶮Q/H^5)+wDԒ D7'(:6?OfwE_ ~O<+}D!C5V}Q(_ꫡbN8Ŗ`n +s-r|]%Oz|hՅ:"x=& +6) {tXBrzv4Taw;HVܬg?%`"usRiDo`z׆!pJͪ2.,=P-\yD5#iQ[;15҉) 7G|$CFdҴc~ʍtt-zvx~%^0 +JQ.+[YW _koMqLԤ0ٔY:gL׉`!5_Neg1åҍF޾%"G=%`HZ$99@ߴm~&=4-]!J(9VgD6Uߣ *ʨ+Ph~o]T-c<&>43 BqZ +7s#^~;",0 xX\IC \4 +!\q]ŮR/>aac{8ӽ Y[u-2PP|{suZl]qd=MD)q!XIuٺ)lռ y(YrxCmQaZv`Mpy "uP(t1Yؖ1(osk{rZ-0&ʭ<6Se7@@aӈ׮ys%G-Hy+PJ;ՠ-vɕLVѝi;%bw5|Xg~ |sN*πqF.fT4ra 7Lx$tAߣ/9tLȎ@I2qTB'E>F޿9O҈ջtMȸON&Ati/ԡN-ſ$4l#/i9c+AM`kwAm<:gͧYn+GTj8rӮJ֯Hv~4 U/)N+۳QEw&blY +ޯ*) +Ş]'=} QB}eoQmC/k#ɝPpM v7q+(Ϩ[PV򤞇4v WZhE.$)͸2H+r|RZHNϏ(8h jN}R;K~;t́U;zp^S v':cWү`g&Į˹UIρ^]`dT[! ;1= +to|;3p$Pb w\,z"^rEy_~r>B ɏ??6|F~Uȳ`8CjE|}Ӄ@Ӏ?pJKc&)w}* L/ mȁ4)8svtdpuEjKo0,to% Vĸp7HGp:W:4׃Z`4[a4eGwV8`~8A<ZY"hA>K'%bݫ,u!0 PBolwNH +@`zzFG7UZBh87|3QNk)wdLHR/|2AA y>K)ړCsN0iȯz~"psc)o8,,ZaܴY9MY,{] w:p``cθ` 繐-8smYc-UƅIqp?!`ogNʞ@&&Yga)xtm |rD~|gF65J|JܿρҊo#[J"?DULiNF̨:.xMQҧꫢ% ϵ2JzIkJ|\Zku?`9 - =s6:Vk 'C6ٗZ6-z'D9O\Q-(+Z8cQa^>v㵸U#֏J[{WΡ+uǴ|<Nղn0l-c< .0*")5Q/DzSnbPn=dtsʽ5Dmaw@6QŨ>!7A#te)A r}oṂtyBBv;->Us~)'0OwBiͫ6 g9fxQ#Lޟ3?F%uQ8Ú" k/bhcy /t-:R047׶X'{i*L 9uUFi&$ t"$B +tJ +'ZCpWJ@J6TxBE[6О\hqlqp{=="{qRZ?܋+ gOA|*ޣ7Ѵ) nc`r{ۭ Shbu~Fy ? BI+539=ўʄ|glX.MCb+tDM߅U&!c][ƤR"Q!-@qƥ8\uȅDdE<,D\@䊝_`^ς3*|y8JDץ$`=j'[5!o"ʌ9P|(`j$M^~yZ7U (Sw]=ig2$+e}o($ (0 \cy &rHn/hl0e8 y|4N!mb)Xzg r<  E5&C*B"ޭk  |ʹ4+WBÍ)ϕ^T'_7 + W$'C⥈ 03(֟hsS5C-Cpfegjޖ+\=ay-+­[M9yzpN;#"O&qe<s>K[7F3(kl4vʹ@__(۱ ̮rӋ8l W\!Œ!:2³9x^ºsX\t,cYvƗdJj8z3JL +@r$RϨ m"PB y/MGKB5L`"eތD'ad_Q5AJ{8c_uS^?֔Zt+G!E@&668Pbu|k+b>WtxJrEKZ2}\_ Mġ΃a3U4?BF;lwҒ WҮ7}#:%)/nByȆ}[cW{1 r( ' U*sT2a”̯]D D GQh<~LbHH#E%t;ah7ܧ3Q1"ɚ?-lMBh|P K$Y!I[r"5 ^N:Dra+"jl< .ڕ4ہ4'ѭܔq\$ Iz0%#;Ql(<@!yEsU}3tfHjr-W*JRVTJTxɳGDIR>KZ_>=VIZ#+gZC3ƍ` +6hS7fuhmp̉-'mtB=b^Ke׆֭Ap)Nm[,HV1tg>>7h%8(.!^+9>@PVcl~!*Da ~~8>cH;!d3Ӕg ٢V4iz̕tJ.I m[Ҹ's!~5!D +q*0uֻ5:Dي6yAv !Kw)QevO+kN О`k Ψ%f\k GrZ$Pr˨4]ey2fބP&)(\[o/I2[=JJJˢg!)oXD 9~_p۾[1OF܋EBNv>LQLRúz{?4G8#b 5g"N:i/ qZw TsOGv*XVYPm%)ke3fWXsk 1v]'1жz-Vk4 V\L%?yg)DO={[Ȣ'y+7mh*uz;_Qq "*By&|#n!`G> G;o{FE;c"P+at^[Āu}JУ=_)[٠:i6{*i\H$z 4bt:AfL{H 㴁 Ʀ!GToሉNoWwn;DmT;L>93p"Tt\2DHQN#8Pi_t+ ˆmc9pQê'ynE6̱]y>^ږ/\2P&Ghk{oiAxOq1Vjn\:MAc&20ʛȍ,)[˒y59OP_X5~Ф>c?X. Β'(szڟ;usxx4_[KkU[S`Ps[<,v1&CmX (^ +pdTze/GfcPR`V6%Z (d#籼<]6([rNqR>W BBw2,d rD\$8'w[Ln/ݦ}1܎gbֿΰPT5<8sTByvWeR>tDh?FFy:%=Ŋr֣DƒOѧ#B[(mJRKjCK/?2TQ@݅uB.Hܑ. + +ugNC#CR'^DuF$gMq/T@_uZ+%%`?RfSP7^I/*}s:GR vB%ƪl#o*m!+_ųK +/vv*g(HRTߠl?{)]̸04MA\FaV [ϛ,+Q?Z3beH8G 3:Xd52xW +cEOTjvk z;P?ED}M<$1(@G'e+1!"zg(f[q&eN4DQIYnG2Z|)0(ks֤ edOFE1] 2+` EQ\&}zOy@hIT1*QbFY '2e +wyP) d޴>+,C~G< ^ أl}~f۬@ؑ}vIw>7Q;paEUUqw[ggy0"~?(^GǕBm\H/Qه@v(loiyS@@uHwgjmLz6dn z׋eY08[nWYSZ)7Uvtʇ>?v%۽*f6T as1ڷ)ipD#gmbC1nhBfU3MyM[ufXe1^%kDlMuRyNXQea^ѝ ~q@ b״a(*uua(vC+-5%9ZXrD D/˫~ZU;ϵW~ž&hX@"SD"⸿.֝ Fd܉- 6%y_.ׅ@9~0 SD+G}5EGLY9 ۺԩdtndg앨J +^A oEQ~GXMXsN0kyƨ4@A o +L PXb.I~[ |^'F +kF&v'Ib|;Asxf3W87, &<@#p +iɮf`<1N|,7i$QlhT> +a6`sk?GA~~̎ȟsxY7?7qUEH}Oy|3ϕBG bBAv1Q̬Wx>,]m˜w=s|a1SP{p-RV>tvU_UxP֙)/(i7#GILnv+LW‘/z+д|6k UϼEk jASW+, wk:E LszAFɣ)$sd7^))|d:aUµ#ke "$L cxKJR0W2i8Do' jSnPFԍoRT=dPV@jG(ۨ8(Qկ:#Kkֿ`E0l@kbX"(|О zF~jFq4+6ķҍ'@};޶ӃX&ْ@IU%KRk!®li#0e0ǃNx ) {VFFg23|G8Jo.~zwZWFJVd Z0AbG'~FA)_GiHNNHqPtC } 8tPG8rwہ#Z,\D@n(#S6 +q㺡Kb"Z;؊lc묏zj_}oA];ڷ>ߛA SJu',i.p=Jx|KIx/k̊bľe" q<tҟ@DEit;nhK"(/Z,p(&6MG`eٺ @ġ&e[0T5kD1dAe@Zn0fR6~t +#ڶJB(';xfVͲ-=1`NHÈJFѯ{[}"6Cwaé~ ҁb] #/{n3aSF\0bhg^%co<XBd=r8c&:^sW6MM LF貓iepu2[C$2uϾߘn*3;zHjR17-hEJܠ¯Mjc#w L9R +Ɛ7&&es(Z'Bl69ӶI#u %;Ty;d +ZQbk]N *o_ 'n= Sɟw` 9W}Ib&csL湵 z9|ț#6ȟh9q% mO񒢐tpt؍1$[CHuሹ!J'.  F-Q`0[=(,=پ뻔tb8*)}^b:қS" @Qh[Ѱž3ĬʡiS'SƝNDֻȫ@/f.03Y/NcV[V!T I,#Q{ۦ"f-&b2ȻkoƯ(;ExqYhIӧµ*"@"R^Դ+7U#:bmUZA41Bl_i"{Z, ÁTV1 R"Nəq Q̟2 Y1E/#4]ZWGD*;RH8}DQ4@h)P(qqoXH01 ⾌ { 13h. ִ'M]\)?h hr>zGf +GѱGۖjRe=4%{~ڊ/epʃnݳպ m䝫 N?EMt;[ΥJے9Vz9>,v7G M+bՅGdڊy`%gҲEy@j~˒d0QVZ+?z „o"H} b1TlZtF *-.) (2YDږ@Ң lf~JʽkR#L궯(F -' +ܯ"S||ـ{3a` p?OyKL֞ 6rUHQ⏈MI]->x;'·Ѿ66u#@Ó; +8Pt01F\oӘ}XlA\‹ Sel =nJIyjz#QִΙ[+ 4=/P<$mwHI7˓Qvy4eNW\[ KvkƏP +Rβ~yJD&&UWH)8m &U!D/V`YzhD1afω hrzXx6e)=3ۀ9]o/'C1PRNG9I=9k1dz$BNq,(H<,@(ڿQAyB-'kì f{YAV5*T ;/Տt*0:u']:TE;nJGtgSfWQny4u:Rʦw.=8uL!Wmu!4K@&tݚ׵u\!Z|ʘ}1wJܨD\W(oJPbbi R \ W)iGUVt_$lw9;ɠ 'ϯΉi&Mck=Bя=X8!n$yC< c26>}Ԉ K-wsU9[ c>#Fn`|p|q~d2ԸdNmC szf&JS "5^aM|Y] 7 VW_S[DT Ro~OB|(`;Aa~8Ej%**%DtM+1B.^k ڿ[m4࿭Q-&$<<^B*o_ ߹Aqc&"ԙj,PTSNH̋ qomc,ʈ#J?5}dD ce.{+dd%Sh=9| uDl%$R+ YlkM F>#nX+ᐭ4_ڤ]-Lgya'7T%"_(7zuWsM)<Bkq]mV>#8^h1O[}*+Ü-JQF!/KzCڹFL~^0 ++];J>S7u={=qϙ#)yhPք9"!Bԣ'I\OoX}uzӷdt$_>}I2XĐ#>Nߣ.m|r5[SYYYQ96U^?ϻ{j+j*.ҽ!O:~8Rq;DB($Xfm]aJI uߢΕU!2n0+֩63ۥ +Uxg/LE*FQi2~ Tm>P(8٬5[H<fD+]^8L_4NjR ,ij\߆[5(H,>=%bv:w` :7ftWZ|w(T"D|%DX%QΑ_qhHC4-6Tɴ $I[sRa+Fr;l )⇴.Eͻ FcwD;܊`Km;v0RVeEv5.+(M93"fFdE(=B +}i٪7֞$ϕZX=aj'9ĬTx¬[C㤠Apl7,w "\J0淒[s4hղ Iv~OfԞ`?jڢ jDccSA0[^0O>nߣP̤47-_ɒFHuZ3/y(ߔnxdy|9R +|Rjx +x~Zib-"Mb'+h#nB=*$ 6c>W" B,/^ʀ(v_IDߢTi[Ɨ:Ρ/{kP E(.oYӡeQ h 3ܢ2k1?&u)Q&oG6(HA>)>D) R^QIfX++ pۍg 6+p͉1,?c>Lrkn[ 6cED ^:J'Se4JcL\ouE;=;V@a!h/^{D[2oQ قR@K^stbnn(?4iN +a,-sZ6gYEYP7;EW빏Q2BSTBG`k19U1ҲBb!vn϶ge՗(ӷFؠ`K!˷#X{s W2LfC\qtܫ3Lk:2 +sET4-=]J(1TjbC~]ن"?JF˂3X+Ik(?$ز +p#1Aڥł;L]Onz[> =pJ2s9UAu39RM8~-TQ vٿXG)J:dY (Aw\h_xWۺ,U_36m, )]9_ԋxa~+rCy\n,V'b8b)1"Z*[JDkr*XwĽ#HS2UJ|:B^㻴"ma t5>)FV5ݗET}G ] / c}gq_逜K&tZ]4D3U"_eLuX4>'10#Xܦ6d{gc2VzpJ[9-6UJuF V~ŀXQ+(CsݥFC*9ˆc6P ; -k*1\nSoDBF4 +y%2ӡgxv+*s"䝛yQ5Tv7YֺHfʩ#D!#^ŵaθ ajS'ڀ 9]ye{#%*uՓ?j]`Mi}jRv~ psXB \D~ ܃v\}6%D[Ty*S5C1$b>8~$;eXQ -AtK% }nx8HVߚ!PUǠuZ) gminO+Պ &Du8Dì-K" &Fln4b: `Br@! +v54T&vRtZW>]`>]lnQElwusepxԕ +rZ}5Xmَl6 />'gơre 0A|RF}C>Z +LkGzȡnѴ.4@M[/JeQ[nr;Ծj05tybsS#8+jL]AU-39M;g"*1mrUekmGq;^v(̬\okh\s*þ+|fJ]oW51[aaiQvL <ܵ5>Vv`$lCa:~-+?dtr^Q@{HS 0gd/)( v|3Ƕ1w9!d:%ލsA̝ 6##l%$ ^j7s.1cȆ 8-S P~:IVv}c>-y;/& m>G:7!]4A^ꏪ{`J5HS޾y"Mȱxw\RhڜFgdk\" ];\7J e.Cz%|dhSG>0 pJt5Y!]Az#rOx%Y3. t@`Fd`v\_oquvj_ ַ-e@nZoDWh(2`N-2neJ}db44֬V wmj="XZ53m{ϭ#Y :^_ˤ_,wu|,gRoYۯ[y Nu(4 + ){-c}aM=oQQpsc^蹝#dZx\k=yN.VgڇW@;˞_mt䁱MVO5H]='6ۊmwCдa[^YHs$ۣ $JrICzY#"ƸR#R)$Q-RP9PڱIɅg2]/y~⮑:o^|v}8t𶗮QҺ&9qđ hsq^eGqxs83N,YqrpSfcL`|=QH +\o}lom)&̪ROS*R褏-ǧb-TgXU =FKH|mu#?( ^ =oS2 G/.iɸT'G_._K³.ε`l{Dn= 0TjJjМ=sz[ȝ;-OhPX.f݈ Qm_voW;@ vEMY leF|͹\d֙@WS`1YHa^"62mQC7z-! V&fGDRJW`I!wVnY㓤ٷfg~' +6G rT̑*m^񜹫 K3CwDY|Cnӏk XoRyG`.h{xg\TC+dQi)b՟J{Ըcp ,yؐu `{F˦Υ|H>ҘXjWߣw?4s3o>(|+ ^EL!-A›!R06Kp ǩZ6/zV !x|8 + дb'*_DZGvjŭ;@}Q|qEa7={_WFQ8K5`'|FG ۍ#\gס{7> W j9\) m;'%qODS)R^xZpv6IQmjYEkݢ=\ȇ>H,.C9az p(5^qM$bW"b-#{6vݺHμt jMMBZoLGV +pXމ;{qmqU8(:2: X)1߃]iW+u_{Ί#]-^ul }hT41^C"* M z%/#Xي,Q]$?,Lޠ^VӳƗ +_C^Ćzш_Ԛe~e<3D Z uJ˥ЉuS2g4aҢ1P@ƦUUv57ךݰdqݟ GAϻd[ɡ\Pj0[)C|w`"\ "5&)عdK6ROlBD +Y:D"Q4Pl<\`v6DĿ$yy` klZN'%`KϢ_1zu;k5B"xyfPKa]J;l&lO?^Jϋ]|i%'zHA`W,0CRw.4.|ֈd JU#3O-VdUU8X$ʫ ]0 q> 6d.[6ǴRm6̸\|jSʤ4L|us:DugG1Gi24#ٵا^5?؇3F C?1ԏjLQUㆯ8JQWJE|swY ,uf>Sxo8_6gMzslw WwY02(W#F')ggiIkVpFL%om=k}9ғE%BoM. _2umukiU\{|{L|Q*S`n[zCBzOͿU{:hprsO\H(ы&=]qA9":(6XC,Mn9raOR%#Xq;RC0XT\dHUu嶍|֧QT TAHDq 6z +A mnUxDc(,QMqX ܏sp a5;-{(=OM*NM`P;0&Ax!v?-hȱh_98cX55yiwE6#׺>(5߸@EЉ.׈uo^"_vШ@\>s/w//Gep[_鍎uȹ#nwUTE>jM>r̤81ݘTh6DOu=N&F#Vƿ=G':DWiSEBzsg˸v7n>pggDx4P̀GzS6bƹ_xc}#:i)Qפ|OjDWqN=hrͲ8Tu$u(vt>@D:h]h+~bz"@'҈&3p4If\?uC PO6Q߻F4܄Typ[8@{ETJ#K.[Y[y*;*iܺ5)i )aw5q"÷n3 Ia4ShT'|K"Ek-V~r*T+RfډYG dH:ʨфj&-TiݣN~3~Bn6)ZFqnUl zbDu:"07O`Mj`#8=./,Qu$@hE9CF4h֚YUxS6o-^b + +F +:2R_ysc9py)TԂ-a0=!js{Hny$L.Ub;EOj:Cf=)ld?*(, i ~-w:@+1'TV_+<Zr)@C V9JE3 +l삙%~j*j ~:9kC +k?nɠ;m0rIkk#op+|26ٵ>le6(8BbNX+WC'ޭWDhT<I %m\@tlL(yg[13n +a kP 9-[T@hz4@Yl<ؘ6 Tq~Rh;6j3bAo! p'c #kycUd+.DQ;5F3nXt`0G@^\??ۏ;RF ;0n?:S|JAR^ +r0X4Cm;2h ;uy}HSy&Zbcp-Q{IWn.eߨK\thQ5W:Cx*TAeo`X-8 03ZNk0_ڛMuN^k dG)׵y޻$CzX4:HG"^ݪHaHanxs6@,Щ,/ƙ$XpW +xE)6RZ֡hGFNΟsكY0. E;C&WH4 J9z]9.DɥP[kxTVdPnQP`PDqwWײH6QRxuHՔH}*Y}DD=TT,QdiRsQIʩL o' {0)MZ$Oq?>$ Cs g5}v&o.D7`;gW9૝ PEVjp3BИiv2P#Eh:,鰖2B?sJ` H+XGpG kf%'ұ#gXɤ9Bׁ`vF}ԥRS\@ќ舂Nh>qEA#I8X g\G5 >kȴ'|:!B!=EV@ꁎ^k?. +g{ovi=ԵPePv}O`~)wҥ*ޥ|<Ԏ` /^Pϳ:^N;/)JS!onZ5یםu;Fb2seDiED\VmV#2-< +.b27_pmLh"y&Ȍ S:Ucګ_V"ɹfJ]S#~xo]8BW-LVBhzFI@TfucL_}l;ӭ>ljϸQeqr:֒T7)A{F)F'!\ig4ֻXeUb?G:.?,WH tTN`Dl#sWT۞{˝B%$" zTwwcYTg3%%"iWձ8H4l­? /<ܲ`<: + 'Z@H)ag|yYwDY5;sX彲]ɜzo(\A!c!P=7e3fַn΀rNg]- ]~kRac\:{,11_AW'+Lf*h\A#k+[Jn^4ib[ݲWC8#"QꝊUkA1z,=iH!]cg$ mcb-eD܈4f}3Nm:9)O9Ѱ;3בKJq3(6( fDSIEjU6LNZBhJNk҄LQaN86tnNh;ЦFLEGE|{jCӈ]\=ɬ׭YLWHX!=#_zӪa CLR(^3-( %ps[3+$&+lϛLjH`=+tzw U5ʝ8!幫`hS@YBra1xe +PRԋJzd)-Uݪ,|Aד>۶8S?8cԢTgpdɵf=Wh|}.boNΎ d: +#to Y`rϧ *0%\p* \1p VkB']$ oK52N԰JwJߞnzR~mg'zM+@ v>TQspfP7"#^a(GS/[ʺF 8Exj ,K&ZcN"JC4!-xgHwdr ߹y}AA; ,{ OI",-r#!JI>RtO0 Jx%sKgQd I~9T(qPD|PaIjgúy[:CUKV,gɍSޱTz8`pP +1 +8,=a!P,H3sb ñ̄Jaf'J1s LCe +Ôι'64JDI4T&TAc3Dhe+l%k7]Bc uy5*aUu)冲>Wo!Z5Xd}0 0/nQ:ZԜ3^ ;RT9P\| F P>_YL%'k[C6dAYGk xϑwo^2u'\HN|G]-n/Ԉ׋g3X* sͱXܗ%huÂ9SSdh`.G[8Oz.6 ͗(5(gU6ӢueQIlZ$4v@CuB}V*k=!݉bG0BWGA!V1$hCTTkT #Up$ti'6b5r"WU8R[Db_ TT:s @-Py_-r%!km\0Yxx@"H69\XF0lf 0G;3Fp(Uz"ea`vۀGv-ӬAIA,ֵ5i4ՔK僼j*oʰ~z|I0).%2QRHƒ%H?qEV)ȷ JDr]+`O8\v Cpg,f? >4=On`]%Y6l2KkTD}<%Ik n8\ع*Ȅ~`unrHL C бu+:yowy 5#28<0%f@`Jg>E H]Jc"],5|8rKOvM~ٻ[rz|a@j쌠ICDqcqA_½#vyid5=jkf  bMF5;1CUs6oVcX`LlWk-yNͤe]CbP4hӪ4%@׈;3{ZcG"ԭb =-CeJ7߄ ;˦k>0An Ejd/tb*˷% /6RKcc˒ڠ, 1qU( TG?w +(˫OV*a OuS5N~O*|39 ,A6f%^ժ\#} 6KdR-hfc$Y5O9$%$ >cvkVb;m28MJŝ3>Sf^a-qpz'U=;8ݒ ^J_\O +͋3K940HgAmKAm\όJ1PU11ףb~QdgJFG1d$k=s+)*#Pu\ )vBS+Ai5 +ӾJ% 2؇s7]eߟQ(ϱd1/aDS`3֜`OwPFRJCl@GjGP#0?,>k>}d< tr`PPgNq'RB RCM"ۯ, \ vKԭ[4O&vxCsEIsFwxtymG ,j,>Cc0\[X iEwBFqk"l{,=hSi[H2G1d,.' 4sz,-E/@+M+"|0BjB=kMNab|P@"nBU:=/(OT|3 gw8RV9~n'u\{ +eϤHLK:Gb;,[ef` &0 ATq}%u7$w+-^ =3FKumg"៟ do q0anrܓV<5lִ؅q +_{)EII xHTMN(ޢ( 2w ++#>>W6kjahbڐ+(zƮ\ikL%9CP$#g<:ҫa㰒N 烶)WDM#XΙ(UF-د#Q S?> (Dp_rg'W=UbĵOAx}w87[9e#~m QqF8}[u%]@zSVyN =%'M5>G{мPX0q-8d1znEU^)bn{\~@Xdr(ȔzUYY@ +G-뎛k<7( (gY32(;ytr4G^`LOVμe *edXS6*`mGH%-o>j'o !bWuEQTyI#{{D*V]~\ ZR1cq)r\h]6GÅ(k$?H!(j'GXh}g_-SZnX"Ӌ17*k  x(*X\[/ĠA(I%1xVګm.UGd֕'UbœґT(`ek*cؾ՜IA ^=HvQG~zbm Jnмr]o+ ek/8;B +GA*gPq:\5`(#^DAc"9bllw)nlx\?Rp1ޭ^ҼPۙU֋᚛,uivrRͽD"ውDD8<Jl.bhfL='"pt*Z*}7%s}/͍oQij1k|oY:]~@ucuk-oCI-$u*DW -v[@tr](zzA5LP-IE׺"D/;`,bH=i9Nz 9h5˘X1*j1mɮgz[DgDmqآD8X)2@|#BFJQ^ߺkfZ{MSSe+ t`Dj_z 8[]/QO}C]6D譕 Ej:JB(47Aې*"{PnkPE6뻂b}kugV{? g&QHJ +61fR tOQ1q.<QPR>D"濻;k/%F6`a}SVf'Os@mR\=Q?\Q^4`QBDsVujShx%ƅXXTO*di"ou#YvF(!p%eK/G@-4g ޻9j.u}rѯ'?Eljefyޢ` >V5~㎞ҋ +뺽 7Jsai+eОA$ߣ\CL6S5dl;E儢s TG +҂6Om0P@%ůWzOYwDoOH,rQYr~j+d&U^/V+Ex5%#9#: vᨮ fyn~0t3@W"%rewz^,V{3KZzaDݿ +5F½PXwBOC}3NMv;aQeE\NA$@ DnaQ=< ?粈BB}5nG{:Yq݊0L{\R6bgL AIXgK ئuv.M#08mrn)I8.F"zu1sG +?VmuP-fsx,ZX0b b!ͰH'Mm*/.IRjhj#[Jples'Ac|Ơ ؤ n8V"?(9"'GQ?'l17T){ւWt}'\Z4]Jj^t(kHPJ#;I8޽‘K3j*'q)O]x_k+=O9rZ#j -Ad3~QsGBXLlP-њy2&!M{Z}K ?Iq"Eis>B+?vީy_(\ޟ:ۘ2Bg>bn,0OKw7=ҷOm?hYYcȩm&F]\9eG^~n{;]s_e+kZ~E|9G1i~oGL 1F(KbJ&ME]Hu)Qa !Y.*{o@;,.Gb(5EXyZF2BlrѺaa m]pJ?%ZBR;AUءu!g&+ٹɨރl8m~BADI"b}$&NWEDP`DG9VKݘI7 dj?b[3jzvCmeӁZF~.wWp^<9)"+m.{j\ନ(U VzvCvs 6z{g,Zd)B3҈FQ.<_9LiO5mLdU +¢KN;qQ5I -H5! ˋ]) x|*dU$shb fa3G[w0\># u$)2Yo׺9@fdا`kEs@A*\U^G̺j sk|ըͲmyӤ_8x.n< 9[k +! )ya۬ꏞ3J%$Ċ4$ҿu]~;߶Bfd>_nj3%'OM GӸ*EʤIUDxCA?범}?!#n#u!%A~RZC_EZ׭Y hŧ)˨ޣ_Kf/*.S<~8XFMA]k-gFhޒU׹)=]}'2+,JAkwsqR\m%3@' ӊLxsxs [z幙J\wY)!r?pgi6ܛM9^8UuW-~O9}#|#vGh{{ƑOD,޻BG: n PCT@U0JTبܩ0o%kdaccE޵#R`Y o㊱U6=]AXx>fe- d=0qƖa[JL4QrWI&5(AMD~*D"8^)XXLoR:?G%!ejEcW>#˕SP/]q)!jKKƨ3ASk ·h72t|=/5go",;{D&3YEwAG>%J?lpI^b1ɄoQo"`dHw61ea(0`m?\iB .DNrW +u/e}=}$dNxEX +drt*6ѴMq7k؏)GF枖G#B($FHS@!K: cMv#<|˩K۰ +76)WT=AgvI584|XRyGFRnwAQԾZ!* Q|p? +àw~n9n5IHf'(p`ADV4`(%PėQQoHl¢IQS}^5':[=ɏ׍D"gEy&QG1'K38kUm 45 +bv1Ζ"Bc9dG~~^zr103W *аrqGgOGE] ֶ$*L?O̿5Cc΍& sK)bep)Y_SS!\[.cny~В`Um7}#2{@HpciuHS 7tT-}0z+BM(g>;ᴽ3cv=`|!kq)):b/-4kVȳʀP,, Z$SڤS)=N9hfuG܉PB4{4qO(YbW((F#Y&o +&l{{ȈnAuEZ#jH5Dܛ@u#`@UJI~EqR &uD -lGVu8tHJ>Y֣}1bUdq(FjЊvP8\Ik1y hiY#@H\ ]ǠƜTJ83k*iU= zh"M.݉+S&9R%Qc߶FQv(9I^Oi˷ +ӆeZ𥢈Qdc gyFk[azcɠGQ }t8**L^A+Yi:oiT#nLN>G?O-\Quv&t xhJ;BAE>"Ѐ5}MZH +R1;wYG0;叁ȱ\ov+i82`^b YL1QXadssק>L],bv'F"ڞ+ij0muBp9ԍ"u^82m!LrhK]";șl`q|k3HRD۽zg؉W<֓oj[z|-uw y 0 +ŔPzl +x0B^fm~rO=-Qv +2h@&{ƎaӀan'Ǔ3 T0Bhs=kfSt|FdY|Bi]쩿ҩb/6(g HvļZ˱m`6b;k md}߈ke9$$ Z zm}#@;Ql,!.kZjεntCUۈYm$Q\ZO>PcSiuwٸԓXʱ"mԜ: (4p&XA,[H ;xG#I\Vۂ66%0 Fֆ,OQBTgJ\V,cNOiۏj, <߰go#QAaj7?!caձE+폘y )ٯ%FZ +; 9kh#Rgzt o͈+GD 2KԪ{bح[ +D":a#DKy [fJ`-@3*vSSul$su,ׯ졎jf:or +~En jJ8$ 퐥c#x7S!be݈{?@3 U$>gms2`/% P0"GtTិ7qkY,~`3 +v\g׆ +7|g(ۙqLѷ_YG]ל)#-)죕 ɷ 6,Z@M )UGiTʼnKYDuhvG4ϽV@g]#dJc=JĜiI2NJQyTGDn5[ sO;cLpscݑ$5azK 6q8%(|I2ہY~Pvz6ؑj ׶%ۤyw.d@!VyKSo۩kolhjJ$]ëY I6zvT"qsy kN:5Ű?2݊nޭS(hAYOn)6O4͔Ƈ1jO{4b`ߨNGtMh_|ϑþODYGwܴ殞7MA~Va>rMk4]uҐw ~6|UsK;+f L6\Yо7qR0 | CFoep +!hkau3Z_(BJMԷfˣDzR#9`0PR\Gɘ 3 +i ;b=˲`)ܪBX}p̧x˰--Ba,5_ajhNTYܷ%t +eE* O_ȍz'wvǸ橓9ÄL wJ;ND;#\`S&fO91FQTRaѺ~Hr<8g#2@K `P]pr{jnZi+!^X|xǧ~+Jvo ExKV%MI&j#==-tzyiU> +~']6Mп6ƈ yK}jY[dYo=lane,:<&HXܹ?IOܶ}Et~ +HXߣhQnv֤4YTduӫ8S>*WϯnN1"^#~aNDmԧLf;'fljذWP?qX| ~ +XE;mlQm>#9#/% +y}!'=[yS}i >(|=g߷Su1WrOx>ȣF׆ukf>osMG%7Q@c't=SHk~1HB/io>Dضj6x:d(+R$D-ۣ~kg]$niXZPuyQLUkHNS"2l:pe-Õ ~dMJ$ũ %䊀&KH8Fw( -<,.8?sJ[+z/@|}- +X,lS> P]M2i)[%:I#~!AdkޢfC3eΨ=~/%Bm(&юc|?1$0L2~F 0hxGg^P&@76U[O1FAY7&>FD9rLA[Tq@DuXA qy{D/K% /qs00=':wGqIC(30Wp*#p+b.'~ƚmDg#=Պ}x?HC?RiCd+nʒ'[ha ߣTD@{N)w{}M)cvmW4'%p8pB**U*$$ KP}s=pĕWZupjZZ+?vI7eI +y^&so52FR~D|O?XņgMMEVg?ޤ}30/rfQ0|-G:ӼQK=A9O+&q _M+ٓ\/Y~680{w^o8xb%b(oZE)-A K動e eǑ./yڔ oVYL +ToWJ3jdZC?0}XixJO>Q 4zT]v%FD(]yT0J(4`3ٸbXd/`뽄ޫF#WLa$ 7_]-Y3^Һ,N!<6˕9!sW8_mnKDH:[: 1/i>iA,=W4#Z@M+K&9tInxE_:1^rzXqΜ?L=únIL>Vx#lĭF#%z.&(BiQԧ腢-SwiZQA8`Ca8VL~%0uW3ւ4t%N+:N;[LU?raQ8}p({AcBT b$ϛ$_ʀ N ] +qO0xi}2 -/Tx`k ~5lcRa"!ȸL}f\DF \;\a]_Wa+IeLjRWՙ+\w" ~u'*)ޙ,(0jOΕod/T,CO9\*y7݈UȴmZ_Cq@Cyz@aC;\kW٩a#f +=NŻd_uׅ_qؒʼnt\~a,zoڇ]6<딧lU;/U/a^Ea֮Hl>i:@3AM3t 9AT;Meld'y&Q( +Ayb3 2l)^|Wo_ylqp2 f'EWCQ$;@:Ԟ%iS: Hw˧wDȠE,Xz7쐃6&o/JvܔJs-:~^StHB&HôQY4anWI[iU.L9R| ٛ`\_A&=_Z08_˝Q»Qd Sg1VU"n1^!8^=. kPqa*pR>5%Bq`-{EL]Wjdko=Pt?b*i:^Va`/c#|KT<`"Rr#Lߓ M^47-cdp9t3s<0SG,_# Ccv9m$+2ltoD׿텈4w8(f Eᾍ;3UϠ#0OB'VNM%n7ړd|]wyz +R!B>v9/mX6{?ysNNԢh05-|@_;$?}'2a7֊<*,s}G < i~ +pK*FX&b91 o-@kA319wy2exq(+2ŀ)&"BJ,ؿeS^1 DZLQUP#E~ddr A6|@O!]h;m@c8@*kO@3 x:';DdOgoGGݢ*QEu/K?1Uʒ90{Iώ]|*}я߂la7Ej4i' :cfъ8GKK|Cȅ$"{}E#6$}Cnflw0vGI-0Uٷؒ TI1aśN[>*"3efN83O"4 +}`Q}N4S-Uuv2w:;%/Llj=R¾K4Ɯōm j32ZH '?pid`P H V({m`j2TmKp}Y.W@%ZN+ǥDi\>^7i!nZS )B*+ZёRItwrf}> c\M+]n%72үlȇc\NG"%1l$SK-:0{=Uv' Ⱥ'הg (SZC_"DRIi)o1l->dKȅy.zW-{)O`Nr.u.lG6˯dƄ֫pl9"ky؈|/fNN9FG*erݨ̴K?̂hli"qْ1[ Lze5 V!i]m+]kkюBt72\ +(gxìңt +&U;`!D>sd)~YR#IpD `BݮCVZC$D><80B@f2@+o<gD|KW4cv $l<2.{S jXp]Wp$\2K>0PWDd>yYJp>V PaW\r}k~HCOG Y8v0"4v!v![%e؊݇=[߳u1z_^_SQ +$']kpJ$76FL4ZKV^ uPk +`@|] +*p9V=Ua4Åϴ1(>*ڨs$Tle4FZ &4x׭}{G#O!=7DEʵzjJraM|fpS+W}2#2+3~dAqjvijlljHɅgLd'.VK\UyH3.[SUΈRD>tyXVued_zߩ_RCyVS8OXe;HwQPcaэk=d.Z?EiO}Hج@tW '\^^*ˇ<ۋu%|}P&A%Q*-9:G)/ʓ\R z34VhCMK\~ o0bw8A#}vtev< ۢ/#Rϱ*Y",)VmTNL3<2ɖBZ M޳aAvzzL TS/H/{x@t_2#āň/EzCšƬD(oYAt(`?En5e k /٣J'W&Z!w=G7Ox[,NxBjmQ$:G])1==THPIpgc(uDiF&9f/V +oFdqap ZOr` +xWpxwl<S@b +sj ;@喸z$e:nUKj|DWn`6M^]F$.^VVDQn\$b`GH#@Yٛ`t9*9wcP}B=Ngr8Zbz/]b[pz +F&߾ +RVy$yh{moK +4'tTN33/4"B:J1mR͢JBs72c1=uVMNiN*䋜'b,u I+f|y5O*SBʸU4d-L;F ,sqtJ؁~sxb:D}ZUaz#o#WxSC?*ojB7y︹.c]&kr8Α2eѢ-_DviO?4R +~267F9yd4<{Kiun"Y[^n/{)bt:N#ܛ,z*3\OԜ1#BBنsk&Kk=h;Jy@g;DW +ƵD_k^$ )Cv\- [ͪ{/3RqnNє"*k${IoJ~ \DhbjDyJ,O+;* tQTD0ˌޙG~\9?U%uڠ3?rxGiUb@RSC;=&z +eJţcGe_uJ^5suE󍶆ŠQ)|KGIQYp*E@eq %V K/Ra?ꨀFt4Pc:׮tBy?u +r3}J +)23$TyE-t*ϑ>=liMᕪ_8a<֋LԴjQ(*PDkðrd2JQg.SCr 5'Ay;t,"눪C#ȡPZ +*Ǚψҏ(p&#]>4R]Ktm큰E޷/X ^ F;l!`7^^,Q79.WO*4c-IWT#̢St 6:梁Vg?IIڧ .Dcc]u D~)co.j%C +XٽOX)lzMvψ{AsJ<[Nbg~0@Z+^2XSIZvHZW!Ո<{KYV>g%Ev1} b/J3"RH"(`!|`NA;` Wn=c*hUzۓIcE#c0Ej*ӽǑd'3PtYWynoiJzGHZIϪv\j4bdXV+-xoB}ԨTW +Db=7Ϭn<؀}ʾCG[~EV pҪXy H^F ̬@/s}(rp$W"e`(ѯHR8|G +%_l o@usw|bAک9MD7rjqeIcP,;3/˗5{V9_Uh5 + RzhjySܥ= +DV l'p#7:e}G5%V;c&0 6/Mv! +#[(b,U޺eQϏPXӹ +^n!-ꌩO{A>N6%*/Hj@em\>ܩ (/8DX +(E1i9jM>sD *c{{^a=8Ȩ *b,રg1E/Skk$iE!׾?'1\;s@xАEgM5?־7,-skWe]KҘD.@p*/(j#8'Qpr\ɫb-Otv+7VFyuN+mF_̠e^ yn/7mHD}GMlz\IT#?*: +R\(ic5Q$ [2%agzBGwNLWUNzμ^\=V2aI=P,^ Ap@ +[ٚ*5۾Qi#; + >qݗl稿WɃw`4CԺ9| 5+J(fEx $tP,r;8 i6- trޟ&̄G4mSs`2P)KyMP_q? 7FWAWIiu&BImg2ip7w_dW9+tV|*#nGݢ~}a|?|ř9x:7ʇ5q RD~AųBj%; C"WxW:^[k?y^2k@ǗһYnW&3iTop@e@Z[LZto\#ʞUgjXB}L9׌ɋ_SwQƝTbLynC6j>x8@8݄&Ӥ]- +Zpz䯃QdwޑDWՐ("5qLӑ xΈ4ţ I$$/xS @U5旘U!"X; x}y%POjCJǚNc +u0]~8+t-s`Oq8n$f5# ̩LQ+k^/m" ,CKNjL`R~."j`W?ߋb|I@* +M-7 +=ڻۈ ++@ h_/D$U!U =Cˈ43D@^筗 Td,yБ [W;r% + t0:Uhsa+PV"hzFoRjSH")*w'T9U@2zLA~vy,N,Qng=PFt):jR2 3S#;%%;J#_[/a$b܈w>냴3#41m#Qt_S+Y֕.踄D̎}ԃ?#z wZD%+ M3;X+M@qc5q}ppk 1 +iAZ(? /R7rCA7vsMK|^lcu?c<*3o*?t%*-;r= H`z )K?}9= u;>Jb? d(A es8=𼮶ʦߥb%Or ہp15 *`QRqF'~^ka{ۣ|DLJ`oJ+u'.W OMDΐf%}(I+G ʟ<6(z@` tPyʚUhe3R u\Vv>=|v$?#Ɗ?/QQڗp:JQTՉ,a>W4J@i~xWT6ŃM`aIIZ|?K"?e c((0ʕ5iGa.z,ezҴd=z0(8ptyTY/|LVWOrKR:w);y^ Lh>^RR?R 9 :k9ݻJ_ˇοǾ18"SI,O(&_B՘ @*~q +=.=b ?5 w{LSpbuK[n Gڌr‘tvv4)`|>j?Ei@|Ż}%_a(Z;H00_ +mȍ_nE ^*DɊz+`79ԼYDoԾcS. d<>|e/(f`= "SEwU ŒR2Au7Yʮ9{$f]x; b* %ꚬr8ax/n}}iF޳%`o:F >juԣ:HT׏G:vVޤ\V> $F> + <](qT.9=GGe"WYGmЙm;Ee2SA4{P/Aއ*Ў81h/ՁyT5<y >,9~Խfr\( XeA2zvУť/yzKG[ۈŽB)27כSL1 ԓI  3$(ȹB1bvsx/fHPtL:@(b^5LortyLvJ ꊂR~U:7|5B3roG@)AL6ia]< $"~zx?n"<&GI#t ]&D>ipw+5v_5^iOU nwAhyan=QN`_LwԅGMWYoBaK9 !Ղ&j/lV}=š8A}UC#rqJ-zQa1ZkL>^BRAv +d DxxmfB<Y!{QhRd^JU9 p' +bQ3MO!'4mnRG~O'b,p!4) 53A{C*b"4LW1yNv_]hx<{;Qu4GDMR!}{tBl|a :>֦9" Ep`ȁ1€CV@Y1?DGc6cbDs-td;xB~>}P|\ϳ8)jAD0CD<{yLqJtѦS\ޟԦ% >;K= # jl%*}ePUEmz7R' +a1+UȒ]YpfTԳ6? s]w]G,5fR2RӷM>)@ЖwěJGü]Oi0<8=' ሤ~ JޛY)ĀkOaNifO +Ffs45ԕp"J~8O=DksBo2_iצفVpPb^0+ȜEa_iJ:lpc'#1!N;3^ /iw_,f+.Df`rCPY__ endstream endobj 46 0 obj <>stream +X^yEԡ s|s3Zj+DNq.))4XW Z`ACvUoHՉPeib J<z`7pκt[fwC^qwAxhڌSxW9ez+]ܥǎ.}nr$`%" +) Fb0“J =d{NkǧZbu"jI#ʭyyQ-"vonXiG$@nj)FnuЖ@nL| A7>ԅ(KV{;x]g?XpK>\Gs &QhcB rׁP9>0UA:4A?l>=~;u.%egGIm0b6#}i2ꋰ"#KL+@Ne]RIygɌ%z0w97ψ)]nDgθII6+}BM s`0$ EsugdS$gD#`;q]:@~]OOIJaS W0 oMDzV;[$p[no6N aYd:3Лtqי :B=oNgei`>\KM]laj9Eޑ<l9!}*ß? Z M"VQWQ`\`ٹQ2@t:aMQ5)v7< ZDtDU/ srHY_NpL鬯ri\&`FN9JyQJ8Ì6.̎Kƛ4 +H3?V!8Q0Nw.Ph kG:cW{3(+$d<_Ee_Dו^@ n"podygQLo&Ps?z)*?+͸I=:j`}[`6蟈R苁i8Kfgu{]8l"csdJ!!NN.O35y5:i~jD +&3C@E՟b ߗrBQ[Gm(u <Z.: ( %`Wx۠g$: dG2;%l֓F& *=둹4ɕyJ6"O]|y`U/`\-K^љ+ӹg!=M.K}GF|gbͤ BbohrSfS ?ҷ?=owk|qRsaq[C&?ɩgY 걮fIbx%a'U:lڕ:?D ~p);mfL2Lu_aWȨM7ʕEx&h( byަQǨmO⫹S5Q|S zxRU|B6fDyש2LMD+G#QDPMKQ̝{Ȫ&h{9"WC\0,s JxcD=䣋>ZZr=,qD/Z",BVX.|5ɜ]?3av.h = t!_?E1BAavAG:qz9 P )SFD OxtiA$>"_@?( U`j8N_j0'%:|[nV'>  O&AbeV)YmEV3z/M^wXàx; [#B"d 0ACKϺ3W<꒯+eѮa`D%(iddZz~2;{Tk#lwwUuEgoِŰ_ `@ HȝտG@yk(dkłׯPLП@q$i + M6ʉYڕ>J7Rc4R,{?QZڭoGXi/z35q/&30,ݙ]bf7!Dj֠XpSZp}ouuG>ʠZçD;0C~kyվPz3JuuPT3'G= 1|WX J +[Hp;jJ೐(ꈰa?g@)H;rKcoۄ4y>ty{KRn42#{mN~8K` C~A+Bܗp} kT;ζJDGr/ ZؗAGPr7"gԿʾ\yImIPb@Zc8^Hο3-$w䲆KK;gFn<3x$v% Ӊ5@%h{H,vB̀}$PjD" \Öz +,ԙ}82%[`Ge} NgAIv o, JS +?Τwr +^|o!SYH4uO,mU裝}bͰi[h78Dq_` G^j2ϑi K2?VLO~9Qaϧhjh)6VyĂ#+\o.%h P~ +G#p 2˝-鄧$Q:/E[3U,X +QpԅO60y1@`whL@#ҡ1}K Ei:=ܟnUSI+&`8߻3 +!&(TXAB@)7ч˲@>ĺ2NW[0F{geDpoys}GD2l g[|"5bv "X{2\":3͘NOQBi㈖/)/[&*;0_ ^(' VVd0|ݤ#KBCyj=lXe w.ͮZu?ze@i@|PtӦ_d_!swisNjۏS+rBm F,R9 lmWb]V 9“V. j{%Ilù_t~%' OBMGe3s9^שY"M3*ue=Q4C~@T%ߡTũ~o\l/DwAj'5y?nCR6e~!ŋ +  wP6p 2ŸZ23Mvu_QJi +%E`oVvpIGkNo ?Ix-gLĬggQ:{T.P$.!aws?8HG yq12:v&~䃴#&=.϶Q+\䏋A_<dSd{ᯫgX& 'Pݡ L4`B]+O,I>l0F$܎%5Պ4/{?Qy;+P^:I + Q +н3rZt=J8'bNR^41]A,wW^o^XDu@c0SN +l-?c7|+E}a+}!/]2fLS|3;.ܶ'_;sS~?PxgΗ:0/zjBSNz48G`P"8-e<(o|i+Q/qA0 5}Y(;mQc_rHBsL}Ul42 +[[;}_#sVnX6o1Au10|z0`{,Tͽ6}G +W?R*JL/mD9O7u0ړғJk|巌n"r+vzR VڅS85fwWrѐ!iĀkD0[Ͻ큗2t< !cRdQbNvJwHƞG(:WI18O} ժ=F`\\PG)&:^_y +ݍ +JFEX˲tò$EYE0Q0EzB A|(~ ?A2L W).% LwԈٟ bMWz5oQ`4PI_>O4"jJj[G@Jiɲ-:3B\@֧0)n#1> ־nCgnASj(uŷBq0 +I J{}4|f KTKν HRNT7~r!IŽ4~[iH]gB"PNcH_1cC ~Ws3ٛ ʣ +Hwڤ`kWyMF)sOձص7O=!g{/+pAb^ +H{e.FSN@ǷzQ] r%JW -氝# MٕE2!|=WP׷6V"Vu%S,YM{4Li(\V!o@66. F s{xA3%oAϫ7ZKwbyyJYDG"׬Eñ^ߏ?pmW*ߑ"naIa$Ċ>t +-uZ) p1P|gZYĆ6>d/oՎP%}f^ݥB\š7cz +0iz])z/.[@#n7ݵ#G9,r౤RZBb@"kACk6YbRMJ8Tv @OKbXȯt|z#l\|v=~i74\( <seHW1~ CsLkpbGPpkA4XYGǒK KaX +,ˡR¥8 S + ;xgO|V{D:u%RɾK+;5)QP_j\JLwꉈJ̶bR0"W 3K\%WAIؔI,:skDak4[GjkN5אxs +;v mx/LDqJNC%?I sKrfTK΅ ^W<Ĩyfn$*g5[9xwHPyQ48y+}Y˺Fhƴh<aƃ6U4!cdr]Zp)|TG.M)>S 'Gs9-/ʀ C&FkqOhgj +A5͉T>8i%`(3? |.)uYuJֶȫ(LDY_o0\Yaw4ܷ!Hrףk2p{i)DaX)YEF~)HyfIܜqV Qx[}77] K}B{ޢ Cӷy2UA5d?W'E8eZQ 7h! kDHqWd`6-~3q&=6z5PtB Plbr*O54C4?UPpXAawt 69bdj)g%]u۫ZK2sͱj$0N|]*lÏy/!Ž0YP[5BapOP&~ #H#Ǔr&WZ'_F8kB|P4[}/3\#B/wXf)Z:Mb!b&_\Hы܌dw8;+ ?̮.u[aa|IX ^^YZTK47dJhJpMDQa5#b~FOTGo7{Ƚhq;Eޚ̦OcՏXҨTF,x6ԝ>@]ښۙp>:0dϖ}u- +'ʤ;W +/LѺQɝL$'a + J:-(ЪF$ϑa&hc(v-[R?Z9ԕ|| 3(u)ći Uj`֠t;8c/j/5Vr7,z,m'n0~EyP$~_Zw佚""I`<A":wF?ör-YQA: =6j&?;~C!Cw lŲWŒ.Z&M;RByߟg,:fBFo-f< C"Mj6PVDǗ?rQVfib; I/2%E軼?˺>=>Wb sO&/ HACMx<81PG.:k [S\Of2r֩sRY\_&;d"8yH7AVp ©Hm!{ +B'l=i@L:~;*z+|Ywt)t/ZQy\Ez}~P:&M#rjL~'jf; ƫĩ~|"*ϭ)"?P"ݩu]OXD -u@w;+.u)$>`4Ziۗ +>=3!4 P%Ro,FI.|L,3Ҭl1dIsO/] M}'6!MK]< x|p<"wl`&t-=j~Z !9*C +!^afI4=J݃zzL~g( (ԍ6WN>AdI@ +w!* )Z;yx\+;膜E=~ڼa3O"Oz_(E8wUh& Br}ԯx+EOu,) T>8JцX*/k@6O2áOW_(36X])l(,W "s48rZ,-! $DUe F'X4F(h-$z 1v@ڭ)e/5[ȅdq6 +JUÿ~(q@bcWT"vzGGFPJk{'zpf/ +bFc֠."ZW=%Wa~KP\ʼn}ORGY {53tt;G@O*~;d@N=%ڥ9U` ,łA=wlK$~X7#}ъw~a_*_/DiF'1,qR̝ߙ~Yt{y~4ɢލdI7@ U.z LМPi L lGo:] cqF9{ feE0Hxj3_Y{ce땑eV7tDi^/(u:nMp=GDo +|;b/g` i/؄,p{wkPUl9gx>>A3?#@FxKn|M8R +n+NaqCj#WЁX«;.Fh +GWp}D^u50>Ǽ=+}Ƨ,P|>k$p!@M kJTD +B.B.IFXϑxZ!Q=zW;4]cW26N +vn}e9#ԣ= ӤPpz'NjU5(@/ʈ|q= + 8PT7o{ڬ1goqUDGggԄ#:>Ǒpg3@^_*+m6k8$<,փ!q88Jaw=@T{_uw8-;>(v$9p#3ݙ踔k +zU`d?V%BHd|WS0diqB_"KM ;G12~Sv"kaBAF9kN$ @8{՘_#6 2Ӹ_lZ0 q;?DL>迃P ;R;u;_Eձ=ۨ E !jB&:m&s$]A4<&D"FE&6QVvfJ8T=p&;j]Hьב&?X}X06)Ή;ralLw:ܾ%p +0=\k):'yݗE[Ա>,Rul"3Hɀi-= cl,1܃&P -o/(D6P1A%q8md#VۛEWPW26܏l RCزA%Do\=IfSݏ:IJF.d8x$~ǚY0 +kЁhYt)/jQtlzw%h `{kqB̊c@}Wx,OgIĩQ E}CP̬b7Q7`|V2/J=K&R99bKA 4jCjŒ9MuY i.Amu,,a?~=IK.X\G9[ʐaS̶ T 38r/%[}J=n:MWѿ◍#5/r,g;Y rV蚨Ӽ]D{m=J'MzvA%V#Hc{T!߀Gu9RZmMFͭ]^V\OYt~`FD]_Ǻtz(/P&qtֻ/t=D7xhQw _ *s>6yO𒜱k)m`!@m Е~zȣh-n$CEnU&jF) d=(ctgZ,hɺxMt_˹#j".򤚋p-> ߢi0[E}oV6GzbZZLD/OrUBZd$v8Rg}R-h5Qϧ>8)LXo1^NRg}}u(kSMW7>tH;PVz"r}:J 3R( k\QxC4E3jR]ZINlcET +Ѿ|67-Zy&nj^*.g`d "pc~0yj¨t(lWTBE0e@(/Pd-0&ynM=B2U"bfq;hOպe +T46'66XEƝ}eG?4j2"1Mմ{9- += o4θC'E:4z,j;Wb;'mޱդOƟm;l6 WCvF a M q TtS3r vu2zOX(:ߣ Fvri")MΚEld*f#A AwRv<55\ǎ9HdJD/צGڴ9$Cߡ6KJP L7hy H"KBViF ]g&}f),XyqĦ_tXO^xkrŜ8pS/WE?<r8gQȥh)jhaR|u7O-'+?5Nm;p.ֲȻ&K?&(H#g5ѧ%>ERjZwisCs̪|ÜgOF$j:D0ãnaˉNJ-lI?`+A&sХ eɎjf-iDݪNQpwq|F촞,D$ 5!iX?6 0"hri3csw_ׂ}&MN2r*1oصv;oMBCDFzm1M80qd;Sgn܉XCWAV}z{iryCP~9C(L`y8Keb#gdDy}܎:lٽ%azˮ$ eΨȠ1H ,)_G0No,udj p-Di;kp<`5긻x;uES5$'~^k 6"0a!'}I-~49K5mbX$~[Q?&n>1#9SBQ9f]P%|ATСL us$p]& IKG8BưѺwYJ9L_RTo`ZXËpXC _aI<OlX?0"u:ѬZF#6^* ج b`4L -> + l6/"uLhIq]`SK=ly-H8=CHsͼϳTYQ9Ly^/` ].0{TT:#Kr@~(Ɣ.K-,X[5[lsBUKk:oǽh"uZ4um7ih͞EoQ6DX[s{;eo6E ++/"-lZ.t)HdғlqN@23޼Mr28(l%?m(BH q}Ί;{RVxcQ +0[W)H}]AFʈ<5 G [D&3XQ5E|I?lNi:r<M}nN-[ | -crxLwqP(}urO, ɨ˨G wg.\σRɴ?֎^z\wFeA peךۄ9eNχe]GRhrېUSVubA z׋9 Eڛ޸qj?7VK~h8U&б? wM3<ŸJu9i&뻦|Bߟ"MU蜎luǒe'42oq?@#%qh8BvyhB0EPHUڦN\0vHz/$_`~VF0jߖqt"Nd6!95/4spId$BCԐse'ddk>h(~xH)*|oC7ƃE#M[Rrc0ޣ1E&&-+[*`/uGXWQ$%Tm5Y/ c$DhFCt'&й$PO?˚ف}_+?ӟ珿7?7n w?? ~ߠY|MUWrXNmq=jgŌihn%߲\:P_} |R^=ĆveJFRk^hQU5ū7UF`g-x^YϒU#y Wh?N>kD5MANbzNWT?w{EiERqwU4r[UO2QibGՕmM]5ïW22Pfy.肬[;tT.xUalEV>Tҏw/XwR$n`TQ+h$gQSBagqVcFZV<:ǵIVJ""]WG(Q|jtcpUʹú<-R 3!:V+;{mEF|ŨUNT*19.|}ڪ fpϤYV<c$ ȃ8JRo-qm JAvq=gŊ>=ly}o>hA)&n>G`cVZjuɢ..ׂ߮@9P6ٿx $^??f&Xwa E nMĊjqXo{ ǫ`(b#虈;0ׁCCqD{NFd|-DJ#0atth:қ@a%~k7 # h_σx6ѧ{Fn'H9 3?%6cؙoxpa* ~~`AyDJ!`M^ݷ `G, t᪁O +bav;O;_L4M?2K͠F*1 +s䃺'Bh(\7 +`F}" H4i]P|0˖36-ASi"\"Y6,&bD#o"~]I4I#^ \OӸp}k* #4"@Pףn-V49;e|%Po{eޘ޵/ I3 "tjJSN4Tqf\v-VRa5\lDtDH $-J@]f@T-fT?wxճ֗&e[vK$ӴC9=ޑDrX~wtGW&3v>lGfgsDf~ŔXfDl|9wx:Xv%*2| ,Q@:Q-$Ro=#I""fAWY +u,u)'_Ыm'~Kp,\I(M5f1*}St\Rp=ҵl?lw^؈1L"G(SjXl-D@թeDSV7wEP>Ih?=EW)OGUz>t3h r + ,nS$;tׂ zCc ARΠ단4>5$Z¼SoA8`%=K't; HQH^G")#C.)TqF@:]QpˁP\)Ӿr_ `L@( ?7(ԓ oq&|"e#@'1t?l7I-*XyXUTk&ޮhIhnS9 r=` {nVFQ$:,*][k*Gqmݬf f{# fHiof +FFaNb7azΞ"bPؠd~v)n=(ـͤc4~+ ΒL+fFʢ!^P<zNk0ex{Լ"V<0G\/y Z-京"{D3Ӕ~E=w(BWP_F5-Yl(hx4ΰI+}]gklgqepX餐nܜ؜[oͳ&R@x25 ג*Fۄeu 8H^HB YTֵ}E1V%믁/Kue>x@ rӵr>ցpc{\`ZiL[<6ԇqi&FgUu qNulpF;RZ0po{A#8$/atOfd! u ͩ l [䶛M3=֠ "LuͫxMVVȏ_ϖ1| d98Lpf.#9/r Jm/2 /Buj0׊$ZOʺZz>ֈЌaH]qi^w^rmS4L1GYs}S ;ck0 ٓ僾Х֝ЋT:Z;}9C95{hH|hN5Q\2 +S=_W\8ug-`)F{#i:^)n1ipEb`D$<Ϗ6p3`n\ԺUvYq0s~OIŊX =@q\_$ߟۘi )eaE@(p7g7}:>+t,5͂0$S"*=/ ha[xE2AEa1 ڋ0OBSaSSq5E Сv=uC# >g 4tB:Tvy!+}oQ +9jk}ZG~%/ڃJ2ltGG<k9>.J  8vUH+Q#J#qu_ ~| ;u$ ҇(`;];?;?3YĂz9jWI7QsY$x 2SKPBf,yxoQoSצ8:4_s\64dNDj75iG8DJn5 nL,kEpʦ v9J27$(K͙~PL吗3ID_Y/Ea53CYA_Su+ӲDAIa xF?D>A P{W*%;umSDZ$'GI{ +q fS-%<2A"(D&ZS;sҞU2p@vhe7-jW6яs]A{$Ђ] φ׋AW4 ]V N +g0dиN+So]&xR?YfYeFf9+lq:mZ} \`^~5`y2P(e2{{TOԄMHNפhZ6"~%)vfs^T4ypFw]#0v#m +J-5z4#jJxDA.J:FRxC-@BQril'+IgFo^v|mp͇֔Ce%IJP!jV3k1BpNI(ϭѷֿ} +"'%wGqzH mkJn>I:m[ބ;uGLTGJbzg,֩̑ +YY BRs}kKԅo7^+QVԩO#^66(6~~&3zn ۈo$q "FT}R4NԾr:WX&ؚP-LUucDc0f]LszǰQ`B]_ YoawP[Dͷ}?P@(w^Qbզ__ {"EÙ>+<\RQ;woP=a?RT).J1gS0QAqx6*{ц컦I=BMSM17=u)i?bf`9@+@1TczxuX^s*DOy:@QNZyS6"ZɉƁh CIν+@bi +:m}I~dӨ2 E^a^kua mi#[>D.1__D!BB#keKT/듉ۆKUHk~~aoIe):g~@8PL` 498Sx3ҿGF/}Gf:A2XN喻xM ]5PdJ6$.WH`Y+@wN5VQ 3y1̻E^XU$ @) >h#L*IzGW w*UA4i?IU%>#x^Q #)Tn #x1[mDD) TOPѭ9܂}$A|Sq+))WWָe~Pb)XS(% iF2d莥bR 73t$GmWVTqRY4Vܱf/.U qȓG7҉-.iC|*#" YWvsCɞ-0v[MX.DQ74h ˫ ֯O2F"1D5)z}lڛp!I6i*}Kk,Zk +ۗ )_& +[~+$oR} H#g܁loA@LU[b~t?DQۃ{HmQ_1X{H}B(JZh/6?0D}EyUXT)/_ T?ޱ\*DУ+N/mq@ft; 輗G:/cFZ4]8%L y0"DSuO}^4-@oHح^P3o(-]*5(8e_Kir?HO +%RD ɺ}ˡ#r(G4Y04\3^2x/l?,6뻗8e뀯|G5Dv + AS%!ω I(q]/:6 `ӟ-JXÛB΂@RtThm(6.H7)#1\]A=و`SrE 8eO$j% l-Z*.ӱ+1s*2\ª^@:݈xV>h]qb$ عAi2_sPjhZ}MwcC6]`,ϬK8<\QAa4 ^(rc7’sqz_";bz׮kߊc>7>/h=0Е8"9 +1Q.܋Фk>'czHT  +1)^o=JbdCCQ>nʶץpZfl̨`ҫ8to5sŮW*'Jv4O0cC8 X3ZF<-dwI]B.C$*t=7 Ssqa oҡDrAj߂?ٮ="ʖ֕ e:ʲGls/Dv"H6(dC4xLX x`YiJJ;Im\ ƢFg]/$5._kP=lL 0Hnhnk-{O@:-/U6]8*t@]قqqgE狾EňbU}AzDP^cK>mT'J-% +V&Is fc+AOD)M2|3x^r,OSO?8edB($K츶5Lf QHF*%'Mdn]*N&Tѯ9FVH$ٙ69"y}@yv., \!Fħ?)Czg_%[!MPP"M=*LwTq&b4bN9'wcw%#?TPQB +)9S^Z5e5tarCSJ iq_#$ӂ+4SHX2_xS^Kn/G$`tɎRC) Ӭ[1 ْw/i>$Kn: IytMm3i*oU8ͷwO1 OTQ*޲ jQYOS.r>Nd@znhֶW\ΚH;I0`0́"i*y{2[R`8CQrͨ-}_՗;hƦue#-IcIyRlHt)}e0+MϤ_{LSld_ܾLELHp:_T Ahg*W㔻rQF%CSsR[P3Mm6,ށCoucP)>.ݲyx*A(ꊋںKv +EhA#-2A(YHb=Q~@:W,JCPzS1"FЎGٚ u@t3UD Ծ@څI/7P RuZLc#xol5p =i r$x4=Aknъ}׸|弳!>HQ^B5`BL܌*a4S3rY/*V14$94b_$Rܛ`&`3*s+ +ޥ*3B@0P_%C3]k$XR돶{+ml3>Vxom|PSPR}>Zl\ +2g5~^'&>&^U&ζzlnGzXlAg}w{x?J +ݡ z%g knM%, #Ҭ":EHO $ck@2[C?:5oю:6+,$m1QE5񮏰p#wN~"7Ű=]-A#}b^8#n&dw%4Q!thWth2Q>T}gdzbRE5o@'FNp4jUzBȔ~qΞ2ŻБ_'QJPTEn3/`*:6%נ+ނۍs!Z#j+L#gڎSaHA˟o@~ n&79;]V ᨺSIaJI'1iza࠭cTZEݱ!8 +?U13H#eklSO2?)dP^+JRC#86WEu>2F qM7FJ`(wZυ7*Z~"O]V'>\`pxD׎4(TmH3m~#mL&iR'J `MKn?&@>f /WtLUIJ,q1ipzT.Z͗jn3c<.?ۈbӳL,.䠋WhTHq".c;wet+)3:aӚe7L((_B9 ^(aR2ܨ)l<iMecTz̈\3(CfiQN᧠ +^'ᐶHd Q^ƉRW3_ Ga*s5*#:*LWBxh^XaQ\ИEg=o0P_ qÉk] $ `T!thz' DY )+-k'$V\,ipܮ"s5"犑T(I›ُb'+ oT#UTá +C 7*(K*#Oĵ}TY}p}d.EDzK_;BsfU>; ͒gEYHuknD,^KT/7 }M|GPykpõ\27:a_±XJXQB0veG_0-ܡl6?mv*UdL=;14ZC#WSnQWt͓/vP28MdǾb +q@~OXK" +\#€Z6Yޔft(7((RZ袦sw8`Kk%w %94mCb;=&xFHz|b7w%L5U|Yd1v7qX~z$:ʐx:ՏtQ]F^C{/S{{LrXkM +݈@3gF7JoZK~a1hRiwAXϬ͢yvJM0J,o|uF?p6ݣ bh&kBJj{x~0o jSU+_ҵd`[e^-vU H_FY}HġUC 9lѬ=JwlRxߩh_C`ҽ}XDSy >r b6AHdq|hL1!G˚񵱑aYg΄j@iAq {@ZL&3}=%ֳIq(3) +4yIGĈ.Gt0܂ &awEvOP(@swݨz[bl9:F6 H5D Rq%JdiBrWm *9ZNf2p;aIQa}/~1ւc3 +O (HةWBiPN4nNkݽ1GYc)/eKZŮMFIJ+kqK(y̕+7_ 'h&r%:ܤ.tRwmA(#|s;̕ll<˓z*f|5J.U`ލ2,~ʴKW>y ߔEmJƲ;&){wʁ4+~ ; x )"' Zӌ-fehjY*\թI`ܭ"ٳ9ϋTţ vCB*x8J.#jMKu bǎW)˙TfMDAdG^IA/έ Ц(Ϲd]/ڵ4bZq1Y67CܚX"KSP=$'n, +mۿE o"9y!J@K5E5eEWEk^6 +̷tir0NJ+IZJ i_q"[>p6@sɀ)Cuv:ht=x6Ӏ7A-ۉUODRg} +0(p>}?FOA[PJ)km$쨇f=Z,A!gy62y_~q84OĹ#6 +՘O|0CǑOo[^ xB`)X1o5|Yw?Z;u`E$eѕ#5:4ǙFEάՕ b6$~8J?׾am7acٖ98uhuxWSK۠R +쾞.*)pAHOĩoؽaV4Q +F.x\yNZ.u'z?}؏C+Z<9kt@ϩ)E.hem3;P)RjtwEٞzeab)f6B#+9@`hZE*M@ ڎjVzu)xrqr +@z]d~F6oB9|P@I4!/Hb/H ϑtr<ػPDIؿ"R'߷*xMkU WǺ#\G^4(ۦ3JU%vKf8ɮGVt3Hckqj*'hZ'=%pӟm(*OՏo +i^ek:h=GV)Ÿ*Q WbZ8&/3/6(_JV;:܂Kr{`E=ŬzЉ29[-pO3LhHCD]3a +)mu/ݡ3>1bU /zg˺m]W,]sIJo^ԍ"Uoݼqzk.L746;P|48U& +&kPU|T?/@Ҕ8Bm ‰qjB|TJGQ#~!ݬi y7aꃵ|$^ym(<ϻm:et)AuaUÕ6umrCyǣ=ȟ&3[fWmh?TZ*䥺Up@֞:=5 ܸ~"#r_auyg}v.F^?[xp[W&ބڒRQfj}#-̬Ȋު2VAה4C qYV6ԕE &.][l)3hF5mY-Z9;.u+ӟQ8E mx0*5=?A"AmA`tnk Жz` + n"DL`1pbN|3 u/.gŹ_O#XLJ FbGE +ۿfj Pq?*2 @/6QQ]yX:̱=9*"@"8x 13E&7D0Hw(ҵƅrTX?Ԃ}ӕ_9bcJ7q:KK^ڠ[L8GTj'+7h'-]ʝY1:wq BVە $dxmxel."I:G -l =MӚxbp n(QaX5@M{)h(qi*_O_ }v ̈r嫼0b+%@Q׋E=#nQT%I_`=`P ::m#xNi"/yDX6WCM0b.@ Sa|tDuŠoץp nicD!y-³9|O魬‹֛Ώ'1f{\.| }] +^ +*n +A0)_?ftTJD{G?mf T >D5WMS=~F"*mqbO~1ucczt߷?|N O :'CylH:D.4I*pAHm|6~Fsen1zveOۗQz*Bӕ0*a)+G-;k?+#YݟFDEW[J _; +hUok <DAo` 1@3"UZw۪  1.ԽEis E+SdįT:R\Ŋ[Cp +dˇ,(qHR]ɳ2(IaKT}-{fiJ'=Ƨ(NGIFlZ1|`5$WutFƈHa݁ +(խ\ium È#rкLW-8"yGgѷP,.(D|6ߢlzV5-7팲zW/` JlJpU~?YI;CY6ߜ:ca7kCJ;$.5HF~W$rMn*mu֨6U "+.Y0r:yi OHyq[|1↘X VRFUb3Uok,3]3;{{+c{Q%^g:hҮɤ { QAP9/x0&QS֑!)}yy):o{@s?` [%I(}?wgU<)47h%ؼmn߶ޓz^?[ 1qh=O3 ro[{dLj+=tlndoaH3Q4b|yCJ~"VYyn,C$ԝl4n6]Zv x&ސiPw'B?@wT}N +wy[ڈM/'7Z?=Lftu23bՏ:bP=٠BjanV/"rw5?[ +hM=߿Gd{üAqi.y'>_nEe`> ~a?DM5 +ۻNTp;#,`oG)o0":=غ{ëV SV~=F=8D#Q)bM-GQ[82xPt"f `h_ 7h5gMmٲRi:45@{U`0`1Qsa/\Qwɭ +n|} @[Df+Xxa7PXDV.Z< +MGZbs?LHmM#^FchEP *R\ֶb +iu)f!qPxIW19Y M'(&\.¿oAv+bhyoyzb@_>hBGI +ZۆQ_/ZI4=>HMHьmS_ H쨄GJo?%v7bpvGU +k%,Rڧ6 v0+뭱aHoo5MQixۇ݄0(F$֌)C+>Xj*+4vAi+Ʒ][3NW{ +޾G<= +ͥe-dlI* 65K.IZH + ֹ/=<)}8^jat|y.&²$ #t+ +r쎙UC!̛{ mz^vDac-MH@w> D_t)VU2(^/(o3|w8#nFoGN!rz=Fs Q[ +!U%Nfwܖ~G`} 9"qRg/6$řJݰncW諮 'XrMՈ{ZDrrő3R> %5#f"zCm~B^LtJ%&}Uk;$mŠkRhзvusʚ?7!I awwG~$RCI +{i @4N38k"PhIt*4uirIbC xA +i ORRSs*o]&cوX@:mon.EV,J=sUhLMWS $%E2DA4¢GD Bɣg;;?]q`ǿWǿ_?߭P??_|P +u|EHqз>5AGss(w$GʸV +ՎŞ2M:CSqGгCZc6}8PEDZS4ɆnxlYj+TPN^U шb@' +#$+!BM{ +孍 ,(^8[`)UݏE552,7GB^A3 47`opP 5QU(S-* &ƅ(@@k'mKZFt xO՝YzpGF0X,GC4r\DԺJ~kYYaCm w +jH= ;hix=b=a>U>nA%gPPxɉ^U  +f;ugO-􎀂Wj~bÚ]rk4uZe⤇c:nE+·o{ .[r M_4:e\U<*?A兣NHؑoA?6- TpxtC?/$?Q"cbCXbSzmFSΜ 2(jK ~Zf5_#ꯣx?h;wٲ 2 pA"b*xz讬޷o#˲B<ҵ#($Hւ@+ZwB4_Tʲ>(es#F[Y9G) \p*xEzR 8a'c:ǹvTHO 8|cj)LDq +YNDgu(8$i +>E2}R]<@{e@#GyP$Q\h 2LOӀ ݠHHG@ʍ._Rjjۧ~AslrlH܏ +YlݨN-|zh8z;?W>>"p'oYp)Y5t%p-_ZE}b'ҳԚd'J# ]G'8Gzk/wYTbq#rZK?Ջ!w4$PcGK(`k@6u*ȭ~'8B_mMHխO"RI@Sx<.Etq꣯[¯`Ƹ H{nqthVŻVl> еp]fXD=- /tkz&dPaM*&aLP3j8>_Fykkc ìhslS_@..}%e}ꦼɗ08~ހz7U߸3BI趣^Qֻv=9SCoܑY]hʳdʆ|fM{}y-t<ϊaZl7 kf32w'C#ڴ8r`r/n[ƒm7|jTKgrwIYL6b2ֲoA;*\m +S,WYX(7!ޚ"\B(cR M[+[e ꬋGp= +Rg]q ~fEo5Z֑>.#5 L+Ss8er8lב@2qdaץ͖\ꁱ3/*E*Ov?[Fxjvjs b*=;4`O(95y+d>|-1)uT8Z۝'ќ(x!ü2[HƔ51'FH>nDɞΦ陉bn#'JKĩ)'IkgGLH=ua`%)pKh*d"tN{ۡm0 XϑfB!/RozU}Tsufƨc+*DQ lJ'mǖ@:]rPt(Tp&3jDؔBǞgL@jsS3z1G% \w:J)|N+'4uyr8\8 GDyn/7V +]ҹ뱵عRB? Z#p&AyIT"EuYKrئl̬A"kBхJC8~L!="emĕz=5 11{/SU>5@KD3 OҚ*GxE#8r6s]+IWu 5 4;`Z퍢3Pf]s;Zgo!ׂ^~yId@#|S`^4 -DŽ4QF&"PZD_(7VkFLOѽZi81];^k_lGTbTr4 jk(@fԶ羢dH%B/9P{W -*tWkEy~,f[Emү-"o?o⪃HWOCʼnOyJQEeĀ= :L`׉ǷGY2ieo%.P/}FȔL>#+}x8 }XH!`Ͼ 31h ށ7C,9?Y*.KA^2."$ 6jf_$ae^gbC%"Glp{>sDoB:fv>D[CQR݀9(>`Tw)70*01/(8y<.~>0DZ +#_eF̆6$:o鰞9܍_mծ<[+KJU  mWK։t<~ۼy>kKȴkmu /\^F ÄJTKJ g>cvwzy@ +R1,[yWu=/c@@HbcIHh"@PJ=0EQK.zQ՘*2v [(|zMׁkVxݛߌBbQTjH=g_'Ogx8 UIFZAon)d-9T`**]I 򜬇Z *Xȶ-yTl*+.YKץTtIpN% 쒻j5)2b>ٜ/FR]U@b*|ߋBA'gY4 {S@8eӇcY &h~QxJox)/ԣB<$I_6C\a=9 ">;& Bv0K!5^ J@sJ\2BkHeHN1* yj'$|~! ;}Y*`Y TR5 =(S*k4o:9o]J~A+PuS:iMږy=9\gٛa qM:&5" +tI(@h]qP#Rg" e8 +Fj\byTi8DW dz1Ybz6*u7}ݙ] =M* |nl +ha!)nq|xYO | jGՏAmP# +tUph!,HG͢kbFV ;P.<E*K;q52oJ" u\f~~ҥGT&&pͤrJ&(' +'ތOt6p?+yZqǃBIP46ˁ#Rکאn&̼\Բ$57cHvC@saI( ,=R%ql%"tL"tl(lۯ$]Vݏ?'daKm!fIgcQx@ *`*>Bk}D5?9oF^TY]! +ʺEUW"AnFt{"D xW#"y$1|QZu~vEA!ߌE)s*Fi2(c#@fC3r.MmėR?-ۨӑn7 JljGpɹ-:/ fE[: '',EX +чܜ +|/ +W`uS+A ٔ $"=fSQʸ7zzB(@3uN##œdQ|2/q8 qbg#T\WnN՘0`vG "xGs4ށ:/jB_x7~h3:3,͠ VU btq(Sz)[G0W8i%Ȓ0,3>J#PJȯ9]܎u9nzUN(p`#6<ɠ;G*wNt`A,giN:Ih$r G0)iF[7r@A`j|# ܟ*g 6G9:~O0N?H^Z$˅uD¬9sӇ O$SEҟsZu*==Tb)5}^"$P(RsӅA8_$VWVwD(rio<\wۯjN|^:=f9M[T؜P"½w( (D7DQoH ܔF`3+3O~~m04[|?GC 8#xH+9pOViY`-?%$pbNcJ-3 m#]([F =墤wUXM~NjC#ѩ ZUhGQC +J4At_S^N;hIYL0剝jNa4G».r +((ьi#Oê]!_'b3]DovמQPx OCweQ +vԆ`j!5FaD d4 ۨYzD̪ޘbv[AES/&PT59YR Uú2IrMg;jkwZ{\D8Kԁ|H~8:EV)&Uب'eqTYQE#| fIC&$`:U a) ~7JBE@ݳp.mMD wlIP 9u`6+kmS nA!M#Za6IGOGd~zJpDP".} vl%㴧`$ :6F[2 +O?'ލHpu.8=1sȈ.!TGCG4`IP)4FHT.0A);Yl8]SAv+^UϬ6c8ieIm9MvpCTTإ[=]ZȀ1"S.MzM9;)]I}&**A ViGGm-9.u]Dz7 lOT ,h3TPBgo@;Z*AYك-AR4\#DV+A\w3WRme zVj+cD ސˈ$s@iBJm<<~"q,.'k$i \ˉ+%DKyKЪͬ]h],xO + u2&Y}u)SJ'^-uu 1?~qCR7qZ9I}U>Z4 +8Xȝ"cJ05E9;HW$qs"(grv4GQIW`zF$Am@NXBzimT"8R,A եN:N \Q'PWhGAAw]j-ܓ ЄjTVڠ@^(:yV2[ +DTzBcPb$w^1LOцLg𺎼wyxc/}dQD";֒ǣt ,$YZ[zR$]~4߁tt":=U<@}2}LL5u-8i$oHnx4 Kz" ~l|.Kx>Ng 'PQcԅ!0+U쮿&ɼxL(4!"e$u "!(Jj^n^U&ifgߤ&1K( wz27ś9IIm,ICThl /FRI8*HW46;r#w#!4t1b)i_)D;)<{]MLJ4J}2{E8EDB 'uҏs)v |l)2Q4^l0Mu0g/\y9f7"lͫ<1#HQr.+:ZEPS'^'x ̳PKUh{Lj T +u1 +&hn› 0gNJa hF!$j<@Gʻ;@Rh濖 D#E#D/JxNKDWK*rxX +@Q:txUO!E?T`ڼ0Tu9$LU:,w8H4 +&yi;5TDH`R"|Celͯ.p Dzl$=͵˪\8T2)!Av% ~Z3pioݓ$ٔWBARsQX!B\3C|E~jzD{UGa]+g~ AM)i*ArǐF۴:DPt9:%QrI\? V9Fp #>Z[GV^-x}\)նW4 DHyԪ~q*4R;A^BK4@fpϴ"PnJhtI[^2VН SLu8)b04yj+蒵q>w p Wonԁ]&@2Yc=Fg$uRvtgi8zc ]՘<Rӛͣ/v# DsAɆb5h/A@@ksGWgG`b;5%`Գ{"FS-$(`[~Q$pbY` +wXED ݓ84!O ]0' 0% wXK(C'GI H~yW)3Q)!2p,.K: +JI[ HJsH<]X]Dp}Bw՝Gd!!SQEe82]/YExG Wސ`٨:;Htwȣ ]? Fd~58Dӭ@(|f6Mĸ +xkxC0 kN(;obarf#:I\Кu$SIgF$hQMq]԰.( v4Pf(icxHV!Ŕ8)?*Mth ?HNodiudCRz8Ew۹hW&1aUbw6%QԠLhњ>z;t! DEoIsB䌼Q%[G,ǐqEȬA%Ԥ~Ǫwa(sa, ҫ)юOdL?գhngmȔPCSq]|ee$K0d4tqg0PS0JGȟ2_A̬920.;1꠴-[{䆁]wE~^7hzW:R!5/1"q]I@P8jǕh~( " `#Juv`g0 /~!uuʔ@^OCHrd!""fjdDܗ|T,&fX/o=?'6_eۢv)͋t2]f.gqQQgϓ^$.N]{v#PV﫴Ht}ЕaarDŽ2p4^I bfG̏m2?cD]wp#MWHh;Q>[`z3)DZP>KStIㄙ +]ͧ͂ ;ț,4͒y=(4g& <zE9t[S2 Տ( %bܑRv8OF.? `#jZLy}5 2IQK2!Fd\XHz $ߩDM(:~I230FПU?+ eͬf7omZD)`(,BUՔAXNk ++A,[kV#.7Aj~ͮt#r*@X0^;rX9$빴8f!K>HT(!24nEH}2i.`a͂Z'R%0("^Sͳ+'^0 16|.-Kr=M'n@^G)xWChr3}lѯ$ U>;=1YJk̵nᄄ<IҒ] 3`ٶR (I-$ IՒQ%%#TX2(< =G (@pnڣ<-POU +K`1҄zUpJU +CED^-x!5zS"ta(î[|ޗiƶJ}PgitU+5?Fb(y=+og{[ڸPVnN$Rl.Ʒ(cvJ>z׀vq6]Zhe]]iBwҴ f|IMzA 6;A[Gu̲ӱ\](ŋ0p>d#yV}팪1KqC4k93D(Ųjx`%. sBÓŝ]w^3rGY+1mB&u<&һi$REƱSw &j'BSv Sȸ)f9$֌&6^5*bB1>rY](>]Ap@|C.J_{@$#4Bz>BwVwMc4،g#fk$^-x5b:~lb8;aAB1gkjKhX興R(zTHo!jc$r qrF.b)O@*cvCB4K\4EUi+ƫ^ëS*5ו4'y< 3DvUE/&_IPHq>B# .UiMFV":ŘŤtOͧ#IA/TZ}uONfa݉OF!OC*DuiuE躒ReUMDR)z#BTaMQ3:-؁| nv$xe:s@٣! bV2"P/$l+PFѭ F)SW 2FxpIt|t0wMg&kQ VK3U7PqȨy WrD +jbE;_``r-JB%(ΣHFD2w`:6$ċyu'뀾Ua ~g@{xqaKcJ9ՀԄidO7 +Zl+" yqX*V39ڔ&]&FtQbdلYxIv^[o k>aSc4!1$Qc5<ߺDLyu$E:`XdV iޕ#OJT Kt$_Ջ4G$X, 5M'hDeߵDmhhrd ͓mdMQ!6wo*XZan |B:ۿZG"DҊ"y@0\(`t4! +骮A'$Bf \Dr|'r' B"Q=ʴXH>ǚṂR)qY5!d~+%yvFP71#q#{$u׻r-jpM7ŃBy1x)6 qdER'Z - V2dR8 }a* $lۑE`W M쀒u~b$غz@)4(V߁[B j2âJ"DاJnlӍwRֶZTOq-#t%u)Ij͗h!)~}CUB/0oYlm6ڐ @Xhvk_'<!It/̿?Ksgf%'`N\pBH5-8Lz)I $:Pжx)%cW y%/ ڪdlp 1و4kp1;4 PQDJСF2pQwg'(-A[5?d&o]v[>g;oEd0 +ʇ8<b5y +>pEw1*(;bJ2! 3Q~@ Rdn⠨n=)WKҧYJj2B(?$v:qP̣[:Nqx0&uגctVAH]l?'S‰>{Ȟa Ur0%4"&ӂ2NK4x驧>=t1B@&`?R}tJP(zO"&<@JFad`L>} $H)+.oKD@wGw ŒHI2"]oM?zA`\@ԧూ_@=-6¶t]0ɪ>p0Kǯ+y0:N/߀/:j;*'9"rJ;Ӟe>Fו ͺ +h-DI& Ab! 1޳OI CI +e&e ^9t1S9 $#D\ vpc$`DH/ y# ,Qq_E>ǒ4qUF#<8DF5wU tx]99k!A\DYq3ã2ʛ)A8?:9!\F8}Y͟E'ef57hR1i<+PDmTble]&1DXP}><M'!ݫQ H#HP.%`U!L Y^C2^IaaNori@+gd/gI< +sw +sQ:{(|l y2Ҫ^|9O)*vumDD ۜg`ռ'I mjrP` 2u f0rQ!ZQ8$c/;\FH~|I+'C::6J]S&F;wMCHM#BZs 4a21Hb#gR< 3.'wFfk1ICg CKN 0QM9\c+ohZ~%mKQ}~iuн[2*)ewqu+GPiü{$0a+;zQ)ݫ&<2bp+ܢ B_0(EUZ@wyc'ͨޕ+{yӮ b!Ə2t.]@M ̅9i <#9&"|*55l% /"5V: iq^B М@$LLofKϨR=F4A|qNAJU2dDG' CmM/T-I1: +Q#$B>@86^G4ug%/٫_B࿠[Thk%) +D5N N;`60ySCFGy`X.=Q<~!i] +j1?0-$TL[9iRRjF2R=Axä [s"4H<׆GJ-vaQK8ﵵ!)N̷R^ZB%l{kTŃ\LJ}[죧ԷlNoI)&? U&ԶuZ2C6rjh#r+eΨÁRƖT./3fk&u r&OnAlqB\E1ԱsI&l#F{vsQA;>J +ɯD [ g4AڿԏMLJ--j-:=Q5$$.e`=avGf׽ԁRh͞~"=rYR*M`;Kb. dEuH^AS+M{3G/}y$68L]ăݓ|M<1S~o0H' Tju@hrmd;) T\giKf<VAf-8fll0! +eA"Y鴚Ŧ׮J/\P5 +E; º>3erAws;N~Spؐx:p:S@srE i:w,cdۼ3G~cLvI)ciQu!i!\K}QEe@o;0'tImrO4eJsz\MsZnb9b*=H@|7{s9Y;k Kr``qaFWUjr8 mT~j*6*w5}WfD5Z hd~洊!1N]yQ}t$+oNXZh #<JOl#8'D +Bv6s%iuJIJC#4 (Y"}<8!aםeϳ񄃤b[LtCc*>"Ȍ嫿eΕrB x]Ǻc((Uai ~Pt+s5ȡ1o!b.vܼDqEki&N5x~QûS{+LlŽpZ!V`5#L>OTbwhCNO͋nkxTb4}CLE]%լLj$ H'JR=OI yPj`Xh8ls*Ӈڢ9dmB$IWcS 9Adi pc5u@K@2"j;\}"ցP4QGuE +v +'8҂`ıN{;jRwTWS4@ F(JF$cH3y+TˌÏ#Yfl㈸¤-Cu,ٯ hVU!C)h>:jwXSl>j0E:K2ߴ4 +^QĎ[ol6{s+.Yfq@8QɣMpt]R #@;Ο)ovE.Z,]G42~ R1i7 }F$1C4Cț:)!feMח AykjmOH fSA5ٔ$vkO ;:|tp#vSĸAMMqSJb@ 0֤9&ܜtX*,Ki  +hqܡ0C@>|׳-554jv:YĢXtĀIl;1;8 j7iLIxk,rmD +d(}ß(T7w^bBāKdWMJϋ£+f g=ʳ^s9Ivۨ_0!0B8@_36(_:^ݡ UϘ&YQ}?_4v:h`+I@G7!M@'0#k#"lޯ +WlwaREW)9t)V:TPN|=yá$B'#AYh pgW2.Ho:蝲j vEupypb޴'wr1[vǫYmd?x²| ܒXDk5*E%N*j{S&"4"B%&3 əy4%[MӒKF= #}kI:؟z@h;\/# +dtOߣf*,+")$kJ-yʍrhіSTBM˧T!( + sVqY3y=GsbUE zP \C¿l4жQ 8o9B_5zB Oi\d*X|[3= :<#xDK]%_W^[gM;Ly|?pb[|&3<-Bם~@kMDZmk4X.;#O![բ*Ct,i`nQ \FO[u8[9 >i,!h~R:L= x`) VC~&%J9 ]@9f>*u5q>L9'mmum.r->E;]Ҧq/IP$o ")z }X?CPLʛx!.t8KxŃiKY_oBՄ<8^"EzLGm5E+Z*bn&3Z_ d׃ԙ!OTW Pf%B>Ǯ7ӂYz(h>s:$Y7,X@jxC~~n yUO o?o?_~w_s_~_|o>Ͽ|;?vgsoy_}o?˯|_޻_W?Og[Go~آn?7ճW~w}uX.?K_7ߌo?߿~[͓":teЧZӠv_jN4W;?o?You}|N +ҞO˻ {Q?njϙ_}w7o䎀7kG6¶=bFI ڞQ$̏2$w,2H^s2rgwiLM]$gj-Z߸ (zOx'8⠯WTIZ2m\dn{u>66'6yÇD) dZDD[{ǜBnz{^A`8VA4yVZSN܅kr\")kN/W)5}̿v=:$F~6–/hz=qAm/JX$ NaSwt{XJ;WFXA DI"*IG뮏rYXc2: JZ@E<Ԓ0C,˘`OULPiQkPMڌ(4 yѲRT8:GGÂY~'3TH @c:*cD{-$B&JDiUFİ>;D^DE.XLe hl E'jAX_{?Wf6u_]37UXg "73+bұCR-R|j($~3}+EYۅIVbs8g(3$2Ko%ղdduH6[1zmAȶ*Z=g@\Nd!*Ϛ؆$|jÒTp +V']ѽapA}V*VxUa<+gY<+%!uO(Ѧ?؍6ۻ |7.W׿Xʟ}`U|GT<م @u|Hi˧D(C Ȩ`c>]H\|LxBQ 玮ON T+H*eu;olܱ 04 6r&9v2U# TMJ6L: g)擠+H*~CMT{=YwL5&T%f){KjIAZ钃`ъޣd,*CrD;O'AjQ*BvUm<0bҵ,g}8 p$m5nHRӭ=PH?fo3>NjZOغwfTtb"~ARA,恵NOm2'[⹶qBS|@,q3F=s -&vݓ4OM)oZ&GMmy|GSR6AM,'.!9-@qk $ #!(]( HRJ'.^k\ G2dZ8Ibl=@af-bk5ЁS+(Ё; +,1Mzl$?g)"v +,# +L8rZ%q5WքR 9\*m) D.Fo b{|aHQ,mڌs_hֶI +C +FM&xyԀNnj- H +^40բ!@iDXgx6v4>4,%p+nyNh~f\h+pMQᰫ BFn4Tdy}]c]>^r.A"Wh"չSvS&bE^Nvc.aD):s9Gm;oN Y◙-x.^ZRQ*Ag +vJf^r-U[OUS784p=ȦQGä]IʤxٛRN)jyR,k0˶8$ڲ5Y'B0y%HB1-t!E M`>Yu?%B! +Jp*<*6*j=}kk+BؓQ r_""oTk9ݖ4]&`v'v2w3IXL_40LGwOf5h1u'QCk€{(=d(ʰ]MKi2S`B~ږ؋< 6lrvtMq"'@2* EPpہgs;8Td̑-vGvPdn0.C:e?\鷳Jy]Շ{CÁȮp"v~W];?E!F_ b1Hٗ1$RjfT5|^^_,Nu"& +xpOZmf 6@ލXtHg^QM"@ŜԼ% hh&G$e&1񼏟gMQ RYKloӸJ7W>g x bD W#-]I@Cf$T1#>Xo8fϩ/uW#}N}M-rffw;򒜡T +/5;TWJתIDt% >}I)l1 [ŕndq* *ʍrA,m<_d8)H+L͞sm/vS)USL=[NOZ >:e57w\\Wm?dIOqf>b[U +_v$7ĢA@vTHdQtb[xI ++E9%w`$t}]?#㫨OCq!{:Y^ kvaZKiS7R#cv()) mvug>[s@8Bƪ)db`ש&JeћK+G_|H +jHۛ>h|߼X?@w-c:Z^5QQ$4)_ Їr#%2XgXvÃGtzA Īn3#-88rҐң!хb]]1+E*xY{rIQ*X!$^1_,:Lmנt@LE/Q<m 6toS܌x\L' WKM=dB*qy1~Wm!(Ȉ s}wW+K@&#>亟QjUg$ZvP,XShXmb/`]PBA֭Q.| 3 ւ9 jhԭN +/Y6 \J@\]#ŏb1/2]wu(;Ed o<8Zw ~VQ'܉~vU!?ʋ=7Iܖf.^lΏ8RUc2"#+_k@ ^(>>3J2+}s {oh $} 0ނ58,߶"HIZ +vSDkDr/~tID@@>T12 E!b?c5(c]Fu 9܄ +Z|Z' L>\(Kq_ +Q9\g̓h\conp-jg@*?ЄzfB0qMf<(;fKSSkhCއ@MI̚ "|C9j63k~{蚑Ol'Qњa<[k>H}4䏠TAoͭPfM?1S[8Y=** $g/mP閴L&?j:Gj{1kok𝏤[ary;fs:㭢zz춤J*B;1=IjU):3s/s_>zh.u)5jT#~ qil {9O>$9y|3$HÐ{uJ2ki?Rr]s&w;ҜuNy6`=y.{)F!R}Qj-UD=h_kx{kXK\KB\+oSkos 7)j7|~濊c0r|w?UƐ=ў:jt!7̹3ѪI gI. t ^הgIuͩ$F8).#4>%}ܝ@1[tV:Οc0 Ȫ!"Kv2NHF#|Ͻg{w80T8Ϋqn?sTI ouPDmTVh)aT`/m_W(;\w32JL;+GlD]˙aݣ=P9P0T]VCaŒBţF#(tJej0v=]6Tś.-T3cS +ѵd>Nԉ>7x +$=Pt2NqU{ QYu".h焭yP+Yoap?A^*A7AD*A1ަd+'wUUEij)G|PlW\m."Y ,fS(JvlJ)mH]u*ZV\DEyP QּT8T>hP9/Sԧ'^A:д~]0THU~;O\Gq|qx2Pŵ0o.ɳ}?ULzMHJhaJૣHm>QF@"cꯓgGyu1 nћwYK[-#xe +fO;f~^_Hb9%}K +Wp=.ۛیlewo'73,7u6:#6{mu}Twd]{4A_޺^wl15*]mKqL]} -tc?o|4-!VRdRtM#'*)Яwj͖\H;+hkn;V6Jr`Gv{;cBsc* XC+S3Gd)?چYtTs8PT +#s5<6Ps }H~3 d5P<'QBk endstream endobj 47 0 obj <>stream +F\9v-dJ9m5pE + ^A{LgeӾECflv,dj{BWS!(Wf.B Ƌ>$f-({[y4/>WI9{" b4itJNbA$Qmj'X˥"`~_$fzQGrjwzC`,GWg?q`2~rvcDtO'}BH^p~R'-T%QZ@6OYO#cIB';`{0Ÿ|8, fmY*/> `r0Cn +nz{3'2>ܩ#vLOuTGVrqXc5ϓF@ͮE(V/m8/- ]bne3rhD{U-;x:ЙӠoSp¯ۦ%~MDS##wyPx٧tu?j)wZ+m6o؛fn{,k`7fm_KL=ؘSbq]w <]&Ȁ)[]VQeo ~&*`\&bAb +P> Hͻ n2p/`BI }d踑`[u"/Rkg{Zb)ȱ.D@|dӱ{H\M"]!Wbu^dݍb&Zo]e8-!]URם$¾]ByHWvم۔QN!aض/HEy#"u Ya@jg@9lѐiC@ "An'V{T2 /t)ChByٌ~Wcw*bIhh"[ȜLWl$%HjY|$Aea^lͱ Χ?55 jV.9t6"H^K@dZmtq/ +L*چn©-mj ZmRw6&ﱻ4Ѭ6{hz+]j7.MBUFI ax]7U۰>>wm$O=FEyE-R+] $]*'i^;ٶ(jjɶEAAƨe^d@[KɶIqL FUM͹4]ob a]_wmHk<]#ӑm|Vx2vakc+&U\6&JjT"轈}VRAFݖ +H@XhQ8n42%;hcfmmm<d6hoW6Gnj0y`nk34֡d#MLgWHm+.ɼۻ$uV_J2ڨYv̜^QF4c|?rhoy4wʥ4gQk/a=eZ*زfy zs;Kftb6f9A_ +3` +*7p_Q;dOf4,Tϰf +^q ދIgaXP"ㅦ_/N }a$z 3eK:l+||iɅW>e"oΌNs_y%EO`*Q55IàZzFsS h +՘2*ŘwDB[6Gy/&&n P&L7k'Fpm6fl8$sƏ\8EcujmT8nŚ9pSc¦i: 5s\& 6vì &} gm6ƛrGL[+'pv zE6dqxXe#hJH UDin>'ٲ>h|sH[}tyl&l6^LGHP?D`gqI݌:]\ˀF;+ݙrs +$5f4e y (A# Jk?>d(4&dx8Kz|H"`9nTC]a;,ŰHf;XrEB$Љo"4cSH +T~Z +^M謦ƵTs?kf :hPh-=ӹ4/*,ƅICDQ9(p " U 8tCa>/hʳ4";?.QA&_B#4Wj(s9d S?6Ĥ%0/+4C'1KӯK<,[(XAf"N +ySF#xξҜ3Db)dj_=pFI{L5\t dRQ7,OjCv+=ӜUi^W63h3@ #Ņ{]Oݿ?]Lx4]3lzqK}ucb_ [~r}8>R|DtkTV#8xU^L X Kܢ6> B+zW.J(hȗ oD3T%`JNNfR̳/}λ!z۸G6GKLCsn %j [yG,53scrzo ASUv+$;]dp+ŗE5wY&nT(XVcgr[ӎ|5lJ`mW.{_Xfr%lp]j̅[¿1o6kLï}iY*5mqdߢ[-|#hxG|{?c##x)x^C]Ti6ANxa Ma&&Vه+qq<ĚYE*ʭŖ43f"gۘY; =f"iO#[j*)nnQfFmSVrp8˚SxْN̞6\e֌6͖ܤmTTR:[zuӶ>Nh>PށhK"Vhcoْ۝l#nh5o5WZG^ XKlpu-l}-.,/޵tje9nkսZ+_ۊfjnw&wm{+m~﷊89vlyUu[뎺U[4[1wZ𭳰7WcBOd]ߺ4[{󈶢pB۵7mO/oܪ"m\HawtW#o ;{C`l]q*Б=`=HncypVd`mA +>#}.0=^AJqϳ£~YݦV֕TXq]{>b5VTٞYi{eŵ='hnKl=54v Vhߖwy `6d̿mxƻ݆ ?Wmfqnny 47]Bt,Dn @[^wn) ~{Pл[>z {?_7Tm~EoYXv]}(To]zXc6!J-%GxiF"EUK`v1H o:4΋b%*$GΙמeEݔçZRR7 +H<%'+fQy*E¢dWkZۯۼ9m-Nh{^ܿZܿ]t*kumVM:gx_$kTaAq.".f/9Fmfn$&Q[rȽTa2yryoKe3\[qVV/ ܩ/d;RW%wɏ3V# I[EnhOP[}h_qsmč$>jIQ#<~w2G@vr{ +[xD *ldBmgprc;EoďF 5x&Mݫ׍GY^+cV+$=@]"Bہg?+$smW +ڭЍɛZuw^ЏjP^k|"mT0?a#riUqAƠK $u +FWT',&UNHBRjIN[gVU]`֊(K\ZZ<vz.,w^cANIzU<'7|`|)g)kv#/>wbMO[M7D(eH'و5Uj*<~W)C[J̩¬NZf{UfͫͶ(5r55uոJNg3Sh+SCh3KOCQ~29,oO;,z}nMhۖv;;qcι;Nms l m{9,ۺY/o][Џ:CZo=h nnW[ [1N|b6 ӾlM?1tF!(v́"JٹȜ6Qnu*Y-87F3͑" â=Qy؝'Bpq.ڞHiԚINX9n# ' I9J?IϛFq0sRP-7_LsxY3MCJ:|`MN^àJIXk? 27?Z( 4/b;.BTX uOU[aܫ>þ6t%f]kf[֗Yo3 i7͎ͶβFouosEu]TܾI4K9ɽ ఝuOw=:a͏ å̞}pNizv=#b^%hUiTOSVмkӟ w<*GSD`l]ވp ߉6=2T`17{ lu$^m^7+m{(eFQMbtTLEM0=œd6e]hEČT+@d; ~3ivF|?/DA;hK᧟$߳,H_O/77kl(挓yfJ"C3KD<<~JFlE4s`Ntt RY!>5vGJk"Qbȍ9ɺ@t6'6hiѕi+cmM0fXO4gdamuw'@u⤝(hrĶ4EAe3ګFmc6e מk}54[Bom`DTB +k3EJ.p_5f6dL#oi*N::Z6SGҔM A lqNJ;34UB3USnNQݭ(oT6PqfM2:Nm̋ˆ= \'X&-)@}릻bSJ414Jl]G}Ilu"| +aeO@lj^ b~yU!R*@8?;8}k$qLրbC><~Qhc=0UYn:wbW0" lffڪ0u0)AuIWn&J$(%(1-;P(ʥnw ,ո; 3iTA񒞲Z#jloW``e T- n9D8$CmǙɹ}Ng} z7ҀiUM_K~3%tGb6 rM0Y;:9lqB;>{oRbڋs|;bN#LK0١ Mt;:ypaR\M˟I,? -:#P\rH5 Ş}Q8d>R.eOb +:)Eޱڅ HH7o2-{39N ~]K :.!>nKF>K[M2icoF$X9'Ł#4kt@h.ACQ@`5fOt=ϦsܓL*;63F䉩dü@H4^&b +5 U؏6Yύ m&?yLLT"v2db':QnS͜(+Fq.*)LT7uP@6,%$>9ɛODzUx=Q[[qQ-Avd8'(Ժ(IUqR,iκ:޺%6)Iq?qMq]<鰙'^oV#"v~n)sgx\0ǐ7 QtȚOt@޺Q28`p +LJL;'v~j'R[C:XHn'ixLpJbu9#■~<*8"@u6l׍s)0jTy`bA nPgp 3r%1_uP('Շi +D:ن{X%LQF`<)r/[ +~obqh\C/By]Ht83[r#r%n#y4F+>X>C$ךZkGӕX依JŜB=GTIkk9±(HDs3nO .G#M<E̋A;=40LqOF)3-GIj7β4gط6'ӵ~K|ԻC +6@B^3 K8. A.N^} ]*ÿAJYj  +k6ӸfouձqBh&nlmRk" 8FU遞օnY+䯻E0%%sě]y*|ueUSgz/qaÖmF^kČ֋囙 )7@XR"$دx;026K76fRk#YEJ1\Z;su4f_&//"@QBA'Py889 xS I$Sao2o%PqcW=lbMʏl0IϏ-x3s.utήҚnV?@~yO!l.S"ZO 3=&㰬HVq"6wpdbB*S*4ۓ YQRn~[/; fQ6X`'E=~dΜ/S7b*Q婷Eh4M)q(5vi$ VSIJ[ jɅK55{zqY2pE68\Rdj#7Ac'8/, deޛsO|ϓW3JJbzk[[Ma4 @p[G܋BӁX|`i%Iz:5@t& '/.& kXy>Tt=i9(|2œDhQ6c >hRhBU*(> +/I}/zdѴL.T*"r&G?H6G28=5 >!)i.pձ6\Φ|.Z+:xur j&@R0Q\ܕ'MHk6ӗrŅ3(v]]$|AbSvi_#vD0s[e3_3ؗ|M |qzBJݙxuQ }11׺_w))i 8uv6Jg" uv39U{ FG Z- +EL2%_AZ/.AYj[; ŇFȝ?|@!"9AR-2RgrN 3Nٲk\3&{f`7tfzoIfpk^W|lyInbWJ;p5 \ЏOմkD *&. Y9 s(5ybjk3b:Ɣ{Kc'vSOYS~y,`OWF0O,>؞QߨppGlOhp7U|q G`p'Nr0s4NXZup:!i%bO3פ˷d &]+ xX ȼ_sjf~}FċK52$6l8\n{&!̯H?j)BDep05XȔy +KoPtg=;=մ)S7WMR3M7h'BsX14@`6߳fXLɚ]51uMϚ_wxMc+pmR6m,f{)uT6XuyOKycN;DգN2tʃyD!& .~gfMJ֣Wϋ L\OoA_T-jrt>' +7q凩$6Y*OqxL u.W#yMv'+$zfQDžrzTwW[*D k]bXᴳRw$ϓ鈟xr~ՠHedLQvMNAUi6ߋ8DZ&*dp9LKNh)I .߈W Y.C|< +( ] +7Y +ae>qWRt|9[Flc ('8"U^R ƨgbnA 7q+(kEIT|LZl&{olb׮'AdXPL\ǀF0k]m̍l576:9]p(4IIM 48B^/w4C4 z:@Gq3jA5<w ˠ6jA.>-DkjLvz?*W%erpNUc +^^AZȗRw8>B/hx=;-gp@o!XNaH ѼQvW)ANbGA$@v*dNmo2PɣiWyhBԎѮ)"W4C%>ّ$vE1~[D*N?PĘShREiv ; 'bqB]pa~(d8;{ME:gA?̾w-Wx8 ƨ F|zL0|"zN}4MŎ +e'`ٵfҴH8ggPpD.B"F"5Y2H=P:^ &\^JzRd9ȉ Hң?%|.W{jj v(FUEQjZf!DwP71x 5 ЛHp~BaGԫ[+utǟpԝW_?P y-ohi}@3]Z~cPv mh$u)TvOUN)/6'kg.)(9t|`vGq QCwN2+wz3X_U\%vWs넦;^cezZ7z`9on=Rurؖ d; vH2>mKGyu2Q\|H:𬠙|9ciL/HoҊ1( CFY1ALpu*U~N~4`P#]uÝf;R *Q봧`gU`S` Ԅ$7 H`| j(ԏ TE2Ou}mPG_\ ++E|{ };QE h5Ҕ[nfX4z(cLY +flae&A=%&wA~?.PoI~5Ju=b}QXQ`R@0Yg8^+İVA-.ꫯVf䪖SI eE zǹQV-%B) l-sZK$(7mmDvh-o^Ғ̼zuLQ #oԖ 6kJrg}Cm#;6‚5f"*[jܨi IyS[.1/Ֆ +p^ >R +}4ІUW63;[]m#kGz`) v_-A'z[Z{QW8FnUb2~Ah˴E>8OADg(oRPKMEʍ? `> a:ګZOT2$aA<#FYE%]Ź)fq +j(yv|q{=A~+t|;{BODhU49)-&g?|\є`_Ǡ#F+w.p 2HQđ'(Q|"r&J'ܘ':ʃH3_(sV {\B(N1Qӫ-n]ۺe~8Q.h3JĖjK*(3/i\{&8ꡪCцr1Y@vj5Tmk\L5d ظQAA7YԀ+z`G褂U!]hJ[6H$/d4/H( yG]9|E(s)^j,.Bg;6R,=3\Y/ +a9%:H!DBڈ%=\jOL*D˲wr4ܻh+V;8;}"M?: +$Y 'c8TNdcHLYq&q0&ы"Hf7P!0"j|J,*̅}ч%2^ cKFNl+Q9#Ph 0ʐᇲ=*Mw d6UxYm"(UIeJ ,!"bńNc$j*2H]FmۑTVftↈs^C#Q\^@:_{ΔZzfk<ڣ`Og*G8/IgJu3_Xۺp3֩w3 $,.8JW>,K(#3ɿEN G@ `njIv~DR݁X): Ns @.X'!C@,#gNlԚ +&oHm{d 't헨N~lvFzȲ_y,*MB㽁;\LR5H1Viԝ7+|%ymzދK-v/xun:.89!Gg8a QvPd'Pn+a +jؙ9f44qHе\k8DܑvD!~*_97PaTvFqY1xGz h㮰1fFxݮ 9t_&ߤ' BŻlVOzvz4FVO +IuwyTPy&R#`k{(8 GXq|.9-?/81i|b2!N? {?@,H!An5 < Dk>io k-)G\x_Po0Vn[-ypgfUx6 ;m<0ЂQO:lD!6Cp[a\N ѣ"XLD +!}ԬCp޵v W6Ct):/m/OAC@^X&1'RE\ ;+)m޿p8mDJ( T)ә&| Hoωl1IL6%U& n[j]jsikAG@55(?Ǯ̸M[Cx|ښq{|)&l$kik+ +GM[!m^ɚf`r˙>oJ0Y$Tּ83kU䭙MG|>o͜P!8d;l-K GHXzW,I'\*V$3}˞†%WlM lX!?r^g[/Gfy?Րvw|QvgV @@ BF1{}leaA{MbD +]~1qؽsF)x{hc +@C U1߰@h!+#6``8[7Og n@=ueL"48}I`AMᩊ/1P]K)D$ +FC=b:=uQ"UPGk^ł3!և|} QRUW!ж5d-r!{֊&ΗC6}X|,3(%Lpڗ}>?8N'LPOLy!k ?`*7Bf a'Ƚ=A#'FV'nLpG&]5J=eA{9>ZDx`,2Iة&\7(DVT{1/\=/؂kOH+P2?-P`#6QΒkv}VK/ڪ(]!Jmh;hz=? AhCa6ŏǷr딑f',1ňjDŽ/Ŕ0(4Xc^7℀RlQ 18m%~CR Ymg\#TN{vB#45088;jړD)B'h.Ab`V5RP߽fQte 'f\>$ЁIچp H rsNj\N*LHK'1S%4/*ISZ4[PN%bzM$A;1FP + ؂".D)NZ1{|OS1uEq&|O1w$;Oٱ1g愬,Aa`~&u #\`I +n. 8:7h'鋘ĘiCr; d4*G,QRgPiq]cԡvќ"AΌ#酎[m{O rWNw&d^ӺpZ< ]ܠsRaeLc7V_'uV%R#J__W3;!@'8J +oE(Ύ'"{FFpOKW9f?v?qDDHvYfnH)%@* &aaDH-5)̵`ߕN"2(/g$9A `4@vܚelS 1>DW0{]xJX#L$5~n4'̨ń]iH! .KDccfM!lT)t> XF %QS;ɊXmx`$CGl9h(Ei0?+pq&foE[EbOE}Bht%&/`?P_δ[u<,_@\'@jD&I^36=Q;/ w^O\%(jb =!P|H}"6ZM0:bS 3"#b6M;M(r"(%UzaLyizK !)%%J 7K5$$ 'ۺjg/k2w^^pkR7 *1)<hP5+!C&$BoERZމ +M89c۹hM`#[zk5} ^g+}$g }O$۔*CPDؼ<"XVGG1AhK-m78b`CG4 +E;;O!dm/DBEE +ۦ~ncUBʜHv2x -Y% {9!FS4L^Hz2rf6nϮ%(F䆼'p(m앆 `tEWcgBkPө/̜lT 6zz5`ˑsz8B +|"uny,ŃvpkcsqQ#5Ĵ{}=Mi( ; ^`tEԾ%&MKVhgku񞋎H]&~ I~Ί=;:U0z3 R+8H\PJ$P8/H0~gj[,n]sظ)ˡPնF:^p`RDIS*EH}{L^a#@]ig6um@Dwah? K`w;DP ` H4;Ņ* +O6f6%ۯ}a@&*PB_m#fߊDUNxFa7;HO<7ci&D2gq/|J6F8IB(B}\eBn.b:v*y54R}>Č"|ZE &i(j(㻏cBlWNG'"ͻ~:H:&Q WM?P$_*k֜+x1jR]7G +G/ 7Yrbp X$B(R_;҇mOQ,|}ILCV(`xԌ1J(7lS?eZa&zn'A þDLk3wҮϒK"L7FuT ]xL:Lnu+ +4wQ{bC]mlQQOF(62F(S兀,-zk1xD j~#ZQ[_;& o1G݄dT>  +;:OUwO *Ř0gHjA᪞UFeLqLD/KllJ]7VHfbS6^.Z/ {6KiqnĮ-UI#S2Jne؜4WSa k2:Gg܆v-y(vxӗ.I 뚶l&za~㩂.xݳ\{VEz#QvOP8{G< -'S~Z4F i݌>5Dí]GXG:S !4Y!^ZK{rJRS^3YqIPUTp&ŒVвT4^+2S2:7&6Fz<̏-=k!mՖJ]9}銷z9 +ɜ ^Y $Y1nk gaN%z{r-ntv]3o]3q.ٮ2tgS6"Uz5[:Wȕ:w2ݹa 㭣W@y<8᳜|5w.ط! WF|Az]PU؎ka!O*kg+ ~53@ox!kDעH...Ze\lԵܼu]?3;{v`iƑ}]OZcʅ]6<\twߑ4 f=|.{,o[39qpʃ@aKfI v)akY6ʼnpXk T\ Q$|-@uuĆk'X{rlObcϮYi~3"2'/)R &* ,¨$K +ّiPYߖ(.߲&Hњ]5}.W_ۖ5v'ck- sAg|WZZV~/se_+ďN"~Ngk-$XcxiM;ayMQ7{}NUBs`Otiw;szMn&]ĺubTXT*{3 U=TjL f:\p_ y!X~ti/F@ Abv[3o%UG3]Ax>@hJ_"CiDsR ~"Z~?Itu݃Fx;S!6p6{sDPp>MqfneE|0|LFʙzV Uz2gTSP>P&&-{"[8IK(SZF[)y)te.=zBvILD6 2^z=TA* pgj;Kތ`TfgJNpuh WI E,*OtKМh+a=ء'HAJIze-Cy]!nbV8եS@G淲RXQuUcWI$a Sư&vȚXCIK~,uޥQSQzg7(hGl}x ŗNPzܿ xLpT=aw)(k@[\R{Gn[+Q9o| Jغ 7v IO?8lgX(HaN;v1b^ S;D<6aCzh?m];Vv†=p>XiD-ÞD?^^qG͋~,Ms삒.wwvW~{07bH?ZiiG"~^gOg;Op-?fvusCOG tAX:/?ugIi>Cj>Cj>C|iC!ު9GDԜ#"jMDi9GDrة;OI<ԝc"i;Dj;Dh;ODvxvxex<5<5Λ+uw7;nqKvKs[$;^:]Sn#Ez3UF^9 ]מ P>@RMxHdMN7!;ӊQSg N(OQ<ճ@A+)(ED820GdQf?Q(EN" ؠHm}zTԀB(m >ȇ(8SEqIc&y|5}";ϩ-~0BT*lM@@ C?TV뜢5ZSmlHSAc:w؇7uRrx,Y io*) oFU]ZNz4tVKBֻ01)yMRY3Y$ޓŠEh]=b;Ibv0m:{_6RF{tg09y|q. ނHM7*i߽o,d2LN]?׾LA{`ڝ{:;{} D gɵa1Y)eg^?yw?ٟ|wgG젽AM"?E2| Y13Od=05a6IҁWVx㉬)y0мR $Ǐ6>\8&LuQt~Lfu&Iirǎ,(ڣ[:A1ruC<*?y6 ifJ@ + r:;ʂRYH)&QC$C^XSO x5ڄ%0"V]=v KM<Ff +6A~({\ S&L!͖0z6QblVg2) ޖ >՜r=FtRCH3'n p񠢭7eoyvdY);;~` N=RAQmYZwDGL&6B0r.%n6؆: +_5S;[4T u )ȯpOZKTKG?ݢЀa܅R@4*Iݑ!#fϣ$|pLSxp=lHHXYCaAnl`\cDf)svhq3"X[rA@+r$rUb bKx4|"Ư UdDA?+tVY{Rc/)苪&38, #kgeFvN ro1}=a (DH58~=T;*4 gg6Ehѐ%j6%DmL=YY`65h|`if;,]Sj"vTRT+b 82S0N#5F!5~ϝM4{&T5 +.9!$Fh-DBdVP)(~F$dn."B`$gPDGG?NZwHa )T#q>{j5BmlP<ӜIv̦E鬒5zuFHMfTtXfwr6wl4׮$-Qudv-J+ۂOsF,6LntЉ*3u 7;4|EC=Mxq!h'd*/WNjˮk>DVr;T6uTVhLܯIE!1L7uP M +YYhx[@͢|+N;:G`5Bण;oo|9 ye28v̮;І?>aPHR_ѰkuDq!B +Tx|.3MVBEbЄ$Ri9֡ *̇Քm^"!T~TP4P\dCV*9 +I1pDž#>(9CTa{qa%^eT#{ܹZCDn5)Kޗ,ҼJܻX ,/+x1Xufڻ̈ Yŷ 5Kpvef%4Q$49Ǟ."={௕ ;1y ?8gǍ.>A)3Hy +w0rdTy4JmqHqs3V4Wę{R Ծfu?,9imW3a yef%¯K 6HU}LFM"^F]GQ3JBeʉSK&:r2["f\o¡b.eqJ'ֽ}\᫦Rp%%dލVyK^+d1`?ޜ \z 'kdx2dp3)9AUX3JH-0[Ͻv )6+ef DAnSa8@]ZMt~1A#%&p{ZB\j[cDkrPEM%kP`6ٹ|W"%tԼNBRvipByC3r@q@$v4l އ\I[O–wظ!C!MndUw ?f<ЙNzLbyO22*̦]` 1zZ۱mb4%1Dl5qnB1k|,rE2j%Ti,XI$s +BBM5"硼UՎ٩ +%h g{>F vgYB̠sd,W>OnCQA >AK4Dа }-? ̞悄o>4eŲC'(h$P`ڵȈ{u@aF"_E?nkZAsHl6O? @j 8 d֬OT0Fpc%{߳fX9ڬY5kviwܞ%)x5?Rkjҟ5O&ߒ5/ۚvM?bcMA{drk͇ϥԝtu)~']uJX B5 N&sNr C]UVϢ]=ɪ]Y\p-p%2Nq6W,"W㌩fhk#gȹ%g2(gJ~ܕSyt-roGSy7iR!Ԝjݼ+]y&Vϻ2[Oh9RkIwĽS8zp'jsO*ţ{{-BY Y +bwQ \Xk|VU\ ͬUϨy^CZڇF60j]\k-v1_5sskDտoのޅ] @0✮}`mT0lpa\=. Cv3?j="ݮ]63oE]6w\w-H[й5QɲMS)r̉L0m'iWM% +bH9k҆z%tVU0V`T1nsE;8L,Ol{U6kxpMPٯ5-Y%2CÔan)Z—ϼE.I``+K__S׬=5, _5_맵^~̫]֝5Ks:ͼނ55њ~yDQy/2 PH ˑ:TGd7*cotDŎNn{$%I +HN0 H9:9O̪w޳:h1\~B.,i= T@~2~_V:.չZ}>kA!OzT@`j_HAbݑAgB .Q*ܹwo C;_ +>wk:TO{jzU_IBO739C${&ŏI`ĝ*2P Sһ\~'Y7,w$۞,Btjx=SoV9]H7v6AoQz^nLFخOt?~N?;]-IYNu C2lRpP['ԪZt#Y(,RCa<B,LJ$Hi髇7=:,o%ɆhNTܑ3˜G*%V1?HCYT:xD#&@fS?y5hvJ# $pht8i $U2ao3)60iUzJ/V`v@V ico;\((t'H$i\|P|)ۂ!l`G@U!Rm~)1[DC$CJ5G/g,%"9 GdS jAvNoN)=ǯ>P{U|Du̵S~7˯?T0ƥCoʜEP K_Lt|8U(NF1}B* )dTz ; F`t\bPbRFR]Hj].Nhھ"3 " nҥy\E*_}AÐ!E=4c`΋ +L:%pZki-|||u]TN:]R)b¥ٙӗJy 88dPQ;.J03Y7j)=( †x"xԴWA=$dT!i*1BR8+BQM"&C@ +!]`[ddp]ՓR +n5Ѓ$D SX]BpR3{:޵*n5 f&Q%系Q̉ie#E7CsI(; K4ZŠGpN7Lɧ(/) LUhaª gpb)Y T+SN"hw +</1d:2f8Qռ>'`V~;1*ΣL$?اהE /4R!6lqIY#35>~/+[u3A0xe/{> Q)'& Dz&h\/⾰N vJk)}0J.a9ׇIhC +y0=ʊ,ʚ93gF# + +H5VǛF@l`ʈ-~b|~#Q9ـl:sgP7ǭ(=:$jSӣ?K )IeRz-{?!\qkv/xs[; ^nlzwuވ҅?ww/h'`Kz}t/ã_?7~_W?W(G7.6?7 +xo414xUK~>^i46BP7OCzXfƗS7Yz k0gz61M'_Cpl; k,~% 84>>1#GLKc"xwW<9?48?$?T'd4<c|Hb|X/19qXs_?LI&gze|/hC|{tE0:%b8+sNa:4ߎ8'kw gKiTalc>{zs/BRsOTëu,nZDlsq"Y/_yn;TN?Kz1b{9M8o c ])c +U}>z]c> +y{2]UYs5cK1c:3[(-LqaEofrߎOSƍ9nV'1Eb@->a7_LRZ^3sd-8Xjs C4%jS2Le^$s?2z{4UV/yȼv@s2B0@u^PFiq"04㨤Bs$BoyW+cc\tsDeT㷦klC!^$k*D +eU'ks۰5״qOCU7| )_s|ۈ>JwFqT1>cLS՞V#xwhm ʼW݇T39OײϵQ{/ЅHӲ?:VUu;هԫlvn:ayDKv|cB#a|>}[-m?es 3U^se qe*, inK| y?E\KvSEV7jnKS6Q#Vf +i<4L{"@8$H͹11k(V"E|@u^(a=oI{9';M>u?x]%;nq8zv0{k=Zn|׽_OxnkdNzW2zB08ca(R?+[y,Ydz"KfcA >':;*3ӌpR'DzǂBŚE85u3hRxY@Ѿl1j$Ii6;}Ω:%Rʬ,uթhqZLwٙ],. \v ɇK3fߣ{dxT%i|1; W$&yLLbLX)4|_=:#` ӟfپ +:}[DG)CP)ko!n4rEg3ֆexk/$;ό40__7vNGL0 IL5& Yr4GDdwuPŌ3f{0pYo -NʬzRj)H0tZ$ 0/91O=P4߇פрqu`a"*A<%2$84Xk|qv~xsG#[1i-c#3MNmLk\L$4xhF c@dpғK~q \!C$Lb6<*WW]jlŤ1Zp+=F6nZ nQg9%{QhDLO)1EcSr*|62z4}mSS_N]GFe[R-ES8MQZT@S3 G4?fxQ;0D~ǵOI%nar(*" +?ŦKӵ;R '߱bT?9 +.zj}mwLDª)AhM@Qҳ\ fP3&`C3cGiB:NQi~=/$f4/K&8 X'A@ +^K@cvSz$4E, `=5$`隙GKrJf}z,e\6GI^Q7} 4s:\E&:D;^U(hkk;妾41p~C%f)tqwOL-@adցqtZSMJw}]H0_T,EH8iOR0;EY:-ҀOYUŧ)QX6!\|o饖Z/Ko zitOH[.|F-ci<~դzA2,,%,:SQ@/oVŤm<,0~St((WJZLzM-  ڣpf=qro0VxpM{d`զt4UwlOLiu)Q;Qu03Qi|LDlBN(ն5QG ]BZktiW#QzRը/3S>r +u0J唤^O=J i%6XHCq\4g%l=v XйvW=3sC9XmFJ3[Z8@%pE\K03DN|Ufe!#ztfe:+u3(L~*a V2 <:ldijR߁hQvI$ +f ^|Y`1 %/!|T)IO=R278.!tYH +DF +LTn+;cRR9Lf*e@7MC8BPQ>~ѡj|}n d199RRT&ҐS[x7gk Rkߑ-ZZyaS¤M/4WAҡkQl$zͲoK+Jw[41NqZh~"d);|:1$K;vV¦dFAl|cpm2޷cRDE"9qh']vJAǢT2K ߟ)ih^_(i)+DUH +>AêhȜ\74/_{+MDgu̇)PD I +~DF=+C!yf4~(G^R5{&V)rZF= YDM2J%3t±a&hK5&$lixZ $dm9ԳK8u6ToYa>YW} Q*z2"W!*aIsm{i JלIzc$*Av(v$LH-vh6STD^nf|3Vt(,0FJgu Kl.gt<-I? z_} gN +=N5%4zԩK +4OE:0 +! +~Вe:.$mR˂ E$"#Ąwꐯ~dElc*P(nRLVgmx.;,X}rq{T IӨ%k}:ni(yD4a&%%264u U )^Cl K$I9\*#Nj{OK9 )m=4*=Zh_q&jeTd@utqzBEZcs@%G:̳pVFeWw)SECrRQ*A2Hh &ZS;@pQ_ D (\ CRڽ.i!BlnBepJr%baT"0_`ӕlDiӳ,s1yȢ6/u-Pb0BG +/6xDcf@F6/. KW'+(Ui}2m d9[]]+uPǑ7an(_`/F,&u&4a "2)G!)e(F"눛foF]TDa=uupYX> J)D?B=nIɎ\Qic#]W,w>5KM1*\'2DF`Ⱥm,ڝ(#hJc&䍋k3HeZ*ᦘ֣ &QN/`qE Tc/xGl[f_ f[ķl]GJTlJIṿj8=K@:6[1UܔTm55ڞr^  RXSr;S2z6QouU)QTe&jXXt+M&WTS:$aݥ/O%=TSweZ;TG x U:s?-OI޺]OX4.p]"\iU&kѨWgpBOdF)jZ3T:ih`QES/TܺF`EVe4̝B:עT)O~V?=t*[Ut)Q#%UIn8GN-\xSCnqxDO;nUr@Z AF`)VNEɉblTB4:6YE0pE9%v+ ™d F)_-ezYo&D('l_h"GE ѥ,69V:^=JջHe: B=i3|]cFC|e"K&`|چm@[Jz)ۓ<Xe +LA/'8 ILC o]o8&WUEB0.!;L[g :SNİY|su~!uI㌪p׾8ϡrt*"YXLQ ݺ9% +;34Lݜf+ݤqI)h*x hqS)Ml~E)T^& 3VS2%SIM$KI.B}oH}qq]8&)3=D7ͧLy֩{o2Ifz+k +}DlP3c}C)vO}=y[gR+_xHO-^ +zZ?t}ѫ +\>k'47[/I~B+>u%U:fI*]箳u jv4:$'-eڴ L܃Ro%7_3#n$xt.gi2M%e "T5MO v$|#ܢZjSUxyV'xFM1$E*R}M^uL*c7mO<Ÿ;Zi`:Qe@/Siݏuʒ9ڜ`R]n7 +9dFQL%=DZIr^o\d$5,)c9=ui'^`]I*LͯJbp5"ǘIE=hgiUO;Bsh)׉~FA!kCFU`u2.5٘بW )u$"0ĸ5g2MMKݸUv[6Ja_N7lc+,'moo>dPJ9U`7c8NN$K>kBɦ(M},O*P^zʸozx3s#4&,h!蛚xAV:gș:=ɦJ,8(W]\*7QQ.Lu.M}kBI0qI9:`lQOsӘJ k;ʕzlY94uP=lNx:&*bڔm +DU.zBS+rZoQlY]WuŌ̑V@Y)QR h\B*X"Z:R4OkN$1F!7t:<Êi(Oɾk*U"k k@gr紻O-Bi5\gUt& Ji]cu܍ +ՠYtC^IY[cK,IԵ)+Qh+p5ْ&3IRZ:dJJL[/,$i7T?YѸX{E6?J@[.T>0a:}Q^>p|3HWrV |Bi֍`t6 +wIs9@ # B1&`6 @J2ѥN_xZr͋.%qPxFD*\JyP3dY/:"L3c?n@R!<9e4ZlN̤3Su4oM;\j)vTy\4yT7w&!Kbo84M6x M6D7Ktq^-ô(0|C LuL'& +im/X*c0Efg:9b냃2~N՛RxXHPH!`*/wL3z.)b8sc)p j*9茛8F 5IT +)"zS G?i$ 9Wn$t n.%KmZ3#FWJU*POu8i BJh`Y"Q W;>T+ `:&$$5%T\byzY\$]La: ;0TxٵsHap6H7g-Iu6?u&Kl~"'TVP4]=` * +kD\7ShÀ}Ϥ|0f"!Cw mnhR܍H5-n=ʰw]Qݏ_S=rԆ&i{TD +5Dd$dI1Y]=bJC,X*Ep>%ɼ&j~8 fF¯F`TP5V mj?_]Њbk\0R{7UU}B|VG{3h&iڿԛIQI2UH+j%imɁAO5Ԭt+)D^7sQq֜&M)/Uy$Q9/)d~*0oopJdQ?q'/sURsZJ[voSs|jqu;rA$uHv(ʍ7]9t:4yW1wZ*O+*VRc[wsA ͤ*u*vSe$&]默Isi:!S7>1Eѹ05(I8C YJ Ǝ?G>0ٶi:0UU&#~jkL[&Ӆ_suw N}jb謭ޚuH};kt+7Q~>TBlS+UL:.3;ʞVs71e5ϫn4a%xSKqL +KqWxl=1G َztbm2#M{%h('4dq_dAHԫ:kqGl]rc)=,݅o:I-=k)"Q;>91}V=+56mp>$ +dzBJE%]:Ɓ~zv[7s\sr?Q]BHVh4!6=ӥ>Aͨw)U@RBО +iTE04雞£Rz0J=]UuadcQvaI9J̥v\{P&gκ.C8v{jm84`<1A񈾍WZJ8{q!4_^Z{M6ݫ#סU}=Z32' Fwc"[M}x鸻Z?.?ΨjgHq"Y">MRfC'Lkb0wUsqӯ[_x ٸEEy#eioǠ=In5"NZ'}K\-t]톫/>v2V{#N/_{s7>)z}{ŋWl j}YR H_=փ+|~Yb?Y`xkr}2wKrC|sYzgmYCW-/A=Pa|ԈlԠ +0{6gh@;8XA=X%`Vwa)>@''`U~G}6O +ol^<P`=Jg̱8|2\z `FL3] HoȖ__?|UiD^x|#F_pQ~K4Øɝϕ SܔBϵRCXZMUZ/L[C*ңlIpe2]X #KLz(4?.-B 0,@dޗqt_|_ˈq>ɫOMSpeXč!m9G'ϯK鿪O V XU}~vS#տo^wO/D=~V?{^z2U]A6ꞈ^Ӱ}.ʏ224uع(/DܽKSY}΋UtjNO^;7G% Fm<#` < ys ;~.a@Vf`:~YOX؊&x+XgUк 7O aԔ! i'wڿ^y鶝 jQ :-^?_dD#:)nZWջAN:[ Yne{uoזMA +|eһ{a;?-/ˎ7&/N;8_4dS$v*&j)׏,1# ӢbG|PsQ99CulvP#4uB9c-1+&Iiؼ|ؚzΎ3؋7@ڇ}V +QN@ՂZ՝B%rvX֌oϷl`9^t;@-]U,g@OC6efe z0[d xi^t5|9ɗ@=y[rXD(n|rT= F;9xsXKFSٲ*[j~u"SƌVq箷M56,v^!UͲlǫ7ão %0Bv +`}688>Ux>z__LI4w`2; jD$l +7Oj'yܹVnxOy1.1OYҽ,A^ug/WNy,kr碵x382Qy7[v^ԎK@* !Aإ1S^ G YYh%C6ve׎.G`U9c&'n0¹ 8DV㭜ص7A(^TZeՃqfq8!b)^mA +@pU9Bmg{ ͶwL@=+P ,``3"$1)d` ?o@oe9 bW +G{`) dJީDpTv19Ϡo 2 g rG?ԆOսjcyv{VGA(wO&GUiTg `UsEslu@Ejr./D7˛??"l/~n,_/x9{mԹ)3<)0oN_t{[ ,m,lX%kj B?oɳɗB]Vxu@j'*ʲ3{ƒEƊaGxSdag <9,)`f(/`юUC i3W:5@>;2xXpRWm_D 0yG{--Ɩi)0Fm}P-@<2/Y@@k :*p1u ]1i/+ Ȼl1VKK}PODm/NM7yWAcQz+,w4v.5zZ\:OfA _;aܫ^sj5/h&V7yԻ+5Ny> \Uǯ3~~(@Ұemp+"kDS\eWW~l^Q=oApe N8?`l[5Qg f(N.؍ t4vv Q9ϣmX=%v. +=g@%eYR :VkX~֎d%Qo݇;.`9`cWN#_Ʊ7?߲2d (}yQm_%k`lС 8 l@63&<1!9; |(lXجi.Xի/azCmewm Xk+<10^pTI޽Lg]E:Kq紵x]P.vy +xZTW˨}cM0xWŠVf`яrʍ'= A뼽nx( teܹN7Uf՝O͌Xe,ʂ<gr묵zLE O?^x=7y߲"ް~ڻ `6X:8bs ûp<Ž3XIPAmBޢghX;E`.h.R( (")[ioծSYB.kJ}^u~^WqAX, 0]-z d,;0sx{2`WmSrnۅ<X<nik7uҦ2o n@Ïw;H02ZG`x~(`:ۙvֱ&z:[ia 0&~ 󜏾>pw}&V:7}0$PYwãykPjl|={?:DtS^ȉfo'{Vwc6^`zؚi8-^Dom50@'`IVNpK{|zWj=>z3^c[~i~gѹО?+"4R!!Dht +G[y'} Vu7 oA`R>h< {+Vl9Pm' %hK"Y^#Fٵ%۰i6!A8'@plʳR&֮%9OkAcoIxz+\ޭT^u^?xΣm$p +紷` |(!~p6hz{=Y(ʭ -Āi&}뇕es3[VEt'X U3;'Qv; p$eHc KXL8 ˪paq8\,Y®ɵH& 0iy< +[GH Q[d '_8i(]*yډgwq^4N|L_x}%@2n5DmH֍4ǯgu/` +^~ _ʳYg;9s +ކmLStM*j9XAs Sҏڳ'?Y)YĒa +bd&0@"q<*v7ʀӗ^ܱEsWL_{ b!cgxBpx0:-`W?Zvj~0!PA jgNjȂSSɻ5OekK& X9j8,p`Q7@sXx_Epp@Y +_Ly=-N>-:1ϣv^GJpf ©s /g!,)͎m k8rmNV6UVxֽ-\L|*Z4B`BIk%>܏59+mDž_z BVޣ !*؞bbQy`?Vkw'q0g'lvTp! n[5؛[Âi-dozFEl\?aBWix 2 l0ԁ D`yEmySP< ûr VWIҽ jjT.^y=U`k?x l_=ZxY&~U +=sY3^٫np6,eyL x E>.I^X(jN0ՙLK @VNVEVq扺a z9q(9 9h LwX,Yrn50cWslx0[/m9znn땛R  8'wA4U"+`U;1\TN' {m֕+b-V6ˇ\_:|cC+n=TaF+M҂qD V@?i6/M4#h ^+y;-\Z|AfQoV  N=҆EKST%| v Y=9n0rJm1P;.*ݳUrKm}!ob(jQ 1#8kp_?u⧫W  R$sQ]'Y⣨uvy6{_R',V x9 P`'ˬ<Њ6&k](ESrCq~! +X/@ +Wzb͗U px=n ގGi4^49'XId` &ɬz |^|e%x/OEe/_tpB gďfX!K m!bre'Q4K`rCN:gIy.H;9bDvs0,]`^+L]pàh~GhG-P1*>uR1XL 5@MPm.$Y׏rbTt`6)`,y%`(vv8-mgK6oP[hX!zKo*Ds׶@.˰vX$k4M{W>< emk@?Vse| !S@S:h cQ%d.;) [ +r^yN4bp C+T^7X8[Ew .&䅬&򋠱* 6QQL A]-xтU,NAd ++ɉ6r)` .B\OA&0' )H8N\r)(pڒSyIXa8痗a$lze6ZZF[LV/o~x-KSVP +Ʈ h NPw;W;YϻE27cAym ȇL>&pv>W?ڶ9 +m4b? |3WlqV&C,v 4C'`|sf^`{@(lxGj*zY7liPs0e; `Un +b l>ԋ0դs/ pA+m+}Ov  xM_j9`G9p +󃙬x]za8 5/d[>㉘شU*SXO3'wAbÇ6~01fa",AJUU{Uc1n-Q:-wޜhuC'4*Տ>ND}E#k| Y?*Rº.7.hdڻ|ś$޶Unw3а[贌/64y公GԪ~ 9-@=^,<!0GNOΩcJՕr|haX3fy6`ՃJP+-@yJG`; Q^$ re/W,R(,T3 s=gUrQ>jd!Yws-О=yb=`ˠ~wl9 z* Kmx'<CNE Acrߙ㟸{ v@7?NnعWӋ{`rدn_No~>ܽ9}9.g`2q}vWep^T}Q|9:fx1=y4Nd0'7ޙMYԹ*aށ_v_ꢵ|Je/h_q *ScGq^韃k-@ aX&x,9~;;pN8 ?sC@r2!&^4 ]Yc|uNK`l< +U* ,YƑh +m̞Z'qksQj+Q3ES +`_vy8rd\;(׏BXO y8zt"j0Ul>TًGme{1cs~=y +f}ܟ\fwoqgǪ Ȁ͖acwBWOjj9@ ˌ]  +$vU4n,+dtV֦Wӫo'7?T'9:?C2ɲ=.I4?c7^7/GoG_۰sLd xZ=i|}uAruOg_l MzT?0E1Y~_ +L:=o^O_>>Oz/w>ΞD˨̺w;n49x^\E}"V:,QjLoARztY} ?>k^Vϓ/C}q+q{o.wOi}܍GEmͮ:{wchp% Al0p~pGߌϿόNkoF_~Mo9\ﭞom~Sez?9^tez}st\?.ĝd|Ӥw<-,`mw?uW/08|au_]6Oǧ_Mn~.h]ϼ]|Z[\}şg׿Vu8/-hV={G5ګOFg.~w'/tc:~K +;xRqJVUW7ᘴV/Gg_Ugw{ZYz7G+Oyw L褜UsI%rΡ:<=9&'c ؘl6l168o}~H{ҽ h(Q B72GzL R8Hc|uyQ!ZR0??#nR>b6@Xר'f'[o'pMF !3˫ :Ȉh cjmJ}¡=`*^ 3B\_}R1xCJ^^n*-=_ )륉c\thm>5}v㲗My[YEk۱DksݛgǴ)Ϟn,/N\lmݨM5?WFm#>*Ξ^vM2 zgozMF_sFs3ުV]΂!e}ɮ/,T*>H6X_.&APxMש`YHtE-?: wVΑZJ[=[5G g\ +q]j:tؕ`AKY:6˧7ST":^OSl|\H4֩`Ppd'1/Q6 +fBL)F}ULsϧғgZu=A$̦{ +jv|\JqՁ}.!.Bn(?qSZaR%՗]7pSJnq|΅'VOo%\(1jKFuhq~~~P?j"Fp`6?%Eۋk'kt elbV.6W2n, 2)# 9& NT3v huZ}I&.Bn.9D?q!Pv>?"e`2^䍒9ӭBw3^iܨ`Cxm3^Kh-mUbHcC-,d&O\r'XmIQE.j|:7y$R[}'3ZabG;ז=P_NG:qI@o/6"xs0s2;LޘZ=He)ڒ2Jv.ڞؾ/?wQLLϝ> 0u,J=_ӂ.oS; Qty̍gXdgKg2|z3P>. 9pJrCh匦юkE \ޛ=_8Fȹl{6<{m}p{_~I<89%:dh(/OھTgF]̘Q#`nAnz;3Nԗp 3h]57Ƿv- 3ƸAfVn`yhqj$@Tpt|t :J@hP$򡚨2p@**>oaj*xc T9rOSL@P ?R= īKi1X:Tc#rn}T +SBz9ڻ gL^>DcEJԱܹ'׮["6,v7a ` 1@ L`BluB8 VB|ڨmipy^0" vVNזk2ܨm ԋp!t0:@U!6@t Ut5DCn庇3CBcCgD`(dHgpa!@'_|3h`HČ֭Lzʘ#@{ rxFL̨Ʌ9   x7V0Fkf$(JlʋQAsri|e< Q@|jŃl HXi!>lo%:;H" ]>hbp8iIO @6ޖ@dyx4xz'$+|QsPv/?jƜm:N/B%6TWօؤ́RDrloۆ*hbWjWll-_roGM c^F΅k@. X2 V+;yP0p&ӭBAOk><;sjj8*Q1cH%mrUbWj.] IJXZ>CeJ @dzYPNDp#D9@ 3"0.XtA AG*F{nXg~oĆAhL1Bf~R⢇= + wp a IvA)yޘ) JNa\8eBFbf6ّm=1yt 빩HeRQV+ +sNT+R_Z>1sMBdע9@7.jr:Y`+(Cbx`>P=NfWΖ'j`@lB|95XxIN pjmIaB: eqi",nʋj\3F%}WMiTOVi8>kyZa|̉0W}\|bR0SVe!a5rBAՋ |9o@C8 #1>ypP zRcřPyILg0Dr1;:fP>Pf:UP.$4bŊ VR|<9 v`*Cl8Q9U aC`d|;\\NO4V/iL PD*'xCM==̱bgǼ'(3bv=r=PՇyB( LO&; 3 Dw hk*ڜ,L,Nn9tK'˨Vm!TScm܄+!ƪi)Zu&g=zHcTlI,OPdƫ&G 7dC\jFi-tMHU`IbH\an)ҙɆv?fy)fr]JG*>^F0'Xt1]?(dknZ㍖AD ;F\N/,X^pk>.>Nײ52Q5hmNIG& +a[|SS~!"ˇ.Nn!OYc\}&;Â19p@I6@HV2RG×7OD`.Bfb54<*F )Rڍhug FDAjB\tP +VbCE6RJe9Yӳ]=7).1 ;@لi8űJ)]]1.;fG̐W %sט~T( dn+Sgo\;?/w77\TEQeS(IsBmYlM.έ~g9uf83qN0BGN㵉Bo9^ ҡgnO>Ͽ~/.K6]HpUUxooz_+QRQI)$JQmM/m8||zU~هc0@?Y/k,V&.BgiFg|ś-(O}_??g_wGm 9Յytwj}+w?r#}x/?ŗ~7>COU2n:`Aֺ7x_{>?y7|_yGxAhB"ҁGN^xƍk}_>O?}]/ߚG^ P:Fᰞ??ۿ^}|߾?ѧ|W~ы/^:vIV(.TR`6>09{cO~/?_OwϿ#^A9 +#f9`[6z=Ͻ{~߿.8g׿}>?|׹+&#>BE=F +Xena}/{w~r 3?7<ͯ{O~˔V6.2s8a 'ߺ^}@4__/}>|s? VjS4s|g?413pڙqg5$I?Վ8 +F0OvZژ;uֹ~ o9{=E3S@{>pF݃W6SF!p[\O?}g܉s9}DN=zF5&Յv}_O>_|/민~ꡇScG' endstream endobj 48 0 obj <>stream +S+ܼ/O^}߽˿sGn-ZJ=@V1!p@VIDRG<ԛG~?w<.\I9J*)LV؏(nX;d3doY,tTkFŅHH& Ԩo`$yǔ,*tC0R1bP*6bϼo. CY݄n5^qrgㄐ0ET㴬1 9<~ c\NNtzĂb̾QY\6+~̱F^ `i(bs}۝?yzEqNۧlH#,vF G1[G=0K΀sWmZ|^1^ x{NwmT>: e JQ= 9߲ע|` 3? y蠣$aJr z`67 !A^Pba'F0,Aq_4? 0IVoFghķ9dv [\fQh`vd7V`v+z;  \20id ־QQK"|Aq1e2<.I&TùF 1viq۽Ia} ?D K1fAֹQV +\60 4н̗dL +>6d2lz aN$`sƭVԏ@ޱ״gb^=!#ܹoН~P/!NxAz=> 6`|!lχk&@s^ -}cȨC"}/@0ِ}CN!2&}1>8kF=%>fŇ\#c> K+cq* A=ltpj`-@II2PIG6D9!={m:2)ZZ .Ò4Xqx{f\h<_ɂm(Qod+uVbq߰׃ȌCv'} hוD? 1!N(LiBގ6dFq`n@Dԋh)φ|4E?e6$>ލDuz8:x!=Onn/cle2\&v) b ;@,|qR.܇X43 Pǂ` ID(WG䘃1C Bv*{.D3D ڜÍ(11; 0c37nC&H'Rťv' e'=lAI;ݳ5>ԡĊQI>#yqT?bq/i͍xrb`XJ%] +>5Nςg*bҠׁ 8.E:sV88p&a)fUkmG6ƌDG\<J0#(7Ģù1&)hNx qBV}fv [ljG@1:F˯"t\I)UR)#@{zi x V`K3J掽a@4dx췹RH|#8 +eÕe2Ә\d4نMtLRbhN80-]0tf lcC@όxTV"92QXo@3YIs!J sRR&D&cA|L + Z I:U3ޱĩ`q ta"Ba +vZN}#n@:U5=/L<p-hof&&Fzu (oW^y7 i@+Pf)Z¥<"Rb3Z@{Z̹Sdh Z-͆Y{ҹO|4!6`91o4u!`^GN=do(9Rf./{0 \ \gCU07w kU /~8P7!AU59gDd{4X7lX],DHEL(PS+>* Oqw&62bx+0&l?,%$7AÙRu19)BNVa߀gnjqr4;si_"\ѩ$.`lyq!štVfC 3ǥpnd2v% T "ܠLf8Pʍn,7uAU<iqz"."@Fm>aԂ SJzB/- \*YBSzMHBg5wbнi3R=aFS9S VH&frJ~=!J.J ^4"I:mJ7\'] K Lm0{fgͧci RY wyI1Çk>]_8}dkOkLr-\x(ZrQF(` &f-En<+t@ڠ_4PKle.j&d( "Z~Trf'D ' aeĊx`y)1g6MDf|B)2D.(H0˳Z@.9}'vl[1dFM~`%lAC6Bals9GVf§I)-n@N1)cԷnGnjtG +p3R Fl8fc5;(J`iPy|b̭gDkEhlFKV=jy%29zr9]nOtac Î1/,)onhɮDs~&^)7¥"8..5wx`a{@J"lV + tu)?is<R8mI~s"OƤ +5Ɂ&q(snf{{NB~ϐ;(E;77Un'>ʅ܂'9}4bu^Hq`QTA(~GMO%k5(nv@.zGC"'LaՌ#/n74 BFQnZG +IL)ǫa9* +ܼRb57f1/(nXC%"L U@%TM֏}ýx**+Z\;ع_K>&6 q&-, 0^,BB6bB nsߘb|XXG'H k,D汛|`y!.,itlDDZ], xf#G<a6:ze:w荧+1d\xa0^ёYe#}.39)A٨;xȵY[dAl&' x(#EG  $+~[C# R~M- ++cpH6phߠ[Πİ{E?{yONl0 V 74itJڨC| +bӔƃ-@0XN_h2A*"eq1KFqjψ} +Z Jy 3q4Z_O909_o,_MϝΟa&DE$/ pE:؎U7I H!gX3)JD,&E$#% ԑDcr9wx;wS\oǣ&/(!ؐ &gpۤ\N1Ϡ%53[=j pa΄ک\{0{ +3].d>2dXd< ;,4bGF0t֥^:x9:p)…AxX3FRr4xx3W۽=U@\@=7%gQKTc/2;y!fq3&'a+oZ䁥;aW"5l#M ҁ1!{X{ڽP~#"2NF>Dǜ8%HO+Rr\̳e ͂=n`dHA L.CD0)O|L4 +RALoQ! 7 DᦀsgBNu6Kƀلm^!P[0Lʹrw8FxiqeC8sAF.>yo?Mj9PGn**K~"uװw)࣒|mfm@l/v_>:f*Hxyrb+F~_,\9)zCf ʆ(XX"$;@HX)^L>H{`p@׳2!71;p1 rpi9?QP}m^⡥ǧ?XY<w `8pQDL:i{ BkEc}v70ƾ1͘ݜ &Qj}4fEڋ0#ry(,|8*pFu<~nt=UÅ(1KJ9F-r O6qvCNU˧ D9RRTP07,&;b˅@ UaVE8 tZNSrV7ؤ,AGx!A|a ^X' ƥFPelLJH-(Jтk~nz6"U[I'ks0S=I-53.oƔ{P49I +J#tJObl>3fc%%-.\bz 'ATs}vg~Z(Raiюya^ 8 *gK΀H+Y`|0. iit[@jMfA BcJ *.(:;\+{ٌ :֪rb&_Aȉ9)>*,-/{3w( sd0}#@} @!RWFcsnHuA*H`P>|^^ >vbڻ^O{ 8|̆g`%FH8R/.7}rw$"%۝X8+u Fk8b fx% D&D?N{ ).MEW!@0`U4ΉPL`B`rJ0.cuX#[Yb<&D+UPJCT+M MvXr=X8Z9>sK/yYݸ`q2b|acހ@1PMd@rf{Bʉ蛜"*T\vS/~;{L j`BX + /,rxS7=a۸6,FZz1M6(*PMl ++;XuIOih뀘Pȥ-̓ܲ66qੁUOQ--Uzkrk-w7/Z\Ă-? +Kg&WIcĎ} B'(in&ʙDa +&CcV5/brfgv3'Fvr#!TH<*ˏ'?cVfJG2fwgrD sy3YSl>8 v3bijo1f6t)Ҭv˧8w0\NHq(fݍLm \ 7P*3Ϩ 1  6|B)9G(``IB*S|hM:ƀӆ@FJ622"äR`D-¸6#!UXe[d0 aKtaHܽ.\Rݥ[ջ`c،2r0KkA{U`*&cxqw޵[3<0}V +rfܴj9H7䱅{]k.y@& Z ?5^E1'̵ˢ + +S5w%B%^6;"*f1>O)Lc9l rX =g<-8Aٽt85ќ\;3wbV&ꊱar=(ҳ+'c b₂G8G1 rWu5C@h^8;g&h%y"\Mte8*.Ft:X0Pz*d6ycA2ؽ؞a˰) T]bqуd梇^F"'Q QQ+X(HQw{9`Wd ՅXVˬ`&;>r3-ecE0duJ(H%P ch(9er@e~́ف21ɎP8P\VbbTעU([=iU'vV; n.:Ulnzb<J ()kny8OF* G:DibGy@4 ̝ZUS+bzV.۬^B7B]9sc +ټmЦO 1x0kP6\}8u^]S\ݺ6y@:ՉCڒm$]NI؜(Q6Dlz~Ջ0vZ*1ARJc8Glzqxi}b*3u~&4jָF!M wܵ &cb|Ҫ* h vR08rzd PL6as./o.`!Fl>'CLK&NuNil`]鯜G`jfKY:ܐSja)7q2>0=O?X;rxF6T gq>:9X)6:t֋FMv v X,2JR2hd;YNd>pcRP~9YȴMl\P9)FۑDgZOQ\/,nZ~L\:Ј[u{MȰ ^MIi`6w'(Fu=9ZzCמv;R5O0ʥ16+[3 yPU [ׯ5,Qͫz8‚qL."kJ +\|`Fo|kp2|Vjv_EWP]u~֏I@*%N4۝CT)eETYsq>RE4JT`n %xa V Ӎr4t &7WX>m1= ^<6r7Mgt&Y(MR9Buh0޴91 ;,iy*eF1wcu2ܜ*Nv.C&eHCf4==s/&e;ɣZv&l2^yKTGu+ݶX9ܜs9P +3+Ŝ T$+ZѶvm-w3qf޼ff/@\s9q(0#؄Bn9TRϩS)lګ0rDs5J''RVx77i0X/ ؠG78ϱz,_Ig#cL*gTlzj2ef' ;[~ǻS@j*Z'^/ڻVe P5aL?91Q)nW +]L6U][izVHg @~ +yCQ=a+;4V7c~|Cvp-ݩ bf lJKN|VӜZCH; x +`eC~qpr 1A+fAOOoΟ}ƅ^Hڌ :&z6!t*:dyYU>< +)(fBP W0HCagScS P) \d0c\ MV.<ߊ +Y g!& 9JLm1K!Af[,Ni)nhEmw^0[;^K/ +joAfV9FTkoyi_?36|#9]h .<:džCC^"F|@0rGw_»0e8Unjvq|j0*Aٕ%T-F8¥AhaF#\-0e fhnv^SR7nϾu<)c(FeoX`Ćˎ +VNDkq~2qu{‹kG{'_Ϗ^& I/z#i$ x|Rk!H?~RO_3'Ox;QOx؇qZJwNGHa4W03+S[Mm??8/~y\r)ܶgh{TAFyu t<P=āKVy67|ʅ{7^oJqeov8t1(Z蜯^ +K $:0H!Gb|ʯfm4čXO E !ֈ3e0) x'X+37U;Żs[G0d!'*x1^.q?Dba<nrW֞Gp`[Fesy#֚{J"- Z}>պ"'zAҨrx|sHq jsz{}j~/88$2eξ* +fuCAsV[`=XTkK8„4f#&ٕLm pncpwrsNe1J + ^~ŷY0iBp#Uw,_}{!υ` 6$ҽç[7[] "Z}ppsou\j +#zF/{p֪ir;R#رSޓap4i~4H@%0kf6;xMɕYz&׹T_6EI1bm118}!H~wQ`ļL(@ + ԩGq"3̥ɕ AZ6s6^Ay3wnrQY 3h)_"8IEuI1MбLi(0#/, b~BI l*ULupjQX?|#ݭSzG7^Nm +iX\0#yݧn>aADNdr}u=,7&hB!׳P:5_& `HASR}V\};ϽD0իjj&Y[_عs{+\,7p[ώ?!X؂/b<{D73#o0y*p0I1ǚN{Y*Ue>{>{?[joW螹'8Lqqc= s>Xc#X)q1ۥ/…I1ʱ&㩍[+R1uxLn-)@M|x3ؐr3~Ƃt2^ J ؎p9jhXf&LU|0GAꡃ[]n}x=ݏ9j[K8y~É.gׁc]ܸ QDxsӌq6śT|DdZɤgX+@&$DR\xa^vj( +#G=Lc-S]3i`&(cICA˟ IVsɕfq !b$kϬLDR PaHz2eɮ~qo`6X.Dn>|(p +Gj(~S{(a"NUbt \Ahw7cSA춑]3ۜ :*RJZ/Ϟ+tҬ[svUgwHWw`U4%I˜ "O ͝[.?_[0|Wo )%;:o7sm)uw=.b_Lue{WZ>zq:z{_xD IQ%ĦشlZsݗ--T_:^={+ދWW +޿3_.\sm^텵AE#bPSV-BʓzRx1*LDb{@UcVVbr +kh xZLf/šAgA"s&$8$ n mP`T1w~St(g cÂ&lRT7|=~* Lϴ+ghÔ%{38*'OO? +u()c&z܋?s{b$<%O2r +e,‚UZ$;YL{֮ZJ4yZQ& +@ۼEj +z XqdRl~Xaa͢Qϵ;K<{뇯>ڹʹskJ'&sWɩo._۹[]hi. +[޼t(Y>5 ++-?﮽$y}sKL/.E)5mO=w3g_ +'g'.9z!RՅznac^+JNK9wIlz6/N-&iJӇJf5Bf./&fX +77-Q?Ct >1:Y "&QJ !,[@1Zc1VԜ/2Znav2<2z55NF`ű v5Lť'9IYNL q% +}x XJW ȂQ^)¹w_6'W>;;^Yۻ/u/zkrnk΃ds]'Ѽޙ'Q0Iv0sDAI=yCթA-?l{vfcf_w>a!+Ҩ^ݼNl;O+?57}V1٦Jr)0'5 THIVsڍ?\0JF5T@H,hiX6ۻ$$P1z]@k2)+?{#vT0p AcqlKM"|sO~)5;'*l/)zb! +f V~1V=c0v3ւ%2Sl)B RTV QG@{f0:EsR{㬖@$7m$w2#$@\qJNe D5D:QLU|٤ #;͙eȗb@xC$mj,(mNMhfҜo̮{ n'U)r*婵݃{oOfRJq ,n]uV3JWT}kBLkov v>V|갶G_x^67y7 M>4v˳Wx/^^ZϿ HUރryr_[@P ԅ/_~{ͥrrҭ7CSC1) ^]Q RR I饕78Ӿ|]+s~z Ji#w~%K>6gG[cNHLI,F1rP2ZR>7B%'`tWQb&}>!&:ve?7sWaRKLߏ>^qG"<9@L 3" OPV``~ƋFDCà g<(?i1fQ|P +\R17%X&k1\wxCD9RbR_8wvEKLƲm=A84c 2CH(.E L iu +D$M2C&'l +d^)NB;vÛY^KhV´DɈi^-B S#QГ֤'ۓ ӛ7Sc,c@R(gd\y80AYČY-$-^-`i^􏲽򢞛%$NwoZo]j#<^0K|ttǏ,eʽ /ydp"JͩB @K7Q( L>~Y 0|caT*18ŒOL"R$@(-%=!9B.Ron5}ήh(*uANBt(̢Sqh)J*FZl[ 4C 5s*'n8Rb 0$&3g;L|})`jDD%OIݩ|ST1b%,9 J-`\Zu;F|`@P @L I1(!)#Iuy}hE36%9G$b0%qNI0-REH+)Z߸pl!a Ff|fC!Ǣ ވ"ᔅs)VBAC˜۽v{aJ md4<2M3V2l3=Tx=%6'Y()yNz)1+5-43ѪNq< 2Bx +վRB(1C4NgB %wwN{БȨlO LaxLh=@}јۼO75(JX ̄e +@Eଽ](U4(!8 Tyt @`h!!9TN5|x0(8jʒv˜ R$b A/?:A0bB 0ĄD[4p= D )մ`6#pȈ?!L/+O.POyhv~ws8mz|H0@@N]%hS“8GS⠀< CJHJH`0aAgGǃ>11|?1WGRR@ҥoQ Y6C!)҄LGXr`c3όy(?~|4VtA<=:F8C,yvj$̉o>qp@624f|5-@`IR*"lr jۯ}/"_8yj$ #iYQ2]s5ca_Έ[㠴8F00dQVQ@X4b5{Eddዀp"9+hmX("3rbL !z3PBIPj$3.{N(JjZ +~p`D1`!uST8)<>~7eQ0KBkJw]GÁ 1IBI$L ` tׁ "pn**F#CccOa ~H`u=`ѵr֭Rn^sGǁ F,i߳ GqRR0Ѻ݂b`QE%Ƣǎ:11> 1sAzTFA#Ӿ'D9 hHshPd| ?~"t0ɠ/ ÉTCuՅ„CPT Nx 0OT A7׊/W 7WF嵭3ɪ,jB8~|hb̋!S]IO΀ֺz1mV7E#fҵ}k+o)Wã tjhT\] WdWw2Ol?wW|O?xᙕR*H +Gpn%pf.iv53e `( +Zب۽ U`/NOla\Hij8ٵRHB0$JRtR5bT>adyxhFQa%RB\(YbdUvf|{O<}xε3kP SP %X-MWnXlbsg飧{_џ~oε%]Qd0 Uev+*R3WblZ,L嶖;w^tƙ_8|᭣sZZ&dG}=><N;y|tl P sD>Nr.>?5ʄ; T<={w4!EJh@ q<)yia^Xw^|y7?w\?@hcpJq|_{b~B_x/}ù.~ɍC`V$&*޴[,w_{O_W~K _~߿^yʽs݅|st3 OZtzxܓ ?yʟ~ϟ?|aO_|lLyC!@,"a?0qbߟ1.-9.wG|nn6"H +ETLz.4;+_y7ϿϿ{g/}ֵ|6&Id &ljŰ"t#o./'tOG._?~Žɭt A FW+^vm/]*~hgo?~/z?ɗ>8ZS.jK;5?~x7w~/p?~;Û_rof/*ˍNݻ퟼/_}~?}>g7/?i#j=kD#4i4We B/Ψw7GG_]yoW;?~;I#PLp'K}^ۇy߿_^|R)e2I`z".E Z* ;G{yc_~GO|^۽~n(V43#(2QLdh-TxQI\߹8}~я^?g^=rvLL V0U1iN[v]bR\/tg/s_֟x/x_~pſ}?~tG/K/VD aө)Mrt)+ݜ^>Ƚvǫw~zӧ>\^Lä9ReBJδkS7ӯ^>8yw+~~߿+[? ɥ슰$0δmgpZ|t_|g^{R5e倷1AJpBRѲV2rL-Z#~q6ww^啯?==k?xa{/W35)FXLat @ !982nT s_zO_<+krB (F4Y`r8ω `){e5`Gg>ywj&>#LBQ>Nΐ͔u~uo/O>~歽յW3 !R,r&jČ#6Gj.6;X,];:ZfnNGcQDho#@8,+d6{Ά}OV_wW.{mꢙy- +(hn@ύu9WwO߾O~W/^۪,wⶥJZF6Fr6`Lj9-[Tph Yh!}gw|2USJ+8( 9($cHK)JNAg +U4Z\tH$V8 0Øw0 ɀG")TiОɫeZq!]Y*ɞ*5m/GFOƃQXx/ +;,ӄIW*ilYWo̼ugхsjF`Dͼ[,,)QhMWtE E +Ut+B4@G&0:(Y D^骓Nr +SO9Ll$""Q&a}[+jGY 4j7'3xA](щ &T崪lT(_)qKO8NwzJk^Ωh8r/4(0A {IsJ6ۖ9&.a[Т +t=sxܬuIq0%nMD1urěkؙ\R̪@"(ttht"/J9)E G x‡T8*Fp\xp Pcx%LIFCq  4"juHU8Q`\s%; BSLgv?WZ"ɖ$$ʬWT XdPٴv'Դ떧t=JHNí%QRRUw4NG,5ČƧ99ۘchD2C0 $!+g2˜ Ҡx a]ٮjnSJNJIVHO3Fj;U9e?"RFJMEt$cMx;1y椗"Wr[5 +y"LیZ!(b̮&o5j  g5 &%;nYZyS/Ixau +׃ZgCy]K y $R1BBuVg7qJPi/d#XQaDctQ0/J`̦UYwRGZ9frZi)@tOXƕFکq\?čz ,T @I%D4 cR bSѡ10 FEX.RM1FfшA;+V|˒bJԈ8`: 氇Dn|hRb#44 +=s7:t0"Fɸx9kb-A4©!ӛZ'Φ4|2̸jzZI ؙl)ٞW#~\.b\:8wKCR5fK rbG q֔VؖҫނL|6&* *F1r Nn~ʪZi=~8q/vDfz3۷} ĂURKVe#ºR&Vvvtڴh,? ,-NX <82.L'^8)JÃ. +0GlwD_A0L\o3iMj6DAHkL)XTAmOj9kaHugwܲU\ ++A'YK dr,e1>?"tW+ӡ.<,ޝ0A1bz0&,f}XFny4a5L$QHk-ѝFl"*h6*'J>{ı7(4%}RLoH`?u b$xkNvFJLABJR]J+$fuvwridz6B')!b +^3^@v:Rj>ӻyp+$rHz3+}dlq|hJ\lƪYl);%0iz62+z~UJr9%:[wGB,mTd(7{gӲn}ܕ'|j6 *yio,?LoNCtJ.߶bb6;usAҦ2mOɾ^28즹8EHSߣc3Ӈ*tuHGBRJXɉM;,GSԐ_" ;:.\}OLNqȤNjZm 15XyX@<5GTL̊'(yċ:F"*nNUg3BCcP7(xOz!;@$YDG(،^8)Iab4Zli_?ky=ӍS-TViQ7d2v-;fg)5%N^L<"%̺)%ʚXnli8=Ljubvw+=/&;AU@ OT7%-5[;>fy.?sx+9 YDȆRr^*NZ[Gԙz=gX?9Tr+jv@J}9 ЙPi{oyi/ ˽3O4H)2 0ZZsz#69(R[/c%!2͹ V|q\4f%*AڇۨVK{SgT篰fy X{M̒Vncx5B&T*;ӥc(兝!JIk%tB D(E4r=rjFt) +vL\}XзkKU/tkSo ͵oްr[z$Y6"cQkލwf_6cXSdۅ󅙋fmKjYҬPv*> bIJǛ@B2'ڹX0kVpy40WxxHg+}1r*k#^SvoK)r7&p)H.ڵEiӋtO8ܵ &ԜVn{\BI 5TFǩm3l4'lIƮN wԲ[5 +Kj*U]c Jjܡ]2l-^n(B .,X垒_[lrEH3HʵKs4hm`XVvaev׮<`i}N{${yy#3[R=ԥ/ l|';}x#~ȼ f*y9,dkP0U9=>8+'!/"-Lc}a)wBP ?,=j "#!.Y r nu-Ѯ'k3v_O_P2ӜQϜ-ybu87c]ʛux[J^bӘZIT6[xs.^h_ܹyWF7p֊nyiӍKwoo>HuN'a llʩn\u s6 +@(:u!$S+ov6sk7qWjvYtqzKW… + e7WCtXcLHpHjV7 a~#ӌZ:@#8*fT(XBvV׮څY0;t}eŭ;/Nxu_..t|={q<d('AIYH@j*GGߩ<2'ɳV}0z#~Y0͙\ +" 0ll1;R !Ω$VS4?ڢT֫Zv80\:B%kN$X񱎞_=B/ Ur^ӳ YXV+V xީ1>u.f;X qXv*%3w7^l=_bBbbBAuU(lH6l#]$W9#d{$H'^b kq[&|/BU޿SWU!6)噕uoMe/XG$7:x>\=6 +\(o=%flyr7>y@G$23[\Ok;o|7ba4bQ_4wC l΃xsYZ۹g8¡@jMa͇QzrOt&X jF~!撕+; Y6hK& vq fӣ>y00BwykR1]o8'YA}0Fs'h!5Jbŭtʊ[Z/,{&C_b̶]4@`01 R`@N7ı.kB%A9Zr$iWɩʌhZk-3"3+ui]]]35۳;챱/H3i;߅<Y.y 1l,BE_ Ϗ|C(iWI l{tHVO?}>zkB0w_v |pE2DTtN4;p@FOJB~!.Nk\=}aR~Z~#EsؒպF?=|qs3~MvFӡRV'y[!*eVa17h}<|M8xXK?sf1]7 +ϥ? +雿Lk}l>?77?N>/_i|:uYc_}?b׾G_Woy>x/J:}_haп6q{|~[9qc\lƋWμl?];y+ślT#9{ݛjjwAp.>1ޘ6gN+5n$wݚL?ڧ?j4A_O8 2> *<sJieI &D\_}ۢ5tevZb9m_.%ڄY!M_}7˫dwAϿIfs@kmKF}N?߼| tQz'/%wz 3?v{j&o鍨_|x^wzGR'~$P5R`U&'G(m8i!txO ׼3I:;'OAKyKBJ)փ Hqc_ϯ~0[50@W;CCM Ϻj8qxvNusq?"؈FfLYk 2tv|A=)\2Z_tNnpP w'J͍p8|5;+?`Y-dpBkuڬsҨز[Nna@p +pE> +G TmN1.W>{ZNEGp:K]\`S>b>޿j!l(|(˟as܅I٥3c\pN(? z r%-o}}dG >㵁1`6?r| oOA lÅ7/?8}m='ͫOP6.#:B35NEn-Ǔӯ)+ ~q{]f+ 0?{w?}?֢ F8ԃ t@cN#?#ZbКoL+`@Je(0>dm !Rv7Wu6NxX4`=KH3iޤp Ywu Qe7;|)!!Z@?ksx%d¹AfgWQQ@bCJԹO>'O))]?& +:F3CSB,;33栚QkۯͭtiNYlk frJ(0RiԿ&^xw7EcpJL;J +@Pbt xsZI@9P\X#-\h^Z`6ʊ7M8Ƿ`g?#'\g? +m޼9}mg~jm|NW1j epp?n9k#+j$-;;J'/O~㵏k`pozopN X!pZIC3H_{a28^?^Q1}&ShgGٛ֙@pr_$wV䊨Tw`Y%ZN -ֵN]gZwr~Cg'SNMdo|4= +'qibL䤻e<|=w|oˆ>.zppu4&|zMmKBH%gK9 8շײ3zG۹;rW닯 5o׼ʊg5jPp`59 +ךr##4=u=v!%ofo{--ο4@y}]4&hN:_k0nh{bm{ڡ^V,NsH,8Wc:\#h8q2 SF[o*+IWE'e +g|OkPw Do)k5=g*\͏|~v75Xg#;/nr<@HYQ=LUC)8)=;.\+@Vsm{0ڣkaulY5Ues~sgo^RQZnjZܟ69dlr 5?g8^Mâ,pˏ@-{0?Bג3Yk#e՛fDO{(l͛R>1I1)jtL;րUr-XeRHi9ouh ^i@!\*9#dK8RnB*c[u*$6kQ:ǔP?=Zhj8CFk|pD'śz)7r2rv:QET i3j,9-ٟڭ9$FKٴ[NP4;v4_}wN9w +gA4<F+% +֯}.B3h2SqiJ0Jb(lS/?u> 90zMdgGu{ 31:(_]X{+=JK/ɻ5M\m1j'j~G`xc":2E+Jķ(q}ETӷ߻Rrљ)2_kuL+:a6ۨ gMAᾬ庙[{mN*=Zgb\V۩**hpZm?Qh1.10&֜ۿIVoCZkn9袎'#xv1ńQ +z0n/OON>}Oc'Eo⃶=ev`A'V̭ԚOaf똥ӠyRN;BQ0 lkdp=5!9#Ak:$ 7ߘJ' Ac#ZɮAqd  Eݽ_e0zFʱ1JfT:6 +iuFs1H/ NC`U۔*.%uwTaT2 (eQ6ጡoHOJ-=9}5>DqC~cNN$5[3?qjzDY:b 31Vmyt&=o5A/V2HJ"hgPeq֯b#`ONmEE6 c\쀈?Himvv +tUk [NE L{^RH ,J0ڮj5hƉ`|:[=mJqKwceG`(*6JA2լ%2@T'ۘ q!E(g2BxrCӜp5g0փ]ٞr0ӟ϶Jf1MKQqE)mv0\2;eZP\3lFsCǃk Iw8=|#W3D<qYj.nt)]CB`Meee {5?|t -} qAmŃ^֌HRgЉ@NrLx }qex0? ꘷~2\ljj#3949%GU\5ݨw!HdFd p/c}nF+cE5%кjlcqSm5ѵhv~ߜw>.M0(9S[`Sʺ;cŴuA avX*\,# XպNGCݛ.%;UaU;ZE2bh9 }M=).A4P? .3]7^sJTjVMLX z tokp{cH RDʶ1i("ꟛɒs\pM l6LEq{RKB wyOBVJLG7U)"D@0Xכ*n7Y>$)P8ɔ@aI օb`T6:v4ϊ!)Y{pIj.rƪ;N*c};{cAL&"uAnZ(4a8ǂ88}k 1I0>g.OQSc6(_΍_z+]*c a2aѾ7~JI"q7p|5-Xނ1o^H>v<<V /C5gV~i b0w1v*/ +97q]HIW'J_.=U60BMw_7p|xRǎ ).Ut~Mq[f 즺cKJU:FI9=bxά!$ ƇA؀.W]'1%ff;M{6;(ߢ~P&`4C= Fb] * . ̫!+FSs]K\zL/osbXR1@@1T˜:z+]a׀C`p*] 9W uXP\&NsC9.FzO^zk->%^ƹDjx 0lcUfCRWE0/G_1ztpIP{5Xh{>*8, ek1d죀*@ݕFsޫօ2"abcY:sm,$0'1enT{XBV}t +\ Rtۊӥ>I':i)s8kS䠻~ +]-v-m&ӻb$)ƪ;$PtGLq6r^\9qCFo֒e +$j\'9Lp=o*aeFP` !٫=8۾m)fB^x`ҽIܾͤ]7_/ €> CZ wy{ؠ*阒;=>.f2FsZl_1J 4!"BL` +xEkPB^BwanYcS$Slִ|A"Ȉ=B{PbBMNp`{ +&9oAt)X{ +lJ=`?\,\s3?\!W6Jiak85c:_Ǎj)J[`( ê=)Q5D-B jt޸S# Piŋtxq)&NH@kUn(ed n'*v7+VMeB7``-s(L4pwjE\QLv|rl㣭ش:i {&&ب2jP3j[|V_C;K/?*KaR7&5~ʄlkKpBkLTkp6&'r,0hWJ 1 l%%/#8PO% v1+NVk?v~vBJ)Cy.P c (`r 6.8u'FztW#'|*Т\>Pe9ֽQU[J!| +X ?8ٚVmrW]DSP,f9zς+==SV&p8\f Lo t@t%2ӆP]H(XY3{6ÃzEAB8R &գ (Մ*ѕZ]_5w_bc 9#U'MPV[j VQ{[\zFtԇ~J 5li2|>6!*U:8ao {_575%'tâkx7.Pp1tJDM y nf7(᪡2ʼnhEwVDK#ݗ M>b%JI]_WO Odvhv7j_=rZ']6o8{I*CٙIΘSPwUa[>ku @MV**@^HKOx81iEJYTqƕLfo$GzQ +iN8W(b~!1EgKٞC}jE!0 x1<уB$oGsxkC+:uieTZ, l [r`u!}>Am[SsZW WY5̧/`J:rhp +ޜ"0uM{>eܨS6)%ޅݻOAzt(R@T5XixsaV|@wԚ'e޹;i7( H֥WR {98 +)Hk]ۅVv@}p[Jt+}uO^?ٟ<'!g`!2yÛS-:O1 /FU.)qҵ=M{Fw'o(%P&F(@fM@ P| \a;ۧfQ TQnɁ ë-y'֞B^FRCȰF8~&Qskb"1INk8͍7՛@n3͛\aL`Ӿ2L: 0Qv $'IzП}a Ơ9n#L`$k[8ċ}5=ۗJq"Qz8=/3yª]p=>9ݓ_Ͽ Z-[=¸fMp~MC MN)8#pyL̞#yK^jGHx)nJ@uvEJmn H> Cv&5ʫ.ݗm2U*]H>Lj$wʊPưj;uQD/EP$2]/>}([ưU@[=v5q.ܮ +Rd~;nvRZł + :pF1),>-[ӫ3LlDPV 3F_*D,ixo39ZG6 %wYk_Ϭ! O8gIiWQ>1c#O*NMd@ w59"59{lNYgFBV@@rd7+Ww]hJˑց͔pJ;CʹUO7.j4D" +Si͓{w>#c8:&r| 6W_&\vx` Q/X2Y-X I:uٮU2@j֩ R\r)P-IIg7'sͿ`v)Fߠ*HeԪ5ٙg0_oۿ] O@K)΅2dͽpɳo;}#8>mJrn}Vz?eqADV.6Ihc5aqzSLwn<5H?3]ָtIoFQhP-k +TXFZX!ER}?Uq^\KgNj_z߫iQmPÝX"厕׈8gŧBJ^2(M7P')yc-. mp>ΥXV zX6Bt^[;6h?EٸTW+:$kB.Rӊ 7(U0 ?hF4]du.g +s%1fRx_Wߨkٯ$_%K\wԲ5c\߫:5mD'`-:%(NKuyă@Ŧ] +fۿ|k*D i;U{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa = 侵ܷ0r@[{}koa M!-z/OǻrAx..D<4Kcqr<;}[H#5Ο|=fs1;\UaSU)_]%K?-oooﴎgGGw>aYyݧœW{ /BGy[l}P|D,xSu|M?^E/?\rzz7s.wJEOzlQ7`v7w)a:N(hCPUaG8:M<OA(Z!gt'2ڄfآh@(`)9RpyWqL m;9cNDoraS&7}9ޒqƸJj0-is֔:']G56nC7ŭS͟{S%ZqG*!ǜݪ6kֱ}_1u1np<ޥ>h(9`&Uʪb +F3;U\++naP!r!nؾvgүajr.Uo0Bٲ5V`BE.Taܽ?N0s&"QޘڈeܪS.h)CNlL +3)ʆEJk9sJjU}RbjF!'g8 Li)G 735&]9v^%ܠ} P+ե2|LmaRKmVARZ^TCrAb|\a:iW*g ]Mtqگgi) 0&ԑj+SF6L;&pehâvk%d+wE}hF\ٓ䍝QQKlrЀi:* *'t'CXsA΂;ef\f…Dpޥ!tYfׄ0tZ_Zާv9SE WeG@C5h1Uhk`lN@3Q}B:=$XOx#p;9xGi(p[ ^C~Z'tV(ydJR) "<⍥ټvc9ܫv ˨(,98B$K`tKUnUTq.f0EU(?.TCW Fu0<^Ԙn9uH.5BS?G3BjTV>БdmsWq %X٩`o[U@\$+yǥ:k + MJ@t1ZҺУC+>%Ė?oa!k8'2'т=%lUx}$Yƭ6SLY{,+;; W(QROjt'_TTe:~R[Wܥl.h_Xzfz^WeAoHAb${RD4Z@ +ZQD &FcchNW*ÉҶS&buwWvGOb 1):5NPp퀎-jsɚW}Ew?:P3KZ +2 j@3&Zc=ś3]BtYEILB}ٞBDvqkt_ݺ/ F[ +ч r <`ɆphАb.%uu*Ta\C O bS!GAAh#)ZbLӐLZx"0_eR] BjĀ. cCZn)vAil" +ANW!@aޠϬڇ`0 +kZ` +( j !:VکnѐkwHp +z2jPV{0 Tj +JCvC&'o`B +$dtZG3 J9s[C5~:R2fjTqǠ橕[䬖zMRU{ݣτx.8[}V3LnZj[Lr%ٛb`B0Yٱ׾,?: Em0e9E{jQ" @x 8nvןDk wpX RQ1F5FuE,PjȰ"SdXcehu 3Uv ^fʘg. f\2@5`0%` !@N A`7p3:4Hg0]b a|*n] +ְfAT瀄8m; opܐ!@pPNT1Ơ<DNChS{y넾*p߮>$\d"g00ĭ5jMn?n`XCRxCs).^.XcL+T^ op^ Zmf_ vEw"3jO{/ &@ WzvDǙ'Dʅ%g@3ژڰJEaWBh ʔ NIKj}7߾j&D6JM +C=$]G: +:cN`JZF $jlW![5IDI:J*#*BJt6snAkdP'=0>.+*>A@AlJp$%R]U]#MU%6p(hfzn!vyRAA6tL0?_Tbafn4U| +m>;pNBRb +4 !X! j[u憷P)@)[!B +x:}ٝح3bz֚цNv'3R%BNI%k>4 26 Ύ (>H6؀!4A>RK/B +(pkAJhQc +.98{hO1')x39\` zc٧s]`R ` ŞTvPXD0nAA>ŠLJZ'\H`C&L۪ +f|qa +vT0H!5RG/b:`.j* A1rݛZA!BN>Q\-r 0PAjxP]9:9 # .oS AXQmmUxm W +,@+M!@4Zu<,]jl1 Nq.+?  + aWI嵼J@V.LYUQ`0e@G3=-vuM"[)NL6?u=v1܂m/yoWE6  :MUƯew#ZI՛j퀱Lg-N|v8kN2YKv]c|A68 +Ԉ   Ԟ4BU!+uL0!$1AH(p0w ,`1k@рk([Uaif ꌃ ^ؠp9~2R&/asB`-Q!BЇRdA`с:i1jQi%DfSjC#v{Mli۝- -.%wpr 'ay/v i BQ7B0bOBFM[v ˨D +w +a P g+ + (DT%oT8"%X Poqk>:c-LelOb0+AzR.xpC4}MEFu +bVsڄe߼K{e ++V#Jh6/Yk` ȢxRx5ܼg:$ ?Z72ƇȓM@0pviA +Sck/cL3RmW!UڲH:?!>ƷTq:HK%{ɪ"wPTD21D̼ozcH?`7 +|*5MPI 6y(]3jd"쇉@Cr9=<sk]hc?^rZ*ׇOeIsu\]:s>3L΁ A@@ DWwZf鮮>axU|~ +NO0JZ\4)"~z279{:rQ#LiEj~1,a .&NyDX(n}*ـaTF,1IZ +%7] V z/l7xЎPqpI(3_|I7? bJ$ ֏TI*`ՄXӋGs|!ɏEAz.D]PfJ> @qHE 2o/jwSC@Bveh0i+9B l?xxE1xjxb#:l~7P +xGHbI'r/CO*hFBքȱ7'uekIT%(xZDQA8L"0Os椏N hȌ!6'&9.I>*Z kesza8!D{XR?p@a1A䂮^6@1 ,Ќ~T 3BX)BXCt;sP ; z!;r` BCv l5MYfE7cQ-zB5VH(nʸhLr vюB? :]c&O1~ |WۜTr{%k_9W3wC֒%sIA A6<ܢ'ɱ6)mn:=}rx`Myp$h^Nhp#7V%%qd NYFvLFKM}MyƬݠˉ \,@c2TVF gQPDVwԼL}V?"\j6g|sք1aLP&VTRZnL^~ +J>Tq< PP> 0 fgUIʨwY)=X)6k+ N9/p"Џc`l^7cYK6A4Y67n-|ݧBSg8m< j! A%f[<ܗ "Q'=d<(hI@}馱/}edԎ}_N *.z`{ȿ$|aN0P.}~p@;.yp~rxx^qRv7 * xv`=BA0bǍ`w[0# +8mdH!& B0w谛%'@Z Fk-0b+#7,|P̪MBi{0kIŏVwn -"T\ك$ZԱ <n!& 2fR(G +BAkLO/]\ra;Hb >y:5A6tF3G("&1>=Cqo@ךPQ;_|I;|­8h^P_vA+Fr67'$bFO@D8' l nE1lC,l;(x*g0*0qzw?胗30v'=! +6_č$;qɍzr qTv,"Z<w &1{|E CjppZ 7p@5#`@AA,xCp-$`K7e02Kc~vH +nb2 PhT!E#D!;;7 JcL^, #@m!DR}1dh= fJ۽ I/jOgB:;# ,HD)Y^R#8-*u"Q|HJ7㦁' +9v H;8%=9< 4NKO@%{n:Yd"!19@YD'8mTe$bc5ACPPgӛFzfEܴoA@ãa,jNvA>D06j-Zi&FAjmZ%]j n=V:z0(GrB=f ;T "7'a~cv!b~g"Uz[IOF `:)Hߒf\E 6;_i8 jrcA [N O$ h:03qQ@.bӚ@q PGײ "VȢlXn3i/Y[P +ib%{(%OaL v D+'a$+Ńku 8d,3ȶ6Ne؄(N:175 yȆaãsZ +62Dy@,8(_@ryi; ![́Q? )UP7=>/ʾ 6sP!9}##6,_,N5\B?xxN ; p.^"M@UJ@ |bA0\@`-YkX*{)zc^;tr4?G58!فΰA _J1&KG2*Ś9 n̈OB{׆=,t H :k (b1`,.Utrߨ( !:?Hguǁ7NjFhk м 8kֺ?v6"E` ƈuW&tkhxz.iVRZc T <8;h8+89AFZPn 䗂AYsi@C`H|R@Mm`A +q*?a. upVLxpzPpؿ +x_M}}a-[ IJx 7/T/'c=hqD(bBb eŠ{kc;#?rc- ZeIp0DMjBSA +.t C*}(hS tO% I㑢 QR/r#UBkJOe~r^A& |d3&bP9I7xo +}P؃֤%AURJ vl$~_ + +H@_`H K$lDDkgf̆=1Iv?6gm0a2^2c F]*'8 +Hq%ZQr\+-pvkUvCx +89q_Iu>4ǁ< 6eCE@U]~yc2@Ry, +(K+rōAd"ypѠ㮰w-ư >m-x8E$#<P|#Cb6ڒYVouH/r-H%*&HjfҔVg ,R0.e&olr]HMhahK֪c %/!lVWq&G֧qLmvrj]NKaH(TjaEe *ȜR cm d2˜_7@rp8P oI{1p9!b>"AU(_>oH9*9ځ(8ctLJ !@|K iSqZz+@A6#Lk $ #r=9+`0hL-Hg ؃QCI/6\*P=o;=LI m5?)|o H`Q 1<C* 7Hvqpv0 X7"FOD1>AF`h5&u? ʧFh[O&Ӕޠ +.Ya6Vb &֦5A&viS\`.hRfi!ƤL$J-ʅTnc6!ALhAJ>x 3(E6i[NǏ9;"y)%9s:tq@m !chq(-'0ӉDP3 #D'ս'X۴@PhRUNN&RG +> *ɚ=>9KKjnVH°O"68i)HrPߋVXG)1{zeI ]D$cU%7f,2(v#jx>7{a>3˴m4R qy?q>֊5W[bMxY:0tD!brmz :.kBbTV] +\VSFeV0jJ:>kZOKI +6O.(q)3m6R-.^̊H9PJ\gx LPJьJsǵVDGLHIDh$Pq7 bvU[aנo`W4|$ezMrɉ SsRzvrrԝH{Qs9hhdQ[Z6JY[L(P_4F}M.%.MR,xMں^^wX 'D$.&C{nzM-X=fJ4֠;aJKN.'O:a!Ţ$f2CՅ3#kRo̫x{G`pϧCld{ZtiJ.;Cwn]?uO EHWn72rONJ ̉PT`QUˏGsF}#>$CB!\}QK6?srvI.cJi }ez8RvdOV{;ݻ +[G-fa|8NgN5W.vn!"iR-u LLPJNΌ[@SǮl WSgSCk |n]._|MpP+;W\@}ϭ[ܩy>=):R4-xqopSFmcrkO4O\^۽De:w.?t6ֶkAUCHO箔.ESΟpgń+;)Ī;F+k!&=Z WDzoocXIwwFxhz6X{'=^P20! ".va|t)=y&Z$|wi)Zyט٫Om/db5{$^w,3boů-Bߍ5+ {rqANN;s  rz|p&ۜ];㟾^<-5w湇w 3p7ozv~b|8{O{qҝHbTWcު'W/ZeM.u0śz:U(9.9{2(p*t6ИHF?^11%>xg\-\(7Hi/7o̞VKHQ5 8p`V̄QZnm˩ʩs^N.W.BWNgvc|_|70`o5[JaW?g_-( *7u0srq7v RQaVs쵇x8YoqPA'"=q÷ +z: +"| dؼ *fHz*f$Ԍd]hD}pr؝)BbJ +qBL(nfo^Y>}Zgr%B|sG@ʓG YKRfrU2#핳b1ͻ8\=<Υq1(v~Ґ#PԒqp8*TwJꜜ0&kvx2m?sRr֬5R!:p"0)g&[>Bw7w]֊+Bv4sPzfDc5 +u6ioϵW.޻p|HӜ*)) wY).g 3jnصBs TA|j~);b'.kj2iRf۬ORKB&Dǔd0F Y)wNfG4dUؼ5S&mAmteTedc osSW%pD4EqoI5 p֯O)Vs+VAŤ|.Ż75.{p #Ub3q|thO\AcL3Z EB4hUOfY; w6]%=#4Vd̵KSGSG +ǩD7(b3}0uJJbP6 R ӑTD2Vl/O46ٳre\}La|[Ii%_w8=;U>Q/]Vjt4h;Ah9,kSǼgp! +H-AB+H'-[|{={ܨ,(H'Yphu5;ަz_$vX*D3f+a:mO\:C&F8כ;X~znXiYI $5iiF`))klk5.x(wT?V`vbɍk٩+ЌJ Q*[{X 8 b͉ 踟~Hj76o" y)dp=&kFkjD 4f$5-qzH(Q]S2Ka +9씘#RYp&|zBdarkyRR*Y[,\JwEs`B6b6rnMnYzGJ9}*ȍtHĊK\3h1/sZ2֭3N>_*Ϯl_i/ecMR-ÀxI#$’H&l.KŠTjC4`ryD: bq-Qַ451A(97mF$'**gq)I2u1BiM5f&A6f +O"x}+V쥻 Z$ jof}ʐ &330>^D|͛Fbٙ[zk3GD]xL,ry^#D hͥ&KN';G!/ d-^E? TXJ0n8!iQ +Jj&VʃFRD{S,s!BŴd2GEr1R$R+,ˀcъdqr >L#@a>dlmBgRslE ?|Ph9wn%&Z%Z/ySrꬔҨsAEOyElN+(-dΩ J*`\aގa2/9)3Sܨbbduօ#rw!܄Lj9R u|gAav"I͊K{\I&RG^Zt΀͈!ĥZm|53 -V͛1Q͆h"f$* 6 S[z$kfp7wӑB,=C#1 Ung\uxY gT8Bp0Zm{:+U|!EIvK汍}CO>ԳO?_?_磿|߽sGX>d1-7 Ot=?y׾y~7^x~#6\.y +.ZJj9-QfA;~wO~?Om~ʯ//-(%(g0bx.x:]m/l.>3}:;{<~/~w鎇&R*BjI..TvXI5fT{.?yw?zz_ȷmGw£()e)ڔob,v3jo5>q{||?0,sgU^X׀%n6DDLDi2u8՜M5_=xow?rϣOw|cW09HJ\$JWfT3U4o]Y;~3W~/~~{~طw4],x-32BÔAGҬW'wO||m_#O{3@G~)X:~ͷ\7|W~׷>O?ɫy7N\-T +#dj|g/]rG˯F^3?~7zϋ?cO|}lҙ-LX,_||~ǟ_> @^{n{a/VaҼʔ[ݩ]8;u|?|7~?_>|/4#Zfv&ƘNf>v涻o3=^w>?yÿ~^owNޞk +Ѧu8cǻեcGO_k?O=w>|O~?Cwo} ɷW܈pc}ؠhӛ{z>y7O_z蓿 0j^Y<|ԕ}G~?~7o|?_O>Ïއ=Twp&ᨵM RZR2L[lϮힾ|Cz?O_w?_}౧na#3Ω-MM.on={[}~៿_wyvBs+NaL5NG"l7Gc<|7o+|} ?{WoŝmŬR{6UڋK;[;{GvuW~ʫ?k?rއ}/_W{yh <WXQΩs8sĉSwuK/wMo{|}Gz^xի?PQ\h//bNRJ=|g?k_~yґsi!d$!'ZDЛ__XZ?q3?~/o'w?o^?ڣN{j'L=a9LVwW!='^xW|7~_?{wz-ߗMHzΏҞ %t#묮~_{͏ ' ?}~~|wwN|sAT %aӫg/r߃>+Ͽ _'ۛo|я._ut,7(uB;LjŹÇ;\rѮ+a(=>Z R{755={ȡ#ksᆱ=x׵_3WnZ^7Hf{7CDVR艓l.JʱWo>W|O~g~셫gVVLAKh1R*h>~w7K`affg}<_?O>yׯ'/~Ge= )$BnA!&QŨrGΗ_xÛ>sv#[d''H2R50`/(tәZۺv7{{O?O~|׿[_bi caϘ=lwbL2?q+z} }~y^|J!HSڬRT$)>|λ~'{z[훿/m~} w&'q#;4(Jޡ;o_|'?{'}g]߽􅈁3zנS|~4r)ЬMֲAorunuQ5o)qяPGB!ۍF1PFC$-R% '84/ifG?D9_ )xӂbQ"Bެ흺s8],BA'!Ə/-NN\TTd63Sd˗Jvorq=sɉNWuQJQ^ahfKQq#ktJ1ϧۛV-;55-6"%EKE2=^. ڜO2HAk|jw~'xl.NO.O*#Q[!G<#~xY>D/rFD51 WX6T:S٩rEȲ zCpC2`T0\TL"&ʍ٭kKT#as%#'iBbY%5_0%glXl.ьEѢnďhvpv9OcU*ŝ3(xKV)rZM6#H!$NQFGMdd/@K9qgD3DKEPv/EY?.F1&x*% !Ap58M2X9nD M4v2d̚.M*"'ąp' $k*zMkl$ϩe1X^ԓ6$-)mn*qP=^wZDIҬpqXs9ZnATUnoQ?m.9dRmzETK7NBix4tyIxC"NŕX'S[M>6'hzdž0 !LR12ӣ6tuA+P1ځVW(1.KWVtcA"forZq4VH>SiWƏ #7SJIJV $ZuBF^!Du]-,H+3ipɇlF>6iCn @0QwsH@]6E!mq`x1q.fL_BhO)Qt9>${T P)"R1&wߐ +;]a-dQ!aqP `/ J, TT RA;>f~ 2zn2YEYs 2fؤE yB#rfz.'ln 8},dF/|Nirj^;:9P[ۜCfԦ=TZOY11&% 'O5/BуhcNT+gP*~pK9Z*jE7[vy#fY%4)d#D;N7@2v'jØr.k#iNkJG⍧6T(gKV "պJypsE8FˆGaj01+epBe ݥ|cj͵16AJy(w)VT)!DjThN9gA\C-P #y>ՋrjrT$؇F@,XDH-~¡A">,g~p̏ǽbQBC<.#>ΏǘL0G\+$ |QMO+l#yw@sӼ`}C0i*iAp)>+yGD`D +a&S+gka.WF PblA >1xm{ʼn>ZFٔ+TN4:jg;ђP/=lhMk6kUW"Y_[Í)7Lڽ'z;{צwh!!7%Ji냩Cǯ<NTrA"˙'' n}I2)\a2a.'MB4i-G<դL)ĺfBOrA5x! :%Xu?h}A$g.-e> +(tGC\P:ޑbm)ޅیz^"!%b5N+:QqNRb+ \*z<'ď3] M^kFmB ;Q 0Wq lQK3[ta^XŸgd?^#ӁҌ(cAa*M)> +ǵ1T`!*o¨0vw{п/7梜^.4p[jN1&ˌo-]ͶѨHƜQʾnAh1.? i0aCu _ܺj7p m] ( +] XC!|!B1ETflo1)H"y÷훈T$7r f~!U^x {NNϝ/8MOWƏGCŚdb6SݝL778<ŧH.SLleD5cU{9DŜ~@;PA2i5;Ô1gbP 0 <ȷh4 Q^470IhE2\HEiq$?fjMpRQ t#L(3BN JPJR!tRfH+( w0T`/ ryKp!c(c<ŋGAqpl8hG>.(.]91!]hS=@*g. I^Q7sbPDJ,i$Ԙ $^-sJӬRJTR->;PKl43gs./I/ +ZO'XIB M|([.l N +`$LNA2!:<b4YpQW63qp>*kJ&҂u^- % Dx{GíX}D,vb|c(ƚ^eLmlvb/=DiuZ_|wǮ>#T0b!De3:F;jW!lJ1dhe5&03}U!4HQjWm^㛃^O#ZZ\rJZ.pQA:Z:!OPDh41NO @,mFf7(M[a> d$5kɉa.Kon? 0\+.&F7\'ahQ[P6`bTHk0!w$'f?=͉ s#UJUfbY2ZUr3L(hz@˥OJΦB$]p.+L S.ρ3bK+@.-?}yhi$Dَ$:h64r amJPJM/.h<ϥ줔6j+bjT{_??q9La遜8| |֋v7F+dk3\䴒UfhBfS3ȅ*Q +V-hnfOQQ$PoZrK[w dP.\DEz7T;wԤl[ tA:$'&6.]* gHHoVKŅHy +GJ+=1\t(yF6.T7S[)oZy~GUs'ce7!Vev8 Q;WL{3 `F,`Ν}^8D'BU"U}냟^qTjpb+8)N~ -J2x|@i8~vΣyR*%ֶ^rg.K (fQ~=hw/dBC}l!D{n+-`%eQZ\q8zf&A'#-\ )%'z֏#/;7uq^8"˩@ ŋ$6jWi1YJ7lRӄVI6'J)Fzkru%#@[Eb֔,ŁXjKL%ը&Sgq S3Ϭ4Xuk_ampa7MrXq7GÆBLgP2q)6 vo$hrrE IjjVXuF*kMe$(A•c].1.}:F"G\w9~:oM Vgø!c>LbΩߝ;W_"g]xx8w?WVG=BJ6`Hi^;!;*57b 5P#}n9>6AtA+ պ#N !9KG.T"4gjRG 6!$xUQi׌PYf0Z&;all^z:zMfa~rNcVj¥6:>$$I(1D(xm6}@8B[H1)S\ ri)9BkE̩dcujbsS~ar2/\dl "bE),D;|d Oj}Az c^ Jzv<1=qa~BnA2̙ǧnP?BBI^7lopa!"ޗ9?ap {#TXZ9|pX%RɃCBLfZch[x[99 EG@~SZ(4fjݝp~Fz˘RS٫yD)nqoFG_xA$rO [vaઆFG +]ǝgJfnܛ'TWoe"R@ţ;_hú*{#~Gb\o$0l>(g)? ;\hSFBdt^sg-9*D[||R, +oӥRC9ZszUhsl x &UހQ1]sd<ȠP~&TON)R-zTCy \jQsRaħ}xdAb2D@h泄! ف  p޲X;@*ù X:`p1 |Y*m1>!9R-N :DZ48rĉ#/9{/T +"8aE!,I5j楷_}xKNB!Tuâ3 G P[(+jY`X`:'6 :|F9p7:F+U j{if텽[kZc>ίB)I"0z 5qʅA2酵z! D?84#dDq1Hf!MjrtX;gV6!+f$EY7\u,3ްj #(HCjQ ,y8\V,=V ̨7_{81T 1h1)]_`,4x6f]/f/<4SKkg?ɩQK5%m^vp]&>6D0xCvӄФ낳 +*ucG`obO89DAH .DP59&4ֻ#ՉVŒQ\v"mB.Oo?lVh0~*? +XP|kurZ|l96P+ȦBA::\cZ! L7l8t+\Ä/|Cra:b0tBs~t1@6\{*lNM/y9\½br9G [ f@ #6P"XZgjs7 3UZV6HcdzZ.G.QL<ʖfã0%K0c7T`-XFl3JFvZ6@ +#f[dۚ@wB0 [C#^Sa:BkE>ڒ%S eff4ؼ( #n/ G탣Խftel`i`p#Y]S@vcQp`1 +nar ԏ(&)1Jzvp׃hdmGK`1Bρ +eӌXbĢBEJ,-}~@>L@֏  X0*@倣Ʌm%`.N(Xe#V_ŵ:뗲Z9ŋ]1RrClל>cwi#uF~*2l aSVui+o~jy3(0wzMOϧϖoʙYZNM91H|ƒ9 S/8,W  ^>DSڲRji~ *AZD¤%##8²z%OP01ԏj4H +kg"q\TsD4kMr:;s gq8 lHJnj`i~c6(]ƨ!LrŹͫJ՛!Q.A PĨa^饽8jGrQLςHKUf7ηW\kw_ZKnX6ꄐ 5F.7fs @I6JG_xq;/ 뷃h6\/F.7.9J4Ԍ^\w'vf7?m<#o"y=;v\MnCdͭ\HsxtPҌiǨ|{6_7T fa.e['[KWɱ +<Ɇ.&"S(#z>I@3|O>6 :IzzAIwsͅKJz2Z̶Ooz|G~i|}C53[bNBsRrmčyŏy}\ +O +ݻ86 9![oqx䒽j\YҚ9.QbnՁA OA:AEz{؀䃄x 3\+l1۞;RAV׋&fp:/KvpƝ/(<1h%iz|[ûg^3 Xڅ/~LnfW|W֤adkDƇG6vSAXFPU38kBN a/ ;<^"Ϝ~,BɲVCy~M3^]{Իd&JӇFn֝↸p|0Vo_;? +LwxXPY!j XUƴet*MR+庉6S%%Ղc5H:RhF +ޛ|O9hd>p(a (嬜]ݼRIOWOsf/ag:'7B|;RmlOra|NHg3TN(bTz/:H2TuDl}j17[!~[ ' X١QL ׄP!4/_5pZ7Rc0c\JON}SVC/%Y )ďv'|c5c^͂_2{wiɇk'ﷻcPAL{3P&dyɈV]n"nB1ȗG7(ʪpPG*4-|A}jm,,fP! )BRW0\$n`Xl)7 b97slmFײ'[ھǴ &=>vz咙eJ6KS'Eۨ w#BɩBkOMPmijH/Df/miQ:c̄:mn~w&ROa7fc%&>G0'Ӄvҋ: rb(;.pL>۹jU秕lWl.@CdQTڧH4v、:6dB';WM3MV9PM'/n^QMl + +$Iu!KDLzl+ٝݻy)x,>nLe1X/up.*g +SjuyA5S / C^/y>s;\o^`EȐlcxS5j~86FɋH>_xqAG$H ՓEZ^;-&gسU-wvy Fe[wk7X3GyR)%[IqF9{}!f^1"py&\\:|W-¨U CCZ-Of· ]`4.s֔b *gFa|qvMJ 1:-eK`_)XRg8mbՕxmEVs*$+|$ לAeą#{V` vC/g_:>7bG `[s(o{[.[k,흹˨i +Z+RJ*/ endstream endobj 49 0 obj <>stream +o>ܙ*,'a:^_FLz҅l{?*͈fuI =W.xޒ{p~Sm(B +Ӥ Pdj͟>~\,B@yϽ_N]BٴPb@V8(->N߼048A= Rl?;Tf'ǯS]":>sw go޸זϧgj -3q[pQy<^]3qG\j4e>daV`^1 o 6\.͞JOZՍ\L}z $.Hl+y1:.%fX+&H2i_s$]xbƄVV=H.?ջ<-Oi._sXyf.7]y{PeIJ|cݕU9 +qrqJJL4S ' !kf˴ "\LsurU[ O>4JӅT}[M9 q̥֠.:S{zə+ln܇4nuF)ݏ~s#`B15+X!&wa' (R`gfTS3n~BvqFUKM'kk~>wT*+ sdXbsw t퇥xfFFQ+c\F&MJJ F<+U,;CP2N߽Rw[N^zOY}/'7nV+S\X?N ލZbx]iDj,>0J!*ĆѱMW+ ՅVs38.gHkܴ rghǨ% +nR֪Do%aփ@af:usp);᪙n-\{^O|9-JIJ)V# .\<¨T}C|0)o¤ o^Kߞ޼+)VPBep[veόfK̔K=L08h%P:E67,>j.3PaV?z#&8B@z6cKr.?p)-` h&u۬ǀZ:  +q{ _ AT)!3Q}n9>!}^AQPj.dys|n7>`m3-4Dٝՙm%ik=1\hD9ZLS\BD  "4&ǀ3Rc''׮HV#Bw/ "d3J|"Hހ NE/ndƏO_̜гhJ8B[ Q:ArY%Cvt R-gb?.|#18*Z[ '^];,wvN?y}{fxp4s7cznRURɫw]8|t[?o.SKc+{ggz_8Gك7>3 ₜն&Vo^yoz1Vx%ۜ=ͺa+( 15WbP.nzQZZǛ&9s9y5hhPZitmᚚY PYKiE9E+y#QK)I!1YM,BK Q€XXh-p߹[v`Q `@k\z9#&}lR\/Hr +}NBR]T*r0mdo$Lm~dc69hG{3y#HGI%KI-L5V%RXaҡb51+[YFD#*NJ`ɱq%3GA|8>eaw>GB#A00fr!Agt۫7O˵#JMJSj7VX"5%R7-B+5!\"?"DWe&w#rbA/vj{|W;{j41pӋ~2]{}/ܞ?}[uL[ƭ'l\cr4õYJɈjѫhVdkwn7oqZę[/iRԱ̅ uOx/ ;(_&K`'6V-&\8mXM%"QpLLɉVc'?p.jrtTH@@ qF-z&vΈYL,kQ u`D8??6৤ +Kꣷ̷6y1dnWxEINFrlln%˂xG_ +ZSo^(3~WwwX$Dh|nN: atHBBJ#j`f"*陮Ҩqd-Ya9C> +bf`oA gxsx9Tp ֻCi} ٠H9p 9$zm&PɃF}3|\*H]I+\' +1˵I1!մO,謞hvHQ6 )cFh 9P|&øD@T gLq.n7TR-)ĒccJR׈~;o fVz8aFq'JiA+PbCSA'3aMg@5soNm^IOllj4q+? BMxX%E {dffA21R֨Lls*Z^0r3$Hqi5N/;~~ۅnCf΃g_}+nXR).ܳ~x{sxFY-7$z'ZtB@4@I_ @]:[ +^%{% $1r"1'&HTt7n.ѳKA6(b QIx02B1V Z.8$ +Rg` +."RaFl(x:\aRjf,t0k7 ?5 +9AMr:a$ MAwg~4HXhi-Ś$@% Ii}V$b0VG=CP ܄0f'xy:R03JRҳH^T^?)ckQ P&,2n?1?【a`KaD[PP%UOB%VJAn><QfoprP^ŪY}G%a:B*͋ p!&ӧob ,$c""B`S >Pa$WJl1GN!t pYY!  -JpWu#~%#D$7W?,·'<<Kh2A >uF̢3;=| /"t49ryqy~Xc:,$fĤhBtu>Q] tWiF(Z7 W6SV~j lA>ď9cWe4-g=A-@DA!Fa9:ADj[ LFC┉QRJȌPT^q;8CZZLd>ȑs:ёA`cxp֒T{*k6>G1? M8m0tFm/lN* !i/ cB*| 1\Lj#l9:7:2 Gީzd Њ!$)rI iמ~+8@"RL %$'/-m_° rw]` V +Ii x%OƄ gS+)j2V%!z\ Ź`DJVԛei=6DVIQb4~!{lb%`<(ෲ:q 8qT.N7@(QBZ '{SG! @R©͉&T4H yBS@^(Ȑ6 + ^,Ns  A;elRHF(Wo z|<{xo C#/}ay9NJaEsxA ]`$)lGGQ׃s|d=,z},NZ(AwMRҠ  búɐ͎ Ðd9<9P(z| s*LnҲĉΗdT h *H@_hj22DŽU^L-.GW? j+z,٬Խqn}baF,* 9"N fJ9tpb>]KEQFv6`a. NHpGd b#T"%zSC=Aã08tiJ35i$@BRf(q ]5<$]^8d`0e0R,YT5%BTdUF8x^Xl )`Oz <$& ܰBGs{/?>2A};}N +@ @Q]k((L@3Ғ(DPdG^?vttx;2 +mı>caN'P>w0!T1!$i:ʋ K}6&Q!ޘVlqRD:\o\?z|cY8b();6䰹P6E!.̅Tf0P4,l2&JdGwOݺ|Fu `m.KH\Ucu*٩y ̣[nl~ݍR**O EțdUtǓF&nل%}aU;c+kU +ۇz=7+- a$JB.>4!XFp̙d(jl,|0!h;B%$YNL,^aKalgxj{vne˛'wO\0=GH!#I,KN^KSUcZZ-~}'?>7_?xXɐ ! PE9.[nE¥H(?S Le'rǗ/?xkO|كj- +|n݁^ GZ.n@VJ!hGcF>/F2f :1c=9vu^=ٳk|;~÷^>2MiܐsDy%8Afjqapz3z#iyݛ_ųw2E yNWaTIQ d4x0}`孛ӯ_7?}7]gۯ߿F.1 rncJ3'|Y9ry"6\]ت={o};>)e& 9Fr !8!ٓk 7#~tc7/' +GpB1 s%Bq<S|O?׿|ǟ=/ϟ~;+n7U U-tv /w?_?~sן߽>SyJdG"s} rDl:lsW"nW__O.?}٥9&:O@`C kZVqb:3 9lzg~o>__Ϯ~??/Ou6d  4Fiȇ j2nkv>uz_.>6O1(%4%9j'Еqt?y;߿o|Ωwo/R&S$NH1B\QK⃽Oӏw?|Ώs=ݹ}~X+Vt3#61\b=TⱢFtA:5d}w<;kxlڵFhjc2G2+bFd*!b,)W|_~_y7߻ ſ?~Az"qCBf9e≦EL 9O?o|泻K˝2>Bf +IbJ7cӷ7ӯ|pyxkƯ?ݙ{ԹbYKȊ{<0@gFƼ ='6ǭn'}ad7.vud<5iDф}E9IUjɔZVbfrk[o|ݟveV~&G/a֭ ⬿֫6}g#A۝?o^×٥ZPÇjc"Q0Ikcܝ6>}zwj5Su:^PliT#>ҽgfGzcw$ɲ47Y]"keZk͵UFDj]JWgOwMOunXKX  30A n9}&׃(`p)D(e +]oΫ^`P=X^V_z +s{2n{k[Rem`Q,~Y^?w?÷ӿ/_o_u刲:(iqb)ƪ]j{ޝ߉_?o/տ;Z؆vk;\啐UCiבG0Ց'#h:&ѲLGVF.VtlJSYXV!Z;lƓf}VܱNkz`Uot5HJ%[3_KaXhY5Fw׃Gs㫋ˣ``Xz-j}XL"h$]G[!;X4˟8xq8ikΈsï)vS,W q-Lrf bckRu $TLNHNaZ, jU׎Z~3aHf4j#'4e͐U0*``RȦ AN8vEXյ,-3j~v{g9;j{^[[\E@:kLgbzcAR[L*ޱj[ܰ[bx}9x:ケܹ9yh\ q."ɲ [yfqJ=/;H5VClo7,&-Eep. izm].^6[G_}+JYDNnwaw֪uM&J4s\ +[D- q#I\k$b$JUʅ +("#"1TWq3eaJ͉q`F% +v>^"#XV2ksj(eEL|$pj{=n(h^SUbnrbOv5!56RͭrgJJ$_M4:r)F*F%Jϳ8)6Ǜ"qe\﷏29hROFh_ƒ5Wt^d^cШ+Z*Iv,?o~c}fR4},x\T6j0Tp|{+Cގ7~jCP=_R?QHSR}רI?ZY._JS[[H$@[P7LTY`XÍREUj%:Rf4:ռO-ԎwG/ Y h]\m*4`z/.*VZ"w])>6F*ȼޗa0Q2Yc.)60<§Bsk&++a&>ULgbI`:׊-I\NqV x/Yv VHE1'AuJ Tց:I~9Z&7~15gݷoٯLX;0Q\hH:J+!6H'zˤe "kY=xLig^Nlϗ~Uy{{Eǔ:Z? &{o=Ly ޞPpD:~}w?g +Lt/`m&gAơbM3*ta IF+ +CsB("F0L]IԦyqpntSe$6ƴ9aNh8iEJvwuпUt]TV3QPLi3jo+`bb=֞Ij|Id1k=uyK~x"S={']Kr ZΎPJeժ{P3y;/T(d_,W3!W1d&o|v+w#vƹT@4)5Q"`wWQ% !Ƃ3R;E;k2Gbe|LuTb'rum4O_?l]~Y9**5R*գ`,X> 3Bt7opNic֗o;/q +<8~"8^. bz^3ns!U0. +,jo?4*ޡ"E-5>XN{Ss@as^Iӻ;'Dn0<4{ekc5<O~uُhPfV֜7z?=Iޞ}_?=InA4{[E[J|L_N?kVoϏ_Ȇvn|+_צXJT rhsϟ/ο:r0~,E{b#;ڗ_ZNNk2҆iw۹I5N^^kfWsRX1f%Ē:-ZKEל? 볧'PA}?<'_ysG_\hr4{{dip3fFwgz8yY#u.Vh_@Lgxo/_>ZePw꫇9FVjSڞ:>RZj1щڼcw&$ݬ;zu.8{9yîk0J(-{aw([swPn\jYu'Kql$rt.[ֽo^0~{c5}@^xxU;Dhwޒ|jwwsVWa|}jvh3.HfofG:x3Gn4krB~c mL OkiC$@}9Te=''1}t'Ow>P]19Reu] 8\a0{Jvhv:ɽovHgDg.{ox7?6^Q*Dek"WwCH^qΘW]ua6]7?z{/~Z\kt%5/hOm]w n{?-/.}X4ǔ59yc;w$MfҖ))A-؛_~OZYm\!b:R"ޛ/7HxHWTnB1f}Ԛ]>x/_kGkקoxnd"8f,ʆM0.;fϣ`S%S拣W9Di&ZKm +I j9`6+s2 F[iaB\w:qGUkwn69wrluwv!eppr,`d#CUw~+{ɒL58z~~ÿX?]5 7emx^_ ވ^cv3`?Ν(^7؍U"?A"J}mw︽+46ҪK]ۻP;;`pܼ$I34W7tpݱ;ax?'BՁ/Eg?^QP!Y?ha}'Ex} hٝg}48^< +ʒNNQkLZutW;wz m/u:IB`)E b?wc@Iýt 1~`N)9jbqYԫ{N댷GwvSDkz\F8 ɟ);mL.A0yw œͺiB5Z'=~ICyR7:X\}# +p|4{[igIIw`x-yVeI_NG_,r[%|45tlq\V;1zlX;G7ߢB7hk{@ka?Cg~fƔ6Ϟ=mg(W3?z];^xǫ^! ^(ޏ/]gGm9ƴ>,vIu 7?2ԫe8}%3zPLAvyS]Ui3N6P &(Qnc5ٽowF^.xCNhR\,L/ *T_ w. p:gӯ~ Pj7Xo$b(eOE7Dĸ(?G'%VaNJy.3> SrMvZz{/yE$k9mT¹>Of?-knm5>xF* F R;b>_ .^/8%w5YӋoW 6_\(^I:^Ѭ^R)J(fr&1.#` {vL +]!-NoI%7zo`]yj .\j lh;0F[GgVh#o|&רT5 ścf)"7AvwEYưƄܒPA-~Yb|O%Ek{V.RIDT"Rڎ]_>SfSea3#\<FmRuy٥A7QMu~Јns W:9WޜH# +è9:~y@'ąmWwɭALȯtU Dc s@ؽ{j5\p+9X:cS4އviغdcCI^bRX`*qrz{-j5jtxE )M*]PXsw]tyfu}sL29@ثZ޺Úmsx-BsB&G5!xsT&{B1uWPb=OيJIU5V/o@%o3ng~~QE+R?=_.)1h"ֳQbb\Zǿ>kJHǬ=͞v#嶠;sZmRnp_vichS)\Ѫ2*]v|kي^-n2|+ʒᴌڼ,ChwP:zJRnjǰu(ص%7sBQ ֬:xО?ogux,!Ay%^"OZ2)V%E0n})q[YWZd2FRho錏ߞkor& + +\5Sy=:/%wY 0_tzP!͝hM(2y=i/mlY P(q6f|R^":ćPS2SJCP r" œjL; A@%Ԥ&kډ} WAx\p$ZNHhZS0݃=a:ovx>7AkKsYu%wU`&#;<|UalE1Yx&0pTl!Ph1$@rNb|eo@.6}jTVhlxACqsxW^0Ni +% up>;Go~NJGօݹ/z+k.gNUi}Uomj1F'm٪hH]`TEP Ip*VǩrsҒH{ޯn[޳d@"$] x B*pbnu&>CK5[F4e+M/$?e "#$)9.aPfaY1d 'TcF"1 "13ƚCI5G"\D#Mxí[i *Ĵ$ΉMIVDr"9Kv+Ջ/{'_6MJ e] @ 7l9"4To"q8{y\*(aXե. '8K^U'Ϭʘ-XVz(W.(9E}lpV 9*s!KTh@Nkٻ;Tsҙi O)֖ǂR'0G,~5ͪ-?^s&'ט؆Ҷ!t{"|F|Ī#]$9nXv&ٲL}vU'))T=8'vZvTPB5*d%QL2fczNRG!<=u%ynO.p'-1]%o tEpYkQ>ۿO9BZ~8:#iK(_W% +,HyoƤ#`]FbFq +6Gw['B9.3I +U; n`0U"a'E/GqrNhuY"|+EqL還hiXSZu'([KYW҇%&Ը"R[Lip =0JfSRrO{SKq9 +ocgv a6xп{O8:V?"6ewEƒBx荞wP -l`r6P+Eu`gxK$&xR!DҒi_s.4a/ dw*lT~fPfl]Jn䍭Byk-bρRhnSPr0zM(ǹKsN +.2-sœ+"R#OJl j~[oή6LPa"3\ƽS +l3La||kȲf0mMJ$X"`&o{4Q?/>!wiuhćFH vt*z'e>er @ޘR t_Unf"]+ yh4az,Sol2RBY=㇌'F+:,rJ|bji;ˉr7jg7s7o$zҊ7YS@z+G뭰y^=쬟ZmvÓWj\ihK;WQ*!3 *~"!RΝGOjJ$Q7TeT?B^0zXxم\haүT/eP&unѲ]|^{>>]ۄx*tUuWOk*I#+Z3}ouަˬy<:Yncsh{YԸ!)d;mf +DhK{L'ˬ9S5h0 k#^3j'S;2HeЄ +6.mqWMuڬNΑ߻sDL1xQy"tmY>Ȱ?Q d +eFYW6}G* @X P+(+4;% ~ʘce05b>b6jndRxWrFn:AYBz|̃EvYͩ)uMo*$!b.2ED{[ Af"Hc" e3G@jj9' +7S7Tp#nBt'ד͂Tm(LS^e(|>ǒ +Z#[dJT! +UZp#Uq-9+P\A\5JI7hf1Qff3S3%5{1B:2+3z8N69ae +@-5H.Xxء ceI0VbVm~vIܑew.o&ʉѽE$[]((:*`>L -Uyk׌Txg"Ug=in+LzӮ\, +o(5` ֓ux^/Y8pRB{0E:* 8^zunĈVJ#ʝ߀HP 'W>@DɹR";(u{ɒ¡6Se3(YdKR2"CD"J l`&+z8˒H!J@`9 :09vlv:0u*ɒAtTVdw<"fm+W':}%\ldB~Ć`uKʌqs+l`lBjTYfJ)X\YJeT/Wdj[q:O'\VTp7C~~3[&tyGs3E| ʀsuRlp&yɔ|Lza +n! a#Ͳr1F iBU)[i>l~qPs2"eLɊGpa,**Azrϰ`()G <\Aߊ1.!V,@zsh|OygKURǪAB%.v(m$sRkq޺5դ;.@фCǙ_ѩ`-{ E3鷷13dX51Q}9<պAHlL¤~]eoVbW77BYFra[A2ev^/@<0wm!n)̖ٗhx]z 0  DF#ZB.t)oK(4babւX`jOf(RrҺE/.. kMt5&]> X(e1FK ++9:ƕ.`8WPBZ?\qڧ:ˤ[tNPUکU^ e1_p6|v3;EJa@Eʁ. Dْ"+\y) +7nnn!lp:cgw׿DJ*D*I\&ZD jw`By)d6#C*$ K +fO+ItP6Ivrovf^jiDϔbLj(dQm[i~j\,@aj<]tZ17)vlc,]`(6ʀ=NhyTN]=]$]})f^~cHk|6ҨQ6ƄA묽E;gdrIha(UBv@td%`2ޚ`3BDg+JY#BCגkPP/9N\'VJmh=L{yEM0\Yi6ĵ9c9HevTA3&oVغ`IJ+PUZ'!a˄I +UY08gijv"^)H.FvEanPr[E4?5whNU5^ +#VE|2Br`wKΜr4/WٲZ&<[1\P?eF`P#0N,~1Ɍf٭2X2rA{74.yk!:;4.`ahL VbppkC1X|'yx5wRFO"iSjRH0.N"EekLj9\7?j p*RK")SnfVWbz[}^dY&tXsi֏` %0@H[vZu%7n}pvRbJkij+Ze+VlA 6@ T(êhV8@5Kn\v晢1-9{HodiWAy 5`dٙT9?#)@! ,]`ͪNqh.6@Fs|@J"ۄ(hrr)h_xHN%5=.#:D^w7JwrK M(gcѧ1KDAtEc| E6."U&!6lToAEdq/Q^5Ce`A%y=SA ,1irAx|O9H1@1Btf,OI I8 +(5*wO`Qɓy)Sy{L}|\ fyB FmmqFxІwJLVSV$#B OrjrLY1iO0*u rFlƘFzm'9TKIST3cHz?:Ĥ!k,[;o&:JGyChA a#ΘA}HxJno͂RR޳{ }nl76޻|92w &P|c+JL٠ "S-b\IM2c|c;'mela%wqa5nnaA0交+kNmVo4P G$ 4S%vU$B]Tĸx0~4rD# +AUDLi!w:q>d#2h2H1"v?EO@P#S$n$gG!Ps;Eݸ.Bvrok/p`?:_[ۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ|lۧ?Ww$y&xg/,]UgGFH}& $GwWW;v$ɦ)(Qn(̊:rHvg47:s* Va>󼏉m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;m;mwe.w/P^,xwF[/d^I[;`ge}:qG K?t!2Y7 (t! + U_JSx +#R$EcHH&IւH4$B Qr`'{4'DB/.ߴӿ /_/,.T++y\*+#TF0"4p BB F\f^h/k.cD$.. ԅT_o;"h?O]@)؅ /1s@i$B()X=Fpz (c\R;գ +rYKÙML'4/7qLZ˲6qvIM(3jQp:JvEL9gDYmTmrMٙUb.!TXk@*5%I ~%p3zaS*K,,v6̘Z<\11˘mz(۾*sL&l<>6k;Fyө`=F6 J \6JQDXIXpBƘ-7H*-V>8NW)Rh4Et{ L *4汃˵8fd'zz@Y3;az$oYhzDQSjfRQz?Z +I\'ļ[v{ja.WTZ?|;!Wdo֎KKqNìSր2_=zz +q’?6O)O=/HG1}1.&H) ŅpRB,)W` ET(0 bP`: a*7HR W}K'I3)FI7$-Q.RB&Y*qqUQ((i +Sq+zWL1>w)F] (ᵖ krp6DO3B1=Fnj`!l$%PF Ie)U:EQL[CLv0qgf~&3^\JQb爵q>/"L//m)`@x4xf1ZBdZ,#OEJ`37 /J)Di]՛:mbtc[ǔY& kt3c !)U-7W Z"l(=)DPf +j0…2-5pޏ)L*zyQmqqhdRn,&Ջ;L}1շLrjf(m +1.7I}@- +F rPaD )g.DhJ!7GH;L|ԑV 2w +K(-D[i 4R0^cI&(잠7Yĉ6\pp*:ˬ1殩rTT?$X(EHM]q{RB 4\9*7RSxwi㈌iJB PPFnFB+ᔴPaG*P m6eFp>@v*6̴п&UZ KX6b 7`aH_x_-ƨ%i&VФr$*5qJR6It +p͟XʼnFCprv"}Jb9[ٔ*ۋaA Ğ֕ oj7`lFfCpՑ3+:@:ngUmIapP*1ʎfwQ^Mq'^)J*;R)w@J0e%@|[6 @V ֶ?fj8SK(௠2IE$j$P#CqeP'HRfp/HJIkBcf1<`Nrc }GtV8 BW 6" y!DT1>$3\srC)5ZQTO6.8{fjf g[@8fP,wŸZ"RJj@( A(BQ|\P9P3Fn75~Xj8+èP%=v/d =Vm F7X76"!KmFmf*!Eeƙ9!y,ղT6Nzʲ; gtr$F۴Rsuuμi G_k+!\Gxpbuf`.h%X~-AeT6IxA(E;D,U{(ڭq>ԒT7S蟯蒍05Z4%0Bׁ9 r`]Nb)/TR1)PLk(%.R)-}'L2b3\o?aO%x ǥp\N.X 3K1Hr +VPB P7x˼9Ac&x0.EKB#BRZH(ܨvF

-OMh䛻rfFtJv )졒H+(n)&'8ƸꭑR1Aݡ IE\J2/5owpbR S$jM;r* (RpOAN})BLPR]tVs)- +T2-F90! 1r"⸋3$TI +'eȳLcx:;8UpEڹQ:1~tV[)xq!s9Uj`cXCAC3#4"(>d@h6\.F!TSbTyҍ!2t1(̌@-V7ֶ-Ĺ. Mu[X 9IXZ +GpCàLFQ+)I +J,[}N7 @ $LHJA1K28qI>ykJiZU\v0 .abR猼UͻCT̛ rYL8jN`')1-xkRO2hSXnRS0[ r<).ē\(f׬5JoBR%'z^H +^Nk@)nb (uq) !8GCF()1g|Ԑ-DxSnAa +* T I !γR@ IpVTx~AL`6Y$lH!FJI`:\f1҆6c2mB5>_ArxJY0 2`{c ^rzq  `6!`LJq2,J,$fkn`lL =808kJ1F`Q8`-ȧ!H@tXtǤP4K8cơ6` 8H1oVTqv}2}!/,">o:B&C) mwqQr#R![50ZHk-ABtg-Vvի2F%\s[B# YX_+NSvlUR>Aa"(@%.HH, +q$ceHSC!܁M2C@` +"#|IS¥!AL+%d +Y0JEHC:BxI̅6b4+qʉ6\0Q 2õpR r()ESz8 4اp!" +OJ"&m_Dܥ%N@jp͝b{c1L$IN` L-Abg|/n& 512P*2-K5k# XL 69,7;ycbB}:XnВ!T6^ʓavhf+U\VkJ$ :Mu&pPSuŨxG3l`dgV[W(tO\!W3u#5<`Rsz/.ơX 2Nv3Ji/.&/pJ,A73 XP&P8] +!K1:ńC(]]T@GQJY40Q.΋KEt!LCAt`hC&źK)$FF;m4YB%(`w +T(.(Zh .bk "8SLy s@/+fh[ϡ,FiDb4MIa!B_>o| K\-A(Ӵ .Jh a +.Y 6)QDT XJ N fI1zJ '7+ N +㬋ip¸(ikQʠE_2Z\!"%pl}]% ʅ9FFOˬՎ3QK:.P+|| +I(8i+u]1)9 Qx\Qm깕8e.h)0NUkJFswK!\L +Ջ1 +X5#?B pNY8QHzg|f!al*cr8 1'['oW_\D/H(5  yu6^P F*7bJxP\]2*t$"*lҹq4v.-"qDH|S<)!5fiVMsEFU.H\ם"8'5ȋ@JC2I8P\2p8ȹ(WAK HlJ(8 ĕ#72M!3"2Tn63*i&g6HFnŬ)Le2R.ZʍPڏIь` +%9j5!b +f :&JsdOds-6CFUJQkn6RW4aǽBBF$ nu+]^WC9Q] Q,H03GEq43vt:& + +N%T($PUZJvDpoXF g +D-ăik9ȼ$T_&"jJN?4Gȕ`TpBf/-&#Q']k#TԆ] Ald|y qePPy9bR ۀ%Qq2!Zrb<a.(Ph"rYFj T&;M -&Q5PЛ8Γ&@y/2.6~}ݬb˸O6`l$x8M1@؜l4QK奤 Rpk!U$)B($sX6B5!QaHq6$ L8AbJ>m09EU-bbY R"e$V\?)@XCtG:k B eӠ D\ZJ,h@T+-O Uq 1ls8Mf cX&v +Ɗ@R5Eg(:KP.NDt.xL:}0H-JX/EAh T“J9H2Q ޏbGa"l0P%˱p8"8ȁxcW3L*ĭlr.+ quVk啷X.S( 8.RiJfMf =9ۃ;w& G[&Z~E͌ ƪ`!(g*+(.$%!F@eeNivp*!e0+HZz'VWX2>L+T8GR֠(pK?G& +Z[Ă+Hz1ʀY0Se [pqC$6OĥRP(JD= U"\!:˂aI^&4T%n\Z@ |'VoN8؆\ [sv[ΎEoAA I (bzIQNv9x +%Ain[_ j Nv3V~d$yQ!ahlBD@_ۜ^kQ½2 opt1_|8W:8|R7.oDsB3i p~$x׮s6"4 [0ނWAɁJ7{a&Wu$ox1C.D(H?Ij'I +9%20@ [GAprZCp9Z`({?]X|R,8:Ha8[&؏K0qYpA ^Ip5=@#u*SODq#//^L r<I%N*x /([ݡUS=72˫d FqnUw&7!x$d ).OiBȦ37&:}Zk2W5k5-sˬ#W(1Ql+Ƃ6Aq^L2!V9ۭ(.G1= 1 /j@9pfT &e-I&bR4 +eޝ.7-EMa8%Zk v8_ +̙$,/0=BFЮdofb1KqG?QD ^08VXd$ȫb 1# J @$\J4($p' T1@%hRBp4jwCD%}/n'qD,`f)2$\%5EӤ+v\4xBj)2[G!c3Zkv1rBT*bz0Y\!87IHi]k&3PrvK+,3_U]?!8fz@f`9mZmNOz!vSO(  Lʮr s,8 B)mv@B*g'gI({ sf Tx.X}NmrP I:U܊7@r<8NHM΀C*( gc<&8[?s0ZHQU%L( 4iB.Qz2@&zaƘmZjR T}5̚]MRag) Ȃ7PS纸hB+5W!wXJI}x`l!dFziͩmJ١NC(?>U97-9;"$oTEbf =W^*Vypnn;=֙pD &)9`VL/r9 f`[ʮ Y +s-o5;16 +Vu_+njm4pYZq@mkW2\{89 :hg&IH\CTG(fiY*X=)gƜ[o71!'=`9S4϶mJZ%͖U܋svi\e6O>t vlFn}"5\Zf@I~<b@,\]^ `rUMk5PZ~AcZ.q~t\\mo[vBEQLj)@lZ]uOD'5|0/MkS J:h-,xEWںxH ʧ +Tc >U +Y\6K0'VJqr_/)ٗ:!WurlvqG>TLQkKU9;7{/kĥVe[,w: +M, ʲ +6voHu57IrA(W-)WL PgIwpA7EO5Z+AaO Pi- +ثܚ[\qm,M5wv4juʹe13Kũvʝ=T+)m)-_sט +eß:UruPpJVb",Oޓw3p[fq-ŖUS/n s|4@/)b bg:V}+>hm>, +4E\eC\녵R1 ٬Nv6nW7uuW +|inGǣ7>vەU^jvoںK{n{l3௄Sh7XkK돊hafGVmǬn;u0:SsFi5ɥI ꥣ'n}8Q㝖6ˆT*Z~7+Ղ3(R[xTϟSzWyZIHUۄ21RXTX\\Q7-xDs7Vw;/Ƨ4w!UVo\}kλ/}b~r63qqxsZiZk~y)cQ.#zN}rcroq{ɣw+RZvz6\PMt+˒Ӭ\;W~ɯϠ,Fq{pNatwziw`NB3̦j&7.e4kQ\OgWځY;P[2v'A9MWtw4緯?_Ses89z}꛳{V3+쿩F^jnlTW^RZIkTWQuv}n۾\dcd ^kklvEr%#8t;isLטf30I7 +Sp\^o޾Se-;(\n_>zyz0kݗWAym$ӛP +'on'5~U*t۹|Mόvqo7C6WoP(4k( ":KoelܬL\<=sk`~yj՚_iDw;Ts3JiWn\etDɮSuקW^]}mszfiݭJ} mN￙/O3Iw~nDS2|?hobvo WԽ}ɷrݳK[W*ف^۵T{?~ݝ'7^߾HL6ֽY^s{>"t0 ˂ӂ3 8 Rkj\̢֝*|eVNm>ܸ8;|̹ޛ7Vޮnׯ=}l0jo:ZΝO^>j]n wvuh|p)͵w2-wY#x :럮yv]ɭ7\ݬNj[+ǯ~j_X9yX5ZkAkk'^d5͢Q+c7ӵd'RB-ENwZyt>}..?9[^[X^̭{>ʚ'׋+w&W;DH9ΨR=\;x8;:%C6Jp`%ߏQ]4ӻuP1:kM> /g++ݽNkϩ>O~ݩO#a Nj2=>yMYp[מ~uvS?yg>eV?̫|\>U\k>mm?˳^D]Y>dGqk~wxx[ܱWWj)gUҲJza vwQY-22 %97+ bVB{˭|J~tOyә\{?oW#s u:|ȵvi7S]K׶ڦW&WlΕWlq{ztrvvhu+_] ×Eg6!Yl +-/ʷvP7^nn=;9Y~O՗㫣ү}/Zop>'Aor711Bll$]߭Llj16ŚU1=5{ja]q:dx`g`' n7FZqRg`Jr}oG;iήQ>'kw@:w 㪏 +YZuު{ˣfmʙ\v~OlfؚbuʾWvIL-\v4J~ja{wF~{vҍ[ww^Zo6GC*F[ɭ;WkogW+XT'gW&o`{ٝo?~u ӴlKp:UwnxȉizqP'O˓t50iۂsIgz6X!یV*%d0i,<_2Uy{K%*C:?{Ǯ/gfyz~~0~_-p+(_XyxE0O͓A *uY&fy*پV} p  7 R9[dFa$ NdL{-(NN!Рlc壝y@Š[ٲ@ǀF1pW/647IҨ\K}JV^_nn#݀) +ԧ7Q!0֠vytRl ]DE֖aL̖hui.q_"BYR +J:gBt?q$=6Oʃ!_fQƢuL?-+^ki"H"6{V1cܘ 4A;{Ԯ\ujUY{Yk)OH5% 'v}0og[W+'vuTӭ+_]L +;ҊNu |ZkGtCoo_޺KZ9{S|&J305wuw@ y:Ģu$ZyM.̵fi%ˬJz/L 3SܮtUxBPt˫hD9 GRkGY/I[Jmɮ19)۳Kb=oR1*kѕ"*^+Xo߆NcU2zTvmkˣ3" euJpe^8m(~i er-: T{0"D N4kz%hRJ⚓zcQSJVӪ L UR$o!nޝWrٚ~'Hl7F +dvd[32kdw}ieeG֥|+ߙvμ.*;᷆JT*:5HCic>`7*;4^ +M̋jU6ls*8n(jbu蹊ۘHYj9Zh:[7{SܫoZݥcWή|^>` +3S0eiYzzrݜvpstY5^qM-].Շy묄i!%vuk쀕 +ǙHM` +xU$Ikew2m3?݃ۯf{[ +eT. PٕJm6#HS[յ!tnžMlGveܜ57f[Ro?xJ~RrfJPb(عqgZmp88F<\rO(QyxعZ]r2y{4?{zɣ7?/~ |{o_oO̷F;w0 ̐J{__;KO|c|׿;=ٝ۳C=wczuOANnܽ7>_~?_~[~;?8*vX-Gpf Jg*hulkOomxx[_w~7?|/.w !4fE\iouW$$TkLwo 6fNco|+ҿ'?ǿsnc)r;Vf͒ZzӍGwҗ?eqozg{'y(Hqf)!ҎVh<ܸ'o?OwϾ/w[>o~SLp]v8cǕV<*ٽ7N=>{?ww_<E7N2;VZ*0RN+[ko?׾_'O[wAq%ܲ˫kW=z~g˿g?~?wwz6)9/WVћn߼}_ޏ~~Og[僓+~[?'???dv9”u\W6N߂ύz3_/ʯۿ???_ask{Cy1:+w]S^oN9S9|nݜs 4QA0!`DE3~ n_ [Oys.WkBT}S/~Ep!?'|?%H~?^g܋:rAC@J|evbfs{/>?ޏ~go?ǟϼRLVp)ٞ6" F+|}b[:q/|wO~)?_}O>ch&%Zϭ:ycWܹܳ~ӟ>q?7~[R[Oue 2Js杧'y׾_|λޏ~/o77Y?SF.+DVffW׷w6o_{?o>g'~O}?sFsHܜ_?~ɳoݾwG >~?o>wƓ"F`SZ03ql|/>?ǿ>7׿XaVBe= +&SKӳK'ξ_7o_G'??|\Cxf. qrP[e{/}oo`~~c]q?oqj\6 zWv?w_跟~_>|/\;1JV㗽ˍ.:wS}?/~|7yՍzmzV떫|Н_[\ySܸy¥3JV$B(;1#p)Lҕfvvv6v'OٹOݾzO^֙[2bY^kIK^? XؕtYm.]x㷟}o?o_g/_עI9YӏIBSڳZ{zbb}i_}?|7~_{gy~m|NW~eB^Lu_܄G*VHwV{띷z{[o/~xSvV\P݃\l0H`u#t:zܩW_y;/psF91&jwGãШ%aj,F٩م\7ݹ7{ַƫ7ܿ{ FX/ +ԠX<hzss֝ϿnݼK_O3_҃'^y g6'ner_GNdI۷n|}/?oY_*U e)NSIA1l>0EHڒOqDK9:f0"c@DP&2l +z8QNs2%ub syi2abӍ0&4FQTPXMMn?;I8< y W@rAC;4&nQBV XP7¦NtRY +xlժAIE֏ &;:4px(R&%j1Mphme*NKI2bR̰;p=`, AIISd.ܼqA%5Ri;>שg3 vd`>8*Ie-2d>.b%lӞufILS# 顇w$H +a0+ +P/giI~ixZS(θh*\]>7 @eP0?REMR9(^QR7̲m}lW8kT=l;<`n +p 9-ͬD-I1EyF)CLԃ(;4/ Z|c6F)fW Ĺy {R@:?1BFP &|0A2 038= L|Ć>2`ӀP60t¢Յ|Ӌ!yA͓|20zÚАP.&.4fFl7 `~~Gr7y%$DǏ6dVE٬C% >;MAؕRҨLԉ(nL|-ƦBXe0yVO9P"?zxt_BCbʤ1o&7#0F`84#2  6r[$ +q9:)'rI_vɡ!ȘłEGF$!R_uEeH =P!`R2nj"L'&ef~,xa8fjZÇm.':5,6b' ex(U:p2Ȩ +Fj Rri`a*q51>Zb -9Yg )AiEBʉ6R1dB B%I|粌ZevFk]`, Z9!}= |T"̟ʏAT9p[$Τ<5<x׼D,_x2:u_ [ݢZU +׵HUʜZP ;=LPƲY_J9{O/au8Ns8!;{_a 2r}jwReb3jiìmiJ-;r1@4ůLj_!4ɧQ*#gG4%0ȘUO`rNFL^:D +IQ/ b5ATcԑבQ/`I! bN ph۝HKJUNp`Tj"Lz}C?nbl.a.e;q+ pR||с1ߐ Wa.)".xd Tc&]>2 }GttaQlZa`(|3 ar\BHIݭLsb H8G< D',:GٳQqd/{NqCѯ=pVH h./?f'ǜ ά^#-A[6FN 0N/ ¼EtҨX})aD@J >cq}l4@yŧt83cAPL;yZ#pBt͝p{.P%kµhc+ދGgZk4HI xKzjtaA;0/H:tI7a:x7eVѺ|K>.D  $W@#+$HU?LPL܇a6R +zOKbZ33g}BfȁaՇ~°h-XCI#vGFN15!bU0==9z` x րkrZQ۰%cS@4txpx9ZPbc#fU:֖2Zm [!&JΩ-W 4dQ p6$LN"8qyx1,v~qb2l\r{OQI +9Npёr<(x-=VI^+8iR!R-mv{(9Ҩ "!̔Y^ 0!"6(u)ًWٕOJ‡j1Z3DdO/.aO+̜ +K@y1j1^^b*e09C@6X +Be仅u0l\Kz2[w_gPZOhf@`@rV }Ʊz(5=3ti⋩~.n\?mq5V݃ĉҵgb U0Uo|/|!B@c@$KիOl[>ĀKiB$jjjJ)zjHO׽D@&A@xQ=_ VҚE8Xm1@FU6%&bm̩;V X ?Sd!<԰%N=rn ldRˮI!ҳ|̋\,}ݭ/_3Nac+'R 1B(D.$ 4d<24b#P6FCCR@Cj9:V  H~@1D(NM#@bR6pҌ_)9Bk@J)NI1P\0W9RN2f@Hx4Q;P!5Behhdbugfwn=F=2QJq37ίRj$(Z`7b˫cfyGfzq6dVν8{Auff,"Q<{yLNFݬ {pzn?8;$E/g +n,E1>KiQD2f."kx| pT UhOHE &Bz@JqS9G+yN/j_x GGmߩJ5D#A3|/''I `ɪFI!Sl$@m>$-f0.BMBzĊd6',c~L*"F"uqZWbE)^0*كt}-UZ\ظ/B\OmlمpeEx M;7t1vAi33O u}dyhEd%5R }!ܐŝrf 'DaAtksae~V*Jazfiɱ ARNHpkn*rXgY-!d<~-:^->h cV&jy$%&*ݭ.iT >ă.Lc ցⲸH5jrAI,leG@jonl VSFH'#6R'Q.ᢽu6Xb2,m.b&9\-vpB +9AĎؐG vp*ca#ɥS' K/o]ba2҂ BE_?G ` (`VԲtG$>mN<{|WFmJfc>Bd]:پ9Iੁt_Aq#+W{joNl?o,kzil*_^#N06ɨBpts ^&3(nbk)@.HcWˋp)I \\h~﷗N3F+O̶6[ 'e3/E6n|p l5N1rYaC Sj @PGE=ɘHi5Z-6[ +@-'#@.QL<̖fG|%1m*1j#q6%#;-F%)ˆFw=} 8Jvru*`j(զȘTZ% z %Ty)+ū{jNS=[0Qe@璌61r~ 68f{ #C2P&&a. ,r6XZ1FqU.r!UmfW>t_bZa d/5SYھ^%2\VhkrB` +SL(5ͩE;V=lsyX N82l RqB@KS/duMDO6cQ9q^`1 !GȰ*/'y)ʫIJLS7_Y;vǍhdFK@bLÀ +eӌXbĢDIJ,-[<?P>@sNL`ixkqb@$.8cX}]N_67jSǺRxxqJ \5v(F@Z:}@Hui;W^*O\{IϠ5==?[Z!gfi9UhrÛ ~}c)4SG\m8,WP72}%dQ?D7~電7kbzRK;4X[:hf0!hI0Χ=l0!,PG\׊reI38.FdkcKlШca &g-m_;2:| +rb1j\uqnm;DiK|u5 P=a# ԜC9<-6l>,ehDZJ|,Tefz|wQX̵w(Xԯb.·iNKU<Q1p0xNa@=#{aERs4kte=FRɱᦒы+sw~3Z4gg">Df% 8F-N 6%Kf,LG5w7j3՛O_jcr>TX eSۏ6ɱN$j$zzAI1Ù%%=mfO>}Ai|}jfVEN BsR rm̅Ň>.@Aa!BHƃ֟\Dy%$40dAM3+b1VK:~3^H'hRx|PMk0lNu玃Ted@U9R")$H 38͗g%q HQVf2=ZeZn/;g>/g o}ܤ]A)^rZn/$X=L.|to.eUU=!i!;jEa +[X8սvAdHSyN3^]oէe:SFn8,}[L/8fn0 #͹HKVnGJӥ +&%Ds 6DOINjA +7Xb&r5>Z=6 !M0|69!T+m1Rs3AesO ;[L &pK,kT_y4y_Z x$,ؤՖvnQ߈F-OMjKg+g΄ +z&ӏ_{׊ +p[Tf_QtaQb1?h&0sC6zFzP;)'&Zhל|闢@6 "W*ݓTv倁:: dBwvy?3̖Jqv9lO-p ޞ˯% Gq6q( _Atc;ڼ,ؖOݗ.Li\T4g +SvN j&?j~=%wo:F:*@[#!YGH4\hm~)@u'HP6qqRNsz>rS :P:"G`}D؃I"l,&̠~`D)eKݕSM?kWN>X:Z:S? DQ$~+>̷a\`rvv,U;c=7:Hiy?:c.Q3s3g?s+xUnjbxs: Aԅ+V p1Ojƒ3\9aSR{9 %JS2&[S7&V.)ˏ=wZXJ,Qcs'$rgeDF/P'J?xvꋯ}{v|o뱙O/v/Z=nmKۯ?u FY0^X8-ը`0%" z_>ep%\a#~HWLa lGEmTwntonD|IM?񻄚'Rn0YJ"1 l_c6/ ?/\33ұ['_~zjjM8 `hVy+@ BfPţbZRl̯r|gҤhq.S_"GI7VKN(7k+bI6wO^:맂LOd!#9qSNTl^h"R`f8sڳc6%;=}KݾpZsiFMÔ/>^jW=/@iL=}|sasgjϡJ{ܾ1Ie:XKZK3; `3UC54]q%)`|S(B +ӤSdjs.>T` !u|w.lZ(Ag8 ڏX)-> sF.7CLB*~p:La6,~u++rۧ}p썗|m|zV2s O]yi|>ѩ1;~d98 +aCLf6Ji(酙PazS7^yl-fO;{F{p-^ 6Xŕ3ldJL.F e{7H;0f& "K#:}Tyf<}| D>NզbiLݸSO+KRAFM#3`W(4D3`!TweM/ +e2eZ I"Yr:q9R[ Бӏ?`l;]Mwq.?]lp7\ZtZw:5O r½Hkm]^Z&J_z;뻗<8M(F +)dssA )0hQ3jjS3n<]?䌪NwyRBV0N80}A +.ǨōYP+mF&Ct{'7qWRT̞ovޥ.<ny杉b).NX!ޅZbnDj,hv%dhcqgjs弜lm].6-9;O@0f.ݬ i/e=+v$s%ClR֪D&a֍!#B¥AƛPxV;w8uXfhiUMPRN4@zAEX *rFj1{bbc|"}8E SbFwDW^}q=; `L#t?J'H. Oa@J +C耫*0pR$Ŏ=I<:F:0ĸY7K+N3~z7Xu1Kc+ƶwd?#6)I'317?N| +#1apb0kowO/8{퉩S駧w\xa\kUUDX_RTb@M KPM ׍D|n|M0KZYৢR`3.DNW4ȂųvFoҠ 73|e +g)%#'yMp}KX=bc&e^:@ @xD`j6sarSmxAebFͧ@TS;W+S'mƬ@t6J|Fɍj zղ`,Ĕh7/^~6b&' LHD7$ bglĂua`:f~5*0s;~tGIyDa 8)?|r nܔ-;pU#MQF 3nl*h%k^TLX?F)9́fٌ\>zx;<$gJ㛘"y|SLuPA2 ء?R*Z"\SmR͏=)1$*wy@$ESR:?k =43k|ܓU9ӎTjZ`gf͗;WTGBF jk{Wjhn$=k$&~P5ck,DH2{'<\R>_~zµXtmvna|)?x񫛧:Hcu+JrՕ#du@8Qb>QZX,WxZSkbj/9|kgOy+W=cNP*A!+5j#_^D>tr_hTM,.pV Fhُ+,$D7\YNٹfJO̔{%qZrۋ:%`!f`зep7*-^6>6QBx!#6h~60RmB~+pJ^TrcAW`Q"$k};cKLHCUW9WuW9`")%Q9ز,K $۲G{9|s:--|"誷~Өo5aT7zg LyHIN(h9_ںpqK08SUf N,gѼIp!,PLNa{as!q@%g 6Ll; +[ C2hd 'k9,ai6LsrAԫ `*=Ea.m-3_]ڿWX'8 +\}`| +B vU Ø!5'ȂglwY)z{Hk^q|x%0+#)ikֹy + +.$RaG}bz|*5 ?nmt~GϿ~(B8EVk{ gӼ =hKد5>@|Eɬn]t7c +`#oEbh(D`L8*[!]]xhWƂcR\P(͚'$K2N,FOYU*jZܾ !:Yǡ;\DH}Fr f!E+f_쟱*jf^) NW:qXy&tF२!EO9kMrSJ!&PrI$x]FBAVOTqDRf4A3D1Af#lxpHZHFM2,Bǁs1nm ]a՜l,"~+QQBzWN8(%JZA:'$ :Baizk\n-1fEJpc ~PN(SCNNI)IxҐy=3TV +6.vu2*֟?3`hc4ʸh\@P'8DH" Ad9reūe4 jIv@JmKv(,lS$">_N}@O#ade/b8,(K%(  "1LIe CF)EFʃd0 䓳 cSSP4r &iNR +FJSv#IĹ@Ng)e?13`9AȒ %yψzl/9q* t@`v•;_Ʃx +hE9Za|.A,=}o~_8y*A3s/?ux;3(`#IdKlϯl +y8kAIA<'Z. 0B`f4oӢ!D<Es) TDIjI2\ay*;>TNR&$f„SCLk +@8ɔ |W S 3Bi#8/ J<(B[bOSMv 6j@Nn es|qh tQ4A$)eƢqϗ&(qv:N L {kO`33dLQռiZP4 Pљd`.j2!LOE|bcQFPʜ!^`M/]UͪD DW(JRǎ͞: +%1|й di,L,!<(h90+ eţ %AgQ3Ӊ@`-"QA4ް(R -Pi\5M:jsAAkYu4SonjQ45db/[5`,`LvfKi6t]GR$h(u+o5V )ƚ[Q +"q8$6Yȋ"i@k۪؆&2Ȣ2 CQR "IҀa)PT5!<"P*T_Iw ˯٭ЬB}mN8Eib!L"ͥ uSU1L$Q`i +xcdILV5bCO>q\jj'ǎdO2%?> +D0%W(-dw=M[Ҏpܮk#^z3ww,Ef67U +2nKŖVźzZ|ٗמ/{ϝٮ糜 ৈ4;`s|ro +'Ir^ۯ\;Syp+<< #0jP(Q:uq*x;_|xL߼_|7sW..b)3JFŝyhY-bTҧr{Kgxϟ^| JE"Dqyj6Ǒ\VKZf!Y9S"wъsoxS7^a^]/n-< "WA46^{yy,|ǯ~ӷ}V?֯?{޽IфLcG +rtF><}O޽ΗF}e߸_ɷK7o3++,s7rwt{/]ixn?͟~?~Z_ gy^ǠTf#.3Qno-[77G?^7R6S4jj8|}'~_~oՇ7;RZQDu +K<2&kȵEަQ}g~/?~݇_g?Wny!80_7Ub^>k}#S߿Gw~^ٻ:[TPE`A晡>c>k{}Oz?K?{у_7ώ0fBe<_It|oGggκ\}x}|7~GwZq>BHUW a?s?x峟|~?z?S|^TElSx$ꐿx3Wׯ__o7.>U-Ȃ rQqnc?~/q\W7~~p~r?~~G,}Vd`p+ftU^+=9=;o?[?z֋O +4a|VW *UVa۩˗\?_}{n6'AʚY4kf3 +_3ͺtmlϾrŸއ/O MqYj(R7Ű4eCvkm<~.tTXTiZ¥|(L_Mf!:fڵr4 *rFv#z(X I#3G FeB7OMRtqZu?ڜ#'gsq6rvY,1Z Z._C(F4mFcH+)!;2LdUe=ͩ{ D.5x)M38n& +#t:QҠDO*^SXs}í1$a ţ MGRzyipB Pɵ̢`Rln6*b"V~V\lVHΫ/r !-_KQޙG`/LPޚ^s_Ɍcr_1cSsDo*VKQBT +hFH#~r*zd4ƀ̺䂁D,"q u\nX*80Qh; %*"8.:m_h._j S(Rb!Ng &9 wϜkZupč0, Po0upENؔZ&4p֤VG,d +Ra.%PӬ֢*5% +50D&:Og0ă36P.8dy1;ɗi_QJa,9i8nT.q4Ce ӘXԲcw2! c4ĉ\,LdPK^Bi0{rJë/1J9’VXOn.8~Rw#L&H1ڂ"d% +p+`T*ڜG"DgPZɎ~MP^s/=4Xuyq .w4<\lu٧ YPZbvioGםV0p X;XykwNmi\Y 6KNS23مYX2\(%H_͎*"xII.ɯ$?ݥ#5E8$We%Jo!%oHd.ܡYrjNu;y#֜OP~LTDA0RoސqGzpD JQcv'%U:e +a DwGVyk.Pr8_cy_„DNWJ"LI`MCjP DPB endstream endobj 50 0 obj <>stream +zxcDt2(iAǴ ŸHR&%H/NɊmr\]@eԕ}ƨN_,qNϩa*N/lS*aZI*-f|z׊7_Op9@(a^ϠB]H/; NOTnWW {=lVڶYYõVn_m|Qi|i 5ND+g&yjxB( N?;i6v4Vo$WRЊdZj;vˏ6[@ w2ʅ +!$oUn]yfMmJqCqFki/gWJ Wo]j [c yєSy lzƨZh[lRI28Nqe9UϲJȦ˫W_Ω3PF m]/~}Rh +Afa~N{]9AtcS .#a>~2#N>Q6L@NFYX'[N?s]غ7Y.5`܄Z%ߤ͎춻W8gJnY.l1-VW ^5W:fD:F?^ȴqM[C}n3C0 }mR<魊-cU7afU%Q2˥kn`ns̤7ʋZelm) +dV-,<8[_)V]ޛַ/<>ؼzgAatM-2rKwV[ŕʭʵʍ$~uH)__~zPZ]x21`^Zޒ3 +iN'w&T *Oi=wcbI+mDR=X1ۼ[YL`}P 1E@\Zq8eN-Uudk]v ZqI gj㻙tp93Prcsp%Bof{2Lix1]9h^Zڕ֨Û]s|`Q~tQ*=:w%$^Zygޱ+iTNoz{*]|۽G:-7q{$vQqt`V=pQi=ϵޞߺ'RGAKr F{\߫g6q N-IwςIPm~frzp/qzS_{0RR mqa2!J/px[].S\.tqٛm% T&FVVα9V]*[zi-4wQY@rqhkϲFW>Y^¬1n;ã7޹$iX1B;ny}³[x5=HԴ{'п {})=tVe%smDH%>av3{3H6 nm sQ&@ ̚<2Rølut0ڿøS&/\Ud>gUbTL)&zW9on]wI@)fia +@9hRXz#X(@}ުG01Nk׬nqXs݉Y] +0nb4hfrzdiPvi8`7"崓R.%ڶ>3>+k֦^\ +"*-"XHd*7q'&ؽ0*NjlF{wC@$թ7W.j2Ii]Z8W]:Wc +-MdOitATQtM= (5c@ƥ\j{_]Mʬ*M931,s˽kKOAL&AogIʭ +}Rw8cR-97z?77׿8[{N#07٭ x_tHug\WkIއ*idPb +na])e$RCh\ww~V,m# @n~+:a3ܸM3lXY]9_~<:1q; +M핶TwrRvP-@){IuNm,i@XKʰP"SiohBAk5+#O)t{%)5?6_--],cT@9N7\8v8F ͇Q;Y `-bjRg NeA(&-3 * yPr][  +N 0$z Z gt=)#Ug]eim77o:* :c>gk/A`٨hF Hk&Fp„]$@Dr6 Q~cXy.gd֨0v7qO|iy3727L6N@ mU~\g<`\23Tb2uZex."y7ܧ~09y4Ea`r %8j ɎW$b!n88+,&4a E$yuF7@'PL}%k[5Dip5 b@JQŅ ZyM).+eg_ʏ#)V ΐPIrrSߌ3T'H p&aJ:<ș7Y&XM +Xϥ@HL.*x(y=%@3SA:I@ , .%( W8P` +7Fk!I4vy}3?gJ!<:Xb. `@L2{KP B2 >1jJK|{ns^=dI h-+RI{ViCW)eR_❾QX3r3Yw9؄,w{&]N.WF +K0W,pEyJ,;QXک4_b)l."jݬlB5l'`O%DJS.ž\Jg!ʠ%>KRzT"T6i`fy8`͆q71.,n5 Ȝ՟Qgr{<%@N16XD%(VXat;!XՒS]etiiac\ZsXJٓ#v.WLJvn_{8g8,aBE(3FqrpItDYRE(U@}m1;hI%4DͭWsC7aEWA>͍QR<@RvǘXM) ¦^:Z+Jm/)=t=1l#҄1;EY +&ί"\>@\bs6*8Oͦp޷kū{xЍTJdF@Hg#-H g>sdo`|IARO}P0d0b$(`` xz&@KrN sqZTlHRdp@>C)G *cQ!MRoTA;+l&hYPhW:Ƶ7W1drD*_ܿշKK@G<= ݺa:ynIN֪VLDej~*y8(uިlF2K߁FF>mb|s5?ldUs6)kvɇC-k ӠdNIL9+2)6OlhhgT +n`b!gQ.S]y>"T Q4#ts)^-42`s a.BJjQ[H#&nFk/AxhÄ́X!6Iu, :3J^.__ NpR M*sQT+;L`T"Je q:?y*NHqHٓ6U!bSBgЃsHi =;<V9MQt}fť(b8!AiB+ IQdrଂR2!Y-@`˔zC)87IZ*KQt 4%d>[;zy$٨"J$H/+ϵ701dk;r:G3LL-mQJ_*,^.ZdR}- #&2 {6w$~oi_߈ d[ YD!&#q=ݭ SZ$&!5RlLeo.1΀2)@b QRG0_HPn'{1ѣx׫ fI&*X4e1{.¥HUPM}>SZ4[ + fA6xSb/b_ЊMvfgcJs8H To>c2=y^g`LEBJE N+ll<+eWI  ;GS!HIbDWa?xSQY>0I%Ι/]* %q3qf,na7FMGNk`\$5B(vPu  z `R2zimgW$`ZھvHra<#}@z O1S^ ;6Ä <5nF(0ELF3ة :B{'gc8Vczs)FM6Q+{ZG1F2.g>ZzVy5NǃD(eBl  1Ҧ[1JbzDAPzɜ_%9D~ug2';A⸇pL$nّs\E\f2Y\hɗUo +&p3A^~q6[YsJveһIt| lrK3"!tV0{ -s5uOcSd@]_ntS +_8?gZYąV.]9q +“SRv9M2L;qx)9u,3"gYM-8aI;f3K 4{ {rvPA`)W2ivf u&ƣ 0sELk!r=d@n !0hXCLl|΁5l*E J0`-Z;sI *-Yy\R +!H17ePڞ(LR<>4i2dkξYdB 'S.ҁ`698[3+ax6B F%pԤ6A  *IqJ)Q:9{m^J98Pu[Jq+IBt^~@L ,RO~5"q*'dC˥ (X *¹J9 "ʖpE$]s-HNI1lDғ;&c"'gC,%dZf +.6"  Υigh;EQHJ jx!y=(FF1 (sZmz }@\RX "9 |z,=Pэ633scIqW\){A)CRBO٥H E75hP}̗z.lYMHFQ=ݛ|F j4˖"`1,Kp6BТ +b \1܍߽SJ-Vuw +dPy[K{!C #e- >B25¶h)ƏUlc\#;ݯs2f@͞ )!X7Biyϰo`/f4@O(?+;}Ɗ`Cdv ngc=cMPeFk#9z'3b\rÓOp\VgP)TLA5(f^q嵯@Vdayx09G/+ĕϲTZzZK%8LFw%'ݽB\INI2t-o |Wv 3AvRp5_^AKTw _x1XYM Z6' &PMoXּ_3W c B 3J@ He Eg*Vm$S~tهAzY \l|E5FKz++9v>J֨ڴS#=VMd^UhlR΅u㣨8^6x$c=;]]~:2 Vj0Bڮ6%N|O_x5"E. @^tAf֐BP*m+ޔbd,xm%kRqp!")Nϊ⎲ɭ9C+LkFnr âDR1!dc vhH +JadUpiE+p"~k ZJhnou:#D"l&VKM8-XhWaZ a$)K+}#~jOљ]k JS\EA.2C2-EOXlgPJ: ^/_LtKwJ|(S[ 7,Mo2cܕLg'KZDJ/_~}khJב:P($isIz گ:̪^~6!c^2o?L@ > + 3/!Z|O'\ ceG`7+ZrrڰT7}#=E!Bmb!l@Vt_׺3=ZtVf6oLlLBNUOtDEx хM be^ҮKh&b^@ ؙԋf׳Þƒ=r#c30xݱ -``eƨEy'@4C^D˒jC*V;nX}^ŕ혲d{sm#Y%4053p H:itqEgyg +IM&wb_WJfU KcHbßFOP]Y~МL-Fݥ Fm љ%{fV0&arR_Gzr/?zj*+$xZ&Nrjtlxt|Ґ=~!fy&RJ@h`v|WV qX-ZRnq뵟b] So[8΍dÙ}Vzk9f4'lV _7j5ӭ ,EC3 n:/:+ Z4)+^b|b||FT{ϲpJH:N+hj-r7r[޲5 3ۻbQ jyhnwt2}0> +Ɋ=6ǙSpۯ &A`-%c[.7*/OǷzWZr ͙C1rdqW#Nh1엜`0ՖV)aPA0ZGVb(> +7Z~-yU!lTs +cko>wߎ~ _ف$su3xxx3: +a$RCcz/ "3St2@ӺaOH 愐4%1҂OK*Y/N$hB"Vkc=zIYYB{zpHsFfK6R`mB sNY*6dNZTVoW%[2y7́``0ݽ lg?|Ƈ3E"W?6O ƪ-Ÿf;Nj{UIiX~B Z VNm4zp@рJ8_rippvN jF>؟}-7:1AEJ~S2U1Nu$٨T~Be3Y%vqu!Hh%' +N4IE1z MبV)_V~T^ppϥ$HqWn Ik=[~~!u7 +}cz|CF:BBycgF!'}a0,5bnYmGߝ _qN#tw윋w&|Jleg"[ ;q;kў4YBȺ7믿. gf댮xQ,}gwVwosы__~f~Dj&<+;&ZW]CUZr˭0i}%璿%:)WJ|g"$Vv&'MoOEjKo+vP4;Vj@UNX &ה֮b )-΃گkF[ &FT=R::dNli{._|+mҚe# +dOgvoE#Fisj/^U}]_3閲9!5֫3b w_mYgV) -b-:ޅ0RPY^xM#d(> %ĈRR(8k[K +>ռ!f<&7RUxvoWp5)W/9J/ˍ..$Ł;80&_Otdc} 7M6>geٛ_Lo~mdg\'w7r̹np)+*XɏO;g k=xfxzewnAZqzAc>-Ft۾rs3ZHs6D\QB,h=|Zl`]!v#'=$yS|t?69hAXKٞA.{k+;NY:a!e^z8^֘ GybL?iYW1`y_0ҳȄ*A&ܙ7Vs5CcX}x𹧢5m`:ZSt)J lKj}}oؠr'3Ã`KI꤆#F -Q1XHAk32K;;6x|}8{NV9kN)]DDomW?@Zvso<lxg|y{[#OϿ6cJ,(ho +JW +phd:>zEsJKڜG/Ʌ5{WN\ +Vگ~px9w#&eă#}~ywϿpzwHZj +֎\'=w3_BlF+= /$ 䅠v-KMComҿ,l#G +VrіPu."v o:o'))u 1ЖN$#J*]~GBB(zqvx{'zkJhVޫֽ/15sL?o'TE>{K))ӓ/R +pd$[]"u!)-6*z=N׷?,;+Ҝ H1u'F|qȔV"ޙ>!"ŨltN6גw׻1%Vv(yxӷ۾U:8j|78$k$-meguąCpٙiK&qGwJ_M35OwgVL5HAb]#\5F3o}o>!}~]GG~ +͝7(D&zyp@mȌ9L1WyKZ2(ΐ +0doBH蝖܆GQ 2 YJ6W@џrVx78~heH%P4owJ)/@ބ%ŒN_.90ApA:cQJ^CFR#E5R',s)\WHG0|&Y# V ]U \ޙ6|u_ׂ"\̎BV| J/tweS@89~0ݤW׹{M`z(n/W{P/FR9%%Ֆ%C]Piw毱.M6اAH;=ZARڸ&k,&m|S^_@8ţû>-0Q 㴾B`C=:|;j_oFczjۼ 'Gsa%4[~WS4|k;OXcK"wx}udJN aEEu瓓b#ԓ7q8c*K+;UyurgÓ_GԐ@e dνή)w*lS/O?9 z|^}Vެ.%M1-%BE:U6H[btҙ^ߢ2) I_oNѲU{d +VV1/n>UexLߕW~j\hsΩ%xrPqu:g@F*؃ҹ>eL``X$[Rrd=AmI63P}>&7TT[V(0RaZ~NIq68%MZ&ѝ|֘؎W7]~v:IO*'g;̛XΛSr'?x2\펞?O?iYMWᬑOb|s<'ٓق|rT[^s9o _~N_ߧ?Tً.w_? + >#]7fxy/ܓ0&|ӛ_ >R}w'{XFBRB4r,H&jYdȪCYF*!ʢMwzR9wH9ŻZeuRZNrPr֠0';}=^řN mZ7zVpB׼>RC0J"/%k*]V6Q~(yN๙.kr0hJ u0~,?kZAYػNɝ?,67 o6D@F ƾ/=$rJm59Ά-gN[RVc&Prf;+ސbH/ML=!\+g?/w&U)$+̉`/{Vc3rYCP{3)#1"θ1FPRVWv^ࢽjݤlAd``]^NjWjE!N`m*[)5B#+%k&S^hW\Vѡ=3 e'+Κ41v6T_x!AqSJ+e]`[٢ R_hщnDo[~;yѱۧӻ63[zG07_3:ֱҳt%1LK %ńbL_Kïzm~tm[#+;I&ۏ?6Fr~/~7)mZ|he'D+Fa& q BH)k(`0ۼ;>1a4Er!i(KI Q֎5Bb<!i>WlpSiڤ.7E*ޖ3:6욬HB]X2V1Pn~jgMic\sN|dZhGg?զ,Hlg.jݲHJQ&`HQSJw ֡)< ;~a~[\tD̬y~sN6Ĵ1 @ `\^"tk{ۏv{-=^6`1ЀM:1{@~Vzz}OH)፾̴5F5AzI^q̨m5 Xp9NqvOILODO3a1*cՁF(pC$>b;!vwm'֞liLJ3!ݹQпZvC)Y$/V;GM1j׵lu<|SV> V9:Ys6`-16X4VX(}YGk#;Atj'>-!#XjC%`iU[#>SN-&YUS6U\6FM6j-z dou+&xO*9-&6Iuگ4gI!WI> -BJ9 &l0G1Q ɏq0~zWV3' .DFP#pYI @Ї޷BϘ^My{N~4ʫlO@i5Fv'*dNsP@Oq.a9?bp?/@[mZ/`%Ay:~U*@Ĝ'jpbHZqxpvv+HNho~;~hJdOuV_D979rAMA1z9)fX d1'Ă3Z*8М4ߧN& +F;ё-ZZtIVvm窿/WS8,۠j k8hB'X^Ft7) T ve6A-Z̰U8h)S` %#>Xe}B\8h3Nr4h>Fk-ֲH.>ACyW2@lG8`S&+8P&x3ZpI94'Wai>N6Isk6^:4pIaZ1&/[+t,bO %g襛e>+RAvVf|ͿFбe1}"/pdrݯXFK=;ѳSX-j:A D1_:ԗmhPqɏ?mmBl V|!⣸w=X|dG. 8e`20s@ǟ}xOY3C(v +@m|_mNpjhHAHǢ5B)NMi6~S' ^0JTt ^ }L +a7:D V0ߞޚՖE#BĬJ@M(pٴ P#H 젮W[&#kB,,hkyC%k`@% { +$L5B\ڤ<I: 4pX|F?1Sp8`M0*MAQg?/Deq +[WN~#};n{֙ڌxqy_"gstkYjEI{OW?V.GmK@~y4"ӣdkFbF)߽F x l;)SZf4  g㓟xs/_J.ղ`a %)MH.xkP% `LBuW UY`\f`{aF 0MBH:,4~x^kSiipl`_ Tdxm%c!Ar!3l 8h1!EeJk}#Rq%RL Tn^%ZeE1V. Q@BF́fM^{MƭB'IegRֽS:oȈJM&X&-֩P&$ ,=Xeo0q//qX+=9gwodsg%^A9F_k1|af`ojGZR kOnh}&833;v7f~'끇JnߪnwlE0%-!n)J0J3=)igAM@m&G1zYAx 픛0,w*IGjY84Zzé]A!ni!(S#7^VJa`4)SF.K.[[3㯔`W!EX) +`Fo26Gw eTNnO^K7U'au$sⷯg9,EI )\*l?:go?`||˕-J΂W{RU[64+휼hwbdُWPC?^ok^ >OAXHdfϪt)5)'_mZ.p;4B@by-w5\ +ٯv(HGNrJI*<6H /70/I1,`w"zσ#YΔ23"`x-Z=8dB$#^(pChUVV/]oJ6H}.wɦK7^qXsz~MV/!נZtU2  +&S +hCcދ;9%a~J +%]̒n!5lx/ZNrZ1޼o)Sڲ97rlLޕA:!0X}LOj[;3vCPJk`)p(%rv7?Lѳ*+I;AӀUT;;Fˁ9,8] 95)%Q{ |JmNt-6'/>yrfJ[2+ - dw:VLb)Aȱbijqא+FM{d#'XNi|γE[ jy uBoPzy͆`47X7 +U_-(@|0:C7"2yuJ-SOj!8P.T2+˨}䳚4Ky8q Rm\p&f,X5d.%} +6L6?W9okJ\&XOlPO +HڢWNlG=\xsb.Z~׬3;pqPeB]fJpLSo_UHɻX/J0o-6nqYK`胆 d"cWZ~&ŽU# RI1%CTj˸{>`PH(+ ڔ Å]+(pPRQ;!ȗWqdjv\YU]r ++ &e"Z: d\Q)XhiGJHXn\HJ쀬7TNHh>РtU^Y޳~iJCţ=l!`TJwb֥$,]'u<BrCtlh1' LBLд XQpM|{sEh9cO gdkRÐ-NDmsB 5odxS ~ްְBZ3AzmvoYsH_3tMpZ̿v1M;RN- ;k ʙׇҭ :ݽ`z(lפgAt5oqM4/R5:z[s@QxAAf7tZ-t{)>1#5ª66d\H|^RmjO'OjC'O Y^4m'uO+?`dfmQ rw&u2E{^v _%&e 6) +w?-@*/FJ ) 1R,w2JAo,>8s;ؚJʌ`&"=X9NONh©E)FHdZpo.=@ +ԎnD{TQ6kgxe!o` y knH94ũ҇5z +oHFJO3PAK!>a}! @hoO:4 DH^ +T*ڃoPO8bŚURlY=ןUFKvH ԆG!4+J# *X51A{?|Fː)>RjP:޳)eZe`[?y( 8ɔHXhںGH&.Tfa (^`Ig{$(/+Þ@CJpL >d 6Uj5N.ltU,M-=;0?kAMtQa?Zۧj^=B-}ؐ.Cՙ9ٱ(E?KO>j>Y?ڍʑՐ.#trZrIֈrڑS|,ax;wj@)PU'^W #OJ4rśk~bM+:jc#;3;Y*I R^Я~J%-)&Vq %NddW[ޚ*L'V<+*WY0Z{yc=1RiYv5_^7oIOZAbTGmoNpY5n08)`LxuuDk6aИ OXBl!uok܆" @@_Q޿W-.ow9̎64*~]S|F ]RzyIOI&9^E(r{ X m:-ZH< a}[2{WO>ր 㔞d!?T Zz +ă}>u*)8G?)U &yl k3(䍉hNBFq? -o0Rnj1n9Y^儢1%fkoOx +,J0 CM!D&9jH(tXiȽA $S$Adՠm JHI>AX*܈ה +F׎fPqR.!kJCq h)LU/F|A`|%\5Qw_)o/(i2bT!:Sao->ѣNش9y@^S 5Nޅ,%o*8}8g[8U5`Sp&-/bA-h)ќUL=ż b)-)o"0u@A~!rR!#ßݓtvϼ߿\Wl.Q; t.Fk9=W- i_%?Qa2}x +;=7'fqdk-9ݣѻWvʷ~Y^}o;Ld] " *篕DN6#ZmL !\ sXCRm9^Tbh_xW`s]vq`|T +U4z߸[{%3j!y lu||L&.!vşCLq֠x /oӢPъ3M ?CNf|$˗n4]{gz~k l,.»O^vV&pe^Zf4 @란ɝɮ".6ވ^#l_Zy{z{7.Xt&S|cv|;8f~/y6ؽ/W +FڧF~Ss+Y Woys3]xpM<ͮ){{w۫7ݓodxpɻk _ᗛ}o_}gARN[E`iWtvqw|vFkFiۂ: ǯO㋟{òE?&돳_~/>1=g/m~Ng?ңi4 G77?w/?́wuxlǷ +?v%F4 ~>Us@NY9TR)Zsݓs `r2lcL0׻o_}OJU {mJ!% n fh6z\lB/̧T(a .KPˀX/TZ3;,0QB-șpm=\[K & ΀)U0HJvbs+H B'h m˙),Xpi$XyE%@T .=/ f>MfT/-No^}Esݭ +:ByP@&O%wÕI/%X8źFu-?y4;y$ޚ?|3?̈́kn2 VLhg7X^ipAF0DksTWkkW}7P^~bJކ'& +a RpShqFHM8H!\/MttFlyl*Zێ5f&'Z<8ULytcl}tv`ubkFmݏhٸ7jtPqdmR{tlݘ)Mh]X?;uuHgT| nBǀ45Vp@ )CLvx4}dJV1%GE2TJv1<"krNB,-jXm5\8xr*WW2Lg7 +HY8X8BUHuP Ǯ<t,? ^JұY>"A|*bj~OtDN f'50dž>~V07*-`J)5bf +9dõ%> puYNu > (2sv%3u"\_ײ3RwcTu}~Hq֍^̴Vk '˧ h}L `O>9_:ʦZXDe>\D+$,nrP3@0j>Z fe.5()7{h:،F7$c08Ry5?-ڭƓϽtb]]]-_w|cks%GO}/&'vvǧ>WuM0FskbJ,z '19OKltTr~dos'ϭ-FANnF Pν7(;d ZJExRK/!qF|mh޾|s#~><o W֪K 2@E'a6ŧt܋PP[W's}֏q9t Cdd0 + @* G fRrKgw. T1Bm))^\;~5=Y)gjvzwcaO\ YH1f8w^v*O? 7 P\@JuؽW{N4qPup!' Q<Ȇ)j oEq8nmJc Fkڶ^Z,FdmiwvFja!3y2䒓\u='=jN +-r1Pӹ#RoK?{Z߸ټtu*8r։O|z|i)ěa2\?p)XLE*K֖Us}bbj|$fY`@r+~DjFi!mg~` +z `"E!:IEd"uTcU V=Luy訝1 %J+gn<%1.?J&> U}4=^\^NG@ϟ.-^F@\3b\ +s zu3i,9|tL^9@kJ)=l1}L b 5;mr˳GStU%whz;DѱPbFz$D#WWQ1x SVcTΑ[| jdB`JO7!^]lOD0msR9`&,RJ(/妎Mm=v5^ +Y5yfa{gb`biD +tWFmKwO1ir_C@FUh^\ f#̧+ +yOt *p+=zGH+L: [ շ@Q$G:V· :qÝCCD,&f|n vXfۆW{-(XÃ5bbFL. \`I5*X3(?&IFQJ5d;T^N+uygP%*X#]Psjd#,e@rJ d{+ABUܸldW?D7ÅH#M|RN񶔝"&CӳLw,?y$X#eZ{Q;4$h;MvR|nxa*r.&l^&kg{6T G (%R}"TeuGfkr(//{;JfƎhJtM=2Rv.\ڦ6wIOIJIZqLϋ3n +z_5o,NSS3|ŇQ4G*iGRPs!lNRTR7FםJ-SZE'O/^=ςbt" r0W}hBu_/ w :`:*TI5bp:w}#6 2P@{`b2Ҕ= PlÅ[c0L| rOƴLmPr +l(23Ύo `@LXMU&fOE*klDZ!Vs*0\􉹝{nZ&[tFtQ2_AWm4/&{5p7rN̓΀#RV.΄KBf? 3M1;YVo2өچt!x-V\˜MpmP%ubĉ̩bh s##rzz MNNcRn؆z "P9 jHf8%Ԑ50LBa~0I0 f!Z<+ \XM/LE[Sdabqr̡S]:YFl kl&\5VMKѪ3<-ы6NFCԤgKby†r(% =5^598g\!R^6JkH/kBNZC +sKΜO6\X'?C1Kp(7RZ8R2"i=Ŋx0덙A![soX"Vo94rzHn&@ogS,XqIqe츈Dk#v|H:B0Q~ܘ @\>tqr봘ybИw31ȈɁJyBb=Zͯ{^0&' +R ZKrV*Rh/ɚ깹HqIMNY9v~&H& x.UJJ4q1>bJ(oB1\ p&cw^e*7>{߻~񵟿?/Ʌ[O[ZuP&;dzs~~y\{!:nӌTn?i]KV|3[k: 'o=/~?| KH6GY @ǁu$ Pj"^{B{~?ɥo=vC7y\w;Kclر>".SbkqiLov~#nzO_şooNEƦUP/1Rc$E|4=sҽgn^㭣Wj3m@Ccw:6hN/.>rˏ=W_{}ٗ>׿?O{.t!a@UUMz}g/|o=[O>қo'_{^}osde2OF.L/:s /}׿z~_oIy>ST-()tڞ_sWo=?x''g8Ox½+*E Az}ȥ}[=>쯟W+%e}Jçn~x^ }?ɟ?C߽ /&^x1baB,t6_=n?~_߃_ӯ˿<ώ;o\ᅭ.̋ϕSۇ^{oW~;~?/Ͽgz_OTp=-D\m]l7cϿ}Wۿ/}?[=*FJg=r 7n\{_?~/+W7Ŗl1dY5byks=<>ͻ/~w_~/֙L/uVx-R^ЈeSӫ˫[/_|go_ί?싯o?/|֯sC̬j&2jR#RcrvбGNvƫG >}񓏿>ɧ[ܗo#IS(pXTJ|'>_ѧ|~ы/^:vIV(.TR`6>09{cO~/?7OwϿ#^A9 +#f9`[6z<Ͻ{~?.8gׯ??|׹+&#>BE=F +Xena}Ư{w~O[p?'{eJ+aOt{90Kѓo k {>|s? VjS4s|g?413pڙqg5$I?Վ8 +F0OvZژ;uֹ~ o9{=E3S@{>pF݃W6SF!p[\??~>ӳ?yĹYHJ>Dc"'Fvv=}ؚW[c;>~'~ŗ_+㧟zlTgXc`*FQ;5ʼn=+T7˯W_~o'/<{у[˭xRcLqU#T2<|}GO?/}ч_/?;| OV%e TE($zGM~#zg&&;~˗}/<ۿ|^x~_xͣLe4gvÀL5r=E"5R;n|'wO=_s#>}bc}u|u%1V#Ty՗_yS{ч_xg+7VW6:*&;!T?L8'hUm`A] 0={, +<)Fԣy5C|dDI-cG1pBٍ3Y>?@8."+3d*dsHd- ÄD ZXSX<ʔkS EǛJ>@!Dw=x!TB$x8iKh݌&")>2I?Ym7=c&׈{ A +D_rn95jbq3>Ӯe%??:44[[9LրI 'â x"KXA!W"LnӒ'bIM`wCVtC +saoC4YVL c|.]Q"ar7Tj)9ʇ;&>_QAQX4LAfP#XIJZNKpzh?*qZy}aD~ f2ũ#wa hKOb ++`p$#Y Y\"nonvO^pBSDd58RK8Q?EFL;G=0K΀sWmZ|^1^ x{NwmT>: e JQ= 9߲ע|` 3? y蠣$aJr z`67 !A^Pba'F0,Aq_4? 0IVoFghķ9dv [\fQh`vd7V`v+z;  \20id ־QQK"|Aq1e2<.I&TùF 1viq۽Ia} ?D K1fAֹQV +\60 4н̗dL +>6d2lz aN$`sƭVԏ@ޱ״gb^=!#ܹoН~P/!NxAz=> 6`|!lχk&@s^ -}cȨC"}/@0ِ}CN!2&}1>8kF=%>fŇ\#c> K+cq* A=ltpj`-@II2PIG6D9!={m:2)ZZ .Ò4Xqx{f\h<_ɂm(Qod+uVbq߰׃ȌCv'} hוD? 1!N(LiBގ6dFq`n@Dԋh)φ|4E?e6$>ލDuz8:x!=Onn/cle2\&v) b ;@,|qR.܇X43 Pǂ` ID(WG䘃1C Bv*{.D3D ڜÍ(11; 0c37nC&H'Rťv' e'=lAI;ݳ5>ԡĊQI>#yqT?bq/i͍xrb`XJ%] +>5Nςg*bҠׁ 8.E:sV88p&a)fUkmG6ƌDG\<J0#(7Ģù1&)hNx qBV}fv [ljG@1:F˯"t\I)UR)#@{zi x V`K3J掽a@4dx췹RH|#8 +eÕe2Ә\d4نMtLRbhN80-]0tf lcC@όxTV"92QXo@3YIs!J sRR&D&cA|L + Z I:U3ޱĩ`q ta"Ba +vZN}#n@:U5=/L<p-hof&&Fzu (oW^yw i@+Pf)Z¥<"Rb3Z@{Z̹Sdh Z-͆Y{ҹO|4!6`91o4u!`^GN=do(9Rf./{0 \ \gCU07w kU /~8P7!AU59gDd{4X7lX],DHEL(PS+>* Oqw&62bx+0&l?,%$7AÙRu19)BNVa߀gnjqr4;si_"\ѩ$.`lyq!štVfC 3ǥpnd2v% T "ܠLf8Pʍn,7uAU<iqz"."@Fm>aԂ SJzB/- \*YBSzMHBg5wbнi3R=aFS9S VH&frJ~=!J.J ^4"I:mJ7\'] K Lm0{fgͧci RY wyI1Çk>]_8}dkOkLr-\x(ZrQF(` &f-En<+t@ڠ_4PKle.j&d( "Z~Trf'D ' aeĊx`y)1g6MDf|B)2D.(H0˳Z@.9}'vl[1dFM~`%lAC6Bals9GVf§I)-nHN1)cԷnGnjtG +p3R Fl8fc5;(J`iPy|b̭gDkEhlFKV=jy%29zr9]nOtac Î1/,)onhɮDs~&^)7¥"8..5wx`a{@J"lV + tu)?is<R8mI~s"OƤ +5Ɂ&q(snf{{NB~ϐ;(E;77Un'>ʅ܂'9}4bu^Hq`QTA(~GMO%k5(nv@.zGC"'LaՌ#/n74 BFQnZG +IL)ǫa9* +ܼRb57f1/(nXC%"L U@%TM֏}ýx**+Z\;ع_K>&6 q&-, 0^,BB6bB nsߘb|XXG'H k,D汛|`y!.,itlDDZ], xf#G<a6:ze:w荧+1d\xa0^ёYe#}.39)A٨;xȵY[dAl&' x(#EG  $+~;C# R~M- ++cpH6phߠ[Πİ{E?{yONl0 V 74itJڨC| +bӔƃ-@0XN_h2A*"eq1KFqjψ} +Z Jy 3q4Z_O909_o,_MϝΟa&DE$/ pE:؎U7I H!gX3)JD,&E$#% ԑDcr9wx;wS\oǣ&/(!ؐ &gpۤ\N1Ϡ%53[=j pa΄ک\{0{ +3].d>2dXd< ;,4bGF0t֥^:x9:p)…AxX3FRr4xx3W۽=U@\@=7%gQKTc/2;y!fq3&'a+oZ䁥;aW"5l#M ҁ1!{X{ڽP~#"2NF>Dǜ8%HO+Rr\̳e ͂=n`dHA L.CD0)O|L4 +RALoQ! 7 DᦀsgBNu6Kƀلm^!P[0Lʹrw8FxiqeC8sAF.>y>Mj9PGn**K~"uװw)࣒|mfm@l/v_>:f*Hxyrb+F~_,\9)zCf ʆ(XX"$;@HX)^L>H{`p@׳2!71;p1 rpi9?QP}m^⡥ǧ?XY<w `8pQDL:i{ BkEc}v70ƾ1͘ݜ &Qj}4fEڋ0#ry(,|8*pFu<~nt=UÅ(1KJ9F-r O6qvCNU˧ D9RRTP07,&;b˅@ UaVE8 tZNSrV7ؤ,AGx!A|a ^X' ƥFPelLJH-(Jтk~nz6"U[I'ks0S=I-53.oƔ{P49I +J#tJObl>3fc%%-.\bz 'ATs}vg~Z(Raiюya^ 8 *gK΀H+Y`|0. iit[@jMfA BcJ *.(:;\+{ٌ :֪rb&_Aȉ9)>*,-/{3w( sd0}#@} @!RWFcsnHuA*H`P>|^^ >vbڻ^O{ 8|̆g`%FH8R/.7}r$"%۝X8+u Fk8b fx% D&D?N{ ).MEW!@0`U4ΉPL`B`rJ0.cuX#[Yb<&D+UPJCT+M MvXr=X8Z9>sK/yYݸ`q2b|acހ@1PMd@rf{Bʉ蛜"*T\vS/;{L j`BX + /,rxS7=a۸6,FZz1M6(*PMl ++;XuIOih뀘Pȥ-̓ܲ66qੁUOQ--Uzkrk-w7/Z\Ă-? +Kg&WIcĎ} B'(in&ʙDa +&CcV5/brfgv3'Fvr#!TH<*ˏg?cVfJG2fwgrD sy3YSl>8 v3bijo1f6t)Ҭv˧8w0\NHq(fݍLm \ 7P*3Ϩ 1  6|B)9G(``IB*S|hM:ƀӆ@FJ622"äR`D-¸6#!UXe[d0 aKtaHܽ.\Rݥ[ջ`c،2r0KgA{U`*&cxqw޵[3<0}V +rfܴj9H7䱅{]k.y@& Z ?5^E1'̵ˢ + +S5w%B%^6;"*f1>O)Lc9l rX =g<-8Aٽt85ќ\;3wbV&ꊱar=(ҳ+'c b₂G8G1 rWu5C@h^8;g&h%y"\Mte8*.Ft:X0Pz*d6ycA2ؽ؞a˰) T]bqуd梇^F"'Q QQ+X(HQw{9`Wd ՅXVˬ`&;>r3-ecE0duJ(H%P ch(9er@e~́ف21ɎP8P\VbbTעU([=iU'vV; n.:Ulnzb<J ()kny8OF* G:DibGy@4 ̝ZUS+bzV.۬^B7B]9sc +ټmЦO 1x0kP6\}8u^]S\ݺ6y@:ՉCڒm$]NI؜(Q6Dlz~Ջ0vZ*1ARJc8Glzqxi}b*3u~&4jָF!M wܵ &cb|Ҫ* h vR08rzd PL6as./o.`!Fl>'CLK&NuNil`]鯜G`jfKY:ܐSja)7q2>0=?X;rxF6T gq>:9X)6:t֋FMv v X,2JR2hd;YNd>pcRP~9YȴMl\P9)FۑDgZOQ\/,nZ~L\:Ј[u{MȰ ^MIi`6w'(Fu=9ZzCמv;R5O0ʥ16+[3 yPU [ׯ5,Qͫz8‚qL."kJ +\|`Fo|kp2|Vjv_EWP]u~֏I@*%N4۝CT)eETYsq>RE4JT`n %xa V Ӎr4t &7WX>]1= ^<6r7MgrD-1VF7q3P +3+Ŝ (+ZѶmٖrw۝g[kfą`P眽=4 +6)J }#tyaHEca3c7u@бHs; 6.g!}O).>yi@+5${e^|ڮ}cG82Mx,4s{vOX'jVq#ۏ7Y{rO(y1RgԲfk\$71 z}ڌ,7İ_x~84(n$rFʬn\Mm vYΤ&s7\|$Low>LuDEZ+kz7;Sxo0Z@dK1iR,HĘ',D[**vcvDBhwP?X١QTC.Wbmљ PQ?fZz6&g5>ũURO''Xw_u\zLSs/>X?h܃Nlv#Ă4.f$.d)1h5dn7tO@to Bl\={Ӓ 9;slmzS3g/}#a¿>ݞ?^jg\μgũsxnlԍy`ɏFb*cS~D]~AIv ܄4jN x"3VN]I6ZzRNgZvohMDp+<(hyPDT+-yQHZ yƉq8CT&[R|J/9x4p͉t>ݹUL_tl1KV.wbqh De=߹q-be5d5[GJ_RAU@zcUs)D'<ǻ=4 +ܜlVp}~c_w#"wHo@'k}悸$ULv%io^&.eUl1{fvQ#A&2c]⸛8rrо +DBB0e>QE,4VǛzimPD3 yqP!ej ן:r܅Pd7tX$7AnHt1J z)vV6k!\ֺV?]{\P?Dhoנ}X4;7v/Y=IQ]jjnƎ c#Q#03_2 *7|{0y69yr "ET-¥AhaF4F|4Z`26Pq#!@@~x'$1f%,N]4%|OvƼ<)c0sewP`,D VNxkQ~<~ysK+KwW燯} x4)AT#BTblʭfu4XMq?Eq!Zҵ%0)Z'x;U_-v m3;8ى۳!023ڊd!+,1O,q/GA< >r +3n=k#8-9hwo=Qg!f i%Sll]=?@iT9RusgrDŽfq%9QN69FLZ2Rsrgel&3Yr'F+sՖ=4r7f"'1!EIr8>yEphy/[O]EBp#Ug +,|k!` Kz{ O7|`E9so۝윺bU˗Rj唚[8u{KU(t*k3#ؑAp4i~4DI5OE-?c rq|j]9\-r¤L Ѷa쾐X &Bn4 +̑sc ʧ],ka\qt4}|D>VVOJ(0ss%1^G8bKX4J\@XSMg "7$ygP #k˔F[ts{]] SNeb ;LֶD-_Jer8TMv*e{.;7n?p#:p"͵οwR\JG` h_ϬB ,hl !ZzVIY%}oGF VDum~օ.r3pco>?rwM` c1OÎ"Wna$$mZ9Lf;S{pJf/?tܫ_{`҅Lw,y`U`=FĜzCiO c Ɠ7+D}nrennDRf4cX}]N{ R~.D{zu/'H˒V]b0˸DVNŒCGNep5݋V8bZgi0~q.Ǻ~ԉ -.)fe+lT5H1߉ɴNNіցL2&D So_X~N0 +#gG]>t}5]Y}ѓq/5LP&& m+3j4wr, YΩ "HgM/OR r"(eKR>Yg\0㵻߼~-FΡO0`%„3>/Õ&wQ99D+$(Σ//Gc'|E!DFr.2ٞQJDz(d+̙|w.Z>wgvJef.-9$-yu +VH#JRBd#AXscAXi19#>P\}N_]M!1dfgzߺw[[%znRr ΙLK7oU&?Oo| )i<Mk^ҙ8-:+O_ywc|{n?'Kz+cݰ6hD *0tѪREH9Rz`VJA\=1f8SОhUj-8E\Ÿ<C[VN7qkV3|k䗗-?KVWzwW:Jqnŷw߿ߜG? FaAJƪ[/Wpəy#;T7$#bBr2]!l?kn>4dzwnkVoF8uP]WBdrb|ް C/l|^2IO1jk-,L㓬dB11b0UJzB,ewnf(WBAXJVܸpÇx}1;G* ڇ OȃJ%b@i@O\>ltps|Gs@0117qr0% &&D3X,,]FMc=%ލ,-ۂbX[Nq6!JYΔ CkAhHI/0j2R&@*uWnzHջ+Tҏz5,ͪ;Ny>^"! 3F큥DmEN,h/Vz[NiO}jouW'ϜʠG7_Koo_y0{+{W_fsvkDc;޸ީQ0"Mz:?}HiAI>~ծzA-7h}zF}^?.`! ˨R\޸vl[Oݭ?9;uF>٢rr(60D5THJVcʵ?\0JJD5Tޠ @H̷6i%ih6ӻ $fQ!2zM@k2I+7eCvDs0p AcqlMM'B_sb%:jfV|U#MOXS.D' Br*R:D*fS#LOq33OP*Y'@U + +$ͥ ZFfKHHl&jØ8-B y=I!%Ff3K!/E*p;I0Ph2^Lڜt1WY+ROt*RerKm3;wޚmwJ3N_{7VZ%[/ HUf7Rs |dv'|x]NL_zrt(xb(8ap"\]++1jUBr/)|[ Ժ~ce{`ONna2N)c8{՛a[GF79vxЋDB3HR +熨l*JZ xx'R^lV2}Ԓ9-WОOs&C zOBlS>pnb}URonqQ<5`e3` cφeẐƥ\GD/jyaMIͻdc wE5Oq^ x=5q.B))1Z͟]ڽ[śL[Ou&Hq| U1Hr i +JjmB&!q +B 6X^o/+ڠv$ 5+nFvɈ)^͓B SCaГVR| (acfAR(ge\y80AY^:--VM`iʺ^ZO3҂!NKvnZꯏ]j!\n0|dxÏ6,D +K}{nq]-d;j@P|*@a#I٥ibp-@!DP8PZۻBbt@^c}s +Y +3YBIZ/@,JDp*i-6IIt\V󒜩֗zf`$4f$ /=2:  3Td3ħKۀ@1MQ\q X-m$zI #I0e\)tE1  dI&pd5LԲ! +a'ϝ9'GdFz |f ވ"ᔅsIVBACKٹrѻAJQj2,Z9-WbJCnDkqs[ JccA#&S84Afz2ް£"l 0 T@@Ԡ5$F()M4z0CF4%!6U2S / +r>J8DlCaTQƹ N&P }sH Pa&۲ h!R (F=nhpd, !fhD@v|PC@ @</G8BIi>rMjVe‹{xy&3ܤ)"㞐7@t!-P\w zƼpiDtTC¤9݅3uZQtyQs:ALw)i1 +SA/Z?:A0b/ 섏hTX9 A,0VERjel7o DC:_VNp]ptyB(:0 +K .|LO"OM>q0)D #)! :@q.2r{ H^flIIݒLOF ϒ O& frcx;< +C2N9u#[3:rdıQϋ2543a#xO?>&)@s'</E2(ya(E &`H9bYE"HӤ$!ᆝʕD ƐPĊHW0HJ6- ˑLB'#QY54]1`aS5C2"1d-LRh$3̵@"Đ[Gƽa ã:VXڛ[PU + \UhX+[+d9@!(QuDI,oKrd6nDLS$SSx +iXdn+! CA>kp0,@5Alaېf.:_sgWw_~|{gk)a[$-apC ǎ2d!/A8a(C:PprBұc.D <D 4f[Źrdsd_oܺy۬؍F !G&H2ޑte hUm3hD-Qb1ZT[;seSrfx=<ꇀn3M#2`G}u*ѫ(9[[oo_߽j3Ƣ0j MXJNiG2q[D?-EWr^}em+o&B#'F0[>9?4j1PďpDQ_pQ{R20 +C̈7H^#аİ˦cN1[[z>&-tgp~{vje̋6{饧޺rzat"AA4' CI,k?;~ttlϯsD.NV.3I_~p}ù/0/?O>?_~ +ۍlP fbr3˯k/VnXM%֧b<:~?|ỏݜUe*_g[Ps&39z6nfI)nZ0]}||^ӯ|w=:ۻKo=<Wxh8eU$%.&Z#g5d7Vow?Ϯ׿_umrJ&rGVҧl߼w|/WO~_^,&M# =IlA\Vngo~ԇz?yۏ.~lڙRP̴qD1t4]vb'3}lʒƯvOzyl`cҜ"51`e_,wwJw|ſ;5œ?~xΤ"|~0K&67m| +-='g*{׿{?z?~wOnsi4 "e -C*u'TLzRܻ7{~gl~toۗ.'K###@:ꋳo^JkWXzҹyE+Ѹ,+,}( RNjdW3كڥgO|lG/krR(**)͞(Bra ]:ԽSgR/ѿ}ڟ>W..U"~DQ iacL?+Ս̥wo/کVM||4)DGL!IJb?_O~˫-#J@Tx5D8`TuftxTp +v%H8 #/D$q\ 0(Pf^>+;֝3+×׾+ f\ + t / *9v:|='QgK^?}>[^peԉE,UzEQ (/ F3_jlɢ_2-L~Zϰ[;S +RJ50gGǁFFE 8ACR^L:d:QWcÅd8)I$/0LƤDQO8"N)$t3*ktipv:slTj&=a +lFx htVTԠ Z.ٯ]~sSg9=_NYV4$' V+K)HGp4`/y /)i̇LAtPb>*U;g3e + +$$K鴭EdVXP +@.,L:Vv)RX&ŤgiΠp^W8b0IV>?5ԬM;VTMv # džF'TR*Qhcdh|l|,=nlԨgvbݳ/[kL?gv9 CNz C.IϰDl,+/g2mcbV% -v'[KJJD1 ca"­ :~q6xsafvP;MZ*YHHN N~$ 鞠# +zXCFj!% eLkf"LJdK8 bV3J~~, NEvHEsU VJ_Ą("ۢԔhTL4H"5ȄGØ-9 5N&Dgx1RLF)&4 +hdcpmτh289øXi 뉞 bViV*eF)¨Ƹ\)zӉ2HjX~R.*+ֶ qwH8M7Tgfu-2TaFo|kxh fQ޴R *?wsboO5):rrpyIBz#CCEQJ0J`CTQH1/7G<,e(%~<㘚cy:n\"!dOXJ0d}Sݤ蜒ݤ)TP`:¨%o!IYhfQsnHfp]LsVbZjA"-vZ+mE)o\bUY0tⳐ=ټ q!7dB*%) "zZiz#aJSn+E=iE\A^˔:8 fW6Pr$<ȵRև讠F+EϏ9^u!~XQZR`M1!G+e1)+Ƥ"&OCc\A \"d +:eӣ!Յ6#gF.K#%<}">1tai%W>50FmŪ`ihzgtxiH 1}s8::tEbStt +'Lojg;^ 㨩)%5;e9l3=7 8p\KM^HD{:U9gAR%fK bE q֤ߒR+ނt|6~Jievy=QߎOy;;xeUQlVW_lo߉v3}Ѩ;Ma8->>oUӽdU^9A]Mmڬgf sc]vV*g q|N d!LP.92gh Ll*&9?էؤG|,DT*rLj)kAH#Un(4"l.ѳKVa/OEVof[~18|XLK/`|nȅiCEZuxg*dZXȉyhrh{٥Q? @Dg +2A|B x(?4+Rcnj/y`kh>rtcGF0ϠPҤI`^Rn@vF;Rr.ݻ~Rg@9$2:4sE.:mvmvbz^c²C,_x^ƪlp9N` Keq:>\q:gg*eL{Stu30qt4{iv1 s+҃J6ħ[+wKziSc"e7{W@¸` +E5)hTš^:,݌T6Lf,V*F?TʇFLVL.+-ڞahvv{NLPC^ $VkZ=w|pIE:ɹ+Սkbr 2@1xbIe_!uÍTܜS+vs'CcP7(|xO9 +Icދa:i= +3 06dTݍɳԙz-̧h?9P+LqH#7iraGΝ{'$PR+O=sۨR'܍OLjur֍O4H)zDw[ճ[3;ORϜz[-Nz\TĚ P,^b#l|p{!2Uf.mH R߾mR+^@'$ZGbNQJ53'&wH=-JZ<_s|b{`.6^ڵ8:Z^_f*篿@Rh q0%][9x{f%9Rܾ^bmL{+?u6?}ެ2z1U[Iu`>Ce*R27A,IXcXHQfӮIN].܈ j;_4 :}ε+ T>u->TR͕ /ەJwkr`,qcrWRrkbZ?ubj |bRJjDkN+ޜX.VE*itY>:@sp)>d"en,\R+F~1D Y%+KbNi-;=Ԁ [6 +QQKE5V&XfԴ E!1# ZY$_޽G*+_<|Z[(%&7^rnzHg.g/eg23*yڳq!4Une.Z{+L%='gWNڕMBb+N~v[F~E&Zwz=#5~ac:nU +\D.Z5{!7N|xu!\X.#J0|kgyrk",R{@J2 먘A9.ǚ&0qza%@gַ 4*fe#:mfn'3ŨųWn4RBmzrP!JM%Lgrr$?Pf'=-oy n5.v6U2%/ӹ:]Ȟ +oU()U>XU_>87w6BL< +i +:iԄH3V\W(Q#шd yY8&#~ +8q%=bLB)Y+/?Uza9V]MA/M/vWB|XhH"\xHrR#ef\$3Sj={{O;:"^[]ZmzSG~ 6E; \eh/]:}.txRl4kt`R]n +=\-V[K׌2B&Vf +2lrڵGM`"EMz({Hfibvr2C4͵veFdfҺ{f{ /H .^$X^ёfvOC{pOgK@`7ax>f79DY(氳at W/{׼"rCRhI6y%#@`\X0D jƂc3[4ׯx֏|C(i6GWIly:zf$KQ'ǟϾ̗x !{/ +ppvqv~/Q12A6>݆&l8ѓif~KӜ5'_e05H dON?_~>= g_|:t}Ꮫ۟5otʤ^Lъ?3F48n/_\߽ /{ b \pg2 k6Y7B?}W`i'{fѧ5Io_5>|՘}"/oG@lwB]M?Z?ÏD{kq*yKFϾ)gk9f<>~j5gVFU +սnU.3;Iww?씹:䮚'Q~R< /@f7g DE':0RuSޝ~s˿@R(^zSvOǝS*[|xϿw7dNm @ 3S=HQnfXR[C\ a 9ӣOm` RLdF0/_}#ww=xns)-yF2'wq[%FTpQBZuw/~j^0*0kBTLg={ܭ^>8sJi*eH &DX]}[tEov Zb9t^.%ڀY!N_}7d뷏AοIOk-KFu?߼|P:(gݓ嗒;Pk5d7F[/?<{EKW)c@?OTs} iqM*lo!g[Tr:ZVLew/I{)h {>951wIH #z0)wfJjg9uy# Yg^ n~Oou8n93W윩>k7AN4/h+ Fiڭ(;_DNg_r#}Ou߁C=`U`GvL"k$-{0@hFe`x.XYv7PAY}3%^6ϧWa( ʇw%,T4ޞӾ9HJ0;;U#V߯FP_1ѶI6&](d֚^j~W03Fg4Ӡ{"Q⶷~nNgַ7?浖Lg_ο h!c-d伿y~pe#t`8ӝ:j"}2>*윲RZ-0;g%\!xw6w-szj=N_=f>3%-m4>PƓ7'ߌ/~@G`Kf2}Yml1v[ϾӇ?8)S4lH=q}e<<[|/{SB h%K'7!6x}x2*H֑>!."嫰u[w$X(0u5 H5ZމXhۼ, _c.ZOZ3XЀyJ4}w™WJIHe`:{_uwU6÷qxb*sy*36g/i%u5y?C(re$!(]F?:?t?LE5\SFهXvf +YA5x{'_'[ <?luf|B(U1RziԻ^x4EcpJLz;3d0>۠H/@frHZr7ӹ a lOtobgpxn N/T F4iΟg9Xg?2mެ1ymg~jn|OW1jeܰ;nB5bܾy5?NZU=0_j87׿u'Phl8$!Ưg=0(d:w`4{OMjL s9XJF/;qrE~~Gkx+%XTk,hyBo˹ux)cBmHBQ{$)ުFe*v4-5Ӌ??#p IAB 5B7O1.߮JE )U.[ՊMć ?١>~EhJƸ6YSE4jivjU! p&y_vvd,)5h .J43;ÄxPfO?vglKnd%=v9כ5 m7e3QO|nf{Vsvqxkd©G_^O?pbw֑ !HKN:/3Ҽkyhs#qzJFgC5.9sI\^KV&o~6ҵ> 8շײϺGƉ۾tW 5o׼ʊg5jP,q`59 {ךt##Zc| :](gɛݧڒKyk@DFGwD|x7W,XqG(_G@`9MIyS|ʭY㬡/YpFx;&U>hp6-d$IH*DCIW6ǒ%*OJ4 +V߽mld-kg:2_͎|~vF7X#;/n|8@HYQ=LU)8)=;.\6+@:Vcekh`޻g~P[Ѣ1|7/Ih#F-O nE2}m6NIIq~TH7ZlBD:]5` /R+y۝/b}:Ϳ]8<ƈq&.fZ|//sV 1,ұg$Z__(ɖ@ʐJ~f˯&g?c\ʡZh|'Ge]&q2]gXr?Nj3pIvxa7֡h!h28x;^or&%NϠi8~n'V8)* d EyMu7ۿDCrÄZR1Z Z#ō !]Q=&Fh`$kk5ڰƴjef=>ekw; 3?/l tw4Qʉ@($&bwpT+&$3b$h 'Ydp3Y3r4{dDK#ٓ(.=,~7 H9]]Fi J^A<]:u>q'`9gBo$;$!|o{ڢfqt)CvGeA%#Q=VaT{ԓ#)WCD'uؚ;DR1sG5..?cզ:O'oQ3Fj#FzFZ&g +f0rK ֒pZn(:I +fDAJk~Tp&;Z%Lآ=p`/jtghBj8eQBv UkA3NiW\2+;CQFQZ f&IFA5l>=y )B80(bV;לX[#SZFkp.pY('8kRTR <v6D#/4G91\ oXM X@Tp[xx-'/9xw +A>yNTVآd٭Ⱥ;eŴxtA avX +\,# XҕNчp7V=Kv*d5wjKIОdk6dw p,JpS5k5܄g-c{÷,?B1!AlJ2ͣ޹,x=a h\fo ə)D'~Q>ocՐSSJɛ +P&?Av^kzC@3+݇" +W0\6Ȑc0,;:0?@LlFێfY>!E0 a.IpUHu[bq6{vn8hX=|p.\ &X0o1#rҁ)!*x,:} :۾Ks%sXeuA>!_" `s=Wï@)I`X8o@ ޛ3F- DzيgUªŝcʯR]6+&Husk>cLIP~!mWU{Pt5-@ޅYgh#u1ʇ+[5Od ii{n;"dVP()r*LBRg|tP9g(14ܡlZAVF&%2!,L0``Qo@toJ˼RAj4qGd hNr&?g! /D9 !YG{сq ='@C0z`9 qq'ۇpsZo46Rj׿#]E !kKdoc~ =F!]UoJ1uQ70<39BipK5:#h mAk~8|t EG1!S\lO[d`ǜkBtu6WU:&NjK@BGތъ ճ^Ao,Ͼe#џP p΅b/C`x߭;E?, T()P> +8j\'9Lp3oŶK$B%WC{3uQ#,S4ͶɅaI{ &+!Iͤܺ^_/€ CJ x{P +蘒ۢ=.f2FsZl_1J4!"BL ^kM +?Ţ/ZTp! Dk.{01)⍨Byk\Wo hdD! +(1!w805v](d8[#o~&~ +^ᅂ7pvWz|;j̏:6VoN=(o8RFz\}N n]-0A +m`՞RUD-B jtܸS# Pitpq)&NHנ@`*E {z73LhpeTEXo*20zjH2 +B;UЏ"phs&#;>BXfAV]AlZi$hֺUB]̞'EאNˏk9B捱hMj_&aۚ=К:A0ɉm$o  ڕsBL! G-.19SwEaa6!fj{yٯANH)&p(oᴋ{}/tX}J\8]Nj^;kFV cIf?/AouoXBUt҇VO7NbUF;hcD!p``JOOCԸnIڢa)= $eP|>{{kR!1T + +Vc%sxQZ("@]HݚTlIh(i4vBQ@XnZ]_6^bȐc 5#U#MPV[ePjVQ[zJt~J WUli2x ?1!]TqڡA룗n,nkBmOHdEW_9Mcnp=qƔu.*fy=;}J^RZ6j|.B&R5⊐FqQ>Κ5w5->ܽBNOs+Yf=֟Lo~/Q.UEeM/ FT $* azF/|h}3ZIPb;l-? Gdvhv6ͽj_=wrZ;^6fo8{A*ٙJΈSPw]a֟<O/{w'Y\"|8Jzn&s37#=(L2'+h_aP3…l`q>Bb +<ӘT~>}Cf D:>E؈XaVB 6vr- K=p)kvG:Pbt:nd|xop>-\ @R#5pք+{]r_! endstream endobj 51 0 obj <>stream +svP4ae8~nOoA"db#5DmuA )/$\qq)h,aq)IrJ#^PZ; Yt!ńL6@gJ0Cج;J]ZU2W˿ +>1T 5Zϵ1'(ЬW-k1? L +5oGh ҒQ +T.V۫[=v@iqj&[:xhN;Sj JVsY-=Mξ0]_|&0AEsحKNu@F8Aϋbpkljel5f.gNd}As_ڂ0Es'PPרWqqt();g.k?ҮdUg*`=ZC0dg\2 {M&P>[qu{ä&Ar h *SLB4%J !gE9o ]A I1)#7[z S*ޗ1O٥ָD>T`y=0ȰFE8[VvX=RmO&6Ac"(+zX/A"ݴhw- R;Ŭ5 z/gVM'h3Ĥ(1Hq'ev*A 2ք=23AtZn!tP!!a o9knicŝik#rdðy {S%ܫjAh 3D9B^`rE AX"_c*-qtΕ0WO(HIxj W]^d{,wk +,,`̋$\úlW +bs 5kTֆ)N1_TDͲ雸>_p濉G`vj)F_ +H%*4ٙe0_oۿ^ O@K(̅2`u8mOj .rF1ڡ+~eemR0.ӟHS<)mk7Ŕ+9Z}vS*z81EKwzft :I<~%jwN+u[W9Xw&ŽNMAp&}2{5MUف!,+Rn[ۿm{V+%.btC +xr7a:RpZx\je`w +e#Lg U¤DG?4{OQ6ޭeDEaupgmqJUThaEʘLA TS@ /~ڗ39Yg|B ]1Rx^ߨkٯ%W!_r%CPvvԌq[|XW `P5o/>]N;٭[GH #ճ?o6zᇍpG#rGU!`Ph%j,ư4>:܈k$$?:,6g2 MPwŲ("4p9tGvvu?͟[m3M&LQX\=Dfwp. "aGG>B?gp(}wģ=|=pC?Jp1䌶`vMFZ>)[ h]Ֆ,$g,BJ."M $z#+[iBpg3c̱P.`bq\Z/G[0WZL FP8sΚPRw]x PFf;VlVr8zTg^T3#cnVY5[V*Er$KuVr׆=qo„"1GYhFxREC1U +aN6(&\(+9{=;Tdn/;qU<׃/0Q5dKƚ10wty0krq6@io&cZmlSFr\j +rZyP 2 HEsU9#n~ (>K[ad**B@e,*oHy@\JX8Bjڸ͉m1y\e>%q6i'7Daw*G!y}YE >.ja&.Tb=Bꄎn1 5S;=u '=Q<\^}g+J(,ΤFwEVHx,6b|E{? k=ޫ2rlmKބwjoBJ޶+?Yo?6(]e*eukh*ZO`QZNҬݎ]ƹbJnbB9#yca6nXeEj2 +K· O`tw+[uܪ nMƹVFnx.ZtUiBU­`TVUƇr#@:up֮z >@VQ\WvIa ; jKVv8E +TpN+;գ%mjV4c<]nt"PVgp~A> H)W(FPZzth%գg-45T gtPVӡrZ:m*%kRr½y`jI1kDigA**e"J +JNDfjsYoi5:Rw'ZUeU8~Yqۿ7z@1=)" a-XhVg:#T1 4'+dpm1rݓᓚFfw\ KcTPyk!H^v)˫C"դ*mT0ZZ²v +u܅C~*NتS|Ĩ8f[v!)zjh]ͬ2iҹj:!l{1;/6آ- ~Ճ ^tO 5ܑp At5E#T"1>/ޜRE֓gU&3 d{zs +abRt~ы&v"P"ʣ_)^l*hxF; + $ %}H6C&t(è}6eT)r(:<-zeMq>C h1N]ު0eDjbE|'Mvk*„uЫv@ (06&B.mͶnM9 #IH٢<3  Ͱ$ +!:?BUԄW}DT`r;a68=X)vK]^*UL\DT`.r7@E0QEXH[ae:GdRr@ nh7Qh#6aAB?Q +UZ%LSAÄZsr[a~.`*0Rd~ߺ 'ʄ M$F w[w3J.yc0>(7JLAk.ZnqqQXX\ +@8mW; oVqT!@pPNT1F<*dNChSyk*p߮>"Zd06ǷajdeÁhgŵ ;ע2Wa`%)VS= 0ڶKyIMlW¥(ѡ9s L@PrLHcJ3RTHNըZzxD+y2%ẁSrRZ+*>A@AlJp$%_m!50TZv45gOu1t~N_+̓]TJ NUL@KuHEH3 ew ^kNOvvLz@.f:*vSR꼏+ ppBp9#H38 +.D=u:ϣP:P ']h饜\H.'FzP&]h/H Zi=IvhOΕ1')7+xS9\V` {է3]`R `ĞTwPXD0nAA=ŠW LvF$LU +!<`.R2 +*Bjy^Kt + ]0eb7B>u¥F0~Jq/7 ju„@eh ';de75d *eIK ;Wi'\Htwa(ʂ[7+ƝlpRI@[!@=ީu\xJCk `(BH)a<΃ P:`@&Y Hr& +3VW*"BLA$Ar*|e!L^aX +Z +zBv,/$UQ I)<`TUIeLE +j + +@>8d>lvså]CȐzq2n"u$W(F]&TSRhy. a H5N! *jLsEOs喈J]2RdAŃ=;xm\ŃآzRKS=[?I P *]+9M^jѫh#؀{\6s7oy|Ɗ-Y}H "4vkhX[У^l6'v Y4a?}-s˛LWWȓ]`h eA +]lVQ_L Ƙf탥8ڮ@ +dk3LOu~C|or(JUA?D("n Y0jWX;x7PDQSa`\d=%SpR\]9WW誮9s9s`!#HAEAE$"P@Q0/5VYkfO{w5#؜B#h4Q\qHE8`(3Rк1FހSWhΜ 0cvAT88qvJj#c~1B!x#TD +J`la!…P-L'(1H~TSF?Y_ sxU|~ +NO0JZ\4)"~z279{:rQ#LiEj~1,a .&NyDX(n}*ـaTF,1IZ +%7] V z/l7xЎPqpI(3_|I7? bJ$ SI*`ՄXӋGs|!ɏEAz.D]PfJ> @qHE 2o/jwSC@Bveh0i+9B l?xxE1xjxb#:l~7P +xGHbI'r/CO*hFBքȱ7'uekIT%(xZDQA8L"0Os椏N hȌ!6'&9.I>*Z kesza8!D{XR?p@a1A䂮^6@1 ,Ќ~T 3BX)BXCt;sP ; z!;r` BCv l5MYfE7cQ-zB5VH(nʸhLr vюB? :]c&O1~ |WۜTr{%k_9W3wC֒%sIA A6<ܢ'ɱ6)mn:=}rx`Myp$h^Nhp#7V%%qd NYFvLFKM}My{Ƭݠˉ \,@c2TVF gQPDVwԼL}V?"\j6g|Kք1aLP&VTRZnL^~ +J>Tq< PP> 0 fgUIʨwY)=X)6k+ N9/p"Џc`l^7cYK6A4Y67n-|ݧBSg8m< j! A%f[<ܗ "Q'=d<(hI@}馱/}edԎ}_N *.z`{ȿ$|aN0P.}~p@;.yp~rxx^qRv7 * xv`=BA0bǍ`w[0# +8mdH!& B0w谛%'@Z Fk-0b+#7,|P̪MBi{0kIŏVwn -"T\ك$ZԱ <n!& 2fR(G +BAkLO/]\ra;Hb >y:5A6tF3G("&1>=Cqo@ךPQ;_|I;|­8h^P_vA+Fr67'$bFO@D8' l nE1lC,l;(x*g0*0qzw?胗30v'=! +6_č$;qɍzr qTv,"Z<w &1{|E CjppZ 7p@5#`@AA,xCp-$`K7e02Kc~vH +nb2 PhT!E#D!;;7 JcL^, #@m!DR}1dh= fJ۽ I/jOgB:;# ,HD)Y^R#8-*u"Q|HJ7㦁' +9v H;8%=9< 4NKO@%{n:Yd"!19@YD'8mTe$bc5ACPPgӛFzfEܴoA@ãa,jNvA>D06j-Zi&FAjmZ%]j n=V:z0(GrB=f ;T "7'a~cv!b~g"Uz[IOF `:)Hߒf\E 6;_i8 jrcA [N O$ h:03qQ@.bӚ@q PGײ "VȢlXn3i/Y[P +ib%{(%OaL v D+'a$+Ńku 8d,3ȶ6Ne؄(N:175 yȆaãsZ +62Dy@,8(_@ryi; ![́Q? )UP7=>/ʾ 6sP!9}##6,_,N5\B?xxN ; p.^"M@UJ@ |bA0\@`-YkX*{)zc^;tr4?G58!فΰA _J1&KG2*Ś9 n̈OB{׆=,t H :k (b1`,.Utrߨ( !:?Hguǁ7NjFhk м 8kֺ?v6"E` ƈuW&tkhxz.iVRZc T <8;h8+89AFZPn 䗂AYsi@C`H|R@Mm`A +q*?a. upVLxpzPpؿ +x_M}}a-[ IJx 7/T/'c=hqD(bBb eŠ{kc;#?rc- ZeIp0DMjBSA +.t C*}(hS tO% I㑢 QR/r#UBkJOe~r^A& |d3&bP9I7xo +}P؃֤%AURJ vl$~_ + +H@_`H K$lDDkgf̆=1Iv?6gm0a2^2c F]*'8 +Hq%ZQr\+-pvkUvCx +89q_Iu>4ǁ< 6eCE@U]~yc2@Ry, +(K+rōAd"ypѠ㮰w-ư >m-x8E$#<P|#Cb6ڒYVouH/r-H%*&HjfҔVg ,R0.e&olr]HMhahK֪c %/!lVWq&G֧qLmvrj]NKaH(TjaEe *ȜR cm d2˜_7@rp8P oI{1p9!b>"AU(_>oH9*9ځ(8ctLJ !@|K iSqZz+@A6#Lk $ #r=9+`0hL-Hg ؃QCI/6\*P=o;=LI m5?)|o H`Q 1<C* 7Hvqpv0 X7"FOD1>AF`h5&u? ʧFh[O&Ӕޠ +.Ya6Vb &֦5A&viS\`.hRfi!ƤL$J-ʅTnc6!ALhAJ>x 3(E6i[NǏ9;"y)%9s:tq@m !chq(-'0ӉDP3 #D'ս'X۴@PhRUNN&RG +> *ɚ=>9KKjnVH°O"68i)HrPߋVXG)1{zeI ]D$cU%7f,2(v#jx>7{a>3˴m4R qy?q>֊5W[bMxY:0tD!brmz :.kBbTV] +\VSFeV0jJ:>kZOKI +6O.(q)3m6R-.^̊H9PJ\gx LPJьJsǵVDGLHIDh$Pq7 bvU[aנo`W4|$ezMrɉ SsRzvrrԝH{Qs9hhdQ[Z6JY[L(P_4F}M.%.MR,xMں^^wX 'D$.&C{nzM-X=fJ4֠;aJKN.'O:a!Ţ$f2CՅ3#kRo̫x{G`pϧCld{ZtiJ.;Cwn]?uO EHWn72rONJ ̉PT`QUˏGsF}#>$CB!\}QK6?srvI.cJi }ez8RvdOV{;ݻ +[G-fa|8NgN5W.vn!"iR-u LLPJNΌ[@SǮl WSgSCk |n]._|MpP+;W\@}ϭ[ܩy>=):R4-xqopSFmcrkO4O\^۽De:w.?t6ֶkAUCHO箔.ESΟpgń+;)Ī;F+k!&=Z WDzoocXIwwFxhz6X{'=^P20! ".va|t)=y&Z$|wi)Zyט٫Om/db5{$^w,3boů-Bߍ5+ {rqANN;s  rz|p&ۜ];㟾^<-5w湇w 3p7ozv~b|8{O{qҝHbTWcު'W/ZeM.u0śz:U(9.9{2(p*t6ИHF?^11%>xg\-\(7Hi/7o̞VKHQ5 8p`V̄QZnm˩ʩs^N.W.BWNgvc|_|70`o5[JaW?g_-( *7u0srq7v RQaVs쵇x8YoqPA'"=q÷ +z: +"| dؼ *fHz*f$Ԍd]hD}pr؝)BbJ +qBL(nfo^Y>}Zgr%B|sG@ʓG YKRfrU2#핳b1ͻ8\=<Υq1(v~Ґ#PԒqp8*TwJꜜ0&kvx2m?sRr֬5R!:p"0)g&[>Bw7w]֊+Bv4sPzfDc5 +u6ioϵW.޻p|HӜ*)) wY).g 3jnصBs TA|j~);b'.kj2iRf۬ORKB&Dǔd0F Y)wNfG4dUؼ5S&mAmteTedc osSW%pD4EqoI5 p֯O)Vs+VAŤ|.Ż75.{p #Ub3q|thO\AcL3Z EB4hUOfY; w6]%=#4Vd̵KSGSG +ǩD7(b3}0uJJbP6 R ӑTD2Vl/O46ٳre\}La|[Ii%_w8=;U>Q/]Vjt4h;Ah9,kSǼgp! +H-AB+H'-[|{={ܨ,(H'Yphu5;ަz_$vX*D3f+a:mO\:C&F8כ;X~znXiYI $5iiF`))klk5.x(wT?V`vbɍk٩+ЌJ Q*[{X 8 b͉ 踟~Hj76o" y)dp=&kFkjD 4f$5-qzH(Q]S2Ka +9씘#RYp&|zBdarkyRR*Y[,\JwEs`B6b6rnMnYzGJ9}*ȍtHĊK\3h1/sZ2֭3N>_*Ϯl_i/ecMR-ÀxI#$’H&l.KŠTjC4`ryD: bq-Qַ451A(97mF$'**gq)I2u1BiM5f&A6f +O"x}+V쥻 Z$ jof}ʐ &330>^D|͛Fbٙ[zk3GD]xL,ry^#D hͥ&KN';G!/ d-^E? TXJ0n8!iQ +Jj&VʃFRD{S,s!BŴd2GEr1R$R+,ˀcъdqr >L#@a>dlmBgRslE ?|Ph9wn%&Z%Z/ySrꬔҨsAEOyElN+(-dΩ J*`\aގa2/9)3Sܨbbduօ#rw!܄Lj9R u|gAav"I͊K{\I&RG^Zt΀͈!ĥZm|53 -V͛1Q͆h"f$* 6 S[z$kfp7wӑB,=C#1 Ung\uxY gT8Bp0Zm{:+U|!EIvK汍}CO>ԳO?_?_磿|߽sGX>d1-7 Ot=?y׾y~7^x~#6\.y +.ZJj9-QfA;~wO~?Om~ʯ//-(%(g0bx.x:]m/l.>3}:;{<~/~w鎇&R*BjI..TvXI5fT{.?yw?zz_ȷmGw£()e)ڔob,v3jo5>q{||?0,sgU^X׀%n6DDLDi2u8՜M5_=xow?rϣOw|cW09HJ\$JWfT3U4o]Y;~3W~/~~{~طw4],x-32BÔAGҬW'wO||m_#O{3@G~)X:~ͷ\7|W~׷>O?ɫy7N\-T +#dj|g/]rG˯F^3?~7zϋ?cO|}lҙ-LX,_||~ǟ_> @^{n{a/VaҼʔ[ݩ]8;u|?|7~?_>|/4#Zfv&ƘNf>v涻o3=^w>?yÿ~^owNޞk +Ѧu8cǻեcGO_k?O=w>|O~?Cwo} ɷW܈pc}ؠhӛ{z>y7O_z蓿 0j^Y<|ԕ}G~?~7o|?_O>Ïއ=Twp&ᨵM RZR2L[lϮힾ|Cz?O_w?_}౧na#3Ω-MM.on={[}~៿_wyvBs+NaL5NG"l7Gc<|7o+|} ?{WoŝmŬR{6UڋK;[;{GvuW~ʫ?k?rއ}/_W{yh <WXQΩs8sĉSwuK/wMo{|}Gz^xի?PQ\h//bNRJ=|g?k_~yґsi!d$!'ZDЛ__XZ?q3?~/o'w?o^?ڣN{j'L=a9LVwW!='^xW|7~_?{wz-ߗMHzΏҞ %t#묮~_{͏ ' ?}~~|wwN|sAT %aӫg/r߃>+Ͽ _'ۛo|я._ut,7(uB;LjŹÇ;\rѮ+a(=>Z R{755={ȡ#ksᆱ=x׵_3WnZ^7Hf{7CDVR艓l.JʱWo>W|O~g~셫gVVLAKh1R*h>~w7K`affg}<_?O>yׯ'/~Ge= )$BnA!&QŨrGΗ_xÛ>sv#[d''H2R50`/(tәZۺv7{{O?O~|׿[_bi caϘ=lwbL2?q+z} }~y^|J!HSڬRT$)>|λ~'{z[훿/m~} w&'q#;4(Jޡ;o_|'?{'}g]߽􅈁3zנS|~4r)ЬMֲAorunuQ5o)qяPGB!ۍF1PFC$-R% '84/ifG?D9_ )xӂbQ"Bެ흺s8],BA'!Ə/-NN\TTd63Sd˗Jvorq=sɉNWuQJQ^ahfKQq#ktJ1ϧۛV-;55-6"%EKE2=^. ڜO2HAk|jw~'xl.NO.O*#Q[!G<#~xY>D/rFD51 WX6T:S٩rEȲ zCpC2`T0\TL"&ʍ٭kKT#as%#'iBbY%5_0%glXl.ьEѢnďhvpv9OcU*ŝ3(xKV)rZM6#H!$NQFGMdd/@K9qgD3DKEPv/EY?.F1&x*% !Ap58M2X9nD M4v2d̚.M*"'ąp' $k*zMkl$ϩe1X^ԓ6$-)mn*qP=^wZDIҬpqXs9ZnATUnoQ?m.9dRmzETK7NBix4tyIxC"NŕX'S[M>6'hzdž0 !LR12ӣ6tuA+P1ځVW(1.KWVtcA"forZq4VH>SiWƏ #7SJIJV $ZuBF^!Du]-,H+3ipɇlF>6iCn @0QwsH@]6E!mq`x1q.fL_BhO)Qt9>${T P)"R1&wߐ +;]a-dQ!aqP `/ J, TT RA;>f~ 2zn2YEYs 2fؤE yB#rfz.'ln 8},dF/|Nirj^;:9P[ۜCfԦ=TZOY11&% 'O5/BуhcNT+gP*~pK9Z*jE7[vy#fY%4)d#D;N7@2v'jØr.k#iNkJG⍧6T(gKV "պJypsE8FˆGaj01+epBe ݥ|cj͵16AJy(w)VT)!DjThN9gA\C-P #y>ՋrjrT$؇F@,XDH-~¡A">,g~p̏ǽbQBC<.#>ΏǘL0G\+$ |QMO+l#yw@sӼ`}C0i*iAp)>+yGD`D +a&S+gka.WF PblA >1xm{ʼn>ZFٔ+TN4:jg;ђP/=lhMk6kUW"Y_[Í)7Lڽ'z;{צwh!!7%Ji냩Cǯ<NTrA"˙'' n}I2)\a2a.'MB4i-G<դL)ĺfBOrA5x! :%Xu?h}A$g.-e> +(tGC\P:ޑbm)ޅیz^"!%b5N+:QqNRb+ \*z<'ď3] M^kFmB ;Q 0Wq lQK3[ta^XŸgd?^#ӁҌ(cAa*M)> +ǵ1T`!*o¨0vw{п/7梜^.4p[jN1&ˌo-]ͶѨHƜQʾnAh1.? i0aCu _ܺj7p m] ( +] XC!|!B1ETflo1)H"y÷훈T$7r f~!U^x {NNϝ/8MOWƏGCŚdb6SݝL778<ŧH.SLleD5cU{9DŜ~@;PA2i5;Ô1gbP 0 <ȷh4 Q^470IhE2\HEiq$?fjMpRQ t#L(3BN JPJR!tRfH+( w0T`/ ryKp!c(c<ŋGAqpl8hG>.(.]91!]hS=@*g. I^Q7sbPDJ,i$Ԙ $^-sJӬRJTR->;PKl43gs./I/ +ZO'XIB M|([.l N +`$LNA2!:<b4YpQW63qp>*kJ&҂u^- % Dx{GíX}D,vb|c(ƚ^eLmlvb/=DiuZ_|wǮ>#T0b!De3:F;jW!lJ1dhe5&03}U!4HQjWm^㛃^O#ZZ\rJZ.pQA:Z:!OPDh41NO @,mFf7(M[a> d$5kɉa.Kon? 0\+.&F7\'ahQ[P6`bTHk0!w$'f?=͉ s#UJUfbY2ZUr3L(hz@˥OJΦB$]p.+L S.ρ3bK+@.-?}yhi$Dَ$:h64r amJPJM/.h<ϥ줔6j+bjT{_??q9La遜8| |֋v7F+dk3\䴒UfhBfS3@űy)5=;|yқ~.m^,wM%bUPU@݄B{'"!7lE 2[Z[2HK@)E>ڈ֥x+k@[`IT#Fͅa:@W=-eT,Nu*mټ"Y'2"D-0\(FA,y+  jta!+QR3ǘjznAabVy%\Z=}jrPщ=FZΩZLe8āN)Bӈ\1a/ DW2+K?r +k¥dc۪&;ƶ:oDk= ԛV+rg^a8<EPHNwhɶUY raJrjjxx4 +Tm!`帄Y\dژEW\2V_qlUN7/gRSz~4J{绿<{y|luq7 X1{APc7x|M.ȨbU{7Ɯ$E91^9zwP]' P JMI<>a{qdq| ;{~rR*C%ֶ~rg/˞ (fQ~=h/dBCl!Dn+-`%eQZ\q8zf6A'&"]-R SJNBG^v>o9pDS-PKY-^!8ILlU.֮bN77l_R3VIԶjjP +#%=3=91 խYX5JJf@be&\jThN\}ݼjkgVaPVyW^am%&:nұj ӋΠdRvs`,hrrE Ijj֤X<}hM <0/* BΑF1Y_<$Z>uE*Oe$Zg iJW WjgO{pvF"ࡆǁ\ܷ9~oM Vwø!c>Lb;ߙ?__*g\xxȎ9 >W=BJ6`WH^ :;*57:b 5P#n9>6AtA+ z;cN !9GG.T"4gjRG 6!$xUQiߌPYf0Z&Ī.tz킛PBgncvjU6:9$$I(1D(xm6@8B[H1)S\ ri)9BkEdcmzRsPSAW=R.26BxqeA R]>2Ņh> =q%FE=P^:e0?gBnA2̙Sƙǧ|P\BBP/640y8߇Oˁ0G\ *,~x^K‹ +1`8ƨ>rr`5QhzY&"1"Ƨs &mRm=և(ǍdeՏ*/8 .HB! @8UcG{ x ,FV"7 31 vA/n%MJo6`! .O\><罐ΎQ3 1E(62!ZPQDBU2>8wEJ- k==sjVvirW6.vK>ζ9rw_y6 |LJVnah` 0)1S~" +I^ IblTFO!LSrRm +*3J+VtB.z=!$L5"G(SMH} |T;w嵹[Uu#aU&ù6$Eh=)ediӓNY%3z͹Ok33pd( o`r4a]HċЍUvc#1.:0q6BPs.4)cf!2 +y:Too\ݽgY->ޑ2K&Bti0rV^f2p<<;:CIU7aT %%2( SrrT> P^¬aԜijz!b i8 8,!GlHv`Cx2֟ǤJ2bRi]xLKTiiqj +q=ՍַpK.F*K@e q@ M3 _@cm>DVm#uv + 9T\ڹ)gf>" \HtͭYD+e=:/K H= HT5&A֨E%hPS[k#NnDlNaZO;#G@ $kBO9\M` l$eVY]OPH8u i \^P1'"vĎ8O^p.S)˧a!NP.};+\r|.,/ +8bbu܀BYQI?t!44?ρa ZlOh,W,^?r1<񫔒 P\$^X `ON Qo@ÊM3BKCya6t&G' +s/sf/hRPjV2[ux3UW0c1Y2 4TVnw+*kv6&j0a;!-A6달F֬Gfzzy܏g#9=q$7^ "*E?4!ԑc=pv T[sN}옟q~UZs1G!ǝ( *&>DŽ&wvڪV5֮[b-@婽mܪR|b~AsSu@Aq#+Wjou'Vbzil*n\Y#.06ɨBpts ^&(m9O7pB5L=(nHu`#3q)I +Y.4|'[gdSϗ{ͭfgf_-9H)Xy/^Shv&"|vx\8ذ8dNg.᜚ ::B* i) GG! cQ\SK\tM|lg,t;g|v d&[`a#SwxZ#[sr,´!T!1hD-8fǞtFm0@#ٍeo{ޢ"dXfiM6W/@p>eff ؼ8 cn/ GԽftel`i`p#Y]W@£vcQp`1 +naq ԏ(&)1J/~~xσhdmGKk`1Bρ +eӌXbĢFEJ,-}~@>L@֏  X0*@倣Ʌm%`.N(Xe3VߐZﰽyŋ=1RrClל>vpcwi#uF;~*2j aSVuyԣo{oqjy3(0wzMO/'ϕnə9ZN;-91Ň'H|ƒفċC݃vgMD hhWۏt£pmEL(sgf&o `vw"S_bd#hIΧl2^!D(` c.Zn/kE92¤BHv-=7ܸpp1>ZSΞ4ș.?l~$EN&;\޾qt} JD1j\ui~m'DiK|u5T=1@.©9rzi/$Q/@gi) Rٙ Fa)ߗ$gׯ`Ru9?:!$Gƃ 2ˍs^ C`}"9 Kˍz΃*c# %5WݹOțHiA΂c3c!228w?)9T4ea3jj*ެgk n?xJyffGkؔlobi )͉)h=$ L̃#>y'dž${=$Y޿5%%ֶ݉3Q{PؿH)ba"!j\scDa^x栠Fa!BNHƃ_\Dy% 40d(nt׮fOKTX-[u aA}NPbm;6 Mk0lLOTedP(U")$D˳q' J@@Olv0=ZeV}f{șED,Bd|a?}&7mw3+H>+UNkZJ2ӡDG6vSAXFPU38kBN Q/ ;<^"Ϝ~,BɲVCy~M3^[{{dK3<-B;a qp?`߾8plp1;𰠲0B՘?P>2iiU)l&W1).4&JG)2j#5H:RhF +ޟ|O9hd>h(a (嬜]ۺZMOT/{f?agK'7B| +RmlOrarNHg3TN(bTz̯H2Tu Dl}z1w7[![ ' XّqL ׄP!F4,-\5vp0R0c\JON}ӼVC/%Y )ďv'|c5c^͂\:woyG'{kcPAL3P&dyوV]n"nB1ȗG!60(ʪpPG*6ϯra}Zm,^,fP! )BRܮW0\$n`Xl)7 b97{lFײ'_޹Ǵ &=pnfcJ6J'E۸ w#BBk_MPmy疚jH/Df-,omQ:c̔:mmy&ROa7fbe&>G0'vҋ: rb(pL?ݽZUglOl.@CdQTڧH4v、:6 dB&zM3MV5HMzK'/N~QMl + +$IuȆ!KDlzb;ݛۿu)x~(';nLe1(q.*g +SjuyA5W /B^/y>sK]o^`8#\ͅ`V@aVӝP*͕{vjta[VkwTWO'<HuQZLJDƜ$Q~fzā}3l 8Hi>\5﬜qDk0jA6|}!HV  D X0楀G5b8ƙq?oss@GRBND29:A +Vzb/vv|VJ6vOݜ;~.@BD}5d!3pSNT>|h"REO'(lKv>TYḙwodaV`^5 3OzmR;ڳxm H\2PWbtRJ̲VOL.FeҾu7Hʻf& '"@KzP]~yW9\ "?j3{ &\loؿWCe)1!FV/V *Tƕ"))M2Li,Ꞁw~؇fr7BpE3͵3|h+kg +sw@B?nqթa;5K V;\ZuϤ&)!~擳Wܸ5i:uK>T*+ udؠbsw td퇥xfQ+c\F&MJJ FĕdiP2ܻ以ގ޻틏>]8Zwν׾lVq⑑ ލZbx]iDj,>2J!*Ćщ-S3Vs+8.gHk&6܌ rghר % +nR֪D%aփ@af~}P[Dk|j[K'j8޹Dԁc]8Ӛb5)֡b5 zA#ޡ1 +I7hˇB&LjN? ;߹|홭¼bռA%TV5jǜ^ZL۽Աa~Q Z4?lZ{闚+*h/=}of#&8B@z6r.?p)ќ-` h&w^z꽷Y%p0}9C=5$u찼99Yf`rt1Z6V Bg**z1wp{nRuv*/@IZFo_ Wr!D)./JZs_~o)5;:.o$n(uvn]>ua5jfμ|ۍթOÛKFu/ۃKs0iK7_Y>YZ8NGK3Ջ{_xnR:O>#vt R/gb?.|#18*Z3'x~]?xfo5XH4 T7/ܬ.OL鹎 +kw<{u?mY! VO?]<4U[\zn''VK;u+}gQ\ \=vk{3{ +ܩPn k.XAxMU#7rFoSЋҲ=>0əɭ3FFD +Jgjjʢ|^Jp֤'(ʡ,BG] =ao{XR̦'6Y4LɷVgN +)jf"%\i͏rRFk9wcʨcj3^Bt^"HKF1KLfAUvJR엃 (ǃh &%a´h$a;ڟɋA:J*Y\Jjf,* +VKғJrZuD'VXsbFTqcJfN2Dp|&}:&`"`dB|*wlk3F*^Jәj/VX"5%R7-B+ u!\"?"DWe6t#rjf@L.vj{r΃׺kj4pxK~2]嗿s{.^8s[͵s;w+ L['n^cr4õ9JɈj>ЬKkޜظigo'"f#JS'j.~';lO*m_uPvQ L,:[˗OOo^NeLq(t{4JDP'X- 0 ʥ+O~\ dtTH@@ qF-z&vϊ9L,kQ u`T8?ˆ?6䧤QZ]ܥ/}oX51^Z9e&OXgWu1v`.T*AC6jN쟸yc"pt#-AȃFb7{+]V/ Z-e:Hhң@๐He;ݹf{Jz!Bnp4f-YK`EXNP,[PeYp4^)-] 6~6oBZvh~60RmB~+I>T`q ")k + RpW +4 JLrmR ;|Gh5-E+7kD34mrB +!Æ(.#4 b*F04Y$dKM l +Jڿ\7߉ۂNddqIRZ +D@tpPB& p6Rsx-Y鸕I&ZYPpT"FAk3(PXkKkT7Fw.=-/YRLqvy:PT?BԊN7t!tGcQ`G,D)pG?=9֬~y^hQ! $د qY-O,y ^[AuyPI@93|M*EZt{[7|T J1$~q!+d-ddVlmbr0C  T0c6<LH.NKIJ0SMH)H53P~IuC33$z p "A!dNPk`ܠNIê}SP_k+>٤  Z+|ZC&Pya HBnEm1gp.76B'=6^! (D0󌒔l(O +ZA`4 K"f8l̏8 dRe90TɴpxRj(GPۃ@nb98\.8cj8Op(7QpIJb1㕁.LyMPpdL0BDl*9=J6d㊞PC) ?)tc.#0"+$ABqPEn7NDr Be0ǃa `T&08ΈYUCzpGBE2 \N8G./nw>?~L ݌4 Bഖ.$K6-`EF +fzo\ m60aL +L'(>c = _-`  hH21J9YnDu&A0.OÃ쯄,V ~pF2Wz@4>1 l6FAa&5~IގbCq10DWqبDRlA`14Pdw#nP + yFKn\P"( tRV4kzafRQ…j/R#%|Ax dP*j23 ;1lcyH偩2`c$=}MLeGp!nV T e:p/BAATJ*YH5HT4 G< dG=6$]v-Z.Kk+V5 +@|:Y跊P5d*Kz GSHQgzq#^ٽ.D 0BUN%KR%h6d7zɱ1?_<#rΉ[c:ݨK^KH (!3B +BQ"x |Pti D +gh1:A#G\vDdž=!WfXKVS[Rމk`|Ř 4e"Hڃfw`D/(_ٜTQA;6F:'=^!@<0TAcՆ|/ؾutt` t@ e^Sx%A!BHRrҢ'?W.TrDJYI6O^^޹CQ1.o<Tӊ6Jd- A0ϊ!8VRd0 5JC0$ ǓAs;‰7\Ұ :zl4*hC$i iŪ^yP oe- v68u)& +q\*y녝n&~7eQXNwS! @R©͉&T4H yBS@^(؈6  ^,Ns  A쎎:elRHF(Wo z|<{to##/}ay9NJaEsxA ]`$)lGdžq׃s|d=,z},NZ(aMRҠ búɐ͎d9:9P(z| s*LnҲĉΗdT h *H@_hj22DŽU^L-DW? j+z,٬ܻy^}jqG,* 9"N fJ9|xb1SHEQFu6`Q. NHpGd b+T"%SC#=A08tiJ;=i$@BRf(q =5<$]^8d`0e0R,YT5%BTdUF8J/.Q  0Ā'=~AdP|n\!En \A+/^NZaQjK AM AJب5P& DQDEgiIF2##/;:>:6؀10z(;D*cCt4A BXhoL'r\+4_Osymnh8v|ӬZrB1q\(IrBZ'UYf3L) K2I tc{n_Zsu\ɎF}0P\Bd$.ý6VռwK\/w.{+TUA<`a7spM&L K%ª4QOv'VW<~<5Q {nV4[8 9H: +\ C}hB(JٳN'V7S S>4bDt ,'s\&/劉Q0X<37LLW“{'n\[H#$ $ije'tѩ'#oXw~`knrd +pA/"RDnJW3 Sw/Zseg^wVIFuEQ/{}OT-7DS dIZd4c#^#^E{35v0qL}nt_WNgq<.7`{^ f{8d\)ʟ_>h9z|m͙/?ٙ|ѣ4t>1#`xBd`1'${Rvu +B3̚yљn}˿O^YDzݥwH;#Rv?8ոsP9_>WW~po??_}xOZEQDҒ{H<ٙ]|VW~ٿ|W_ު>.q#JF0~j׫W^:Uytw/o?Ͽ?ǏQ A8 <$dvqEya5u~=0:d=Ͽzowܟ?o]ڙg,ȑHBfJ>ӥ.i$?'ιOnѵo>jA@h\3*am9Ky.rᇏ Oo>_O?;{_O|=|i_V6ry~O}xOo/O{{Q3\!Жv/+g?\ɳO_[''ӿp:JЀXJ7M0oN{__}~>7w~ݛ|rӻfOvE*2/c.GJtϥmj ޿իKXxvx~^ÚUhu2syf1Qܜћ/?gWW~鵯_߾_ֳ`1Mp#AuRةp|\~ٕ~ \BS +Sv]-g{'ʟ>> {|wN{ocg2Y"qBRDDL:Tgnl~?_|×6?_tӧwNŊnfD5C&K,gJPxt^HYNtٲxiSR}utǏVwg7o~ֳ{+ݔ2>Bf +IbJ7'cNwү]<<ռy<}vοqqBr%DdE=jl3#cĉI`M_\->}u'roE߬Qauk +g׏diz쒜2i»>>##̬,\4gzf8rhVĒK AH +Nt[@!+M9y=|C +Y%d7_xpTLB$XE$*}e^U?~rd|>WFpZf|W/;cWovw~wώ8"T2@ٮ7UjTUi^/o·_=y==7{v5Edp-cbQxɲ6VFI(~p,p'߾_]_~}ܯ(GUAIkLHa7VZW+^/{OoϿz4m8mU^ )Z54oٟvyXy<Ҏa9Z>ci-tdU`bENg!V4eue1f#XV2ksj(eEL|$pj{=n(h^SUbnrbOv556RrgJL$_M4:r)F*F%Jϳ8)6qʸ2GWB4Fħn#/[c+Z:/2J1ydTQ-$C 7VrUk>z3X)>zvw.{ڷ3̝4U&lAmoeHƏCvXB-}K'iZjtՃ"gQk3KT ھYijk )(`F# +8K kp1=\D?>#`5/o=:c %yC5U5Km2_CV}僻@Er>Z!R %{.6%OB+vQ.`49R9!՝ƺ>LY/;3zh.pr*-x͹SLZ/Y|G?!V+&g 6$&e.tt(u2$xr2C2g(y{2,!jU5w,Cښ"g|Ca+2Q OFcD("w})>6F*ȼޗa0Q2Yc.)60<§Bsk&++a&>SLgbI`:׊-Y,N^2 X@jcbgO7xWۭurLnkmc +l?kZZ_U/(_a]*R?% *w` ^+^t`?6ZWC*mjOɊ~-8ch|Ә?xݳ{z{!8Z^-o~Zy{{Eǔ:Z? &O{ &ǼWoO(8v኏V?_x+џ3&pM06糠P&NVa IF+ +CsB("Fj!M +^"2H"mis.=X%t3jHqP) A2Wew){S[FA)35}Ψ<5ZX{'&u-1㭊LMtE.65hy :;z|@)MWg +v^PȦ߿bY,f +Bb`+M޺NV)&%!os%hRrkPa2WE婫.'Kh CTg Kv w]?e2: VY R_q'Nf'rum4O?컊rh6.?/ Q0{,_Յ h!SћIю7t{ձZwq`Pi:v?I +Eo/5V_WR|(]sx~O|qWjW@+ɪVjP;W?BlbMB[(-:v:DW Ѿ}hq8y׏;hUC84[Btݜx{96qQۋf65y5S2]ť޼ԫݓ'o~QUH}NK~o?/FQ_Ms<)nut )ieSۗYD(3UAfں?@2ze2B9",suqoAbn!6)}ۑջ?eޫ7wAQsi{9)NE|]_11R* Sa̡ +iεxx~pK=>r39>;'j4;|wzc'w>x3^^8}IQgQ[}=>|HTYu)"nArr`sgږ[{%Nyzl6 \?oxAY={B[s}?g70=ݽ??=AnEo/Vco"|Kς㧿iae}|]lH+{|Ƨ_NymDr+׏`6K*'R'F;RC}=q/@!c)m-v߸ˍT\eݓ癊ط9WBGBmZkvNm]Ooz߸"P.W}:םo_ѓoG%o`Tnz?x?zO%wؚ]/Hc!ƘqPKF봶x +Cj-_Fӗ̓oUp4Ϟ@>&_x G_hr4{{diZ y3=^KѼ,TƑ:\?jPF=_Gw3N}(JmJS[G\[sQJK R86:Q׿d5^ NuNކ3!LJ^8V=Zdl z<<\ks9 +:gϿHWo]h|O,P>>?{sw$Zsvq/?UUj{Z Yѓl3k7sVJC&g->᪈6JƔP6,^.*&a1T# eA%s|"bß,gt֗_^A;_?yAv矯^=>Z>{%Lv'1e(U6oq=_ςOL͛/^ uH h/kޚ"T*'93mD?#pe„VBtFHVnls\*C3ʐX2FPQkugN%- 5FkpzqۃGX?U+ 7emx^_ ވ^cvNO*U ß RXޕxF/ZKwpY^iե掎.]M=0U\n^$qkϛ[iTQxnٝӰs;U!& RnBA ک;~1ƀG{FA6c̓$7B3S7s"xbqYYv:.v!qθ6}Wọ*ojlō\n>-Ѥ6X^|/* 8T_ w. p:g/ Pj7 Xo$b(eOE7Dĸ(?G7m`]uw%2:GLQ_kp7Ǽ ag͘SDlAn.ËP#a % )\b6Z7>鯟9KR~6} ]7a*T݅!D9!|̦fGd.84`oUhKh+o5ʣ/,tr9y,FPQrt),O ;x3;ӓoJՓ;Y1_ hZ^\{ajV8;rtZzm B;i<}.Әuɞ+Ɔ=o¤!!UP|Zj :{Mc(X.Sy#(;Tk0" &*esxWgu5(F[\@LP^kBLA3uWelE*ynի[d[& ۙ_bTŠqŷr2>MCz1JL]~x䧓Vs=>yCB!ٳ7zgzuBm\jҍ.6s vy{*K1ZZ7@+#Ml31[+\QeQMxyTY>QEt(^؃WX'OIڭ{Z|ndfNa6*v!U CƊdJQ R+q~ښ\iL9.)wL"]n(& #}\"&`ʳ 9)| (+8ϒ')N_6wg5vj*ٲ(q6f|R^":!) %Ŕҁ-D +D@RDz@s\i$ȡdR;1~2 DéɝCu +a{g9LN?̲wG?5h>]|wN7ε.dw+L(F>ϥ`v[8R6ƘHi_?Rpj_~O`pq1 i4l7okhIE î!6(90@dAY?~vRW>d.[\]w9s/zHíxg`Vkv)g5"v SB;'P'Re4~kZMt3KKfw#ruOo|On[ݏ d@#$8Aj4Uxjꀃ&u.HjhV6 _.)H;}DFH֏cRBaP5 -"tu;òbJA&Olo Ǩ|E*bEcg5-k E6F |:[wtZUiIjm%Z[J +Er!WƫN(mMJ e] @ o9"4To"q8{y__*(aXե. '8K^U'ϭʘ-XVz(W.(9E}lpV 9*s!%*4H3wM5|7'  nmy"x+%:xs$WP۬5Wnrxm<%ۣ|Gh4#V)7'9qDz3ɖhgR+cwpS(aʋe-"F(odxx<;[VJh\XQ|E+c.聆M 6BRƘ'1}L*gao :Rn["&Sr9}p탯9o)R42(UhXcHR\hΨUK2Fyb֪ J +a̡;9v}jH&@sZ$ڍ<9طׂ[΀W+2eHoDQ^o6(%Yx$:Pr/ !XWv;Rgy?mk^2NgxZ\ /~]~՗@ɲtu_0]V8kL<Qe.va/0V!~kTV3ǥv&YBb(}d=LnUH"Y#A89zJ:BStAH4Ǵ?) +x`FʕCIɨuyW?U*%cQ" AɌvJ]JqcjGTQ!md3P$OG?YDԦ!wiuhćFH vt*z'e>er @ޘR tUng"]+ yh4azLSomw2RBY=n#FB#ZdVF]%>G!CalقD5SY۹wQk|=Y7S@z+G뭰y^=꬟Ymv'k㇓݃/K z|w,WKUB g@HUHDrC{<%UMRXj/=icm +rCuFOӗ2l(:g 7hY.Q>@=}Sajx]ۄx*tUuW~k*I#+Z3}aq2kxtpֵGrmr/w3d~;qRx4kNTpM4LBhe"ڈnjIT !L2Rk4 jk+ +!IЖb6Uѐ@i9{8{)&g䖪`;ǀ|]qj2խ, +6SZ 72M"/k;`^:ˇOn7vBBYQV O>odxBk +dqdoC +VnZ], + +0[]Zov1.ǂ3Qhh + FB2h#oX綏Xw%b3ޕ8_RքЇ%uQ]Vxs*xkJ| +RP@"W@=孅`ϠsIAcBz {1}Lӈ#X‹K5ҜF)Ri2=tȃ۽ !d0g p@րyi*٪ G98.y,YYCAkdL *5cDBP[A7REے{G +r4nQLwMvlce6;oA6)9c)\w ,SThArAB#mLsݭ,N c%-f'wTAѪYvB6 n#)[dKUCQalh]f8cQB8HVvc_gv bQox{@1gtK@Pc%Xo)t)*#\ۀWցMh+) qp.j 9W\TJdrnV2Y@8<@flf5+2q 8{ISZd4iHW$ViM2%WgY)D,uA&P=snNvZ'ƕԺSE62Jߪ κ'\Č}w2%-_10JJʅ찑fYݘ\|CTݴX-SՍ46v߻]\!HyD*f2"\-˹>)De3,=Jxd|з"bK2 D*_ySR!jPҍb ;695pLohr5YchBq&jt*XK^i06`l벽 &H=j/PWZ79i }Z`Zע=/":únj &=֢oJgs`xQIrUUL'x?2(p 0RE [Z'#cjJL1p!To^bu5&)<lUh8_V@T9ܥ1,}zrw.B81v wAͭx1)Ip7[)`krj9Ծwf2FF(U!QbGKE ]4ng,:P1J{wSvMeZn#T<ԗ ۟S(mP dHvȱيʩ}3!y\T\pn)hC@O(Wń@c]I]\jj:܄7Od +$)D8QFm-:ShRP!~I5oC@`V+ +J9IfM-)!{HIC[Or3h9r{ њR,R=&s,9*I_l*2,0BW~62 d +Cu0tI㬥HZ=>>emsTƋ@J$Ҳ/sBJMbj /E̢j v>s,#->HSX! 1MP BTP౲>1F9 *a:ςZ,ЄyJPJHViV۲7+1~txgn/k- eO BΣ6c+xmO2 P-4fƅxZpQ4!40!!ն@:&%.aT!8䓳fby cg\iA>4P tI&#V +Ȑ9­-\=NtReZ;W9 +x>.&=>g֡^MNT{ϗhRFxKBc|EyTfᴶ` C*`?Q)NZhLWLh*a32£_՛~Sh +1qud"Δ7nj1FmT*Q!01n3*|@e҃T`Ba.`l`x +,Q >) `l CDpJ E  D4Z!^%.Bvv$-7vtCNoaxAQcΚc +cX'7~2C#01D䮶"?0v7flYTb ]@n>vȏ$[AqX鴯vhJ; [ּ3&%ܿPQ?z瓓Ͻlͼe2zk2*=FSJe3nLAP3Shɵ$kE- $TfZуN63Fy`6ݬ +1ck +XTK_ #ob'U6 FA!TѺ`|Qbn{+ʜ0k E.%*$d +eQDjM DMNVhޤH:(bRۼYEZ3%(SE4Y};GrtTakN%߹9uZ:67 ҠwnJ\39Ր+0o{ CX\cQpq CI'Նqy2""v.p:H3I픠0 +,Y)Jl XTnLB~vE6a,o-oj#op%; +j,@j* +@V6`QJrvIOБkhCަ ڍ3yO`wv(_n)8ͣ{oxR;*cvdwK57E2] F͍0& ZgϺ8çenKJ s@ +lT#r$+Ikb| +p(YLd͏=^K|탡 _rvhO!,*6 +zW'ݓZ2T mɉksZsFIe;b AޙR 7+l]0$t%*Se$`v,34Yjv2^)H.FvGanPr[G"i0~23.(BwhNU5^ +#VEx2Br`wKΜr6/PWٲZ&<[1\pʲB`` >9)1EL2~r ѦL)uEލ,mZg( X)>%H|f`'+Pb*.V s.^p&AcXvR@<nd]1:tkuw.(}UeNJMu!80B=d N*\T$mHJm_1E @>b dsaVmb5kwv[m;OEZشtI=%8fCH'=) @^bMΣ +*kѝm.XcDI1%ç^LϿϋL#21>„k. s egUW|Sꖸ:'o'%&Fa>Y\ fyB 7ڒ:< ;ڙHGd<}o3=bӞ` *urFlƘFzm'9TKISTC2cHz?:Ĥ!k,[;&:JGyChA a#ΘA@|HxJno͂RRؽ>[޻|92w &P|c+IB ٠ "S-b\IM2c|c;'mela%wqa5noa A0交+kNmV4P G$ 4S%nU$B]Tĸx0t?Wg9"@Vnz(}Aմjx;JoQ8\AJ4Dr;z|Ȃ +' h̑fb6|&+@kK!=Tj ."wd2fFd Lu->-;yD83-<7;e)Kq'+®r3*[%A dzZ} Щ$1PVzP +b#ɧْLJ-SJmx9T{{ y67v7E! a~r f;#8.%[Y!U2l%hRifF(}IVj@I~EiodR LndK=qo' ӟutq F$\ DGgP0 2p\ĶS"CŝZp QxuV?"VE@^dɤb""WcLp$49<VG5g:w +Fsߌo8k#]RIoA+JB}Ѷ"Vsv'MIrhܣQN^_N΢6޺?Pyø)|HA*Rn~M_fpSZVDϒBQ62-gV,R!7ڑ:Mb\f9@d@j pzf Bii2Jwwgn0Y8:y.HŊo2&,9?O h\hħcZj{U¥O+|4v*bL7ێȲ~@XZ*n֕ U,V "#hbȋDr=Eoz'sIG2#E2pyϿ?=B?~y)OWuuw"ձ_p;? QA/D0'Yړ/?~᫗{ Ze"s,g>DY&22}Ldne"s,g>DY&22}Ldne"s,g>DY&22}Ldne"s,g>DY&22}Ldne"s,g>DY&22}Ldne"s,g>DY&22}Ldne"s,g>>gy'ޞ|O|IFೃwyÛۏnϯNo~^^@Ց\^+WrίbwrA2|aӺYoQ +uK\#ڶWm=5]׶k/u骦ы&;Vᄋ/.ɺXG7/_{_L?=8ڿ']?Y`S^weX7߾]Ⱦޜ8{v~f}On۟s_o>x?_ɏW oqDt%aTWOdlvFO)r_;jζsy>tE\tE\tEtG>8CQvU$TfP^>h)rTtO-eE6kׯݓӗ/^^=z(`3sDz“ד_Od{}OX߾d3ܿsoYˋӛz~}~o7޽ش$^ܞ$|[GxylcmYKsO{v}q}֬P +?iz9=wBBgE϶ oa 0eƎTvvܓ(.۱UGxIG#u;;}#;~yѾKoN Mؚ[|\z(vzs~r}q*nmrFxC},w̟Nϟln1/N_gYXv;0%ygRxO5VrD]ޒ7% +<:xt^mkl~C';Df_e_t{>`p9: MT-;h{d{==OfQ[.u[h|iڃx>gi3ڌ&9k݇_#`\9Ev{QfO@t:8{u=*LTm_gWW.:;/$7.\.Hcu^V}Wi틢g'%3d*|5Θ߶w /m:0ӷ^oOׯl_G{i|Z-{HxZn/:٧ۇ67n9'?l?{0bp݋{ŏ?o}/ݞ;xv룋J,noӛ}Jlaq{LN/wq>6$5lf\9E;{a3KC7}%p8Pg~|x3[+I8sgѾJ{8Ö̜&ZΜ-3198͜=g/tWvO[1b;-Jg/8w dG,nVp%=ߴp}7(ϳз[з }WзoX u[H~B-Bݶnݜm=_W^p!z!ZQYZu_XqЇ/Z_|qq7%)1>4?Yjy 휖Z.r~HZ.K-;'Wm ]G;⎻-Nk5{^l2A[aREmٹ\DU):e~C}IeNф;g͜omgחϯ__i8Ns?{wޜ>\nvmm5:6=!s۟lc9f_339/GX?hk,7^;w+Yϋy?xLqh[};P˛"?ޭyip|ӗ/W"_mO&^_\\:Jysϱ3ri1Lx?=%`zOCw?Ű'E]*ẏ.ƜŘscbY91gF޳1'nԘ-;,Ɯy벋11EyhqI3L=fi7Ћnx_Xsef^A6ؾs,8{ym/N_F[XB陳]Iܹ烩nF9胩nRAUy[Vo0Ãj'<~vǥПu.0z' wC +[ݺP2tYOdӧ/ַ87';Q}s)7+ sٜϾ,J(qK޿Gζ^XYel/?އh|L~<C9==| y 7wImͳf+o'Pmݒz{\}HKK奥[n$7חۣ / ڵoϴ,ꭋ/䏝LwOlo/wp |R$oN=ZzK>Rp~׾Jo?z;qE;"ߠW[4>rHO&=-[Gt;˽`Ӿ5c֜׸wf7.;4'b6WMH Zq5Wca"g|?73,,ta {Y认`s3sF9fzi*9csْ7C_d߶E=Ӭ:ϵv's'fU6}ːmo#dΧG룰_ʣ.FtO o0ʃ 4~]Wz0EV?^\O 'z8f(܉ۛ;tU/殕/&7wjQi4};R-?87o.?h&}{l{|h.˫/5j^Bs +!TUՋw?LɛqsM0h&:܋dAb[3%y3]@`;7ia·ꛏVV@ yk*Ϟ^zq}Շ?A/!W~_Z=_Z{ԵƯ;:Ӯ.𭭻 9ɐCb|AuT*ԝV ꨑcj[5:&TMh.x+2UgSH'h 49tuhRӃCd"Q:R]д樶/Y_YtaW^UY#5|1Qݴ5U[G!T- U۴XXVC+4Uv c|0׹x, dw2mj:ョ>#Mͬ6k4GMMW2Um2(UFbe#S{A(K'/$ӪA֬vXyoE "*Gj2|I~7t]'밵`e4F6" %T^pmJ[jw F քZM4G7ƞYS +pdw\sh0Ҷk|md" ]'x.%(1m<6`&fiieۛP{:x\+L3ti4]=@D P0DdMr L! LJSg,Dd 8U`ePHnuy%˻(Gm&[5NV5rHOlme}jK_5yc7XTrT^Lqdqd 9X,E(6F=ʁp NNl}PTP_a@ %Ч@%QdR.ȩ {'S򮩭"\0mUu?qBXgHTGPP"Wx%BA8KRlde9ֆUsou | B"3-Z%t+!ؾ+ nC-)VN,Ԁ^rh2a9A-DseIz}= Q.k9„6Ls8r^9 L"22b&"uKf$%)g!)vd<,r[ V]aX +:WF_795#7 hM[YM%RB>75$HȺ a~‹"ЎRU5 *`zEA$vdyr_c _1wJ2ybK^,$0S5,@6DK+Ev2y?`peفOZ=yDt#Бl,{s'W5m+5Wi;rk.D Arڐ!{ȂWaZ3∬,k6E YʗD%!(G٣lFۇ6ab\뺮LuO> l Zox=Vscqi&?:"{~oB P -> +-wXAE3j4"f4dE|=2-T0%S.4BͷY)CՇqA:#FXPljx +G{N*<PEkyZk/\pQtȳEы -։r%d`,w\ +YWX퇴WGMjJ\c._ZhJ9"υ|4b His 5o(Ⱦa^ˠ+vub;,PB5r{9#j&W(M1 !=l]U J@x0i_ :Jv y!rQKi8:a5ʠBBMe=<KDAz;XlA}T9cpRQ?"{L1g_ ~0R2oخ99c}FӇ&yJe[m%D尢*6FQlX1flp)e!cS$2@D_ݵ\<.S/_+!kp1c1 +8}Xniʫ!ltfILFHpt&aAZV\q}8NtG$!㠏i`(xs0$W+Z՗=ް X.{ Dj DBhmNmm+һ*/nB(reetC j0_TluvH#}`TV0SuwN8<^r@x`[y?RA.QbX82xh Plш]ɜ.3^M q"z( !ΤfnÐ2O79{T!WrLruBw,t?`z).E[,T22B) 2"Ϩ+mKH!U}]v%^J[Cu I3\ogaW =ۈOB5*YuC4n&Ŗq8M byHk&9ys ʬAFC40V&g[]S]4>R*`xT,ڌtPsC?p&K1,4Q:4:;%6#ǚWR+m*±ȓczi]O&~8ؐU1ɻbL]¾L68QbC&:;e!mv1mhID8lHWe5eFG`E@@,fB`:XN3Rlf'E?Óhh1- yM\-ܰ630bA7 @Qƾ`hpܽFX&F6GU;Qԇ#zn@iC&z5n>U8^$*=y6&1^F`XQ@"xWpz+R=]/aV xrQ3GW<H~\>:h.li +~G#})o]2 !Lk5Nv.8P;:y|ui])ӈnziug&kԦ&Ea? endstream endobj 26 0 obj <>stream +HdM%ua[ hHhH?/ۍXd2"22߷o?O|ŭʜ[=V1/mbݶ_n ϶Z-,ֶ}xw mMr,z` +1%̲}5p =LScJC/S\VgV!e㽆x2[_/<dfK!zktF8G-Y?#ˈ)9T| +sީM(-YesCM 34}g͡$ \G*4ô#DZ͒[{4f&W4bfhm# Iͩx)60KYU=5|3b'V3(| ^k vt3F-2hlK:B,mD%ZK" r>$rAw2$qJb|)>>3.ʗz)Jm|%swjyܸ7g?u1v+1:;ovq,5fIVJ6v}6J_4kI4NehO^N:*uIijkLn̬ya`n:8:Cip8rC,2ij#ax92W6ug}.$ٓ,x ^:PS',Jv* 2%Ot=5XX%ZWP +M&Ffq$cĭqY8';ˉ&595GU\j1%kHAU^b' + AnyCӜx#G)q"*oܖyIT $!!^ځ]qxH֙\>k}WZ*#$ǂuK4V/u{atTXe"䦏s*؜Vi [_|VV Jcnq*5f@ъI'7*[dz9p\UU=))eeMtSߞM|AɡNMwsNvo%d܌n![ +w/![5: +@suT]v]=JsZafPVOɊ^CՋIO +npfeTp}b)n'^wV9Py,m/El&E:?AI > +sys:QkY.^ +Bq:!ir3L+jOw7o5nQw+ى7HsC'7e:>`uS ;= j +={O~غ{_r3t/c9S?Eeuw'As (Oi#o1b|ҖzeYߛL.5JXx3ͥ]s)UV iTL'+2aD2d +.7: +wK÷USMo1bՋM4y$9sՆ nH䞣2lHPߕ${y9UguGnB[ud]8(t=["wJj%jdw;*N \(z>|t(ǻކnW-$;˪Glw%ySJWc{?}F] endstream endobj 27 0 obj <>stream +8;W:kM\3i\#Xd:cqp3,?ai,>e#TU=aeg^>E$V[QmLC>'u(CZNe<9-R-=Ke@8n+oPe +EK,0>]31`]'#.#9(+?TEbUCt=?&Vsco#_oG;2M"]$HshMnK)9H2JO`_N?g/c*Tri1 +M'J\=l]'V>('IXP7,^.^'fu"Ha/O1b_J'W[o^C)dF_Q0FF*N)f +X.j[6Z=H]_rI1aok678&_k-kAf-fpU1,\-K=3m3pmcX5lX4DI_KY75!GAf!:RHI7c +]+-m(?U>![?!jLYmsa[S>E_saSdLB^&nY.sBqEWn4P'k&4Fb`(ne>+cK3H\`0Tu+T +m:.'>D\bJ9\;eYJg\-[.<.>b2!+;Wfb5~> endstream endobj 24 0 obj <>stream +HdI%GDqU5+A -tDC$3cDtH~a?߷_P˖Bi{c+ #SG*}K%쭧}|駟77=fqϡQƴ1z=H}ldc1MŰ28=W3=uia7 }Hyoq=E~,-nw-{mcbkJ+y/,y̳=b,<&G&QLz[P<FcJ.hYѮQY UAju+Ŀ{Dٗp),sU茽g2G=mf@|!^*W{l^BpV;*Irݸ`NXrYP$DHDgל{qZɏ_ st_,,Z3.%'LaӡT'azT +X +AUܫ؟ W@_393p Z0q+ r`N _1sҩjHkY6p-S.?O|ײg+^x7R[;dB7f7j&6mINSkF؛]$IF)?Mj80}әdEx|,qd,8)җa"SKhJ0ɷ(ZYMGX9g{cfuv= +C^!äuҥn|\$,UZa x+<@1!@Hކ + r3g$Qc{J@3PP%oP^z؝^`%ZB-%;*+] cF?JweOO|H$%q qiVqVeOBɗE֯\(|*lURd[ ?`lA#MTۓ<) (RѺ%a,Iba4K9,e\lrth8MXZ,7:IM$8\lF Vy5b}n7t?-\.q,*֓.|-Vb'npeCS\*1%nr%(2H oO\DE tj<9W,.0ک2dMNBӥf(.&୶$$ {>?XorӢOQ׵ϱ§Hw|ixp<>r'@` GwKN{i:,U'@Yr"oN`zP r +>eĩYCշP|M| 3ih&15bG w寢F2 ͳ2JJ.YDXw^Y:Zt<f& +CUHғMCڜ#$"83xaŵ30-n\ՠ -k@b`)r5,VƃY&}u[)7XHV*ԀQ +l(t(T *|%~|icJÎUʘ>mP &@Z]+-M%ًwRo_LeS.-=?TYָRo鑜0Isߕ$p» < Z#/LWj1Vj2p.#X4y'kH#5-*P'\cUGQ)#iY&N[I< z]Uc*x1~g JQ욓MBǜr5O4q +eH1h#W1@*5Ja~d +jX(G]'6+ B>i +4U5nTt#׻hjʵBtkTN]gHPJ3$k}, 5'fçv)ش)@UٴYP4~vS;v0&87(m1x.7}0' +/GfGar\L%> +UcFpe=Y<I}qMY#C|,iQj)~K,֙P4Lp]9V^4 Pܺj]B>Ud`a0#"fȊZTxvKY(@Z'|'W bJbnlp;™p'iW8,8a¥N |}Z7d<-{HgkșA Xӏ Xj IPl=S']AĹTEBu6FӴYLȎWd\M, pK45&ŚZJ8dvMA?64͓iqZ<-Kb4^x>kG<ӳ$DŽ0뉐iln&V#Km#tE5hTX,cS۹ +ױ*\Z׺*$\c3 )8*zJZGFnP6jLh(ܻu%PI ;+ĥյc5@hKd>4%׿d9v; Dsa=?q ?u AVd?M)G>r)U_Y1RCDJ)aiqU<"Cp0I-{MN<ё_6氤˒lc65-zb=6o`o44ޅ X"H0"bhk $Z!5Ȳ!<љ*/,^WU>@.pRT,oOX_!{ܚ\򱯡l0}}nL7u<,-pᯝ +ή0O-qF]#Qk7f + %=Ca ]@Q~// +nrGeтc|X3tJ>B%Wia*2@F8/z/r15-ӷO]<+bs6]IhPY'Hjv h^x/byz/,0߲,xU`,'Snґ߃`$4$K_YQo[ I^/QjP-ڒH#cj&nvXJMnm%p0 +COSU_8b` X v)S6yb؏w ?3uwȑuOJ*t""Сigc p +&k /UT,|DÓe^6f橉=VH& 5WeeRbg"Y[|[H0j$aw`"A9˜OB{jUl]pNŗ&95Ot (n1b@0>Ue8fN}rTi>2F<.VD,<5L*l=$9\Sh=kaa11[zuőrg/z*lC5/gKȑB]xa0$nu+ +Wi)ܑr&-󽢜Jy6UZ_}A"'uy=]Xޘb[F\M5qq^,cc%[^e d^W t^1& G1YgX}4>ggZ%üf9_&3iCm((M8VG` +%I#, l8GpIB.Ej7 +R>ER$.0L!1"D-NjJɰ` 4FG1LWOU3j5h2PbPU=(!x^ÎABx-ױ{R)pemOiVGҧMO.z 꺺4@i, +aK.Q\\95;W>Ǣ&k +ŗ| hݎͤrK.SA 04}xfaiϧ{$TUS3泊 'XU۴-`x&R(T4lZ"F0aЪf2KXS DX<@6_<<ƕ@x5u~ +T'xtЄ̔a$QPd(< @ZbK'0Ħ"OsoXbg`,.5'u2ǎ\IUp|) }+ wsVY0?wEmMdnQuuܰ(ɦv-ǹg7A.;JlL4eR<Мx6-Zm-Tejn֯,x"g8'0[{|{4.4^sl)&f33tt>xh~,=M][9]GE +g}MW Kgb +qJ})6_rgc + gɺu"?oJDEMu~M8 NZ1N+_ 9FJcK+|:œ(}}9s6o>Α߯At]>8UMݥyHv  ?7W$y<#*=6=5 + ~aSo2|h\=ⶮRX+'}\k +p_tjU]o\fGF or9qWf40kD<{ƯiBK+V YFiwa>,w8L]g0Ӵ]icx˰]ſ~7XX1M>Fx0%=N1y@$R,BY}UrFLj & j8R?3$U K4=44cv͉xmI1Hޙ*Xz4K$*pw@VMjM(vP|r0]o>+2y s#Ǫ11nS9/~'E<\! +;bgP<ڴ FwH`uˆwnRdܡQo Б4Ú]q4 xy\E5BH+AO0A]yS6l4ʆ>9/+|Cxеp8Wƨ1(F_MF4IIvߦFsN*FmG&̴h "\nц69><@F86'*'nB'ClVv"Ҁw%0ѐ1]FC=;† Tv`q;Ls,N}jk +j@?7oRXbBxٔxhb~\kLTY!hҌbX͵cfw El|ȇ`!} 0V{ =0N0rƿylRU#֝qǡw@U) [viS6V*E}jfIpuRa +aWǶ3, QB7!w> +|C6g2M)A򟶙Dw?;Ha1pk64Lܢ A?3;F(Jk[f(hljol3"t.*xugsQ+}ni=M;3&N3dҮ<+=KLŷRFiCs!c4 +=̰qyN%HW>QCܜВ"HL;gr1HJsNklQb3IPOYarPFG[}$u?oau']Y#JÞZfwaЙ^'ba1]Gsl\U;{zo+{vkB}tfP)?2y"UcÒ>^%wt뷶4m(s}_+)ߡ^n))lO-nȜil<2_'T9+Y 9ưA F/RXu @=*Tس@UHPJ&T]?+sD^+4WrMiL3RDI\!:o|"YPC0.2&g>p&` +4>]k:TF^J| >Pb%e l*0y PMLKc3[:J6n,̴2–m2]!skc coʊBM!DЦfsG fB/y 2[ޕ>+y0{i+R6n]i<]AsoI}[.tOiZٲ2z,i\pK9[\|:e8s/GA_/NV39cG:TݘB)NC"f}D汽^ܪ^ں36zk_O@JdzjgߍB+999cSц^e܇}V s(H : WH=v +_en"P08*o vhUldoAbyWgi.:_Vԏc&:ar02ד0-f.yH˦*M`MF>aA|*'QWGN׃F(^U-d}Oq ΫdԜ^ nd~yo1o0B.6 :TZ3]4IR#IMgUQE0AlTtWc ZfZ GV^;0fqfNAOE:oA @QdaR2 RM>k7 +rU>VnF:{,BH޺ +|tD8Sak2ch7ɩ=lN/WCe޴jTL)A]Jݔ0q+!B܅wz(Ķ%e 0HJ} u6qfeOB,7D^)aFZE1HR$ ?%Ɋ&`jOn֠JVHin QT顠?ؽ,V*`VL'ޅliz=a~(qQbZ%þq +r ėB!XhsE'E23.9,>"r`lU(P/tõlef0ؒOá[sNjM8MpŔ۴NףySI/T2ɇ)$8G\mJev% kʈIQs` +W Ygޏ&S欄-5P5B!groӤ1QoKf/Y&K6%ݵgS v1SP^Mro«ꋵ JYVTH;g\+7mϮE[:2iK6k[AHKN.ҢߔU+.-/fY.Lz)ha̘79)\{Y>E^ P_pVG+BfdѴV^]lпn#Y-/I&3F./ŗo)ƥ{S~3G +a>mq:<2F]-H>vxUyVC)YDuI0MXѬ/ؽ^ILSIBG)$UiG!u B85^>,v>o7mt%Rf/exP&/0[nc{|'3n1 QHYLr +!(//O "/i,&f" +w-X>;ܷM-qbu %SJc+_ No݃w.ܝƄIn%*XA(1Ǫl]~s4F2*n(S>#Ҩ',CѭX z*4c>}90ӏ J(vr$rU_|ǟ\ endstream endobj 25 0 obj <>stream +8;Y!EM\3f[$q%Eup7K=i5T3k4RtTW!D0jQlTD^=;R!D'*B,V\=LB@/7O['bUqZCu4 +KBqAZLr+;;3s/&!C"9k?_tXsn.!1]78mNi(UL.)4j:*l#aYMn`C9c)r+@Ju'9I'9i +DVbnr5JC#9i]QL2,3F31=ddJJS&GZ@M`S)?Q.i=jeB%2%eUsGfIIAcc55O'LM`'j: +do?]E<_eGJ6j=8rh)[>GjK]e)jHU]T73Ud`Dm!"Z4tuNP&NPka/Ld%:iVA_=cU?,\ +oO`?ljN$W96kRRt;!2Y(@X4D_?g4poXt"ahYu[j:,A-A;=C!9ZDHs^2RCuZs9t8Hj +aul9'Q)6PtgGEkjS,\oB]'s.+j@dZr>;Q61OrnJ^a[uL>[Ft/t6q=3IT!&.p@O3S;~> endstream endobj 22 0 obj <>stream +Hd͎e ) \m= 2 <@c:`ՑHVH}?o?_q+i2s},ĶfM?F_oRk>~ӏ;6arYL!,]C.mcH}lfc)4f12ZȵCw!ec^COp7"0#gZ2E_bdl)$+>4;W~_+QKh֏yA{Jsn͡jXZH34:gכFCVp=D qLI~0tjZ4U3叢n)/e^Ԩl殘6 6چCLRog0I6NcPӌ/ +_Ģ% sb%W5 28!>`;a7eE-1+b(aNǻЪ]h*X/+9N>/+Wڧ`Lؔc +d'cq,K0[!hcV?FN.hEX7]+wNo bAֽ̞l"_iZv94 WjkܙLRD9K2jbüz0PJOWKe&y<^JhWGXn(5 +IIi*,)<悕UF61C3k:A 錅!\~(.-;D x+i]< +r,E!QI9}3I8 [륅}1k)!8K.DJ>Tr}TA~ `W]-mgdr$ zbmB\=U$OBɘ=/_yRw([Lʝ; 5r(J3I-Мz "JHJZWPANlN+iKk.XqLK"]h&WK&jfA=8Fp(u>` 9VYe|\ .vCi7+h=wV]DK[wX)u;{DqqF%^{ߋuiXcu$GK6L^\a`NWMʽ(t6)˒*#Qc.p,2f?('ɟ\,o7B sh"ՇإepߞL'}VINN w{Nvod܌o!A[Jv/A[5=xBʝ׮uex=iӪ3kk_=X@q,I٥-^ &dz +=T,%pGs) +u7KQH}{='0P{:AhZ\f+`]'0j*˅QJm=az C/d8V E>ճbFݥdGjݸu& + fu<9v]T5![ SJ=B{O{cr4צcйSAD!e5w'B0= +S9/K&NɧvRΥKk$?Qt$~hh2K(n?{4о>@Jjf(NN$;T!"'̪f>%: D,QdAtƴKoUʙn;G@jr-woݾs Mz+g<  컲~/=7=Gj鬌<2\:X=*΋YF!gDf+w\$Ί>$ZٝRqGM gؠj&籠gf嘉jQ2J@R"A륤r5Ox?/ endstream endobj 23 0 obj <>stream +8;W:jgD,>p$q$BK=,&0aH(F(h/6P^T-O0o"Y%>Y@afR\edrS4?DVWU50NHG,>A, +!WC1incI]gT'_I=jj586c\q.Jc@(bQX('I:^^;+[7TATF+),;=?JC`p;jBoF$Dc3O +,A-s2;N*;EDI0%DT(]A]F*0\m4FtrA8[jr']7_AY#P"cJ:.Q=3c*CQ0s+(.VnLD8F>f8kbZYM<_Kr_ +CQSO26 endstream endobj 20 0 obj <>stream +HdK$ Dy@JB !̦G3e`ziF#˿~~a^VjC-[ +}}Z?^a/3n};lc'-TJ[OiK?zc}c%`L{`l?^6=io-űj%)GT{{o"}ؼƗe 8YҞz YZ,?{ԲOCj.o)yk kީ1,mOe{Kn' =#b\LIm8-:8xb]Haju+@WP٘)0sUT~d NsV[hfPjK[s-h=tJP8"_X+K0 M2Dz'KC&p(;e#Z9,|dΙ>ERli_ޏ'if§HSxʗzGNk ~+$oVR ~ $'l7bW@l7"ccTic|Z:yBYv { z-pElgc[r2+CKŰԶ%5N:-8<*ѷoE;XXHt%ueXi귦 &)Ebl.dyUH١x5kNM܇X +a\r7,-' o >,a`@"oJ0ȱtX!NfKfn$nGc-઄]RbCe8ԐXǒO1u}a%`8aBljj3_p9QmB`Α.H#[;9sF;W**Oq ^NJ&aЉړ4ѩu H +4u%K DBM5sZ,!KBs,L˔^}3yUV ~ rיhkwQ +(XThr%U\>HrDrή\`.K$ `;pJ +uq0<{JP'Sh-}ЖK*o@UAu+~0>gh(|Vϵ‡17B.y޳_H\O嚥~?|~+%"iG* Yi4ku fHR_Emژ5zg%H5Jٓ%B߫ctGݥBPѢ|)W<5GU*B͙Sz9WJ=B%w~EWi+AD逸_>VN #LB b t}%4UWܸteS&254`9ڒgJgeJ N%cLk͙:;\JUgh0gQtR9"yVNjRn;*.OY >eMPwXӣ&B@B=)"=횔T =oqJNTkmd+\U)6#y@v+5ru`sMwTpZ!xt#}w}{EeT98B.'`n[6vMf`6HRV*K0t _݄M>z6c2cY,j+dmL3t)x">/z4)A& !BsM:ޒ۠{g +ދ$Qk鸦xn'߿&IG ?۝C0+IیB4K}9PPhҞ.Q4]K]tik206d (rGp»JYQ?µNbA)6 (&d;g@g)vg!$WPzPs燶2w_=41*nNY -rJw 'qGyjV:QJ:WUWgL !]oq )< +vT9i U#-A^Y[5H]JةxGP`R9t{?4W?eќ{sڛ(Q0~fH%?P Hg6=ޱ[NyjwEDpJ IHE̩[u?vRNOϴk9purL'7;&r!6>/%Gٔ +T{ YRDL %&;, {l=r*ʁpQI4}MNH0%پc(p52n Gء/qJ8!X{ {8 '$NW@fE!JW@sƦW,?NK,Ok`0V~"b|itjvnV%zT5Q +S-5fLnera+dfh10ho3%$A]gEm^P8 d#P.Gyp+Ҧ ?gl,ک <TU HeT>)l;nWD[L '}>H|@ˆf3F}e{{*ȧP8t|;0̛N_f|e[Q˧ڱ`PT1,[VaHMO]<+be)fjIhLk v 1/{{1~xvNt܊e0$Tu{ݢґ߭;`,4$KlwDIV1 ׵JO!?y"!LTk&Gjf,ek>`.VD +B5Ʌ;§jlo/ R2ehI'69|lE~fxp*(~d +t^:Lz6z +\A@&¦Pk!NgyE3OL TD}jLHǶFo0 +j1*uIq,wr90/g1㙲-{DuަNPQ}ZO5^Ŵ[Rz'E`@}D[혙ptr4_y +Gin>ƌ# ~ l5L*lAs' ~}jnqX@ ^l#![|DxB_QkCIw`sg9،8i Lj5#uhP\9E1ޏ.h4ת=ȑFG5F nJS8Zl +[Ȟ[ +l€wC}&S鏈}F߱LxL.Om۳cvMfmj97ӊ%C)c7ϗDZD(B5̅Hp}l| ) NY(gpܼF\A'&l0 3=>p!d©heiYgV4S +E(JG -U}TAhUR@U&!¾TB>jZVx&n7&'ߧ8TZ߾bt}tG=sIڥ95Oˉ/({"Ն5h6"(If-W5D^tHD0.ݼyZU`R̂ 7.S1T̺4}eExˀWˢѣUpdUY+-lШհz@a7YND ;2١6͒0 5ZqAT & e8 i]S+GS5AG1slZ>J͸M$A%d[N3/D_].=f[ +*I\{px<M2h +E;HUgc v /ԖQ}JrAvi ߬Hhs؝ ?1$ 4 seMD?\wLܢNbFYeFvݙy y(/MO)1T.e/2c|t- =4Wy [>քMx'2yrn$c>3]5ߑ{׿*U )]i}]U= cg,g2'C =Ea^L@ GR#l){#^Wq𖾤ҕqHSDd/}a7\R,fwIle/l]yJ6u>uLE $ 4g|a+a-R_9Mγz,?9c}S +Ԡ!q1|Ў5ȷ(okh%ucK)ɱFeԌ8L.h G#M./9f/mjCj}p6bp:klO+MU=5CxՂUrխKhifTA5Z|^J۸uSJe6䆂6k\܈nU%{3͗fƺ.ͦ4]`s.u +Hг8 +*t2q$rG͂BJ5rtPK;J?O21u%l,b G&[$W7GS[ic,D#PgwSr@j֜ot!fU^&Z"ePM̷VuŲV(at`?N8L T2 :qҍc]c|qYXx;nO'l #ďB;_y67ZVD$Ӡ0 b+L~} +2>Q7W8JU]XHqGbyZ!o`,3JEIbq"6xꐖ8_p3 < ck%]{ASNZX;-Ι,%dkюh#p[6c/=I:}MLA f_mrj`ߟӈrHK#uY{hisƓxE|:(geg8.ZFRXpAn]Fyn +.͋bp78CDثȑg +9['1 䔄^ wyٞ΢9׺^:J4Kak#}iR].3eHj(%ZHS hrcs ^"j9GfsZDtTA"C9s<ګ޾zؚǗN61i`u*}`7X3M.C#L= <xwmT6-gĝ>re~1gl틖, %_EeSzלiKBdխkh;m]bP$Ayp9pAʹ X;BSQXqNk; .{K'? F# 56Ʊj?N]twjCy:7c}!5r b'ք/ͿyʵS+Tq#v5hVx@[oN=Q2wXK$3IMSD{$ >e侳J~L=0nR{֐Ȕ=6_O5Z͟JѠBMRQGzvkLwj)bfm(WD ō qjOv',7sƅHG&ڪbJZBү]BpktҶH:m8rE` +Bo^Ԇ}[7.CK@c6*JIl/ {u2_#6g ݛRv;@?7fAqlhڵ)>ȭf+ؔ5ɰ zy5w}iN_%/jОDu~YG.Z@kİW.mU5-v妛dWڮCt=dk + G~?#Zbq QT2I{Ċ_+NY *Pbݼy B3iH،UHfH~P8ۙf~dFDi529sz=-GH `#W(1.ZB2 +]1XPKdX6b~V1pŌ)Z]-o]NxZUn+AL Lg᳂7oex{ƴ?`o+HVXQ`d!8V  d]R:w"Xak1$ro< 79_$jP^KAJ9ZV:0]q$}he@4 j_Bal}p-3{H+WVQZ:;/) -YwPp)8w%)CIi ztcNX %¬ %b.t/K0:G hfȓ| +r6|[zֈ2˘aܥJ^KOku=wHO:WtRÍv|Dɢt$UB6 GHB.&-vk +b{7 CHRϭ 8wxh/t8*x o|t- +dZ+/|]7>)yv7@,5|+iklhؑ 3C+`ZY:1g:oE6R6&Fp;A.,^֏;ݥ`h|׹tR0d%UQAkIS35!<NgVs*|X >stream +8;Y!D=V?B1$q)bl(Pa`cbB4#qFp,3f7L.*L_@em_OkEncr_I=Z[e:5%S`G(Rd88?c +IG'bI&RDS$)MCX!mBg2A"H8KYRIru.=5'4l:^*Y4aRpuXa4_J&HLDmn;A5hFC"M@7 +CI^[FK[p?rp5b3N^=dh34c=s:Gs,bF2IC5`Ahpa)@/j"%ofd9Xn`$`g)YB>#UXS[[.On1_2 +D6<'C#5MA= endstream endobj 18 0 obj <>stream +Hd͎e ) \m= 2 <@c:`(VH}?o?_q+i2s},/^߸O¬m)`K?xcho&{Zȱh(bJ>̲}56a& K7)ck!WC]bH٘c*lúЛk=Re('-dk>ZivVG-Y?+ˊ۔jgߚCjXZH-̗OfhL䈳b!+d ii+ m%%N<^5c )L@8V1S`fUʏ4gŴY6͠돗܏y#h)ʭg0"Inx8+Nb7PE[qXU,$/ڽ3!zJ+bN)BNtwU҈UA;._Vp=}Ji[ ҢLa>-L7Nk }+6YiU XPq}}Yglbb@Wst.Ȇ;JƂ؍aX;8wugp*ۅ1xWqtUjkޙ㒛LVDb :8yva$5 Mx< +8 +I.PLb}T"^&Vǯy+sJlb$fgtAө@8AЮl^j#Yp9E6d!0+Ξ+\T!̞E֯D<dJ(u M$R}Os <H+֕+TjS'I?cx1{um%+.iiijrTh"7MV2;!&dSZბl2 I\'r=W)qYW]DCt <6hWŊMeHpc# E\5u&/yo*^vH7%PP\(z$(ÄEtU%9ZJgҾ,UV rUskW1 +V4Gy?IB录Pgszc*J/$+tvM$Ptl"q0}߁WҨI.Tx>Q .=xKk|.5?4[i|%44i \-ubOvW*$ʬryVTG)Ktmow髶$t/y +U$rTELɩT}МMHLȫ+K<#EFjua=vqFEF2aĹ(Tw 'tj3bYU9f6Yݤ~Fm+}'bq>,.K +%ʪOz%('TƓOlRC;RܪZ ] 7QV?*;`bzc@9{Jʳq#Aa~W~w_gis$'j2V +">stream +8;Xp,I2%Wl;(r>H_'g-(UL:;.J,fZOFNR>A~> endstream endobj 14 0 obj <>stream +HdM$ u@Hc+ /|13s_WΗ,D1A_xV7Kc>-ߟ~ǿ_?xM[Ok>̶796=Vy/QFkXuzԾ1ܗ#&[N {粗v+imtG/JWb+{|Y'˱ųn3d huyj.nY, mey[sYn-—OqeA!r{l(24EEZƽ N+{Za.0}ͶU T6&` +G@sYӜl{}JݱLЬƭמ^RW;NŊ-ETqbXʀ[OʐKޅ|E>T;WFsJqLw{{{7A:*$e' ׼1Y[cIedAT2#s\3(ƼjW%@`A]H5Nd؊]QoϷM"oE‘Jg@ay`zZ:w}lu1=^85He*BRyM!+R*}7o&)77OadӵػИQE0\Ir%=\KU JKkd,VVǯ{ܔ%8~ +r64y)MާtXr:J7]={O +ԪXT}p +C8ފp&!)2M3eR4vw( r#[ GP+DPBxBq!ε:[=t0v .h2ڍM#[ٸ3[P,{9rU_!zJNQiNS`M ֈ?DZU\$2 ,vW%r}0էo&_UT~EF<(U&,h~tJ޿p{\U +]d.K$O8]x%Hq=\Be<u ;? fjZ?x+'qA<{:KXSN7ʓâҜm#"zXIZ*TngCG=[f呷/<0ʦUAvJ6=n'*[RINޒB,TI.4`3 }/\0(̵F}eqɔ8fAamVNdȚbF+f*Vv "Ԓyp(4ޜ}ϹƧ'>4xp| +~Rʟ#O8zxkr45>iZud[F^5ڻ !%W$SVmޥak=4f$WT3-I!OG f%ubg*N7$;1<+CT|D|km_#j }U'>`N !WA{IUE\jNmiݩiȫ!q:s]X.Ѡ͉ EiG!6S ֈB/gI\Wuq4h \+FNq>,J +%+UGƀJjJP(ʼ$ @HVF Q:蘦KqkjiSMpB >E.hkJTp m0njwb"#ZS31yԪ~64}$(lw'Idzgv^kEݙ`PW(af5_Gx hpim=KE \Szg}y +D:kbz~ʞ6C'ķԳTib ?9a.ŤX\KQ,cl((xZ.Ģ&ϼC݇EIT i9׍i򀢌].V#+cPx p А +Fvmf .?<Z3 /Xf4C\0U<%mPJHYEH. [wCBNu~ .g̱$9r )9DV'Cg$z1˧"5Ahcݚ\rK`^&fknnx$9Y04=|kaZᷝ +ry_σ+Q`UÍ'vq?F7,$d6v+j/rj uya{ lwyr9iƐܻ Mh  arhS:Pm0ִv < QJ,+$&SҠ-31{Q=սf^ Ued$.ImNZ`sඍ*pA"IfT!3ы +yVn`NUT>Wɱ` t%  S56 +`*V:|9SL0{M+ WśZ &-93Lc%{3%\gBqRw<,dtlqԇޜD$$+ڦRg0یE8~]\A8a{PӶgL YV۾y-F +׺A:X,:)CׯuP0xb[o(wBlO#z(^}ZsH|e35w Xni+N + uD5#7>@R(!R#F iPgU r.#P<:Ш++[Sfy7ȢqDI󷐼ǗDYy2DsLmؚO$՚hg9 w%ix9 /)kؾɣF`+vGΦʹU `102GZCAA"wu]Q `y $'[5\#0=_ZM$ʹI8nFT&&LI08ƎxEz*c+ +X_XQ3TA)jFYUP>uK<A$"v s->m*OT_Z7ZL>Qrs!^ȿk2Ysr}FXWl51B"P"NaUZu N.KXb˩_Qv A l(Gf]:=8E>cujW?* 41>MM2Y7hْc$4AcE^QeȪVZx1M{5^;Pa5ȴi9D +oáUecLKxATۜpC$@nZ*P9sc9nGy<T(!ڲuJva>WI:mmG?#݊5<QU;Aَ)Ss‹6F䵌|*s"BT9AviOG f,dpL>Y DŽaPj˭}kuRp +ΪO-ڽJΤy9KsD&RO-ڑ(V?>qQ,j)3=X0yorI|'ݻ]{ڧW>wK~&Y`uK%ƛcc4Tdڭc {<{MR#l{#]W¤^Drl8hvت]~ycJhT<%ב"ֱSU%̱ǚMRI~v\ h>&4ZFTd%vدW퀼īPHk5ަEc;ȷ 4ydRk$X]9H()1 % +W{)2ϧَj6O=$F2T]nO}eH|mSoR[&j"%&n[[gMGjOsO^Plb2A$Rs VNSדnLVMM5~~l  *!mv\>hb,(a)#H;1r A0y~6.qν +ouĞZOM"&)Z <&QxxϳDžx/=PI|,HSOpӹ)n1̽wh:<͹IZH+FׁD }2KhGvF<g@Lǁ -l"J#'^iatWɹr?cNXzmszJ&PLLk7t\ܩ7Gk.4R;1~61t0WDLKGs)PXc.Ԋi|cLTtv Spŵ^Ha{(}|ɪ=80BfgIf`0=# `cn"V8J*}KołRQ=3׀/cKP{7jto{x}_BlcF$̭~쾘,Y 1F`Y>sa)tl:[Joo}}s =#"z&uTay~J0Dn |/ZpW!Kr#j=A9J,j wpH=]E !2(cT,-ך;YYr(q7z&@;y}%B=k}Rp(V51C3f'07q̳?ɌAw; ]ef5=JS7Vy70/<(uA#BXggě"mj8N㐐g}մD/{՝$[jF-H7E]*؅vNJ 9Ǻx ^lx8d(dL X':C c>H~XW}Bo.3>r |I f5uq +!NlbU;L|BHђjaFj8;a/<ѹV0yzeZT3ɸ6j4o5Pd`&'sQ( >Z=|#pwGʱll/xM4kBJ +ߐN6#_WlaO6z0dG"%pSR;EKřg`)Ber8waE܎qӨ;aID#` @c;;Θ0J5X0SGšl#!ٞ׉A]y*[PLjyLs`x/-jK5K$Zkx@gbxo5K+Jր8KtSBMm8/C0uI?_^NWXe~0p] +aI؀()_Tc^k3f tWګ_J4 +BԲ^;n4mŇQF|[0O +bT+$%iœጯgloP!C;gG(x,;?VzRSbzG$Bk>mJAZ2*c89: +1ܩFn?L9;~`˶[Xdžx *W?Uю=V`7{v[9ٷA6zT /\iM#}xh{U9NaJ)ssO +wux7iET%n`xd}P qƊ$v2,[(g B 7e)Ҭ۽x)&%Q-' 5 bZ>"wa_{)FÚD9bؼGUjR~"`6:9؋_Cj^"w;VG5Ċ|&%BW"~VjUKݝhGG8Q`&( Y?75CZ WWIN;/R`X%+XLD13$U͂*|ЮtWuDx%]}["!`,_XJ>~V~+O~1[cO2jsŒ;|_KPY Y7[( GF.2gyPꞜҎl5zl62FY0t.$;kj!qÓ)]r@el9+s= Je9/F~|oErg{V/E ZrܒҶ]-c̱=8θ+SZzLtP)TޡlD +#OXhD1sG,j^i{{`6֕p8%Ig߿!!:t,hMލ B'B@!qs/cSѦ\u>+:vmIҏA)N!l~.Amr ЊuB)QnI̭<ĽW._xXUv❾5Acgo.{Z:u;GC}W3+dM.~"=pXiRqPE5O@F\c|Ϭ1#^ WY͕t,/~V=]7Vvԫtp'pi{fƟfuF,dkk~s0u(R" 崕ʢ:pAy| ]*'ܑ4)Ё*GS@op$Fcj=P5LpTI㷱=QI=঴ߓx=s®Z%נ"\0<31hs%˹DcP|Eջ}R×[vR9B]/zYcɤ,앴i'RY^>EAd3YzQlc]j14U `-]Ț㺱fDWs#;ѯ`QVCQbo偱t9e};y1^ eLjx#[n&& khP}ɍ[gv%!Fޓ[h"\LZetA)_I]IrUnTs`B-^AO|r*uU꓂ +ju(-2T_̪GfzX\}PC 3=*V8ya |Plr3ya j*B1R'EtC!}v(݂f0'T}Uh:f6FQ4#}$uw.%eUR,;[3ܳ1K)+!EZ{sbN1fX&shޅji&L%V,7!(r\ 5bL2e8nwlRlHz=ޢ}ҹ"{<ְK#'N#%:S#'#CN@ݡC6)["GqEOP,JJʦm% > ,JsKO~Y2AQ\S&Y{̤t,ɂGg P?嚨~!湒q~t~TAa|~i z^ejZ_ZwWTPϸVĽw-RI\2guۼm9&͢-Y]E!FVܜ mou1zf? x`•M/UAvB%,9{8=0yQB-h/\$ ޸-70pypm`PZs޵7. &k!Cהnd8B,4]O9o&SK&Oɗyk/p46'78W u_{Yn|NفćR] :؎O7[ PW&|h5FlFa6B0[y_Llgxz4_,/w=KrbhvN +rК؉'B!'r\0(K.oڴ}-V}zK'Sv +:*hw!J1$̩|aC_L@BqKteWaI߿p ^ endstream endobj 17 0 obj <>stream +8;Z]L0`_7S!5bE.$!5._?9eMkn2C@P!##eA!r~> endstream endobj 12 0 obj [11 0 R] endobj 52 0 obj <> endobj xref +0 53 +0000000000 65535 f +0000000016 00000 n +0000000147 00000 n +0000015336 00000 n +0000000000 00000 f +0000015425 00000 n +0000015803 00000 n +0000016177 00000 n +0000016555 00000 n +0000016929 00000 n +0000017307 00000 n +0000023367 00000 n +0000710627 00000 n +0000017682 00000 n +0000699897 00000 n +0000023666 00000 n +0000023553 00000 n +0000710447 00000 n +0000697578 00000 n +0000699720 00000 n +0000686442 00000 n +0000697003 00000 n +0000683766 00000 n +0000685910 00000 n +0000672680 00000 n +0000683227 00000 n +0000670029 00000 n +0000672175 00000 n +0000018080 00000 n +0000022715 00000 n +0000020721 00000 n +0000022154 00000 n +0000022202 00000 n +0000022861 00000 n +0000023003 00000 n +0000023123 00000 n +0000023247 00000 n +0000023437 00000 n +0000023468 00000 n +0000023740 00000 n +0000024148 00000 n +0000025695 00000 n +0000028934 00000 n +0000094522 00000 n +0000145325 00000 n +0000210913 00000 n +0000276501 00000 n +0000342089 00000 n +0000407677 00000 n +0000473265 00000 n +0000538853 00000 n +0000604441 00000 n +0000710652 00000 n +trailer <<9B0616C908B34AD39F15C3556859163D>]>> startxref 710872 %%EOF \ No newline at end of file diff --git a/microsite/static/logo_assets/pdf/Individual/01_Logo_White.pdf b/microsite/static/logo_assets/pdf/Individual/01_Logo_White.pdf new file mode 100644 index 0000000000..6ebc9fa52c Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/01_Logo_White.pdf differ diff --git a/microsite/static/logo_assets/pdf/Individual/02_Icon_White.pdf b/microsite/static/logo_assets/pdf/Individual/02_Icon_White.pdf new file mode 100644 index 0000000000..ce1618903c Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/02_Icon_White.pdf differ diff --git a/microsite/static/logo_assets/pdf/Individual/03_Logo_Teal.pdf b/microsite/static/logo_assets/pdf/Individual/03_Logo_Teal.pdf new file mode 100644 index 0000000000..d12f5fe99e Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/03_Logo_Teal.pdf differ diff --git a/microsite/static/logo_assets/pdf/Individual/04_Icon_Teal.pdf b/microsite/static/logo_assets/pdf/Individual/04_Icon_Teal.pdf new file mode 100644 index 0000000000..125d287602 Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/04_Icon_Teal.pdf differ diff --git a/microsite/static/logo_assets/pdf/Individual/05_Logo_Black.pdf b/microsite/static/logo_assets/pdf/Individual/05_Logo_Black.pdf new file mode 100644 index 0000000000..be9a572b37 Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/05_Logo_Black.pdf differ diff --git a/microsite/static/logo_assets/pdf/Individual/06_Icon_Black.pdf b/microsite/static/logo_assets/pdf/Individual/06_Icon_Black.pdf new file mode 100644 index 0000000000..330754384f Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/06_Icon_Black.pdf differ diff --git a/microsite/static/logo_assets/pdf/Individual/07_Large Icon_Gradient.pdf b/microsite/static/logo_assets/pdf/Individual/07_Large Icon_Gradient.pdf new file mode 100644 index 0000000000..01f600e5bc Binary files /dev/null and b/microsite/static/logo_assets/pdf/Individual/07_Large Icon_Gradient.pdf differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_01_Logo_White.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_01_Logo_White.png new file mode 100644 index 0000000000..84a1dba855 Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_01_Logo_White.png differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_02_Icon_White.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_02_Icon_White.png new file mode 100644 index 0000000000..29264f8ac0 Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_02_Icon_White.png differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_03_Logo_Teal.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_03_Logo_Teal.png new file mode 100644 index 0000000000..092599ce63 Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_03_Logo_Teal.png differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png new file mode 100644 index 0000000000..d662301101 Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_04_Icon_Teal.png differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_05_Logo_Black.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_05_Logo_Black.png new file mode 100644 index 0000000000..7da1808784 Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_05_Logo_Black.png differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_06_Icon_Black.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_06_Icon_Black.png new file mode 100644 index 0000000000..5049d54513 Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_06_Icon_Black.png differ diff --git a/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_07_Large_Icon_Gradient.png b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_07_Large_Icon_Gradient.png new file mode 100644 index 0000000000..889017fbfb Binary files /dev/null and b/microsite/static/logo_assets/png/Backstage_Identity_Assets_Artwork_RGB_07_Large_Icon_Gradient.png differ diff --git a/microsite/static/logo_assets/svg/Icon_Black.svg b/microsite/static/logo_assets/svg/Icon_Black.svg new file mode 100644 index 0000000000..2eb2dda646 --- /dev/null +++ b/microsite/static/logo_assets/svg/Icon_Black.svg @@ -0,0 +1 @@ +06 Icon_Black \ No newline at end of file diff --git a/microsite/static/logo_assets/svg/Icon_Gradient.svg b/microsite/static/logo_assets/svg/Icon_Gradient.svg new file mode 100644 index 0000000000..bbdb4bba27 --- /dev/null +++ b/microsite/static/logo_assets/svg/Icon_Gradient.svg @@ -0,0 +1 @@ +07 Large Icon_Gradient \ No newline at end of file diff --git a/microsite/static/logo_assets/svg/Icon_Teal.svg b/microsite/static/logo_assets/svg/Icon_Teal.svg new file mode 100644 index 0000000000..7152749073 --- /dev/null +++ b/microsite/static/logo_assets/svg/Icon_Teal.svg @@ -0,0 +1 @@ +04 Icon_Teal \ No newline at end of file diff --git a/microsite/static/logo_assets/svg/Icon_White.svg b/microsite/static/logo_assets/svg/Icon_White.svg new file mode 100644 index 0000000000..c1d6f388b4 --- /dev/null +++ b/microsite/static/logo_assets/svg/Icon_White.svg @@ -0,0 +1 @@ +02 Icon_White \ No newline at end of file diff --git a/microsite/static/logo_assets/svg/Logo_Black.svg b/microsite/static/logo_assets/svg/Logo_Black.svg new file mode 100644 index 0000000000..b7d10e429c --- /dev/null +++ b/microsite/static/logo_assets/svg/Logo_Black.svg @@ -0,0 +1 @@ +05 Logo_Black \ No newline at end of file diff --git a/microsite/static/logo_assets/svg/Logo_Teal.svg b/microsite/static/logo_assets/svg/Logo_Teal.svg new file mode 100644 index 0000000000..b3babaa39a --- /dev/null +++ b/microsite/static/logo_assets/svg/Logo_Teal.svg @@ -0,0 +1 @@ +03 Logo_Teal \ No newline at end of file diff --git a/microsite/static/logo_assets/svg/Logo_White.svg b/microsite/static/logo_assets/svg/Logo_White.svg new file mode 100644 index 0000000000..7b9c543951 --- /dev/null +++ b/microsite/static/logo_assets/svg/Logo_White.svg @@ -0,0 +1 @@ +01 Logo_White \ No newline at end of file diff --git a/microsite/yarn.lock b/microsite/yarn.lock new file mode 100644 index 0000000000..84b5d50d60 --- /dev/null +++ b/microsite/yarn.lock @@ -0,0 +1,6650 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@7.5.5": + version "7.5.5" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + +"@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/compat-data@^7.10.4", "@babel/compat-data@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" + integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ== + dependencies: + browserslist "^4.12.0" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@^7.9.0": + version "7.11.6" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" + integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.11.6" + "@babel/helper-module-transforms" "^7.11.0" + "@babel/helpers" "^7.10.4" + "@babel/parser" "^7.11.5" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.11.5" + "@babel/types" "^7.11.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.11.5", "@babel/generator@^7.11.6": + version "7.11.6" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" + integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== + dependencies: + "@babel/types" "^7.11.5" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-builder-react-jsx-experimental@^7.10.4", "@babel/helper-builder-react-jsx-experimental@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.11.5.tgz#4ea43dd63857b0a35cd1f1b161dc29b43414e79f" + integrity sha512-Vc4aPJnRZKWfzeCBsqTBnzulVNjABVdahSPhtdMD3Vs80ykx4a87jTHtF/VR+alSrDmNvat7l13yrRHauGcHVw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/types" "^7.11.5" + +"@babel/helper-builder-react-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.10.4.tgz#8095cddbff858e6fa9c326daee54a2f2732c1d5d" + integrity sha512-5nPcIZ7+KKDxT1427oBivl9V9YTal7qk0diccnh7RrcgrT/pGFOjgGw1dgryyx1GvHEpXVfoDF6Ak3rTiWh8Rg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-compilation-targets@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" + integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== + dependencies: + "@babel/compat-data" "^7.10.4" + browserslist "^4.12.0" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-class-features-plugin@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" + integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.10.5" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + +"@babel/helper-create-regexp-features-plugin@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" + integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + regexpu-core "^4.7.0" + +"@babel/helper-define-map@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" + integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + +"@babel/helper-explode-assignable-expression@^7.10.4": + version "7.11.4" + resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b" + integrity sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-hoist-variables@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" + integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" + integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== + dependencies: + "@babel/types" "^7.11.0" + +"@babel/helper-module-imports@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" + integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" + integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/template" "^7.10.4" + "@babel/types" "^7.11.0" + lodash "^4.17.19" + +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + +"@babel/helper-regex@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" + integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== + dependencies: + lodash "^4.17.19" + +"@babel/helper-remap-async-to-generator@^7.10.4": + version "7.11.4" + resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz#4474ea9f7438f18575e30b0cac784045b402a12d" + integrity sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-wrap-function" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-replace-supers@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" + integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-simple-access@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" + integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== + dependencies: + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" + integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== + dependencies: + "@babel/types" "^7.11.0" + +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/helper-wrap-function@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" + integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helpers@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" + integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/highlight@^7.0.0", "@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.10.4", "@babel/parser@^7.11.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" + integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== + +"@babel/plugin-proposal-async-generator-functions@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" + integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" + integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-dynamic-import@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" + integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-export-namespace-from@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" + integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" + integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-logical-assignment-operators@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" + integrity sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" + integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" + integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.11.0", "@babel/plugin-proposal-object-rest-spread@^7.9.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" + integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.10.4" + +"@babel/plugin-proposal-optional-catch-binding@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" + integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" + integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-private-methods@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" + integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" + integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" + integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.4.tgz#39abaae3cbf710c4373d8429484e6ba21340166c" + integrity sha512-KCg9mio9jwiARCB7WAcQ7Y1q+qicILjoK8LP/VkPkEKaf5dkaZZK1EcTe91a3JJlZ3qy6L5s9X52boEYi8DM9g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" + integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-arrow-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" + integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-async-to-generator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" + integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== + dependencies: + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.10.4" + +"@babel/plugin-transform-block-scoped-functions@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" + integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-block-scoping@^7.10.4": + version "7.11.1" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" + integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-classes@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" + integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-define-map" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.10.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" + integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-destructuring@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" + integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" + integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-duplicate-keys@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" + integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-exponentiation-operator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" + integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-for-of@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" + integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" + integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" + integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" + integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-modules-amd@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" + integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw== + dependencies: + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" + integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== + dependencies: + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-simple-access" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" + integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw== + dependencies: + "@babel/helper-hoist-variables" "^7.10.4" + "@babel/helper-module-transforms" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" + integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== + dependencies: + "@babel/helper-module-transforms" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" + integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + +"@babel/plugin-transform-new-target@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" + integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-object-super@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" + integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.10.4" + +"@babel/plugin-transform-parameters@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" + integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-property-literals@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" + integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-display-name@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.10.4.tgz#b5795f4e3e3140419c3611b7a2a3832b9aef328d" + integrity sha512-Zd4X54Mu9SBfPGnEcaGcOrVAYOtjT2on8QZkLKEq1S/tHexG39d9XXGZv19VfRrDjPJzFmPfTAqOQS1pfFOujw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-react-jsx-development@^7.10.4": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.11.5.tgz#e1439e6a57ee3d43e9f54ace363fb29cefe5d7b6" + integrity sha512-cImAmIlKJ84sDmpQzm4/0q/2xrXlDezQoixy3qoz1NJeZL/8PRon6xZtluvr4H4FzwlDGI5tCcFupMnXGtr+qw== + dependencies: + "@babel/helper-builder-react-jsx-experimental" "^7.11.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" + +"@babel/plugin-transform-react-jsx-self@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.10.4.tgz#cd301a5fed8988c182ed0b9d55e9bd6db0bd9369" + integrity sha512-yOvxY2pDiVJi0axdTWHSMi5T0DILN+H+SaeJeACHKjQLezEzhLx9nEF9xgpBLPtkZsks9cnb5P9iBEi21En3gg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" + +"@babel/plugin-transform-react-jsx-source@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.10.5.tgz#34f1779117520a779c054f2cdd9680435b9222b4" + integrity sha512-wTeqHVkN1lfPLubRiZH3o73f4rfon42HpgxUSs86Nc+8QIcm/B9s8NNVXu/gwGcOyd7yDib9ikxoDLxJP0UiDA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" + +"@babel/plugin-transform-react-jsx@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.10.4.tgz#673c9f913948764a4421683b2bef2936968fddf2" + integrity sha512-L+MfRhWjX0eI7Js093MM6MacKU4M6dnCRa/QPDwYMxjljzSCzzlzKzj9Pk4P3OtrPcxr2N3znR419nr3Xw+65A== + dependencies: + "@babel/helper-builder-react-jsx" "^7.10.4" + "@babel/helper-builder-react-jsx-experimental" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-jsx" "^7.10.4" + +"@babel/plugin-transform-react-pure-annotations@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.10.4.tgz#3eefbb73db94afbc075f097523e445354a1c6501" + integrity sha512-+njZkqcOuS8RaPakrnR9KvxjoG1ASJWpoIv/doyWngId88JoFlPlISenGXjrVacZUIALGUr6eodRs1vmPnF23A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-regenerator@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" + integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" + integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-shorthand-properties@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" + integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-spread@^7.11.0": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" + integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" + +"@babel/plugin-transform-sticky-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" + integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + +"@babel/plugin-transform-template-literals@^7.10.4": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" + integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-typeof-symbol@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" + integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-unicode-escapes@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" + integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-unicode-regex@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" + integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/polyfill@^7.8.7": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.11.5.tgz#df550b2ec53abbc2ed599367ec59e64c7a707bb5" + integrity sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.9.0": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz#18cb4b9379e3e92ffea92c07471a99a2914e4272" + integrity sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA== + dependencies: + "@babel/compat-data" "^7.11.0" + "@babel/helper-compilation-targets" "^7.10.4" + "@babel/helper-module-imports" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-proposal-async-generator-functions" "^7.10.4" + "@babel/plugin-proposal-class-properties" "^7.10.4" + "@babel/plugin-proposal-dynamic-import" "^7.10.4" + "@babel/plugin-proposal-export-namespace-from" "^7.10.4" + "@babel/plugin-proposal-json-strings" "^7.10.4" + "@babel/plugin-proposal-logical-assignment-operators" "^7.11.0" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" + "@babel/plugin-proposal-numeric-separator" "^7.10.4" + "@babel/plugin-proposal-object-rest-spread" "^7.11.0" + "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" + "@babel/plugin-proposal-optional-chaining" "^7.11.0" + "@babel/plugin-proposal-private-methods" "^7.10.4" + "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-class-properties" "^7.10.4" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.10.4" + "@babel/plugin-transform-arrow-functions" "^7.10.4" + "@babel/plugin-transform-async-to-generator" "^7.10.4" + "@babel/plugin-transform-block-scoped-functions" "^7.10.4" + "@babel/plugin-transform-block-scoping" "^7.10.4" + "@babel/plugin-transform-classes" "^7.10.4" + "@babel/plugin-transform-computed-properties" "^7.10.4" + "@babel/plugin-transform-destructuring" "^7.10.4" + "@babel/plugin-transform-dotall-regex" "^7.10.4" + "@babel/plugin-transform-duplicate-keys" "^7.10.4" + "@babel/plugin-transform-exponentiation-operator" "^7.10.4" + "@babel/plugin-transform-for-of" "^7.10.4" + "@babel/plugin-transform-function-name" "^7.10.4" + "@babel/plugin-transform-literals" "^7.10.4" + "@babel/plugin-transform-member-expression-literals" "^7.10.4" + "@babel/plugin-transform-modules-amd" "^7.10.4" + "@babel/plugin-transform-modules-commonjs" "^7.10.4" + "@babel/plugin-transform-modules-systemjs" "^7.10.4" + "@babel/plugin-transform-modules-umd" "^7.10.4" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" + "@babel/plugin-transform-new-target" "^7.10.4" + "@babel/plugin-transform-object-super" "^7.10.4" + "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/plugin-transform-property-literals" "^7.10.4" + "@babel/plugin-transform-regenerator" "^7.10.4" + "@babel/plugin-transform-reserved-words" "^7.10.4" + "@babel/plugin-transform-shorthand-properties" "^7.10.4" + "@babel/plugin-transform-spread" "^7.11.0" + "@babel/plugin-transform-sticky-regex" "^7.10.4" + "@babel/plugin-transform-template-literals" "^7.10.4" + "@babel/plugin-transform-typeof-symbol" "^7.10.4" + "@babel/plugin-transform-unicode-escapes" "^7.10.4" + "@babel/plugin-transform-unicode-regex" "^7.10.4" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.11.5" + browserslist "^4.12.0" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-modules@^0.1.3": + version "0.1.4" + resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-react@^7.9.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.10.4.tgz#92e8a66d816f9911d11d4cc935be67adfc82dbcf" + integrity sha512-BrHp4TgOIy4M19JAfO1LhycVXOPWdDbTRep7eVyatf174Hff+6Uk53sDyajqZPu8W1qXRBiYOfIamek6jA7YVw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-react-display-name" "^7.10.4" + "@babel/plugin-transform-react-jsx" "^7.10.4" + "@babel/plugin-transform-react-jsx-development" "^7.10.4" + "@babel/plugin-transform-react-jsx-self" "^7.10.4" + "@babel/plugin-transform-react-jsx-source" "^7.10.4" + "@babel/plugin-transform-react-pure-annotations" "^7.10.4" + +"@babel/register@^7.9.0": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/register/-/register-7.11.5.tgz#79becf89e0ddd0fba8b92bc279bc0f5d2d7ce2ea" + integrity sha512-CAml0ioKX+kOAvBQDHa/+t1fgOt3qkTIz0TrRtRAT6XY0m5qYZXR85k6/sLCNPMGhYDlCFHCYuU0ybTJbvlC6w== + dependencies: + find-cache-dir "^2.0.0" + lodash "^4.17.19" + make-dir "^2.1.0" + pirates "^4.0.0" + source-map-support "^0.5.16" + +"@babel/runtime@^7.8.4": + version "7.11.2" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5", "@babel/traverse@^7.9.0": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" + integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.11.5" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.11.5" + "@babel/types" "^7.11.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4", "@babel/types@^7.9.0": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" + integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== + +"@types/cheerio@^0.22.8": + version "0.22.21" + resolved "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.21.tgz#5e37887de309ba11b2e19a6e14cad7874b31a8a3" + integrity sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q== + dependencies: + "@types/node" "*" + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/node@*": + version "14.6.4" + resolved "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz#a145cc0bb14ef9c4777361b7bbafa5cf8e3acb5a" + integrity sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ== + +"@types/q@^1.5.1": + version "1.5.4" + resolved "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24" + integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug== + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +address@1.1.2, address@^1.0.1: + version "1.1.2" + resolved "https://registry.npmjs.org/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== + +ajv@^6.12.3: + version "6.12.4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" + integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-red@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" + integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= + dependencies: + ansi-wrap "0.1.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +ansi-wrap@0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +arch@^2.1.0: + version "2.1.2" + resolved "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz#0c52bbe7344bb4fa260c443d2cbad9c00ff2f0bf" + integrity sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ== + +archive-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" + integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= + dependencies: + file-type "^4.2.0" + +argparse@^1.0.10, argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.npmjs.org/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autolinker@^3.11.0: + version "3.14.1" + resolved "https://registry.npmjs.org/autolinker/-/autolinker-3.14.1.tgz#6ae4b812b6eaf42d4d68138b9e67757cbf2bc1e4" + integrity sha512-yvsRHIaY51EYDml6MGlbqyJGfl4n7zezGYf+R7gvM8c5LNpRGc4SISkvgAswSS8SWxk/OrGCylKV9mJyVstz7w== + dependencies: + tslib "^1.9.3" + +autolinker@~0.28.0: + version "0.28.1" + resolved "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" + integrity sha1-BlK0kYgYefB3XazgzcoyM5QqTkc= + dependencies: + gulp-header "^1.7.1" + +autoprefixer@^9.7.5: + version "9.8.6" + resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + colorette "^1.2.1" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.10.1" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" + integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== + +babel-code-frame@^6.22.0: + version "6.26.0" + resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +bin-build@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz#c5780a25a8a9f966d8244217e6c1f5082a143861" + integrity sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA== + dependencies: + decompress "^4.0.0" + download "^6.2.2" + execa "^0.7.0" + p-map-series "^1.0.0" + tempfile "^2.0.0" + +bin-check@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz#fc495970bdc88bb1d5a35fc17e65c4a149fc4a49" + integrity sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA== + dependencies: + execa "^0.7.0" + executable "^4.1.0" + +bin-version-check@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz#7d819c62496991f80d893e6e02a3032361608f71" + integrity sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ== + dependencies: + bin-version "^3.0.0" + semver "^5.6.0" + semver-truncate "^1.1.2" + +bin-version@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz#5b09eb280752b1bd28f0c9db3f96f2f43b6c0839" + integrity sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ== + dependencies: + execa "^1.0.0" + find-versions "^3.0.0" + +bin-wrapper@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz#99348f2cf85031e3ef7efce7e5300aeaae960605" + integrity sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q== + dependencies: + bin-check "^4.1.0" + bin-version-check "^4.0.0" + download "^7.1.0" + import-lazy "^3.1.0" + os-filter-obj "^2.0.0" + pify "^4.0.1" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +body@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= + dependencies: + continuable-cache "^0.3.1" + error "^7.0.0" + raw-body "~1.1.0" + safe-json-parse "~1.0.1" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +browserslist@4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz#9ee89225ffc07db03409f2fee524dc8227458a17" + integrity sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA== + dependencies: + caniuse-lite "^1.0.30000989" + electron-to-chromium "^1.3.247" + node-releases "^1.1.29" + +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.5: + version "4.14.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.14.1.tgz#cb2b490ba881d45dc3039078c7ed04411eaf3fa3" + integrity sha512-zyBTIHydW37pnb63c7fHFXUG6EcqWOqoMdDx6cdyaDFriZ20EoVxcE95S54N+heRqY8m8IUgB5zYta/gCwSaaA== + dependencies: + caniuse-lite "^1.0.30001124" + electron-to-chromium "^1.3.562" + escalade "^3.0.2" + node-releases "^1.1.60" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer@^5.2.1: + version "5.6.0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +bytes@1: + version "1.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001124: + version "1.0.30001124" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001124.tgz#5d9998190258e11630d674fc50ea8e579ae0ced2" + integrity sha512-zQW8V3CdND7GHRH6rxm6s59Ww4g/qGWTheoboW9nfeMg7sUoopIfKCcNZUjwYRCOrvereh3kwDpZj4VLQ7zGtA== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +caw@^2.0.0, caw@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" + integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== + dependencies: + get-proxy "^2.0.0" + isurl "^1.0.0-alpha5" + tunnel-agent "^0.6.0" + url-to-options "^1.0.1" + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^1.0.0, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +cheerio@0.22.0: + version "0.22.0" + resolved "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" + integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= + dependencies: + css-select "~1.2.0" + dom-serializer "~0.1.0" + entities "~1.1.1" + htmlparser2 "^3.9.1" + lodash.assignin "^4.0.9" + lodash.bind "^4.1.4" + lodash.defaults "^4.0.1" + lodash.filter "^4.4.0" + lodash.flatten "^4.2.0" + lodash.foreach "^4.3.0" + lodash.map "^4.4.0" + lodash.merge "^4.4.0" + lodash.pick "^4.2.1" + lodash.reduce "^4.4.0" + lodash.reject "^4.4.0" + lodash.some "^4.4.0" + +chokidar@^2.0.4: + version "2.1.8" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classnames@^2.2.6: + version "2.2.6" + resolved "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +clipboard@^2.0.0: + version "2.0.6" + resolved "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376" + integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg== + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +coffee-script@^1.12.4: + version "1.12.7" + resolved "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53" + integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.1: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" + integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colorette@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" + integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.8.1: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.0.1: + version "4.1.1" + resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commander@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-with-sourcemaps@*: + version "1.1.0" + resolved "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== + dependencies: + source-map "^0.6.1" + +config-chain@^1.1.11: + version "1.1.12" + resolved "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +console-stream@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz#a095fe07b20465955f2fafd28b5d72bccd949d44" + integrity sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ= + +content-disposition@0.5.3, content-disposition@^0.5.2: + version "0.5.3" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +continuable-cache@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= + +convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.6.2: + version "3.6.5" + resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" + integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== + dependencies: + browserslist "^4.8.5" + semver "7.0.0" + +core-js@^2.6.5: + version "2.6.11" + resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.0.0: + version "5.2.1" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +cross-spawn@6.0.5, cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + +crowdin-cli@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/crowdin-cli/-/crowdin-cli-0.3.0.tgz#eac9989a6fe7feaaf33090397afc187c67b46191" + integrity sha1-6smYmm/n/qrzMJA5evwYfGe0YZE= + dependencies: + request "^2.53.0" + yamljs "^0.2.1" + yargs "^2.3.0" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-select@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@1.0.0-alpha.39: + version "1.0.0-alpha.39" + resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" + integrity sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA== + dependencies: + mdn-data "2.0.6" + source-map "^0.6.1" + +css-what@2.1: + version "2.1.3" + resolved "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" + integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== + +css-what@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/css-what/-/css-what-3.3.0.tgz#10fec696a9ece2e591ac772d759aacabac38cd39" + integrity sha512-pv9JPyatiPaQ6pf4OvD/dbfm0o5LviWmwxNWzblYf/1u9QZd0ihV+PMwy5jdQWQ3349kZmKEx9WXuSka2dM4cg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^4.0.7: + version "4.0.7" + resolved "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" + integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== + dependencies: + css-declaration-sorter "^4.0.1" + cssnano-util-raw-cache "^4.0.1" + postcss "^7.0.0" + postcss-calc "^7.0.1" + postcss-colormin "^4.0.3" + postcss-convert-values "^4.0.1" + postcss-discard-comments "^4.0.2" + postcss-discard-duplicates "^4.0.2" + postcss-discard-empty "^4.0.1" + postcss-discard-overridden "^4.0.1" + postcss-merge-longhand "^4.0.11" + postcss-merge-rules "^4.0.3" + postcss-minify-font-values "^4.0.2" + postcss-minify-gradients "^4.0.2" + postcss-minify-params "^4.0.2" + postcss-minify-selectors "^4.0.2" + postcss-normalize-charset "^4.0.1" + postcss-normalize-display-values "^4.0.2" + postcss-normalize-positions "^4.0.2" + postcss-normalize-repeat-style "^4.0.2" + postcss-normalize-string "^4.0.2" + postcss-normalize-timing-functions "^4.0.2" + postcss-normalize-unicode "^4.0.1" + postcss-normalize-url "^4.0.1" + postcss-normalize-whitespace "^4.0.2" + postcss-ordered-values "^4.1.2" + postcss-reduce-initial "^4.0.3" + postcss-reduce-transforms "^4.0.2" + postcss-svgo "^4.0.2" + postcss-unique-selectors "^4.0.1" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.10" + resolved "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" + integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.7" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.0.3" + resolved "https://registry.npmjs.org/csso/-/csso-4.0.3.tgz#0d9985dc852c7cc2b2cacfbbe1079014d1a8e903" + integrity sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ== + dependencies: + css-tree "1.0.0-alpha.39" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" + integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== + dependencies: + ms "^2.1.1" + +debug@^3.1.0, debug@^3.1.1, debug@^3.2.5: + version "3.2.6" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0, decompress@^4.2.0: + version "4.2.1" + resolved "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" + integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + +deep-is@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-port-alt@1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== + dependencies: + address "^1.0.1" + debug "^2.6.0" + +diacritics-map@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz#6dfc0ff9d01000a2edf2865371cac316e94977af" + integrity sha1-bfwP+dAQAKLt8oZTccrDFulJd68= + +dir-glob@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" + integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== + dependencies: + arrify "^1.0.1" + path-type "^3.0.0" + +docusaurus@^2.0.0-alpha.64: + version "2.0.0-alpha.64" + resolved "https://registry.yarnpkg.com/docusaurus/-/docusaurus-2.0.0-alpha.64.tgz#7833960e9d338403894a27b79058aa4076a676d3" + integrity sha512-ARCx0GwAvc5qx7AHvRVZidZuoDTfaaGXzgmkU23NahU6jzO/aK2Q1bH8IKNEQ5C2JuDerQ/hHDh80N20ijk82g== + dependencies: + "@babel/core" "^7.9.0" + "@babel/plugin-proposal-class-properties" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.0" + "@babel/polyfill" "^7.8.7" + "@babel/preset-env" "^7.9.0" + "@babel/preset-react" "^7.9.4" + "@babel/register" "^7.9.0" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" + autoprefixer "^9.7.5" + babylon "^6.18.0" + chalk "^3.0.0" + classnames "^2.2.6" + commander "^4.0.1" + crowdin-cli "^0.3.0" + cssnano "^4.1.10" + escape-string-regexp "^2.0.0" + express "^4.17.1" + feed "^4.0.0" + fs-extra "^8.1.0" + gaze "^1.1.3" + github-slugger "^1.2.1" + glob "^7.1.6" + highlight.js "^9.16.2" + imagemin "^6.0.0" + imagemin-gifsicle "^6.0.1" + imagemin-jpegtran "^6.0.0" + imagemin-optipng "^6.0.0" + imagemin-svgo "^7.0.0" + lodash "^4.17.15" + markdown-toc "^1.2.0" + mkdirp "^0.5.1" + portfinder "^1.0.25" + postcss "^7.0.23" + prismjs "^1.17.1" + react "^16.8.4" + react-dev-utils "^9.1.0" + react-dom "^16.8.4" + remarkable "^2.0.0" + request "^2.88.0" + shelljs "^0.8.4" + sitemap "^3.2.2" + tcp-port-used "^1.0.1" + tiny-lr "^1.1.1" + tree-node-cli "^1.2.5" + truncate-html "^1.0.3" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +dom-serializer@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" + integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== + dependencies: + domelementtype "^1.3.0" + entities "^1.1.1" + +domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" + integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== + +domhandler@^2.3.0: + version "2.4.2" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" + integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8= + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1, domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + +download@^6.2.2: + version "6.2.5" + resolved "https://registry.npmjs.org/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" + integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== + dependencies: + caw "^2.0.0" + content-disposition "^0.5.2" + decompress "^4.0.0" + ext-name "^5.0.0" + file-type "5.2.0" + filenamify "^2.0.0" + get-stream "^3.0.0" + got "^7.0.0" + make-dir "^1.0.0" + p-event "^1.0.0" + pify "^3.0.0" + +download@^7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/download/-/download-7.1.0.tgz#9059aa9d70b503ee76a132897be6dec8e5587233" + integrity sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ== + dependencies: + archive-type "^4.0.0" + caw "^2.0.1" + content-disposition "^0.5.2" + decompress "^4.2.0" + ext-name "^5.0.0" + file-type "^8.1.0" + filenamify "^2.0.0" + get-stream "^3.0.0" + got "^8.3.1" + make-dir "^1.2.0" + p-event "^2.1.0" + pify "^3.0.0" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.562: + version "1.3.562" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.562.tgz#79c20277ee1c8d0173a22af00e38433b752bc70f" + integrity sha512-WhRe6liQ2q/w1MZc8mD8INkenHivuHdrr4r5EQHNomy3NJux+incP6M6lDMd0paShP3MD0WGe5R1TWmEClf+Bg== + +"emoji-regex@>=6.0.0 <=6.1.1": + version "6.1.1" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e" + integrity sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4= + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +entities@^2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" + integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error@^7.0.0: + version "7.2.1" + resolved "https://registry.npmjs.org/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" + integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== + dependencies: + string-template "~0.2.1" + +es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: + version "1.17.6" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" + integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.0" + is-regex "^1.1.0" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.0.2.tgz#6a580d70edb87880f22b4c91d0d56078df6962c4" + integrity sha512-gPYAU37hYCUhW5euPeR+Y74F7BL+IBsV93j5cvGriSaD1aG6MGsqsV1yamRdrWrb2j3aiZvb0X+UBOWpx3JWtQ== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventsource@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0" + integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ== + dependencies: + original "^1.0.0" + +exec-buffer@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz#b1686dbd904c7cf982e652c1f5a79b1e5573082b" + integrity sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA== + dependencies: + execa "^0.7.0" + p-finally "^1.0.0" + pify "^3.0.0" + rimraf "^2.5.4" + tempfile "^2.0.0" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +executable@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.npmjs.org/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +ext-list@^2.0.0: + version "2.2.2" + resolved "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" + integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== + dependencies: + mime-db "^1.28.0" + +ext-name@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" + integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== + dependencies: + ext-list "^2.0.0" + sort-keys-length "^1.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^2.0.2: + version "2.2.7" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" + integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.1.2" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.3" + micromatch "^3.1.10" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +faye-websocket@~0.10.0: + version "0.10.0" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +faye-websocket@~0.11.1: + version "0.11.3" + resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" + integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== + dependencies: + websocket-driver ">=0.5.1" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +feed@^4.0.0: + version "4.2.1" + resolved "https://registry.npmjs.org/feed/-/feed-4.2.1.tgz#b246ef891051c7dbf088ca203341d9fb0444baee" + integrity sha512-l28KKcK1J/u3iq5dRDmmoB2p7dtBfACC2NqJh4dI2kFptxH0asfjmOfcxqh5Sv8suAlVa73gZJ4REY5RrafVvg== + dependencies: + xml-js "^1.6.11" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-type@5.2.0, file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + +file-type@^10.4.0, file-type@^10.7.0: + version "10.11.0" + resolved "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz#2961d09e4675b9fb9a3ee6b69e9cd23f43fd1890" + integrity sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw== + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + +file-type@^4.2.0: + version "4.4.0" + resolved "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" + integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + +file-type@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz#244f3b7ef641bbe0cca196c7276e4b332399f68c" + integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filename-reserved-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" + integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= + +filenamify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" + integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== + dependencies: + filename-reserved-regex "^2.0.0" + strip-outer "^1.0.0" + trim-repeated "^1.0.0" + +filesize@3.6.1: + version "3.6.1" + resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-versions@^3.0.0: + version "3.2.0" + resolved "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" + integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== + dependencies: + semver-regex "^2.0.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +fork-ts-checker-webpack-plugin@1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-1.5.0.tgz#ce1d77190b44d81a761b10b6284a373795e41f0c" + integrity sha512-zEhg7Hz+KhZlBhILYpXy+Beu96gwvkROWJiTXOCyOOMMrdBIRPvsBpBqgTI4jfJGrJXcqGwJR8zsBGDmzY0jsA== + dependencies: + babel-code-frame "^6.22.0" + chalk "^2.4.1" + chokidar "^2.0.4" + micromatch "^3.1.10" + minimatch "^3.0.4" + semver "^5.6.0" + tapable "^1.0.0" + worker-rpc "^0.1.0" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.1: + version "2.3.0" + resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gaze@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-proxy@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" + integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== + dependencies: + npm-conf "^1.1.0" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +gifsicle@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/gifsicle/-/gifsicle-4.0.1.tgz#30e1e61e3ee4884ef702641b2e98a15c2127b2e2" + integrity sha512-A/kiCLfDdV+ERV/UB+2O41mifd+RxH8jlRG8DMxZO84Bma/Fw0htqZ+hY2iaalLRNyUu7tYZQslqUBJxBggxbg== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + execa "^1.0.0" + logalot "^2.0.0" + +github-slugger@^1.2.1: + version "1.3.0" + resolved "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz#9bd0a95c5efdfc46005e82a906ef8e2a059124c9" + integrity sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q== + dependencies: + emoji-regex ">=6.0.0 <=6.1.1" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + +glob@^7.0.0, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.1.1: + version "7.1.6" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@8.0.2, globby@^8.0.1: + version "8.0.2" + resolved "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" + integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== + dependencies: + array-union "^1.0.1" + dir-glob "2.0.0" + fast-glob "^2.0.2" + glob "^7.1.2" + ignore "^3.3.5" + pify "^3.0.0" + slash "^1.0.0" + +globule@^1.0.0: + version "1.3.2" + resolved "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4" + integrity sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA= + dependencies: + delegate "^3.1.2" + +got@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +got@^8.3.1: + version "8.3.2" + resolved "https://registry.npmjs.org/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.4" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +gray-matter@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz#3042d9adec2a1ded6a7707a9ed2380f8a17a430e" + integrity sha1-MELZrewqHe1qdwep7SOA+KF6Qw4= + dependencies: + ansi-red "^0.1.1" + coffee-script "^1.12.4" + extend-shallow "^2.0.1" + js-yaml "^3.8.1" + toml "^2.3.2" + +gulp-header@^1.7.1: + version "1.8.12" + resolved "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" + integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== + dependencies: + concat-with-sourcemaps "*" + lodash.template "^4.4.0" + through2 "^2.0.0" + +gzip-size@5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" + integrity sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +highlight.js@^9.16.2: + version "9.18.3" + resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634" + integrity sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ== + +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-comment-regex@^1.1.0, html-comment-regex@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" + integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== + +htmlparser2@^3.9.1: + version "3.10.1" + resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" + integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== + dependencies: + domelementtype "^1.3.1" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^3.1.1" + +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-parser-js@>=0.5.1: + version "0.5.2" + resolved "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" + integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +ignore@^3.3.5: + version "3.3.10" + resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" + integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== + +imagemin-gifsicle@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-6.0.1.tgz#6abad4e95566d52e5a104aba1c24b4f3b48581b3" + integrity sha512-kuu47c6iKDQ6R9J10xCwL0lgs0+sMz3LRHqRcJ2CRBWdcNmo3T5hUaM8hSZfksptZXJLGKk8heSAvwtSdB1Fng== + dependencies: + exec-buffer "^3.0.0" + gifsicle "^4.0.0" + is-gif "^3.0.0" + +imagemin-jpegtran@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/imagemin-jpegtran/-/imagemin-jpegtran-6.0.0.tgz#c8d3bcfb6ec9c561c20a987142854be70d90b04f" + integrity sha512-Ih+NgThzqYfEWv9t58EItncaaXIHR0u9RuhKa8CtVBlMBvY0dCIxgQJQCfwImA4AV1PMfmUKlkyIHJjb7V4z1g== + dependencies: + exec-buffer "^3.0.0" + is-jpg "^2.0.0" + jpegtran-bin "^4.0.0" + +imagemin-optipng@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-6.0.0.tgz#a6bfc7b542fc08fc687e83dfb131249179a51a68" + integrity sha512-FoD2sMXvmoNm/zKPOWdhKpWdFdF9qiJmKC17MxZJPH42VMAp17/QENI/lIuP7LCUnLVAloO3AUoTSNzfhpyd8A== + dependencies: + exec-buffer "^3.0.0" + is-png "^1.0.0" + optipng-bin "^5.0.0" + +imagemin-svgo@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-7.1.0.tgz#528a42fd3d55eff5d4af8fd1113f25fb61ad6d9a" + integrity sha512-0JlIZNWP0Luasn1HT82uB9nU9aa+vUj6kpT+MjPW11LbprXC+iC4HDwn1r4Q2/91qj4iy9tRZNsFySMlEpLdpg== + dependencies: + is-svg "^4.2.1" + svgo "^1.3.2" + +imagemin@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/imagemin/-/imagemin-6.1.0.tgz#62508b465728fea36c03cdc07d915fe2d8cf9e13" + integrity sha512-8ryJBL1CN5uSHpiBMX0rJw79C9F9aJqMnjGnrd/1CafegpNuA81RBAAru/jQQEOWlOJJlpRnlcVFF6wq+Ist0A== + dependencies: + file-type "^10.7.0" + globby "^8.0.1" + make-dir "^1.0.0" + p-pipe "^1.1.0" + pify "^4.0.1" + replace-ext "^1.0.0" + +immer@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" + integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-lazy@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" + integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@^1.3.5: + version "1.3.5" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inquirer@6.5.0: + version "6.5.0" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" + integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + +invariant@^2.2.2, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" + integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-gif@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz#c4be60b26a301d695bb833b20d9b5d66c6cf83b1" + integrity sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw== + dependencies: + file-type "^10.4.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-jpg@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz#2e1997fa6e9166eaac0242daae443403e4ef1d97" + integrity sha1-LhmX+m6RZuqsAkLarkQ0A+TvHZc= + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= + +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-png@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-png/-/is-png-1.1.0.tgz#d574b12bf275c0350455570b0e5b57ab062077ce" + integrity sha1-1XSxK/J1wDUEVVcLDltXqwYgd84= + +is-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-root@2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== + dependencies: + html-comment-regex "^1.1.0" + +is-svg@^4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/is-svg/-/is-svg-4.2.1.tgz#095b496e345fec9211c2a7d5d021003e040d6f81" + integrity sha512-PHx3ANecKsKNl5y5+Jvt53Y4J7MfMpbNZkv384QNiswMKAWIbvcqbPz+sYbFKJI8Xv3be01GSFniPmoaP+Ai5A== + dependencies: + html-comment-regex "^1.1.2" + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-url@^1.2.2: + version "1.2.4" + resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is2@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz#8ac355644840921ce435d94f05d3a94634d3481a" + integrity sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA== + dependencies: + deep-is "^0.1.3" + ip-regex "^2.1.0" + is-url "^1.2.2" + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jpegtran-bin@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jpegtran-bin/-/jpegtran-bin-4.0.0.tgz#d00aed809fba7aa6f30817e59eee4ddf198f8f10" + integrity sha512-2cRl1ism+wJUoYAYFt6O/rLBfpXNWG2dUWbgcEkTt5WGMnqI46eEro8T4C5zGROxKRqyKpCBSdHPvt5UYCtxaQ== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + logalot "^2.0.0" + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +js-yaml@^3.13.1, js-yaml@^3.14.0, js-yaml@^3.8.1: + version "3.14.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@^3.3.2: + version "3.3.3" + resolved "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +lazy-cache@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" + integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ= + dependencies: + set-getter "^0.1.0" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + +list-item@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz#0c65d00e287cb663ccb3cb3849a77e89ec268a56" + integrity sha1-DGXQDih8tmPMs8s4Sad+iewmilY= + dependencies: + expand-range "^1.8.1" + extend-shallow "^2.0.1" + is-number "^2.1.0" + repeat-string "^1.5.2" + +livereload-js@^2.3.0: + version "2.4.0" + resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" + integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +loader-utils@1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== + dependencies: + big.js "^5.2.2" + emojis-list "^2.0.0" + json5 "^1.0.1" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash.assignin@^4.0.9: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.bind@^4.1.4: + version "4.2.1" + resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" + integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= + +lodash.chunk@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc" + integrity sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw= + +lodash.defaults@^4.0.1: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.filter@^4.4.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" + integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= + +lodash.flatten@^4.2.0: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.foreach@^4.3.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.map@^4.4.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" + integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.merge@^4.4.0: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.padstart@^4.6.1: + version "4.6.1" + resolved "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" + integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs= + +lodash.pick@^4.2.1: + version "4.4.0" + resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + +lodash.reduce@^4.4.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" + integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= + +lodash.reject@^4.4.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" + integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= + +lodash.some@^4.4.0: + version "4.6.0" + resolved "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.template@^4.4.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@~4.17.10: + version "4.17.20" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +logalot@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz#5f8e8c90d304edf12530951a5554abb8c5e3f552" + integrity sha1-X46MkNME7fElMJUaVVSruMXj9VI= + dependencies: + figures "^1.3.5" + squeak "^1.0.0" + +longest@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lpad-align@^1.0.1: + version "1.1.2" + resolved "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz#21f600ac1c3095c3c6e497ee67271ee08481fe9e" + integrity sha1-IfYArBwwlcPG5JfuZyce4ISB/p4= + dependencies: + get-stdin "^4.0.1" + indent-string "^2.1.0" + longest "^1.0.0" + meow "^3.3.0" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +make-dir@^1.0.0, make-dir@^1.2.0: + version "1.3.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-link@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz#32c5c65199a6457316322d1e4229d13407c8c7cf" + integrity sha1-MsXGUZmmRXMWMi0eQinRNAfIx88= + +markdown-toc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz#44a15606844490314afc0444483f9e7b1122c339" + integrity sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg== + dependencies: + concat-stream "^1.5.2" + diacritics-map "^0.1.0" + gray-matter "^2.1.0" + lazy-cache "^2.0.2" + list-item "^1.1.1" + markdown-link "^0.1.1" + minimist "^1.2.0" + mixin-deep "^1.1.3" + object.pick "^1.2.0" + remarkable "^1.7.1" + repeat-string "^1.6.1" + strip-color "^0.1.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +mdn-data@2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" + integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +meow@^3.3.0: + version "3.7.0" + resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge2@^1.2.3: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +microevent.ts@~0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" + integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== + +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +mime-db@1.44.0, mime-db@^1.28.0: + version "1.44.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mixin-deep@^1.1.3, mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +nan@^2.12.1: + version "2.14.1" + resolved "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-releases@^1.1.29, node-releases@^1.1.60: + version "1.1.60" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" + integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA== + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.5.0" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +npm-conf@^1.1.0: + version "1.1.3" + resolved "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" + integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== + dependencies: + config-chain "^1.1.11" + pify "^3.0.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +nth-check@^1.0.2, nth-check@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +object.pick@^1.2.0, object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +open@^6.3.0: + version "6.4.0" + resolved "https://registry.npmjs.org/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" + integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== + dependencies: + is-wsl "^1.1.0" + +optipng-bin@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/optipng-bin/-/optipng-bin-5.1.0.tgz#a7c7ab600a3ab5a177dae2f94c2d800aa386b5a9" + integrity sha512-9baoqZTNNmXQjq/PQTWEXbVV3AMO2sI/GaaqZJZ8SExfAzjijeAP7FEeT+TtyumSw7gr0PZtSUYB/Ke7iHQVKA== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + logalot "^2.0.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-filter-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz#1c0b62d5f3a2442749a2d139e6dddee6e81d8d16" + integrity sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg== + dependencies: + arch "^2.1.0" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== + +p-event@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085" + integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU= + dependencies: + p-timeout "^1.1.1" + +p-event@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" + integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== + dependencies: + p-timeout "^2.0.1" + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-map-series@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" + integrity sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco= + dependencies: + p-reduce "^1.0.0" + +p-pipe@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz#4b1a11399a11520a67790ee5a0c1d5881d6befe9" + integrity sha1-SxoROZoRUgpneQ7loMHViB1r7+k= + +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pify@^2.0.0, pify@^2.2.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pirates@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-up@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + +portfinder@^1.0.25: + version "1.0.28" + resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-calc@^7.0.1: + version "7.0.4" + resolved "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.4.tgz#5e177ddb417341e6d4a193c5d9fd8ada79094f8b" + integrity sha512-0I79VRAd1UTkaHzY9w83P39YGO/M3bG7/tNLrHGEunBolfoGM0hSjrGvjoeaj0JE/zIw5GsI2KZ0UwDJqv5hjw== + dependencies: + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + alphanum-sort "^1.0.0" + browserslist "^4.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-selector-parser@^3.0.0: + version "3.1.2" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== + dependencies: + dot-prop "^5.2.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" + integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== + dependencies: + cssesc "^3.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" + integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== + dependencies: + is-svg "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0: + version "3.3.1" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.23, postcss@^7.0.27, postcss@^7.0.32: + version "7.0.32" + resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" + integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +prismjs@^1.17.1: + version "1.21.0" + resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.21.0.tgz#36c086ec36b45319ec4218ee164c110f9fc015a3" + integrity sha512-uGdSIu1nk3kej2iZsLyDoJ7e9bnPzIgY0naW/HdknGj61zScaprVEVGHrPoXqI+M9sP0NDnTK2jpkvmldpuqDw== + optionalDependencies: + clipboard "^2.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.npmjs.org/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@^6.4.0: + version "6.9.4" + resolved "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" + integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@~1.1.0: + version "1.1.7" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= + dependencies: + bytes "1" + string_decoder "0.10" + +react-dev-utils@^9.1.0: + version "9.1.0" + resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.1.0.tgz#3ad2bb8848a32319d760d0a84c56c14bdaae5e81" + integrity sha512-X2KYF/lIGyGwP/F/oXgGDF24nxDA2KC4b7AFto+eqzc/t838gpSGiaU8trTqHXOohuLxxc5qi1eDzsl9ucPDpg== + dependencies: + "@babel/code-frame" "7.5.5" + address "1.1.2" + browserslist "4.7.0" + chalk "2.4.2" + cross-spawn "6.0.5" + detect-port-alt "1.1.6" + escape-string-regexp "1.0.5" + filesize "3.6.1" + find-up "3.0.0" + fork-ts-checker-webpack-plugin "1.5.0" + global-modules "2.0.0" + globby "8.0.2" + gzip-size "5.1.1" + immer "1.10.0" + inquirer "6.5.0" + is-root "2.1.0" + loader-utils "1.2.3" + open "^6.3.0" + pkg-up "2.0.0" + react-error-overlay "^6.0.3" + recursive-readdir "2.2.2" + shell-quote "1.7.2" + sockjs-client "1.4.0" + strip-ansi "5.2.0" + text-table "0.2.0" + +react-dom@^16.8.4: + version "16.13.1" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" + integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + scheduler "^0.19.1" + +react-error-overlay@^6.0.3: + version "6.0.7" + resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" + integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== + +react-is@^16.8.1: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react@^16.8.4: + version "16.13.1" + resolved "https://registry.npmjs.org/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" + integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +recursive-readdir@2.2.2: + version "2.2.2" + resolved "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" + integrity sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg== + dependencies: + minimatch "3.0.4" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.1" + resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" + integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== + +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + +remarkable@^1.7.1: + version "1.7.4" + resolved "https://registry.npmjs.org/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" + integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== + dependencies: + argparse "^1.0.10" + autolinker "~0.28.0" + +remarkable@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz#280ae6627384dfb13d98ee3995627ca550a12f31" + integrity sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA== + dependencies: + argparse "^1.0.10" + autolinker "^3.11.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.2, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +replace-ext@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" + integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== + +request@^2.53.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2: + version "1.17.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@^2.5.4: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +run-async@^2.2.0: + version "2.4.1" + resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +rxjs@^6.4.0: + version "6.6.2" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" + integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-json-parse@~1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4, sax@~1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +scheduler@^0.19.1: + version "0.19.1" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" + integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +seek-bzip@^1.0.5: + version "1.0.6" + resolved "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" + integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== + dependencies: + commander "^2.8.1" + +select@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= + +semver-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" + integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== + +semver-truncate@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz#57f41de69707a62709a7e0104ba2117109ea47e8" + integrity sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g= + dependencies: + semver "^5.3.0" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-getter@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" + integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y= + dependencies: + to-object-path "^0.3.0" + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shell-quote@1.7.2: + version "1.7.2" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shelljs@^0.8.4: + version "0.8.4" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +sitemap@^3.2.2: + version "3.2.2" + resolved "https://registry.npmjs.org/sitemap/-/sitemap-3.2.2.tgz#3f77c358fa97b555c879e457098e39910095c62b" + integrity sha512-TModL/WU4m2q/mQcrDgNANn0P4LwprM9MMvG4hu5zP4c6IIKs2YLTu6nXXnNr8ODW/WFtxKggiJ1EGn2W0GNmg== + dependencies: + lodash.chunk "^4.2.0" + lodash.padstart "^4.6.1" + whatwg-url "^7.0.0" + xmlbuilder "^13.0.0" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" + integrity sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g== + dependencies: + debug "^3.2.5" + eventsource "^1.0.7" + faye-websocket "~0.11.1" + inherits "^2.0.3" + json3 "^3.3.2" + url-parse "^1.4.3" + +sort-keys-length@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" + integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= + dependencies: + sort-keys "^1.0.0" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.16: + version "0.5.19" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +squeak@^1.0.0: + version "1.3.0" + resolved "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz#33045037b64388b567674b84322a6521073916c3" + integrity sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM= + dependencies: + chalk "^1.0.0" + console-stream "^0.1.1" + lpad-align "^1.0.1" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= + +string-width@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string.prototype.trimend@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimstart@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@0.10: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@5.2.0, strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-color@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz#106f65d3d3e6a2d9401cac0eb0ce8b8a702b4f7b" + integrity sha1-EG9l09PmotlAHKwOsM6LinArT3s= + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + +strip-outer@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" + integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== + dependencies: + escape-string-regexp "^1.0.2" + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +svgo@^1.0.0, svgo@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +tapable@^1.0.0: + version "1.1.3" + resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tcp-port-used@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz#46061078e2d38c73979a2c2c12b5a674e6689d70" + integrity sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q== + dependencies: + debug "4.1.0" + is2 "2.0.1" + +temp-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" + integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= + +tempfile@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" + integrity sha1-awRGhWqbERTRhW/8vlCczLCXcmU= + dependencies: + temp-dir "^1.0.0" + uuid "^3.0.1" + +text-table@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@^2.3.6, through@^2.3.8: + version "2.3.8" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +tiny-emitter@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" + integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== + +tiny-lr@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== + dependencies: + body "^5.1.0" + debug "^3.1.0" + faye-websocket "~0.10.0" + livereload-js "^2.3.0" + object-assign "^4.1.0" + qs "^6.4.0" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +toml@^2.3.2: + version "2.3.6" + resolved "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz#25b0866483a9722474895559088b436fd11f861b" + integrity sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ== + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +tree-node-cli@^1.2.5: + version "1.4.0" + resolved "https://registry.npmjs.org/tree-node-cli/-/tree-node-cli-1.4.0.tgz#8f4028554610d6ee1cdeb98554a60841a3cfa3ac" + integrity sha512-hBc/cp7rTSHFSFvaTzmHNYyJv87UJBsxsfCoq2DtDQuMES4vhnLuvXZit/asGtZG8edWTCydWeFWoBz9LYkJdQ== + dependencies: + commander "^5.0.0" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +trim-repeated@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" + integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= + dependencies: + escape-string-regexp "^1.0.2" + +truncate-html@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/truncate-html/-/truncate-html-1.0.3.tgz#0166dfc7890626130c2e4174c6b73d4d63993e5f" + integrity sha512-1o1prdRv+iehXcGwn29YgXU17DotHkr+OK3ijVEG7FGMwHNG9RyobXwimw6djDvbIc24rhmz3tjNNvNESjkNkQ== + dependencies: + "@types/cheerio" "^0.22.8" + cheerio "0.22.0" + +tslib@^1.9.0, tslib@^1.9.3: + version "1.13.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" + integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +unbzip2-stream@^1.0.9: + version "1.4.3" + resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +uri-js@^4.2.2: + version "4.4.0" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-parse@^1.4.3: + version "1.4.7" + resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" + integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.0.1, uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= + +worker-rpc@^0.1.0: + version "0.1.1" + resolved "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5" + integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg== + dependencies: + microevent.ts "~0.1.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +xml-js@^1.6.11: + version "1.6.11" + resolved "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + +xmlbuilder@^13.0.0: + version "13.0.2" + resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7" + integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ== + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yamljs@^0.2.1: + version "0.2.10" + resolved "https://registry.npmjs.org/yamljs/-/yamljs-0.2.10.tgz#481cc7c25ca73af59f591f0c96e3ce56c757a40f" + integrity sha1-SBzHwlynOvWfWR8MluPOVsdXpA8= + dependencies: + argparse "^1.0.7" + glob "^7.0.5" + +yargs@^2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-2.3.0.tgz#e900c87250ec5cd080db6009fe3dd63156f1d7fb" + integrity sha1-6QDIclDsXNCA22AJ/j3WMVbx1/s= + dependencies: + wordwrap "0.0.2" + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" diff --git a/mkdocs.yml b/mkdocs.yml index b12c8f81c7..a74ef5737f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -10,8 +10,10 @@ nav: - Vision: 'overview/vision.md' - The Spotify story: 'overview/background.md' - Strategies for adopting: 'overview/adopting.md' + - Logo assets: 'overview/logos.md' - Getting started: - - Running Backstage locally: 'getting-started/index.md' + - Getting Started: 'getting-started/index.md' + - Running Backstage locally: 'getting-started/running-backstage-locally.md' - Installation: 'getting-started/installation.md' - Local development: 'getting-started/development-environment.md' - Demo deployment: https://backstage-demo.roadie.io @@ -28,22 +30,25 @@ nav: - Overview: 'features/software-catalog/index.md' - System model: 'features/software-catalog/system-model.md' - YAML File Format: 'features/software-catalog/descriptor-format.md' + - Well-known Annotations: 'features/software-catalog/well-known-annotations.md' - Configuration: 'features/software-catalog/configuration.md' - Extending the model: 'features/software-catalog/extending-the-model.md' - External integrations: 'features/software-catalog/external-integrations.md' - API: 'features/software-catalog/api.md' - Software creation templates: - Overview: 'features/software-templates/index.md' + - Installation: 'features/software-templates/installation.md' - Adding templates: 'features/software-templates/adding-templates.md' - Extending the Scaffolder: - Overview: 'features/software-templates/extending/index.md' - Create your own Templater: 'features/software-templates/extending/create-your-own-templater.md' - Create your own Publisher: 'features/software-templates/extending/create-your-own-publisher.md' - Create your own Preparer: 'features/software-templates/extending/create-your-own-preparer.md' - - Docs-like-code: + - TechDocs: - Overview: 'features/techdocs/README.md' - Getting Started: 'features/techdocs/getting-started.md' - Concepts: 'features/techdocs/concepts.md' + - TechDocs Architecture: 'features/techdocs/architecture.md' - Creating and Publishing Documentation: 'features/techdocs/creating-and-publishing.md' - FAQ: 'features/techdocs/FAQ.md' - Plugins: diff --git a/package.json b/package.json index e6ee961701..c64b7f6951 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "start-backend": "yarn workspace example-backend start", "build": "lerna run build", "tsc": "tsc", + "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli clean && lerna run clean", "diff": "lerna run diff --", "test": "lerna run test --since origin/master -- --coverage", @@ -18,11 +19,12 @@ "lint:all": "lerna run lint --", "lint:type-deps": "node scripts/check-type-dependencies.js", "docgen": "lerna run docgen", - "docker-build": "yarn workspace example-app build && docker build . -t spotify/backstage", - "docker-build:all": "yarn tsc && yarn build && yarn docker-build && yarn workspace example-backend build-image", + "docker-build:app": "yarn workspace example-app build && docker build . -t spotify/backstage", + "docker-build": "yarn tsc && yarn workspace example-backend build-image", "create-plugin": "backstage-cli create-plugin", "remove-plugin": "backstage-cli remove-plugin", "release": "if [ \"$(git symbolic-ref --short HEAD)\" = master ]; then echo \"don't try to release master\"; exit 1; else lerna version --no-push --force-publish; fi", + "prettier:check": "prettier --check .", "lerna": "lerna", "storybook": "yarn workspace storybook start", "build-storybook": "yarn workspace storybook build-storybook" @@ -30,8 +32,7 @@ "workspaces": { "packages": [ "packages/*", - "plugins/*", - "microsite" + "plugins/*" ] }, "version": "1.0.0", diff --git a/packages/app/package.json b/packages/app/package.json index 1affbe4d09..bf0f340a40 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -11,6 +11,7 @@ "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/plugin-circleci": "^0.1.1-alpha.21", "@backstage/plugin-explore": "^0.1.1-alpha.21", + "@backstage/plugin-gcp-projects": "^0.1.1-alpha.21", "@backstage/plugin-github-actions": "^0.1.1-alpha.21", "@backstage/plugin-gitops-profiles": "^0.1.1-alpha.21", "@backstage/plugin-graphiql": "^0.1.1-alpha.21", @@ -26,7 +27,7 @@ "@backstage/plugin-welcome": "^0.1.1-alpha.21", "@backstage/test-utils": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@octokit/rest": "^18.0.0", "@roadiehq/backstage-plugin-github-pull-requests": "0.3.0", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index cb38726716..667b14366f 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -19,6 +19,7 @@ import { AlertDisplay, OAuthRequestDialog, SignInPage, + createRouteRef, } from '@backstage/core'; import React, { FC } from 'react'; import Root from './components/Root'; @@ -27,6 +28,11 @@ import { apis } from './apis'; import { hot } from 'react-hot-loader/root'; import { providers } from './identityProviders'; import { Router as CatalogRouter } from '@backstage/plugin-catalog'; +import { Router as DocsRouter } from '@backstage/plugin-techdocs'; +import { Router as GraphiQLRouter } from '@backstage/plugin-graphiql'; +import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; +import { Router as LighthouseRouter } from '@backstage/plugin-lighthouse'; +import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component'; import { Route, Routes, Navigate } from 'react-router'; import { EntityPage } from './components/catalog/EntityPage'; @@ -52,13 +58,29 @@ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); const deprecatedAppRoutes = app.getRoutes(); +const catalogRouteRef = createRouteRef({ + path: '/catalog', + title: 'Service Catalog', +}); + const AppRoutes = () => ( + } /> - + } /> + } + /> + } /> + } /> + } + /> {...deprecatedAppRoutes} ); diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index 387c9b95c5..7f57f6f970 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -15,66 +15,18 @@ */ import { - ApiRegistry, - alertApiRef, errorApiRef, - AlertApiForwarder, - ConfigApi, - ErrorApiForwarder, - ErrorAlerter, - featureFlagsApiRef, - FeatureFlags, discoveryApiRef, UrlPatternDiscovery, - GoogleAuth, - GithubAuth, - OAuth2, - OktaAuth, - GitlabAuth, - Auth0Auth, - MicrosoftAuth, - oauthRequestApiRef, - OAuthRequestManager, - googleAuthApiRef, githubAuthApiRef, - oauth2ApiRef, - oktaAuthApiRef, - gitlabAuthApiRef, - auth0AuthApiRef, - microsoftAuthApiRef, - storageApiRef, - WebStorage, - SamlAuth, - samlAuthApiRef, + createApiFactory, + configApiRef, } from '@backstage/core'; -import { - lighthouseApiRef, - LighthouseRestApi, -} from '@backstage/plugin-lighthouse'; - -import { techRadarApiRef, TechRadar } from '@backstage/plugin-tech-radar'; - -import { CircleCIApi, circleCIApiRef } from '@backstage/plugin-circleci'; -import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; - -import { gitOpsApiRef, GitOpsRestApi } from '@backstage/plugin-gitops-profiles'; import { graphQlBrowseApiRef, GraphQLEndpoints, } from '@backstage/plugin-graphiql'; -import { scaffolderApiRef, ScaffolderApi } from '@backstage/plugin-scaffolder'; -import { - techdocsStorageApiRef, - TechDocsStorageApi, -} from '@backstage/plugin-techdocs'; - -import { rollbarApiRef, RollbarClient } from '@backstage/plugin-rollbar'; -import { - GithubActionsClient, - githubActionsApiRef, -} from '@backstage/plugin-github-actions'; -import { jenkinsApiRef, JenkinsApi } from '@backstage/plugin-jenkins'; import { TravisCIApi, @@ -85,150 +37,36 @@ import { githubPullRequestsApiRef, } from '@roadiehq/backstage-plugin-github-pull-requests'; -export const apis = (config: ConfigApi) => { - // eslint-disable-next-line no-console - console.log(`Creating APIs for ${config.getString('app.title')}`); +export const apis = [ + // TODO(Rugvip): migrate to use /api + createApiFactory({ + api: discoveryApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => + UrlPatternDiscovery.compile( + `${configApi.getString('backend.baseUrl')}/{{ pluginId }}`, + ), + }), + createApiFactory({ + api: graphQlBrowseApiRef, + deps: { errorApi: errorApiRef, githubAuthApi: githubAuthApiRef }, + factory: ({ errorApi, githubAuthApi }) => + GraphQLEndpoints.from([ + GraphQLEndpoints.create({ + id: 'gitlab', + title: 'GitLab', + url: 'https://gitlab.com/api/graphql', + }), + GraphQLEndpoints.github({ + id: 'github', + title: 'GitHub', + errorApi, + githubAuthApi, + }), + ]), + }), - const backendUrl = config.getString('backend.baseUrl'); - const techdocsUrl = config.getString('techdocs.storageUrl'); - - const builder = ApiRegistry.builder(); - - const discoveryApi = builder.add( - discoveryApiRef, - UrlPatternDiscovery.compile(`${backendUrl}/{{ pluginId }}`), - ); - const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); - const errorApi = builder.add( - errorApiRef, - new ErrorAlerter(alertApi, new ErrorApiForwarder()), - ); - - builder.add(storageApiRef, WebStorage.create({ errorApi })); - builder.add( - circleCIApiRef, - new CircleCIApi(`${backendUrl}/proxy/circleci/api`), - ); - - builder.add(jenkinsApiRef, new JenkinsApi(`${backendUrl}/proxy/jenkins/api`)); - - builder.add(githubActionsApiRef, new GithubActionsClient()); - - builder.add(featureFlagsApiRef, new FeatureFlags()); - - builder.add(lighthouseApiRef, LighthouseRestApi.fromConfig(config)); - - builder.add(travisCIApiRef, new TravisCIApi()); - builder.add(githubPullRequestsApiRef, new GithubPullRequestsClient()); - - const oauthRequestApi = builder.add( - oauthRequestApiRef, - new OAuthRequestManager(), - ); - - builder.add( - googleAuthApiRef, - GoogleAuth.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - builder.add( - microsoftAuthApiRef, - MicrosoftAuth.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - const githubAuthApi = builder.add( - githubAuthApiRef, - GithubAuth.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - builder.add( - oktaAuthApiRef, - OktaAuth.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - builder.add( - gitlabAuthApiRef, - GitlabAuth.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - builder.add( - auth0AuthApiRef, - Auth0Auth.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - builder.add( - oauth2ApiRef, - OAuth2.create({ - discoveryApi, - oauthRequestApi, - }), - ); - - builder.add( - samlAuthApiRef, - SamlAuth.create({ - apiOrigin: backendUrl, - basePath: '/auth/', - }), - ); - - builder.add( - techRadarApiRef, - new TechRadar({ - width: 1500, - height: 800, - }), - ); - - builder.add(catalogApiRef, new CatalogClient({ discoveryApi })); - - builder.add(scaffolderApiRef, new ScaffolderApi({ discoveryApi })); - - builder.add(gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')); - - builder.add( - graphQlBrowseApiRef, - GraphQLEndpoints.from([ - GraphQLEndpoints.create({ - id: 'gitlab', - title: 'GitLab', - url: 'https://gitlab.com/api/graphql', - }), - GraphQLEndpoints.github({ - id: 'github', - title: 'GitHub', - errorApi, - githubAuthApi, - }), - ]), - ); - - builder.add(rollbarApiRef, new RollbarClient({ discoveryApi })); - - builder.add( - techdocsStorageApiRef, - new TechDocsStorageApi({ - apiOrigin: techdocsUrl, - }), - ); - - return builder.build(); -}; + // TODO: move to plugins + createApiFactory(travisCIApiRef, new TravisCIApi()), + createApiFactory(githubPullRequestsApiRef, new GithubPullRequestsClient()), +]; diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index ab95f623af..e91504d619 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -18,9 +18,7 @@ import React, { FC, useContext } from 'react'; import PropTypes from 'prop-types'; import { Link, makeStyles } from '@material-ui/core'; import HomeIcon from '@material-ui/icons/Home'; -import ExploreIcon from '@material-ui/icons/Explore'; import ExtensionIcon from '@material-ui/icons/Extension'; -import BuildIcon from '@material-ui/icons/BuildRounded'; import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; import MapIcon from '@material-ui/icons/MyLocation'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; @@ -91,7 +89,6 @@ const Root: FC<{}> = ({ children }) => ( {/* Global nav, not org-specific */} - @@ -99,7 +96,6 @@ const Root: FC<{}> = ({ children }) => ( - { + // This component is just an example of how you can implement your company's logic in entity page. + // You can for example enforce that all components of type 'service' should use GitHubActions + switch (true) { + case isGitHubActionsAvailable(entity): + return ; + case isCircleCIAvailable(entity): + return ; + default: + return ( + + No CI/CD is available for this entity. Check corresponding + annotations! + + ); + } +}; const OverviewContent = ({ entity }: { entity: Entity }) => ( @@ -41,7 +70,22 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( } + element={} + /> + } + /> + } + /> + } /> ); @@ -56,11 +100,20 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => ( } + element={} + /> + } + /> + } /> ); - const DefaultEntityPage = ({ entity }: { entity: Entity }) => ( ( title="Overview" element={} /> + } + /> ); diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts index f338c169b7..b36d0323e0 100644 --- a/packages/app/src/plugins.ts +++ b/packages/app/src/plugins.ts @@ -32,3 +32,4 @@ export { plugin as TravisCI } from '@roadiehq/backstage-plugin-travis-ci'; export { plugin as Jenkins } from '@backstage/plugin-jenkins'; export { plugin as ApiDocs } from '@backstage/plugin-api-docs'; export { plugin as GithubPullRequests } from '@roadiehq/backstage-plugin-github-pull-requests'; +export { plugin as GcpProjects } from '@backstage/plugin-gcp-projects'; diff --git a/packages/backend-common/src/middleware/requestLoggingHandler.ts b/packages/backend-common/src/middleware/requestLoggingHandler.ts index 6604ec245c..061dfbbd25 100644 --- a/packages/backend-common/src/middleware/requestLoggingHandler.ts +++ b/packages/backend-common/src/middleware/requestLoggingHandler.ts @@ -33,7 +33,7 @@ export function requestLoggingHandler(logger?: Logger): RequestHandler { return morgan('combined', { stream: { write(message: String) { - actualLogger.info(message); + actualLogger.info(message.trimRight()); }, }, }); diff --git a/packages/backend/Dockerfile b/packages/backend/Dockerfile index 8d17821101..a7bd814b19 100644 --- a/packages/backend/Dockerfile +++ b/packages/backend/Dockerfile @@ -2,10 +2,15 @@ FROM node:12 WORKDIR /usr/src/app +# Copy repo skeleton first, to avoid unnecessary docker cache invalidation. +# The skeleton contains the package.json of each package in the monorepo, +# and along with yarn.lock and the root package.json, that's enough to run yarn install. +ADD yarn.lock package.json skeleton.tar ./ + +RUN yarn install --frozen-lockfile --production + # This will copy the contents of the dist-workspace when running the build-image command. # Do not use this Dockerfile outside of that command, as it will copy in the source code instead. COPY . . -RUN yarn install --frozen-lockfile --production - CMD ["node", "packages/backend"] diff --git a/packages/backend/README.md b/packages/backend/README.md index 860520f4b5..c45a0d28d9 100644 --- a/packages/backend/README.md +++ b/packages/backend/README.md @@ -43,21 +43,13 @@ The backend starts up on port 7000 per default. ## Populating The Catalog -If you want to use the catalog functionality, you need to add so called locations -to the backend. These are places where the backend can find some entity descriptor -data to consume and serve. +If you want to use the catalog functionality, you need to add so called +locations to the backend. These are places where the backend can find some +entity descriptor data to consume and serve. For more information, see +[Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview#adding-components-to-the-catalog). -To get started, you can issue the following after starting the backend, from inside -the `plugins/catalog-backend` directory: - -```bash -yarn mock-data -``` - -You should then start seeing data on `localhost:7000/catalog/entities`. - -The catalog currently runs in-memory only, so feel free to try it out, but it will -need to be re-populated on next startup. +For convenience we already include some statically configured example locations +in `app-config.yaml` under `catalog.locations`. For local development you can override these in your own `app-config.local.yaml`. ## Authentication diff --git a/packages/backend/package.json b/packages/backend/package.json index 03d768ca0b..d944ac6535 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -10,7 +10,7 @@ }, "scripts": { "build": "backstage-cli backend:build", - "build-image": "backstage-cli backend:build-image example-backend", + "build-image": "backstage-cli backend:build-image --build --tag example-backend", "start": "backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", diff --git a/packages/catalog-model/examples/all-apis.yaml b/packages/catalog-model/examples/all-apis.yaml new file mode 100644 index 0000000000..33b000d1ae --- /dev/null +++ b/packages/catalog-model/examples/all-apis.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: example-apis + description: A collection of all Backstage example APIs +spec: + type: github + targets: + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/hello-world-api.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/streetlights-api.yaml diff --git a/packages/catalog-model/examples/all-components.yaml b/packages/catalog-model/examples/all-components.yaml new file mode 100644 index 0000000000..cad4eee044 --- /dev/null +++ b/packages/catalog-model/examples/all-components.yaml @@ -0,0 +1,16 @@ +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: example-components + description: A collection of all Backstage example components +spec: + type: github + targets: + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-order-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/podcast-api-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/queue-proxy-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/searcher-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-lib-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml + - https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml diff --git a/packages/cli-common/src/paths.ts b/packages/cli-common/src/paths.ts index 70761ad2d7..0db712e6cb 100644 --- a/packages/cli-common/src/paths.ts +++ b/packages/cli-common/src/paths.ts @@ -106,7 +106,10 @@ export function findOwnRootDir(ownDir: string) { */ export function findPaths(searchDir: string): Paths { const ownDir = findOwnDir(searchDir); - const targetDir = fs.realpathSync(process.cwd()); + // Drive letter can end up being lowercased here on Windows, bring back to uppercase for consistency + const targetDir = fs + .realpathSync(process.cwd()) + .replace(/^[a-z]:/, str => str.toUpperCase()); // Lazy load this as it will throw an error if we're not inside the Backstage repo. let ownRoot = ''; diff --git a/packages/cli/config/eslint.backend.js b/packages/cli/config/eslint.backend.js index 9b9efc7649..113ba55818 100644 --- a/packages/cli/config/eslint.backend.js +++ b/packages/cli/config/eslint.backend.js @@ -35,7 +35,7 @@ module.exports = { ecmaVersion: 2018, sourceType: 'module', }, - ignorePatterns: ['.eslintrc.js', '**/dist/**'], + ignorePatterns: ['.eslintrc.js', '**/dist/**', '**/dist-types/**'], rules: { 'no-console': 0, // Permitted in console programs 'new-cap': ['error', { capIsNew: false }], // Because Express constructs things e.g. like 'const r = express.Router()' diff --git a/packages/cli/config/eslint.js b/packages/cli/config/eslint.js index 792cd467d5..3e171d1f82 100644 --- a/packages/cli/config/eslint.js +++ b/packages/cli/config/eslint.js @@ -39,7 +39,7 @@ module.exports = { version: 'detect', }, }, - ignorePatterns: ['.eslintrc.js', '**/dist/**'], + ignorePatterns: ['.eslintrc.js', '**/dist/**', '**/dist-types/**'], rules: { 'import/newline-after-import': 'error', 'import/no-duplicates': 'warn', diff --git a/packages/cli/config/tsconfig.json b/packages/cli/config/tsconfig.json index ce031bc5e7..ef1a8df353 100644 --- a/packages/cli/config/tsconfig.json +++ b/packages/cli/config/tsconfig.json @@ -25,6 +25,7 @@ "removeComments": false, "resolveJsonModule": true, "sourceMap": false, + "skipLibCheck": true, "strict": true, "strictBindCallApply": true, "strictFunctionTypes": true, diff --git a/packages/cli/package.json b/packages/cli/package.json index 3b69e9b1b5..492cd3b958 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -41,7 +41,7 @@ "@spotify/eslint-config": "^7.0.1", "@sucrase/webpack-loader": "^2.0.0", "@svgr/plugin-jsx": "5.4.x", - "@svgr/plugin-svgo": "4.3.x", + "@svgr/plugin-svgo": "5.4.x", "@svgr/rollup": "5.4.x", "@svgr/webpack": "5.4.x", "@types/start-server-webpack-plugin": "^2.2.0", diff --git a/packages/cli/src/commands/backend/buildImage.ts b/packages/cli/src/commands/backend/buildImage.ts index 258ef102d7..b6e9da7b39 100644 --- a/packages/cli/src/commands/backend/buildImage.ts +++ b/packages/cli/src/commands/backend/buildImage.ts @@ -15,28 +15,65 @@ */ import fs from 'fs-extra'; +import { join as joinPath, relative as relativePath } from 'path'; import { createDistWorkspace } from '../../lib/packager'; import { paths } from '../../lib/paths'; import { run } from '../../lib/run'; +import { Command } from 'commander'; const PKG_PATH = 'package.json'; -export default async (imageTag: string) => { +export default async (cmd: Command) => { + // Skip the preparation steps if we're being asked for help + if (cmd.args.includes('--help')) { + await run('docker', ['image', 'build', '--help']); + return; + } + const pkgPath = paths.resolveTarget(PKG_PATH); const pkg = await fs.readJson(pkgPath); + const appConfigs = await findAppConfigs(); const tempDistWorkspace = await createDistWorkspace([pkg.name], { + buildDependencies: Boolean(cmd.build), files: [ 'package.json', 'yarn.lock', - 'app-config.yaml', + ...appConfigs, { src: paths.resolveTarget('Dockerfile'), dest: 'Dockerfile' }, ], + skeleton: 'skeleton.tar', }); console.log(`Dist workspace ready at ${tempDistWorkspace}`); - await run('docker', ['build', '.', '-t', imageTag], { + // all args are forwarded to docker build + await run('docker', ['image', 'build', '.', ...cmd.args], { cwd: tempDistWorkspace, }); await fs.remove(tempDistWorkspace); }; + +/** + * Find all config files to copy into the image + */ +async function findAppConfigs(): Promise { + const files = []; + + for (const name of await fs.readdir(paths.targetRoot)) { + if (name.startsWith('app-config.') && name.endsWith('.yaml')) { + files.push(name); + } + } + + if (paths.targetRoot !== paths.targetDir) { + const dirPath = relativePath(paths.targetRoot, paths.targetDir); + + for (const name of await fs.readdir(paths.targetDir)) { + if (name.startsWith('app-config.') && name.endsWith('.yaml')) { + files.push(joinPath(dirPath, name)); + } + } + } + + return files; +} diff --git a/packages/cli/src/commands/clean/clean.ts b/packages/cli/src/commands/clean/clean.ts index 2fa3e4a18f..bc2bcd23ac 100644 --- a/packages/cli/src/commands/clean/clean.ts +++ b/packages/cli/src/commands/clean/clean.ts @@ -19,5 +19,6 @@ import { paths } from '../../lib/paths'; export default async function clean() { await fs.remove(paths.resolveTarget('dist')); + await fs.remove(paths.resolveTarget('dist-types')); await fs.remove(paths.resolveTarget('coverage')); } diff --git a/packages/cli/src/commands/create-plugin/createPlugin.test.ts b/packages/cli/src/commands/create-plugin/createPlugin.test.ts index 57fa33d173..72b95b072c 100644 --- a/packages/cli/src/commands/create-plugin/createPlugin.test.ts +++ b/packages/cli/src/commands/create-plugin/createPlugin.test.ts @@ -59,7 +59,7 @@ describe('createPlugin', () => { await createTemporaryPluginFolder(tempDir); await movePlugin(tempDir, pluginDir, id); await expect(fs.pathExists(pluginDir)).resolves.toBe(true); - expect(pluginDir).toMatch(`/plugins\/${id}`); + expect(pluginDir).toMatch(path.join('', 'plugins', id)); } finally { await del(tempDir, { force: true }); await del(rootDir, { force: true }); diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts new file mode 100644 index 0000000000..4e031cdbc1 --- /dev/null +++ b/packages/cli/src/commands/index.ts @@ -0,0 +1,172 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CommanderStatic } from 'commander'; +import { exitWithError } from '../lib/errors'; + +export function registerCommands(program: CommanderStatic) { + program + .command('app:build') + .description('Build an app for a production release') + .option('--stats', 'Write bundle stats to output directory') + .action(lazy(() => import('./app/build').then(m => m.default))); + + program + .command('app:serve') + .description('Serve an app for local development') + .option('--check', 'Enable type checking and linting') + .action(lazy(() => import('./app/serve').then(m => m.default))); + + program + .command('backend:build') + .description('Build a backend plugin') + .action(lazy(() => import('./backend/build').then(m => m.default))); + + program + .command('backend:build-image') + .allowUnknownOption(true) + .helpOption(', --backstage-cli-help') // Let docker handle --help + .option('--build', 'Build packages before packing them into the image') + .description( + 'Bundles the package into a docker image. All extra args are forwarded to docker image build', + ) + .action(lazy(() => import('./backend/buildImage').then(m => m.default))); + + program + .command('backend:dev') + .description('Start local development server with HMR for the backend') + .option('--check', 'Enable type checking and linting') + .option('--inspect', 'Enable debugger') + .action(lazy(() => import('./backend/dev').then(m => m.default))); + + program + .command('app:diff') + .option('--check', 'Fail if changes are required') + .option('--yes', 'Apply all changes') + .description('Diff an existing app with the creation template') + .action(lazy(() => import('./app/diff').then(m => m.default))); + + program + .command('create-plugin') + .description('Creates a new plugin in the current repository') + .action( + lazy(() => import('./create-plugin/createPlugin').then(m => m.default)), + ); + + program + .command('remove-plugin') + .description('Removes plugin in the current repository') + .action( + lazy(() => import('./remove-plugin/removePlugin').then(m => m.default)), + ); + + program + .command('plugin:build') + .description('Build a plugin') + .action(lazy(() => import('./plugin/build').then(m => m.default))); + + program + .command('plugin:serve') + .description('Serves the dev/ folder of a plugin') + .option('--check', 'Enable type checking and linting') + .action(lazy(() => import('./plugin/serve').then(m => m.default))); + + program + .command('plugin:export') + .description('Exports the dev/ folder of a plugin') + .option('--stats', 'Write bundle stats to output directory') + .action(lazy(() => import('./plugin/export').then(m => m.default))); + + program + .command('plugin:diff') + .option('--check', 'Fail if changes are required') + .option('--yes', 'Apply all changes') + .description('Diff an existing plugin with the creation template') + .action(lazy(() => import('./plugin/diff').then(m => m.default))); + + program + .command('build') + .description('Build a package for publishing') + .option('--outputs ', 'List of formats to output [types,cjs,esm]') + .action(lazy(() => import('./build').then(m => m.default))); + + program + .command('lint') + .option( + '--format ', + 'Lint report output format', + 'eslint-formatter-friendly', + ) + .option('--fix', 'Attempt to automatically fix violations') + .description('Lint a package') + .action(lazy(() => import('./lint').then(m => m.default))); + + program + .command('test') + .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args + .helpOption(', --backstage-cli-help') // Let Jest handle help + .description('Run tests, forwarding args to Jest, defaulting to watch mode') + .action(lazy(() => import('./testCommand').then(m => m.default))); + + program + .command('config:print') + .option('--with-secrets', 'Include secrets in the printed configuration') + .option( + '--env ', + 'The environment to print configuration for [NODE_ENV or development]', + ) + .option( + '--format ', + 'Format to print the configuration in, either json or yaml [yaml]', + ) + .description('Print the app configuration for the current package') + .action(lazy(() => import('./config/print').then(m => m.default))); + + program + .command('prepack') + .description('Prepares a package for packaging before publishing') + .action(lazy(() => import('./pack').then(m => m.pre))); + + program + .command('postpack') + .description('Restores the changes made by the prepack command') + .action(lazy(() => import('./pack').then(m => m.post))); + + program + .command('clean') + .description('Delete cache directories') + .action(lazy(() => import('./clean/clean').then(m => m.default))); + + program + .command('build-workspace ...') + .description('Builds a temporary dist workspace from the provided packages') + .action(lazy(() => import('./buildWorkspace').then(m => m.default))); +} + +// Wraps an action function so that it always exits and handles errors +function lazy( + getActionFunc: () => Promise<(...args: any[]) => Promise>, +): (...args: any[]) => Promise { + return async (...args: any[]) => { + try { + const actionFunc = await getActionFunc(); + await actionFunc(...args); + process.exit(0); + } catch (error) { + exitWithError(error); + } + }; +} diff --git a/packages/cli/src/commands/remove-plugin/removePlugin.test.ts b/packages/cli/src/commands/remove-plugin/removePlugin.test.ts index 465260008d..3ffa8d63cf 100644 --- a/packages/cli/src/commands/remove-plugin/removePlugin.test.ts +++ b/packages/cli/src/commands/remove-plugin/removePlugin.test.ts @@ -39,7 +39,7 @@ const testPluginPackage = `${BACKSTAGE}/plugin-${testPluginName}`; const tempDir = path.join(os.tmpdir(), 'remove-plugin-test'); const removeEmptyLines = (file: string): string => - file.split('\n').filter(Boolean).join('\n'); + file.split(/\r?\n/).filter(Boolean).join('\n'); const createTestPackageFile = async ( testFilePath: string, @@ -66,7 +66,7 @@ const createTestPluginFile = async ( fse.copyFileSync(pluginsFilePath, testFilePath); const pluginNameCapitalized = testPluginName .split('-') - .map((name) => capitalize(name)) + .map(name => capitalize(name)) .join(''); const exportStatement = `export { default as ${pluginNameCapitalized}} from @backstage/plugin-${testPluginName}`; addExportStatement(testFilePath, exportStatement); @@ -100,7 +100,7 @@ describe('removePlugin', () => { const packageFileContent = removeEmptyLines( fse.readFileSync(packageFilePath, 'utf8'), ); - expect(testFileContent === packageFileContent).toBe(true); + expect(testFileContent).toBe(packageFileContent); } finally { fse.removeSync(testFilePath); } @@ -117,7 +117,7 @@ describe('removePlugin', () => { const pluginsFileContent = removeEmptyLines( fse.readFileSync(pluginsFilePaths, 'utf8'), ); - expect(testFileContent === pluginsFileContent).toBe(true); + expect(testFileContent).toBe(pluginsFileContent); } finally { fse.removeSync(testFilePath); } @@ -138,7 +138,7 @@ describe('removePlugin', () => { 'test@gmail.com', ]); await removePluginFromCodeOwners(testFilePath, testPluginName); - expect(testFileContent === codeOwnersFileContent).toBeTruthy(); + expect(testFileContent).toBe(codeOwnersFileContent); } finally { if (fse.existsSync(testFilePath)) fse.removeSync(testFilePath); } diff --git a/packages/cli/src/commands/remove-plugin/removePlugin.ts b/packages/cli/src/commands/remove-plugin/removePlugin.ts index b9bf1c4af3..1395384022 100644 --- a/packages/cli/src/commands/remove-plugin/removePlugin.ts +++ b/packages/cli/src/commands/remove-plugin/removePlugin.ts @@ -84,7 +84,7 @@ const removeAllStatementsContainingID = async (file: string, ID: string) => { const originalContent = await fse.readFile(file, 'utf8'); const contentAfterRemoval = originalContent .split('\n') - .filter((statement) => !statement.includes(`${ID}`)) // get rid of lines with pluginName + .filter(statement => !statement.includes(`${ID}`)) // get rid of lines with pluginName .join('\n'); if (originalContent !== contentAfterRemoval) { await fse.writeFile(file, contentAfterRemoval, 'utf8'); @@ -100,7 +100,7 @@ export const removeReferencesFromPluginsFile = async ( ) => { const pluginNameCapitalized = pluginName .split('-') - .map((name) => capitalize(name)) + .map(name => capitalize(name)) .join(''); await Task.forItem('removing', 'export references', async () => { diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 9fb909592b..e278164f4c 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -18,151 +18,12 @@ import program from 'commander'; import chalk from 'chalk'; import { exitWithError } from './lib/errors'; import { version } from './lib/version'; +import { registerCommands } from './commands'; const main = (argv: string[]) => { program.name('backstage-cli').version(version); - program - .command('app:build') - .description('Build an app for a production release') - .option('--stats', 'Write bundle stats to output directory') - .action(lazyAction(() => import('./commands/app/build'), 'default')); - - program - .command('app:serve') - .description('Serve an app for local development') - .option('--check', 'Enable type checking and linting') - .action(lazyAction(() => import('./commands/app/serve'), 'default')); - - program - .command('backend:build') - .description('Build a backend plugin') - .action(lazyAction(() => import('./commands/backend/build'), 'default')); - - program - .command('backend:build-image ') - .description( - 'Builds a docker image from the package, with all local deps included', - ) - .action( - lazyAction(() => import('./commands/backend/buildImage'), 'default'), - ); - - program - .command('backend:dev') - .description('Start local development server with HMR for the backend') - .option('--check', 'Enable type checking and linting') - .option('--inspect', 'Enable debugger') - .action(lazyAction(() => import('./commands/backend/dev'), 'default')); - - program - .command('app:diff') - .option('--check', 'Fail if changes are required') - .option('--yes', 'Apply all changes') - .description('Diff an existing app with the creation template') - .action(lazyAction(() => import('./commands/app/diff'), 'default')); - - program - .command('create-plugin') - .description('Creates a new plugin in the current repository') - .action( - lazyAction( - () => import('./commands/create-plugin/createPlugin'), - 'default', - ), - ); - - program - .command('remove-plugin') - .description('Removes plugin in the current repository') - .action( - lazyAction( - () => import('./commands/remove-plugin/removePlugin'), - 'default', - ), - ); - - program - .command('plugin:build') - .description('Build a plugin') - .action(lazyAction(() => import('./commands/plugin/build'), 'default')); - - program - .command('plugin:serve') - .description('Serves the dev/ folder of a plugin') - .option('--check', 'Enable type checking and linting') - .action(lazyAction(() => import('./commands/plugin/serve'), 'default')); - - program - .command('plugin:export') - .description('Exports the dev/ folder of a plugin') - .option('--stats', 'Write bundle stats to output directory') - .action(lazyAction(() => import('./commands/plugin/export'), 'default')); - - program - .command('plugin:diff') - .option('--check', 'Fail if changes are required') - .option('--yes', 'Apply all changes') - .description('Diff an existing plugin with the creation template') - .action(lazyAction(() => import('./commands/plugin/diff'), 'default')); - - program - .command('build') - .description('Build a package for publishing') - .option('--outputs ', 'List of formats to output [types,cjs,esm]') - .action(lazyAction(() => import('./commands/build'), 'default')); - - program - .command('lint') - .option( - '--format ', - 'Lint report output format', - 'eslint-formatter-friendly', - ) - .option('--fix', 'Attempt to automatically fix violations') - .description('Lint a package') - .action(lazyAction(() => import('./commands/lint'), 'default')); - - program - .command('test') - .allowUnknownOption(true) // Allows the command to run, but we still need to parse raw args - .helpOption(', --backstage-cli-help') // Let Jest handle help - .description('Run tests, forwarding args to Jest, defaulting to watch mode') - .action(lazyAction(() => import('./commands/testCommand'), 'default')); - - program - .command('config:print') - .option('--with-secrets', 'Include secrets in the printed configuration') - .option( - '--env ', - 'The environment to print configuration for [NODE_ENV or development]', - ) - .option( - '--format ', - 'Format to print the configuration in, either json or yaml [yaml]', - ) - .description('Print the app configuration for the current package') - .action(lazyAction(() => import('./commands/config/print'), 'default')); - - program - .command('prepack') - .description('Prepares a package for packaging before publishing') - .action(lazyAction(() => import('./commands/pack'), 'pre')); - - program - .command('postpack') - .description('Restores the changes made by the prepack command') - .action(lazyAction(() => import('./commands/pack'), 'post')); - - program - .command('clean') - .description('Delete cache directories') - .action(lazyAction(() => import('./commands/clean/clean'), 'default')); - - program - .command('build-workspace ...') - .description('Builds a temporary dist workspace from the provided packages') - .action(lazyAction(() => import('./commands/buildWorkspace'), 'default')); + registerCommands(program); program.on('command:*', () => { console.log(); @@ -181,25 +42,6 @@ const main = (argv: string[]) => { program.parse(argv); }; -// Wraps an action function so that it always exits and handles errors -function lazyAction( - actionRequireFunc: () => Promise< - { [name in Export]: (...args: T) => Promise } - >, - exportName: Export, -): (...args: T) => Promise { - return async (...args: T) => { - try { - const module = await actionRequireFunc(); - const actionFunc = module[exportName]; - await actionFunc(...args); - process.exit(0); - } catch (error) { - exitWithError(error); - } - }; -} - process.on('unhandledRejection', rejection => { if (rejection instanceof Error) { exitWithError(rejection); diff --git a/packages/cli/src/lib/builder/config.ts b/packages/cli/src/lib/builder/config.ts index bc689a3eb0..e91fc32633 100644 --- a/packages/cli/src/lib/builder/config.ts +++ b/packages/cli/src/lib/builder/config.ts @@ -37,7 +37,7 @@ export const makeConfigs = async ( options: BuildOptions, ): Promise => { const typesInput = paths.resolveTargetRoot( - 'dist', + 'dist-types', relativePath(paths.targetRoot, paths.targetDir), 'src/index.d.ts', ); diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 4c4a424d08..e1fb560e22 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -42,7 +42,11 @@ export async function serveBundle(options: ServeOptions) { contentBase: paths.targetPublic, contentBasePublicPath: config.output?.publicPath, publicPath: config.output?.publicPath, - historyApiFallback: true, + historyApiFallback: { + // Paths with dots should still use the history fallback. + // See https://github.com/facebookincubator/create-react-app/issues/387. + disableDotRule: true, + }, clientLogLevel: 'warning', stats: 'errors-warnings', https: url.protocol === 'https:', diff --git a/packages/cli/src/lib/packager/index.ts b/packages/cli/src/lib/packager/index.ts index fda85dd68a..564317e46a 100644 --- a/packages/cli/src/lib/packager/index.ts +++ b/packages/cli/src/lib/packager/index.ts @@ -15,10 +15,14 @@ */ import fs from 'fs-extra'; -import { resolve as resolvePath, relative as relativePath } from 'path'; +import { + join as joinPath, + resolve as resolvePath, + relative as relativePath, +} from 'path'; import { paths } from '../paths'; import { run } from '../run'; -import tar from 'tar'; +import tar, { CreateOptions } from 'tar'; import { tmpdir } from 'os'; type LernaPackage = { @@ -48,6 +52,17 @@ type Options = { * Defaults to ['yarn.lock', 'package.json']. */ files?: FileEntry[]; + + /** + * If set to true, the target packages are built before they are packaged into the workspace. + */ + buildDependencies?: boolean; + + /** + * If set, creates a skeleton tarball that contains all package.json files + * with the same structure as the workspace dir. + */ + skeleton?: 'skeleton.tar'; }; /** @@ -68,6 +83,13 @@ export async function createDistWorkspace( const targets = await findTargetPackages(packageNames); + if (options.buildDependencies) { + const scopeArgs = targets.flatMap(target => ['--scope', target.name]); + await run('yarn', ['lerna', 'run', ...scopeArgs, 'build'], { + cwd: paths.targetRoot, + }); + } + await moveToDistWorkspace(targetDir, targets); const files: FileEntry[] = options.files ?? ['yarn.lock', 'package.json']; @@ -77,6 +99,24 @@ export async function createDistWorkspace( const dest = typeof file === 'string' ? file : file.dest; await fs.copy(paths.resolveTargetRoot(src), resolvePath(targetDir, dest)); } + + if (options.skeleton) { + const skeletonFiles = targets.map(target => { + const dir = relativePath(paths.targetRoot, target.location); + return joinPath(dir, 'package.json'); + }); + + await tar.create( + { + file: resolvePath(targetDir, options.skeleton), + cwd: targetDir, + portable: true, + noMtime: true, + } as CreateOptions & { noMtime: boolean }, + skeletonFiles, + ); + } + return targetDir; } diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index 38d4e41b5b..dbfb639b16 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -23,7 +23,7 @@ "dependencies": { "@backstage/core": "^{{backstageVersion}}", "@backstage/theme": "^{{backstageVersion}}", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "react": "^16.13.1", diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 92d20ef1e7..592b8eefb3 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -37,8 +37,10 @@ }, "devDependencies": { "@types/jest": "^26.0.7", + "@types/mock-fs": "^4.10.0", "@types/node": "^12.0.0", - "@types/yup": "^0.28.2" + "@types/yup": "^0.28.2", + "mock-fs": "^4.13.0" }, "files": [ "dist" diff --git a/packages/config-loader/src/lib/resolver.test.ts b/packages/config-loader/src/lib/resolver.test.ts index c804a6cef3..9fd71f2486 100644 --- a/packages/config-loader/src/lib/resolver.test.ts +++ b/packages/config-loader/src/lib/resolver.test.ts @@ -14,46 +14,48 @@ * limitations under the License. */ -const pathExists = jest.fn(); - -jest.mock('fs-extra', () => ({ pathExists })); - +import mockFs from 'mock-fs'; import { resolveStaticConfig } from './resolver'; +function normalizePaths(paths: string[]) { + return paths.map(p => + p + .replace(/^[a-z]:/i, '') + .split('\\') + .join('/'), + ); +} + describe('resolveStaticConfig', () => { afterEach(() => { - jest.resetAllMocks(); + mockFs.restore(); }); it('should resolve no files for empty roots', async () => { + mockFs({}); const resolved = await resolveStaticConfig({ env: 'development', rootPaths: [], }); - expect(resolved).toEqual([]); - expect(pathExists).not.toHaveBeenCalled(); + expect(normalizePaths(resolved)).toEqual([]); }); it('should resolve a single app-config', async () => { - pathExists.mockImplementation(async (path: string) => - ['/repo/app-config.yaml'].includes(path), - ); + mockFs({ '/repo/app-config.yaml': '' }); const resolved = await resolveStaticConfig({ env: 'development', rootPaths: ['/repo'], }); - expect(resolved).toEqual(['/repo/app-config.yaml']); - expect(pathExists).toHaveBeenCalledTimes(4); + expect(normalizePaths(resolved)).toEqual(['/repo/app-config.yaml']); }); it('should resolve a app-configs in different directories', async () => { - pathExists.mockImplementation(async (path: string) => - ['/repo/app-config.yaml', '/repo/packages/a/app-config.yaml'].includes( - path, - ), - ); + mockFs({ + '/repo/app-config.yaml': '', + '/repo/packages/a/app-config.yaml': '', + }); const resolved = await resolveStaticConfig({ env: 'development', rootPaths: [ @@ -64,53 +66,54 @@ describe('resolveStaticConfig', () => { ], }); - expect(resolved).toEqual([ + expect(normalizePaths(resolved)).toEqual([ '/repo/app-config.yaml', '/repo/packages/a/app-config.yaml', ]); - expect(pathExists).toHaveBeenCalledTimes(16); }); it('should resolve env and local configs', async () => { - pathExists.mockImplementation(async (path: string) => - [ - '/repo/app-config.yaml', - '/repo/app-config.local.yaml', - '/repo/app-config.production.yaml', - '/repo/app-config.production.local.yaml', - '/repo/app-config.development.local.yaml', - '/repo/packages/a/app-config.development.yaml', - '/repo/packages/a/app-config.local.yaml', - ].includes(path), - ); + mockFs({ + '/repo/app-config.yaml': '', + '/repo/app-config.local.yaml': '', + '/repo/app-config.production.yaml': '', + '/repo/app-config.production.local.yaml': '', + '/repo/app-config.development.local.yaml': '', + '/repo/packages/a/app-config.development.yaml': '', + '/repo/packages/a/app-config.local.yaml': '', + }); const resolved = await resolveStaticConfig({ env: 'development', rootPaths: ['/repo', '/repo/packages/a'], }); - expect(resolved).toEqual([ + expect(normalizePaths(resolved)).toEqual([ '/repo/app-config.yaml', '/repo/app-config.local.yaml', '/repo/app-config.development.local.yaml', '/repo/packages/a/app-config.local.yaml', '/repo/packages/a/app-config.development.yaml', ]); - expect(pathExists).toHaveBeenCalledTimes(8); }); it('resolves suffixed configs in the correct order', async () => { - pathExists.mockImplementation(async () => true); + mockFs({ + '/repo/app-config.yaml': '', + '/repo/app-config.local.yaml': '', + '/repo/app-config.production.yaml': '', + '/repo/app-config.production.local.yaml': '', + }); + const resolved = await resolveStaticConfig({ env: 'production', rootPaths: ['/repo'], }); - expect(resolved).toEqual([ + expect(normalizePaths(resolved)).toEqual([ '/repo/app-config.yaml', '/repo/app-config.local.yaml', '/repo/app-config.production.yaml', '/repo/app-config.production.local.yaml', ]); - expect(pathExists).toHaveBeenCalledTimes(4); }); }); diff --git a/packages/config-loader/src/loader.test.ts b/packages/config-loader/src/loader.test.ts index 4a7c9f238c..a7547ee8fb 100644 --- a/packages/config-loader/src/loader.test.ts +++ b/packages/config-loader/src/loader.test.ts @@ -15,45 +15,30 @@ */ import { loadConfig } from './loader'; - -jest.mock('fs-extra', () => { - const mockFiles: { [path in string]: string } = { - '/root/app-config.yaml': ` - app: - title: Example App - sessionKey: - $secret: - file: secrets/session-key.txt - `, - '/root/app-config.development.yaml': ` - app: - sessionKey: development-key - `, - '/root/secrets/session-key.txt': 'abc123', - '/secret-port/app-config.yaml': ` - backend: - listen: - port: - $secret: - file: secrets/port.txt - `, - '/secret-port/secrets/port.txt': '12345', - }; - - return { - async readFile(path: string) { - if (path in mockFiles) { - return mockFiles[path]; - } - throw new Error(`File not found, ${path}`); - }, - async pathExists(path: string) { - return path in mockFiles; - }, - }; -}); +import mockFs from 'mock-fs'; describe('loadConfig', () => { + beforeAll(() => { + mockFs({ + '/root/app-config.yaml': ` + app: + title: Example App + sessionKey: + $secret: + file: secrets/session-key.txt + `, + '/root/app-config.development.yaml': ` + app: + sessionKey: development-key + `, + '/root/secrets/session-key.txt': 'abc123', + }); + }); + + afterAll(() => { + mockFs.restore(); + }); + it('loads config without secrets', async () => { await expect( loadConfig({ diff --git a/packages/core-api/package.json b/packages/core-api/package.json index a5e23796cd..191394e536 100644 --- a/packages/core-api/package.json +++ b/packages/core-api/package.json @@ -31,7 +31,7 @@ "dependencies": { "@backstage/config": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@types/react": "^16.9", "prop-types": "^15.7.2", diff --git a/packages/core-api/src/apis/ApiFactoryRegistry.test.ts b/packages/core-api/src/apis/ApiFactoryRegistry.test.ts new file mode 100644 index 0000000000..9f44adaef3 --- /dev/null +++ b/packages/core-api/src/apis/ApiFactoryRegistry.test.ts @@ -0,0 +1,70 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ApiFactoryRegistry } from './ApiFactoryRegistry'; +import { createApiRef } from './ApiRef'; + +const aRef = createApiRef({ id: 'a', description: '' }); +const aFactory1 = { api: aRef, deps: {}, factory: () => 1 }; +const aFactory2 = { api: aRef, deps: {}, factory: () => 2 }; +const bRef = createApiRef({ id: 'b', description: '' }); +const bFactory = { api: bRef, deps: {}, factory: () => 'x' }; +const cRef = createApiRef({ id: 'c', description: '' }); +const cFactory = { api: cRef, deps: {}, factory: () => 'y' }; + +describe('ApiFactoryRegistry', () => { + it('should be empty when created', () => { + const registry = new ApiFactoryRegistry(); + expect(registry.getAllApis()).toEqual(new Set()); + }); + + it('should register a factory', () => { + const registry = new ApiFactoryRegistry(); + expect(registry.register('default', aFactory1)).toBe(true); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.getAllApis()).toEqual(new Set([aRef])); + }); + + it('should prioritize factories based on scope', () => { + const registry = new ApiFactoryRegistry(); + expect(registry.register('default', aFactory1)).toBe(true); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.register('default', aFactory2)).toBe(false); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.register('app', aFactory2)).toBe(true); + expect(registry.get(aRef)).toBe(aFactory2); + expect(registry.register('default', aFactory1)).toBe(false); + expect(registry.get(aRef)).toBe(aFactory2); + expect(registry.register('static', aFactory1)).toBe(true); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.register('static', aFactory2)).toBe(false); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.register('app', aFactory2)).toBe(false); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.getAllApis()).toEqual(new Set([aRef])); + }); + + it('should register multiple factories without conflict', () => { + const registry = new ApiFactoryRegistry(); + expect(registry.register('static', aFactory1)).toBe(true); + expect(registry.register('default', bFactory)).toBe(true); + expect(registry.register('app', cFactory)).toBe(true); + expect(registry.get(aRef)).toBe(aFactory1); + expect(registry.get(bRef)).toBe(bFactory); + expect(registry.get(cRef)).toBe(cFactory); + expect(registry.getAllApis()).toEqual(new Set([aRef, bRef, cRef])); + }); +}); diff --git a/packages/core-api/src/apis/ApiFactoryRegistry.ts b/packages/core-api/src/apis/ApiFactoryRegistry.ts new file mode 100644 index 0000000000..0d36e6c550 --- /dev/null +++ b/packages/core-api/src/apis/ApiFactoryRegistry.ts @@ -0,0 +1,83 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + ApiFactoryHolder, + ApiFactory, + AnyApiRef, + AnyApiFactory, +} from './types'; +import { ApiRef } from './ApiRef'; + +type ApiFactoryScope = + | 'default' // Default factories registered by core and plugins + | 'app' // Factories registered in the app, overriding default ones + | 'static'; // APIs that can't be overridden, e.g. config + +enum ScopePriority { + default = 10, + app = 50, + static = 100, +} + +type FactoryTuple = { + priority: number; + factory: AnyApiFactory; +}; + +/** + * ApiFactoryRegistry is an ApiFactoryHolder implementation that enables + * registration of API Factories with different scope. + * + * Each scope has an assigned priority, where factories registered with + * higher priority scopes override ones with lower priority. + */ +export class ApiFactoryRegistry implements ApiFactoryHolder { + private readonly factories = new Map(); + + /** + * Register a new API factory. Returns true if the factory was added + * to the registry. + * + * A factory will not be added to the registry if there is already + * an existing factory with the same or higher priority. + */ + register( + scope: ApiFactoryScope, + factory: ApiFactory, + ) { + const priority = ScopePriority[scope]; + const existing = this.factories.get(factory.api); + if (existing && existing.priority >= priority) { + return false; + } + + this.factories.set(factory.api, { priority, factory }); + return true; + } + + get(api: ApiRef): ApiFactory | undefined { + const tuple = this.factories.get(api); + if (!tuple) { + return undefined; + } + return tuple.factory as ApiFactory; + } + + getAllApis(): Set { + return new Set(this.factories.keys()); + } +} diff --git a/packages/core-api/src/apis/ApiResolver.test.ts b/packages/core-api/src/apis/ApiResolver.test.ts new file mode 100644 index 0000000000..3cd40f289e --- /dev/null +++ b/packages/core-api/src/apis/ApiResolver.test.ts @@ -0,0 +1,177 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ApiResolver } from './ApiResolver'; +import { createApiRef } from './ApiRef'; +import { ApiFactoryRegistry } from './ApiFactoryRegistry'; + +const aRef = createApiRef({ id: 'a', description: '' }); +const bRef = createApiRef({ id: 'b', description: '' }); +const cRef = createApiRef<{ x: string }>({ id: 'c', description: '' }); + +function createRegistry() { + const registry = new ApiFactoryRegistry(); + registry.register('default', { + api: aRef, + deps: {}, + factory: () => 1, + }); + registry.register('default', { + api: bRef, + deps: {}, + factory: () => 'b', + }); + registry.register('default', { + api: cRef, + deps: { b: bRef }, + factory: ({ b }) => ({ x: 'x', b }), + }); + return registry; +} + +function createLongCyclicRegistry() { + const registry = new ApiFactoryRegistry(); + registry.register('default', { + api: aRef, + deps: { b: bRef }, + factory: () => 1, + }); + registry.register('default', { + api: bRef, + deps: { c: cRef }, + factory: () => 'b', + }); + registry.register('default', { + api: cRef, + deps: { a: aRef }, + factory: () => ({ x: 'x' }), + }); + return registry; +} + +function createShortCyclicRegistry() { + const registry = new ApiFactoryRegistry(); + registry.register('default', { + api: aRef, + deps: { a: aRef }, + factory: () => 1, + }); + registry.register('default', { + api: bRef, + deps: { c: cRef }, + factory: () => 'b', + }); + registry.register('default', { + api: cRef, + deps: { b: bRef }, + factory: () => ({ x: 'x' }), + }); + return registry; +} + +describe('ApiResolver', () => { + it('should be created empty', () => { + const resolver = new ApiResolver(new ApiFactoryRegistry()); + expect(resolver.get(aRef)).toBe(undefined); + expect(resolver.get(bRef)).toBe(undefined); + expect(resolver.get(cRef)).toBe(undefined); + }); + + it('should instantiate APIs', () => { + const resolver = new ApiResolver(createRegistry()); + expect(resolver.get(aRef)).toBe(1); + expect(resolver.get(bRef)).toBe('b'); + expect(resolver.get(cRef)).toEqual({ x: 'x', b: 'b' }); + expect(resolver.get(cRef)).toBe(resolver.get(cRef)); + }); + + it('should detect long dependency cycles', () => { + const resolver = new ApiResolver(createLongCyclicRegistry()); + expect(() => resolver.get(aRef)).toThrow( + 'Circular dependency of api factory for apiRef{a}', + ); + // Second call for same ref should still throw + expect(() => resolver.get(aRef)).toThrow( + 'Circular dependency of api factory for apiRef{a}', + ); + expect(() => resolver.get(bRef)).toThrow( + 'Circular dependency of api factory for apiRef{b}', + ); + expect(() => resolver.get(cRef)).toThrow( + 'Circular dependency of api factory for apiRef{c}', + ); + }); + + it('should detect short dependency cycles', () => { + const resolver = new ApiResolver(createShortCyclicRegistry()); + expect(() => resolver.get(aRef)).toThrow( + 'Circular dependency of api factory for apiRef{a}', + ); + expect(() => resolver.get(bRef)).toThrow( + 'Circular dependency of api factory for apiRef{b}', + ); + expect(() => resolver.get(cRef)).toThrow( + 'Circular dependency of api factory for apiRef{c}', + ); + }); + + it('should validate a factory holder', () => { + expect(() => { + ApiResolver.validateFactories(createRegistry(), [aRef, bRef, cRef]); + }).not.toThrow(); + }); + + it('should find dependency cycles with validation', () => { + const short = createShortCyclicRegistry(); + expect(() => + ApiResolver.validateFactories(short, short.getAllApis()), + ).toThrow('Circular dependency of api factory for apiRef{a}'); + expect(() => ApiResolver.validateFactories(short, [bRef])).toThrow( + 'Circular dependency of api factory for apiRef{b}', + ); + expect(() => ApiResolver.validateFactories(short, [cRef])).toThrow( + 'Circular dependency of api factory for apiRef{c}', + ); + + const long = createLongCyclicRegistry(); + expect(() => + ApiResolver.validateFactories(long, long.getAllApis()), + ).toThrow('Circular dependency of api factory for apiRef{a}'); + expect(() => ApiResolver.validateFactories(long, [bRef])).toThrow( + 'Circular dependency of api factory for apiRef{b}', + ); + expect(() => ApiResolver.validateFactories(long, [cRef])).toThrow( + 'Circular dependency of api factory for apiRef{c}', + ); + }); + + it('should only call factory func once', () => { + const registry = new ApiFactoryRegistry(); + const factory = jest.fn().mockReturnValue(2); + registry.register('default', { + api: aRef, + deps: {}, + factory, + }); + + const resolver = new ApiResolver(registry); + expect(factory).toHaveBeenCalledTimes(0); + expect(resolver.get(aRef)).toBe(2); + expect(factory).toHaveBeenCalledTimes(1); + expect(resolver.get(aRef)).toBe(2); + expect(factory).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/core-api/src/apis/ApiTestRegistry.ts b/packages/core-api/src/apis/ApiResolver.ts similarity index 57% rename from packages/core-api/src/apis/ApiTestRegistry.ts rename to packages/core-api/src/apis/ApiResolver.ts index 7aed3c7917..cb65186a37 100644 --- a/packages/core-api/src/apis/ApiTestRegistry.ts +++ b/packages/core-api/src/apis/ApiResolver.ts @@ -15,38 +15,54 @@ */ import { ApiRef } from './ApiRef'; -import { TypesToApiRefs, AnyApiRef, ApiHolder, ApiFactory } from './types'; +import { + ApiHolder, + ApiFactoryHolder, + AnyApiRef, + TypesToApiRefs, +} from './types'; -export class ApiTestRegistry implements ApiHolder { +export class ApiResolver implements ApiHolder { private readonly apis = new Map(); - private factories = new Map< - AnyApiRef, - ApiFactory - >(); - private savedFactories = new Map< - AnyApiRef, - ApiFactory - >(); + + /** + * Validate factories by making sure that each of the apis can be created + * without hitting any circular dependencies. + */ + static validateFactories( + factories: ApiFactoryHolder, + apis: Iterable, + ) { + for (const api of apis) { + const heap = [api]; + const allDeps = new Set(); + + while (heap.length) { + const apiRef = heap.shift()!; + const factory = factories.get(apiRef); + if (!factory) { + continue; + } + + for (const dep of Object.values(factory.deps)) { + if (dep === api) { + throw new Error(`Circular dependency of api factory for ${api}`); + } + if (!allDeps.has(dep)) { + allDeps.add(dep); + heap.push(dep); + } + } + } + } + } + + constructor(private readonly factories: ApiFactoryHolder) {} get(ref: ApiRef): T | undefined { return this.load(ref); } - register(factory: ApiFactory): ApiTestRegistry { - this.factories.set(factory.implements, factory); - return this; - } - - reset() { - this.factories = this.savedFactories; - this.apis.clear(); - } - - save(): ApiTestRegistry { - this.savedFactories = new Map(this.factories); - return this; - } - private load(ref: ApiRef, loading: AnyApiRef[] = []): T | undefined { const impl = this.apis.get(ref); if (impl) { @@ -58,16 +74,11 @@ export class ApiTestRegistry implements ApiHolder { return undefined; } - if (loading.includes(factory.implements)) { - throw new Error( - `Circular dependency of api factory for ${factory.implements}`, - ); + if (loading.includes(factory.api)) { + throw new Error(`Circular dependency of api factory for ${factory.api}`); } - const deps = this.loadDeps(ref, factory.deps, [ - ...loading, - factory.implements, - ]); + const deps = this.loadDeps(ref, factory.deps, [...loading, factory.api]); const api = factory.factory(deps); this.apis.set(ref, api); return api as T; diff --git a/packages/core-api/src/apis/ApiTestRegistry.test.ts b/packages/core-api/src/apis/ApiTestRegistry.test.ts deleted file mode 100644 index fa42e64707..0000000000 --- a/packages/core-api/src/apis/ApiTestRegistry.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ApiTestRegistry } from './ApiTestRegistry'; -import { createApiRef } from './ApiRef'; - -describe('ApiTestRegistry', () => { - const aRef = createApiRef({ id: 'a', description: '' }); - const bRef = createApiRef({ id: 'b', description: '' }); - const cRef = createApiRef({ id: 'c', description: '' }); - - it('should be created', () => { - const registry = new ApiTestRegistry(); - expect(registry.get(aRef)).toBe(undefined); - expect(registry.get(bRef)).toBe(undefined); - expect(registry.get(cRef)).toBe(undefined); - }); - - it('should register a factory', () => { - const registry = new ApiTestRegistry(); - registry.register({ implements: aRef, deps: {}, factory: () => 3 }); - expect(registry.get(aRef)).toBe(3); - expect(registry.get(bRef)).toBe(undefined); - expect(registry.get(cRef)).toBe(undefined); - }); - - it('should remove factories when resetting', () => { - const registry = new ApiTestRegistry(); - registry.register({ implements: aRef, deps: {}, factory: () => 3 }); - expect(registry.get(aRef)).toBe(3); - registry.reset(); - expect(registry.get(aRef)).toBe(undefined); - }); - - it('should keep saved factories when resetting', () => { - const registry = new ApiTestRegistry(); - registry.register({ implements: aRef, deps: {}, factory: () => 3 }); - registry.save(); - registry.register({ implements: bRef, deps: {}, factory: () => 'x' }); - expect(registry.get(aRef)).toBe(3); - expect(registry.get(bRef)).toBe('x'); - registry.reset(); - expect(registry.get(aRef)).toBe(3); - expect(registry.get(bRef)).toBe(undefined); - }); - - it('should register factories with dependencies', () => { - // 100% coverage + happy typescript = hasOwnProperty + this atrocity - const cDeps = Object.create( - { c: cRef }, - { a: { enumerable: true, value: aRef } }, - ); - cDeps.b = bRef; - - const registry = new ApiTestRegistry(); - registry.register({ implements: aRef, deps: {}, factory: () => 3 }); - registry.register({ - implements: bRef, - deps: { dep: aRef }, - factory: ({ dep }) => `hello ${dep}`, - }); - registry.register({ - implements: cRef, - deps: cDeps, - factory: ({ a, b }) => b.repeat(a), - }); - expect(registry.get(aRef)).toBe(3); - expect(registry.get(bRef)).toBe('hello 3'); - expect(registry.get(cRef)).toBe('hello 3hello 3hello 3'); - }); - - it('should not allow cyclic dependencies', () => { - const registry = new ApiTestRegistry(); - registry.register({ - implements: aRef, - deps: { b: bRef }, - factory: () => 1, - }); - registry.register({ - implements: bRef, - deps: { c: cRef }, - factory: () => 'b', - }); - registry.register({ - implements: cRef, - deps: { a: aRef }, - factory: () => 'c', - }); - expect(() => registry.get(aRef)).toThrow( - 'Circular dependency of api factory for apiRef{a}', - ); - expect(() => registry.get(bRef)).toThrow( - 'Circular dependency of api factory for apiRef{b}', - ); - expect(() => registry.get(cRef)).toThrow( - 'Circular dependency of api factory for apiRef{c}', - ); - }); - - it('should throw error if dependency is not available', () => { - const registry = new ApiTestRegistry(); - registry.register({ - implements: aRef, - deps: { b: bRef }, - factory: () => 1, - }); - expect(() => registry.get(aRef)).toThrow( - 'No API factory available for dependency apiRef{b} of dependent apiRef{a}', - ); - expect(registry.get(bRef)).toBe(undefined); - expect(registry.get(cRef)).toBe(undefined); - }); - - it('should only call factory func once', () => { - const registry = new ApiTestRegistry(); - const factory = jest.fn().mockReturnValue(2); - registry.register({ implements: aRef, deps: {}, factory }); - - expect(factory).toHaveBeenCalledTimes(0); - expect(registry.get(aRef)).toBe(2); - expect(factory).toHaveBeenCalledTimes(1); - expect(registry.get(aRef)).toBe(2); - expect(factory).toHaveBeenCalledTimes(1); - }); - - it('should call factory again after reset', () => { - const registry = new ApiTestRegistry(); - const factory = jest.fn().mockReturnValue(2); - registry.register({ implements: aRef, deps: {}, factory }); - registry.save(); - - expect(factory).toHaveBeenCalledTimes(0); - expect(registry.get(aRef)).toBe(2); - expect(factory).toHaveBeenCalledTimes(1); - expect(registry.get(aRef)).toBe(2); - expect(factory).toHaveBeenCalledTimes(1); - registry.reset(); - expect(registry.get(aRef)).toBe(2); - expect(factory).toHaveBeenCalledTimes(2); - }); -}); diff --git a/packages/core-api/src/apis/definitions/auth.ts b/packages/core-api/src/apis/definitions/auth.ts index 9c8615536a..ec99bae6b2 100644 --- a/packages/core-api/src/apis/definitions/auth.ts +++ b/packages/core-api/src/apis/definitions/auth.ts @@ -317,7 +317,11 @@ export const microsoftAuthApiRef = createApiRef< * Provides authentication for custom identity providers. */ export const oauth2ApiRef = createApiRef< - OAuthApi & OpenIdConnectApi & ProfileInfoApi & SessionStateApi + OAuthApi & + OpenIdConnectApi & + ProfileInfoApi & + SessionStateApi & + BackstageIdentityApi >({ id: 'core.auth.oauth2', description: 'Example of how to use oauth2 custom provider', diff --git a/packages/core-api/src/apis/helpers.ts b/packages/core-api/src/apis/helpers.ts index d8f8e8ac11..7d616acd01 100644 --- a/packages/core-api/src/apis/helpers.ts +++ b/packages/core-api/src/apis/helpers.ts @@ -14,15 +14,36 @@ * limitations under the License. */ -import { ApiFactory } from './types'; +import { ApiFactory, TypesToApiRefs } from './types'; +import { ApiRef } from './ApiRef'; /** * Used to infer types for a standalone ApiFactory that isn't immediately passed * to another function. * This function doesn't actually do anything, it's only used to infer types. */ -export function createApiFactory( - factory: ApiFactory, -): ApiFactory { +export function createApiFactory< + Api, + Impl extends Api, + Deps extends { [name in string]: unknown } +>(factory: ApiFactory): ApiFactory; +export function createApiFactory( + api: ApiRef, + instance: Api, +): ApiFactory; +export function createApiFactory< + Api, + Deps extends { [name in string]: unknown } +>( + factory: ApiFactory | ApiRef, + instance?: Api, +): ApiFactory { + if ('id' in factory) { + return { + api: factory, + deps: {} as TypesToApiRefs, + factory: () => instance!, + }; + } return factory; } diff --git a/packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.ts b/packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.ts index 505c283b71..40e537169c 100644 --- a/packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.ts +++ b/packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.ts @@ -15,26 +15,13 @@ */ import Auth0Icon from '@material-ui/icons/AcUnit'; -import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; -import { Auth0Session } from './types'; -import { - OpenIdConnectApi, - ProfileInfoApi, - ProfileInfo, - SessionStateApi, - SessionState, - BackstageIdentityApi, - AuthRequestOptions, - BackstageIdentity, -} from '../../../definitions/auth'; +import { auth0AuthApiRef } from '../../../definitions/auth'; import { OAuthRequestApi, AuthProvider, DiscoveryApi, } from '../../../definitions'; -import { SessionManager } from '../../../../lib/AuthSessionManager/types'; -import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; -import { Observable } from '../../../../types'; +import { OAuth2 } from '../oauth2'; type CreateOptions = { discoveryApi: DiscoveryApi; @@ -44,106 +31,27 @@ type CreateOptions = { provider?: AuthProvider & { id: string }; }; -export type Auth0AuthResponse = { - providerInfo: { - accessToken: string; - idToken: string; - scope: string; - expiresInSeconds: number; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; - const DEFAULT_PROVIDER = { id: 'auth0', title: 'Auth0', icon: Auth0Icon, }; -class Auth0Auth - implements - OpenIdConnectApi, - ProfileInfoApi, - BackstageIdentityApi, - SessionStateApi { +class Auth0Auth { static create({ discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, oauthRequestApi, - }: CreateOptions) { - const connector = new DefaultAuthConnector({ + }: CreateOptions): typeof auth0AuthApiRef.T { + return OAuth2.create({ discoveryApi, - environment, + oauthRequestApi, provider, - oauthRequestApi: oauthRequestApi, - sessionTransform(res: Auth0AuthResponse): Auth0Session { - return { - ...res, - providerInfo: { - idToken: res.providerInfo.idToken, - accessToken: res.providerInfo.accessToken, - scopes: Auth0Auth.normalizeScopes(res.providerInfo.scope), - expiresAt: new Date( - Date.now() + res.providerInfo.expiresInSeconds * 1000, - ), - }, - }; - }, + environment, + defaultScopes: ['openid', `email`, `profile`], }); - - const sessionManager = new RefreshingAuthSessionManager({ - connector, - defaultScopes: new Set(['openid', `email`, `profile`]), - sessionScopes: (session: Auth0Session) => session.providerInfo.scopes, - sessionShouldRefresh: (session: Auth0Session) => { - const expiresInSec = - (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000; - return expiresInSec < 60 * 5; - }, - }); - - return new Auth0Auth(sessionManager); - } - - sessionState$(): Observable { - return this.sessionManager.sessionState$(); - } - - constructor(private readonly sessionManager: SessionManager) {} - - async getIdToken(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.providerInfo.idToken ?? ''; - } - - async logout() { - await this.sessionManager.removeSession(); - } - - async getBackstageIdentity( - options: AuthRequestOptions = {}, - ): Promise { - const session = await this.sessionManager.getSession(options); - return session?.backstageIdentity; - } - - async getProfile(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.profile; - } - - static normalizeScopes(scope?: string | string[]): Set { - if (!scope) { - return new Set(); - } - - const scopeList = Array.isArray(scope) - ? scope - : scope.split(/[\s|,]/).filter(Boolean); - - return new Set(scopeList); } } + export default Auth0Auth; diff --git a/packages/core-api/src/apis/implementations/auth/auth0/index.ts b/packages/core-api/src/apis/implementations/auth/auth0/index.ts index fb5d432642..dda27d0fa3 100644 --- a/packages/core-api/src/apis/implementations/auth/auth0/index.ts +++ b/packages/core-api/src/apis/implementations/auth/auth0/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './types'; export { default as Auth0Auth } from './Auth0Auth'; diff --git a/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts b/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts index 18346b3208..44b9aeb14e 100644 --- a/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts +++ b/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.test.ts @@ -14,33 +14,37 @@ * limitations under the License. */ +import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; +import { UrlPatternDiscovery } from '../../DiscoveryApi'; import GitlabAuth from './GitlabAuth'; -describe('GitlabAuth', () => { - it('should get access token', async () => { - const getSession = jest - .fn() - .mockResolvedValue({ providerInfo: { accessToken: 'access-token' } }); - const gitlabAuth = new GitlabAuth({ getSession } as any); +const getSession = jest.fn(); - expect(await gitlabAuth.getAccessToken()).toBe('access-token'); - expect(getSession).toBeCalledTimes(1); +jest.mock('../../../../lib/AuthSessionManager', () => ({ + ...(jest.requireActual('../../../../lib/AuthSessionManager') as any), + RefreshingAuthSessionManager: class { + getSession = getSession; + }, +})); + +describe('GitlabAuth', () => { + afterEach(() => { + jest.resetAllMocks(); }); - it('should normalize scope', () => { - const tests = [ - { - arguments: ['read_user api write_repository'], - expect: new Set(['read_user', 'api', 'write_repository']), - }, - { - arguments: ['read_repository sudo'], - expect: new Set(['read_repository', 'sudo']), - }, - ]; + it.each([ + [ + 'read_user api write_repository', + ['read_user', 'api', 'write_repository'], + ], + ['read_repository sudo', ['read_repository', 'sudo']], + ])(`should normalize scopes correctly - %p`, (scope, scopes) => { + const googleAuth = GitlabAuth.create({ + oauthRequestApi: new MockOAuthApi(), + discoveryApi: UrlPatternDiscovery.compile('http://example.com'), + }); - for (const test of tests) { - expect(GitlabAuth.normalizeScope(...test.arguments)).toEqual(test.expect); - } + googleAuth.getAccessToken(scope); + expect(getSession).toHaveBeenCalledWith({ scopes: new Set(scopes) }); }); }); diff --git a/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts b/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts index 1734e930fa..9e2acd4537 100644 --- a/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/gitlab/GitlabAuth.ts @@ -15,24 +15,13 @@ */ import GitlabIcon from '@material-ui/icons/AcUnit'; -import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; -import { GitlabSession } from './types'; -import { - OAuthApi, - SessionStateApi, - SessionState, - ProfileInfo, - BackstageIdentity, - AuthRequestOptions, -} from '../../../definitions/auth'; +import { gitlabAuthApiRef } from '../../../definitions/auth'; import { OAuthRequestApi, AuthProvider, DiscoveryApi, } from '../../../definitions'; -import { SessionManager } from '../../../../lib/AuthSessionManager/types'; -import { StaticAuthSessionManager } from '../../../../lib/AuthSessionManager'; -import { Observable } from '../../../../types'; +import { OAuth2 } from '../oauth2'; type CreateOptions = { discoveryApi: DiscoveryApi; @@ -42,94 +31,26 @@ type CreateOptions = { provider?: AuthProvider & { id: string }; }; -export type GitlabAuthResponse = { - providerInfo: { - accessToken: string; - scope: string; - expiresInSeconds: number; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; - const DEFAULT_PROVIDER = { id: 'gitlab', title: 'Gitlab', icon: GitlabIcon, }; -class GitlabAuth implements OAuthApi, SessionStateApi { +class GitlabAuth { static create({ discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, oauthRequestApi, - }: CreateOptions) { - const connector = new DefaultAuthConnector({ + }: CreateOptions): typeof gitlabAuthApiRef.T { + return OAuth2.create({ discoveryApi, - environment, - provider, oauthRequestApi, - sessionTransform(res: GitlabAuthResponse): GitlabSession { - return { - ...res, - providerInfo: { - accessToken: res.providerInfo.accessToken, - scopes: GitlabAuth.normalizeScope(res.providerInfo.scope), - expiresAt: new Date( - Date.now() + res.providerInfo.expiresInSeconds * 1000, - ), - }, - }; - }, + provider, + environment, + defaultScopes: ['read_user'], }); - - const sessionManager = new StaticAuthSessionManager({ - connector, - defaultScopes: new Set(['read_user']), - sessionScopes: (session: GitlabSession) => session.providerInfo.scopes, - }); - - return new GitlabAuth(sessionManager); - } - - sessionState$(): Observable { - return this.sessionManager.sessionState$(); - } - - constructor(private readonly sessionManager: SessionManager) {} - - async getAccessToken(scope?: string, options?: AuthRequestOptions) { - const session = await this.sessionManager.getSession({ - ...options, - scopes: GitlabAuth.normalizeScope(scope), - }); - return session?.providerInfo.accessToken ?? ''; - } - - async getBackstageIdentity( - options: AuthRequestOptions = {}, - ): Promise { - const session = await this.sessionManager.getSession(options); - return session?.backstageIdentity; - } - - async getProfile(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.profile; - } - - async logout() { - await this.sessionManager.removeSession(); - } - - static normalizeScope(scope?: string): Set { - if (!scope) { - return new Set(); - } - - const scopeList = Array.isArray(scope) ? scope : scope.split(' '); - return new Set(scopeList); } } export default GitlabAuth; diff --git a/packages/core-api/src/apis/implementations/auth/gitlab/index.ts b/packages/core-api/src/apis/implementations/auth/gitlab/index.ts index ee17b7de06..42d7210551 100644 --- a/packages/core-api/src/apis/implementations/auth/gitlab/index.ts +++ b/packages/core-api/src/apis/implementations/auth/gitlab/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './types'; export { default as GitlabAuth } from './GitlabAuth'; diff --git a/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.test.ts b/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.test.ts index 5290ee798b..9e8569c5cf 100644 --- a/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.test.ts +++ b/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.test.ts @@ -15,101 +15,23 @@ */ import GoogleAuth from './GoogleAuth'; - -const theFuture = new Date(Date.now() + 3600000); -const thePast = new Date(Date.now() - 10); +import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; +import { UrlPatternDiscovery } from '../../DiscoveryApi'; const PREFIX = 'https://www.googleapis.com/auth/'; +const getSession = jest.fn(); + +jest.mock('../../../../lib/AuthSessionManager', () => ({ + ...(jest.requireActual('../../../../lib/AuthSessionManager') as any), + RefreshingAuthSessionManager: class { + getSession = getSession; + }, +})); + describe('GoogleAuth', () => { - it('should get refreshed access token', async () => { - const getSession = jest.fn().mockResolvedValue({ - providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, - }); - const googleAuth = new GoogleAuth({ getSession } as any); - - expect(await googleAuth.getAccessToken()).toBe('access-token'); - expect(getSession).toBeCalledTimes(1); - }); - - it('should get refreshed id token', async () => { - const getSession = jest.fn().mockResolvedValue({ - providerInfo: { idToken: 'id-token', expiresAt: theFuture }, - }); - const googleAuth = new GoogleAuth({ getSession } as any); - - expect(await googleAuth.getIdToken()).toBe('id-token'); - expect(getSession).toBeCalledTimes(1); - }); - - it('should get optional id token', async () => { - const getSession = jest.fn().mockResolvedValue({ - providerInfo: { idToken: 'id-token', expiresAt: theFuture }, - }); - const googleAuth = new GoogleAuth({ getSession } as any); - - expect(await googleAuth.getIdToken({ optional: true })).toBe('id-token'); - expect(getSession).toBeCalledTimes(1); - }); - - it('should share popup closed errors', async () => { - const error = new Error('NOPE'); - error.name = 'RejectedError'; - const getSession = jest - .fn() - .mockResolvedValueOnce({ - providerInfo: { - accessToken: 'access-token', - expiresAt: theFuture, - scopes: new Set([`${PREFIX}not-enough`]), - }, - }) - .mockRejectedValue(error); - const googleAuth = new GoogleAuth({ getSession } as any); - - // Make sure we have a session before we do the double request, so that we get past the !this.currentSession check - await expect(googleAuth.getAccessToken()).resolves.toBe('access-token'); - - const promise1 = googleAuth.getAccessToken('more'); - const promise2 = googleAuth.getAccessToken('more'); - await expect(promise1).rejects.toBe(error); - await expect(promise2).rejects.toBe(error); - expect(getSession).toBeCalledTimes(3); - }); - - it('should wait for all session refreshes', async () => { - const initialSession = { - providerInfo: { - idToken: 'token1', - expiresAt: theFuture, - scopes: new Set(), - }, - }; - const getSession = jest - .fn() - .mockResolvedValueOnce(initialSession) - .mockResolvedValue({ - providerInfo: { - idToken: 'token2', - expiresAt: theFuture, - scopes: new Set(), - }, - }); - const googleAuth = new GoogleAuth({ getSession } as any); - - // Grab the expired session first - await expect(googleAuth.getIdToken()).resolves.toBe('token1'); - expect(getSession).toBeCalledTimes(1); - - initialSession.providerInfo.expiresAt = thePast; - - const promise1 = googleAuth.getIdToken(); - const promise2 = googleAuth.getIdToken(); - const promise3 = googleAuth.getIdToken(); - await expect(promise1).resolves.toBe('token2'); - await expect(promise2).resolves.toBe('token2'); - await expect(promise3).resolves.toBe('token2'); - expect(getSession).toBeCalledTimes(4); // De-duping of session requests happens in client + afterEach(() => { + jest.resetAllMocks(); }); it.each([ @@ -136,6 +58,12 @@ describe('GoogleAuth', () => { [`${PREFIX}profile`, [`${PREFIX}profile`]], [`${PREFIX}openid`, [`${PREFIX}openid`]], ])(`should normalize scopes correctly - %p`, (scope, scopes) => { - expect(GoogleAuth.normalizeScopes(scope)).toEqual(new Set(scopes)); + const googleAuth = GoogleAuth.create({ + oauthRequestApi: new MockOAuthApi(), + discoveryApi: UrlPatternDiscovery.compile('http://example.com'), + }); + + googleAuth.getAccessToken(scope); + expect(getSession).toHaveBeenCalledWith({ scopes: new Set(scopes) }); }); }); diff --git a/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.ts b/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.ts index fdf9d46ba8..7e84226508 100644 --- a/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/google/GoogleAuth.ts @@ -15,27 +15,13 @@ */ import GoogleIcon from '@material-ui/icons/AcUnit'; -import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; -import { GoogleSession } from './types'; -import { - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - ProfileInfo, - SessionStateApi, - SessionState, - BackstageIdentityApi, - AuthRequestOptions, - BackstageIdentity, -} from '../../../definitions/auth'; +import { googleAuthApiRef } from '../../../definitions/auth'; import { OAuthRequestApi, AuthProvider, DiscoveryApi, } from '../../../definitions'; -import { SessionManager } from '../../../../lib/AuthSessionManager/types'; -import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; -import { Observable } from '../../../../types'; +import { OAuth2 } from '../oauth2'; type CreateOptions = { discoveryApi: DiscoveryApi; @@ -45,140 +31,49 @@ type CreateOptions = { provider?: AuthProvider & { id: string }; }; -export type GoogleAuthResponse = { - providerInfo: { - accessToken: string; - idToken: string; - scope: string; - expiresInSeconds: number; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; - const DEFAULT_PROVIDER = { id: 'google', title: 'Google', icon: GoogleIcon, }; -const SCOPE_PREFIX = 'https://www.googleapis.com/auth/'; - -class GoogleAuth - implements - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - BackstageIdentityApi, - SessionStateApi { +class GoogleAuth { static create({ discoveryApi, + oauthRequestApi, environment = 'development', provider = DEFAULT_PROVIDER, - oauthRequestApi, - }: CreateOptions) { - const connector = new DefaultAuthConnector({ - discoveryApi, - environment, - provider, - oauthRequestApi: oauthRequestApi, - sessionTransform(res: GoogleAuthResponse): GoogleSession { - return { - ...res, - providerInfo: { - idToken: res.providerInfo.idToken, - accessToken: res.providerInfo.accessToken, - scopes: GoogleAuth.normalizeScopes(res.providerInfo.scope), - expiresAt: new Date( - Date.now() + res.providerInfo.expiresInSeconds * 1000, - ), - }, - }; - }, - }); + }: CreateOptions): typeof googleAuthApiRef.T { + const SCOPE_PREFIX = 'https://www.googleapis.com/auth/'; - const sessionManager = new RefreshingAuthSessionManager({ - connector, - defaultScopes: new Set([ + return OAuth2.create({ + discoveryApi, + oauthRequestApi, + provider, + environment, + defaultScopes: [ 'openid', `${SCOPE_PREFIX}userinfo.email`, `${SCOPE_PREFIX}userinfo.profile`, - ]), - sessionScopes: (session: GoogleSession) => session.providerInfo.scopes, - sessionShouldRefresh: (session: GoogleSession) => { - const expiresInSec = - (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000; - return expiresInSec < 60 * 5; + ], + scopeTransform(scopes: string[]) { + return scopes.map(scope => { + if (scope === 'openid') { + return scope; + } + + if (scope === 'profile' || scope === 'email') { + return `${SCOPE_PREFIX}userinfo.${scope}`; + } + + if (scope.startsWith(SCOPE_PREFIX)) { + return scope; + } + + return `${SCOPE_PREFIX}${scope}`; + }); }, }); - - return new GoogleAuth(sessionManager); - } - - sessionState$(): Observable { - return this.sessionManager.sessionState$(); - } - - constructor(private readonly sessionManager: SessionManager) {} - - async getAccessToken( - scope?: string | string[], - options?: AuthRequestOptions, - ) { - const session = await this.sessionManager.getSession({ - ...options, - scopes: GoogleAuth.normalizeScopes(scope), - }); - return session?.providerInfo.accessToken ?? ''; - } - - async getIdToken(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.providerInfo.idToken ?? ''; - } - - async logout() { - await this.sessionManager.removeSession(); - } - - async getBackstageIdentity( - options: AuthRequestOptions = {}, - ): Promise { - const session = await this.sessionManager.getSession(options); - return session?.backstageIdentity; - } - - async getProfile(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.profile; - } - - static normalizeScopes(scopes?: string | string[]): Set { - if (!scopes) { - return new Set(); - } - - const scopeList = Array.isArray(scopes) - ? scopes - : scopes.split(/[\s]/).filter(Boolean); - - const normalizedScopes = scopeList.map(scope => { - if (scope === 'openid') { - return scope; - } - - if (scope === 'profile' || scope === 'email') { - return `${SCOPE_PREFIX}userinfo.${scope}`; - } - - if (scope.startsWith(SCOPE_PREFIX)) { - return scope; - } - - return `${SCOPE_PREFIX}${scope}`; - }); - - return new Set(normalizedScopes); } } export default GoogleAuth; diff --git a/packages/core-api/src/apis/implementations/auth/google/index.ts b/packages/core-api/src/apis/implementations/auth/google/index.ts index 78e8a97c31..2521d46046 100644 --- a/packages/core-api/src/apis/implementations/auth/google/index.ts +++ b/packages/core-api/src/apis/implementations/auth/google/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './types'; export { default as GoogleAuth } from './GoogleAuth'; diff --git a/packages/core-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts b/packages/core-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts index 5800308c26..241ac7b802 100644 --- a/packages/core-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/microsoft/MicrosoftAuth.ts @@ -15,29 +15,14 @@ */ import MicrosoftIcon from '@material-ui/icons/AcUnit'; -import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; -import { MicrosoftSession } from './types'; - -import { - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - ProfileInfo, - SessionStateApi, - SessionState, - BackstageIdentityApi, - AuthRequestOptions, - BackstageIdentity, -} from '../../../definitions/auth'; +import { microsoftAuthApiRef } from '../../../definitions/auth'; import { OAuthRequestApi, AuthProvider, DiscoveryApi, } from '../../../definitions'; -import { SessionManager } from '../../../../lib/AuthSessionManager/types'; -import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; -import { Observable } from '../../../../types'; +import { OAuth2 } from '../oauth2'; type CreateOptions = { discoveryApi: DiscoveryApi; @@ -47,126 +32,33 @@ type CreateOptions = { provider?: AuthProvider & { id: string }; }; -export type MicrosoftAuthResponse = { - providerInfo: { - accessToken: string; - idToken: string; - scope: string; - expiresInSeconds: number; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; - const DEFAULT_PROVIDER = { id: 'microsoft', title: 'Microsoft', icon: MicrosoftIcon, }; -class MicrosoftAuth - implements - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - BackstageIdentityApi, - SessionStateApi { +class MicrosoftAuth { static create({ environment = 'development', provider = DEFAULT_PROVIDER, oauthRequestApi, discoveryApi, - }: CreateOptions) { - const connector = new DefaultAuthConnector({ + }: CreateOptions): typeof microsoftAuthApiRef.T { + return OAuth2.create({ discoveryApi, - environment, + oauthRequestApi, provider, - oauthRequestApi: oauthRequestApi, - sessionTransform(res: MicrosoftAuthResponse): MicrosoftSession { - return { - ...res, - providerInfo: { - idToken: res.providerInfo.idToken, - accessToken: res.providerInfo.accessToken, - scopes: MicrosoftAuth.normalizeScopes(res.providerInfo.scope), - expiresAt: new Date( - Date.now() + res.providerInfo.expiresInSeconds * 1000, - ), - }, - }; - }, - }); - - const sessionManager = new RefreshingAuthSessionManager({ - connector, - defaultScopes: new Set([ + environment, + defaultScopes: [ 'openid', 'offline_access', 'profile', 'email', 'User.Read', - ]), - sessionScopes: (session: MicrosoftSession) => session.providerInfo.scopes, - sessionShouldRefresh: (session: MicrosoftSession) => { - const expiresInSec = - (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000; - return expiresInSec < 60 * 5; - }, + ], }); - - return new MicrosoftAuth(sessionManager); - } - - sessionState$(): Observable { - return this.sessionManager.sessionState$(); - } - - constructor( - private readonly sessionManager: SessionManager, - ) {} - - async getAccessToken( - scope?: string | string[], - options?: AuthRequestOptions, - ) { - const session = await this.sessionManager.getSession({ - ...options, - scopes: MicrosoftAuth.normalizeScopes(scope), - }); - return session?.providerInfo.accessToken ?? ''; - } - - async getIdToken(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.providerInfo.idToken ?? ''; - } - - async logout() { - await this.sessionManager.removeSession(); - } - - async getBackstageIdentity( - options: AuthRequestOptions = {}, - ): Promise { - const session = await this.sessionManager.getSession(options); - return session?.backstageIdentity; - } - - async getProfile(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.profile; - } - - static normalizeScopes(scopes?: string | string[]): Set { - if (!scopes) { - return new Set(); - } - - const scopeList = Array.isArray(scopes) - ? scopes - : scopes.split(/[\s|,]/).filter(Boolean); - - return new Set(scopeList); } } + export default MicrosoftAuth; diff --git a/packages/core-api/src/apis/implementations/auth/microsoft/index.ts b/packages/core-api/src/apis/implementations/auth/microsoft/index.ts index e3ae4ee4f1..77328d8557 100644 --- a/packages/core-api/src/apis/implementations/auth/microsoft/index.ts +++ b/packages/core-api/src/apis/implementations/auth/microsoft/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './types'; export { default as MicrosoftAuth } from './MicrosoftAuth'; diff --git a/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts b/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts new file mode 100644 index 0000000000..93db2c732d --- /dev/null +++ b/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.test.ts @@ -0,0 +1,152 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import OAuth2 from './OAuth2'; + +const theFuture = new Date(Date.now() + 3600000); +const thePast = new Date(Date.now() - 10); + +const PREFIX = 'https://www.googleapis.com/auth/'; + +const scopeTransform = (x: string[]) => x; + +describe('OAuth2', () => { + it('should get refreshed access token', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, + }); + const oauth2 = new OAuth2({ + sessionManager: { getSession } as any, + scopeTransform, + }); + + expect(await oauth2.getAccessToken('my-scope my-scope2')).toBe( + 'access-token', + ); + expect(getSession).toBeCalledTimes(1); + expect(getSession.mock.calls[0][0].scopes).toEqual( + new Set(['my-scope', 'my-scope2']), + ); + }); + + it('should transform scopes', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, + }); + const oauth2 = new OAuth2({ + sessionManager: { getSession } as any, + scopeTransform: scopes => scopes.map(scope => `my-prefix/${scope}`), + }); + + expect(await oauth2.getAccessToken('my-scope')).toBe('access-token'); + expect(getSession).toBeCalledTimes(1); + expect(getSession.mock.calls[0][0].scopes).toEqual( + new Set(['my-prefix/my-scope']), + ); + }); + + it('should get refreshed id token', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { idToken: 'id-token', expiresAt: theFuture }, + }); + const oauth2 = new OAuth2({ + sessionManager: { getSession } as any, + scopeTransform, + }); + + expect(await oauth2.getIdToken()).toBe('id-token'); + expect(getSession).toBeCalledTimes(1); + }); + + it('should get optional id token', async () => { + const getSession = jest.fn().mockResolvedValue({ + providerInfo: { idToken: 'id-token', expiresAt: theFuture }, + }); + const oauth2 = new OAuth2({ + sessionManager: { getSession } as any, + scopeTransform, + }); + + expect(await oauth2.getIdToken({ optional: true })).toBe('id-token'); + expect(getSession).toBeCalledTimes(1); + }); + + it('should share popup closed errors', async () => { + const error = new Error('NOPE'); + error.name = 'RejectedError'; + const getSession = jest + .fn() + .mockResolvedValueOnce({ + providerInfo: { + accessToken: 'access-token', + expiresAt: theFuture, + scopes: new Set([`${PREFIX}not-enough`]), + }, + }) + .mockRejectedValue(error); + const oauth2 = new OAuth2({ + sessionManager: { getSession } as any, + scopeTransform, + }); + + // Make sure we have a session before we do the double request, so that we get past the !this.currentSession check + await expect(oauth2.getAccessToken()).resolves.toBe('access-token'); + + const promise1 = oauth2.getAccessToken('more'); + const promise2 = oauth2.getAccessToken('more'); + await expect(promise1).rejects.toBe(error); + await expect(promise2).rejects.toBe(error); + expect(getSession).toBeCalledTimes(3); + }); + + it('should wait for all session refreshes', async () => { + const initialSession = { + providerInfo: { + idToken: 'token1', + expiresAt: theFuture, + scopes: new Set(), + }, + }; + const getSession = jest + .fn() + .mockResolvedValueOnce(initialSession) + .mockResolvedValue({ + providerInfo: { + idToken: 'token2', + expiresAt: theFuture, + scopes: new Set(), + }, + }); + const oauth2 = new OAuth2({ + sessionManager: { getSession } as any, + scopeTransform, + }); + + // Grab the expired session first + await expect(oauth2.getIdToken()).resolves.toBe('token1'); + expect(getSession).toBeCalledTimes(1); + + initialSession.providerInfo.expiresAt = thePast; + + const promise1 = oauth2.getIdToken(); + const promise2 = oauth2.getIdToken(); + const promise3 = oauth2.getIdToken(); + await expect(promise1).resolves.toBe('token2'); + await expect(promise2).resolves.toBe('token2'); + await expect(promise3).resolves.toBe('token2'); + expect(getSession).toBeCalledTimes(4); // De-duping of session requests happens in client + }); +}); diff --git a/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.ts b/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.ts index cf582b3a13..27626aac5a 100644 --- a/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.ts +++ b/packages/core-api/src/apis/implementations/auth/oauth2/OAuth2.ts @@ -33,15 +33,23 @@ import { ProfileInfoApi, SessionState, SessionStateApi, + BackstageIdentityApi, } from '../../../definitions/auth'; import { OAuth2Session } from './types'; +type Options = { + sessionManager: SessionManager; + scopeTransform: (scopes: string[]) => string[]; +}; + type CreateOptions = { discoveryApi: DiscoveryApi; oauthRequestApi: OAuthRequestApi; environment?: string; provider?: AuthProvider & { id: string }; + defaultScopes?: string[]; + scopeTransform?: (scopes: string[]) => string[]; }; export type OAuth2Response = { @@ -61,15 +69,20 @@ const DEFAULT_PROVIDER = { icon: OAuth2Icon, }; -const SCOPE_PREFIX = ''; - class OAuth2 - implements OAuthApi, OpenIdConnectApi, ProfileInfoApi, SessionStateApi { + implements + OAuthApi, + OpenIdConnectApi, + ProfileInfoApi, + BackstageIdentityApi, + SessionStateApi { static create({ discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, oauthRequestApi, + defaultScopes = [], + scopeTransform = x => x, }: CreateOptions) { const connector = new DefaultAuthConnector({ discoveryApi, @@ -82,7 +95,10 @@ class OAuth2 providerInfo: { idToken: res.providerInfo.idToken, accessToken: res.providerInfo.accessToken, - scopes: OAuth2.normalizeScopes(res.providerInfo.scope), + scopes: OAuth2.normalizeScopes( + scopeTransform, + res.providerInfo.scope, + ), expiresAt: new Date( Date.now() + res.providerInfo.expiresInSeconds * 1000, ), @@ -93,11 +109,7 @@ class OAuth2 const sessionManager = new RefreshingAuthSessionManager({ connector, - defaultScopes: new Set([ - 'openid', - `${SCOPE_PREFIX}userinfo.email`, - `${SCOPE_PREFIX}userinfo.profile`, - ]), + defaultScopes: new Set(defaultScopes), sessionScopes: (session: OAuth2Session) => session.providerInfo.scopes, sessionShouldRefresh: (session: OAuth2Session) => { const expiresInSec = @@ -106,20 +118,26 @@ class OAuth2 }, }); - return new OAuth2(sessionManager); + return new OAuth2({ sessionManager, scopeTransform }); + } + + private readonly sessionManager: SessionManager; + private readonly scopeTransform: (scopes: string[]) => string[]; + + constructor(options: Options) { + this.sessionManager = options.sessionManager; + this.scopeTransform = options.scopeTransform; } sessionState$(): Observable { return this.sessionManager.sessionState$(); } - constructor(private readonly sessionManager: SessionManager) {} - async getAccessToken( scope?: string | string[], options?: AuthRequestOptions, ) { - const normalizedScopes = OAuth2.normalizeScopes(scope); + const normalizedScopes = OAuth2.normalizeScopes(this.scopeTransform, scope); const session = await this.sessionManager.getSession({ ...options, scopes: normalizedScopes, @@ -148,16 +166,19 @@ class OAuth2 return session?.profile; } - static normalizeScopes(scopes?: string | string[]): Set { + private static normalizeScopes( + scopeTransform: (scopes: string[]) => string[], + scopes?: string | string[], + ): Set { if (!scopes) { return new Set(); } const scopeList = Array.isArray(scopes) ? scopes - : scopes.split(/[\s]/).filter(Boolean); + : scopes.split(/[\s|,]/).filter(Boolean); - return new Set(scopeList); + return new Set(scopeTransform(scopeList)); } } diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts index ab6c46c9b4..d6b1a07d9d 100644 --- a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.test.ts @@ -13,102 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import OktaAuth from './OktaAuth'; -const theFuture = new Date(Date.now() + 3600000); -const thePast = new Date(Date.now() - 10); +import OktaAuth from './OktaAuth'; +import MockOAuthApi from '../../OAuthRequestApi/MockOAuthApi'; +import { UrlPatternDiscovery } from '../../DiscoveryApi'; const PREFIX = 'okta.'; +const getSession = jest.fn(); + +jest.mock('../../../../lib/AuthSessionManager', () => ({ + ...(jest.requireActual('../../../../lib/AuthSessionManager') as any), + RefreshingAuthSessionManager: class { + getSession = getSession; + }, +})); + describe('OktaAuth', () => { - it('should get refreshed access token', async () => { - const getSession = jest.fn().mockResolvedValue({ - providerInfo: { accessToken: 'access-token', expiresAt: theFuture }, - }); - const oktaAuth = new OktaAuth({ getSession } as any); - - expect(await oktaAuth.getAccessToken()).toBe('access-token'); - expect(getSession).toBeCalledTimes(1); - }); - - it('should get refreshed id token', async () => { - const getSession = jest.fn().mockResolvedValue({ - providerInfo: { idToken: 'id-token', expiresAt: theFuture }, - }); - const oktaAuth = new OktaAuth({ getSession } as any); - - expect(await oktaAuth.getIdToken()).toBe('id-token'); - expect(getSession).toBeCalledTimes(1); - }); - - it('should get optional id token', async () => { - const getSession = jest.fn().mockResolvedValue({ - providerInfo: { idToken: 'id-token', expiresAt: theFuture }, - }); - const oktaAuth = new OktaAuth({ getSession } as any); - - expect(await oktaAuth.getIdToken({ optional: true })).toBe('id-token'); - expect(getSession).toBeCalledTimes(1); - }); - - it('should share popup closed errors', async () => { - const error = new Error('NOPE'); - error.name = 'RejectedError'; - const getSession = jest - .fn() - .mockResolvedValueOnce({ - providerInfo: { - accessToken: 'access-token', - expiresAt: theFuture, - scopes: new Set([`not-a-scope`]), - }, - }) - .mockRejectedValue(error); - const oktaAuth = new OktaAuth({ getSession } as any); - - // Make sure we have a session before we do the double request, so that we get past the !this.currentSession check - await expect(oktaAuth.getAccessToken()).resolves.toBe('access-token'); - - const promise1 = oktaAuth.getAccessToken('more'); - const promise2 = oktaAuth.getAccessToken('more'); - await expect(promise1).rejects.toBe(error); - await expect(promise2).rejects.toBe(error); - expect(getSession).toBeCalledTimes(3); - }); - - it('should wait for all session refreshes', async () => { - const initialSession = { - providerInfo: { - idToken: 'token1', - expiresAt: theFuture, - scopes: new Set(), - }, - }; - const getSession = jest - .fn() - .mockResolvedValueOnce(initialSession) - .mockResolvedValue({ - providerInfo: { - idToken: 'token2', - expiresAt: theFuture, - scopes: new Set(), - }, - }); - const oktaAuth = new OktaAuth({ getSession } as any); - - // Grab the expired session first - await expect(oktaAuth.getIdToken()).resolves.toBe('token1'); - expect(getSession).toBeCalledTimes(1); - - initialSession.providerInfo.expiresAt = thePast; - - const promise1 = oktaAuth.getIdToken(); - const promise2 = oktaAuth.getIdToken(); - const promise3 = oktaAuth.getIdToken(); - await expect(promise1).resolves.toBe('token2'); - await expect(promise2).resolves.toBe('token2'); - await expect(promise3).resolves.toBe('token2'); - expect(getSession).toBeCalledTimes(4); // De-duping of session requests happens in client + afterEach(() => { + jest.resetAllMocks(); }); it.each([ @@ -116,7 +39,10 @@ describe('OktaAuth', () => { ['profile email', ['profile', 'email']], [`${PREFIX}groups.manage`, [`${PREFIX}groups.manage`]], ['groups.read', [`${PREFIX}groups.read`]], - [`${PREFIX}groups.manage groups.read, openid`, [`${PREFIX}groups.manage`, `${PREFIX}groups.read`, 'openid']], + [ + `${PREFIX}groups.manage groups.read, openid`, + [`${PREFIX}groups.manage`, `${PREFIX}groups.read`, 'openid'], + ], [`email\t ${PREFIX}groups.read`, ['email', `${PREFIX}groups.read`]], // Some incorrect scopes that we don't try to fix @@ -124,6 +50,12 @@ describe('OktaAuth', () => { [`${PREFIX}profile`, [`${PREFIX}profile`]], [`${PREFIX}openid`, [`${PREFIX}openid`]], ])(`should normalize scopes correctly - %p`, (scope, scopes) => { - expect(OktaAuth.normalizeScopes(scope)).toEqual(new Set(scopes)); + const auth = OktaAuth.create({ + oauthRequestApi: new MockOAuthApi(), + discoveryApi: UrlPatternDiscovery.compile('http://example.com'), + }); + + auth.getAccessToken(scope); + expect(getSession).toHaveBeenCalledWith({ scopes: new Set(scopes) }); }); -}); +}); diff --git a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts index 1f804748f0..7e9ff77678 100644 --- a/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts +++ b/packages/core-api/src/apis/implementations/auth/okta/OktaAuth.ts @@ -15,27 +15,13 @@ */ import OktaIcon from '@material-ui/icons/AcUnit'; -import { DefaultAuthConnector } from '../../../../lib/AuthConnector'; -import { OktaSession } from './types'; -import { - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - ProfileInfo, - SessionStateApi, - SessionState, - BackstageIdentityApi, - AuthRequestOptions, - BackstageIdentity, -} from '../../../definitions/auth'; +import { oktaAuthApiRef } from '../../../definitions/auth'; import { OAuthRequestApi, AuthProvider, DiscoveryApi, } from '../../../definitions'; -import { SessionManager } from '../../../../lib/AuthSessionManager/types'; -import { RefreshingAuthSessionManager } from '../../../../lib/AuthSessionManager'; -import { Observable } from '../../../../types'; +import { OAuth2 } from '../oauth2'; type CreateOptions = { discoveryApi: DiscoveryApi; @@ -45,17 +31,6 @@ type CreateOptions = { provider?: AuthProvider & { id: string }; }; -export type OktaAuthResponse = { - providerInfo: { - accessToken: string; - idToken: string; - scope: string; - expiresInSeconds: number; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; - const DEFAULT_PROVIDER = { id: 'okta', title: 'Okta', @@ -74,110 +49,33 @@ const OKTA_OIDC_SCOPES: Set = new Set([ const OKTA_SCOPE_PREFIX: string = 'okta.'; -class OktaAuth - implements - OAuthApi, - OpenIdConnectApi, - ProfileInfoApi, - BackstageIdentityApi, - SessionStateApi { +class OktaAuth { static create({ discoveryApi, environment = 'development', provider = DEFAULT_PROVIDER, oauthRequestApi, - }: CreateOptions) { - const connector = new DefaultAuthConnector({ + }: CreateOptions): typeof oktaAuthApiRef.T { + return OAuth2.create({ discoveryApi, - environment, + oauthRequestApi, provider, - oauthRequestApi: oauthRequestApi, - sessionTransform(res: OktaAuthResponse): OktaSession { - return { - ...res, - providerInfo: { - idToken: res.providerInfo.idToken, - accessToken: res.providerInfo.accessToken, - scopes: OktaAuth.normalizeScopes(res.providerInfo.scope), - expiresAt: new Date( - Date.now() + res.providerInfo.expiresInSeconds * 1000, - ), - }, - }; + environment, + defaultScopes: ['openid', 'email', 'profile', 'offline_access'], + scopeTransform(scopes) { + return scopes.map(scope => { + if (OKTA_OIDC_SCOPES.has(scope)) { + return scope; + } + + if (scope.startsWith(OKTA_SCOPE_PREFIX)) { + return scope; + } + + return `${OKTA_SCOPE_PREFIX}${scope}`; + }); }, }); - - const sessionManager = new RefreshingAuthSessionManager({ - connector, - defaultScopes: new Set(['openid', 'email', 'profile', 'offline_access']), - sessionScopes: session => session.scopes, - sessionShouldRefresh: session => { - const expiresInSec = - (session.providerInfo.expiresAt.getTime() - Date.now()) / 1000; - return expiresInSec < 60 * 5; - }, - }); - - return new OktaAuth(sessionManager); - } - - sessionState$(): Observable { - return this.sessionManager.sessionState$(); - } - - constructor(private readonly sessionManager: SessionManager) {} - - async getAccessToken(scope?: string, options?: AuthRequestOptions) { - const session = await this.sessionManager.getSession({ - ...options, - scopes: OktaAuth.normalizeScopes(scope), - }); - return session?.providerInfo.accessToken ?? ''; - } - - async getIdToken(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.providerInfo.idToken ?? ''; - } - - async logout() { - await this.sessionManager.removeSession(); - } - - async getBackstageIdentity( - options: AuthRequestOptions = {}, - ): Promise { - const session = await this.sessionManager.getSession(options); - return session?.backstageIdentity; - } - - async getProfile(options: AuthRequestOptions = {}) { - const session = await this.sessionManager.getSession(options); - return session?.profile; - } - - static normalizeScopes(scopes?: string | string[]): Set { - if (!scopes) { - return new Set(); - } - - const scopeList = Array.isArray(scopes) - ? scopes - : scopes.split(/[\s|,]/).filter(Boolean); - - const normalizedScopes = scopeList.map(scope => { - if (OKTA_OIDC_SCOPES.has(scope)) { - return scope; - } - - if (scope.startsWith(OKTA_SCOPE_PREFIX)) { - return scope; - } - - return `${OKTA_SCOPE_PREFIX}${scope}`; - }); - - return new Set(normalizedScopes); } } diff --git a/packages/core-api/src/apis/implementations/auth/okta/index.ts b/packages/core-api/src/apis/implementations/auth/okta/index.ts index 2bef0ce0db..4cc774b26b 100644 --- a/packages/core-api/src/apis/implementations/auth/okta/index.ts +++ b/packages/core-api/src/apis/implementations/auth/okta/index.ts @@ -14,5 +14,4 @@ * limitations under the License. */ -export * from './types'; -export { default as OktaAuth } from './OktaAuth'; +export { default as OktaAuth } from './OktaAuth'; diff --git a/packages/core-api/src/apis/implementations/auth/okta/types.ts b/packages/core-api/src/apis/implementations/auth/okta/types.ts deleted file mode 100644 index e3392ba1d6..0000000000 --- a/packages/core-api/src/apis/implementations/auth/okta/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { ProfileInfo, BackstageIdentity } from '../../../definitions'; - -export type OktaSession = { - providerInfo: { - idToken: string; - accessToken: string; - scopes: Set; - expiresAt: Date; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; diff --git a/packages/core-api/src/apis/index.ts b/packages/core-api/src/apis/index.ts index c3689b6703..c856a13668 100644 --- a/packages/core-api/src/apis/index.ts +++ b/packages/core-api/src/apis/index.ts @@ -16,7 +16,6 @@ export { ApiProvider, useApi, useApiHolder } from './ApiProvider'; export { ApiRegistry } from './ApiRegistry'; -export { ApiTestRegistry } from './ApiTestRegistry'; export * from './ApiRef'; export * from './types'; export * from './helpers'; diff --git a/packages/core-api/src/apis/types.ts b/packages/core-api/src/apis/types.ts index 4ee9b39ca9..61c229b18e 100644 --- a/packages/core-api/src/apis/types.ts +++ b/packages/core-api/src/apis/types.ts @@ -16,13 +16,13 @@ import { ApiRef } from './ApiRef'; -export type AnyApiRef = ApiRef; +export type AnyApiRef = ApiRef; export type ApiRefType = T extends ApiRef ? U : never; export type TypesToApiRefs = { [key in keyof T]: ApiRef }; -export type ApiRefsToTypes }> = { +export type ApiRefsToTypes }> = { [key in keyof T]: ApiRefType; }; @@ -30,8 +30,16 @@ export type ApiHolder = { get(api: ApiRef): T | undefined; }; -export type ApiFactory = { - implements: ApiRef; +export type ApiFactory = { + api: ApiRef; deps: TypesToApiRefs; - factory(deps: Deps): Impl extends Api ? Impl : never; + factory(deps: Deps): Api; +}; + +export type AnyApiFactory = ApiFactory; + +export type ApiFactoryHolder = { + get( + api: ApiRef, + ): ApiFactory | undefined; }; diff --git a/packages/core-api/src/app/App.tsx b/packages/core-api/src/app/App.tsx index bfa26b7547..9dd2fb138f 100644 --- a/packages/core-api/src/app/App.tsx +++ b/packages/core-api/src/app/App.tsx @@ -26,7 +26,6 @@ import { BackstageApp, AppComponents, AppConfigLoader, - Apis, SignInResult, SignInPageProps, } from './types'; @@ -42,7 +41,6 @@ import { AppThemeProvider } from './AppThemeProvider'; import { IconComponent, SystemIcons, SystemIconKey } from '../icons'; import { - ApiHolder, ApiProvider, ApiRegistry, AppTheme, @@ -51,18 +49,22 @@ import { configApiRef, ConfigReader, useApi, + AnyApiFactory, + ApiHolder, } from '../apis'; -import { ApiAggregator } from '../apis/ApiAggregator'; import { useAsync } from 'react-use'; import { AppIdentity } from './AppIdentity'; +import { ApiFactoryRegistry } from '../apis/ApiFactoryRegistry'; +import { ApiResolver } from '../apis/ApiResolver'; type FullAppOptions = { - apis: Apis; + apis: Iterable; icons: SystemIcons; plugins: BackstagePlugin[]; components: AppComponents; themes: AppTheme[]; configLoader?: AppConfigLoader; + defaultApis: Iterable; }; function useConfigLoader( @@ -101,31 +103,27 @@ function useConfigLoader( } export class PrivateAppImpl implements BackstageApp { - private apis?: ApiHolder = undefined; + private apiHolder?: ApiHolder; + private configApi?: ConfigApi; + + private readonly apis: Iterable; private readonly icons: SystemIcons; private readonly plugins: BackstagePlugin[]; private readonly components: AppComponents; private readonly themes: AppTheme[]; private readonly configLoader?: AppConfigLoader; + private readonly defaultApis: Iterable; private readonly identityApi = new AppIdentity(); - private apisOrFactory: Apis; - constructor(options: FullAppOptions) { - this.apisOrFactory = options.apis; + this.apis = options.apis; this.icons = options.icons; this.plugins = options.plugins; this.components = options.components; this.themes = options.themes; this.configLoader = options.configLoader; - } - - getApis(): ApiHolder { - if (!this.apis) { - throw new Error('Tried to access APIs before app was loaded'); - } - return this.apis; + this.defaultApis = options.defaultApis; } getPlugins(): BackstagePlugin[] { @@ -186,12 +184,12 @@ export class PrivateAppImpl implements BackstageApp { } } - const FeatureFlags = this.apis && this.apis.get(featureFlagsApiRef); - if (FeatureFlags) { - FeatureFlags.registeredFeatureFlags = registeredFeatureFlags; + const featureFlags = this.getApiHolder().get(featureFlagsApiRef); + if (featureFlags) { + featureFlags.registeredFeatureFlags = registeredFeatureFlags; } - routes.push(} />); + routes.push(} />); return routes; } @@ -210,28 +208,14 @@ export class PrivateAppImpl implements BackstageApp { ); if ('node' in loadedConfig) { + // Loading or error return loadedConfig.node; } - const configApi = loadedConfig.api; - const appApis = ApiRegistry.from([ - [appThemeApiRef, appThemeApi], - [configApiRef, configApi], - [identityApiRef, this.identityApi], - ]); - - if (!this.apis) { - if ('get' in this.apisOrFactory) { - this.apis = this.apisOrFactory; - } else { - this.apis = this.apisOrFactory(configApi); - } - } - - const apis = new ApiAggregator(this.apis, appApis); + this.configApi = loadedConfig.api; return ( - + {children} @@ -306,6 +290,67 @@ export class PrivateAppImpl implements BackstageApp { return AppRouter; } + private getApiHolder(): ApiHolder { + if (this.apiHolder) { + return this.apiHolder; + } + + const registry = new ApiFactoryRegistry(); + + registry.register('static', { + api: appThemeApiRef, + deps: {}, + factory: () => AppThemeSelector.createWithStorage(this.themes), + }); + registry.register('static', { + api: configApiRef, + deps: {}, + factory: () => { + if (!this.configApi) { + throw new Error( + 'Tried to access config API before config was loaded', + ); + } + return this.configApi; + }, + }); + registry.register('static', { + api: identityApiRef, + deps: {}, + factory: () => this.identityApi, + }); + + for (const factory of this.defaultApis) { + registry.register('default', factory); + } + + for (const plugin of this.plugins) { + for (const factory of plugin.getApis()) { + if (!registry.register('default', factory)) { + throw new Error( + `Plugin ${plugin.getId()} tried to register duplicate or forbidden API factory for ${ + factory.api + }`, + ); + } + } + } + + for (const factory of this.apis) { + if (!registry.register('app', factory)) { + throw new Error( + `Duplicate or forbidden API factory for ${factory.api} in app`, + ); + } + } + + ApiResolver.validateFactories(registry, registry.getAllApis()); + + this.apiHolder = new ApiResolver(registry); + + return this.apiHolder; + } + verify() { const pluginIds = new Set(); diff --git a/packages/core-api/src/app/types.ts b/packages/core-api/src/app/types.ts index db7a0897b1..565e073aed 100644 --- a/packages/core-api/src/app/types.ts +++ b/packages/core-api/src/app/types.ts @@ -17,8 +17,8 @@ import { ComponentType } from 'react'; import { IconComponent, SystemIconKey, SystemIcons } from '../icons'; import { BackstagePlugin } from '../plugin'; -import { ApiHolder } from '../apis'; -import { AppTheme, ConfigApi, ProfileInfo } from '../apis/definitions'; +import { AnyApiFactory } from '../apis'; +import { AppTheme, ProfileInfo } from '../apis/definitions'; import { AppConfig } from '@backstage/config'; export type BootErrorPageProps = { @@ -77,16 +77,12 @@ export type AppComponents = { */ export type AppConfigLoader = () => Promise; -// TODO(Rugvip): Temporary workaround for accessing config when instantiating APIs, we might want to do this differently -export type Apis = ApiHolder | ((config: ConfigApi) => ApiHolder); - export type AppOptions = { /** - * A holder of all APIs available in the app. - * - * Use for example ApiRegistry or ApiTestRegistry. + * A collection of ApiFactories to register in the application to either + * add add new ones, or override factories provided by default or by plugins. */ - apis?: Apis; + apis?: Iterable; /** * Supply icons to override the default ones. @@ -138,11 +134,6 @@ export type AppOptions = { }; export type BackstageApp = { - /** - * Get the holder for all APIs available in the app. - */ - getApis(): ApiHolder; - /** * Returns all plugins registered for the app. */ diff --git a/packages/core-api/src/plugin/Plugin.tsx b/packages/core-api/src/plugin/Plugin.tsx index bf98919c2b..1835ec03ad 100644 --- a/packages/core-api/src/plugin/Plugin.tsx +++ b/packages/core-api/src/plugin/Plugin.tsx @@ -24,9 +24,11 @@ import { } from './types'; import { validateBrowserCompat, validateFlagName } from '../app/FeatureFlags'; import { RouteRef } from '../routing'; +import { AnyApiFactory } from '../apis'; export type PluginConfig = { id: string; + apis?: Iterable; register?(hooks: PluginHooks): void; }; @@ -65,6 +67,10 @@ export class PluginImpl { return this.config.id; } + getApis(): Iterable { + return this.config.apis ?? []; + } + output(): PluginOutput[] { if (this.storedOutput) { return this.storedOutput; diff --git a/packages/core-api/src/plugin/types.ts b/packages/core-api/src/plugin/types.ts index fabe97434e..12992f3620 100644 --- a/packages/core-api/src/plugin/types.ts +++ b/packages/core-api/src/plugin/types.ts @@ -16,6 +16,7 @@ import { ComponentType } from 'react'; import { RouteRef } from '../routing'; +import { AnyApiFactory } from '../apis'; export type RouteOptions = { // Whether the route path must match exactly, defaults to true. @@ -70,4 +71,5 @@ export type PluginOutput = export type BackstagePlugin = { getId(): string; output(): PluginOutput[]; + getApis(): Iterable; }; diff --git a/packages/core/package.json b/packages/core/package.json index d6731aca9a..7e9932bdc1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -32,7 +32,7 @@ "@backstage/config": "^0.1.1-alpha.21", "@backstage/core-api": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@types/react": "^16.9", diff --git a/packages/core/src/api-wrappers/createApp.test.tsx b/packages/core/src/api-wrappers/createApp.test.tsx index 33623b4869..a1655b88dd 100644 --- a/packages/core/src/api-wrappers/createApp.test.tsx +++ b/packages/core/src/api-wrappers/createApp.test.tsx @@ -15,21 +15,21 @@ */ import { defaultConfigLoader } from './createApp'; -import { AppConfig } from '@backstage/config'; + +(process as any).env = { NODE_ENV: 'test' }; +const anyEnv = process.env as any; describe('defaultConfigLoader', () => { afterEach(() => { - delete process.env.APP_CONFIG; + delete anyEnv.APP_CONFIG; }); it('loads static config', async () => { - Object.defineProperty(process.env, 'APP_CONFIG', { - configurable: true, - value: [ - { data: { my: 'config' }, context: 'a' }, - { data: { my: 'override-config' }, context: 'b' }, - ] as AppConfig[], - }); + anyEnv.APP_CONFIG = [ + { data: { my: 'config' }, context: 'a' }, + { data: { my: 'override-config' }, context: 'b' }, + ]; + const configs = await defaultConfigLoader(); expect(configs).toEqual([ { data: { my: 'config' }, context: 'a' }, @@ -38,13 +38,11 @@ describe('defaultConfigLoader', () => { }); it('loads runtime config', async () => { - Object.defineProperty(process.env, 'APP_CONFIG', { - configurable: true, - value: [ - { data: { my: 'override-config' }, context: 'a' }, - { data: { my: 'config' }, context: 'b' }, - ] as AppConfig[], - }); + anyEnv.APP_CONFIG = [ + { data: { my: 'override-config' }, context: 'a' }, + { data: { my: 'config' }, context: 'b' }, + ]; + const configs = await (defaultConfigLoader as any)( '{"my":"runtime-config"}', ); @@ -62,20 +60,14 @@ describe('defaultConfigLoader', () => { }); it('fails to load invalid static config', async () => { - Object.defineProperty(process.env, 'APP_CONFIG', { - configurable: true, - value: { my: 'invalid-config' } as any, - }); + anyEnv.APP_CONFIG = { my: 'invalid-config' }; await expect(defaultConfigLoader()).rejects.toThrow( 'Static configuration has invalid format', ); }); it('fails to load bad runtime config', async () => { - Object.defineProperty(process.env, 'APP_CONFIG', { - configurable: true, - value: [{ data: { my: 'config' }, context: 'a' }] as AppConfig[], - }); + anyEnv.APP_CONFIG = [{ data: { my: 'config' }, context: 'a' }]; await expect((defaultConfigLoader as any)('}')).rejects.toThrow( 'Failed to load runtime configuration, SyntaxError: Unexpected token } in JSON at position 0', diff --git a/packages/core/src/api-wrappers/createApp.tsx b/packages/core/src/api-wrappers/createApp.tsx index 9d2096cfff..7fe77423e2 100644 --- a/packages/core/src/api-wrappers/createApp.tsx +++ b/packages/core/src/api-wrappers/createApp.tsx @@ -17,7 +17,6 @@ import React, { FC } from 'react'; import privateExports, { AppOptions, - ApiRegistry, defaultSystemIcons, BootErrorPageProps, AppConfigLoader, @@ -26,6 +25,7 @@ import { BrowserRouter, MemoryRouter } from 'react-router-dom'; import { ErrorPage } from '../layout/ErrorPage'; import { Progress } from '../components/Progress'; +import { defaultApis } from './defaultApis'; import { lightTheme, darkTheme } from '@backstage/theme'; import { AppConfig, JsonObject } from '@backstage/config'; @@ -94,7 +94,7 @@ export function createApp(options?: AppOptions) { ); }; - const apis = options?.apis ?? ApiRegistry.from([]); + const apis = options?.apis ?? []; const icons = { ...defaultSystemIcons, ...options?.icons }; const plugins = options?.plugins ?? []; const components = { @@ -127,6 +127,7 @@ export function createApp(options?: AppOptions) { components, themes, configLoader, + defaultApis, }); app.verify(); diff --git a/packages/core/src/api-wrappers/defaultApis.ts b/packages/core/src/api-wrappers/defaultApis.ts new file mode 100644 index 0000000000..a3f0cb0251 --- /dev/null +++ b/packages/core/src/api-wrappers/defaultApis.ts @@ -0,0 +1,135 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + alertApiRef, + errorApiRef, + AlertApiForwarder, + ErrorApiForwarder, + ErrorAlerter, + featureFlagsApiRef, + FeatureFlags, + discoveryApiRef, + GoogleAuth, + GithubAuth, + OAuth2, + OktaAuth, + GitlabAuth, + Auth0Auth, + MicrosoftAuth, + oauthRequestApiRef, + OAuthRequestManager, + googleAuthApiRef, + githubAuthApiRef, + oauth2ApiRef, + oktaAuthApiRef, + gitlabAuthApiRef, + auth0AuthApiRef, + microsoftAuthApiRef, + storageApiRef, + WebStorage, + createApiFactory, + configApiRef, + UrlPatternDiscovery, +} from '@backstage/core-api'; + +export const defaultApis = [ + createApiFactory({ + api: discoveryApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => + UrlPatternDiscovery.compile( + `${configApi.getString('backend.baseUrl')}/api/{{ pluginId }}`, + ), + }), + createApiFactory(alertApiRef, new AlertApiForwarder()), + createApiFactory({ + api: errorApiRef, + deps: { alertApi: alertApiRef }, + factory: ({ alertApi }) => + new ErrorAlerter(alertApi, new ErrorApiForwarder()), + }), + createApiFactory({ + api: storageApiRef, + deps: { errorApi: errorApiRef }, + factory: ({ errorApi }) => WebStorage.create({ errorApi }), + }), + createApiFactory(featureFlagsApiRef, new FeatureFlags()), + createApiFactory(oauthRequestApiRef, new OAuthRequestManager()), + createApiFactory({ + api: googleAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + GoogleAuth.create({ discoveryApi, oauthRequestApi }), + }), + createApiFactory({ + api: microsoftAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + MicrosoftAuth.create({ discoveryApi, oauthRequestApi }), + }), + createApiFactory({ + api: githubAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + GithubAuth.create({ discoveryApi, oauthRequestApi }), + }), + createApiFactory({ + api: oktaAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + OktaAuth.create({ discoveryApi, oauthRequestApi }), + }), + createApiFactory({ + api: gitlabAuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + GitlabAuth.create({ discoveryApi, oauthRequestApi }), + }), + createApiFactory({ + api: auth0AuthApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + Auth0Auth.create({ discoveryApi, oauthRequestApi }), + }), + createApiFactory({ + api: oauth2ApiRef, + deps: { + discoveryApi: discoveryApiRef, + oauthRequestApi: oauthRequestApiRef, + }, + factory: ({ discoveryApi, oauthRequestApi }) => + OAuth2.create({ discoveryApi, oauthRequestApi }), + }), +]; diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx index c0f57d6330..77f3ca51cc 100644 --- a/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx @@ -86,3 +86,9 @@ export const Languages = () => ( ); + +export const CopyCode = () => ( + + + +); diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx index 42efbf14af..1a76f84f44 100644 --- a/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; import { CodeSnippet } from './CodeSnippet'; @@ -55,4 +55,14 @@ describe('', () => { expect(queryByText(/2/)).toBeInTheDocument(); expect(queryByText(/3/)).toBeInTheDocument(); }); + + it('copy code using button', async () => { + document.execCommand = jest.fn(); + const rendered = render( + wrapInTestApp(), + ); + const button = rendered.getByTitle('Text copied to clipboard'); + fireEvent.click(button); + expect(document.execCommand).toHaveBeenCalled(); + }); }); diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.tsx index 324d71e936..b6d9b3a5aa 100644 --- a/packages/core/src/components/CodeSnippet/CodeSnippet.tsx +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.tsx @@ -20,19 +20,22 @@ import SyntaxHighlighter from 'react-syntax-highlighter'; import { docco, dark } from 'react-syntax-highlighter/dist/cjs/styles/hljs'; import { useTheme } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; +import { CopyTextButton } from '../CopyTextButton'; type Props = { text: string; language: string; showLineNumbers?: boolean; + showCopyCodeButton?: boolean; }; const defaultProps = { showLineNumbers: false, + showCopyCodeButton: false, }; export const CodeSnippet: FC = props => { - const { text, language, showLineNumbers } = { + const { text, language, showLineNumbers, showCopyCodeButton } = { ...defaultProps, ...props, }; @@ -41,13 +44,20 @@ export const CodeSnippet: FC = props => { const mode = theme.palette.type === 'dark' ? dark : docco; return ( - - {text} - +

); }; @@ -56,4 +66,5 @@ CodeSnippet.propTypes = { text: PropTypes.string.isRequired, language: PropTypes.string.isRequired, showLineNumbers: PropTypes.bool, + showCopyCodeButton: PropTypes.bool, }; diff --git a/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx b/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx index e789035b44..cab992e11a 100644 --- a/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx +++ b/packages/core/src/components/CopyTextButton/CopyTextButton.test.tsx @@ -15,7 +15,7 @@ */ import React from 'react'; -import { render } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; import { CopyTextButton } from './CopyTextButton'; import { @@ -76,7 +76,7 @@ describe('', () => { ), ); const button = rendered.getByTitle('mockTooltip'); - button.click(); + fireEvent.click(button); expect(document.execCommand).toHaveBeenCalled(); rendered.getByText('mockTooltip'); }); diff --git a/packages/core/src/components/CopyTextButton/CopyTextButton.tsx b/packages/core/src/components/CopyTextButton/CopyTextButton.tsx index e4773165cc..cb322e5b56 100644 --- a/packages/core/src/components/CopyTextButton/CopyTextButton.tsx +++ b/packages/core/src/components/CopyTextButton/CopyTextButton.tsx @@ -63,7 +63,7 @@ export const CopyTextButton: FC = props => { }; const classes = useStyles(props); const errorApi = useApi(errorApiRef); - const inputRef = useRef(null); + const inputRef = useRef(null); const [open, setOpen] = useState(false); const handleCopyClick: MouseEventHandler = e => { @@ -82,9 +82,8 @@ export const CopyTextButton: FC = props => { return ( <> - diff --git a/packages/core/src/components/ProgressBars/ProgressCard.stories.tsx b/packages/core/src/components/ProgressBars/GaugeCard.stories.tsx similarity index 69% rename from packages/core/src/components/ProgressBars/ProgressCard.stories.tsx rename to packages/core/src/components/ProgressBars/GaugeCard.stories.tsx index 62c9f3be6e..922bb63b2f 100644 --- a/packages/core/src/components/ProgressBars/ProgressCard.stories.tsx +++ b/packages/core/src/components/ProgressBars/GaugeCard.stories.tsx @@ -15,26 +15,26 @@ */ import React from 'react'; -import { ProgressCard } from './ProgressCard'; +import { GaugeCard } from './GaugeCard'; import { Grid } from '@material-ui/core'; const linkInfo = { title: 'Go to XYZ Location', link: '#' }; export default { title: 'Progress Card', - component: ProgressCard, + component: GaugeCard, }; export const Default = () => ( - + - + - + ); @@ -42,21 +42,17 @@ export const Default = () => ( export const Subhead = () => ( - + - - ( export const LinkInFooter = () => ( - + - + - + ); diff --git a/packages/core/src/components/ProgressBars/ProgressCard.test.jsx b/packages/core/src/components/ProgressBars/GaugeCard.test.jsx similarity index 75% rename from packages/core/src/components/ProgressBars/ProgressCard.test.jsx rename to packages/core/src/components/ProgressBars/GaugeCard.test.jsx index 8568077a92..27ef0bb188 100644 --- a/packages/core/src/components/ProgressBars/ProgressCard.test.jsx +++ b/packages/core/src/components/ProgressBars/GaugeCard.test.jsx @@ -18,32 +18,30 @@ import React from 'react'; import { render } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; -import { ProgressCard } from './ProgressCard'; +import { GaugeCard } from './GaugeCard'; const minProps = { title: 'Tingle upgrade', progress: 0.12 }; -describe('', () => { +describe('', () => { it('renders without exploding', () => { - const { getByText } = render(wrapInTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText(/Tingle.*/)).toBeInTheDocument(); }); it('renders progress and title', () => { - const { getByText } = render(wrapInTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText(/Tingle.*/)).toBeInTheDocument(); expect(getByText(/12%.*/)).toBeInTheDocument(); }); it('does not render deepLink', () => { - const { queryByText } = render( - wrapInTestApp(), - ); + const { queryByText } = render(wrapInTestApp()); expect(queryByText('View more')).not.toBeInTheDocument(); }); it('handles invalid numbers', () => { const badProps = { title: 'Tingle upgrade', progress: 'hejjo' }; - const { getByText } = render(wrapInTestApp()); + const { getByText } = render(wrapInTestApp()); expect(getByText(/N\/A.*/)).toBeInTheDocument(); }); }); diff --git a/packages/core/src/components/ProgressBars/ProgressCard.tsx b/packages/core/src/components/ProgressBars/GaugeCard.tsx similarity index 90% rename from packages/core/src/components/ProgressBars/ProgressCard.tsx rename to packages/core/src/components/ProgressBars/GaugeCard.tsx index eef6312600..fc7055f705 100644 --- a/packages/core/src/components/ProgressBars/ProgressCard.tsx +++ b/packages/core/src/components/ProgressBars/GaugeCard.tsx @@ -18,7 +18,7 @@ import React, { FC } from 'react'; import { makeStyles } from '@material-ui/core'; import { InfoCard } from '../../layout/InfoCard'; import { BottomLinkProps } from '../../layout/BottomLink'; -import { CircleProgress } from './CircleProgress'; +import { GaugeProgress } from './GaugeProgress'; type Props = { title: string; @@ -36,7 +36,7 @@ const useStyles = makeStyles({ }, }); -export const ProgressCard: FC = props => { +export const GaugeCard: FC = props => { const classes = useStyles(props); const { title, subheader, progress, deepLink, variant } = props; @@ -48,7 +48,7 @@ export const ProgressCard: FC = props => { deepLink={deepLink} variant={variant} > - + ); diff --git a/packages/core/src/components/ProgressBars/CircleProgress.test.jsx b/packages/core/src/components/ProgressBars/GaugeProgress.test.jsx similarity index 82% rename from packages/core/src/components/ProgressBars/CircleProgress.test.jsx rename to packages/core/src/components/ProgressBars/GaugeProgress.test.jsx index 9b9eae1bb8..778abdf12c 100644 --- a/packages/core/src/components/ProgressBars/CircleProgress.test.jsx +++ b/packages/core/src/components/ProgressBars/GaugeProgress.test.jsx @@ -17,32 +17,32 @@ import React from 'react'; import { render } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; -import { CircleProgress, getProgressColor } from './CircleProgress'; +import { GaugeProgress, getProgressColor } from './GaugeProgress'; -describe('', () => { +describe('', () => { it('renders without exploding', () => { const { getByText } = render( - wrapInTestApp(), + wrapInTestApp(), ); getByText('10%'); }); it('handles fractional prop', () => { const { getByText } = render( - wrapInTestApp(), + wrapInTestApp(), ); getByText('10%'); }); it('handles max prop', () => { const { getByText } = render( - wrapInTestApp(), + wrapInTestApp(), ); getByText('1%'); }); it('handles unit prop', () => { const { getByText } = render( - wrapInTestApp(), + wrapInTestApp(), ); getByText('10m'); }); diff --git a/packages/core/src/components/ProgressBars/CircleProgress.tsx b/packages/core/src/components/ProgressBars/GaugeProgress.tsx similarity index 98% rename from packages/core/src/components/ProgressBars/CircleProgress.tsx rename to packages/core/src/components/ProgressBars/GaugeProgress.tsx index 79a451b14e..14776ed431 100644 --- a/packages/core/src/components/ProgressBars/CircleProgress.tsx +++ b/packages/core/src/components/ProgressBars/GaugeProgress.tsx @@ -77,7 +77,7 @@ export function getProgressColor( return palette.status.ok; } -export const CircleProgress: FC = props => { +export const GaugeProgress: FC = props => { const classes = useStyles(props); const theme = useTheme(); const { value, fractional, inverse, unit, max } = { diff --git a/packages/core/src/components/ProgressBars/HorizontalProgress.stories.tsx b/packages/core/src/components/ProgressBars/LinearGauge.stories.tsx similarity index 79% rename from packages/core/src/components/ProgressBars/HorizontalProgress.stories.tsx rename to packages/core/src/components/ProgressBars/LinearGauge.stories.tsx index 6e8f4ed7fd..c4492986b6 100644 --- a/packages/core/src/components/ProgressBars/HorizontalProgress.stories.tsx +++ b/packages/core/src/components/ProgressBars/LinearGauge.stories.tsx @@ -15,29 +15,29 @@ */ import React from 'react'; -import { HorizontalProgress } from './HorizontalProgress'; +import { LinearGauge } from './LinearGauge'; const containerStyle = { width: 300 }; export default { - title: 'HorizontalProgress', - component: HorizontalProgress, + title: 'LinearGauge', + component: LinearGauge, }; export const Default = () => (
- +
); export const MediumProgress = () => (
- +
); export const LowProgress = () => (
- +
); diff --git a/packages/core/src/components/ProgressBars/HorizontalProgress.tsx b/packages/core/src/components/ProgressBars/LinearGauge.tsx similarity index 92% rename from packages/core/src/components/ProgressBars/HorizontalProgress.tsx rename to packages/core/src/components/ProgressBars/LinearGauge.tsx index 72bf1f34c3..73163b345f 100644 --- a/packages/core/src/components/ProgressBars/HorizontalProgress.tsx +++ b/packages/core/src/components/ProgressBars/LinearGauge.tsx @@ -19,7 +19,7 @@ import { Tooltip, useTheme } from '@material-ui/core'; // @ts-ignore import { Line } from 'rc-progress'; import { BackstageTheme } from '@backstage/theme'; -import { getProgressColor } from './CircleProgress'; +import { getProgressColor } from './GaugeProgress'; type Props = { /** @@ -28,7 +28,7 @@ type Props = { value: number; }; -export const HorizontalProgress: FC = ({ value }) => { +export const LinearGauge: FC = ({ value }) => { const theme = useTheme(); if (isNaN(value)) { return null; diff --git a/packages/core/src/components/ProgressBars/index.ts b/packages/core/src/components/ProgressBars/index.ts index c74e283ae6..c7131c8831 100644 --- a/packages/core/src/components/ProgressBars/index.ts +++ b/packages/core/src/components/ProgressBars/index.ts @@ -14,6 +14,6 @@ * limitations under the License. */ -export { ProgressCard } from './ProgressCard'; -export { CircleProgress } from './CircleProgress'; -export { HorizontalProgress } from './HorizontalProgress'; +export { GaugeCard } from './GaugeCard'; +export { GaugeProgress } from './GaugeProgress'; +export { LinearGauge } from './LinearGauge'; diff --git a/packages/core/src/components/SimpleStepper/SimpleStepper.stories.tsx b/packages/core/src/components/SimpleStepper/SimpleStepper.stories.tsx index 81f558f49d..52710ffeaf 100644 --- a/packages/core/src/components/SimpleStepper/SimpleStepper.stories.tsx +++ b/packages/core/src/components/SimpleStepper/SimpleStepper.stories.tsx @@ -51,7 +51,7 @@ export const ConditionalButtons = () => { setRequired(!!e.target.value)} + onChange={e => setRequired(!!e.target.value)} /> diff --git a/packages/core/src/components/WarningPanel/WarningPanel.tsx b/packages/core/src/components/WarningPanel/WarningPanel.tsx index ab0927fc4c..ae4d2bff02 100644 --- a/packages/core/src/components/WarningPanel/WarningPanel.tsx +++ b/packages/core/src/components/WarningPanel/WarningPanel.tsx @@ -14,10 +14,10 @@ * limitations under the License. */ -import React, { FC } from 'react'; -import { Typography, makeStyles } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; +import { makeStyles, Typography } from '@material-ui/core'; import ErrorOutline from '@material-ui/icons/ErrorOutline'; +import React from 'react'; const useErrorOutlineStyles = makeStyles(theme => ({ root: { @@ -60,9 +60,10 @@ const useStyles = makeStyles(theme => ({ type Props = { message?: React.ReactNode; title?: string; + children?: React.ReactNode; }; -export const WarningPanel: FC = props => { +export const WarningPanel = (props: Props) => { const classes = useStyles(props); const { title, message, children } = props; return ( diff --git a/packages/core/src/components/stories/Chip.stories.tsx b/packages/core/src/components/stories/Chip.stories.tsx new file mode 100644 index 0000000000..c0e644fcc5 --- /dev/null +++ b/packages/core/src/components/stories/Chip.stories.tsx @@ -0,0 +1,41 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Chip } from '@material-ui/core'; + +export default { + title: 'Chip', + component: Chip, +}; + +export const Default = () => ; + +export const LargeDeletable = () => ( + ({})} /> +); + +export const LargeNotDeletable = () => ( + +); + +export const SmallDeletable = () => ( + ({})} /> +); + +export const SmallNotDeletable = () => ( + +); diff --git a/packages/core/src/layout/InfoCard/InfoCard.stories.tsx b/packages/core/src/layout/InfoCard/InfoCard.stories.tsx index 7d888f5486..3e476c5480 100644 --- a/packages/core/src/layout/InfoCard/InfoCard.stories.tsx +++ b/packages/core/src/layout/InfoCard/InfoCard.stories.tsx @@ -15,9 +15,8 @@ */ import React, { FC } from 'react'; import { InfoCard } from '.'; -import { Grid } from '@material-ui/core'; +import { Grid, Typography } from '@material-ui/core'; -const cardContentStyle = { height: 200, width: 500 }; const linkInfo = { title: 'Go to XYZ Location', link: '#' }; export default { @@ -25,24 +24,35 @@ export default { component: InfoCard, }; +const text = ( + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat + non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. + +); + const Wrapper: FC<{}> = ({ children }) => ( - {children} + + {children} + ); export const Default = () => ( - -
- + {text} ); export const Subhead = () => ( - -
+ + {text} ); @@ -50,7 +60,7 @@ export const Subhead = () => ( export const LinkInFooter = () => ( -
+ {text} ); diff --git a/packages/core/src/layout/InfoCard/InfoCard.tsx b/packages/core/src/layout/InfoCard/InfoCard.tsx index 86e9c79ced..6914d396b1 100644 --- a/packages/core/src/layout/InfoCard/InfoCard.tsx +++ b/packages/core/src/layout/InfoCard/InfoCard.tsx @@ -14,12 +14,13 @@ * limitations under the License. */ -import React, { FC, ReactNode } from 'react'; +import React, { ReactNode } from 'react'; import { Card, CardActions, CardContent, CardHeader, + CardHeaderProps, Divider, withStyles, makeStyles, @@ -29,22 +30,26 @@ import { ErrorBoundary } from '../ErrorBoundary'; import { BottomLink, BottomLinkProps } from '../BottomLink'; const useStyles = makeStyles(theme => ({ - header: { - padding: theme.spacing(2, 2, 2, 2.5), - }, noPadding: { padding: 0, '&:last-child': { paddingBottom: 0, }, }, + header: { + padding: theme.spacing(2, 2, 2, 2.5), + }, + headerTitle: { + fontWeight: 700, + }, + headerSubheader: { + paddingTop: theme.spacing(1), + }, + headerAvatar: {}, + headerAction: {}, + headerContent: {}, })); -const BoldHeader = withStyles(theme => ({ - title: { fontWeight: 700 }, - subheader: { paddingTop: theme.spacing(1) }, -}))(CardHeader); - const CardActionsTopRight = withStyles(theme => ({ root: { display: 'inline-block', @@ -130,7 +135,7 @@ type Props = { cardStyle?: object; children?: ReactNode; headerStyle?: object; - headerProps?: object; + headerProps?: CardHeaderProps; actionsClassName?: string; actions?: ReactNode; cardClassName?: string; @@ -139,7 +144,7 @@ type Props = { noPadding?: boolean; }; -export const InfoCard: FC = ({ +export const InfoCard = ({ title, subheader, divider, @@ -155,7 +160,7 @@ export const InfoCard: FC = ({ actionsTopRight, className, noPadding, -}) => { +}: Props): JSX.Element => { const classes = useStyles(); /** @@ -186,8 +191,15 @@ export const InfoCard: FC = ({ {title && ( <> - { +const tabs = [ + { label: 'Overview' }, + { label: 'CI/CD' }, + { label: 'Cost Efficiency' }, + { label: 'Code Coverage' }, + { label: 'Test' }, + { label: 'Compliance Advisor' }, +]; + +const DataGrid = () => ( + + + + + + + + + + + + + + + + + + + Rightsize GKE deployment + + Services are considered underutilized in GKE when the average usage of + requested cores is less than 80%. + + What can I do? + + Review requested core and limit settings. Check HPA target scaling + settings in hpa.yaml. The recommended value for  + targetCPUUtilizationPercentage is 80. + + + For single pods, there is of course no HPA. But it can also be useful + to think about a single pod out of a larger deployment, then modify + based on HPA requirements. Within a pod, each container has its own + CPU and memory requests and limits. + + Definitions + + A request is a minimum reserved value; a container will never have + less than this amount allocated to it, even if it doesn't actually use + it. Requests are used for determining what nodes to schedule pods on + (bin-packing). The tension here is between not allocating resources we + don't need, and having easy-enough access to enough resources to be + able to function. + + + Contact #cost-awareness for information and support. + + + + +); + +const ExampleHeader = () => ( +
+ + +
+); + +const ExampleContentHeader = ({ selectedTab }: { selectedTab?: number }) => ( + + + This Plugin is an example. This text could provide usefull information for + the user. + + +); + +export const PluginWithData = () => { + const [selectedTab, setSelectedTab] = useState(2); return ( - -
- - -
- - - - - This Plugin is an example. This text could provide usefull - information for the user. - - - + + + setSelectedTab(index)} + tabs={tabs.map(({ label }, index) => ({ + id: index.toString(), + label, + }))} /> - - + + + + + + + ); +}; + +export const PluginWithTable = () => { + return ( +
+ + + + +
+ + + ); }; diff --git a/packages/core/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core/src/layout/Sidebar/Sidebar.stories.tsx index b286071426..d7451965fe 100644 --- a/packages/core/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core/src/layout/Sidebar/Sidebar.stories.tsx @@ -29,9 +29,7 @@ import HomeOutlinedIcon from '@material-ui/icons/HomeOutlined'; import AddCircleOutlineIcon from '@material-ui/icons/AddCircleOutline'; import Star from '@material-ui/icons/Star'; import { MemoryRouter } from 'react-router-dom'; -import { - githubAuthApiRef, -} from '@backstage/core-api'; +import { githubAuthApiRef } from '@backstage/core-api'; export default { title: 'Sidebar', @@ -60,12 +58,14 @@ export const SampleSidebar = () => ( - - } /> + + } + /> ); diff --git a/packages/create-app/templates/default-app/.gitignore b/packages/create-app/templates/default-app/.gitignore index 3e786d566e..4f9065c60b 100644 --- a/packages/create-app/templates/default-app/.gitignore +++ b/packages/create-app/templates/default-app/.gitignore @@ -22,6 +22,7 @@ node_modules/ # Build output dist +dist-types # Temporary change files created by Vim *.swp diff --git a/packages/create-app/templates/default-app/app-config.development.yaml b/packages/create-app/templates/default-app/app-config.development.yaml new file mode 100644 index 0000000000..da274ba1a8 --- /dev/null +++ b/packages/create-app/templates/default-app/app-config.development.yaml @@ -0,0 +1,11 @@ +app: + baseUrl: http://localhost:3000 + +backend: + baseUrl: http://localhost:7000 + listen: + port: 7000 + cors: + origin: http://localhost:3000 + methods: [GET, POST, PUT, DELETE] + credentials: true diff --git a/packages/create-app/templates/default-app/app-config.yaml.hbs b/packages/create-app/templates/default-app/app-config.yaml.hbs index dea37814c1..7b86b4f50e 100644 --- a/packages/create-app/templates/default-app/app-config.yaml.hbs +++ b/packages/create-app/templates/default-app/app-config.yaml.hbs @@ -1,6 +1,6 @@ app: title: Scaffolded Backstage App - baseUrl: http://localhost:3000 + baseUrl: http://localhost:7000 organization: name: Acme Corporation @@ -9,10 +9,6 @@ backend: baseUrl: http://localhost:7000 listen: port: 7000 - cors: - origin: http://localhost:3000 - methods: [GET, POST, PUT, DELETE] - credentials: true {{#if dbTypeSqlite}} database: client: sqlite3 @@ -43,6 +39,7 @@ proxy: techdocs: storageUrl: http://localhost:7000/techdocs/static/docs + requestUrl: http://localhost:7000/techdocs/docs lighthouse: baseUrl: http://localhost:3003 @@ -54,25 +51,12 @@ catalog: locations: # Backstage example components - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/artist-lookup-component.yaml + target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/all-components.yaml + + # Backstage example APIs - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-order-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/podcast-api-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/queue-proxy-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/searcher-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/playback-lib-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/www-artist-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/shuffle-api-component.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/hello-world-api.yaml - - type: github - target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/streetlights-api.yaml + target: https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/all-apis.yaml + # Backstage example templates - type: github target: https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index af4384318a..b95b5bbc5b 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -9,6 +9,7 @@ "start": "yarn workspace app start", "build": "lerna run build", "tsc": "tsc", + "tsc:full": "tsc --skipLibCheck false --incremental false", "clean": "backstage-cli clean && lerna run clean", "diff": "lerna run diff --", "test": "lerna run test --since origin/master -- --coverage", diff --git a/packages/create-app/templates/default-app/packages/app/package.json.hbs b/packages/create-app/templates/default-app/packages/app/package.json.hbs index c80d9c92d8..a057826ba4 100644 --- a/packages/create-app/templates/default-app/packages/app/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/app/package.json.hbs @@ -4,10 +4,11 @@ "private": true, "bundled": true, "dependencies": { - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@backstage/cli": "^{{version}}", "@backstage/core": "^{{version}}", + "@backstage/plugin-api-docs": "^{{version}}", "@backstage/plugin-catalog": "^{{version}}", "@backstage/plugin-register-component": "^{{version}}", "@backstage/plugin-scaffolder": "^{{version}}", diff --git a/packages/create-app/templates/default-app/packages/app/src/App.tsx b/packages/create-app/templates/default-app/packages/app/src/App.tsx index f002bbc7c7..9449ac68a1 100644 --- a/packages/create-app/templates/default-app/packages/app/src/App.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/App.tsx @@ -4,12 +4,17 @@ import { AlertDisplay, OAuthRequestDialog, SidebarPage, + createRouteRef, } from '@backstage/core'; import { apis } from './apis'; import * as plugins from './plugins'; import { AppSidebar } from './sidebar'; import { Route, Routes, Navigate } from 'react-router'; import { Router as CatalogRouter } from '@backstage/plugin-catalog'; +import { Router as DocsRouter } from '@backstage/plugin-techdocs'; +import { Router as RegisterComponentRouter } from '@backstage/plugin-register-component'; +import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; + import { EntityPage } from './components/catalog/EntityPage'; const app = createApp({ @@ -21,6 +26,12 @@ const AppProvider = app.getProvider(); const AppRouter = app.getRouter(); const deprecatedAppRoutes = app.getRoutes(); +const catalogRouteRef = createRouteRef({ + path: '/catalog', + title: 'Service Catalog', +}); + + const App: FC<{}> = () => ( @@ -29,11 +40,20 @@ const App: FC<{}> = () => ( + } /> - + } /> + } + /> + } + /> {deprecatedAppRoutes} diff --git a/packages/create-app/templates/default-app/packages/app/src/apis.ts b/packages/create-app/templates/default-app/packages/app/src/apis.ts index 14351eaba7..e0503e504f 100644 --- a/packages/create-app/templates/default-app/packages/app/src/apis.ts +++ b/packages/create-app/templates/default-app/packages/app/src/apis.ts @@ -1,89 +1,17 @@ import { - ApiRegistry, - alertApiRef, - errorApiRef, - AlertApiForwarder, - ConfigApi, - ErrorApiForwarder, - ErrorAlerter, discoveryApiRef, UrlPatternDiscovery, - oauthRequestApiRef, - OAuthRequestManager, - storageApiRef, - WebStorage, + createApiFactory, + configApiRef, } from '@backstage/core'; -import { - lighthouseApiRef, - LighthouseRestApi, -} from '@backstage/plugin-lighthouse'; - -import { - GithubActionsClient, - githubActionsApiRef, -} from '@backstage/plugin-github-actions'; - -import { - techdocsStorageApiRef, - TechDocsStorageApi, -} from '@backstage/plugin-techdocs'; - -import { techRadarApiRef, TechRadar } from '@backstage/plugin-tech-radar'; - -import { catalogApiRef, CatalogClient } from '@backstage/plugin-catalog'; -import { CircleCIApi, circleCIApiRef } from '@backstage/plugin-circleci'; - -import { scaffolderApiRef, ScaffolderApi } from '@backstage/plugin-scaffolder'; - - - -export const apis = (config: ConfigApi) => { - // eslint-disable-next-line no-console - console.log(`Creating APIs for ${config.getString('app.title')}`); - - const backendUrl = config.getString('backend.baseUrl'); - const techdocsStorageUrl = config.getString('techdocs.storageUrl'); - - const builder = ApiRegistry.builder(); - - const discoveryApi = builder.add( - discoveryApiRef, - UrlPatternDiscovery.compile(`${backendUrl}/{{ pluginId }}`), - ); - const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); - const errorApi = builder.add( - errorApiRef, - new ErrorAlerter(alertApi, new ErrorApiForwarder()), - ); - - builder.add(storageApiRef, WebStorage.create({ errorApi })); - builder.add(oauthRequestApiRef, new OAuthRequestManager()); - - builder.add(catalogApiRef, new CatalogClient({ discoveryApi })); - builder.add(githubActionsApiRef, new GithubActionsClient()); - - builder.add(lighthouseApiRef, new LighthouseRestApi('http://localhost:3003')); - - builder.add( - circleCIApiRef, - new CircleCIApi(`${backendUrl}/proxy/circleci/api`), - ); - - builder.add(scaffolderApiRef, new ScaffolderApi({ discoveryApi })); - - builder.add( - techRadarApiRef, - new TechRadar({ - width: 1500, - height: 800, - }), - ); - - builder.add( - techdocsStorageApiRef, - new TechDocsStorageApi({ apiOrigin: techdocsStorageUrl }), - ); - - return builder.build(); -}; +export const apis = [ + createApiFactory({ + api: discoveryApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => + UrlPatternDiscovery.compile( + `${configApi.getString('backend.baseUrl')}/{{ pluginId }}`, + ), + }), +]; diff --git a/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx b/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx index 4087789deb..5480d8218a 100644 --- a/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/components/catalog/EntityPage.tsx @@ -13,7 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Router as GitHubActionsRouter } from '@backstage/plugin-github-actions'; +import { + Router as GitHubActionsRouter, + isPluginApplicableToEntity as isGitHubActionsAvailable, +} from '@backstage/plugin-github-actions'; +import { + Router as CircleCIRouter, + isPluginApplicableToEntity as isCircleCIAvailable, +} from '@backstage/plugin-circleci'; +import { Router as ApiDocsRouter } from '@backstage/plugin-api-docs'; +import { EmbeddedDocsRouter as DocsRouter } from '@backstage/plugin-techdocs'; + import React from 'react'; import { EntityPageLayout, @@ -21,9 +31,33 @@ import { AboutCard, } from '@backstage/plugin-catalog'; import { Entity } from '@backstage/catalog-model'; +import { Grid } from '@material-ui/core'; +import { WarningPanel } from '@backstage/core'; + +const CICDSwitcher = ({ entity }: { entity: Entity }) => { + // This component is just an example of how you can implement your company's logic in entity page. + // You can for example enforce that all components of type 'service' should use GitHubActions + switch (true) { + case isGitHubActionsAvailable(entity): + return ; + case isCircleCIAvailable(entity): + return ; + default: + return ( + + No CI/CD is available for this entity. Check corresponding + annotations! + + ); + } +}; const OverviewContent = ({ entity }: { entity: Entity }) => ( - + + + + + ); const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( @@ -36,7 +70,17 @@ const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( } + element={} + /> + } + /> + } /> ); @@ -51,7 +95,12 @@ const WebsiteEntityPage = ({ entity }: { entity: Entity }) => ( } + element={} + /> + } /> ); @@ -63,6 +112,11 @@ const DefaultEntityPage = ({ entity }: { entity: Entity }) => ( title="Overview" element={} /> + } + /> ); diff --git a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx index fa9a397751..9e343b86ac 100644 --- a/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx +++ b/packages/create-app/templates/default-app/packages/app/src/sidebar.tsx @@ -2,7 +2,6 @@ import React from 'react'; import HomeIcon from '@material-ui/icons/Home'; import LibraryBooks from '@material-ui/icons/LibraryBooks'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; -import ExploreIcon from '@material-ui/icons/Explore'; import BuildIcon from '@material-ui/icons/BuildRounded'; import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; import MapIcon from '@material-ui/icons/MyLocation'; @@ -23,7 +22,6 @@ export const AppSidebar = () => ( {/* Global nav, not org-specific */} - diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index 3e8ba36cec..a7bd814b19 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -2,8 +2,15 @@ FROM node:12 WORKDIR /usr/src/app -COPY . . +# Copy repo skeleton first, to avoid unnecessary docker cache invalidation. +# The skeleton contains the package.json of each package in the monorepo, +# and along with yarn.lock and the root package.json, that's enough to run yarn install. +ADD yarn.lock package.json skeleton.tar ./ RUN yarn install --frozen-lockfile --production +# This will copy the contents of the dist-workspace when running the build-image command. +# Do not use this Dockerfile outside of that command, as it will copy in the source code instead. +COPY . . + CMD ["node", "packages/backend"] diff --git a/packages/create-app/templates/default-app/packages/backend/README.md b/packages/create-app/templates/default-app/packages/backend/README.md index f94904a930..5583bff625 100644 --- a/packages/create-app/templates/default-app/packages/backend/README.md +++ b/packages/create-app/templates/default-app/packages/backend/README.md @@ -3,8 +3,8 @@ This package is an EXAMPLE of a Backstage backend. The main purpose of this package is to provide a test bed for Backstage plugins -that have a backend part. Feel free to experiment locally or within your fork -by adding dependencies and routes to this backend, to try things out. +that have a backend part. Feel free to experiment locally or within your fork by +adding dependencies and routes to this backend, to try things out. Our goal is to eventually amend the create-app flow of the CLI, such that a production ready version of a backend skeleton is made alongside the frontend @@ -33,34 +33,32 @@ LOG_LEVEL=debug \ yarn start ``` -Substitute `x` for actual values, or leave them as -dummy values just to try out the backend without using the auth or sentry features. +Substitute `x` for actual values, or leave them as dummy values just to try out +the backend without using the auth or sentry features. The backend starts up on port 7000 per default. ## Populating The Catalog -If you want to use the catalog functionality, you need to add so called locations -to the backend. These are places where the backend can find some entity descriptor -data to consume and serve. +If you want to use the catalog functionality, you need to add so called +locations to the backend. These are places where the backend can find some +entity descriptor data to consume and serve. For more information, see +[Software Catalog Overview - Adding Components to the Catalog](https://backstage.io/docs/features/software-catalog/software-catalog-overview#adding-components-to-the-catalog). -To get started, you can issue the following after starting the backend, from inside -the `plugins/catalog-backend` directory: - -```bash -yarn mock-data -``` - -You should then start seeing data on `localhost:7000/catalog/entities`. - -The catalog currently runs in-memory only, so feel free to try it out, but it will -need to be re-populated on next startup. +To get started quickly, this template already includes some statically configured example locations +in `app-config.yaml` under `catalog.locations`. You can remove and replace these locations as you +like, and also override them for local development in `app-config.local.yaml`. ## Authentication -We chose [Passport](http://www.passportjs.org/) as authentication platform due to its comprehensive set of supported authentication [strategies](http://www.passportjs.org/packages/). +We chose [Passport](http://www.passportjs.org/) as authentication platform due +to its comprehensive set of supported authentication +[strategies](http://www.passportjs.org/packages/). -Read more about the [auth-backend](https://github.com/spotify/backstage/blob/master/plugins/auth-backend/README.md) and [how to add a new provider](https://github.com/spotify/backstage/blob/master/docs/auth/add-auth-provider.md) +Read more about the +[auth-backend](https://github.com/spotify/backstage/blob/master/plugins/auth-backend/README.md) +and +[how to add a new provider](https://github.com/spotify/backstage/blob/master/docs/auth/add-auth-provider.md) ## Documentation diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index 53bfd6d990..044ee1560a 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -9,7 +9,7 @@ }, "scripts": { "build": "backstage-cli backend:build", - "build-image": "backstage-cli backend:build-image example-backend", + "build-image": "backstage-cli backend:build-image --build --tag example-backend", "start": "backstage-cli backend:dev", "lint": "backstage-cli lint", "test": "backstage-cli test", diff --git a/packages/create-app/templates/default-app/tsconfig.json b/packages/create-app/templates/default-app/tsconfig.json index cccc375f63..ba3f90177d 100644 --- a/packages/create-app/templates/default-app/tsconfig.json +++ b/packages/create-app/templates/default-app/tsconfig.json @@ -8,8 +8,7 @@ ], "exclude": ["node_modules"], "compilerOptions": { - "outDir": "dist", - "rootDir": ".", - "skipLibCheck": true + "outDir": "dist-types", + "rootDir": "." } } diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index c917130cbd..fe7272bf04 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -33,7 +33,7 @@ "@backstage/core": "^0.1.1-alpha.21", "@backstage/test-utils": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", diff --git a/packages/dev-utils/src/devApp/apiFactories.test.ts b/packages/dev-utils/src/devApp/apiFactories.test.ts deleted file mode 100644 index be3ae2cdbe..0000000000 --- a/packages/dev-utils/src/devApp/apiFactories.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import * as apiFactories from './apiFactories'; -import { ApiTestRegistry, ApiFactory } from '@backstage/core'; - -describe('apiFactories', () => { - it('should be possible to get an instance of each API', () => { - const registry = new ApiTestRegistry(); - const factories: ApiFactory[] = Object.values( - apiFactories, - ); - - for (const factory of factories) { - registry.register(factory); - } - - for (const factory of factories) { - const api = registry.get(factory.implements); - expect(api).toBeDefined(); - } - }); -}); diff --git a/packages/dev-utils/src/devApp/apiFactories.ts b/packages/dev-utils/src/devApp/apiFactories.ts deleted file mode 100644 index 4cf208f5d2..0000000000 --- a/packages/dev-utils/src/devApp/apiFactories.ts +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - alertApiRef, - errorApiRef, - ErrorApiForwarder, - AlertApi, - createApiFactory, - ErrorAlerter, - AlertApiForwarder, - oauthRequestApiRef, - OAuthRequestManager, - UrlPatternDiscovery, - discoveryApiRef, - GoogleAuth, - googleAuthApiRef, - GithubAuth, - githubAuthApiRef, - GitlabAuth, - gitlabAuthApiRef, - Auth0Auth, - auth0AuthApiRef, -} from '@backstage/core'; - -// TODO(rugvip): We should likely figure out how to reuse all of these between apps -// and plugin serve with minimal boilerplate. For example we might move everything -// to DI, and provide factories for the default implementations, so this just becomes -// a list of things like `[ErrorApiForwarder.factory, AlertApiDialog.factory]`. - -export const alertApiFactory = createApiFactory({ - implements: alertApiRef, - deps: {}, - factory: (): AlertApi => new AlertApiForwarder(), -}); - -export const errorApiFactory = createApiFactory({ - implements: errorApiRef, - deps: { alertApi: alertApiRef }, - factory: ({ alertApi }) => - new ErrorAlerter(alertApi, new ErrorApiForwarder()), -}); - -export const oauthRequestApiFactory = createApiFactory({ - implements: oauthRequestApiRef, - deps: {}, - factory: () => new OAuthRequestManager(), -}); - -export const discoveryApiFactory = createApiFactory({ - implements: discoveryApiRef, - deps: {}, - factory: () => - UrlPatternDiscovery.compile(`http://localhost:7000/{{ pluginId }}`), -}); - -export const googleAuthApiFactory = createApiFactory({ - implements: googleAuthApiRef, - deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef }, - factory: ({ discoveryApi, oauthRequestApi }) => - GoogleAuth.create({ - discoveryApi, - oauthRequestApi, - }), -}); - -export const githubAuthApiFactory = createApiFactory({ - implements: githubAuthApiRef, - deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef }, - factory: ({ discoveryApi, oauthRequestApi }) => - GithubAuth.create({ - discoveryApi, - oauthRequestApi, - }), -}); - -export const gitlabAuthApiFactory = createApiFactory({ - implements: gitlabAuthApiRef, - deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef }, - factory: ({ discoveryApi, oauthRequestApi }) => - GitlabAuth.create({ - discoveryApi, - oauthRequestApi, - }), -}); - -export const auth0AuthApiFactory = createApiFactory({ - implements: auth0AuthApiRef, - deps: { discoveryApi: discoveryApiRef, oauthRequestApi: oauthRequestApiRef }, - factory: ({ discoveryApi, oauthRequestApi }) => - Auth0Auth.create({ - discoveryApi, - oauthRequestApi, - }), -}); diff --git a/packages/dev-utils/src/devApp/render.test.tsx b/packages/dev-utils/src/devApp/render.test.tsx new file mode 100644 index 0000000000..fbebf2039b --- /dev/null +++ b/packages/dev-utils/src/devApp/render.test.tsx @@ -0,0 +1,43 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { useApi, configApiRef } from '@backstage/core'; +import { createDevApp } from './render'; + +const anyEnv = (process.env = { ...process.env }) as any; + +describe('DevAppBuilder', () => { + it('should be able to render a component in a dev app', async () => { + anyEnv.APP_CONFIG = [ + { context: 'test', data: { app: { title: 'Test App' } } }, + ]; + + const MyComponent = () => { + const configApi = useApi(configApiRef); + return
My App: {configApi.getString('app.title')}
; + }; + + const DevApp = createDevApp() + .addRootChild() + .build(); + + const rendered = render(); + + expect(await rendered.findByText('My App: Test App')).toBeInTheDocument(); + }); +}); diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index cde39fdd05..cca3470f3f 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -26,13 +26,12 @@ import { SidebarSpacer, ApiFactory, createPlugin, - ApiTestRegistry, - ApiHolder, AlertDisplay, OAuthRequestDialog, + AnyApiFactory, } from '@backstage/core'; -import * as defaultApiFactories from './apiFactories'; import SentimentDissatisfiedIcon from '@material-ui/icons/SentimentDissatisfied'; +import { Routes } from 'react-router'; // TODO(rugvip): export proper plugin type from core that isn't the plugin class type BackstagePlugin = ReturnType; @@ -43,7 +42,7 @@ type BackstagePlugin = ReturnType; */ class DevAppBuilder { private readonly plugins = new Array(); - private readonly factories = new Array>(); + private readonly apis = new Array(); private readonly rootChildren = new Array(); /** @@ -57,10 +56,10 @@ class DevAppBuilder { /** * Register an API factory to add to the app */ - registerApiFactory( - factory: ApiFactory, + registerApi( + factory: ApiFactory, ): DevAppBuilder { - this.factories.push(factory); + this.apis.push(factory); return this; } @@ -79,7 +78,7 @@ class DevAppBuilder { */ build(): ComponentType<{}> { const app = createApp({ - apis: this.setupApiRegistry(this.factories), + apis: this.apis, plugins: this.plugins, }); @@ -99,7 +98,7 @@ class DevAppBuilder { {sidebar} - {deprecatedAppRoutes} + {deprecatedAppRoutes}
@@ -170,30 +169,6 @@ class DevAppBuilder { ); } - // Set up an API registry that merges together default implementations with ones provided through config. - private setupApiRegistry( - providedFactories: ApiFactory[], - ): ApiHolder { - const providedApis = new Set( - providedFactories.map(factory => factory.implements), - ); - - // Exlude any default API factory that we receive a factory for in the config - const defaultFactories = Object.values(defaultApiFactories).filter( - factory => !providedApis.has(factory.implements), - ); - const allFactories = [...defaultFactories, ...providedFactories]; - - // Use a test registry with dependency injection so that the consumer - // can override APIs but still depend on the default implementations. - const registry = new ApiTestRegistry(); - for (const factory of allFactories) { - registry.register(factory); - } - - return registry; - } - private findPluginPaths(plugins: BackstagePlugin[]) { const paths = new Array(); diff --git a/packages/storybook/.storybook/config.js b/packages/storybook/.storybook/preview.js similarity index 68% rename from packages/storybook/.storybook/config.js rename to packages/storybook/.storybook/preview.js index 69145ea057..f92e07b045 100644 --- a/packages/storybook/.storybook/config.js +++ b/packages/storybook/.storybook/preview.js @@ -22,4 +22,24 @@ addParameters({ // Set the initial theme current: 'light', }, + layout: 'fullscreen', }); + +export const parameters = { + options: { + storySort: { + order: [ + 'Example Plugin', + 'Header', + 'Sidebar', + 'Tabs', + 'Information Card', + 'Tabbed Card', + 'Table', + 'Status', + 'Trendline', + 'Progress Card', + ], + }, + }, +}; diff --git a/packages/storybook/package.json b/packages/storybook/package.json index 35b609eebf..8f12a2891c 100644 --- a/packages/storybook/package.json +++ b/packages/storybook/package.json @@ -17,11 +17,11 @@ "@backstage/theme": "^0.1.1-alpha.21" }, "devDependencies": { - "@storybook/addon-actions": "^5.3.17", - "@storybook/addon-links": "^5.3.17", - "@storybook/addon-storysource": "^5.3.18", - "@storybook/addons": "^6.0.4", - "@storybook/react": "^5.3.17", - "storybook-dark-mode": "^0.6.1" + "@storybook/addon-actions": "^6.0.21", + "@storybook/addon-links": "^6.0.21", + "@storybook/addon-storysource": "^6.0.21", + "@storybook/addons": "^6.0.21", + "@storybook/react": "^6.0.21", + "storybook-dark-mode": "^1.0.2" } } diff --git a/packages/techdocs-container/Dockerfile b/packages/techdocs-container/Dockerfile index 2002d93d70..a5017cd2cd 100644 --- a/packages/techdocs-container/Dockerfile +++ b/packages/techdocs-container/Dockerfile @@ -18,7 +18,7 @@ FROM python:3.8-alpine RUN apk update && apk --no-cache add gcc musl-dev openjdk11-jdk curl graphviz ttf-dejavu fontconfig RUN curl -L http://sourceforge.net/projects/plantuml/files/plantuml.1.2020.16.jar/download > /opt/plantuml.jar -RUN pip install --upgrade pip && pip install mkdocs-techdocs-core==0.0.4 +RUN pip install --upgrade pip && pip install mkdocs-techdocs-core==0.0.6 # Create script to call plantuml.jar from a location in path diff --git a/packages/techdocs-container/mock-docs/mkdocs.yml b/packages/techdocs-container/mock-docs/mkdocs.yml index 8639c6abef..d769fddfcf 100644 --- a/packages/techdocs-container/mock-docs/mkdocs.yml +++ b/packages/techdocs-container/mock-docs/mkdocs.yml @@ -1,7 +1,7 @@ site_name: 'mock-docs' site_description: 'mock-docs site description' -nav: +nav: - Home: index.md - SubDocs: '!include ./sub-docs/mkdocs.yml' diff --git a/packages/techdocs-container/mock-docs/sub-docs/mkdocs.yml b/packages/techdocs-container/mock-docs/sub-docs/mkdocs.yml index 09504c1b31..4490ddbefa 100644 --- a/packages/techdocs-container/mock-docs/sub-docs/mkdocs.yml +++ b/packages/techdocs-container/mock-docs/sub-docs/mkdocs.yml @@ -1,4 +1,4 @@ site_name: subdocs nav: - - Home 2: "index.md" + - Home 2: 'index.md' diff --git a/packages/techdocs-container/techdocs-core/README.md b/packages/techdocs-container/techdocs-core/README.md index a4afed0158..94123f52ee 100644 --- a/packages/techdocs-container/techdocs-core/README.md +++ b/packages/techdocs-container/techdocs-core/README.md @@ -50,6 +50,10 @@ python -m black src/ ## Changelog +### 0.0.5 + +- Downgrade some versions of markdown extensions to versions that are more stable + ### 0.0.4 - Added support for more mkdocs extensions diff --git a/packages/techdocs-container/techdocs-core/requirements.txt b/packages/techdocs-container/techdocs-core/requirements.txt index 4037a174ea..36daaab4d7 100644 --- a/packages/techdocs-container/techdocs-core/requirements.txt +++ b/packages/techdocs-container/techdocs-core/requirements.txt @@ -4,10 +4,10 @@ mkdocs==1.1.2 mkdocs-material==5.3.2 mkdocs-monorepo-plugin==0.4.5 -plantuml-markdown==3.4.0 +plantuml-markdown==3.1.2 markdown_inline_graphviz_extension==1.1 pygments==2.6.1 -pymdown-extensions==7.1 +pymdown-extensions==8.0.0 # The linter using for Python # Note: This requires Python 3.6+ to run, but can format Python 2 code too. diff --git a/packages/techdocs-container/techdocs-core/setup.py b/packages/techdocs-container/techdocs-core/setup.py index 72593dc433..4b80fe2a6f 100644 --- a/packages/techdocs-container/techdocs-core/setup.py +++ b/packages/techdocs-container/techdocs-core/setup.py @@ -18,7 +18,7 @@ from setuptools import setup, find_packages setup( name='mkdocs-techdocs-core', - version='0.0.4', + version='0.0.6', description='A Mkdocs package that contains TechDocs defaults', long_description='', keywords='mkdocs', @@ -31,10 +31,10 @@ setup( 'mkdocs>=1.1.2', 'mkdocs-material==5.3.2', 'mkdocs-monorepo-plugin==0.4.5', - 'plantuml-markdown==3.4.0', + 'plantuml-markdown==3.1.2', 'markdown_inline_graphviz_extension==1.1', 'pygments==2.6.1', - 'pymdown-extensions==7.1' + 'pymdown-extensions==8.0.0' ], classifiers=[ 'Development Status :: 1 - Planning', diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index d28b66a9ed..8567af8c14 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -33,7 +33,7 @@ "@backstage/core-api": "^0.1.1-alpha.21", "@backstage/test-utils-core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^10.4.1", "@testing-library/user-event": "^12.0.7", diff --git a/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts b/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts index 9b22a352e8..7bf50314d0 100644 --- a/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts +++ b/packages/test-utils/src/testUtils/apis/ErrorApi/MockErrorApi.ts @@ -14,12 +14,7 @@ * limitations under the License. */ -import { - ErrorApi, - ErrorContext, - errorApiRef, - Observable, -} from '@backstage/core-api'; +import { ErrorApi, ErrorContext, Observable } from '@backstage/core-api'; type Options = { collect?: boolean; @@ -40,12 +35,6 @@ const nullObservable = { }; export class MockErrorApi implements ErrorApi { - static factory = { - implements: errorApiRef, - deps: {}, - factory: () => new MockErrorApi(), - }; - private readonly errors = new Array(); private readonly waiters = new Set(); diff --git a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts index a3a4ef16d6..006b44a49c 100644 --- a/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts +++ b/packages/test-utils/src/testUtils/apis/StorageApi/MockStorageApi.ts @@ -17,7 +17,6 @@ import { Observable, StorageApi, - storageApiRef, StorageValueChange, } from '@backstage/core-api'; import ObservableImpl from 'zen-observable'; @@ -25,12 +24,6 @@ import ObservableImpl from 'zen-observable'; export type MockStorageBucket = { [key: string]: any }; export class MockStorageApi implements StorageApi { - static factory = { - implements: storageApiRef, - deps: {}, - factory: () => MockStorageApi.create(), - }; - private readonly namespace: string; private readonly data: MockStorageBucket; diff --git a/packages/test-utils/src/testUtils/appWrappers.test.tsx b/packages/test-utils/src/testUtils/appWrappers.test.tsx index 19c02c2158..464c547ecc 100644 --- a/packages/test-utils/src/testUtils/appWrappers.test.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.test.tsx @@ -49,9 +49,6 @@ describe('wrapInTestApp', () => { expect.stringMatching( /^Warning: An update to %s inside a test was not wrapped in act\(...\)/, ), - expect.stringMatching( - /^Warning: An update to %s inside a test was not wrapped in act\(...\)/, - ), ]); }); diff --git a/packages/test-utils/src/testUtils/appWrappers.tsx b/packages/test-utils/src/testUtils/appWrappers.tsx index 2e3a73e346..182de1ef63 100644 --- a/packages/test-utils/src/testUtils/appWrappers.tsx +++ b/packages/test-utils/src/testUtils/appWrappers.tsx @@ -24,7 +24,7 @@ import privateExports, { } from '@backstage/core-api'; import { RenderResult } from '@testing-library/react'; import { renderWithEffects } from '@backstage/test-utils-core'; -import { createMockApiRegistry } from './mockApiRegistry'; +import { mockApis } from './mockApis'; const { PrivateAppImpl } = privateExports; @@ -58,10 +58,9 @@ export function wrapInTestApp( options: TestAppOptions = {}, ): ReactElement { const { routeEntries = ['/'] } = options; - const apis = createMockApiRegistry(); const app = new PrivateAppImpl({ - apis, + apis: [], components: { NotFoundErrorPage, BootErrorPage, @@ -80,6 +79,7 @@ export function wrapInTestApp( variant: 'light', }, ], + defaultApis: mockApis, }); let Wrapper: ComponentType; diff --git a/packages/test-utils/src/testUtils/mockApiRegistry.ts b/packages/test-utils/src/testUtils/mockApis.ts similarity index 70% rename from packages/test-utils/src/testUtils/mockApiRegistry.ts rename to packages/test-utils/src/testUtils/mockApis.ts index 15733ead88..e05a8e6cac 100644 --- a/packages/test-utils/src/testUtils/mockApiRegistry.ts +++ b/packages/test-utils/src/testUtils/mockApis.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import { ApiTestRegistry } from '@backstage/core-api'; +import { + storageApiRef, + errorApiRef, + createApiFactory, +} from '@backstage/core-api'; import { MockErrorApi, MockStorageApi } from './apis'; -export function createMockApiRegistry(): ApiTestRegistry { - const registry = new ApiTestRegistry(); - - registry.register(MockErrorApi.factory); - registry.register(MockStorageApi.factory); - - return registry; -} +export const mockApis = [ + createApiFactory(errorApiRef, new MockErrorApi()), + createApiFactory(storageApiRef, MockStorageApi.create()), +]; diff --git a/packages/theme/package.json b/packages/theme/package.json index e946482f32..436455633b 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -28,7 +28,7 @@ "clean": "backstage-cli clean" }, "dependencies": { - "@material-ui/core": "^4.9.1" + "@material-ui/core": "^4.11.0" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.21" diff --git a/packages/theme/src/baseTheme.ts b/packages/theme/src/baseTheme.ts index dc68db11d6..00a485bb41 100644 --- a/packages/theme/src/baseTheme.ts +++ b/packages/theme/src/baseTheme.ts @@ -192,10 +192,31 @@ export function createThemeOverrides(theme: BackstageTheme): Overrides { }, MuiChip: { root: { + backgroundColor: '#D9D9D9', // By default there's no margin, but it's usually wanted, so we add some trailing margin marginRight: theme.spacing(1), marginBottom: theme.spacing(1), }, + label: { + color: theme.palette.grey[900], + lineHeight: `${theme.spacing(2.5)}px`, + fontWeight: theme.typography.fontWeightMedium, + fontSize: `${theme.spacing(1.75)}px`, + }, + labelSmall: { + fontSize: `${theme.spacing(1.5)}px`, + }, + deleteIcon: { + color: theme.palette.grey[500], + width: `${theme.spacing(3)}px`, + height: `${theme.spacing(3)}px`, + margin: `0 ${theme.spacing(0.75)}px 0 -${theme.spacing(0.75)}px`, + }, + deleteIconSmall: { + width: `${theme.spacing(2)}px`, + height: `${theme.spacing(2)}px`, + margin: `0 ${theme.spacing(0.5)}px 0 -${theme.spacing(0.5)}px`, + }, }, MuiCardHeader: { root: { diff --git a/packages/theme/src/themes.ts b/packages/theme/src/themes.ts index eddd6a4ede..73d6c13859 100644 --- a/packages/theme/src/themes.ts +++ b/packages/theme/src/themes.ts @@ -15,7 +15,7 @@ */ import { createTheme } from './baseTheme'; -import { blue, yellow } from '@material-ui/core/colors'; +import { yellow } from '@material-ui/core/colors'; export const lightTheme = createTheme({ palette: { @@ -39,7 +39,7 @@ export const lightTheme = createTheme({ }, }, primary: { - main: blue[500], + main: '#2E77D0', }, banner: { info: '#2E77D0', @@ -95,7 +95,7 @@ export const darkTheme = createTheme({ }, }, primary: { - main: blue[500], + main: '#2E77D0', }, banner: { info: '#2E77D0', diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 644c6ed63a..a913316925 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -26,11 +26,12 @@ "@backstage/theme": "^0.1.1-alpha.21", "@kyma-project/asyncapi-react": "^0.11.0", "@material-icons/font": "^1.0.2", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^15.3.3", "swagger-ui-react": "^3.31.1" diff --git a/plugins/api-docs/src/catalog/EntityPageApi/EntityPageApi.tsx b/plugins/api-docs/src/catalog/EntityPageApi/EntityPageApi.tsx new file mode 100644 index 0000000000..f26691d58c --- /dev/null +++ b/plugins/api-docs/src/catalog/EntityPageApi/EntityPageApi.tsx @@ -0,0 +1,47 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentEntity, Entity } from '@backstage/catalog-model'; +import { Progress } from '@backstage/core'; +import React, { FC } from 'react'; +import { Grid } from '@material-ui/core'; +import { + ApiDefinitionCard, + useComponentApiEntities, + useComponentApiNames, +} from '../../components'; + +export const EntityPageApi: FC<{ entity: Entity }> = ({ entity }) => { + const apiNames = useComponentApiNames(entity as ComponentEntity); + + const { apiEntities, loading } = useComponentApiEntities({ + entity: entity as ComponentEntity, + }); + + if (loading) { + return ; + } + + return ( + + {apiNames.map(api => ( + + + + ))} + + ); +}; diff --git a/plugins/circleci/src/components/Settings/index.ts b/plugins/api-docs/src/catalog/EntityPageApi/index.ts similarity index 92% rename from plugins/circleci/src/components/Settings/index.ts rename to plugins/api-docs/src/catalog/EntityPageApi/index.ts index c04ded6dea..1d382e01de 100644 --- a/plugins/circleci/src/components/Settings/index.ts +++ b/plugins/api-docs/src/catalog/EntityPageApi/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default as Settings } from './Settings'; + +export { EntityPageApi } from './EntityPageApi'; diff --git a/plugins/api-docs/src/catalog/Router.tsx b/plugins/api-docs/src/catalog/Router.tsx new file mode 100644 index 0000000000..71640954b3 --- /dev/null +++ b/plugins/api-docs/src/catalog/Router.tsx @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { Route, Routes } from 'react-router'; +import { WarningPanel } from '@backstage/core'; +import { catalogRoute } from '../routes'; +import { EntityPageApi } from './EntityPageApi'; + +const isPluginApplicableToEntity = (entity: Entity) => { + return ((entity.spec?.implementsApis as string[]) || []).length > 0; +}; + +export const Router = ({ entity }: { entity: Entity }) => + // TODO(shmidt-i): move warning to a separate standardized component + !isPluginApplicableToEntity(entity) ? ( + + The entity doesn't implement any APIs. + + ) : ( + + } + /> + ) + + ); diff --git a/plugins/circleci/src/components/Layout/index.ts b/plugins/api-docs/src/catalog/index.ts similarity index 94% rename from plugins/circleci/src/components/Layout/index.ts rename to plugins/api-docs/src/catalog/index.ts index 236fc98851..4c177df914 100644 --- a/plugins/circleci/src/components/Layout/index.ts +++ b/plugins/api-docs/src/catalog/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './Layout'; + +export { Router } from './Router'; diff --git a/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx index 19cbaf6038..78afa51937 100644 --- a/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx +++ b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.test.tsx @@ -16,7 +16,6 @@ import { Entity } from '@backstage/catalog-model'; import { ApiProvider, ApiRegistry, storageApiRef } from '@backstage/core'; -// TODO: Circular ref! import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog'; import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils'; import { render } from '@testing-library/react'; diff --git a/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx index f624ec9f92..cfeb71f7b7 100644 --- a/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx +++ b/plugins/api-docs/src/components/ApiCatalogPage/ApiCatalogPage.tsx @@ -15,11 +15,10 @@ */ import { Content, useApi } from '@backstage/core'; -// TODO: Circular ref import { catalogApiRef } from '@backstage/plugin-catalog'; import React from 'react'; import { useAsync } from 'react-use'; -import { ApiCatalogTable } from '../ApiCatalogTable/ApiCatalogTable'; +import { ApiCatalogTable } from '../ApiCatalogTable'; import ApiCatalogLayout from './ApiCatalogLayout'; const CatalogPageContents = () => { diff --git a/plugins/circleci/src/pages/BuildsPage/index.ts b/plugins/api-docs/src/components/ApiCatalogPage/index.ts similarity index 90% rename from plugins/circleci/src/pages/BuildsPage/index.ts rename to plugins/api-docs/src/components/ApiCatalogPage/index.ts index 72b46d6bc9..bec9de705a 100644 --- a/plugins/circleci/src/pages/BuildsPage/index.ts +++ b/plugins/api-docs/src/components/ApiCatalogPage/index.ts @@ -13,4 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default as BuildsPage, Builds } from './BuildsPage'; + +export { ApiCatalogPage } from './ApiCatalogPage'; diff --git a/plugins/api-docs/src/components/ApiCatalogTable/index.ts b/plugins/api-docs/src/components/ApiCatalogTable/index.ts new file mode 100644 index 0000000000..14129b2258 --- /dev/null +++ b/plugins/api-docs/src/components/ApiCatalogTable/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ApiCatalogTable } from './ApiCatalogTable'; diff --git a/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.tsx b/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.tsx index d5bd9d1851..5650b0745f 100644 --- a/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.tsx +++ b/plugins/api-docs/src/components/ApiDefinitionCard/ApiDefinitionCard.tsx @@ -14,23 +14,93 @@ * limitations under the License. */ -import { ApiEntityV1alpha1 } from '@backstage/catalog-model'; -import { InfoCard } from '@backstage/core'; +import { ApiEntity } from '@backstage/catalog-model'; +import { TabbedCard, CardTab } from '@backstage/core'; import React from 'react'; -import { ApiDefinitionWidget } from '../ApiDefinitionWidget/ApiDefinitionWidget'; +import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget'; +import { Alert } from '@material-ui/lab'; +import { OpenApiDefinitionWidget } from '../OpenApiDefinitionWidget'; +import { AsyncApiDefinitionWidget } from '../AsyncApiDefinitionWidget'; + +type ApiDefinitionWidget = { + type: string; + title: string; + component: (definition: string) => React.ReactElement; + rawLanguage?: string; +}; + +export function defaultDefinitionWidgets(): ApiDefinitionWidget[] { + return [ + { + type: 'openapi', + title: 'OpenAPI', + rawLanguage: 'yaml', + component: definition => ( + + ), + }, + { + type: 'asyncapi', + title: 'AsyncAPI', + rawLanguage: 'yaml', + component: definition => ( + + ), + }, + ]; +} type Props = { - title?: string; - apiEntity: ApiEntityV1alpha1; + apiEntity?: ApiEntity; + definitionWidgets?: ApiDefinitionWidget[]; }; -export const ApiDefinitionCard = ({ title, apiEntity }: Props) => { - const type = apiEntity?.spec?.type || ''; - const definition = apiEntity?.spec?.definition || ''; +const defaultProps = { + definitionWidgets: defaultDefinitionWidgets(), +}; + +export const ApiDefinitionCard = (props: Props) => { + const { apiEntity, definitionWidgets } = { + ...defaultProps, + ...props, + }; + + if (!apiEntity) { + return Could not fetch the API; + } + + const definitionWidget = definitionWidgets.find( + d => d.type === apiEntity.spec.type, + ); + + if (definitionWidget) { + return ( + + + {definitionWidget.component(apiEntity.spec.definition)} + + + + + + ); + } return ( - - - + + + , + ]} + /> ); }; diff --git a/plugins/api-docs/src/components/ApiDefinitionCard/index.ts b/plugins/api-docs/src/components/ApiDefinitionCard/index.ts new file mode 100644 index 0000000000..b2a2f3af62 --- /dev/null +++ b/plugins/api-docs/src/components/ApiDefinitionCard/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ApiDefinitionCard } from './ApiDefinitionCard'; diff --git a/plugins/api-docs/src/components/ApiDefinitionWidget/ApiDefinitionWidget.tsx b/plugins/api-docs/src/components/ApiDefinitionWidget/ApiDefinitionWidget.tsx deleted file mode 100644 index 0ea894b5a2..0000000000 --- a/plugins/api-docs/src/components/ApiDefinitionWidget/ApiDefinitionWidget.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React from 'react'; -import { AsyncApiDefinitionWidget } from '../AsyncApiDefinitionWidget/AsyncApiDefinitionWidget'; -import { OpenApiDefinitionWidget } from '../OpenApiDefinitionWidget/OpenApiDefinitionWidget'; -import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget/PlainApiDefinitionWidget'; - -type Props = { - type: string; - definition: string; -}; - -export const ApiDefinitionWidget = ({ type, definition }: Props) => { - switch (type) { - case 'openapi': - return ; - - case 'asyncapi': - return ; - - default: - return ( - - ); - } -}; diff --git a/plugins/api-docs/src/components/ApiEntityPage/ApiEntityPage.tsx b/plugins/api-docs/src/components/ApiEntityPage/ApiEntityPage.tsx index 6717222a8e..aa0df3f20f 100644 --- a/plugins/api-docs/src/components/ApiEntityPage/ApiEntityPage.tsx +++ b/plugins/api-docs/src/components/ApiEntityPage/ApiEntityPage.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ApiEntityV1alpha1, Entity } from '@backstage/catalog-model'; +import { ApiEntity, Entity } from '@backstage/catalog-model'; import { Content, errorApiRef, @@ -25,14 +25,13 @@ import { Progress, useApi, } from '@backstage/core'; -// TODO: Circular ref import { catalogApiRef } from '@backstage/plugin-catalog'; import { Box } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; import React, { useEffect } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useAsync } from 'react-use'; -import { ApiDefinitionCard } from '../ApiDefinitionCard/ApiDefinitionCard'; +import { ApiDefinitionCard } from '../ApiDefinitionCard'; const REDIRECT_DELAY = 1000; function headerProps( @@ -125,7 +124,7 @@ export const ApiEntityPage = () => { {entity && ( <> - + )} diff --git a/plugins/api-docs/src/components/ApiEntityPage/index.ts b/plugins/api-docs/src/components/ApiEntityPage/index.ts new file mode 100644 index 0000000000..561350744b --- /dev/null +++ b/plugins/api-docs/src/components/ApiEntityPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ApiEntityPage } from './ApiEntityPage'; diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx index 01e2ac33a7..ac5dedfd9c 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx @@ -48,7 +48,7 @@ const useStyles = makeStyles(theme => ({ border: `1px solid ${fade(theme.palette.primary.main, 0.5)}`, '&:hover': { textDecoration: 'none', - '&$disabled': { + '&.Mui-disabled': { backgroundColor: 'transparent', }, border: `1px solid ${theme.palette.primary.main}`, @@ -61,7 +61,7 @@ const useStyles = makeStyles(theme => ({ backgroundColor: 'transparent', }, }, - '&$disabled': { + '&.Mui-disabled': { color: theme.palette.action.disabled, }, }, @@ -136,7 +136,7 @@ const useStyles = makeStyles(theme => ({ })); type Props = { - definition: any; + definition: string; }; export const AsyncApiDefinitionWidget = ({ definition }: Props) => { diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts new file mode 100644 index 0000000000..ecafd7d756 --- /dev/null +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { AsyncApiDefinitionWidget } from './AsyncApiDefinitionWidget'; diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx index 61f5cb2b75..b96f50166e 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx @@ -66,7 +66,7 @@ const useStyles = makeStyles(theme => ({ })); type Props = { - definition: any; + definition: string; }; export const OpenApiDefinitionWidget = ({ definition }: Props) => { diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts b/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts new file mode 100644 index 0000000000..b2a0f0b86d --- /dev/null +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { OpenApiDefinitionWidget } from './OpenApiDefinitionWidget'; diff --git a/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx b/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx index 46631c5a4b..0b2ebb4ca4 100644 --- a/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx @@ -23,5 +23,7 @@ type Props = { }; export const PlainApiDefinitionWidget = ({ definition, language }: Props) => { - return ; + return ( + + ); }; diff --git a/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts b/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts new file mode 100644 index 0000000000..c9d18d1ae8 --- /dev/null +++ b/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { PlainApiDefinitionWidget } from './PlainApiDefinitionWidget'; diff --git a/packages/core-api/src/apis/implementations/auth/gitlab/types.ts b/plugins/api-docs/src/components/index.ts similarity index 59% rename from packages/core-api/src/apis/implementations/auth/gitlab/types.ts rename to plugins/api-docs/src/components/index.ts index b03dfec084..55b9517f9c 100644 --- a/packages/core-api/src/apis/implementations/auth/gitlab/types.ts +++ b/plugins/api-docs/src/components/index.ts @@ -14,14 +14,9 @@ * limitations under the License. */ -import { ProfileInfo, BackstageIdentity } from '../../../definitions'; - -export type GitlabSession = { - providerInfo: { - accessToken: string; - scopes: Set; - expiresAt: Date; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; +export { ApiDefinitionCard } from './ApiDefinitionCard'; +export { AsyncApiDefinitionWidget } from './AsyncApiDefinitionWidget'; +export { OpenApiDefinitionWidget } from './OpenApiDefinitionWidget'; +export { PlainApiDefinitionWidget } from './PlainApiDefinitionWidget'; +export { useComponentApiNames } from './useComponentApiNames'; +export { useComponentApiEntities } from './useComponentApiEntities'; diff --git a/plugins/api-docs/src/components/useComponentApiEntities.ts b/plugins/api-docs/src/components/useComponentApiEntities.ts new file mode 100644 index 0000000000..11b5de988f --- /dev/null +++ b/plugins/api-docs/src/components/useComponentApiEntities.ts @@ -0,0 +1,69 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useAsyncRetry } from 'react-use'; +import { errorApiRef, useApi } from '@backstage/core'; +import { ApiEntity, ComponentEntity } from '@backstage/catalog-model'; +import { catalogApiRef } from '@backstage/plugin-catalog'; +import { useComponentApiNames } from './useComponentApiNames'; + +export function useComponentApiEntities({ + entity, +}: { + entity: ComponentEntity; +}): { + loading: boolean; + apiEntities?: Map; + error?: Error; + retry: () => void; +} { + const catalogApi = useApi(catalogApiRef); + const errorApi = useApi(errorApiRef); + + const apiNames = useComponentApiNames(entity); + + const { loading, value: apiEntities, retry, error } = useAsyncRetry< + Map + >(async () => { + const resultMap = new Map(); + + await Promise.all( + apiNames.map(async name => { + try { + const api = (await catalogApi.getEntityByName({ + kind: 'API', + name, + })) as ApiEntity | undefined; + + if (api) { + resultMap.set(api.metadata.name, api); + } + } catch (e) { + errorApi.post(e); + } + }), + ); + + return resultMap; + }, [catalogApi, entity]); + + return { + apiEntities, + loading, + error, + retry, + }; +} diff --git a/plugins/api-docs/src/components/useComponentApiNames.ts b/plugins/api-docs/src/components/useComponentApiNames.ts new file mode 100644 index 0000000000..0eabe2b6c7 --- /dev/null +++ b/plugins/api-docs/src/components/useComponentApiNames.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ComponentEntity } from '@backstage/catalog-model'; + +export const useComponentApiNames = (entity: ComponentEntity) => { + return (entity.spec?.implementsApis as string[]) || []; +}; diff --git a/plugins/api-docs/src/index.ts b/plugins/api-docs/src/index.ts index c82a2c263b..958355f063 100644 --- a/plugins/api-docs/src/index.ts +++ b/plugins/api-docs/src/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { ApiDefinitionCard } from './components/ApiDefinitionCard/ApiDefinitionCard'; +export { Router } from './catalog'; export { plugin } from './plugin'; diff --git a/plugins/api-docs/src/routes.ts b/plugins/api-docs/src/routes.ts index 48c530d4b5..eea911dd62 100644 --- a/plugins/api-docs/src/routes.ts +++ b/plugins/api-docs/src/routes.ts @@ -28,3 +28,8 @@ export const entityRoute = createRouteRef({ path: '/api-docs/:optionalNamespaceAndName/', title: 'API', }); +export const catalogRoute = createRouteRef({ + icon: NoIcon, + path: '', + title: 'API', +}); diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index e6c3dde7b6..f4080abc42 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -4,7 +4,7 @@ "main": "src/index.ts", "types": "src/index.ts", "license": "Apache-2.0", - "private": true, + "private": false, "publishConfig": { "access": "public", "main": "dist/index.cjs.js", diff --git a/plugins/app-backend/src/service/router.test.ts b/plugins/app-backend/src/service/router.test.ts index 4e0c27c47a..417fdc43b6 100644 --- a/plugins/app-backend/src/service/router.test.ts +++ b/plugins/app-backend/src/service/router.test.ts @@ -47,21 +47,21 @@ describe('createRouter', () => { const response = await request(app).get('/index.html'); expect(response.status).toBe(200); - expect(response.text).toBe('this is index.html\n'); + expect(response.text.trim()).toBe('this is index.html'); }); it('returns other.html', async () => { const response = await request(app).get('/other.html'); expect(response.status).toBe(200); - expect(response.text).toBe('this is other.html\n'); + expect(response.text.trim()).toBe('this is other.html'); }); it('returns index.html if missing', async () => { const response = await request(app).get('/missing.html'); expect(response.status).toBe(200); - expect(response.text).toBe('this is index.html\n'); + expect(response.text.trim()).toBe('this is index.html'); }); }); @@ -83,11 +83,11 @@ describe('createRouter with static fallback handler', () => { const response1 = await request(app).get('/static/main.txt'); expect(response1.status).toBe(200); - expect(response1.text).toBe('this is main.txt\n'); + expect(response1.text.trim()).toBe('this is main.txt'); const response2 = await request(app).get('/static/test.txt'); expect(response2.status).toBe(200); - expect(response2.text).toBe('this is test.txt'); + expect(response2.text.trim()).toBe('this is test.txt'); const response3 = await request(app).get('/static/missing.txt'); expect(response3.status).toBe(404); diff --git a/plugins/auth-backend/README.md b/plugins/auth-backend/README.md index e1d144c1e0..9af90df3f2 100644 --- a/plugins/auth-backend/README.md +++ b/plugins/auth-backend/README.md @@ -85,8 +85,8 @@ Click [here](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMe - Give the app a name. e.g. `backstage-dev` - Select `Accounts in this organizational directory only` under supported account types. - Enter the callback URL for your backstage backend instance: - - For local development, this is likely `http://localhost:7000/auth/microsoft/handler/frame` - - For non-local deployments, this will be `https://{APP_FQDN}:{APP_BACKEND_PORT}/auth/microsoft/handler/frame` + - For local development, this is likely `http://localhost:7000/auth/microsoft/handler/frame` + - For non-local deployments, this will be `https://{APP_FQDN}:{APP_BACKEND_PORT}/auth/microsoft/handler/frame` - Click `Register`. We also need to generate a client secret so Backstage can authenticate as this app. diff --git a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts index 0f092ae780..62cb8e444d 100644 --- a/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts +++ b/plugins/auth-backend/src/lib/oauth/OAuthAdapter.ts @@ -24,9 +24,9 @@ import { } from '../../providers/types'; import { InputError } from '@backstage/backend-common'; import { TokenIssuer } from '../../identity'; -import { verifyNonce, encodeState } from './helpers'; +import { verifyNonce } from './helpers'; import { postMessageResponse, ensuresXRequestedWith } from '../flow'; -import { OAuthHandlers } from './types'; +import { OAuthHandlers, OAuthStartRequest, OAuthRefreshRequest } from './types'; export const THOUSAND_DAYS_MS = 1000 * 24 * 60 * 60 * 1000; export const TEN_MINUTES_MS = 600 * 1000; @@ -86,15 +86,12 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { // set a nonce cookie before redirecting to oauth provider this.setNonceCookie(res, nonce); - const stateObject = { nonce: nonce, env: env }; - const stateParameter = encodeState(stateObject); + const state = { nonce: nonce, env: env }; + const forwardReq = Object.assign(req, { scope, state }); - const queryParameters = { - scope, - state: stateParameter, - }; - - const { url, status } = await this.handlers.start(req, queryParameters); + const { url, status } = await this.handlers.start( + forwardReq as OAuthStartRequest, + ); res.statusCode = status || 302; res.setHeader('Location', url); @@ -185,8 +182,12 @@ export class OAuthAdapter implements AuthProviderRouteHandlers { const scope = req.query.scope?.toString() ?? ''; + const forwardReq = Object.assign(req, { scope, refreshToken }); + // get new access_token - const response = await this.handlers.refresh(refreshToken, scope); + const response = await this.handlers.refresh( + forwardReq as OAuthRefreshRequest, + ); await this.populateIdentity(response.backstageIdentity); diff --git a/plugins/auth-backend/src/lib/oauth/index.ts b/plugins/auth-backend/src/lib/oauth/index.ts index 05c8bd9d3d..564a0e1e7c 100644 --- a/plugins/auth-backend/src/lib/oauth/index.ts +++ b/plugins/auth-backend/src/lib/oauth/index.ts @@ -16,10 +16,13 @@ export { OAuthEnvironmentHandler } from './OAuthEnvironmentHandler'; export { OAuthAdapter } from './OAuthAdapter'; +export { encodeState } from './helpers'; export type { OAuthHandlers, OAuthProviderInfo, OAuthProviderOptions, OAuthResponse, OAuthState, + OAuthStartRequest, + OAuthRefreshRequest, } from './types'; diff --git a/plugins/auth-backend/src/lib/oauth/types.ts b/plugins/auth-backend/src/lib/oauth/types.ts index a854326bed..b2b7915a4e 100644 --- a/plugins/auth-backend/src/lib/oauth/types.ts +++ b/plugins/auth-backend/src/lib/oauth/types.ts @@ -67,6 +67,16 @@ export type OAuthState = { env: string; }; +export type OAuthStartRequest = express.Request<{}> & { + scope: string; + state: OAuthState; +}; + +export type OAuthRefreshRequest = express.Request<{}> & { + scope: string; + refreshToken: string; +}; + /** * Any OAuth provider needs to implement this interface which has provider specific * handlers for different methods to perform authentication, get access tokens, @@ -78,10 +88,7 @@ export interface OAuthHandlers { * @param {express.Request} req * @param options */ - start( - req: express.Request, - options: Record, - ): Promise; + start(req: OAuthStartRequest): Promise; /** * Handles the redirect from the auth provider when the user has signed in. @@ -99,10 +106,7 @@ export interface OAuthHandlers { * @param {string} refreshToken * @param {string} scope */ - refresh?( - refreshToken: string, - scope: string, - ): Promise>; + refresh?(req: OAuthRefreshRequest): Promise>; /** * (Optional) Sign out of the auth provider. diff --git a/plugins/auth-backend/src/providers/auth0/provider.ts b/plugins/auth-backend/src/providers/auth0/provider.ts index 3b7817ffe9..668ab17ee1 100644 --- a/plugins/auth-backend/src/providers/auth0/provider.ts +++ b/plugins/auth-backend/src/providers/auth0/provider.ts @@ -23,6 +23,9 @@ import { OAuthHandlers, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, + OAuthRefreshRequest, } from '../../lib/oauth'; import { executeFetchUserProfileStrategy, @@ -81,16 +84,13 @@ export class Auth0AuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - const providerOptions = { - ...options, + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { accessType: 'offline', prompt: 'consent', - }; - return await executeRedirectStrategy(req, this._strategy, providerOptions); + scope: req.scope, + state: encodeState(req.state), + }); } async handler( @@ -107,11 +107,11 @@ export class Auth0AuthProvider implements OAuthHandlers { }; } - async refresh(refreshToken: string, scope: string): Promise { + async refresh(req: OAuthRefreshRequest): Promise { const { accessToken, params } = await executeRefreshTokenStrategy( this._strategy, - refreshToken, - scope, + req.refreshToken, + req.scope, ); const profile = await executeFetchUserProfileStrategy( diff --git a/plugins/auth-backend/src/providers/github/provider.ts b/plugins/auth-backend/src/providers/github/provider.ts index 2205fb6794..bab7b3fc28 100644 --- a/plugins/auth-backend/src/providers/github/provider.ts +++ b/plugins/auth-backend/src/providers/github/provider.ts @@ -29,6 +29,8 @@ import { OAuthHandlers, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, } from '../../lib/oauth'; import passport from 'passport'; @@ -117,11 +119,11 @@ export class GithubAuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - return await executeRedirectStrategy(req, this._strategy, options); + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { + scope: req.scope, + state: encodeState(req.state), + }); } async handler(req: express.Request) { diff --git a/plugins/auth-backend/src/providers/gitlab/provider.ts b/plugins/auth-backend/src/providers/gitlab/provider.ts index 97f0b2bd22..4d4ecc3b56 100644 --- a/plugins/auth-backend/src/providers/gitlab/provider.ts +++ b/plugins/auth-backend/src/providers/gitlab/provider.ts @@ -29,6 +29,8 @@ import { OAuthHandlers, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, } from '../../lib/oauth'; import passport from 'passport'; @@ -122,11 +124,11 @@ export class GitlabAuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - return await executeRedirectStrategy(req, this._strategy, options); + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { + scope: req.scope, + state: encodeState(req.state), + }); } async handler(req: express.Request): Promise<{ response: OAuthResponse }> { diff --git a/plugins/auth-backend/src/providers/google/provider.ts b/plugins/auth-backend/src/providers/google/provider.ts index 9ee2e1d680..3cc585605c 100644 --- a/plugins/auth-backend/src/providers/google/provider.ts +++ b/plugins/auth-backend/src/providers/google/provider.ts @@ -31,6 +31,9 @@ import { OAuthProviderOptions, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, + OAuthRefreshRequest, } from '../../lib/oauth'; import passport from 'passport'; @@ -79,16 +82,13 @@ export class GoogleAuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - const providerOptions = { - ...options, + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { accessType: 'offline', prompt: 'consent', - }; - return await executeRedirectStrategy(req, this._strategy, providerOptions); + scope: req.scope, + state: encodeState(req.state), + }); } async handler( @@ -105,11 +105,11 @@ export class GoogleAuthProvider implements OAuthHandlers { }; } - async refresh(refreshToken: string, scope: string): Promise { + async refresh(req: OAuthRefreshRequest): Promise { const { accessToken, params } = await executeRefreshTokenStrategy( this._strategy, - refreshToken, - scope, + req.refreshToken, + req.scope, ); const profile = await executeFetchUserProfileStrategy( diff --git a/plugins/auth-backend/src/providers/microsoft/provider.ts b/plugins/auth-backend/src/providers/microsoft/provider.ts index edc5509d84..baa66f0662 100644 --- a/plugins/auth-backend/src/providers/microsoft/provider.ts +++ b/plugins/auth-backend/src/providers/microsoft/provider.ts @@ -35,6 +35,9 @@ import { OAuthHandlers, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, + OAuthRefreshRequest, } from '../../lib/oauth'; import got from 'got'; @@ -111,11 +114,11 @@ export class MicrosoftAuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - return await executeRedirectStrategy(req, this._strategy, options); + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { + scope: req.scope, + state: encodeState(req.state), + }); } async handler( @@ -132,11 +135,11 @@ export class MicrosoftAuthProvider implements OAuthHandlers { }; } - async refresh(refreshToken: string, scope: string): Promise { + async refresh(req: OAuthRefreshRequest): Promise { const { accessToken, params } = await executeRefreshTokenStrategy( this._strategy, - refreshToken, - scope, + req.refreshToken, + req.scope, ); const profile = await executeFetchUserProfileStrategy( diff --git a/plugins/auth-backend/src/providers/oauth2/provider.ts b/plugins/auth-backend/src/providers/oauth2/provider.ts index 5a4882fa6f..a657ea2195 100644 --- a/plugins/auth-backend/src/providers/oauth2/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2/provider.ts @@ -23,6 +23,9 @@ import { OAuthHandlers, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, + OAuthRefreshRequest, } from '../../lib/oauth'; import { executeFetchUserProfileStrategy, @@ -84,16 +87,13 @@ export class OAuth2AuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - const providerOptions = { - ...options, + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { accessType: 'offline', prompt: 'consent', - }; - return await executeRedirectStrategy(req, this._strategy, providerOptions); + scope: req.scope, + state: encodeState(req.state), + }); } async handler( @@ -110,11 +110,11 @@ export class OAuth2AuthProvider implements OAuthHandlers { }; } - async refresh(refreshToken: string, scope: string): Promise { + async refresh(req: OAuthRefreshRequest): Promise { const refreshTokenResponse = await executeRefreshTokenStrategy( this._strategy, - refreshToken, - scope, + req.refreshToken, + req.scope, ); const { accessToken, diff --git a/plugins/auth-backend/src/providers/okta/index.ts b/plugins/auth-backend/src/providers/okta/index.ts index bc32601ac2..05cc398f43 100644 --- a/plugins/auth-backend/src/providers/okta/index.ts +++ b/plugins/auth-backend/src/providers/okta/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { createOktaProvider } from './provider'; +export { createOktaProvider } from './provider'; diff --git a/plugins/auth-backend/src/providers/okta/provider.ts b/plugins/auth-backend/src/providers/okta/provider.ts index 0368bd8415..09597696ba 100644 --- a/plugins/auth-backend/src/providers/okta/provider.ts +++ b/plugins/auth-backend/src/providers/okta/provider.ts @@ -20,6 +20,9 @@ import { OAuthHandlers, OAuthResponse, OAuthEnvironmentHandler, + OAuthStartRequest, + encodeState, + OAuthRefreshRequest, } from '../../lib/oauth'; import { Strategy as OktaStrategy } from 'passport-okta-oauth'; import passport from 'passport'; @@ -101,16 +104,13 @@ export class OktaAuthProvider implements OAuthHandlers { ); } - async start( - req: express.Request, - options: Record, - ): Promise { - const providerOptions = { - ...options, + async start(req: OAuthStartRequest): Promise { + return await executeRedirectStrategy(req, this._strategy, { accessType: 'offline', prompt: 'consent', - }; - return await executeRedirectStrategy(req, this._strategy, providerOptions); + scope: req.scope, + state: encodeState(req.state), + }); } async handler( @@ -127,11 +127,11 @@ export class OktaAuthProvider implements OAuthHandlers { }; } - async refresh(refreshToken: string, scope: string): Promise { + async refresh(req: OAuthRefreshRequest): Promise { const { accessToken, params } = await executeRefreshTokenStrategy( this._strategy, - refreshToken, - scope, + req.refreshToken, + req.scope, ); const profile = await executeFetchUserProfileStrategy( diff --git a/plugins/auth-backend/src/providers/okta/types.d.ts b/plugins/auth-backend/src/providers/okta/types.d.ts index bed6d24043..6b49d99817 100644 --- a/plugins/auth-backend/src/providers/okta/types.d.ts +++ b/plugins/auth-backend/src/providers/okta/types.d.ts @@ -14,9 +14,7 @@ * limitations under the License. */ declare module 'passport-okta-oauth' { - export class Strategy { - constructor(options: any, verify: any) + constructor(options: any, verify: any); } } - \ No newline at end of file diff --git a/plugins/catalog-backend/README.md b/plugins/catalog-backend/README.md index 7c52dfad72..1b4a653f4a 100644 --- a/plugins/catalog-backend/README.md +++ b/plugins/catalog-backend/README.md @@ -21,12 +21,9 @@ To evaluate the catalog and have a greater amount of functionality available, in # in one terminal window, run this from from the very root of the Backstage project cd packages/backend yarn start - -# open another terminal window, and run the following from the very root of the Backstage project -yarn lerna run mock-data ``` -This will launch the full example backend and populate its catalog with some mock entities. +This will launch the full example backend, populated some example entities. ## Links diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index c1b20ed7bb..d1711cf3d5 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -17,9 +17,7 @@ "test": "backstage-cli test", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", - "mock-data": "./scripts/mock-data.sh", - "mock-data:local": "./scripts/mock-data-local.sh" + "clean": "backstage-cli clean" }, "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.21", diff --git a/plugins/catalog-backend/scripts/mock-data-local.sh b/plugins/catalog-backend/scripts/mock-data-local.sh deleted file mode 100755 index 3bea819319..0000000000 --- a/plugins/catalog-backend/scripts/mock-data-local.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -for FILE in \ - ../../packages/catalog-model/examples/*.yaml \ -; do \ - curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"file\", \"target\": \"../catalog-model/${FILE}\"}" - echo -done diff --git a/plugins/catalog-backend/scripts/mock-data.sh b/plugins/catalog-backend/scripts/mock-data.sh deleted file mode 100755 index 92ec647281..0000000000 --- a/plugins/catalog-backend/scripts/mock-data.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -for URL in \ - 'artist-lookup-component.yaml' \ - 'playback-order-component.yaml' \ - 'podcast-api-component.yaml' \ - 'queue-proxy-component.yaml' \ - 'searcher-component.yaml' \ - 'playback-lib-component.yaml' \ - 'www-artist-component.yaml' \ - 'shuffle-api-component.yaml' \ - 'petstore-api.yaml' \ - 'streetlights-api.yaml' \ -; do \ - curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"github\", \"target\": \"https://github.com/spotify/backstage/blob/master/packages/catalog-model/examples/${URL}\"}" - echo -done diff --git a/plugins/catalog-backend/src/ingestion/LocationReaders.ts b/plugins/catalog-backend/src/ingestion/LocationReaders.ts index bddef6b4de..a86e073af9 100644 --- a/plugins/catalog-backend/src/ingestion/LocationReaders.ts +++ b/plugins/catalog-backend/src/ingestion/LocationReaders.ts @@ -77,7 +77,7 @@ export class LocationReaders implements LocationReader { return [ StaticLocationProcessor.fromConfig(config), new FileReaderProcessor(), - new GithubReaderProcessor(), + new GithubReaderProcessor(config), new GithubApiReaderProcessor(config), new GitlabApiReaderProcessor(config), new GitlabReaderProcessor(), diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index b088e1699b..e1b52795d3 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -23,15 +23,13 @@ "dependencies": { "@backstage/catalog-model": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", - "@backstage/plugin-api-docs": "^0.1.1-alpha.21", - "@backstage/plugin-github-actions": "^0.1.1-alpha.21", - "@backstage/plugin-jenkins": "^0.1.1-alpha.21", "@backstage/plugin-scaffolder": "^0.1.1-alpha.21", "@backstage/plugin-techdocs": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", + "classnames": "^2.2.6", "moment": "^2.26.0", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/plugins/catalog/src/components/AboutCard/AboutCard.tsx b/plugins/catalog/src/components/AboutCard/AboutCard.tsx index d83beaedb5..939449f719 100644 --- a/plugins/catalog/src/components/AboutCard/AboutCard.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutCard.tsx @@ -102,9 +102,14 @@ export function AboutCard({ entity }: AboutCardProps) { } diff --git a/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx b/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx index 91a5211925..580dcff0f5 100644 --- a/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx +++ b/plugins/catalog/src/components/AboutCard/IconLinkVertical/IconLinkVertical.tsx @@ -14,12 +14,14 @@ * limitations under the License. */ import * as React from 'react'; +import classnames from 'classnames'; import { makeStyles, Link } from '@material-ui/core'; import LinkIcon from '@material-ui/icons/Link'; export type IconLinkVerticalProps = { icon?: React.ReactNode; href?: string; + disabled?: boolean; label: string; }; @@ -30,6 +32,9 @@ const useIconStyles = makeStyles({ gridGap: 4, textAlign: 'center', }, + disabled: { + color: 'gray', + }, label: { fontSize: '0.7rem', textTransform: 'uppercase', @@ -41,9 +46,24 @@ const useIconStyles = makeStyles({ export function IconLinkVertical({ icon = , href = '#', + disabled = false, ...props }: IconLinkVerticalProps) { const classes = useIconStyles(); + + if (disabled) { + return ( + + {icon} + {props.label} + + ); + } + return ( {icon} diff --git a/plugins/catalog/src/components/CatalogPage/CatalogLayout.tsx b/plugins/catalog/src/components/CatalogPage/CatalogLayout.tsx index 39b3c66013..92f51ace06 100644 --- a/plugins/catalog/src/components/CatalogPage/CatalogLayout.tsx +++ b/plugins/catalog/src/components/CatalogPage/CatalogLayout.tsx @@ -31,12 +31,13 @@ type Props = { const CatalogLayout = ({ children }: Props) => { const greeting = getTimeBasedGreeting(); + const profile = useApi(identityApiRef).getProfile(); const userId = useApi(identityApiRef).getUserId(); return (
{ getLocationByEntity: () => Promise.resolve({ id: 'id', type: 'github', target: 'url' }), }; + const testProfile: Partial = { + displayName: 'Display Name', + }; const indentityApi: Partial = { getUserId: () => 'tools@example.com', + getProfile: () => testProfile, }; const renderWrapped = (children: React.ReactNode) => diff --git a/plugins/catalog/src/components/EntityPageApi/EntityPageApi.tsx b/plugins/catalog/src/components/EntityPageApi/EntityPageApi.tsx deleted file mode 100644 index 5c0ff5485b..0000000000 --- a/plugins/catalog/src/components/EntityPageApi/EntityPageApi.tsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ApiEntityV1alpha1, Entity } from '@backstage/catalog-model'; -import { Content, Progress, useApi } from '@backstage/core'; -import { ApiDefinitionCard } from '@backstage/plugin-api-docs'; -import { Grid } from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; -import React, { FC } from 'react'; -import { useAsync } from 'react-use'; -import { catalogApiRef } from '../..'; - -export const EntityPageApi: FC<{ entity: Entity }> = ({ entity }) => { - const catalogApi = useApi(catalogApiRef); - - const { value: apiEntities, loading } = useAsync(async () => { - const a = await Promise.all( - ((entity?.spec?.implementsApis as string[]) || []).map(api => - catalogApi.getEntityByName({ - kind: 'API', - name: api, - }), - ), - ); - const b = new Map(); - - a.filter(api => !!api).forEach(api => { - b.set(api?.metadata?.name!, api as ApiEntityV1alpha1); - }); - return b; - }, [catalogApi, entity]); - - return ( - - {loading && } - {!loading && ( - - {((entity?.spec?.implementsApis as string[]) || []).map(api => { - const apiEntity = apiEntities && apiEntities.get(api); - - return ( - - {!apiEntity && ( - - Error on fetching the API: {api} - - )} - - {apiEntity && ( - - )} - - ); - })} - - )} - - ); -}; diff --git a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx b/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx deleted file mode 100644 index 9b29b205cf..0000000000 --- a/plugins/catalog/src/components/EntityPageOverview/EntityPageOverview.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// TODO(shmidt-i): move to the app -import { Entity } from '@backstage/catalog-model'; -import { Content } from '@backstage/core'; -import { LatestWorkflowRunCard } from '@backstage/plugin-github-actions'; -import { - JenkinsBuildsWidget, - JenkinsLastBuildWidget, -} from '@backstage/plugin-jenkins'; -import { Grid } from '@material-ui/core'; -import React, { FC } from 'react'; -import { AboutCard } from '../AboutCard'; - -export const EntityPageOverview: FC<{ entity: Entity }> = ({ entity }) => { - return ( - - - - - - {entity.metadata?.annotations?.[ - 'backstage.io/jenkins-github-folder' - ] && ( - - - - )} - {entity.metadata?.annotations?.[ - 'backstage.io/jenkins-github-folder' - ] && ( - - - - )} - {entity.metadata?.annotations?.['backstage.io/github-actions-id'] && ( - - - - )} - - - ); -}; diff --git a/plugins/catalog/src/plugin.ts b/plugins/catalog/src/plugin.ts index 4bfbf2453b..dfe12fd500 100644 --- a/plugins/catalog/src/plugin.ts +++ b/plugins/catalog/src/plugin.ts @@ -14,8 +14,21 @@ * limitations under the License. */ -import { createPlugin } from '@backstage/core'; +import { + createPlugin, + createApiFactory, + discoveryApiRef, +} from '@backstage/core'; +import { catalogApiRef } from './api/types'; +import { CatalogClient } from './api/CatalogClient'; export const plugin = createPlugin({ id: 'catalog', + apis: [ + createApiFactory({ + api: catalogApiRef, + deps: { discoveryApi: discoveryApiRef }, + factory: ({ discoveryApi }) => new CatalogClient({ discoveryApi }), + }), + ], }); diff --git a/plugins/circleci/README.md b/plugins/circleci/README.md index 2dcc137a47..48e1bee6cc 100644 --- a/plugins/circleci/README.md +++ b/plugins/circleci/README.md @@ -4,8 +4,6 @@ Website: [https://circleci.com/](https://circleci.com/) - - ## Setup @@ -35,8 +33,39 @@ export default builder.build() as ApiHolder; export { plugin as Circleci } from '@backstage/plugin-circleci'; ``` -3. Run app with `yarn start` and navigate to `/circleci/settings` -4. Enter project settings and **project** token, acquired according to [https://circleci.com/docs/2.0/managing-api-tokens/](https://circleci.com/docs/2.0/managing-api-tokens/) +3. Register the plugin router: + +```jsx +// packages/app/src/components/catalog/EntityPage.tsx + +import { Router as CircleCIRouter } from '@backstage/plugin-circleci'; + +// Then somewhere inside +} +/>; +``` + +4. Add proxy config: + +``` +// app-config.yaml +proxy: + '/circleci/api': + target: https://circleci.com/api/v1.1 + changeOrigin: true + pathRewrite: + '^/proxy/circleci/api/': '/' + headers: + Circle-Token: + $secret: + env: CIRCLECI_AUTH_TOKEN +``` + +5. Get and provide `CIRCLECI_AUTH_TOKEN` as env variable (https://circleci.com/docs/api/#add-an-api-token) +6. Add `circleci.com/project-slug` annotation to your component-info.yaml file in format // (https://backstage.io/docs/architecture-decisions/adrs-adr002#format) ## Features @@ -50,3 +79,4 @@ export { plugin as Circleci } from '@backstage/plugin-circleci'; ## Limitations - CircleCI has pretty strict rate limits per token, be careful with opened tabs +- CircelCI doesn't provide a way to auth by 3rd party (e.g. GitHub) token, nor by calling their OAuth endpoints, which currently stands in the way of better auth integration with Backstage (https://discuss.circleci.com/t/circleci-api-authorization-with-github-token/5356) diff --git a/plugins/circleci/dev/index.tsx b/plugins/circleci/dev/index.tsx index ed7dd5de9c..4bf67d5cb2 100644 --- a/plugins/circleci/dev/index.tsx +++ b/plugins/circleci/dev/index.tsx @@ -20,9 +20,9 @@ import { circleCIApiRef, CircleCIApi } from '../src/api'; createDevApp() .registerPlugin(plugin) - .registerApiFactory({ + .registerApi({ + api: circleCIApiRef, deps: {}, factory: () => new CircleCIApi(), - implements: circleCIApiRef, }) .render(); diff --git a/plugins/circleci/package.json b/plugins/circleci/package.json index b5824d3869..7c8f36d370 100644 --- a/plugins/circleci/package.json +++ b/plugins/circleci/package.json @@ -22,8 +22,10 @@ }, "dependencies": { "@backstage/core": "^0.1.1-alpha.21", + "@backstage/catalog-model": "^0.1.1-alpha.21", + "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "circleci-api": "^4.0.0", diff --git a/plugins/circleci/src/api/index.ts b/plugins/circleci/src/api/index.ts index 64a33e4c13..da4c811812 100644 --- a/plugins/circleci/src/api/index.ts +++ b/plugins/circleci/src/api/index.ts @@ -42,8 +42,8 @@ export class CircleCIApi { this.apiUrl = apiUrl; } - async retry(buildNumber: number, options: CircleCIOptions) { - return postBuildActions(options.token, buildNumber, BuildAction.RETRY, { + async retry(buildNumber: number, options: Partial) { + return postBuildActions('', buildNumber, BuildAction.RETRY, { circleHost: this.apiUrl, ...options.vcs, }); @@ -51,9 +51,9 @@ export class CircleCIApi { async getBuilds( { limit = 10, offset = 0 }: { limit: number; offset: number }, - options: CircleCIOptions, + options: Partial, ) { - return getBuildSummaries(options.token, { + return getBuildSummaries('', { options: { limit, offset, @@ -64,12 +64,12 @@ export class CircleCIApi { }); } - async getUser(options: CircleCIOptions) { - return getMe(options.token, { circleHost: this.apiUrl, ...options }); + async getUser(options: Partial) { + return getMe('', { circleHost: this.apiUrl, ...options }); } - async getBuild(buildNumber: number, options: CircleCIOptions) { - return getFullBuild(options.token, buildNumber, { + async getBuild(buildNumber: number, options: Partial) { + return getFullBuild('', buildNumber, { circleHost: this.apiUrl, ...options.vcs, }); diff --git a/plugins/circleci/src/assets/screenshot-1.png b/plugins/circleci/src/assets/screenshot-1.png index 2e3f1f420b..db99230a65 100644 Binary files a/plugins/circleci/src/assets/screenshot-1.png and b/plugins/circleci/src/assets/screenshot-1.png differ diff --git a/plugins/circleci/src/assets/screenshot-2.png b/plugins/circleci/src/assets/screenshot-2.png index 4e97cbcf8e..4f9ddcaec6 100644 Binary files a/plugins/circleci/src/assets/screenshot-2.png and b/plugins/circleci/src/assets/screenshot-2.png differ diff --git a/plugins/circleci/src/assets/screenshot-3.png b/plugins/circleci/src/assets/screenshot-3.png deleted file mode 100644 index ac20d58246..0000000000 Binary files a/plugins/circleci/src/assets/screenshot-3.png and /dev/null differ diff --git a/plugins/circleci/src/assets/screenshot-4.png b/plugins/circleci/src/assets/screenshot-4.png deleted file mode 100644 index 2d4ab5fe77..0000000000 Binary files a/plugins/circleci/src/assets/screenshot-4.png and /dev/null differ diff --git a/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx b/plugins/circleci/src/components/BuildWithStepsPage/BuildWithStepsPage.tsx similarity index 80% rename from plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx rename to plugins/circleci/src/components/BuildWithStepsPage/BuildWithStepsPage.tsx index d0e0c655c3..30994f5ce3 100644 --- a/plugins/circleci/src/pages/BuildWithStepsPage/BuildWithStepsPage.tsx +++ b/plugins/circleci/src/components/BuildWithStepsPage/BuildWithStepsPage.tsx @@ -15,20 +15,22 @@ */ import React, { FC, useEffect } from 'react'; import { useParams } from 'react-router-dom'; -import { Content, InfoCard, Progress } from '@backstage/core'; +import { InfoCard, Progress, Link } from '@backstage/core'; import { BuildWithSteps, BuildStepAction } from '../../api'; -import { Grid, Box, Link, IconButton } from '@material-ui/core'; +import { + Grid, + Box, + IconButton, + Breadcrumbs, + Typography, + Link as MaterialLink, +} from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; -import { PluginHeader } from '../../components/PluginHeader'; import { ActionOutput } from './lib/ActionOutput/ActionOutput'; -import { Layout } from '../../components/Layout'; import LaunchIcon from '@material-ui/icons/Launch'; -import { useSettings } from '../../state/useSettings'; import { useBuildWithSteps } from '../../state/useBuildWithSteps'; -import { AppStateProvider } from '../../state'; -import { Settings } from '../../components/Settings'; -const IconLink = IconButton as typeof Link; +const IconLink = (IconButton as any) as typeof MaterialLink; const BuildName: FC<{ build?: BuildWithSteps }> = ({ build }) => ( #{build?.build_num} - {build?.subject} @@ -94,56 +96,13 @@ const pickClassName = ( return classes.neutral; }; -const Page = () => ( - - - - - - - - -); - -const BuildWithStepsView: FC<{}> = () => { - const { buildId = '' } = useParams(); - const classes = useStyles(); - const [settings] = useSettings(); - const [{ loading, value }, { startPolling, stopPolling }] = useBuildWithSteps( - parseInt(buildId, 10), - ); - - useEffect(() => { - startPolling(); - return () => stopPolling(); - }, [buildId, settings, startPolling, stopPolling]); - - return ( - <> - - - - - } - cardClassName={classes.cardContent} - > - {loading ? : } - - - - - ); -}; - const BuildsList: FC<{ build?: BuildWithSteps }> = ({ build }) => ( {build && build.steps && build.steps.map( ({ name, actions }: { name: string; actions: BuildStepAction[] }) => ( - + ), )} @@ -167,5 +126,35 @@ const ActionsList: FC<{ actions: BuildStepAction[]; name: string }> = ({ ); }; -export default Page; -export { BuildWithStepsView as BuildWithSteps }; +export const BuildWithStepsPage = () => { + const { buildId = '' } = useParams(); + const classes = useStyles(); + const [{ loading, value }, { startPolling, stopPolling }] = useBuildWithSteps( + parseInt(buildId, 10), + ); + + useEffect(() => { + startPolling(); + return () => stopPolling(); + }, [buildId, startPolling, stopPolling]); + + return ( + <> + + All builds + Build details + + + + } + cardClassName={classes.cardContent} + > + {loading ? : } + + + + + ); +}; diff --git a/plugins/circleci/src/components/BuildWithStepsPage/index.ts b/plugins/circleci/src/components/BuildWithStepsPage/index.ts new file mode 100644 index 0000000000..c5627bda1c --- /dev/null +++ b/plugins/circleci/src/components/BuildWithStepsPage/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { BuildWithStepsPage } from './BuildWithStepsPage'; diff --git a/plugins/circleci/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx similarity index 84% rename from plugins/circleci/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx rename to plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx index dd526c1b5f..65e4537ad7 100644 --- a/plugins/circleci/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx +++ b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx @@ -13,23 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useEffect, useState, FC, Suspense } from 'react'; + import { - ExpansionPanel, - ExpansionPanelSummary, - Typography, - ExpansionPanelDetails, + Accordion, + AccordionDetails, + AccordionSummary, LinearProgress, + Typography, } from '@material-ui/core'; -import moment from 'moment'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { makeStyles } from '@material-ui/core/styles'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { BuildStepAction } from 'circleci-api'; +import moment from 'moment'; +import React, { FC, Suspense, useEffect, useState } from 'react'; const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); moment.relativeTimeThreshold('ss', 0); const useStyles = makeStyles({ - expansionPanelDetails: { + accordionDetails: { padding: 0, }, button: { @@ -66,11 +67,8 @@ export const ActionOutput: FC<{ ) .humanize(); return ( - - + } aria-controls={`panel-${name}-content`} id={`panel-${name}-header`} @@ -81,8 +79,8 @@ export const ActionOutput: FC<{ {name} ({timeElapsed}) - - + + {messages.length === 0 ? ( 'Nothing here...' ) : ( @@ -92,7 +90,7 @@ export const ActionOutput: FC<{ )} - - + + ); }; diff --git a/plugins/circleci/src/pages/BuildWithStepsPage/lib/ActionOutput/index.ts b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/index.ts similarity index 100% rename from plugins/circleci/src/pages/BuildWithStepsPage/lib/ActionOutput/index.ts rename to plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/index.ts diff --git a/plugins/circleci/src/components/BuildsPage/BuildsPage.tsx b/plugins/circleci/src/components/BuildsPage/BuildsPage.tsx new file mode 100644 index 0000000000..d8c38de481 --- /dev/null +++ b/plugins/circleci/src/components/BuildsPage/BuildsPage.tsx @@ -0,0 +1,26 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Builds } from './lib/Builds'; +import { Grid } from '@material-ui/core'; + +export const BuildsPage = () => ( + + + + + +); diff --git a/plugins/circleci/src/components/BuildsPage/index.ts b/plugins/circleci/src/components/BuildsPage/index.ts new file mode 100644 index 0000000000..f9543ed0a8 --- /dev/null +++ b/plugins/circleci/src/components/BuildsPage/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { BuildsPage } from './BuildsPage'; diff --git a/plugins/circleci/src/pages/BuildsPage/lib/Builds/Builds.tsx b/plugins/circleci/src/components/BuildsPage/lib/Builds/Builds.tsx similarity index 100% rename from plugins/circleci/src/pages/BuildsPage/lib/Builds/Builds.tsx rename to plugins/circleci/src/components/BuildsPage/lib/Builds/Builds.tsx diff --git a/plugins/circleci/src/pages/BuildsPage/lib/Builds/index.ts b/plugins/circleci/src/components/BuildsPage/lib/Builds/index.ts similarity index 100% rename from plugins/circleci/src/pages/BuildsPage/lib/Builds/index.ts rename to plugins/circleci/src/components/BuildsPage/lib/Builds/index.ts diff --git a/plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx b/plugins/circleci/src/components/BuildsPage/lib/CITable/CITable.tsx similarity index 93% rename from plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx rename to plugins/circleci/src/components/BuildsPage/lib/CITable/CITable.tsx index b349dcfcbe..8e693429c2 100644 --- a/plugins/circleci/src/pages/BuildsPage/lib/CITable/CITable.tsx +++ b/plugins/circleci/src/components/BuildsPage/lib/CITable/CITable.tsx @@ -17,7 +17,7 @@ import React, { FC } from 'react'; import { Link, Typography, Box, IconButton } from '@material-ui/core'; import RetryIcon from '@material-ui/icons/Replay'; import GitHubIcon from '@material-ui/icons/GitHub'; -import { Link as RouterLink } from 'react-router-dom'; +import { Link as RouterLink, generatePath } from 'react-router-dom'; import { StatusError, StatusWarning, @@ -27,6 +27,7 @@ import { Table, TableColumn, } from '@backstage/core'; +import { circleCIBuildRouteRef } from '../../../../route-refs'; export type CITableBuildInfo = { id: string; @@ -80,7 +81,10 @@ const generatedColumns: TableColumn[] = [ field: 'buildName', highlight: true, render: (row: Partial) => ( - + {row.buildName} ), diff --git a/plugins/circleci/src/pages/BuildsPage/lib/CITable/index.ts b/plugins/circleci/src/components/BuildsPage/lib/CITable/index.ts similarity index 100% rename from plugins/circleci/src/pages/BuildsPage/lib/CITable/index.ts rename to plugins/circleci/src/components/BuildsPage/lib/CITable/index.ts diff --git a/plugins/circleci/src/components/CircleCIWidget.tsx b/plugins/circleci/src/components/CircleCIWidget.tsx deleted file mode 100644 index 767eb6d5c7..0000000000 --- a/plugins/circleci/src/components/CircleCIWidget.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React from 'react'; -import { Route, MemoryRouter, Routes } from 'react-router'; -import { Builds } from '../pages/BuildsPage'; -import { BuildWithSteps } from '../pages/BuildWithStepsPage'; -import { AppStateProvider } from '../state'; -import { Settings } from './Settings'; - -// TODO: allow pass in settings as props -// When some shared settings workflow -// will be established -export const CircleCIWidget = () => ( - - - <> - - } /> - } /> - - - - - -); diff --git a/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx b/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx deleted file mode 100644 index 9f94cff480..0000000000 --- a/plugins/circleci/src/components/PluginHeader/PluginHeader.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React, { FC } from 'react'; -import { Link as RouterLink, useLocation } from 'react-router-dom'; -import { ContentHeader, SupportButton } from '@backstage/core'; -import { Button, IconButton, Box, Typography } from '@material-ui/core'; -import ArrowBack from '@material-ui/icons/ArrowBack'; -import SettingsIcon from '@material-ui/icons/Settings'; -import { useSettings } from '../../state'; - -export type Props = { title?: string }; -export const PluginHeader: FC = ({ title = 'CircleCI' }) => { - const [, { showSettings }] = useSettings(); - const location = useLocation(); - const notRoot = !location.pathname.match(/\/circleci\/?$/); - const isSettingsPage = location.pathname.match(/\/circleci\/settings\/?/); - return ( - ( - - {notRoot && ( - - - - )} - {title} - - )} - > - {!isSettingsPage && ( - - )} - - This plugin allows you to view and interact with your builds within the - Circle CI environment. - - - ); -}; diff --git a/plugins/circleci/src/components/Router.tsx b/plugins/circleci/src/components/Router.tsx new file mode 100644 index 0000000000..282eac9111 --- /dev/null +++ b/plugins/circleci/src/components/Router.tsx @@ -0,0 +1,43 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Routes, Route } from 'react-router'; +import { circleCIRouteRef, circleCIBuildRouteRef } from '../route-refs'; +import { BuildWithStepsPage } from './BuildWithStepsPage/'; +import { BuildsPage } from './BuildsPage'; +import { CIRCLECI_ANNOTATION } from '../constants'; +import { Entity } from '@backstage/catalog-model'; +import { WarningPanel } from '@backstage/core'; + +export const isPluginApplicableToEntity = (entity: Entity) => + Boolean(entity.metadata.annotations?.[CIRCLECI_ANNOTATION]) && + entity.metadata.annotations?.[CIRCLECI_ANNOTATION] !== ''; + +export const Router = ({ entity }: { entity: Entity }) => + !isPluginApplicableToEntity(entity) ? ( + +
{CIRCLECI_ANNOTATION}
annotation is missing on the entity. +
+ ) : ( + + } /> + } + /> + + ); diff --git a/plugins/circleci/src/components/Settings/Settings.tsx b/plugins/circleci/src/components/Settings/Settings.tsx deleted file mode 100644 index b3b62ce930..0000000000 --- a/plugins/circleci/src/components/Settings/Settings.tsx +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React, { useState, useEffect } from 'react'; -import { - Button, - TextField, - List, - ListItem, - Snackbar, - Box, - Dialog, - DialogTitle, -} from '@material-ui/core'; -import { Alert } from '@material-ui/lab'; -import { useSettings } from '../../state'; - -const Settings = () => { - const [ - { - repo: repoFromStore, - owner: ownerFromStore, - token: tokenFromStore, - showSettings, - }, - { saveSettings, hideSettings }, - ] = useSettings(); - - const [token, setToken] = useState(() => tokenFromStore); - const [owner, setOwner] = useState(() => ownerFromStore); - const [repo, setRepo] = useState(() => repoFromStore); - - useEffect(() => { - if (tokenFromStore !== token) { - setToken(token); - } - if (ownerFromStore !== owner) { - setOwner(owner); - } - if (repoFromStore !== repo) { - setRepo(repo); - } - }, [ownerFromStore, repoFromStore, tokenFromStore, token, owner, repo]); - - const [saved, setSaved] = useState(false); - - return ( - <> - setSaved(false)} - > - Credentials saved. - - - - Project Credentials - {/* {authed ? : } */} - - - - - setToken(e.target.value)} - /> - - - setOwner(e.target.value)} - /> - - - setRepo(e.target.value)} - /> - - - - - - - - - - - ); -}; - -export default Settings; diff --git a/plugins/circleci/src/constants.ts b/plugins/circleci/src/constants.ts new file mode 100644 index 0000000000..8c96db93e2 --- /dev/null +++ b/plugins/circleci/src/constants.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const CIRCLECI_ANNOTATION = 'circleci.com/project-slug'; diff --git a/plugins/circleci/src/index.ts b/plugins/circleci/src/index.ts index e2e6c4fa69..c6cb140208 100644 --- a/plugins/circleci/src/index.ts +++ b/plugins/circleci/src/index.ts @@ -17,4 +17,5 @@ export { plugin } from './plugin'; export * from './api'; export * from './route-refs'; -export { CircleCIWidget } from './components/CircleCIWidget'; +export { Router, isPluginApplicableToEntity } from './components/Router'; +export { CIRCLECI_ANNOTATION } from './constants'; diff --git a/plugins/circleci/src/pages/BuildsPage/BuildsPage.tsx b/plugins/circleci/src/pages/BuildsPage/BuildsPage.tsx deleted file mode 100644 index 6e7fc44249..0000000000 --- a/plugins/circleci/src/pages/BuildsPage/BuildsPage.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React, { FC } from 'react'; -import { Content } from '@backstage/core'; -import { Grid } from '@material-ui/core'; -import { Builds as BuildsComp } from './lib/Builds'; -import { Layout } from '../../components/Layout'; -import { PluginHeader } from '../../components/PluginHeader'; -import { AppStateProvider } from '../../state/AppState'; -import { Settings } from '../../components/Settings'; - -const BuildsPage: FC<{}> = () => ( - - - - - - - - -); - -const Builds = () => ( - <> - - - - - - - -); - -export default BuildsPage; -export { Builds }; diff --git a/plugins/circleci/src/plugin.ts b/plugins/circleci/src/plugin.ts index 47ecccef4f..f966caa383 100644 --- a/plugins/circleci/src/plugin.ts +++ b/plugins/circleci/src/plugin.ts @@ -13,15 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createPlugin } from '@backstage/core'; -import { circleCIRouteRef, circleCIBuildRouteRef } from './route-refs'; -import BuildsPage from './pages/BuildsPage/BuildsPage'; -import BuildWithStepsPage from './pages/BuildWithStepsPage/BuildWithStepsPage'; + +import { createPlugin, createApiFactory, configApiRef } from '@backstage/core'; +import { circleCIApiRef, CircleCIApi } from './api'; export const plugin = createPlugin({ id: 'circleci', - register({ router }) { - router.addRoute(circleCIRouteRef, BuildsPage); - router.addRoute(circleCIBuildRouteRef, BuildWithStepsPage); - }, + apis: [ + createApiFactory({ + api: circleCIApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => + new CircleCIApi( + `${configApi.getString('backend.baseUrl')}/proxy/circleci/api`, + ), + }), + ], }); diff --git a/plugins/circleci/src/route-refs.tsx b/plugins/circleci/src/route-refs.tsx index 581f035c1d..d6bad363ed 100644 --- a/plugins/circleci/src/route-refs.tsx +++ b/plugins/circleci/src/route-refs.tsx @@ -33,11 +33,11 @@ const CircleCIIcon: FC = props => ( export const circleCIRouteRef = createRouteRef({ icon: CircleCIIcon, - path: '/circleci', + path: '', title: 'CircleCI | All builds', }); export const circleCIBuildRouteRef = createRouteRef({ - path: '/circleci/build/:buildId', + path: ':buildId', title: 'CircleCI | Build info', }); diff --git a/plugins/circleci/src/state/AppState.tsx b/plugins/circleci/src/state/AppState.tsx deleted file mode 100644 index 2ee00362ee..0000000000 --- a/plugins/circleci/src/state/AppState.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import React, { FC, useReducer, Dispatch, Reducer } from 'react'; -import { circleCIApiRef } from '../api'; -import type { State, Action, SettingsState } from './types'; - -export type { SettingsState }; - -export const AppContext = React.createContext<[State, Dispatch]>( - [] as any, -); -export const STORAGE_KEY = `${circleCIApiRef.id}.settings`; - -const initialState: State = { - owner: '', - repo: '', - token: '', - showSettings: false, -}; - -const reducer: Reducer = (state, action) => { - switch (action.type) { - case 'setCredentials': - return { - ...state, - ...action.payload, - }; - case 'showSettings': - return { ...state, showSettings: true }; - case 'hideSettings': - return { ...state, showSettings: false }; - default: - return state; - } -}; - -export const AppStateProvider: FC = ({ children }) => { - const [state, dispatch] = useReducer(reducer, initialState); - return ( - - <>{children} - - ); -}; diff --git a/plugins/circleci/src/state/index.ts b/plugins/circleci/src/state/index.ts index 2321103eb4..d21a380c2a 100644 --- a/plugins/circleci/src/state/index.ts +++ b/plugins/circleci/src/state/index.ts @@ -13,7 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './AppState'; -export * from './useSettings'; export * from './useBuilds'; export * from './useBuildWithSteps'; diff --git a/plugins/circleci/src/state/useBuildWithSteps.ts b/plugins/circleci/src/state/useBuildWithSteps.ts index 8fa7fa896d..c169b8fe63 100644 --- a/plugins/circleci/src/state/useBuildWithSteps.ts +++ b/plugins/circleci/src/state/useBuildWithSteps.ts @@ -14,31 +14,35 @@ * limitations under the License. */ import { errorApiRef, useApi } from '@backstage/core'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import { useAsyncRetry } from 'react-use'; -import { circleCIApiRef, GitType } from '../api/index'; +import { circleCIApiRef } from '../api/index'; import { useAsyncPolling } from './useAsyncPolling'; -import { useSettings } from './useSettings'; +import { useProjectSlugFromEntity, mapVcsType } from './useBuilds'; const INTERVAL_AMOUNT = 1500; export function useBuildWithSteps(buildId: number) { - const [{ token, repo, owner }] = useSettings(); + const { vcs, repo, owner } = useProjectSlugFromEntity(); const api = useApi(circleCIApiRef); const errorApi = useApi(errorApiRef); + const vcsOption = useMemo( + () => ({ + owner: owner, + repo: repo, + type: mapVcsType(vcs), + }), + [owner, repo, vcs], + ); + const getBuildWithSteps = useCallback(async () => { - if (owner === '' || repo === '' || token === '') { + if (owner === '' || repo === '' || vcs === '') { return Promise.reject('No credentials provided'); } try { const options = { - token: token, - vcs: { - owner: owner, - repo: repo, - type: GitType.GITHUB, - }, + vcs: vcsOption, }; const build = await api.getBuild(buildId, options); return Promise.resolve(build); @@ -46,17 +50,12 @@ export function useBuildWithSteps(buildId: number) { errorApi.post(e); return Promise.reject(e); } - }, [token, owner, repo, buildId, api, errorApi]); + }, [vcsOption, buildId, api, errorApi]); // eslint-disable-line react-hooks/exhaustive-deps const restartBuild = async () => { try { await api.retry(buildId, { - token: token, - vcs: { - owner: owner, - repo: repo, - type: GitType.GITHUB, - }, + vcs: vcsOption, }); } catch (e) { errorApi.post(e); diff --git a/plugins/circleci/src/state/useBuilds.ts b/plugins/circleci/src/state/useBuilds.ts index 282ef68f12..2a4aed7fd6 100644 --- a/plugins/circleci/src/state/useBuilds.ts +++ b/plugins/circleci/src/state/useBuilds.ts @@ -18,8 +18,9 @@ import { BuildSummary, GitType } from 'circleci-api'; import { useCallback, useEffect, useState } from 'react'; import { useAsyncRetry } from 'react-use'; import { circleCIApiRef } from '../api/index'; -import type { CITableBuildInfo } from '../pages/BuildsPage/lib/CITable'; -import { useSettings } from './useSettings'; +import type { CITableBuildInfo } from '../components/BuildsPage/lib/CITable'; +import { useEntity } from '@backstage/plugin-catalog'; +import { CIRCLECI_ANNOTATION } from '../constants'; const makeReadableStatus = (status: string | undefined) => { if (!status) return ''; @@ -68,8 +69,25 @@ export const transform = ( }); }; +export const useProjectSlugFromEntity = () => { + const { entity } = useEntity(); + const [vcs, owner, repo] = ( + entity.metadata.annotations?.[CIRCLECI_ANNOTATION] ?? '' + ).split('/'); + return { vcs, owner, repo }; +}; + +export function mapVcsType(vcs: string): GitType { + switch (vcs) { + case 'github': + return GitType.GITHUB; + default: + return GitType.BITBUCKET; + } +} + export function useBuilds() { - const [{ repo, owner, token }] = useSettings(); + const { repo, owner, vcs } = useProjectSlugFromEntity(); const api = useApi(circleCIApiRef); const errorApi = useApi(errorApiRef); @@ -79,7 +97,7 @@ export function useBuilds() { const getBuilds = useCallback( async ({ limit, offset }: { limit: number; offset: number }) => { - if (owner === '' || repo === '' || token === '') { + if (owner === '' || repo === '' || vcs === '') { return Promise.reject('No credentials provided'); } @@ -87,11 +105,10 @@ export function useBuilds() { return await api.getBuilds( { limit, offset }, { - token: token, vcs: { owner: owner, repo: repo, - type: GitType.GITHUB, + type: mapVcsType(vcs), }, }, ); @@ -100,13 +117,12 @@ export function useBuilds() { return Promise.reject(e); } }, - [repo, token, owner, api, errorApi], + [repo, owner, vcs, api, errorApi], ); const restartBuild = async (buildId: number) => { try { await api.retry(buildId, { - token: token, vcs: { owner: owner, repo: repo, diff --git a/plugins/circleci/src/state/useSettings.ts b/plugins/circleci/src/state/useSettings.ts deleted file mode 100644 index 3cc58a65bd..0000000000 --- a/plugins/circleci/src/state/useSettings.ts +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import { errorApiRef, useApi } from '@backstage/core'; -import { useContext, useEffect } from 'react'; -import { AppContext, STORAGE_KEY } from './AppState'; -import { Settings } from './types'; - -export function useSettings() { - const [settings, dispatch] = useContext(AppContext); - - const errorApi = useApi(errorApiRef); - - useEffect(() => { - const rehydrate = () => { - try { - const stateFromStorage = JSON.parse( - sessionStorage.getItem(STORAGE_KEY)!, - ); - if ( - stateFromStorage && - Object.keys(stateFromStorage).some( - k => (settings as any)[k] !== stateFromStorage[k], - ) - ) - dispatch({ - type: 'setCredentials', - payload: stateFromStorage, - }); - } catch (error) { - errorApi.post(error); - } - }; - - rehydrate(); - }, [dispatch, errorApi, settings]); - - const persist = (state: Settings) => { - sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state)); - }; - - return [ - settings, - { - saveSettings: (state: Settings) => { - persist(state); - dispatch({ - type: 'setCredentials', - payload: state, - }); - }, - showSettings: () => dispatch({ type: 'showSettings' }), - hideSettings: () => dispatch({ type: 'hideSettings' }), - }, - ] as const; -} diff --git a/plugins/explore/README.md b/plugins/explore/README.md index 12a4e58380..d5453e594c 100644 --- a/plugins/explore/README.md +++ b/plugins/explore/README.md @@ -1,4 +1,5 @@ # Title + Welcome to the explore plugin! ## Sub-section 1 diff --git a/plugins/explore/package.json b/plugins/explore/package.json index 42176c45cf..f302f4080c 100644 --- a/plugins/explore/package.json +++ b/plugins/explore/package.json @@ -23,13 +23,14 @@ "dependencies": { "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "classnames": "^2.2.6", "react": "^16.13.1", "react-dom": "^16.13.1", - "react-use": "^15.3.3" + "react-use": "^15.3.3", + "react-router": "6.0.0-beta.0" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.21", diff --git a/plugins/explore/src/components/ExploreCard.tsx b/plugins/explore/src/components/ExploreCard.tsx index af6eca61b7..9c61e9bea8 100644 --- a/plugins/explore/src/components/ExploreCard.tsx +++ b/plugins/explore/src/components/ExploreCard.tsx @@ -28,7 +28,7 @@ import { } from '@material-ui/core'; import { BackstageTheme } from '@backstage/theme'; -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles(theme => ({ card: { display: 'flex', flexDirection: 'column', diff --git a/plugins/explore/src/components/ExplorePluginPage.tsx b/plugins/explore/src/components/ExplorePluginPage.tsx index 3e073ad322..4365157f62 100644 --- a/plugins/explore/src/components/ExplorePluginPage.tsx +++ b/plugins/explore/src/components/ExplorePluginPage.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { FC } from 'react'; +import React from 'react'; import { makeStyles, Typography } from '@material-ui/core'; import { Content, @@ -107,7 +107,7 @@ const toolsCards = [ }, ]; -const ExplorePluginPage: FC<{}> = () => { +export const ExplorePluginPage = () => { const classes = useStyles(); return ( @@ -130,5 +130,3 @@ const ExplorePluginPage: FC<{}> = () => { ); }; - -export default ExplorePluginPage; diff --git a/packages/core-api/src/apis/implementations/auth/microsoft/types.ts b/plugins/explore/src/components/Router.tsx similarity index 66% rename from packages/core-api/src/apis/implementations/auth/microsoft/types.ts rename to plugins/explore/src/components/Router.tsx index 6eaf92808a..becb2522d0 100644 --- a/packages/core-api/src/apis/implementations/auth/microsoft/types.ts +++ b/plugins/explore/src/components/Router.tsx @@ -14,15 +14,13 @@ * limitations under the License. */ -import { ProfileInfo, BackstageIdentity } from '../../../definitions'; +import React from 'react'; +import { Route, Routes } from 'react-router'; +import { ExplorePluginPage } from './ExplorePluginPage'; +import { rootRouteRef } from '../plugin'; -export type MicrosoftSession = { - providerInfo: { - idToken: string; - accessToken: string; - scopes: Set; - expiresAt: Date; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; -}; +export const Router = () => ( + + } /> + +); diff --git a/plugins/explore/src/index.ts b/plugins/explore/src/index.ts index 3a0a0fe2d3..ff7857cacd 100644 --- a/plugins/explore/src/index.ts +++ b/plugins/explore/src/index.ts @@ -15,3 +15,4 @@ */ export { plugin } from './plugin'; +export { Router } from './components/Router'; diff --git a/plugins/explore/src/plugin.ts b/plugins/explore/src/plugin.ts index 66e48a9b15..75ea892242 100644 --- a/plugins/explore/src/plugin.ts +++ b/plugins/explore/src/plugin.ts @@ -14,12 +14,9 @@ * limitations under the License. */ -import { createPlugin } from '@backstage/core'; -import ExplorePluginPage from './components/ExplorePluginPage'; +import { createPlugin, createRouteRef } from '@backstage/core'; +export const rootRouteRef = createRouteRef({ path: '', title: 'Explore' }); export const plugin = createPlugin({ id: 'explore', - register({ router }) { - router.registerRoute('/explore', ExplorePluginPage); - }, }); diff --git a/plugins/gcp-projects/.eslintrc.js b/plugins/gcp-projects/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/gcp-projects/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/plugins/gcp-projects/README.md b/plugins/gcp-projects/README.md new file mode 100644 index 0000000000..586cd7b603 --- /dev/null +++ b/plugins/gcp-projects/README.md @@ -0,0 +1,13 @@ +# gcp-projects + +Welcome to the gcp-projects plugin! + +_This plugin was created through the Backstage CLI_ + +## Getting started + +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/gcp-projects](http://localhost:3000/gcp-projects). + +You can also serve the plugin in isolation by running `yarn start` in the plugin directory. +This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. +It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. diff --git a/plugins/circleci/src/pages/BuildWithStepsPage/index.ts b/plugins/gcp-projects/dev/index.tsx similarity index 80% rename from plugins/circleci/src/pages/BuildWithStepsPage/index.ts rename to plugins/gcp-projects/dev/index.tsx index fddff7088c..812a5585d4 100644 --- a/plugins/circleci/src/pages/BuildWithStepsPage/index.ts +++ b/plugins/gcp-projects/dev/index.tsx @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { - default as DetailedViewPage, - BuildWithSteps, -} from './BuildWithStepsPage'; + +import { createDevApp } from '@backstage/dev-utils'; +import { plugin } from '../src/plugin'; + +createDevApp().registerPlugin(plugin).render(); diff --git a/plugins/gcp-projects/package.json b/plugins/gcp-projects/package.json new file mode 100644 index 0000000000..cdc4bb507d --- /dev/null +++ b/plugins/gcp-projects/package.json @@ -0,0 +1,47 @@ +{ + "name": "@backstage/plugin-gcp-projects", + "version": "0.1.1-alpha.21", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "private": true, + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "scripts": { + "build": "backstage-cli plugin:build", + "start": "backstage-cli plugin:serve", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "diff": "backstage-cli plugin:diff", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/core": "^0.1.1-alpha.21", + "@backstage/theme": "^0.1.1-alpha.21", + "@material-ui/core": "^4.11.0", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.45", + "react": "^16.13.1", + "react-dom": "^16.13.1", + "react-router-dom": "^5.2.0", + "react-use": "^15.3.3" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.21", + "@backstage/dev-utils": "^0.1.1-alpha.21", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^10.4.1", + "@testing-library/user-event": "^12.0.7", + "@types/jest": "^26.0.7", + "@types/node": "^12.0.0", + "jest-fetch-mock": "^3.0.3" + }, + "files": [ + "dist" + ] +} diff --git a/packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.test.ts b/plugins/gcp-projects/src/api/GCPApi.ts similarity index 52% rename from packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.test.ts rename to plugins/gcp-projects/src/api/GCPApi.ts index 5912c2a364..95b686815e 100644 --- a/packages/core-api/src/apis/implementations/auth/auth0/Auth0Auth.test.ts +++ b/plugins/gcp-projects/src/api/GCPApi.ts @@ -14,23 +14,21 @@ * limitations under the License. */ -import Auth0Auth from './Auth0Auth'; +import { createApiRef } from '@backstage/core'; +import { Project, Operation } from './types'; -describe('Auth0Auth', () => { - it('should normalize scope', () => { - const tests = [ - { - arguments: ['read_user api write_repository'], - expect: new Set(['read_user', 'api', 'write_repository']), - }, - { - arguments: ['read_repository sudo'], - expect: new Set(['read_repository', 'sudo']), - }, - ]; - - for (const test of tests) { - expect(Auth0Auth.normalizeScopes(...test.arguments)).toEqual(test.expect); - } - }); +export const GCPApiRef = createApiRef({ + id: 'plugin.gcpprojects.service', + description: 'Used by the GCP Projects plugin to make requests', }); + +export type GCPApi = { + listProjects: ({ token }: { token: string }) => Promise; + getProject: (projectId: string, token: Promise) => Promise; + createProject: ( + projectName: string, + projectId: string, + owner: string, + token: string, + ) => Promise; +}; diff --git a/plugins/gcp-projects/src/api/GCPClient.ts b/plugins/gcp-projects/src/api/GCPClient.ts new file mode 100644 index 0000000000..dc4fe21132 --- /dev/null +++ b/plugins/gcp-projects/src/api/GCPClient.ts @@ -0,0 +1,124 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { GCPApi } from './GCPApi'; +import { Project, Operation, Status } from './types'; + +const BaseURL = + 'https://content-cloudresourcemanager.googleapis.com/v1/projects'; + +export class GCPClient implements GCPApi { + async listProjects({ token }: { token: string }): Promise { + const response = await fetch(BaseURL, { + headers: new Headers({ + Accept: '*/*', + Authorization: `Bearer ${token}`, + }), + }); + + if (!response.ok) { + return [ + { + name: 'Error', + projectNumber: 'Response status is not OK', + projectId: 'Error', + lifecycleState: 'error', + createTime: 'Error', + }, + ]; + } + + const data = await response.json(); + + return data.projects; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async getProject( + projectId: string, + token: Promise, + ): Promise { + const url = `${BaseURL}/${projectId}`; + const response = await fetch(url, { + headers: new Headers({ + Authorization: `Bearer ${await token}`, + }), + }); + + const dataBlank: Project = { + name: 'Error', + projectNumber: `Response status is ${response.status}`, + projectId: 'Error', + lifecycleState: 'error', + createTime: 'Error', + }; + + if (!response.ok) { + return dataBlank; + } + + const data = await response.json(); + + const newData: Project = data; + + return newData; + } + + async createProject( + projectName: string, + projectId: string, + token: string, + ): Promise { + const status: Status = { + code: 0, + message: '', + details: [], + }; + + const op: Operation = { + name: '', + metadata: '', + done: true, + error: status, + response: '', + }; + + const newProject: Project = { + name: projectName, + projectId: projectId, + }; + + const body = JSON.stringify(newProject); + + const response = await fetch(BaseURL, { + headers: new Headers({ + Accept: '*/*', + Authorization: `Bearer ${token}`, + }), + body: body, + method: 'POST', + }); + + if (!response.ok) { + status.code = response.status; + return op; + } + + const data = await response.json(); + + return data; + } +} diff --git a/plugins/gcp-projects/src/api/index.ts b/plugins/gcp-projects/src/api/index.ts new file mode 100644 index 0000000000..51f617f19c --- /dev/null +++ b/plugins/gcp-projects/src/api/index.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './GCPApi'; +export * from './GCPClient'; +export * from './types'; diff --git a/packages/core-api/src/apis/implementations/auth/auth0/types.ts b/plugins/gcp-projects/src/api/types.ts similarity index 60% rename from packages/core-api/src/apis/implementations/auth/auth0/types.ts rename to plugins/gcp-projects/src/api/types.ts index 203ccd9fd9..8dccaec5e2 100644 --- a/packages/core-api/src/apis/implementations/auth/auth0/types.ts +++ b/plugins/gcp-projects/src/api/types.ts @@ -14,15 +14,28 @@ * limitations under the License. */ -import { ProfileInfo, BackstageIdentity } from '../../../definitions'; - -export type Auth0Session = { - providerInfo: { - idToken: string; - accessToken: string; - scopes: Set; - expiresAt: Date; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; +export type Project = { + name: string; + projectNumber?: string; + projectId: string; + lifecycleState?: string; + createTime?: string; +}; + +export type ProjectDetails = { + details: string; +}; + +export type Operation = { + name: string; + metadata: string; + done: boolean; + error: Status; + response: string; +}; + +export type Status = { + code: number; + message: string; + details: string[]; }; diff --git a/plugins/gcp-projects/src/components/NewProjectPage/NewProjectPage.tsx b/plugins/gcp-projects/src/components/NewProjectPage/NewProjectPage.tsx new file mode 100644 index 0000000000..0149f8ac92 --- /dev/null +++ b/plugins/gcp-projects/src/components/NewProjectPage/NewProjectPage.tsx @@ -0,0 +1,131 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { FC, useState } from 'react'; +import { Grid, Button, TextField } from '@material-ui/core'; + +import { + InfoCard, + Content, + ContentHeader, + SimpleStepper, + SimpleStepperStep, + StructuredMetadataTable, + HeaderLabel, + Page, + Header, + pageTheme, + SupportButton, +} from '@backstage/core'; + +export const Project: FC<{}> = () => { + const [projectName, setProjectName] = useState(''); + const [projectId, setProjectId] = useState(''); + const [disabled, setDisabled] = useState(true); + + const metadata = { + ProjectName: projectName, + ProjectId: projectId, + }; + + return ( + + + + + + + setProjectName(e.target.value)} + value={projectName} + fullWidth + /> + + + setProjectId(e.target.value)} + value={projectId} + fullWidth + /> + + + setDisabled(false), + }} + > + + + + + + + + + + ); +}; + +const labels = ( + <> + + + +); + +export const NewProjectPage = () => { + return ( + +
+ {labels} +
+ + + + This plugin allows you to view and interact with your gcp projects. + + + + +
+ ); +}; diff --git a/plugins/gcp-projects/src/components/NewProjectPage/index.ts b/plugins/gcp-projects/src/components/NewProjectPage/index.ts new file mode 100644 index 0000000000..1d2f023887 --- /dev/null +++ b/plugins/gcp-projects/src/components/NewProjectPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { NewProjectPage } from './NewProjectPage'; diff --git a/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx b/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx new file mode 100644 index 0000000000..41d0b11019 --- /dev/null +++ b/plugins/gcp-projects/src/components/ProjectDetailsPage/ProjectDetailsPage.tsx @@ -0,0 +1,171 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Button, + ButtonGroup, + LinearProgress, + makeStyles, + Paper, + Table, + TableBody, + TableCell, + TableRow, + Theme, + Typography, +} from '@material-ui/core'; +import { + useApi, + googleAuthApiRef, + HeaderLabel, + Page, + Header, + pageTheme, + SupportButton, + Content, + ContentHeader, +} from '@backstage/core'; +import React from 'react'; +import { useAsync } from 'react-use'; +import { GCPApiRef } from '../../api'; + +const useStyles = makeStyles(theme => ({ + root: { + maxWidth: 720, + margin: theme.spacing(2), + }, + title: { + padding: theme.spacing(1, 0, 2, 0), + }, + table: { + padding: theme.spacing(1), + }, +})); + +const DetailsPage = () => { + const api = useApi(GCPApiRef); + const googleApi = useApi(googleAuthApiRef); + const token = googleApi.getAccessToken( + 'https://www.googleapis.com/auth/cloud-platform.read-only', + ); + + const classes = useStyles(); + const status = useAsync( + () => + api.getProject( + decodeURIComponent(location.search.split('projectId=')[1]), + token, + ), + [location.search], + ); + + if (status.loading) { + return ; + } else if (status.error) { + return ( + + Failed to load build, {status.error.message} + + ); + } + + const details = status.value; + + return ( +
+
+ + + + Name + + {details?.name} + + + + Project Number + + {details?.projectNumber} + + + + Project ID + + {details?.projectId} + + + + State + + {details?.lifecycleState} + + + + Creation Time + + {details?.createTime} + + + + Links + + + + {details?.name && ( + + )} + {details?.name && ( + + )} + + + + +
+ + ); +}; + +const labels = ( + <> + + + +); + +export const ProjectDetailsPage = () => { + return ( + +
+ {labels} +
+ + + Support Button + + + +
+ ); +}; diff --git a/plugins/gcp-projects/src/components/ProjectDetailsPage/index.ts b/plugins/gcp-projects/src/components/ProjectDetailsPage/index.ts new file mode 100644 index 0000000000..e9b6eb095a --- /dev/null +++ b/plugins/gcp-projects/src/components/ProjectDetailsPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ProjectDetailsPage } from './ProjectDetailsPage'; diff --git a/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx b/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx new file mode 100644 index 0000000000..7e09a307c9 --- /dev/null +++ b/plugins/gcp-projects/src/components/ProjectListPage/ProjectListPage.tsx @@ -0,0 +1,164 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// NEEDS WORK + +import { + Link, + useApi, + googleAuthApiRef, + HeaderLabel, + Page, + Header, + pageTheme, + SupportButton, + Content, + ContentHeader, +} from '@backstage/core'; +import { + LinearProgress, + Paper, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Tooltip, + Typography, + Button, +} from '@material-ui/core'; +import React from 'react'; +import { useAsync } from 'react-use'; +import { GCPApiRef, Project } from '../../api'; + +const LongText = ({ text, max }: { text: string; max: number }) => { + if (text.length < max) { + return {text}; + } + return ( + + {text.slice(0, max)}... + + ); +}; + +const labels = ( + <> + + + +); + +const PageContents = () => { + const api = useApi(GCPApiRef); + const googleApi = useApi(googleAuthApiRef); + + const { loading, error, value } = useAsync(async () => { + const token = await googleApi.getAccessToken( + 'https://www.googleapis.com/auth/cloud-platform.read-only', + ); + + const projects = api.listProjects({ token }); + return projects; + }); + + if (loading) { + return ; + } + + if (error) { + return ( + + {error.message}{' '} + + ); + } + + return ( + +
+ + + Name + Project Number + Project ID + State + Creation Time + + + + {value?.map((project: Project) => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ))} + +
+ + ); +}; + +export const ProjectListPage = () => { + return ( + +
+ {labels} +
+ + + + All your software catalog entities + + + +
+ ); +}; diff --git a/plugins/gcp-projects/src/components/ProjectListPage/index.ts b/plugins/gcp-projects/src/components/ProjectListPage/index.ts new file mode 100644 index 0000000000..c2b0479cef --- /dev/null +++ b/plugins/gcp-projects/src/components/ProjectListPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { ProjectListPage } from './ProjectListPage'; diff --git a/plugins/gcp-projects/src/index.ts b/plugins/gcp-projects/src/index.ts new file mode 100644 index 0000000000..d67bc6a864 --- /dev/null +++ b/plugins/gcp-projects/src/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { plugin } from './plugin'; +export * from './api'; diff --git a/plugins/gcp-projects/src/plugin.test.ts b/plugins/gcp-projects/src/plugin.test.ts new file mode 100644 index 0000000000..86e909995f --- /dev/null +++ b/plugins/gcp-projects/src/plugin.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { plugin } from './plugin'; + +describe('gcp-projects', () => { + it('should export plugin', () => { + expect(plugin).toBeDefined(); + }); +}); diff --git a/plugins/gcp-projects/src/plugin.ts b/plugins/gcp-projects/src/plugin.ts new file mode 100644 index 0000000000..41aacde597 --- /dev/null +++ b/plugins/gcp-projects/src/plugin.ts @@ -0,0 +1,48 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createPlugin, + createRouteRef, + createApiFactory, +} from '@backstage/core'; +import { ProjectListPage } from './components/ProjectListPage'; +import { ProjectDetailsPage } from './components/ProjectDetailsPage'; +import { NewProjectPage } from './components/NewProjectPage'; +import { GCPApiRef, GCPClient } from './api'; + +export const rootRouteRef = createRouteRef({ + path: '/gcp-projects', + title: 'GCP Projects', +}); +export const ProjectRouteRef = createRouteRef({ + path: '/gcp-projects/project', + title: 'GCP Project Page', +}); +export const NewProjectRouteRef = createRouteRef({ + path: '/gcp-projects/new', + title: 'GCP Project Page', +}); + +export const plugin = createPlugin({ + id: 'gcp-projects', + apis: [createApiFactory(GCPApiRef, new GCPClient())], + register({ router }) { + router.addRoute(rootRouteRef, ProjectListPage); + router.addRoute(ProjectRouteRef, ProjectDetailsPage); + router.addRoute(NewProjectRouteRef, NewProjectPage); + }, +}); diff --git a/plugins/gcp-projects/src/setupTests.ts b/plugins/gcp-projects/src/setupTests.ts new file mode 100644 index 0000000000..8553642152 --- /dev/null +++ b/plugins/gcp-projects/src/setupTests.ts @@ -0,0 +1,19 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '@testing-library/jest-dom'; + +require('jest-fetch-mock').enableMocks(); diff --git a/plugins/github-actions/scripts/sample.yaml b/plugins/github-actions/examples/sample.yaml similarity index 100% rename from plugins/github-actions/scripts/sample.yaml rename to plugins/github-actions/examples/sample.yaml diff --git a/plugins/github-actions/package.json b/plugins/github-actions/package.json index e4f09976eb..49862dea80 100644 --- a/plugins/github-actions/package.json +++ b/plugins/github-actions/package.json @@ -18,8 +18,7 @@ "diff": "backstage-cli plugin:diff", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", - "mock-data": "./scripts/mock-data.sh" + "clean": "backstage-cli clean" }, "dependencies": { "@backstage/catalog-model": "^0.1.1-alpha.21", @@ -27,14 +26,15 @@ "@backstage/core-api": "^0.1.1-alpha.21", "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@octokit/rest": "^18.0.0", - "@octokit/types": "^5.0.1", + "@octokit/types": "^5.4.1", "moment": "^2.27.0", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-lazylog": "^4.5.3", "react-router": "6.0.0-beta.0", "react-router-dom": "6.0.0-beta.0", "react-use": "^15.3.3" diff --git a/plugins/github-actions/scripts/mock-data.sh b/plugins/github-actions/scripts/mock-data.sh deleted file mode 100755 index 2653a415dd..0000000000 --- a/plugins/github-actions/scripts/mock-data.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - - curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/scripts/sample.yaml\"}" - echo diff --git a/plugins/github-actions/src/api/GithubActionsApi.ts b/plugins/github-actions/src/api/GithubActionsApi.ts index 9a95f21860..bf79e74351 100644 --- a/plugins/github-actions/src/api/GithubActionsApi.ts +++ b/plugins/github-actions/src/api/GithubActionsApi.ts @@ -19,6 +19,7 @@ import { ActionsListWorkflowRunsForRepoResponseData, ActionsGetWorkflowResponseData, ActionsGetWorkflowRunResponseData, + EndpointInterface, } from '@octokit/types'; export const githubActionsApiRef = createApiRef({ @@ -75,4 +76,15 @@ export type GithubActionsApi = { repo: string; runId: number; }) => Promise; + downloadJobLogsForWorkflowRun: ({ + token, + owner, + repo, + runId, + }: { + token: string; + owner: string; + repo: string; + runId: number; + }) => Promise; }; diff --git a/plugins/github-actions/src/api/GithubActionsClient.ts b/plugins/github-actions/src/api/GithubActionsClient.ts index 72f65075e6..94fb774537 100644 --- a/plugins/github-actions/src/api/GithubActionsClient.ts +++ b/plugins/github-actions/src/api/GithubActionsClient.ts @@ -20,6 +20,7 @@ import { ActionsListWorkflowRunsForRepoResponseData, ActionsGetWorkflowResponseData, ActionsGetWorkflowRunResponseData, + EndpointInterface, } from '@octokit/types'; export class GithubActionsClient implements GithubActionsApi { @@ -102,4 +103,24 @@ export class GithubActionsClient implements GithubActionsApi { }); return run.data; } + async downloadJobLogsForWorkflowRun({ + token, + owner, + repo, + runId, + }: { + token: string; + owner: string; + repo: string; + runId: number; + }): Promise { + const workflow = await new Octokit({ + auth: token, + }).actions.downloadJobLogsForWorkflowRun({ + owner, + repo, + job_id: runId, + }); + return workflow.data; + } } diff --git a/plugins/github-actions/src/api/types.ts b/plugins/github-actions/src/api/types.ts index cd74a20cda..ccc9198e58 100644 --- a/plugins/github-actions/src/api/types.ts +++ b/plugins/github-actions/src/api/types.ts @@ -29,6 +29,7 @@ export type Job = { conclusion: string; started_at: string; completed_at: string; + id: string; name: string; steps: Step[]; }; diff --git a/plugins/github-actions/src/components/Cards/Cards.tsx b/plugins/github-actions/src/components/Cards/Cards.tsx index 478b3810cb..28783efdea 100644 --- a/plugins/github-actions/src/components/Cards/Cards.tsx +++ b/plugins/github-actions/src/components/Cards/Cards.tsx @@ -32,6 +32,7 @@ import { useApi, } from '@backstage/core'; import ExternalLinkIcon from '@material-ui/icons/Launch'; +import { GITHUB_ACTIONS_ANNOTATION } from '../useProjectName'; const useStyles = makeStyles({ externalLinkIcon: { @@ -83,7 +84,7 @@ export const LatestWorkflowRunCard = ({ }) => { const errorApi = useApi(errorApiRef); const [owner, repo] = ( - entity?.metadata.annotations?.['backstage.io/github-actions-id'] ?? '/' + entity?.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] ?? '/' ).split('/'); const [{ runs, loading, error }] = useWorkflowRuns({ owner, diff --git a/plugins/github-actions/src/components/Router.tsx b/plugins/github-actions/src/components/Router.tsx index d0745f67d4..7d340fb8b8 100644 --- a/plugins/github-actions/src/components/Router.tsx +++ b/plugins/github-actions/src/components/Router.tsx @@ -22,7 +22,7 @@ import { WorkflowRunsTable } from './WorkflowRunsTable'; import { GITHUB_ACTIONS_ANNOTATION } from './useProjectName'; import { WarningPanel } from '@backstage/core'; -const isPluginApplicableToEntity = (entity: Entity) => +export const isPluginApplicableToEntity = (entity: Entity) => Boolean(entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION]) && entity.metadata.annotations?.[GITHUB_ACTIONS_ANNOTATION] !== ''; @@ -30,8 +30,8 @@ export const Router = ({ entity }: { entity: Entity }) => // TODO(shmidt-i): move warning to a separate standardized component !isPluginApplicableToEntity(entity) ? ( - `entity.metadata.annotations[' - {GITHUB_ACTIONS_ANNOTATION}']` key is missing on the entity.{' '} +
{GITHUB_ACTIONS_ANNOTATION}
annotation is missing on the + entity.
) : ( diff --git a/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx b/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx index d8e3b02524..fd2cc69376 100644 --- a/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx +++ b/plugins/github-actions/src/components/WorkflowRunDetails/WorkflowRunDetails.tsx @@ -13,37 +13,38 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; -import { useWorkflowRunJobs } from './useWorkflowRunJobs'; -import { useProjectName } from '../useProjectName'; -import { - makeStyles, - Box, - TableRow, - TableCell, - ListItemText, - ExpansionPanel, - ExpansionPanelSummary, - Typography, - ExpansionPanelDetails, - TableContainer, - Table, - Paper, - TableBody, - LinearProgress, - CircularProgress, - Theme, - Breadcrumbs, - Link as MaterialLink, -} from '@material-ui/core'; -import { Jobs, Job, Step } from '../../api'; -import moment from 'moment'; -import { WorkflowRunStatus } from '../WorkflowRunStatus'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; -import ExternalLinkIcon from '@material-ui/icons/Launch'; import { Entity } from '@backstage/catalog-model'; import { Link } from '@backstage/core'; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Box, + Breadcrumbs, + CircularProgress, + LinearProgress, + Link as MaterialLink, + ListItemText, + makeStyles, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableRow, + Theme, + Typography, +} from '@material-ui/core'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import ExternalLinkIcon from '@material-ui/icons/Launch'; +import moment from 'moment'; +import React from 'react'; +import { Job, Jobs, Step } from '../../api'; +import { useProjectName } from '../useProjectName'; +import { WorkflowRunStatus } from '../WorkflowRunStatus'; +import { useWorkflowRunJobs } from './useWorkflowRunJobs'; +import { useWorkflowRunsDetails } from './useWorkflowRunsDetails'; +import { WorkflowRunLogs } from '../WorkflowRunLogs'; const useStyles = makeStyles(theme => ({ root: { @@ -56,7 +57,7 @@ const useStyles = makeStyles(theme => ({ table: { padding: theme.spacing(1), }, - expansionPanelDetails: { + accordionDetails: { padding: 0, }, button: { @@ -70,7 +71,7 @@ const useStyles = makeStyles(theme => ({ }, })); -const JobsList = ({ jobs }: { jobs?: Jobs }) => { +const JobsList = ({ jobs, entity }: { jobs?: Jobs; entity: Entity }) => { const classes = useStyles(); return ( @@ -82,6 +83,7 @@ const JobsList = ({ jobs }: { jobs?: Jobs }) => { className={ job.status !== 'success' ? classes.failed : classes.success } + entity={entity} /> ))} @@ -110,14 +112,19 @@ const StepView = ({ step }: { step: Step }) => { ); }; -const JobListItem = ({ job, className }: { job: Job; className: string }) => { +const JobListItem = ({ + job, + className, + entity, +}: { + job: Job; + className: string; + entity: Entity; +}) => { const classes = useStyles(); return ( - - + } aria-controls={`panel-${name}-content`} id={`panel-${name}-header`} @@ -128,8 +135,8 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => { {job.name} ({getElapsedTime(job.started_at, job.completed_at)}) - - + + {job.steps.map((step: Step) => ( @@ -137,8 +144,13 @@ const JobListItem = ({ job, className }: { job: Job; className: string }) => { ))}
-
-
+ + {job.status === 'queued' || job.status === 'in_progress' ? ( + + ) : ( + + )} + ); }; @@ -220,7 +232,7 @@ export const WorkflowRunDetails = ({ entity }: { entity: Entity }) => { {jobs.loading ? ( ) : ( - + )} diff --git a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx new file mode 100644 index 0000000000..390f35d516 --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx @@ -0,0 +1,169 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Accordion, + AccordionSummary, + CircularProgress, + Fade, + LinearProgress, + makeStyles, + Modal, + Theme, + Tooltip, + Typography, + Zoom, +} from '@material-ui/core'; + +import React, { Suspense } from 'react'; +import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs'; +import LinePart from 'react-lazylog/build/LinePart'; +import { useProjectName } from '../useProjectName'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import DescriptionIcon from '@material-ui/icons/Description'; +import { Entity } from '@backstage/catalog-model'; + +const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); + +const useStyles = makeStyles(() => ({ + button: { + order: -1, + marginRight: 0, + marginLeft: '-20px', + }, + modal: { + display: 'flex', + alignItems: 'center', + width: '85%', + height: '85%', + justifyContent: 'center', + margin: 'auto', + }, + normalLog: { + height: '75vh', + width: '100%', + }, + modalLog: { + height: '100%', + width: '100%', + }, +})); + +const DisplayLog = ({ + jobLogs, + className, +}: { + jobLogs: any; + className: string; +}) => { + return ( + }> +
+ { + if ( + line.toLocaleLowerCase().includes('error') || + line.toLocaleLowerCase().includes('failed') || + line.toLocaleLowerCase().includes('failure') + ) { + return ( + + ); + } + return line; + }} + /> +
+
+ ); +}; + +/** + * A component for Run Logs visualization. + */ +export const WorkflowRunLogs = ({ + entity, + runId, + inProgress, +}: { + entity: Entity; + runId: string; + inProgress: boolean; +}) => { + const classes = useStyles(); + const projectName = useProjectName(entity); + + const [owner, repo] = projectName.value ? projectName.value.split('/') : []; + const jobLogs = useDownloadWorkflowRunLogs(repo, owner, runId); + const [open, setOpen] = React.useState(false); + + const handleOpen = () => { + setOpen(true); + }; + + const handleClose = () => { + setOpen(false); + }; + + return ( + + } + aria-controls={`panel-${name}-content`} + id={`panel-${name}-header`} + IconButtonProps={{ + className: classes.button, + }} + > + + {jobLogs.loading ? : 'Job Log'} + + + { + event.stopPropagation(); + handleOpen(); + }} + style={{ marginLeft: 'auto' }} + /> + + event.stopPropagation()} + open={open} + onClose={handleClose} + > + + + + + + {jobLogs.value && ( + + )} + + ); +}; diff --git a/plugins/github-actions/src/components/WorkflowRunLogs/index.ts b/plugins/github-actions/src/components/WorkflowRunLogs/index.ts new file mode 100644 index 0000000000..0fcffd4dec --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunLogs/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { WorkflowRunLogs } from './WorkflowRunLogs'; diff --git a/plugins/github-actions/src/components/WorkflowRunLogs/useDownloadWorkflowRunLogs.ts b/plugins/github-actions/src/components/WorkflowRunLogs/useDownloadWorkflowRunLogs.ts new file mode 100644 index 0000000000..734f617b1f --- /dev/null +++ b/plugins/github-actions/src/components/WorkflowRunLogs/useDownloadWorkflowRunLogs.ts @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useApi, githubAuthApiRef } from '@backstage/core'; +import { useAsync } from 'react-use'; +import { githubActionsApiRef } from '../../api'; + +export const useDownloadWorkflowRunLogs = ( + repo: string, + owner: string, + id: string, +) => { + const api = useApi(githubActionsApiRef); + const auth = useApi(githubAuthApiRef); + const details = useAsync(async () => { + const token = await auth.getAccessToken(['repo']); + return repo && owner + ? api.downloadJobLogsForWorkflowRun({ + token, + owner, + repo, + runId: parseInt(id, 10), + }) + : Promise.reject('No repo/owner provided'); + }, [repo, owner, id]); + return details; +}; diff --git a/plugins/github-actions/src/index.ts b/plugins/github-actions/src/index.ts index 17c1fa2dd7..24fe6fc90d 100644 --- a/plugins/github-actions/src/index.ts +++ b/plugins/github-actions/src/index.ts @@ -16,6 +16,6 @@ export { plugin } from './plugin'; export * from './api'; -export { Router } from './components/Router'; +export { Router, isPluginApplicableToEntity } from './components/Router'; export * from './components/Cards'; export { GITHUB_ACTIONS_ANNOTATION } from './components/useProjectName'; diff --git a/plugins/github-actions/src/plugin.ts b/plugins/github-actions/src/plugin.ts index 7e08229d6d..9e3c965d46 100644 --- a/plugins/github-actions/src/plugin.ts +++ b/plugins/github-actions/src/plugin.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { createPlugin, createRouteRef } from '@backstage/core'; +import { + createPlugin, + createRouteRef, + createApiFactory, +} from '@backstage/core'; +import { githubActionsApiRef, GithubActionsClient } from './api'; // TODO(freben): This is just a demo route for now export const rootRouteRef = createRouteRef({ @@ -29,4 +34,5 @@ export const buildRouteRef = createRouteRef({ export const plugin = createPlugin({ id: 'github-actions', + apis: [createApiFactory(githubActionsApiRef, new GithubActionsClient())], }); diff --git a/plugins/gitops-profiles/package.json b/plugins/gitops-profiles/package.json index dc32a4df14..62dacb5e91 100644 --- a/plugins/gitops-profiles/package.json +++ b/plugins/gitops-profiles/package.json @@ -23,7 +23,7 @@ "dependencies": { "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "react": "^16.13.1", diff --git a/plugins/gitops-profiles/src/plugin.ts b/plugins/gitops-profiles/src/plugin.ts index af180aff20..45820644f7 100644 --- a/plugins/gitops-profiles/src/plugin.ts +++ b/plugins/gitops-profiles/src/plugin.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createPlugin } from '@backstage/core'; +import { createPlugin, createApiFactory } from '@backstage/core'; import ProfileCatalog from './components/ProfileCatalog'; import ClusterPage from './components/ClusterPage'; import ClusterList from './components/ClusterList'; @@ -23,9 +23,13 @@ import { gitOpsClusterDetailsRoute, gitOpsClusterCreateRoute, } from './routes'; +import { gitOpsApiRef, GitOpsRestApi } from './api'; export const plugin = createPlugin({ id: 'gitops-profiles', + apis: [ + createApiFactory(gitOpsApiRef, new GitOpsRestApi('http://localhost:3008')), + ], register({ router }) { router.addRoute(gitOpsClusterListRoute, ClusterList); router.addRoute(gitOpsClusterDetailsRoute, ClusterPage); diff --git a/plugins/graphiql/dev/index.tsx b/plugins/graphiql/dev/index.tsx index efcf19a89d..b93995a5dc 100644 --- a/plugins/graphiql/dev/index.tsx +++ b/plugins/graphiql/dev/index.tsx @@ -20,8 +20,8 @@ import { plugin, GraphQLEndpoints, graphQlBrowseApiRef } from '../src'; createDevApp() .registerPlugin(plugin) - .registerApiFactory({ - implements: graphQlBrowseApiRef, + .registerApi({ + api: graphQlBrowseApiRef, deps: { errorApi: errorApiRef, githubAuthApi: githubAuthApiRef, diff --git a/plugins/graphiql/package.json b/plugins/graphiql/package.json index cc1a0a7204..b4d0b685da 100644 --- a/plugins/graphiql/package.json +++ b/plugins/graphiql/package.json @@ -33,7 +33,7 @@ "dependencies": { "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "graphiql": "^1.0.0-alpha.10", diff --git a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx index b41fc04b9e..ce56017984 100644 --- a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx +++ b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx @@ -24,7 +24,7 @@ import { BackstageTheme } from '@backstage/theme'; const GraphiQL = React.lazy(() => import('graphiql')); -const useStyles = makeStyles((theme) => ({ +const useStyles = makeStyles(theme => ({ root: { height: '100%', display: 'flex', diff --git a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx index a16fdf3ee6..7eb91b59d8 100644 --- a/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx +++ b/plugins/graphiql/src/components/GraphiQLPage/GraphiQLPage.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React, { FC } from 'react'; +import React from 'react'; import { Content, Header, @@ -30,7 +30,7 @@ import { graphQlBrowseApiRef } from '../../lib/api'; import { GraphiQLBrowser } from '../GraphiQLBrowser'; import { Typography } from '@material-ui/core'; -export const GraphiQLPage: FC<{}> = () => { +export const GraphiQLPage = () => { const graphQlBrowseApi = useApi(graphQlBrowseApiRef); const endpoints = useAsync(() => graphQlBrowseApi.getEndpoints()); diff --git a/plugins/graphiql/src/index.ts b/plugins/graphiql/src/index.ts index e7614aba81..50698cdb4c 100644 --- a/plugins/graphiql/src/index.ts +++ b/plugins/graphiql/src/index.ts @@ -15,5 +15,6 @@ */ export { plugin } from './plugin'; +export { GraphiQLPage as Router } from './components'; export * from './lib/api'; export * from './route-refs'; diff --git a/plugins/graphiql/src/plugin.ts b/plugins/graphiql/src/plugin.ts index f118faf871..28d27802d0 100644 --- a/plugins/graphiql/src/plugin.ts +++ b/plugins/graphiql/src/plugin.ts @@ -14,13 +14,22 @@ * limitations under the License. */ -import { createPlugin } from '@backstage/core'; -import { GraphiQLPage } from './components'; -import { graphiQLRouteRef } from './route-refs'; +import { createPlugin, createApiFactory } from '@backstage/core'; +import { graphQlBrowseApiRef, GraphQLEndpoints } from './lib/api'; export const plugin = createPlugin({ id: 'graphiql', - register({ router }) { - router.addRoute(graphiQLRouteRef, GraphiQLPage); - }, + apis: [ + // GitLab is used as an example endpoint, but most plug + createApiFactory( + graphQlBrowseApiRef, + GraphQLEndpoints.from([ + GraphQLEndpoints.create({ + id: 'gitlab', + title: 'GitLab', + url: 'https://gitlab.com/api/graphql', + }), + ]), + ), + ], }); diff --git a/plugins/graphql/package.json b/plugins/graphql/package.json index 1612398ea9..706592c430 100644 --- a/plugins/graphql/package.json +++ b/plugins/graphql/package.json @@ -16,8 +16,7 @@ "test": "backstage-cli test", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", - "mock-data": "./scripts/mock-data.sh" + "clean": "backstage-cli clean" }, "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.21", diff --git a/plugins/graphql/scripts/mock-data.sh b/plugins/graphql/scripts/mock-data.sh deleted file mode 100755 index ff30921715..0000000000 --- a/plugins/graphql/scripts/mock-data.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -echo "use this script to load your service with some mock data if needed!" diff --git a/plugins/jenkins/package.json b/plugins/jenkins/package.json index da1754749f..0d532f8c45 100644 --- a/plugins/jenkins/package.json +++ b/plugins/jenkins/package.json @@ -24,7 +24,7 @@ "@backstage/catalog-model": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "jenkins": "^0.28.0", diff --git a/plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx b/plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx index 1143121a98..0dcaeb8948 100644 --- a/plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx +++ b/plugins/jenkins/src/pages/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx @@ -13,18 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useEffect, FC } from 'react'; + import { - ExpansionPanel, - ExpansionPanelSummary, + Accordion, + AccordionDetails, + AccordionSummary, Typography, - ExpansionPanelDetails, } from '@material-ui/core'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import { makeStyles } from '@material-ui/core/styles'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import React, { FC, useEffect } from 'react'; const useStyles = makeStyles({ - expansionPanelDetails: { + accordionDetails: { padding: 0, }, button: { @@ -45,11 +46,8 @@ export const ActionOutput: FC<{ useEffect(() => {}, [url]); return ( - - + } aria-controls={`panel-${name}-content`} id={`panel-${name}-header`} @@ -58,10 +56,10 @@ export const ActionOutput: FC<{ }} > {name} - - + + Nothing here... - - + + ); }; diff --git a/plugins/jenkins/src/plugin.ts b/plugins/jenkins/src/plugin.ts index 979b0a31cf..4d1af322c4 100644 --- a/plugins/jenkins/src/plugin.ts +++ b/plugins/jenkins/src/plugin.ts @@ -14,8 +14,14 @@ * limitations under the License. */ -import { createPlugin, createRouteRef } from '@backstage/core'; +import { + createPlugin, + createRouteRef, + createApiFactory, + configApiRef, +} from '@backstage/core'; import { DetailedViewPage } from './pages/BuildWithStepsPage'; +import { jenkinsApiRef, JenkinsApi } from './api'; export const buildRouteRef = createRouteRef({ path: '/jenkins/job', @@ -24,6 +30,16 @@ export const buildRouteRef = createRouteRef({ export const plugin = createPlugin({ id: 'jenkins', + apis: [ + createApiFactory({ + api: jenkinsApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => + new JenkinsApi( + `${configApi.getString('backend.baseUrl')}/proxy/jenkins/api`, + ), + }), + ], register({ router }) { router.addRoute(buildRouteRef, DetailedViewPage); }, diff --git a/plugins/lighthouse/dev/index.tsx b/plugins/lighthouse/dev/index.tsx index 6496fb658a..bf761965f1 100644 --- a/plugins/lighthouse/dev/index.tsx +++ b/plugins/lighthouse/dev/index.tsx @@ -20,8 +20,8 @@ import { lighthouseApiRef, LighthouseRestApi } from '../src'; createDevApp() .registerPlugin(plugin) - .registerApiFactory({ - implements: lighthouseApiRef, + .registerApi({ + api: lighthouseApiRef, deps: {}, factory: () => new LighthouseRestApi('http://localhost:3003'), }) diff --git a/plugins/lighthouse/package.json b/plugins/lighthouse/package.json index 647215f7f8..24a106e53d 100644 --- a/plugins/lighthouse/package.json +++ b/plugins/lighthouse/package.json @@ -24,7 +24,7 @@ "@backstage/config": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "react": "^16.13.1", diff --git a/plugins/lighthouse/src/Router.tsx b/plugins/lighthouse/src/Router.tsx new file mode 100644 index 0000000000..46843504fd --- /dev/null +++ b/plugins/lighthouse/src/Router.tsx @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Routes, Route } from 'react-router-dom'; +import { rootRouteRef, viewAuditRouteRef, createAuditRouteRef } from './plugin'; +import AuditList from './components/AuditList'; +import AuditView from './components/AuditView'; +import CreateAudit from './components/CreateAudit'; + +export const Router = () => ( + + } /> + } /> + } /> + +); diff --git a/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx b/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx index 039b397083..e67f939ba1 100644 --- a/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx +++ b/plugins/lighthouse/src/components/AuditList/AuditListTable.test.tsx @@ -58,10 +58,7 @@ describe('AuditListTable', () => { if (!website) throw new Error('https://anchor.fm must be present in fixture'); expect(link).toBeInTheDocument(); - expect(link).toHaveAttribute( - 'href', - `/lighthouse/audit/${website.lastAudit.id}`, - ); + expect(link).toHaveAttribute('href', `/audit/${website.lastAudit.id}`); }); it('renders the dates that are available for a given row', () => { diff --git a/plugins/lighthouse/src/components/AuditList/AuditListTable.tsx b/plugins/lighthouse/src/components/AuditList/AuditListTable.tsx index 20dd1f39f8..332dd5e3ca 100644 --- a/plugins/lighthouse/src/components/AuditList/AuditListTable.tsx +++ b/plugins/lighthouse/src/components/AuditList/AuditListTable.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { FC, useState } from 'react'; +import React, { FC, useState, useEffect } from 'react'; import { Table, TableColumn, TrendLine, useApi } from '@backstage/core'; import { Website, lighthouseApiRef } from '../../api'; import { useInterval } from 'react-use'; @@ -23,15 +23,16 @@ import { CATEGORY_LABELS, buildSparklinesDataForItem, } from '../../utils'; -import { Link } from '@material-ui/core'; +import { Link, generatePath } from 'react-router-dom'; import AuditStatusIcon from '../AuditStatusIcon'; +import { viewAuditRouteRef } from '../../plugin'; const columns: TableColumn[] = [ { title: 'Website URL', field: 'websiteUrl', }, - ...CATEGORIES.map((category) => ({ + ...CATEGORIES.map(category => ({ title: CATEGORY_LABELS[category], field: category, })), @@ -55,8 +56,12 @@ export const AuditListTable: FC<{ items: Website[] }> = ({ items }) => { const [websiteState, setWebsiteState] = useState(items); const lighthouseApi = useApi(lighthouseApiRef); + useEffect(() => { + setWebsiteState(items); + }, [items]); + const runRefresh = (websites: Website[]) => { - websites.forEach(async (website) => { + websites.forEach(async website => { const response = await lighthouseApi.getWebsiteForAuditId( website.lastAudit.id, ); @@ -64,7 +69,7 @@ export const AuditListTable: FC<{ items: Website[] }> = ({ items }) => { if (auditStatus === 'COMPLETED' || auditStatus === 'FAILED') { const newWebsiteData = websiteState.slice(0); newWebsiteData[ - newWebsiteData.findIndex((w) => w.url === response.url) + newWebsiteData.findIndex(w => w.url === response.url) ] = response; setWebsiteState(newWebsiteData); } @@ -72,7 +77,7 @@ export const AuditListTable: FC<{ items: Website[] }> = ({ items }) => { }; const runningWebsiteAudits = websiteState - ? websiteState.filter((website) => website.lastAudit.status === 'RUNNING') + ? websiteState.filter(website => website.lastAudit.status === 'RUNNING') : []; useInterval( @@ -80,10 +85,10 @@ export const AuditListTable: FC<{ items: Website[] }> = ({ items }) => { runningWebsiteAudits.length > 0 ? 5000 : null, ); - const data = websiteState.map((website) => { + const data = websiteState.map(website => { const trendlineData = buildSparklinesDataForItem(website); const trendlines: any = {}; - CATEGORIES.forEach((category) => { + CATEGORIES.forEach(category => { trendlines[category] = ( = ({ items }) => { return { websiteUrl: ( - + {website.url} ), diff --git a/plugins/lighthouse/src/components/AuditList/index.test.tsx b/plugins/lighthouse/src/components/AuditList/index.test.tsx index 076bb5819a..34fd760801 100644 --- a/plugins/lighthouse/src/components/AuditList/index.test.tsx +++ b/plugins/lighthouse/src/components/AuditList/index.test.tsx @@ -63,7 +63,7 @@ describe('AuditList', () => { expect(element).toBeInTheDocument(); }); - it('renders a link to create a new audit', async () => { + it('renders a button to create a new audit', async () => { const rendered = render( wrapInTestApp( @@ -71,12 +71,8 @@ describe('AuditList', () => { , ), ); - const element = await rendered.findByText('Create Audit'); - expect(element).toBeInTheDocument(); - expect(element.parentElement).toHaveAttribute( - 'href', - '/lighthouse/create-audit', - ); + const button = await rendered.findByText('Create Audit'); + expect(button).toBeInTheDocument(); }); describe('pagination', () => { @@ -87,7 +83,7 @@ describe('AuditList', () => { , - { routeEntries: ['/lighthouse?page=2'] }, + { routeEntries: ['?page=2'] }, ), ); expect(mockFetch).toHaveBeenLastCalledWith( @@ -137,13 +133,13 @@ describe('AuditList', () => { , - { routeEntries: ['/lighthouse?page=2'] }, + { routeEntries: ['?page=2'] }, ), ); const element = await rendered.findByLabelText(/Go to page 1/); fireEvent.click(element); - expect(useNavigate()).toHaveBeenCalledWith(`/lighthouse?page=1`); + expect(useNavigate()).toHaveBeenCalledWith(`?page=1`); }); }); }); diff --git a/plugins/lighthouse/src/components/AuditList/index.tsx b/plugins/lighthouse/src/components/AuditList/index.tsx index c83ce9f641..a75bb25a0d 100644 --- a/plugins/lighthouse/src/components/AuditList/index.tsx +++ b/plugins/lighthouse/src/components/AuditList/index.tsx @@ -37,6 +37,7 @@ import { useQuery } from '../../utils'; import LighthouseSupportButton from '../SupportButton'; import LighthouseIntro, { LIGHTHOUSE_INTRO_LOCAL_STORAGE } from '../Intro'; import AuditListTable from './AuditListTable'; +import { createAuditRouteRef } from '../../plugin'; export const LIMIT = 10; @@ -77,7 +78,7 @@ const AuditList: FC<{}> = () => { page={page} count={pageCount} onChange={(_event: Event, newPage: number) => { - navigate(`/lighthouse?page=${newPage}`); + navigate(`?page=${newPage}`); }} /> )} @@ -111,7 +112,7 @@ const AuditList: FC<{}> = () => { diff --git a/plugins/lighthouse/src/components/AuditView/index.test.tsx b/plugins/lighthouse/src/components/AuditView/index.test.tsx index b2c15cd8b7..742be67fed 100644 --- a/plugins/lighthouse/src/components/AuditView/index.test.tsx +++ b/plugins/lighthouse/src/components/AuditView/index.test.tsx @@ -18,15 +18,17 @@ jest.mock('react-router-dom', () => { const actual = jest.requireActual('react-router-dom'); + const mockNavigation = jest.fn(); return { ...actual, useParams: jest.fn(() => ({})), + useNavigate: jest.fn(() => mockNavigation), }; }); import React from 'react'; import mockFetch from 'jest-fetch-mock'; -import { render } from '@testing-library/react'; +import { render, fireEvent } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; import { ApiRegistry, ApiProvider } from '@backstage/core'; @@ -34,11 +36,13 @@ import AuditView from '.'; import { lighthouseApiRef, LighthouseRestApi, Audit, Website } from '../../api'; import { formatTime } from '../../utils'; import * as data from '../../__fixtures__/website-response.json'; +import { act } from 'react-dom/test-utils'; const { useParams }: { useParams: jest.Mock } = jest.requireMock( 'react-router-dom', ); const websiteResponse = data as Website; +const { useNavigate } = jest.requireMock('react-router-dom'); describe('AuditView', () => { let apis: ApiRegistry; @@ -70,7 +74,7 @@ describe('AuditView', () => { expect(iframe).toHaveAttribute('src', `https://lighthouse/v1/audits/${id}`); }); - it('renders a link to create a new audit for this website', async () => { + it('renders a button to click to create a new audit for this website', async () => { const rendered = render( wrapInTestApp( @@ -79,13 +83,15 @@ describe('AuditView', () => { ), ); - const button = await rendered.findByText('Create Audit'); + const button = await rendered.findByText('Create New Audit'); expect(button).toBeInTheDocument(); - expect(button.parentElement).toHaveAttribute( - 'href', - `/lighthouse/create-audit?url=${encodeURIComponent( - 'https://spotify.com', - )}`, + + act(() => { + fireEvent.click(button); + }); + + expect(useNavigate()).toHaveBeenCalledWith( + `../../create-audit?url=${encodeURIComponent('https://spotify.com')}`, ); }); @@ -151,7 +157,7 @@ describe('AuditView', () => { expect( rendered.getByText(formatTime(a.timeCreated)).parentElement ?.parentElement, - ).toHaveAttribute('href', `/lighthouse/audit/${a.id}`); + ).toHaveAttribute('href', `/audit/${a.id}`); }); }); }); diff --git a/plugins/lighthouse/src/components/AuditView/index.tsx b/plugins/lighthouse/src/components/AuditView/index.tsx index 12606482bf..d0e743a77f 100644 --- a/plugins/lighthouse/src/components/AuditView/index.tsx +++ b/plugins/lighthouse/src/components/AuditView/index.tsx @@ -14,7 +14,13 @@ * limitations under the License. */ import React, { useState, useEffect, ReactNode, FC } from 'react'; -import { Link, useParams } from 'react-router-dom'; +import { + Link, + useParams, + useNavigate, + generatePath, + resolvePath, +} from 'react-router-dom'; import { useAsync } from 'react-use'; import { makeStyles, @@ -42,6 +48,7 @@ import { lighthouseApiRef, Website, Audit } from '../../api'; import AuditStatusIcon from '../AuditStatusIcon'; import LighthouseSupportButton from '../SupportButton'; import { formatTime } from '../../utils'; +import { viewAuditRouteRef, createAuditRouteRef } from '../../plugin'; const useStyles = makeStyles({ contentGrid: { @@ -75,7 +82,12 @@ const AuditLinkList: FC = ({ button component={Link} replace - to={`/lighthouse/audit/${audit.id}`} + to={resolvePath( + generatePath(viewAuditRouteRef.path, { + id: audit.id, + }), + '../../', + )} > @@ -116,6 +128,7 @@ const ConnectedAuditView: FC<{}> = () => { const lighthouseApi = useApi(lighthouseApiRef); const params = useParams() as { id: string }; const classes = useStyles(); + const navigate = useNavigate(); const { loading, error, value: nextValue } = useAsync( async () => await lighthouseApi.getWebsiteForAuditId(params.id), @@ -154,7 +167,7 @@ const ConnectedAuditView: FC<{}> = () => { ); } - let createAuditButtonUrl = '/lighthouse/create-audit'; + let createAuditButtonUrl = createAuditRouteRef.path; if (value?.url) { createAuditButtonUrl += `?url=${encodeURIComponent(value.url)}`; } @@ -176,9 +189,9 @@ const ConnectedAuditView: FC<{}> = () => { diff --git a/plugins/lighthouse/src/components/CreateAudit/index.test.tsx b/plugins/lighthouse/src/components/CreateAudit/index.test.tsx index aaf376923f..b2348bf5ff 100644 --- a/plugins/lighthouse/src/components/CreateAudit/index.test.tsx +++ b/plugins/lighthouse/src/components/CreateAudit/index.test.tsx @@ -78,9 +78,7 @@ describe('CreateAudit', () => { , { - routeEntries: [ - `/lighthouse/create-audit?url=${encodeURIComponent(url)}`, - ], + routeEntries: [`/create-audit?url=${encodeURIComponent(url)}`], }, ), ); @@ -137,7 +135,7 @@ describe('CreateAudit', () => { await wait(() => expect(rendered.getByLabelText(/URL/)).toBeEnabled()); - expect(useNavigate()).toHaveBeenCalledWith('/lighthouse'); + expect(useNavigate()).toHaveBeenCalledWith('..'); }); }); diff --git a/plugins/lighthouse/src/components/CreateAudit/index.tsx b/plugins/lighthouse/src/components/CreateAudit/index.tsx index a699e148c8..36bd97485a 100644 --- a/plugins/lighthouse/src/components/CreateAudit/index.tsx +++ b/plugins/lighthouse/src/components/CreateAudit/index.tsx @@ -78,7 +78,7 @@ const CreateAudit: FC<{}> = () => { }, }, }); - navigate('/lighthouse'); + navigate('..'); } catch (err) { errorApi.post(err); } finally { @@ -154,7 +154,7 @@ const CreateAudit: FC<{}> = () => { diff --git a/plugins/circleci/src/components/Layout/Layout.tsx b/plugins/register-component/src/components/Router.tsx similarity index 57% rename from plugins/circleci/src/components/Layout/Layout.tsx rename to plugins/register-component/src/components/Router.tsx index 09479e6ef0..eee7fd3806 100644 --- a/plugins/circleci/src/components/Layout/Layout.tsx +++ b/plugins/register-component/src/components/Router.tsx @@ -14,16 +14,16 @@ * limitations under the License. */ import React from 'react'; -import { Header, Page, pageTheme, HeaderLabel } from '@backstage/core'; +import { Route, Routes } from 'react-router'; +import { RegisterComponentPage } from './RegisterComponentPage'; +import { RouteRef } from '@backstage/core'; -export const Layout: React.FC = ({ children }) => { - return ( - -
- - -
- {children} -
- ); -}; +// As we don't know which path the catalog's router mounted on +// We need to inject this from the app +export const Router = ({ catalogRouteRef }: { catalogRouteRef: RouteRef }) => ( + + } + /> + +); diff --git a/plugins/register-component/src/index.ts b/plugins/register-component/src/index.ts index 5b20cb0158..ff7857cacd 100644 --- a/plugins/register-component/src/index.ts +++ b/plugins/register-component/src/index.ts @@ -14,4 +14,5 @@ * limitations under the License. */ -export { plugin, rootRoute } from './plugin'; +export { plugin } from './plugin'; +export { Router } from './components/Router'; diff --git a/plugins/register-component/src/plugin.ts b/plugins/register-component/src/plugin.ts index 9c73688a70..17f99917c8 100644 --- a/plugins/register-component/src/plugin.ts +++ b/plugins/register-component/src/plugin.ts @@ -14,18 +14,8 @@ * limitations under the License. */ -import { createPlugin, createRouteRef } from '@backstage/core'; -import RegisterComponentPage from './components/RegisterComponentPage'; - -export const rootRoute = createRouteRef({ - icon: () => null, - path: '/register-component', - title: 'Register component', -}); +import { createPlugin } from '@backstage/core'; export const plugin = createPlugin({ id: 'register-component', - register({ router }) { - router.addRoute(rootRoute, RegisterComponentPage); - }, }); diff --git a/plugins/rollbar/README.md b/plugins/rollbar/README.md index 94ef38b43a..b2d2100dd9 100644 --- a/plugins/rollbar/README.md +++ b/plugins/rollbar/README.md @@ -26,25 +26,57 @@ export { plugin as Rollbar } from '@backstage/plugin-rollbar'; import { RollbarClient, rollbarApiRef } from '@backstage/plugin-rollbar'; // ... - -builder.add( - rollbarApiRef, - new RollbarClient({ - apiOrigin: backendUrl, - basePath: '/rollbar', - }), -); - -// Alternatively you can use the mock client -// builder.add(rollbarApiRef, new RollbarMockClient()); +builder.add(rollbarApiRef, new RollbarClient({ discoveryApi })); ``` -5. Run app with `yarn start` and navigate to `/rollbar` +5. Add to the app `EntityPage` component: + +```ts +// packages/app/src/components/catalog/EntityPage.tsx +import { Router as RollbarRouter } from '@backstage/plugin-rollbar'; + +// ... +const ServiceEntityPage = ({ entity }: { entity: Entity }) => ( + + // ... + } + /> + +); +``` + +6. Setup the `app.config.yaml` and account token environment variable + +```yaml +# app.config.yaml +rollbar: + organization: spotify + accountToken: + $secret: + env: ROLLBAR_ACCOUNT_TOKEN +``` + +7. Annotate entities with the rollbar project slug + +```yaml +# pump-station-catalog-component.yaml +# ... +metadata: + annotations: + rollbar.com/project-slug: organization-name/project-name + # -- or just --- + rollbar.com/project-slug: project-name +``` + +8. Run app with `yarn start` and navigate to `/rollbar` or a catalog entity ## Features -- List rollbar projects -- View top active items for each project +- List rollbar entities that are annotated with `rollbar.com/project-slug` +- View top active items for each rollbar annotated entity ## Limitations diff --git a/plugins/rollbar/package.json b/plugins/rollbar/package.json index 9c5343247c..ae9d0c5bc5 100644 --- a/plugins/rollbar/package.json +++ b/plugins/rollbar/package.json @@ -21,9 +21,11 @@ "clean": "backstage-cli clean" }, "dependencies": { + "@backstage/catalog-model": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", + "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "lodash": "^4.17.15", diff --git a/plugins/rollbar/src/api/RollbarApi.ts b/plugins/rollbar/src/api/RollbarApi.ts index c08bc08d48..bde6c5e9f2 100644 --- a/plugins/rollbar/src/api/RollbarApi.ts +++ b/plugins/rollbar/src/api/RollbarApi.ts @@ -29,6 +29,7 @@ export const rollbarApiRef = createApiRef({ export interface RollbarApi { getAllProjects(): Promise; + getProject(projectName: string): Promise; getTopActiveItems( project: string, hours?: number, diff --git a/plugins/rollbar/src/api/RollbarClient.ts b/plugins/rollbar/src/api/RollbarClient.ts index 1862ad8270..e612890655 100644 --- a/plugins/rollbar/src/api/RollbarClient.ts +++ b/plugins/rollbar/src/api/RollbarClient.ts @@ -30,9 +30,11 @@ export class RollbarClient implements RollbarApi { } async getAllProjects(): Promise { - const path = `/projects`; + return await this.get(`/projects`); + } - return await this.get(path); + async getProject(projectName: string): Promise { + return await this.get(`/projects/${projectName}`); } async getTopActiveItems( @@ -40,15 +42,13 @@ export class RollbarClient implements RollbarApi { hours = 24, environment = 'production', ): Promise { - const path = `/projects/${project}/top_active_items?environment=${environment}&hours=${hours}`; - - return await this.get(path); + return await this.get( + `/projects/${project}/top_active_items?environment=${environment}&hours=${hours}`, + ); } async getProjectItems(project: string): Promise { - const path = `/projects/${project}/items`; - - return await this.get(path); + return await this.get(`/projects/${project}/items`); } private async get(path: string): Promise { diff --git a/plugins/rollbar/src/api/RollbarMockClient.ts b/plugins/rollbar/src/api/RollbarMockClient.ts deleted file mode 100644 index cab9a0d23a..0000000000 --- a/plugins/rollbar/src/api/RollbarMockClient.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* eslint-disable @typescript-eslint/no-unused-vars */ - -import { RollbarApi } from './RollbarApi'; -import { - RollbarItemsResponse, - RollbarProject, - RollbarTopActiveItem, -} from './types'; - -export class RollbarMockClient implements RollbarApi { - async getAllProjects(): Promise { - return Promise.resolve([ - { id: 123, name: 'project-a', accountId: 1, status: 'enabled' }, - { id: 356, name: 'project-b', accountId: 1, status: 'enabled' }, - { id: 789, name: 'project-c', accountId: 1, status: 'enabled' }, - ]); - } - - async getTopActiveItems( - _project: string, - _hours = 24, - _environment = 'production', - ): Promise { - const createItem = (id: number): RollbarTopActiveItem => ({ - item: { - id, - counter: id, - environment: 'production', - framework: 2, - lastOccurrenceTimestamp: new Date().getTime() / 1000, - level: 50, - occurrences: 100, - projectId: 12345, - title: `Some error occurred in service - ${id}`, - uniqueOccurrences: 10, - }, - counts: Array.from({ length: 168 }, () => - Math.floor(Math.random() * 100), - ), - }); - - const items = Array.from({ length: 10 }, (_, i) => createItem(i)); - - return Promise.resolve(items); - } - - async getProjectItems(_project: string): Promise { - return Promise.resolve({ - items: [], - page: 0, - totalCount: 0, - }); - } -} diff --git a/plugins/rollbar/src/api/index.ts b/plugins/rollbar/src/api/index.ts new file mode 100644 index 0000000000..f45ff5bf8a --- /dev/null +++ b/plugins/rollbar/src/api/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './RollbarApi'; +export * from './RollbarClient'; diff --git a/packages/core-api/src/apis/implementations/auth/google/types.ts b/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx similarity index 67% rename from packages/core-api/src/apis/implementations/auth/google/types.ts rename to plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx index 3b40932980..888b9aabe0 100644 --- a/packages/core-api/src/apis/implementations/auth/google/types.ts +++ b/plugins/rollbar/src/components/EntityPageRollbar/EntityPageRollbar.tsx @@ -14,15 +14,14 @@ * limitations under the License. */ -import { ProfileInfo, BackstageIdentity } from '../../../definitions'; +import React from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { RollbarProject } from '../RollbarProject/RollbarProject'; -export type GoogleSession = { - providerInfo: { - idToken: string; - accessToken: string; - scopes: Set; - expiresAt: Date; - }; - profile: ProfileInfo; - backstageIdentity: BackstageIdentity; +type Props = { + entity: Entity; +}; + +export const EntityPageRollbar = ({ entity }: Props) => { + return ; }; diff --git a/plugins/rollbar/src/components/RollbarPage/RollbarPage.test.tsx b/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx similarity index 80% rename from plugins/rollbar/src/components/RollbarPage/RollbarPage.test.tsx rename to plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx index 11263ed820..c6ee052c0e 100644 --- a/plugins/rollbar/src/components/RollbarPage/RollbarPage.test.tsx +++ b/plugins/rollbar/src/components/RollbarHome/RollbarHome.test.tsx @@ -21,13 +21,14 @@ import { ConfigApi, configApiRef, } from '@backstage/core'; +import { catalogApiRef, CatalogApi } from '@backstage/plugin-catalog'; import { wrapInTestApp } from '@backstage/test-utils'; import { render } from '@testing-library/react'; import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi'; import { RollbarProject } from '../../api/types'; -import { RollbarPage } from './RollbarPage'; +import { RollbarHome } from './RollbarHome'; -describe('RollbarPage component', () => { +describe('RollbarHome component', () => { const projects: RollbarProject[] = [ { id: 123, name: 'abc', accountId: 1, status: 'enabled' }, { id: 456, name: 'xyz', accountId: 1, status: 'enabled' }, @@ -47,6 +48,14 @@ describe('RollbarPage component', () => { apis={ApiRegistry.from([ [rollbarApiRef, rollbarApi], [configApiRef, config], + [ + catalogApiRef, + ({ + async getEntities() { + return []; + }, + } as Partial) as CatalogApi, + ], ])} > {children} @@ -55,7 +64,7 @@ describe('RollbarPage component', () => { ); it('should render rollbar landing page', async () => { - const rendered = renderWrapped(); + const rendered = renderWrapped(); expect(rendered.getByText(/Rollbar/)).toBeInTheDocument(); }); }); diff --git a/plugins/rollbar/src/components/RollbarLayout/RollbarLayout.tsx b/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx similarity index 51% rename from plugins/rollbar/src/components/RollbarLayout/RollbarLayout.tsx rename to plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx index c0524fabc5..d09c2054b1 100644 --- a/plugins/rollbar/src/components/RollbarLayout/RollbarLayout.tsx +++ b/plugins/rollbar/src/components/RollbarHome/RollbarHome.tsx @@ -14,42 +14,26 @@ * limitations under the License. */ -import React, { ReactNode } from 'react'; -import { - Header, - HeaderLabel, - Page, - pageTheme, - Content, - ContentHeader, - SupportButton, -} from '@backstage/core'; -import { Grid } from '@material-ui/core'; +import React from 'react'; +import { Content, Header, Page, pageTheme } from '@backstage/core'; +import { RollbarProjectTable } from '../RollbarProjectTable/RollbarProjectTable'; +import { useRollbarEntities } from '../../hooks/useRollbarEntities'; -type Props = { - title?: string; - children: ReactNode; -}; +export const RollbarHome = () => { + const { entities, loading, error } = useRollbarEntities(); -export const RollbarLayout = ({ title = 'Dashboard', children }: Props) => { return (
- - -
+ /> - - - Rollbar plugin allows you to preview issues and navigate to rollbar. - - - - {children} - +
); diff --git a/plugins/catalog/src/components/EntityPageCi/EntityPageCi.tsx b/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx similarity index 52% rename from plugins/catalog/src/components/EntityPageCi/EntityPageCi.tsx rename to plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx index 3261764d11..34881ba560 100644 --- a/plugins/catalog/src/components/EntityPageCi/EntityPageCi.tsx +++ b/plugins/rollbar/src/components/RollbarProject/RollbarProject.tsx @@ -14,23 +14,27 @@ * limitations under the License. */ -// TODO(shmidt-i): move to the app +import React from 'react'; import { Entity } from '@backstage/catalog-model'; -import { Content } from '@backstage/core'; -import { LatestWorkflowsForBranchCard } from '@backstage/plugin-github-actions'; -import { Grid } from '@material-ui/core'; -import React, { FC } from 'react'; +import { useTopActiveItems } from '../../hooks/useTopActiveItems'; +import { RollbarTopItemsTable } from '../RollbarTopItemsTable/RollbarTopItemsTable'; + +type Props = { + entity: Entity; +}; + +export const RollbarProject = ({ entity }: Props) => { + const { items, organization, project, loading, error } = useTopActiveItems( + entity, + ); -export const EntityPageCi: FC<{ entity: Entity }> = ({ entity }) => { return ( - - - {entity.metadata?.annotations?.['backstage.io/github-actions-id'] && ( - - - - )} - - + ); }; diff --git a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx index e4919a68bd..ad3d4a554d 100644 --- a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx +++ b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.test.tsx @@ -26,6 +26,7 @@ import { render } from '@testing-library/react'; import { RollbarApi, rollbarApiRef } from '../../api/RollbarApi'; import { RollbarTopActiveItem } from '../../api/types'; import { RollbarProjectPage } from './RollbarProjectPage'; +import { catalogApiRef, CatalogApi } from '@backstage/plugin-catalog'; describe('RollbarProjectPage component', () => { const items: RollbarTopActiveItem[] = [ @@ -60,6 +61,17 @@ describe('RollbarProjectPage component', () => { apis={ApiRegistry.from([ [rollbarApiRef, rollbarApi], [configApiRef, config], + [ + catalogApiRef, + ({ + async getEntityByName() { + return { + metadata: { name: 'foo' }, + spec: { owner: 'bar', lifecycle: 'experimental' }, + } as any; + }, + } as Partial) as CatalogApi, + ], ])} > {children} @@ -69,6 +81,6 @@ describe('RollbarProjectPage component', () => { it('should render rollbar project page', async () => { const rendered = renderWrapped(); - expect(rendered.getByText(/Top Active Items/)).toBeInTheDocument(); + expect(rendered.getByText(/Rollbar/)).toBeInTheDocument(); }); }); diff --git a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx index 6635a72086..b18357e310 100644 --- a/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx +++ b/plugins/rollbar/src/components/RollbarProjectPage/RollbarProjectPage.tsx @@ -15,39 +15,22 @@ */ import React from 'react'; -import { useParams } from 'react-router-dom'; -import { useAsync } from 'react-use'; -import { configApiRef, useApi } from '@backstage/core'; -import { rollbarApiRef } from '../../api/RollbarApi'; -import { RollbarLayout } from '../RollbarLayout/RollbarLayout'; -import { RollbarTopItemsTable } from '../RollbarTopItemsTable/RollbarTopItemsTable'; +import { Content, Header, HeaderLabel, Page, pageTheme } from '@backstage/core'; +import { useCatalogEntity } from '../../hooks/useCatalogEntity'; +import { RollbarProject } from '../RollbarProject/RollbarProject'; export const RollbarProjectPage = () => { - const configApi = useApi(configApiRef); - const rollbarApi = useApi(rollbarApiRef); - const org = - configApi.getOptionalString('rollbar.organization') ?? - configApi.getString('organization.name'); - const { componentId } = useParams() as { - componentId: string; - }; - const { value, loading, error } = useAsync(() => - rollbarApi - .getTopActiveItems(componentId, 168) - .then(data => - data.sort((a, b) => b.item.occurrences - a.item.occurrences), - ), - ); + const { entity } = useCatalogEntity(); return ( - - - + +
+ + +
+ + {entity ? : 'Loading'} + +
); }; diff --git a/plugins/rollbar/src/components/RollbarPage/RollbarProjectTable.tsx b/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx similarity index 57% rename from plugins/rollbar/src/components/RollbarPage/RollbarProjectTable.tsx rename to plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx index fdf90c468e..5b3631ade9 100644 --- a/plugins/rollbar/src/components/RollbarPage/RollbarProjectTable.tsx +++ b/plugins/rollbar/src/components/RollbarProjectTable/RollbarProjectTable.tsx @@ -15,68 +15,49 @@ */ import React from 'react'; -import { Link as RouterLink } from 'react-router-dom'; +import { Link as RouterLink, generatePath } from 'react-router-dom'; +import { Table, TableColumn } from '@backstage/core'; +import { Entity } from '@backstage/catalog-model'; import { Link } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; -import OpenInNewIcon from '@material-ui/icons/OpenInNew'; -import { Table, TableColumn } from '@backstage/core'; -import { RollbarProject } from '../../api/types'; - -const projectUrl = (org: string, id: number) => - `https://rollbar.com/${org}/all/items/?projects=${id}`; +import { entityRouteRef } from '../../routes'; const columns: TableColumn[] = [ - { - title: 'ID', - field: 'id', - type: 'numeric', - align: 'left', - width: '100px', - }, { title: 'Name', - field: 'name', + field: 'metadata.name', type: 'string', highlight: true, - render: (row: Partial) => ( - - {row.name} - - ), - }, - { - title: 'Status', - field: 'status', - type: 'string', - }, - { - title: 'Open', - width: '10%', - render: (row: any) => ( + render: (entity: any) => ( - + {entity.metadata.name} ), }, + { + title: 'Description', + field: 'metadata.description', + }, ]; type Props = { - projects: RollbarProject[]; + entities: Entity[]; loading: boolean; - organization: string; error?: any; }; -export const RollbarProjectTable = ({ - projects, - organization, - loading, - error, -}: Props) => { +export const RollbarProjectTable = ({ entities, loading, error }: Props) => { if (error) { return (
@@ -92,14 +73,13 @@ export const RollbarProjectTable = ({ isLoading={loading} columns={columns} options={{ - padding: 'dense', search: true, paging: true, pageSize: 10, showEmptyDataSourceMessage: !loading, }} title="Projects" - data={projects.map(p => ({ organization, ...p }))} + data={entities} /> ); }; diff --git a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx index 913ecca28a..a04155a0c3 100644 --- a/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx +++ b/plugins/rollbar/src/components/RollbarTopItemsTable/RollbarTopItemsTable.tsx @@ -16,17 +16,15 @@ import React from 'react'; import { Table, TableColumn } from '@backstage/core'; -import { Link } from '@material-ui/core'; +import { Box, Link, Typography } from '@material-ui/core'; import { Alert } from '@material-ui/lab'; import { RollbarFrameworkId, RollbarLevel, RollbarTopActiveItem, } from '../../api/types'; -import { RollbarTrendGraph } from '../RollbarTrendGraph/RollbarTrendGraph'; - -const itemUrl = (org: string, project: string, id: number) => - `https://rollbar.com/${org}/${project}/items/${id}`; +import { buildItemUrl } from '../../utils'; +import { TrendGraph } from '../TrendGraph/TrendGraph'; const columns: TableColumn[] = [ { @@ -37,7 +35,7 @@ const columns: TableColumn[] = [ width: '70px', render: (data: any) => ( @@ -54,7 +52,7 @@ const columns: TableColumn[] = [ { title: 'Trend', sorting: false, - render: (data: any) => , + render: (data: any) => , }, { title: 'Occurrences', @@ -127,7 +125,12 @@ export const RollbarTopItemsTable = ({ pageSize: 5, showEmptyDataSourceMessage: !loading, }} - title="Top Active Items" + title={ + + + Top Active Items / {project} + + } data={items.map(i => ({ org: organization, project, ...i }))} /> ); diff --git a/plugins/rollbar/src/components/Router.tsx b/plugins/rollbar/src/components/Router.tsx new file mode 100644 index 0000000000..bcf325f281 --- /dev/null +++ b/plugins/rollbar/src/components/Router.tsx @@ -0,0 +1,44 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Routes, Route } from 'react-router'; +import { Entity } from '@backstage/catalog-model'; +import { WarningPanel } from '@backstage/core'; +import { catalogRouteRef } from '../routes'; +import { ROLLBAR_ANNOTATION } from '../constants'; +import { EntityPageRollbar } from './EntityPageRollbar/EntityPageRollbar'; + +export const isPluginApplicableToEntity = (entity: Entity) => + entity.metadata.annotations?.[ROLLBAR_ANNOTATION] !== ''; + +type Props = { + entity: Entity; +}; + +export const Router = ({ entity }: Props) => + !isPluginApplicableToEntity(entity) ? ( + +
{ROLLBAR_ANNOTATION}
annotation is missing on the entity. +
+ ) : ( + + } + /> + + ); diff --git a/plugins/rollbar/src/components/RollbarTrendGraph/RollbarTrendGraph.test.tsx b/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx similarity index 81% rename from plugins/rollbar/src/components/RollbarTrendGraph/RollbarTrendGraph.test.tsx rename to plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx index 1f9d317e5b..ac1a328521 100644 --- a/plugins/rollbar/src/components/RollbarTrendGraph/RollbarTrendGraph.test.tsx +++ b/plugins/rollbar/src/components/TrendGraph/TrendGraph.test.tsx @@ -17,15 +17,13 @@ import React from 'react'; import { render } from '@testing-library/react'; import { wrapInTestApp } from '@backstage/test-utils'; -import { RollbarTrendGraph } from './RollbarTrendGraph'; +import { TrendGraph } from './TrendGraph'; -describe('RollbarTrendGraph component', () => { +describe('TrendGraph component', () => { it('should render a trend graph sparkline', async () => { const mockCounts = [1, 2, 3, 4]; const rendered = render( - wrapInTestApp( - , - ), + wrapInTestApp(), ); expect(rendered).toBeTruthy(); }); diff --git a/plugins/rollbar/src/components/RollbarTrendGraph/RollbarTrendGraph.tsx b/plugins/rollbar/src/components/TrendGraph/TrendGraph.tsx similarity index 93% rename from plugins/rollbar/src/components/RollbarTrendGraph/RollbarTrendGraph.tsx rename to plugins/rollbar/src/components/TrendGraph/TrendGraph.tsx index 4f0b53eb4a..5d518817bc 100644 --- a/plugins/rollbar/src/components/RollbarTrendGraph/RollbarTrendGraph.tsx +++ b/plugins/rollbar/src/components/TrendGraph/TrendGraph.tsx @@ -21,7 +21,7 @@ type Props = { counts: number[]; }; -export const RollbarTrendGraph = ({ counts }: Props) => { +export const TrendGraph = ({ counts }: Props) => { return ( diff --git a/plugins/rollbar/src/constants.ts b/plugins/rollbar/src/constants.ts new file mode 100644 index 0000000000..e3a89d655e --- /dev/null +++ b/plugins/rollbar/src/constants.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const ROLLBAR_ANNOTATION = 'rollbar.com/project-slug'; diff --git a/plugins/rollbar/src/hooks/useCatalogEntity.ts b/plugins/rollbar/src/hooks/useCatalogEntity.ts new file mode 100644 index 0000000000..172d057738 --- /dev/null +++ b/plugins/rollbar/src/hooks/useCatalogEntity.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useAsync } from 'react-use'; +import { useApi } from '@backstage/core'; +import { + catalogApiRef, + useEntityCompoundName, +} from '@backstage/plugin-catalog'; + +export function useCatalogEntity() { + const catalogApi = useApi(catalogApiRef); + const { namespace, name } = useEntityCompoundName(); + + const { value: entity, error, loading } = useAsync( + () => catalogApi.getEntityByName({ kind: 'Component', namespace, name }), + [catalogApi, namespace, name], + ); + + return { entity, error, loading }; +} diff --git a/plugins/rollbar/src/hooks/useProject.ts b/plugins/rollbar/src/hooks/useProject.ts new file mode 100644 index 0000000000..5d61b63ffb --- /dev/null +++ b/plugins/rollbar/src/hooks/useProject.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useApi, configApiRef } from '@backstage/core'; +import { Entity } from '@backstage/catalog-model'; +import { ROLLBAR_ANNOTATION } from '../constants'; + +export function useProjectSlugFromEntity(entity: Entity) { + const configApi = useApi(configApiRef); + + const [project, organization] = ( + entity?.metadata?.annotations?.[ROLLBAR_ANNOTATION] ?? '' + ) + .split('/') + .reverse(); + + return { + project, + organization: + organization ?? + configApi.getOptionalString('rollbar.organization') ?? + configApi.getString('organization.name'), + }; +} diff --git a/plugins/rollbar/src/components/RollbarPage/RollbarPage.tsx b/plugins/rollbar/src/hooks/useRollbarEntities.ts similarity index 55% rename from plugins/rollbar/src/components/RollbarPage/RollbarPage.tsx rename to plugins/rollbar/src/hooks/useRollbarEntities.ts index 0460b4a308..3edf34d1f3 100644 --- a/plugins/rollbar/src/components/RollbarPage/RollbarPage.tsx +++ b/plugins/rollbar/src/hooks/useRollbarEntities.ts @@ -14,29 +14,25 @@ * limitations under the License. */ -import React from 'react'; import { useAsync } from 'react-use'; -import { configApiRef, useApi } from '@backstage/core'; -import { rollbarApiRef } from '../../api/RollbarApi'; -import { RollbarLayout } from '../RollbarLayout/RollbarLayout'; -import { RollbarProjectTable } from './RollbarProjectTable'; +import { useApi, configApiRef } from '@backstage/core'; +import { catalogApiRef } from '@backstage/plugin-catalog'; +import { ROLLBAR_ANNOTATION } from '../constants'; -export const RollbarPage = () => { +export function useRollbarEntities() { const configApi = useApi(configApiRef); - const rollbarApi = useApi(rollbarApiRef); - const org = + const catalogApi = useApi(catalogApiRef); + + const organization = configApi.getOptionalString('rollbar.organization') ?? configApi.getString('organization.name'); - const { value, loading, error } = useAsync(() => rollbarApi.getAllProjects()); - return ( - - - - ); -}; + const { value, loading, error } = useAsync(async () => { + const entities = await catalogApi.getEntities(); + return entities.filter(entity => { + return !!entity.metadata.annotations?.[ROLLBAR_ANNOTATION]; + }); + }, [catalogApi]); + + return { entities: value, organization, loading, error }; +} diff --git a/plugins/rollbar/src/hooks/useTopActiveItems.ts b/plugins/rollbar/src/hooks/useTopActiveItems.ts new file mode 100644 index 0000000000..cb1689355f --- /dev/null +++ b/plugins/rollbar/src/hooks/useTopActiveItems.ts @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { useAsync } from 'react-use'; +import { useApi } from '@backstage/core'; +import { Entity } from '@backstage/catalog-model'; +import { rollbarApiRef } from '../api'; +import { RollbarTopActiveItem } from '../api/types'; +import { useProjectSlugFromEntity } from './useProject'; + +export function useTopActiveItems(entity: Entity) { + const api = useApi(rollbarApiRef); + const { organization, project } = useProjectSlugFromEntity(entity); + const { value, loading, error } = useAsync(() => { + if (!project) { + return Promise.resolve([]); + } + + return api + .getTopActiveItems(project, 168) + .then(data => + data.sort((a, b) => b.item.occurrences - a.item.occurrences), + ); + }, [api, organization, project, entity]); + + return { + items: value as RollbarTopActiveItem[], + organization, + project, + loading, + error, + }; +} diff --git a/plugins/rollbar/src/index.ts b/plugins/rollbar/src/index.ts index 3a8288a545..2a31c91a13 100644 --- a/plugins/rollbar/src/index.ts +++ b/plugins/rollbar/src/index.ts @@ -15,6 +15,9 @@ */ export { plugin } from './plugin'; -export * from './api/RollbarApi'; -export { RollbarClient } from './api/RollbarClient'; -export { RollbarMockClient } from './api/RollbarMockClient'; +export * from './api'; +export * from './routes'; +export { Router } from './components/Router'; +export { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage'; +export { EntityPageRollbar } from './components/EntityPageRollbar/EntityPageRollbar'; +export { ROLLBAR_ANNOTATION } from './constants'; diff --git a/plugins/rollbar/src/plugin.ts b/plugins/rollbar/src/plugin.ts index d682750a83..c3ca6173ff 100644 --- a/plugins/rollbar/src/plugin.ts +++ b/plugins/rollbar/src/plugin.ts @@ -14,15 +14,28 @@ * limitations under the License. */ -import { createPlugin } from '@backstage/core'; -import { RollbarPage } from './components/RollbarPage/RollbarPage'; +import { + createPlugin, + createApiFactory, + discoveryApiRef, +} from '@backstage/core'; +import { rootRouteRef, entityRouteRef } from './routes'; +import { RollbarHome } from './components/RollbarHome/RollbarHome'; import { RollbarProjectPage } from './components/RollbarProjectPage/RollbarProjectPage'; -import { rootRoute, rootProjectRoute } from './routes'; +import { rollbarApiRef } from './api/RollbarApi'; +import { RollbarClient } from './api/RollbarClient'; export const plugin = createPlugin({ id: 'rollbar', + apis: [ + createApiFactory({ + api: rollbarApiRef, + deps: { discoveryApi: discoveryApiRef }, + factory: ({ discoveryApi }) => new RollbarClient({ discoveryApi }), + }), + ], register({ router }) { - router.addRoute(rootRoute, RollbarPage); - router.addRoute(rootProjectRoute, RollbarProjectPage); + router.addRoute(rootRouteRef, RollbarHome); + router.addRoute(entityRouteRef, RollbarProjectPage); }, }); diff --git a/plugins/rollbar/src/routes.ts b/plugins/rollbar/src/routes.ts index ecf20f3167..b514dff3c8 100644 --- a/plugins/rollbar/src/routes.ts +++ b/plugins/rollbar/src/routes.ts @@ -16,12 +16,21 @@ import { createRouteRef } from '@backstage/core'; -export const rootRoute = createRouteRef({ +const NoIcon = () => null; + +export const rootRouteRef = createRouteRef({ + icon: NoIcon, path: '/rollbar', title: 'Rollbar Home', }); -export const rootProjectRoute = createRouteRef({ - path: '/rollbar/:componentId/*', +export const entityRouteRef = createRouteRef({ + path: '/rollbar/:optionalNamespaceAndName', + title: 'Rollbar', +}); + +export const catalogRouteRef = createRouteRef({ + icon: NoIcon, + path: '', title: 'Rollbar', }); diff --git a/plugins/rollbar/src/utils/index.ts b/plugins/rollbar/src/utils/index.ts new file mode 100644 index 0000000000..1c8f8ff39e --- /dev/null +++ b/plugins/rollbar/src/utils/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const buildProjectUrl = (org: string, id: number) => + `https://rollbar.com/${org}/all/items/?projects=${id}`; + +export const buildItemUrl = (org: string, project: string, id: number) => + `https://rollbar.com/${org}/${project}/items/${id}`; diff --git a/plugins/scaffolder-backend/README.md b/plugins/scaffolder-backend/README.md index 7ffbeae1d1..185938b006 100644 --- a/plugins/scaffolder-backend/README.md +++ b/plugins/scaffolder-backend/README.md @@ -1,4 +1,5 @@ # Title + Welcome to the scaffolder plugin! ## Sub-section 1 diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 720eb7cc15..2283dd5d05 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -17,8 +17,7 @@ "test": "backstage-cli test", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", - "mock-data": "./scripts/mock-data.sh" + "clean": "backstage-cli clean" }, "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.21", @@ -45,7 +44,7 @@ }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.21", - "@octokit/types": "^5.0.1", + "@octokit/types": "^5.4.1", "@types/fs-extra": "^9.0.1", "@types/git-url-parse": "^9.0.0", "@types/nodegit": "0.26.8", diff --git a/plugins/scaffolder-backend/sample-templates/all-templates.yaml b/plugins/scaffolder-backend/sample-templates/all-templates.yaml new file mode 100644 index 0000000000..1eb619a072 --- /dev/null +++ b/plugins/scaffolder-backend/sample-templates/all-templates.yaml @@ -0,0 +1,13 @@ +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: example-templates + description: A collection of all Backstage example templates +spec: + type: github + targets: + - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml + - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml + - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml + - https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml + - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml diff --git a/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml b/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml index a377d60ccc..2c8b3b3d6d 100644 --- a/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/create-react-app/template.yaml @@ -22,11 +22,11 @@ spec: component_id: title: Name type: string - description: Unique name of the component + description: Unique name of the component. Lowercase, URL-safe characters only. description: title: Description type: string - description: Description of the component + description: Help others understand what this website is for. use_typescript: title: Use Typescript type: boolean diff --git a/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml b/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml index da2152280d..b4bd45d163 100644 --- a/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/docs-template/template.yaml @@ -5,7 +5,7 @@ metadata: title: Documentation Template description: Create a new standalone documentation project tags: - - experimental + - recommended - techdocs - mkdocs spec: @@ -25,5 +25,5 @@ spec: description: title: Description type: string - description: Description of the component + description: Help others understand what these docs are about. diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml index ee051de6e0..a667e6e6b6 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/template.yaml @@ -24,4 +24,4 @@ spec: description: title: Description type: string - description: Description of the component + description: Help others understand what this website is for. diff --git a/plugins/scaffolder-backend/sample-templates/react-ssr-template/{{cookiecutter.component_id}}/component-info.yaml b/plugins/scaffolder-backend/sample-templates/react-ssr-template/{{cookiecutter.component_id}}/component-info.yaml index 832b539ac6..f6e1d2c8d9 100644 --- a/plugins/scaffolder-backend/sample-templates/react-ssr-template/{{cookiecutter.component_id}}/component-info.yaml +++ b/plugins/scaffolder-backend/sample-templates/react-ssr-template/{{cookiecutter.component_id}}/component-info.yaml @@ -5,7 +5,6 @@ metadata: description: {{cookiecutter.description}} annotations: github.com/project-slug: {{cookiecutter.storePath}} - backstage.io/github-actions-id: {{cookiecutter.storePath}} backstage.io/techdocs-ref: github:https://github.com/{{cookiecutter.storePath}} spec: type: website diff --git a/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml index c6189fe7c8..8b89298a0e 100644 --- a/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml +++ b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/template.yaml @@ -2,11 +2,12 @@ apiVersion: backstage.io/v1alpha1 kind: Template metadata: name: springboot-template - title: Spring Boot GRPC Service + title: Spring Boot gRPC Service description: Create a simple microservice using gRPC and Spring Boot Java tags: - recommended - java + - grpc spec: owner: service@example.com templater: cookiecutter @@ -24,9 +25,9 @@ spec: description: title: Description type: string - description: Description of the component + description: Help others understand what this service does. http_port: title: Port type: integer default: 8080 - description: The port to run the GRPC service on + description: The port to run the gRPC service on diff --git a/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/component-info.yaml b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/component-info.yaml index 15c8fdcfff..05b87c9c0c 100644 --- a/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/component-info.yaml +++ b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/component-info.yaml @@ -5,7 +5,7 @@ metadata: description: {{cookiecutter.description}} annotations: github.com/project-slug: {{cookiecutter.storePath}} - backstage.io/github-actions-id: {{cookiecutter.storePath}} + backstage.io/techdocs-ref: github:https://github.com/{{cookiecutter.storePath}} spec: type: service lifecycle: experimental diff --git a/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/docs/index.md b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/docs/index.md new file mode 100644 index 0000000000..5352ef7801 --- /dev/null +++ b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/docs/index.md @@ -0,0 +1,28 @@ +## {{ cookiecutter.component_id }} + +{{ cookiecutter.description }} + +## Getting started + +Start write your documentation by adding more markdown (.md) files to this folder (/docs) or replace the content in this file. + +## Table of Contents + +The Table of Contents on the right is generated automatically based on the hierarchy +of headings. Only use one H1 (`#` in Markdown) per file. + +## Site navigation + +For new pages to appear in the left hand navigation you need edit the `mkdocs.yml` +file in root of your repo. The navigation can also link out to other sites. + +Alternatively, if there is no `nav` section in `mkdocs.yml`, a navigation section +will be created for you. However, you will not be able to use alternate titles for +pages, or include links to other sites. + +Note that MkDocs uses `mkdocs.yml`, not `mkdocs.yaml`, although both appear to work. +See also . + +## Support + +That's it. If you need support, reach out in [#docs-like-code](https://discord.com/channels/687207715902193673/714754240933003266) on Discord. diff --git a/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/mkdocs.yml b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/mkdocs.yml new file mode 100644 index 0000000000..0d10d11063 --- /dev/null +++ b/plugins/scaffolder-backend/sample-templates/springboot-grpc-template/{{cookiecutter.component_id}}/mkdocs.yml @@ -0,0 +1,8 @@ +site_name: {{cookiecutter.component_id}} +site_description: {{cookiecutter.description}} + +nav: + - Introduction: index.md + +plugins: + - techdocs-core diff --git a/plugins/scaffolder-backend/scripts/mock-data.sh b/plugins/scaffolder-backend/scripts/mock-data.sh deleted file mode 100755 index 9a9b0b186b..0000000000 --- a/plugins/scaffolder-backend/scripts/mock-data.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash - -for URL in \ - 'react-ssr-template' \ - 'springboot-grpc-template' \ - 'create-react-app' \ - 'docs-template' \ -; do \ - curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/sample-templates/${URL}/template.yaml\"}" - echo -done - -curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"github\", \"target\": \"https://github.com/spotify/cookiecutter-golang/blob/master/template.yaml\"}" -echo diff --git a/plugins/scaffolder-backend/src/index.ts b/plugins/scaffolder-backend/src/index.ts index 0a0a4cb95f..c461bfede6 100644 --- a/plugins/scaffolder-backend/src/index.ts +++ b/plugins/scaffolder-backend/src/index.ts @@ -16,4 +16,3 @@ export * from './scaffolder'; export * from './service/router'; - diff --git a/plugins/scaffolder-backend/src/scaffolder/__mocks__/@octokit/rest/index.ts b/plugins/scaffolder-backend/src/scaffolder/__mocks__/@octokit/rest/index.ts index 85bed3a223..a302bc5931 100644 --- a/plugins/scaffolder-backend/src/scaffolder/__mocks__/@octokit/rest/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/__mocks__/@octokit/rest/index.ts @@ -19,6 +19,9 @@ export const mockGithubClient = { createInOrg: jest.fn(), createForAuthenticatedUser: jest.fn(), }, + users: { + getByUsername: jest.fn(), + }, }; export class Octokit { diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts index a61e5de867..4409d815b5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.test.ts @@ -96,6 +96,8 @@ describe('GitHubPreparer', () => { mockEntity.spec.path = './template/test/1/2/3'; const response = await preparer.prepare(mockEntity); - expect(response).toMatch(new RegExp(/\/template\/test\/1\/2\/3$/)); + expect(response.split('\\').join('/')).toMatch( + /\/template\/test\/1\/2\/3$/, + ); }); }); diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts index 93493ab2cc..718c01438c 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.test.ts @@ -19,11 +19,18 @@ jest.mock('nodegit'); import { Octokit } from '@octokit/rest'; import * as NodeGit from 'nodegit'; -import { OctokitResponse, ReposCreateInOrgResponseData } from '@octokit/types'; +import { + OctokitResponse, + ReposCreateInOrgResponseData, + UsersGetByUsernameResponseData, +} from '@octokit/types'; import { GithubPublisher } from './github'; const { mockGithubClient } = require('@octokit/rest') as { - mockGithubClient: { repos: jest.Mocked }; + mockGithubClient: { + repos: jest.Mocked; + users: jest.Mocked; + }; }; const { @@ -59,10 +66,14 @@ describe('GitHub Publisher', () => { clone_url: 'mockclone', }, } as OctokitResponse); + mockGithubClient.users.getByUsername.mockResolvedValue({ + data: { + type: 'Organization', + }, + } as OctokitResponse); await publisher.publish({ values: { - isOrg: true, storePath: 'blam/test', owner: 'bob', }, @@ -81,6 +92,11 @@ describe('GitHub Publisher', () => { clone_url: 'mockclone', }, } as OctokitResponse); + mockGithubClient.users.getByUsername.mockResolvedValue({ + data: { + type: 'User', + }, + } as OctokitResponse); await publisher.publish({ values: { @@ -112,6 +128,12 @@ describe('GitHub Publisher', () => { clone_url: 'mockclone', }, } as OctokitResponse); + mockGithubClient.users.getByUsername.mockResolvedValue({ + data: { + type: 'Organization', + }, + } as OctokitResponse); + it('should call init on the repo with the directory', async () => { await publisher.publish({ values, diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts index 5fd64d69fc..f3306e3662 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/publish/github.ts @@ -45,9 +45,12 @@ export class GithubPublisher implements PublisherBase { ) { const [owner, name] = values.storePath.split('/'); - const repoCreationPromise = values.isOrg - ? this.client.repos.createInOrg({ name, org: owner }) - : this.client.repos.createForAuthenticatedUser({ name }); + const user = await this.client.users.getByUsername({ username: owner }); + + const repoCreationPromise = + user.data.type === 'Organization' + ? this.client.repos.createInOrg({ name, org: owner }) + : this.client.repos.createForAuthenticatedUser({ name }); const { data } = await repoCreationPromise; diff --git a/plugins/scaffolder-backend/src/scaffolder/stages/templater/helpers.test.ts b/plugins/scaffolder-backend/src/scaffolder/stages/templater/helpers.test.ts index b7e969cd47..a4441ca23f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/stages/templater/helpers.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/stages/templater/helpers.test.ts @@ -20,6 +20,13 @@ import Docker from 'dockerode'; import { runDockerContainer } from './helpers'; describe('helpers', () => { + if (process.platform === 'win32') { + // eslint-disable-next-line jest/no-focused-tests + it.only('should skip tests on windows', () => { + expect('test').not.toBe('run'); + }); + } + const mockDocker = new Docker() as jest.Mocked; beforeEach(() => { diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 7497cbe024..2efc2c270a 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -25,7 +25,7 @@ "@backstage/core": "^0.1.1-alpha.21", "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@rjsf/core": "^2.1.0", diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index 3c42ed2ca4..f58c8e68d1 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -30,6 +30,8 @@ export class ScaffolderApi { } /** + * Executes the scaffolding of a component, given a template and its + * parameter values. * * @param template Template entity for the scaffolder to use. New project is going to be created out of this template. * @param values Parameters for the template, e.g. name, description @@ -44,12 +46,13 @@ export class ScaffolderApi { headers: { 'Content-Type': 'application/json', }, - // TODO(shmidt-i): when repo picker is implemented, take isOrg from it - body: JSON.stringify({ template, values: { ...values, isOrg: true } }), + body: JSON.stringify({ template, values: { ...values } }), }); if (response.status !== 201) { - throw new Error(await response.text()); + const status = `${response.status} ${response.statusText}`; + const body = await response.text(); + throw new Error(`Backend request failed, ${status} ${body.trim()}`); } const { id } = await response.json(); @@ -57,9 +60,8 @@ export class ScaffolderApi { } async getJob(jobId: string) { - const url = `${await this.discoveryApi.getBaseUrl( - 'scaffolder', - )}/v1/job/${encodeURIComponent(jobId)}`; + const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); + const url = `${baseUrl}/v1/job/${encodeURIComponent(jobId)}`; return fetch(url).then(x => x.json()); } } diff --git a/plugins/scaffolder/src/components/JobStage/JobStage.tsx b/plugins/scaffolder/src/components/JobStage/JobStage.tsx index 1e9adafb18..0baba0c9b9 100644 --- a/plugins/scaffolder/src/components/JobStage/JobStage.tsx +++ b/plugins/scaffolder/src/components/JobStage/JobStage.tsx @@ -13,16 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { + Accordion, + AccordionDetails, + AccordionSummary, Box, - ExpansionPanel, - ExpansionPanelDetails, - ExpansionPanelSummary, + CircularProgress, LinearProgress, Typography, } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import ExpandLessIcon from '@material-ui/icons/ExpandLess'; import cn from 'classnames'; import moment from 'moment'; import React, { Suspense, useEffect, useState } from 'react'; @@ -32,18 +35,17 @@ const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); moment.relativeTimeThreshold('ss', 0); const useStyles = makeStyles(theme => ({ - expansionPanelDetails: { + accordionDetails: { padding: 0, }, button: { order: -1, - marginRight: 0, - marginLeft: '-20px', + margin: '0 1em 0 -20px', }, cardContent: { backgroundColor: theme.palette.background.default, }, - expansionPanel: { + accordion: { position: 'relative', '&:after': { pointerEvents: 'none', @@ -98,18 +100,18 @@ export const JobStage = ({ endedAt, startedAt, name, log, status }: Props) => { : null; return ( - ] ?? classes.neutral, )} expanded={expanded} onChange={(_, newState) => setExpanded(newState)} > - } + : } aria-controls={`panel-${name}-content`} id={`panel-${name}-header`} IconButtonProps={{ @@ -117,10 +119,11 @@ export const JobStage = ({ endedAt, startedAt, name, log, status }: Props) => { }} > - {name} {timeElapsed && `(${timeElapsed})`} + {name} {timeElapsed && `(${timeElapsed})`}{' '} + {startedAt && !endedAt && } - - + + {log.length === 0 ? ( No logs available for this step ) : ( @@ -130,7 +133,7 @@ export const JobStage = ({ endedAt, startedAt, name, log, status }: Props) => {
)} - - + + ); }; diff --git a/plugins/scaffolder/src/components/JobStatusModal/JobStatusModal.tsx b/plugins/scaffolder/src/components/JobStatusModal/JobStatusModal.tsx index c6ed55c92c..87b70a9553 100644 --- a/plugins/scaffolder/src/components/JobStatusModal/JobStatusModal.tsx +++ b/plugins/scaffolder/src/components/JobStatusModal/JobStatusModal.tsx @@ -51,7 +51,7 @@ export const JobStatusModal = ({ return ( - Creating component... + Creating Component... {!job ? ( @@ -72,7 +72,7 @@ export const JobStatusModal = ({ {entity && ( Create new software components using standard templates. Different @@ -101,16 +103,16 @@ export const ScaffolderPage: React.FC<{}> = () => { )} {error && ( - + Oops! Something went wrong loading the templates: {error.message} - + )} {templates && templates?.length > 0 && templates.map(template => { return ( - + ); diff --git a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx b/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx index d98b1a11e9..470fef1148 100644 --- a/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx +++ b/plugins/scaffolder/src/components/TemplateCard/TemplateCard.tsx @@ -23,8 +23,8 @@ const useStyles = makeStyles(theme => ({ header: { color: theme.palette.common.white, padding: theme.spacing(2, 2, 6), - backgroundImage: (props: { gradientStart: string; gradientStop: string }) => - `linear-gradient(-137deg, ${props.gradientStart} 0%, ${props.gradientStop} 100%)`, + backgroundImage: (props: { backgroundImage: string }) => + props.backgroundImage, }, content: { padding: theme.spacing(2), @@ -56,8 +56,7 @@ export const TemplateCard = ({ name, }: TemplateCardProps) => { const theme = pageTheme[type] ?? pageTheme.other; - const [gradientStart, gradientStop] = theme.colors; - const classes = useStyles({ gradientStart, gradientStop }); + const classes = useStyles({ backgroundImage: theme.backgroundImage }); const href = generatePath(templateRoute.path, { templateName: name }); return ( diff --git a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx index 3c22e8d50c..1ed0504894 100644 --- a/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx +++ b/plugins/scaffolder/src/components/TemplatePage/TemplatePage.tsx @@ -91,8 +91,12 @@ export const TemplatePage = () => { const handleClose = () => setJobId(null); const handleCreate = async () => { - const job = await scaffolderApi.scaffold(template!, formState); - setJobId(job); + try { + const job = await scaffolderApi.scaffold(template!, formState); + setJobId(job); + } catch (e) { + errorApi.post(e); + } }; const [entity, setEntity] = React.useState( @@ -157,7 +161,7 @@ export const TemplatePage = () => { /> )} {template && ( - + new ScaffolderApi({ discoveryApi }), + }), + ], register({ router }) { router.addRoute(rootRoute, ScaffolderPage); router.addRoute(templateRoute, TemplatePage); diff --git a/plugins/sentry-backend/src/service/sentry-api.ts b/plugins/sentry-backend/src/service/sentry-api.ts index 5c8a9f1aa5..8d35038840 100644 --- a/plugins/sentry-backend/src/service/sentry-api.ts +++ b/plugins/sentry-backend/src/service/sentry-api.ts @@ -26,7 +26,7 @@ export function getRequestHeaders(token: string) { } export function getSentryApiForwarder(token: string, logger: Logger) { - return function fowardRequest( + return function forwardRequest( request: express.Request, response: express.Response, ) { diff --git a/plugins/sentry/package.json b/plugins/sentry/package.json index d5b29cc307..e3b900ca8d 100644 --- a/plugins/sentry/package.json +++ b/plugins/sentry/package.json @@ -21,14 +21,16 @@ "clean": "backstage-cli clean" }, "dependencies": { + "@backstage/catalog-model": "^0.1.1-alpha.21", "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@types/react": "^16.9", "react": "^16.13.1", "react-dom": "^16.13.1", + "react-router": "6.0.0-beta.0", "react-sparklines": "^1.7.0", "react-use": "^15.3.3", "timeago.js": "^4.0.2" diff --git a/plugins/sentry/src/components/Router.tsx b/plugins/sentry/src/components/Router.tsx new file mode 100644 index 0000000000..47d532b4e3 --- /dev/null +++ b/plugins/sentry/src/components/Router.tsx @@ -0,0 +1,46 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { Routes, Route } from 'react-router'; +import { WarningPanel } from '@backstage/core'; +import { SentryPluginWidget } from './SentryPluginWidget/SentryPluginWidget'; + +const SENTRY_ANNOTATION = 'sentry.io/project-slug'; + +export const Router = ({ entity }: { entity: Entity }) => { + const projectId = entity.metadata.annotations?.[SENTRY_ANNOTATION]; + + if (!projectId) { + return ( + +
{SENTRY_ANNOTATION}
annotation is missing on the entity. +
+ ); + } + + return ( + + + } + /> + ) + + ); +}; diff --git a/plugins/sentry/src/index.ts b/plugins/sentry/src/index.ts index 50da801a40..a0d3cab1be 100644 --- a/plugins/sentry/src/index.ts +++ b/plugins/sentry/src/index.ts @@ -15,4 +15,5 @@ */ export { plugin } from './plugin'; +export { Router } from './components/Router'; export { SentryPluginWidget as SentryIssuesWidget } from './components/SentryPluginWidget/SentryPluginWidget'; diff --git a/plugins/tech-radar/README.md b/plugins/tech-radar/README.md index fb9d220b8c..cbe4dd22eb 100644 --- a/plugins/tech-radar/README.md +++ b/plugins/tech-radar/README.md @@ -29,71 +29,34 @@ For either simple or advanced installations, you'll need to add the dependency u yarn add @backstage/plugin-tech-radar ``` -### Simple Configuration +### Configuration -In your `apis.ts` set up the simple "out of the box" implementation for Tech Radar: - -```ts -import { ApiHolder, ApiRegistry } from '@backstage/core'; -import { - techRadarApiRef, - TechRadar, -} from '@backstage/plugin-tech-radar'; - -const builder = ApiRegistry.builder(); - -builder.add(techRadarApiRef, new TechRadar({ - width: 1400, - height: 800 -)); - -export default builder.build() as ApiHolder; -``` - -Congrats, you're done! We'll just load it with [example data](src/sampleData.ts) to get you started. Just go to to see it live in action. - -And if you'd like to configure it more, such as providing it with your own data, see the `TechRadarApi` TypeScript interface below for the options: - -```ts -export interface TechRadarComponentProps { - width: number; - height: number; - getData?: () => Promise; - svgProps?: object; -} - -export interface TechRadarApi extends TechRadarComponentProps { - title?: string; - subtitle?: string; -} -``` - -You can see the API directly over at [src/api.ts](./src/api.ts). - -### Advanced Configuration - -This way won't expose an `/tech-radar` path. Instead, you'll need to create your own Backstage plugin and use the Tech Radar as any other React UI component. - -In your Backstage app, run the following command: - -```sh -yarn create-plugin -``` - -In your plugin, in any React component you'd like to import the Tech Radar, do the following: +Modify your app routes to include the Router component exported from the tech radar, for example: ```tsx -import { TechRadarComponent } from '@backstage/plugin-tech-radar'; +import { Router as TechRadarRouter } from '@backstage/plugin-tech-radar'; -function MyCustomRadar() { - return ; -} +// Inside App component + + {/* other routes ... */} + } + /> + {/* other routes ... */} +; ``` -If you'd like to configure it more, see the `TechRadarComponentProps` TypeScript interface for options: +If you'd like to configure it more, see the `TechRadarPageProps` and `TechRadarComponentProps` types for options: ```ts -export interface TechRadarComponentProps { +export type TechRadarPageProps = TechRadarComponentProps & { + title?: string; + subtitle?: string; + pageTitle?: string; +}; + +export interface TechRadarPageProps { width: number; height: number; getData?: () => Promise; @@ -101,8 +64,6 @@ export interface TechRadarComponentProps { } ``` -You can see the API directly over at [src/api.ts](./src/api.ts). - ## Frequently Asked Questions ### Who created the Tech Radar? @@ -111,7 +72,7 @@ You can see the API directly over at [src/api.ts](./src/api.ts). ### How do I load in my own data? -It's simple. In both the Simple (Backstage plugin) and Advanced (React component) configurations, you can pass through a `getData` prop which expects a `Promise` signature. See more in [src/api.ts](./src/api.ts). +It's simple, you can pass through a `getData` prop which expects a `Promise` signature. Here's an example: @@ -133,42 +94,21 @@ const getHardCodedData = () => ], }); -// Simple -builder.add(techRadarApiRef, new TechRadar({ - width: 1400, - height: 800, - getData: getHardCodedData -)); - -// Advanced - +; ``` ### How do I write tests? You can use the `svgProps` option to pass custom React props to the `` element we create for the Tech Radar. This complements well with the `data-testid` attribute and the `@testing-library/react` library we use in Backstage. -```ts -// Simple -builder.add( - techRadarApiRef, - new TechRadar({ - width: 1400, - height: 800, - svgProps: { - 'data-testid': 'tech-radar-svg', - }, - }), -); - -// Advanced +```tsx ; +/> // Then, in your tests... // const { getByTestId } = render(...); diff --git a/plugins/tech-radar/dev/index.tsx b/plugins/tech-radar/dev/index.tsx index ac19b63a90..92eb6da567 100644 --- a/plugins/tech-radar/dev/index.tsx +++ b/plugins/tech-radar/dev/index.tsx @@ -15,14 +15,6 @@ */ import { createDevApp } from '@backstage/dev-utils'; -import { plugin } from '../src/plugin'; -import { techRadarApiRef, TechRadar } from '../src'; +import { plugin } from '../src'; -createDevApp() - .registerPlugin(plugin) - .registerApiFactory({ - implements: techRadarApiRef, - deps: {}, - factory: () => new TechRadar({ width: 1500, height: 800 }), - }) - .render(); +createDevApp().registerPlugin(plugin).render(); diff --git a/plugins/tech-radar/package.json b/plugins/tech-radar/package.json index 4039f40878..fc29d9c836 100644 --- a/plugins/tech-radar/package.json +++ b/plugins/tech-radar/package.json @@ -22,9 +22,9 @@ }, "dependencies": { "@backstage/core": "^0.1.1-alpha.21", - "@backstage/test-utils-core": "^0.1.1-alpha.21", + "@backstage/test-utils": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "color": "^3.1.2", diff --git a/plugins/tech-radar/src/api.ts b/plugins/tech-radar/src/api.ts index 856cf4ff3c..7a6e790136 100644 --- a/plugins/tech-radar/src/api.ts +++ b/plugins/tech-radar/src/api.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { createApiRef } from '@backstage/core'; import { MovedState } from './utils/types'; /** @@ -72,37 +71,3 @@ export interface TechRadarApi extends TechRadarComponentProps { subtitle?: string; pageTitle?: string; } - -export const techRadarApiRef = createApiRef({ - id: 'plugin.techradar', - description: 'Used by the Tech Radar to render the visualization', -}); - -export class TechRadar implements TechRadarApi { - // Default columns - public width: TechRadarApi['width']; - public height: TechRadarApi['height']; - public getData: TechRadarApi['getData']; - public svgProps: TechRadarApi['svgProps']; - public title: TechRadarApi['title']; - public subtitle: TechRadarApi['subtitle']; - public pageTitle: TechRadarApi['pageTitle']; - - constructor(overrideOptions: TechRadarApi) { - const defaultOptions: Partial = { - title: 'Tech Radar', - subtitle: 'Pick the recommended technologies for your projects', - pageTitle: 'Company Radar', - }; - - const options = { ...defaultOptions, ...overrideOptions }; - - this.width = options.width; - this.height = options.height; - this.getData = options.getData; - this.svgProps = options.svgProps; - this.title = options.title; - this.subtitle = options.subtitle; - this.pageTitle = options.pageTitle; - } -} diff --git a/plugins/tech-radar/src/components/RadarComponent.test.tsx b/plugins/tech-radar/src/components/RadarComponent.test.tsx index 2f3fcff198..5591d74b82 100644 --- a/plugins/tech-radar/src/components/RadarComponent.test.tsx +++ b/plugins/tech-radar/src/components/RadarComponent.test.tsx @@ -19,7 +19,7 @@ import { render, waitForElement } from '@testing-library/react'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; import { ApiRegistry, ApiProvider, errorApiRef } from '@backstage/core'; -import { withLogCollector } from '@backstage/test-utils-core'; +import { withLogCollector } from '@backstage/test-utils'; import GetBBoxPolyfill from '../utils/polyfills/getBBox'; import RadarComponent from './RadarComponent'; diff --git a/plugins/tech-radar/src/components/RadarPage.test.tsx b/plugins/tech-radar/src/components/RadarPage.test.tsx index c318985acd..97fae16380 100644 --- a/plugins/tech-radar/src/components/RadarPage.test.tsx +++ b/plugins/tech-radar/src/components/RadarPage.test.tsx @@ -19,11 +19,10 @@ import { render, waitForElement } from '@testing-library/react'; import { ThemeProvider } from '@material-ui/core'; import { lightTheme } from '@backstage/theme'; import { ApiRegistry, ApiProvider, errorApiRef } from '@backstage/core'; -import { withLogCollector } from '@backstage/test-utils-core'; import GetBBoxPolyfill from '../utils/polyfills/getBBox'; -import { techRadarApiRef, TechRadar } from '../index'; -import RadarPage from './RadarPage'; +import { RadarPage } from './RadarPage'; +import { MockErrorApi, wrapInTestApp } from '@backstage/test-utils'; describe('RadarPage', () => { beforeAll(() => { @@ -35,24 +34,18 @@ describe('RadarPage', () => { }); it('should render a progress bar', async () => { - const errorApi = { post: () => {} }; - const techRadarApi = new TechRadar({ + const techRadarProps = { width: 1200, height: 800, svgProps: { 'data-testid': 'tech-radar-svg' }, - }); + }; const { getByTestId, queryByTestId } = render( - - - - - , + wrapInTestApp( + + + , + ), ); expect(getByTestId('progress')).toBeInTheDocument(); @@ -61,24 +54,18 @@ describe('RadarPage', () => { }); it('should render a header with a svg', async () => { - const errorApi = { post: () => {} }; - const techRadarApi = new TechRadar({ + const techRadarProps = { width: 1200, height: 800, svgProps: { 'data-testid': 'tech-radar-svg' }, - }); + }; const { getByText, getByTestId } = render( - - - - - , + wrapInTestApp( + + + , + ), ); await waitForElement(() => getByTestId('tech-radar-svg')); @@ -90,78 +77,29 @@ describe('RadarPage', () => { }); it('should call the errorApi if load fails', async () => { - const errorApi = { post: jest.fn() }; + const errorApi = new MockErrorApi({ collect: true }); const techRadarLoadFail = () => Promise.reject(new Error('404 Page Not Found')); - const techRadarApi = new TechRadar({ + const techRadarProps = { width: 1200, height: 800, getData: techRadarLoadFail, svgProps: { 'data-testid': 'tech-radar-svg' }, - }); + }; const { queryByTestId } = render( - - + + , ); await waitForElement(() => !queryByTestId('progress')); - expect(errorApi.post).toHaveBeenCalledTimes(1); - expect(errorApi.post).toHaveBeenCalledWith(new Error('404 Page Not Found')); + expect(errorApi.getErrors()).toEqual([ + { error: new Error('404 Page Not Found'), context: undefined }, + ]); expect(queryByTestId('tech-radar-svg')).not.toBeInTheDocument(); }); - - it('should not render without errorApiRef', () => { - const techRadarApi = new TechRadar({ - width: 1200, - height: 800, - }); - - expect( - withLogCollector(['error'], () => { - expect(() => { - render( - - - - - , - ); - }).toThrow(); - }).error[0], - ).toMatch( - /^Error: Uncaught \[Error: No implementation available for apiRef{core.error}\]/, - ); - }); - - it('should not render without techRadarApiRef', () => { - const errorApi = { post: () => {} }; - - expect( - withLogCollector(['error'], () => { - expect(() => { - render( - - - - - , - ); - }).toThrow(); - }).error[0], - ).toMatch( - /^Error: Uncaught \[Error: No implementation available for apiRef{plugin.techradar}\]/, - ); - }); }); diff --git a/plugins/tech-radar/src/components/RadarPage.tsx b/plugins/tech-radar/src/components/RadarPage.tsx index 1aefb72eca..519c9afeee 100644 --- a/plugins/tech-radar/src/components/RadarPage.tsx +++ b/plugins/tech-radar/src/components/RadarPage.tsx @@ -24,36 +24,46 @@ import { HeaderLabel, SupportButton, pageTheme, - useApi, } from '@backstage/core'; import RadarComponent from '../components/RadarComponent'; -import { techRadarApiRef, TechRadarApi } from '../api'; +import { TechRadarComponentProps } from '../api'; -const RadarPage = (): JSX.Element => { - const techRadarApi = useApi(techRadarApiRef); - - return ( - -
- - -
- - - - This is used for visualizing the official guidelines of different - areas of software development such as languages, frameworks, - infrastructure and processes. - - - - - - - - -
- ); +export type TechRadarPageProps = TechRadarComponentProps & { + title?: string; + subtitle?: string; + pageTitle?: string; }; -export default RadarPage; +export const RadarPage = ({ + title, + subtitle, + pageTitle, + ...props +}: TechRadarPageProps): JSX.Element => ( + +
+ + +
+ + + + This is used for visualizing the official guidelines of different + areas of software development such as languages, frameworks, + infrastructure and processes. + + + + + + + + +
+); + +RadarPage.defaultProps = { + title: 'Tech Radar', + subtitle: 'Pick the recommended technologies for your projects', + pageTitle: 'Company Radar', +}; diff --git a/plugins/tech-radar/src/index.ts b/plugins/tech-radar/src/index.ts index df22e57558..d7b4921e9a 100644 --- a/plugins/tech-radar/src/index.ts +++ b/plugins/tech-radar/src/index.ts @@ -16,6 +16,8 @@ export { plugin } from './plugin'; +export { RadarPage as Router } from './components/RadarPage'; + /** * The TypeScript API for configuring Tech Radar. */ diff --git a/plugins/tech-radar/src/plugin.ts b/plugins/tech-radar/src/plugin.ts index 3497a66f5d..d8dc41af2e 100644 --- a/plugins/tech-radar/src/plugin.ts +++ b/plugins/tech-radar/src/plugin.ts @@ -15,11 +15,7 @@ */ import { createPlugin } from '@backstage/core'; -import RadarPage from './components/RadarPage'; export const plugin = createPlugin({ id: 'tech-radar', - register({ router }) { - router.registerRoute('/tech-radar', RadarPage); - }, }); diff --git a/plugins/techdocs-backend/README.md b/plugins/techdocs-backend/README.md index 6a54971788..2185c3b3e4 100644 --- a/plugins/techdocs-backend/README.md +++ b/plugins/techdocs-backend/README.md @@ -14,9 +14,6 @@ To evaluate TechDocs and have a greater amount of functionality available, inste # in one terminal window, run this from from the very root of the Backstage project cd packages/backend yarn start - -# open another terminal window, and run the following from the very root of the Backstage project -yarn lerna run mock-data ``` ## What techdocs-backend does diff --git a/plugins/techdocs-backend/package.json b/plugins/techdocs-backend/package.json index 00650ccca8..47b2ebc8aa 100644 --- a/plugins/techdocs-backend/package.json +++ b/plugins/techdocs-backend/package.json @@ -17,8 +17,7 @@ "test": "backstage-cli test", "prepack": "backstage-cli prepack", "postpack": "backstage-cli postpack", - "clean": "backstage-cli clean", - "mock-data": "./scripts/mock-data.sh" + "clean": "backstage-cli clean" }, "dependencies": { "@backstage/backend-common": "^0.1.1-alpha.21", @@ -26,6 +25,7 @@ "@backstage/config": "^0.1.1-alpha.21", "@types/dockerode": "^2.5.34", "@types/express": "^4.17.6", + "default-branch": "^1.0.8", "dockerode": "^3.2.1", "express": "^4.17.1", "express-promise-router": "^3.0.3", diff --git a/plugins/techdocs-backend/scripts/mock-data.sh b/plugins/techdocs-backend/scripts/mock-data.sh deleted file mode 100755 index 0630490694..0000000000 --- a/plugins/techdocs-backend/scripts/mock-data.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash - -for URL in \ - 'documented-component/documented-component.yaml' \ -; do \ - curl \ - --location \ - --request POST 'localhost:7000/catalog/locations' \ - --header 'Content-Type: application/json' \ - --data-raw "{\"type\": \"file\", \"target\": \"$(pwd)/examples/${URL}\"}" - echo -done diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts b/plugins/techdocs-backend/src/helpers.ts similarity index 54% rename from plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts rename to plugins/techdocs-backend/src/helpers.ts index d962242262..14f4d490ba 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/helpers.ts +++ b/plugins/techdocs-backend/src/helpers.ts @@ -13,14 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; -import { InputError } from '@backstage/backend-common'; -import { RemoteProtocol } from './types'; + +import os from 'os'; +import path from 'path'; import parseGitUrl from 'git-url-parse'; import { Clone, Repository } from 'nodegit'; import fs from 'fs-extra'; -import os from 'os'; -import path from 'path'; +// @ts-ignore +import defaultBranch from 'default-branch'; +import { Entity } from '@backstage/catalog-model'; +import { InputError } from '@backstage/backend-common'; +import { RemoteProtocol } from './techdocs/stages/prepare/types'; +import { Logger } from 'winston'; export type ParsedLocationAnnotation = { type: RemoteProtocol; @@ -58,16 +62,43 @@ export const parseReferenceAnnotation = ( }; }; -export const clearGithubRepositoryCache = () => { - fs.removeSync(path.join(fs.realpathSync(os.tmpdir()), 'backstage-repo')); +export const getLocationForEntity = ( + entity: Entity, +): ParsedLocationAnnotation => { + const { type, target } = parseReferenceAnnotation( + 'backstage.io/techdocs-ref', + entity, + ); + + switch (type) { + case 'github': + return { type, target }; + case 'dir': + if (path.isAbsolute(target)) return { type, target }; + + return parseReferenceAnnotation( + 'backstage.io/managed-by-location', + entity, + ); + default: + throw new Error(`Invalid reference annotation ${type}`); + } }; -export const checkoutGitRepository = async ( - repoUrl: string, +export const getGitHubRepositoryTempFolder = async ( + repositoryUrl: string, ): Promise => { - const parsedGitLocation = parseGitUrl(repoUrl); + const parsedGitLocation = parseGitUrl(repositoryUrl); + // removes .git from git location path + parsedGitLocation.git_suffix = false; - const repositoryTmpPath = path.join( + if (!parsedGitLocation.ref) { + parsedGitLocation.ref = await defaultBranch( + parsedGitLocation.toString('https'), + ); + } + + return path.join( // fs.realpathSync fixes a problem with macOS returning a path that is a symlink fs.realpathSync(os.tmpdir()), 'backstage-repo', @@ -76,53 +107,37 @@ export const checkoutGitRepository = async ( parsedGitLocation.name, parsedGitLocation.ref, ); - - if (fs.existsSync(repositoryTmpPath)) { - const repository = await Repository.open(repositoryTmpPath); - const currentBranchName = (await repository.getCurrentBranch()).shorthand(); - await repository.mergeBranches( - currentBranchName, - `origin/${currentBranchName}`, - ); - return repositoryTmpPath; - } - - const repositoryCheckoutUrl = parsedGitLocation.toString('https'); - - fs.mkdirSync(repositoryTmpPath, { recursive: true }); - await Clone.clone(repositoryCheckoutUrl, repositoryTmpPath, {}); - - return repositoryTmpPath; }; -// Could be merged with checkoutGitRepository export const checkoutGithubRepository = async ( repoUrl: string, + logger: Logger, ): Promise => { const parsedGitLocation = parseGitUrl(repoUrl); + const repositoryTmpPath = await getGitHubRepositoryTempFolder(repoUrl); - // Should propably not be hardcoded names of env variables, but seems too hard to access config down here + // TODO: Should propably not be hardcoded names of env variables, but seems too hard to access config down here const user = process.env.GITHUB_PRIVATE_TOKEN_USER || ''; const token = process.env.GITHUB_PRIVATE_TOKEN || ''; - const repositoryTmpPath = path.join( - // fs.realpathSync fixes a problem with macOS returning a path that is a symlink - fs.realpathSync(os.tmpdir()), - 'backstage-repo', - parsedGitLocation.source, - parsedGitLocation.owner, - parsedGitLocation.name, - parsedGitLocation.ref, - ); - if (fs.existsSync(repositoryTmpPath)) { - const repository = await Repository.open(repositoryTmpPath); - const currentBranchName = (await repository.getCurrentBranch()).shorthand(); - await repository.mergeBranches( - currentBranchName, - `origin/${currentBranchName}`, - ); - return repositoryTmpPath; + try { + const repository = await Repository.open(repositoryTmpPath); + const currentBranchName = ( + await repository.getCurrentBranch() + ).shorthand(); + await repository.fetch('origin'); + await repository.mergeBranches( + currentBranchName, + `origin/${currentBranchName}`, + ); + return repositoryTmpPath; + } catch (e) { + logger.info( + `Found error "${e.message}" in cached repository "${repoUrl}" when getting latest changes. Removing cached repository.`, + ); + fs.removeSync(repositoryTmpPath); + } } if (user && token) { @@ -136,3 +151,18 @@ export const checkoutGithubRepository = async ( return repositoryTmpPath; }; + +export const getLastCommitTimestamp = async ( + repositoryUrl: string, + logger: Logger, +): Promise => { + const repositoryLocation = await checkoutGithubRepository( + repositoryUrl, + logger, + ); + + const repository = await Repository.open(repositoryLocation); + const commit = await repository.getReferenceCommit('HEAD'); + + return commit.date().getTime(); +}; diff --git a/plugins/techdocs-backend/src/service/helpers.ts b/plugins/techdocs-backend/src/service/helpers.ts new file mode 100644 index 0000000000..60c76e6384 --- /dev/null +++ b/plugins/techdocs-backend/src/service/helpers.ts @@ -0,0 +1,132 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import Docker from 'dockerode'; +import { Logger } from 'winston'; +import { Entity } from '@backstage/catalog-model'; +import { + PreparerBuilder, + PublisherBase, + GeneratorBuilder, + PreparerBase, + GeneratorBase, +} from '../techdocs'; +import { BuildMetadataStorage } from '../storage'; +import { getLocationForEntity, getLastCommitTimestamp } from '../helpers'; + +const getEntityId = (entity: Entity) => { + return `${entity.kind}:${entity.metadata.namespace ?? ''}:${ + entity.metadata.name + }`; +}; + +type DocsBuilderArguments = { + preparers: PreparerBuilder; + generators: GeneratorBuilder; + publisher: PublisherBase; + entity: Entity; + logger: Logger; + dockerClient: Docker; +}; + +export class DocsBuilder { + private preparer: PreparerBase; + private generator: GeneratorBase; + private publisher: PublisherBase; + private entity: Entity; + private logger: Logger; + private dockerClient: Docker; + + constructor({ + preparers, + generators, + publisher, + entity, + logger, + dockerClient, + }: DocsBuilderArguments) { + this.preparer = preparers.get(entity); + this.generator = generators.get(entity); + this.publisher = publisher; + this.entity = entity; + this.logger = logger; + this.dockerClient = dockerClient; + } + + public async build() { + this.logger.info( + `[TechDocs] Running preparer on entity ${getEntityId(this.entity)}`, + ); + const preparedDir = await this.preparer.prepare(this.entity); + + this.logger.info( + `[TechDocs] Running generator on entity ${getEntityId(this.entity)}`, + ); + const { resultDir } = await this.generator.run({ + directory: preparedDir, + dockerClient: this.dockerClient, + }); + + this.logger.info( + `[TechDocs] Running publisher on entity ${getEntityId(this.entity)}`, + ); + await this.publisher.publish({ + entity: this.entity, + directory: resultDir, + }); + + if (!this.entity.metadata.uid) { + throw new Error( + 'Trying to build documentation for entity not in service catalog', + ); + } + + new BuildMetadataStorage(this.entity.metadata.uid).storeBuildTimestamp(); + } + + public async docsUpToDate() { + if (!this.entity.metadata.uid) { + throw new Error( + 'Trying to build documentation for entity not in service catalog', + ); + } + + const buildMetadataStorage = new BuildMetadataStorage( + this.entity.metadata.uid, + ); + const { type, target } = getLocationForEntity(this.entity); + + // Should probably be broken out and handled per type later. Doing this for now since we only support github age checks + if (type === 'github') { + const lastCommit = await getLastCommitTimestamp(target, this.logger); + const storageTimeStamp = buildMetadataStorage.getTimestamp(); + + // Check if documentation source is newer than what we have + if (storageTimeStamp && storageTimeStamp >= lastCommit) { + this.logger.debug( + `[TechDocs] Docs for entity ${getEntityId( + this.entity, + )} is up to date.`, + ); + return true; + } + } + + this.logger.debug( + `[TechDocs] Docs for entity ${getEntityId(this.entity)} was outdated.`, + ); + return false; + } +} diff --git a/plugins/techdocs-backend/src/service/router.test.ts b/plugins/techdocs-backend/src/service/router.test.ts deleted file mode 100644 index c266f98677..0000000000 --- a/plugins/techdocs-backend/src/service/router.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { getVoidLogger } from '@backstage/backend-common'; -import { Preparers, LocalPublish, Generators } from '../techdocs'; -import { ConfigReader } from '@backstage/config'; -import Docker from 'dockerode'; -import express from 'express'; -import request from 'supertest'; -import { createRouter } from './router'; - -describe('createRouter', () => { - let app: express.Express; - const logger = getVoidLogger(); - - beforeAll(async () => { - const router = await createRouter({ - preparers: new Preparers(), - generators: new Generators(), - publisher: new LocalPublish(logger), - logger: getVoidLogger(), - dockerClient: new Docker(), - config: ConfigReader.fromConfigs([]), - }); - app = express().use(router); - }); - - describe('GET /', () => { - it('does not explode', async () => { - const response = await request(app).get('/'); - - expect(response.status).toEqual(200); - expect(response.text).toEqual('Hello TechDocs Backend'); - }); - }); -}); diff --git a/plugins/techdocs-backend/src/service/router.ts b/plugins/techdocs-backend/src/service/router.ts index bb26ea19b8..e0a066c168 100644 --- a/plugins/techdocs-backend/src/service/router.ts +++ b/plugins/techdocs-backend/src/service/router.ts @@ -28,6 +28,7 @@ import { } from '../techdocs'; import { resolvePackagePath } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; +import { DocsBuilder } from './helpers'; type RouterOptions = { preparers: PreparerBuilder; @@ -54,77 +55,36 @@ export async function createRouter({ }: RouterOptions): Promise { const router = Router(); - const getEntityId = (entity: Entity) => { - return `${entity.kind}:${entity.metadata.namespace ?? ''}:${ - entity.metadata.name - }`; - }; - - const buildDocsForEntity = async (entity: Entity) => { - const preparer = preparers.get(entity); - const generator = generators.get(entity); - - logger.info(`[TechDocs] Running preparer on entity ${getEntityId(entity)}`); - const preparedDir = await preparer.prepare(entity); - - logger.info( - `[TechDocs] Running generator on entity ${getEntityId(entity)}`, - ); - const { resultDir } = await generator.run({ - directory: preparedDir, - dockerClient, - }); - - logger.info( - `[TechDocs] Running publisher on entity ${getEntityId(entity)}`, - ); - await publisher.publish({ - entity, - directory: resultDir, - }); - }; - - router.get('/', async (_, res) => { - res.status(200).send('Hello TechDocs Backend'); - }); - - // TODO: This route should not exist in the future - router.get('/buildall', async (_, res) => { + router.get('/docs/:kind/:namespace/:name/*', async (req, res) => { const baseUrl = config.getString('backend.baseUrl'); - const entitiesResponse = (await ( - await fetch(`${baseUrl}/catalog/entities`) - ).json()) as Entity[]; + const storageUrl = config.getString('techdocs.storageUrl'); - const entitiesWithDocs = entitiesResponse.filter( - entity => entity.metadata.annotations?.['backstage.io/techdocs-ref'], - ); + const { kind, namespace, name } = req.params; - entitiesWithDocs.forEach(async entity => { - await buildDocsForEntity(entity); + const entity = (await ( + await fetch( + `${baseUrl}/catalog/entities/by-name/${kind}/${namespace}/${name}`, + ) + ).json()) as Entity; + + const docsBuilder = new DocsBuilder({ + preparers, + generators, + publisher, + dockerClient, + logger, + entity, }); - res.send('Successfully generated documentation'); + if (!(await docsBuilder.docsUpToDate())) { + await docsBuilder.build(); + } + + return res.redirect(`${storageUrl}${req.path.replace('/docs', '')}`); }); if (publisher instanceof LocalPublish) { - router.use('/static/docs/', express.static(staticDocsDir)); - router.use( - '/static/docs/:kind/:namespace/:name', - async (req, res, next) => { - const baseUrl = config.getString('backend.baseUrl'); - const { kind, namespace, name } = req.params; - - const entityResponse = await fetch( - `${baseUrl}/catalog/entities/by-name/${kind}/${namespace}/${name}`, - ); - if (!entityResponse.ok) next(); - const entity = (await entityResponse.json()) as Entity; - - await buildDocsForEntity(entity); - - res.redirect(req.originalUrl); - }, - ); + router.use('/static/docs', express.static(staticDocsDir)); } return router; diff --git a/plugins/circleci/src/state/types.ts b/plugins/techdocs-backend/src/storage/BuildMetadataStorage.ts similarity index 58% rename from plugins/circleci/src/state/types.ts rename to plugins/techdocs-backend/src/storage/BuildMetadataStorage.ts index 41b3577082..b82ec1291a 100644 --- a/plugins/circleci/src/state/types.ts +++ b/plugins/techdocs-backend/src/storage/BuildMetadataStorage.ts @@ -13,24 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -export type Settings = { owner: string; repo: string; token: string }; -export type SettingsState = Settings & { - showSettings: boolean; +type buildInfo = { + // uid: timestamp + [key: string]: number; }; -export type State = SettingsState; +const builds = {} as buildInfo; -type SettingsAction = - | { - type: 'setCredentials'; - payload: { - repo: string; - owner: string; - token: string; - }; - } - | { type: 'showSettings' } - | { type: 'hideSettings' }; +export class BuildMetadataStorage { + public entityUid: string; + private builds: buildInfo; -export type Action = SettingsAction; + constructor(entityUid: string) { + this.entityUid = entityUid; + this.builds = builds; + } + + storeBuildTimestamp() { + this.builds[this.entityUid] = Date.now(); + } + + getTimestamp() { + return this.builds[this.entityUid]; + } +} diff --git a/plugins/circleci/src/components/PluginHeader/index.ts b/plugins/techdocs-backend/src/storage/index.ts similarity index 93% rename from plugins/circleci/src/components/PluginHeader/index.ts rename to plugins/techdocs-backend/src/storage/index.ts index 4de972f6f2..3d37f69679 100644 --- a/plugins/circleci/src/components/PluginHeader/index.ts +++ b/plugins/techdocs-backend/src/storage/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './PluginHeader'; +export * from './BuildMetadataStorage'; diff --git a/plugins/techdocs-backend/src/techdocs/stages/generate/index.ts b/plugins/techdocs-backend/src/techdocs/stages/generate/index.ts index 5c086a976a..3a8b9ad828 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/generate/index.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/generate/index.ts @@ -15,4 +15,4 @@ */ export { TechdocsGenerator } from './techdocs'; export { Generators } from './generators'; -export type { GeneratorBuilder } from './types'; +export type { GeneratorBuilder, GeneratorBase } from './types'; diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.test.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.test.ts index 1635995b9e..e2b94d7e88 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.test.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.test.ts @@ -15,11 +15,20 @@ */ import { DirectoryPreparer } from './dir'; import { getVoidLogger } from '@backstage/backend-common'; -import { checkoutGitRepository } from './helpers'; +import { checkoutGithubRepository } from '../../../helpers'; -jest.mock('./helpers', () => ({ - ...jest.requireActual<{}>('./helpers'), - checkoutGitRepository: jest.fn(() => '/tmp/backstage-repo/org/name/branch/'), +function normalizePath(path: string) { + return path + .replace(/^[a-z]:/i, '') + .split('\\') + .join('/'); +} + +jest.mock('../../../helpers', () => ({ + ...jest.requireActual<{}>('../../../helpers'), + checkoutGithubRepository: jest.fn( + () => '/tmp/backstage-repo/org/name/branch/', + ), })); const logger = getVoidLogger(); @@ -47,7 +56,7 @@ describe('directory preparer', () => { 'backstage.io/techdocs-ref': 'dir:./our-documentation', }); - expect(await directoryPreparer.prepare(mockEntity)).toEqual( + expect(normalizePath(await directoryPreparer.prepare(mockEntity))).toEqual( '/directory/our-documentation', ); }); @@ -61,7 +70,7 @@ describe('directory preparer', () => { 'backstage.io/techdocs-ref': 'dir:/our-documentation/techdocs', }); - expect(await directoryPreparer.prepare(mockEntity)).toEqual( + expect(normalizePath(await directoryPreparer.prepare(mockEntity))).toEqual( '/our-documentation/techdocs', ); }); @@ -75,9 +84,9 @@ describe('directory preparer', () => { 'backstage.io/techdocs-ref': 'dir:./docs', }); - expect(await directoryPreparer.prepare(mockEntity)).toEqual( + expect(normalizePath(await directoryPreparer.prepare(mockEntity))).toEqual( '/tmp/backstage-repo/org/name/branch/docs', ); - expect(checkoutGitRepository).toHaveBeenCalledTimes(1); + expect(checkoutGithubRepository).toHaveBeenCalledTimes(1); }); }); diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts index cc0416c331..5fd4abb4bd 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/dir.ts @@ -16,7 +16,10 @@ import { PreparerBase } from './types'; import { Entity } from '@backstage/catalog-model'; import path from 'path'; -import { parseReferenceAnnotation, checkoutGitRepository } from './helpers'; +import { + parseReferenceAnnotation, + checkoutGithubRepository, +} from '../../../helpers'; import { InputError } from '@backstage/backend-common'; import parseGitUrl from 'git-url-parse'; import { Logger } from 'winston'; @@ -40,7 +43,10 @@ export class DirectoryPreparer implements PreparerBase { switch (type) { case 'github': { const parsedGitLocation = parseGitUrl(target); - const repoLocation = await checkoutGitRepository(target); + const repoLocation = await checkoutGithubRepository( + target, + this.logger, + ); return path.dirname( path.join(repoLocation, parsedGitLocation.filepath), diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/github.test.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/github.test.ts index 99a7d3bb5c..a188e1c986 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/github.test.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/github.test.ts @@ -16,10 +16,17 @@ import { getVoidLogger } from '@backstage/backend-common'; import { GithubPreparer } from './github'; -import { checkoutGithubRepository } from './helpers'; +import { checkoutGithubRepository } from '../../../helpers'; -jest.mock('./helpers', () => ({ - ...jest.requireActual<{}>('./helpers'), +function normalizePath(path: string) { + return path + .replace(/^[a-z]:/i, '') + .split('\\') + .join('/'); +} + +jest.mock('../../../helpers', () => ({ + ...jest.requireActual<{}>('../../../helpers'), checkoutGithubRepository: jest.fn( () => '/tmp/backstage-repo/org/name/branch', ), @@ -51,7 +58,7 @@ describe('github preparer', () => { const tempDocsPath = await preparer.prepare(mockEntity); expect(checkoutGithubRepository).toHaveBeenCalledTimes(1); - expect(tempDocsPath).toEqual( + expect(normalizePath(tempDocsPath)).toEqual( '/tmp/backstage-repo/org/name/branch/plugins/techdocs-backend/examples/documented-component', ); }); diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/github.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/github.ts index 242b19c24d..03b0adcb88 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/github.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/github.ts @@ -18,7 +18,11 @@ import { Entity } from '@backstage/catalog-model'; import { InputError } from '@backstage/backend-common'; import { PreparerBase } from './types'; import parseGitUrl from 'git-url-parse'; -import { parseReferenceAnnotation, checkoutGithubRepository } from './helpers'; +import { + parseReferenceAnnotation, + checkoutGithubRepository, +} from '../../../helpers'; + import { Logger } from 'winston'; export class GithubPreparer implements PreparerBase { @@ -39,7 +43,7 @@ export class GithubPreparer implements PreparerBase { } try { - const repoPath = await checkoutGithubRepository(target); + const repoPath = await checkoutGithubRepository(target, this.logger); const parsedGitLocation = parseGitUrl(target); return path.join(repoPath, parsedGitLocation.filepath); diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/index.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/index.ts index 535b56f327..48ffa75903 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/index.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/index.ts @@ -16,4 +16,4 @@ export { DirectoryPreparer } from './dir'; export { GithubPreparer } from './github'; export { Preparers } from './preparers'; -export type { PreparerBuilder } from './types'; +export type { PreparerBuilder, PreparerBase } from './types'; diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/preparers.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/preparers.ts index 1c8fadd145..2f0df47de4 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/preparers.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/preparers.ts @@ -16,7 +16,7 @@ import { PreparerBase, RemoteProtocol, PreparerBuilder } from './types'; import { Entity } from '@backstage/catalog-model'; -import { parseReferenceAnnotation } from './helpers'; +import { parseReferenceAnnotation } from '../../../helpers'; export class Preparers implements PreparerBuilder { private preparerMap = new Map(); diff --git a/plugins/techdocs-backend/src/techdocs/stages/prepare/types.ts b/plugins/techdocs-backend/src/techdocs/stages/prepare/types.ts index 8baf6347bb..1ceb884ea8 100644 --- a/plugins/techdocs-backend/src/techdocs/stages/prepare/types.ts +++ b/plugins/techdocs-backend/src/techdocs/stages/prepare/types.ts @@ -30,4 +30,4 @@ export type PreparerBuilder = { get(entity: Entity): PreparerBase; }; -export type RemoteProtocol = 'dir' | string; +export type RemoteProtocol = 'dir' | 'github' | 'file'; diff --git a/plugins/techdocs/dev/index.tsx b/plugins/techdocs/dev/index.tsx index b415256fde..12974ef8b7 100644 --- a/plugins/techdocs/dev/index.tsx +++ b/plugins/techdocs/dev/index.tsx @@ -20,13 +20,13 @@ import { TechDocsDevStorageApi } from './api'; import { techdocsStorageApiRef } from '../src'; createDevApp() - .registerApiFactory({ + .registerApi({ + api: techdocsStorageApiRef, deps: {}, factory: () => new TechDocsDevStorageApi({ apiOrigin: 'http://localhost:3000/api', }), - implements: techdocsStorageApiRef, }) .registerPlugin(plugin) .render(); diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 2d63c9dd53..a3471c8142 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -28,7 +28,7 @@ "@backstage/plugin-catalog": "^0.1.1-alpha.21", "@backstage/test-utils": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "@types/react": "^16.9", diff --git a/plugins/catalog/src/components/EntityPageDocs/EntityDocsPage.tsx b/plugins/techdocs/src/EntityPageDocs.tsx similarity index 72% rename from plugins/catalog/src/components/EntityPageDocs/EntityDocsPage.tsx rename to plugins/techdocs/src/EntityPageDocs.tsx index ceba7e3200..d10c7a5932 100644 --- a/plugins/catalog/src/components/EntityPageDocs/EntityDocsPage.tsx +++ b/plugins/techdocs/src/EntityPageDocs.tsx @@ -16,19 +16,16 @@ import React from 'react'; import { Entity } from '@backstage/catalog-model'; -import { Reader } from '@backstage/plugin-techdocs'; -import { Content } from '@backstage/core'; +import { Reader } from './reader'; export const EntityPageDocs = ({ entity }: { entity: Entity }) => { return ( - - - + ); }; diff --git a/plugins/techdocs/src/Router.tsx b/plugins/techdocs/src/Router.tsx new file mode 100644 index 0000000000..6dc0dd02ad --- /dev/null +++ b/plugins/techdocs/src/Router.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { Entity } from '@backstage/catalog-model'; +import { Route, Routes } from 'react-router-dom'; +import { WarningPanel } from '@backstage/core'; + +import { + rootRouteRef, + rootDocsRouteRef, + rootCatalogDocsRouteRef, +} from './plugin'; +import { TechDocsHome } from './reader/components/TechDocsHome'; +import { TechDocsPage } from './reader/components/TechDocsPage'; +import { EntityPageDocs } from './EntityPageDocs'; + +const TECHDOCS_ANNOTATION = 'backstage.io/techdocs-ref'; + +export const Router = () => { + return ( + + } /> + } /> + + ); +}; + +export const EmbeddedDocsRouter = ({ entity }: { entity: Entity }) => { + const projectId = entity.metadata.annotations?.[TECHDOCS_ANNOTATION]; + + if (!projectId) { + return ( + +
{TECHDOCS_ANNOTATION}
annotation is missing on the entity. +
+ + Getting Started + + + ); + } + + return ( + + } + /> + + ); +}; diff --git a/plugins/techdocs/src/api.ts b/plugins/techdocs/src/api.ts index 951ad5e16c..6fc913e5df 100644 --- a/plugins/techdocs/src/api.ts +++ b/plugins/techdocs/src/api.ts @@ -42,7 +42,9 @@ export class TechDocsStorageApi implements TechDocsStorage { async getEntityDocs(entityId: ParsedEntityId, path: string) { const { kind, namespace, name } = entityId; - const url = `${this.apiOrigin}/${kind}/${namespace ? namespace : 'default'}/${name}/${path}`; + const url = `${this.apiOrigin}/${kind}/${ + namespace ? namespace : 'default' + }/${name}/${path}`; const request = await fetch( `${url.endsWith('/') ? url : `${url}/`}index.html`, @@ -64,7 +66,9 @@ export class TechDocsStorageApi implements TechDocsStorage { return new URL( oldBaseUrl, - `${this.apiOrigin}/${kind}/${namespace ? namespace : 'default'}/${name}/${path}`, + `${this.apiOrigin}/${kind}/${ + namespace ? namespace : 'default' + }/${name}/${path}`, ).toString(); } } diff --git a/plugins/techdocs/src/index.ts b/plugins/techdocs/src/index.ts index 2a412d1b20..1726e0daf3 100644 --- a/plugins/techdocs/src/index.ts +++ b/plugins/techdocs/src/index.ts @@ -15,5 +15,6 @@ */ export { plugin } from './plugin'; +export { Router, EmbeddedDocsRouter } from './Router'; export * from './reader'; export * from './api'; diff --git a/plugins/techdocs/src/plugin.ts b/plugins/techdocs/src/plugin.ts index 9b09544427..1f15e9ebd6 100644 --- a/plugins/techdocs/src/plugin.ts +++ b/plugins/techdocs/src/plugin.ts @@ -29,24 +29,39 @@ * limitations under the License. */ -import { createPlugin, createRouteRef } from '@backstage/core'; -import { TechDocsHome } from './reader/components/TechDocsHome'; -import { TechDocsPage } from './reader/components/TechDocsPage'; +import { + createPlugin, + createRouteRef, + createApiFactory, + configApiRef, +} from '@backstage/core'; +import { techdocsStorageApiRef, TechDocsStorageApi } from './api'; export const rootRouteRef = createRouteRef({ - path: '/docs', + path: '', title: 'TechDocs Landing Page', }); export const rootDocsRouteRef = createRouteRef({ - path: '/docs/:entityId/*', + path: ':entityId/*', + title: 'Docs', +}); + +export const rootCatalogDocsRouteRef = createRouteRef({ + path: '*', title: 'Docs', }); export const plugin = createPlugin({ id: 'techdocs', - register({ router }) { - router.addRoute(rootRouteRef, TechDocsHome); - router.addRoute(rootDocsRouteRef, TechDocsPage); - }, + apis: [ + createApiFactory({ + api: techdocsStorageApiRef, + deps: { configApi: configApiRef }, + factory: ({ configApi }) => + new TechDocsStorageApi({ + apiOrigin: configApi.getString('techdocs.requestUrl'), + }), + }), + ], }); diff --git a/plugins/techdocs/src/reader/components/TechDocsHome.tsx b/plugins/techdocs/src/reader/components/TechDocsHome.tsx index 17b9fd36f7..e51de8f57f 100644 --- a/plugins/techdocs/src/reader/components/TechDocsHome.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsHome.tsx @@ -16,11 +16,12 @@ import React from 'react'; import { useAsync } from 'react-use'; -import { useNavigate } from 'react-router-dom'; +import { useNavigate, generatePath } from 'react-router-dom'; import { Grid } from '@material-ui/core'; import { ItemCard, Progress, useApi } from '@backstage/core'; import { TechDocsPageWrapper } from './TechDocsPageWrapper'; import { catalogApiRef } from '@backstage/plugin-catalog'; +import { rootDocsRouteRef } from '../../plugin'; export const TechDocsHome = () => { const catalogApi = useApi(catalogApiRef); @@ -67,9 +68,11 @@ export const TechDocsHome = () => { navigate( - `/docs/${entity.kind}:${ - entity.metadata.namespace ?? '' - }:${entity.metadata.name}`, + generatePath(rootDocsRouteRef.path, { + entityId: `${entity.kind}:${ + entity.metadata.namespace ?? '' + }:${entity.metadata.name}`, + }), ) } title={entity.metadata.name} diff --git a/plugins/techdocs/src/reader/transformers/addLinkClickListener.ts b/plugins/techdocs/src/reader/transformers/addLinkClickListener.ts index 93e4b67a1b..3566b403a2 100644 --- a/plugins/techdocs/src/reader/transformers/addLinkClickListener.ts +++ b/plugins/techdocs/src/reader/transformers/addLinkClickListener.ts @@ -26,9 +26,11 @@ export const addLinkClickListener = ({ return dom => { Array.from(dom.getElementsByTagName('a')).forEach(elem => { elem.addEventListener('click', (e: MouseEvent) => { - e.preventDefault(); const target = e.target as HTMLAnchorElement; - if (target?.getAttribute('href')) { + const href = target?.getAttribute('href'); + if (!href) return; + if (!href.match(/^https?:\/\//i)) { + e.preventDefault(); onClick(e, target.getAttribute('href')!); } }); diff --git a/plugins/techdocs/src/reader/transformers/rewriteDocLinks.ts b/plugins/techdocs/src/reader/transformers/rewriteDocLinks.ts index 856bb40f0f..7b0c23c3e3 100644 --- a/plugins/techdocs/src/reader/transformers/rewriteDocLinks.ts +++ b/plugins/techdocs/src/reader/transformers/rewriteDocLinks.ts @@ -27,6 +27,10 @@ export const rewriteDocLinks = (): Transformer => { .forEach((elem: T) => { const elemAttribute = elem.getAttribute(attributeName); if (elemAttribute) { + // if link is external, add target to open in a new window or tab + if (elemAttribute.match(/^https?:\/\//i)) { + elem.setAttribute('target', '_blank'); + } const normalizedWindowLocation = window.location.href.endsWith('/') ? window.location.href : `${window.location.href}/`; diff --git a/plugins/welcome/README.md b/plugins/welcome/README.md index 95d8947824..f0211c248a 100644 --- a/plugins/welcome/README.md +++ b/plugins/welcome/README.md @@ -1,4 +1,5 @@ # Title + Welcome to the welcome plugin! ## Sub-section 1 diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index 2d754a51a6..a0dae6859d 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -23,7 +23,7 @@ "dependencies": { "@backstage/core": "^0.1.1-alpha.21", "@backstage/theme": "^0.1.1-alpha.21", - "@material-ui/core": "^4.9.1", + "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", "react": "^16.13.1", diff --git a/tsconfig.json b/tsconfig.json index 7ea674798c..d6cb6f4c96 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,7 @@ "plugins/*/migrations" ], "compilerOptions": { - "outDir": "dist", + "outDir": "dist-types", "rootDir": "." } } diff --git a/yarn.lock b/yarn.lock index 4d544e2275..38f5d6c799 100644 --- a/yarn.lock +++ b/yarn.lock @@ -95,13 +95,6 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/code-frame@7.5.5": - version "7.5.5" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== - dependencies: - "@babel/highlight" "^7.0.0" - "@babel/code-frame@7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -125,7 +118,7 @@ invariant "^2.2.4" semver "^5.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.4.4", "@babel/core@^7.4.5", "@babel/core@^7.7.5", "@babel/core@^7.9.0": +"@babel/core@^7.1.0", "@babel/core@^7.4.4", "@babel/core@^7.7.5", "@babel/core@^7.9.0": version "7.11.1" resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz#2c55b604e73a40dc21b0e52650b11c65cf276643" integrity sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ== @@ -199,7 +192,7 @@ levenary "^1.1.1" semver "^5.5.0" -"@babel/helper-create-class-features-plugin@^7.10.4": +"@babel/helper-create-class-features-plugin@^7.10.4", "@babel/helper-create-class-features-plugin@^7.10.5": version "7.10.5" resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== @@ -382,7 +375,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1", "@babel/parser@^7.7.5": +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.1": version "7.11.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz#9e1eae46738bcd08e23e867bab43e7b95299a8f9" integrity sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA== @@ -396,7 +389,7 @@ "@babel/helper-remap-async-to-generator" "^7.10.4" "@babel/plugin-syntax-async-generators" "^7.8.0" -"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.7.0", "@babel/plugin-proposal-class-properties@^7.8.3": +"@babel/plugin-proposal-class-properties@^7.10.4", "@babel/plugin-proposal-class-properties@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== @@ -404,6 +397,15 @@ "@babel/helper-create-class-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-proposal-decorators@^7.8.3": + version "7.10.5" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.5.tgz#42898bba478bc4b1ae242a703a953a7ad350ffb4" + integrity sha512-Sc5TAQSZuLzgY0664mMDn24Vw2P8g/VhyLyGPaWiHahhgLqeZvcGeyBZOrJW0oSKIK2mvQ22a1ENXBIQLhrEiQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-decorators" "^7.10.4" + "@babel/plugin-proposal-dynamic-import@^7.10.4": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" @@ -412,6 +414,14 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-dynamic-import" "^7.8.0" +"@babel/plugin-proposal-export-default-from@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.10.4.tgz#08f66eef0067cbf6a7bc036977dcdccecaf0c6c5" + integrity sha512-G1l00VvDZ7Yk2yRlC5D8Ybvu3gmeHS3rCHoUYdjrqGYUtdeOBoRypnvDZ5KQqxyaiiGHWnVDeSEzA5F9ozItig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-default-from" "^7.10.4" + "@babel/plugin-proposal-export-namespace-from@^7.10.4": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" @@ -436,7 +446,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": +"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.1", "@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== @@ -452,7 +462,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.11.0", "@babel/plugin-proposal-object-rest-spread@^7.6.2", "@babel/plugin-proposal-object-rest-spread@^7.9.0": +"@babel/plugin-proposal-object-rest-spread@^7.11.0", "@babel/plugin-proposal-object-rest-spread@^7.9.6": version "7.11.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== @@ -469,7 +479,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" -"@babel/plugin-proposal-optional-chaining@^7.11.0": +"@babel/plugin-proposal-optional-chaining@^7.10.1", "@babel/plugin-proposal-optional-chaining@^7.11.0": version "7.11.0" resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== @@ -478,7 +488,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" "@babel/plugin-syntax-optional-chaining" "^7.8.0" -"@babel/plugin-proposal-private-methods@^7.10.4": +"@babel/plugin-proposal-private-methods@^7.10.4", "@babel/plugin-proposal-private-methods@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== @@ -515,13 +525,27 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-dynamic-import@^7.2.0", "@babel/plugin-syntax-dynamic-import@^7.8.0": +"@babel/plugin-syntax-decorators@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.4.tgz#6853085b2c429f9d322d02f5a635018cdeb2360c" + integrity sha512-2NaoC6fAk2VMdhY1eerkfHV+lVYC1u8b+jmRJISqANCJlTxYy19HGdIkkQtix2UtkcPuPu+IlDgrVseZnU03bw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-dynamic-import@^7.8.0", "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-export-default-from@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.10.4.tgz#e5494f95006355c10292a0ff1ce42a5746002ec8" + integrity sha512-79V6r6Pgudz0RnuMGp5xidu6Z+bPFugh8/Q9eDHonmLp4wKFAZDwygJwYgCzuDu8lFA/sYyT+mc5y2wkd7bTXA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-namespace-from@^7.8.3": version "7.8.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" @@ -606,7 +630,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-arrow-functions@^7.10.4": +"@babel/plugin-syntax-typescript@^7.10.4": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.10.4.tgz#2f55e770d3501e83af217d782cb7517d7bb34d25" + integrity sha512-oSAEz1YkBCAKr5Yiq8/BNtvSAPwkp/IyUnwZogd8p+F0RuYQQrLeRUzIQhueQTTBy/F+a40uS7OFKxnkRvmvFQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-arrow-functions@^7.10.4", "@babel/plugin-transform-arrow-functions@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== @@ -629,14 +660,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-block-scoping@^7.10.4": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.5.tgz#b81b8aafefbfe68f0f65f7ef397b9ece68a6037d" - integrity sha512-6Ycw3hjpQti0qssQcA6AMSFDHeNJ++R6dIMnpRqUjFeBBTmTDPa8zgF90OVfTvAo11mXZTlVUViY1g8ffrURLg== +"@babel/plugin-transform-block-scoping@^7.10.4", "@babel/plugin-transform-block-scoping@^7.8.3": + version "7.11.1" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" + integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-classes@^7.10.4": +"@babel/plugin-transform-classes@^7.10.4", "@babel/plugin-transform-classes@^7.9.5": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== @@ -657,7 +688,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-destructuring@^7.10.4": +"@babel/plugin-transform-destructuring@^7.10.4", "@babel/plugin-transform-destructuring@^7.9.5": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== @@ -695,7 +726,7 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-flow" "^7.8.3" -"@babel/plugin-transform-for-of@^7.10.4": +"@babel/plugin-transform-for-of@^7.10.4", "@babel/plugin-transform-for-of@^7.9.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== @@ -783,7 +814,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-replace-supers" "^7.10.4" -"@babel/plugin-transform-parameters@^7.10.4": +"@babel/plugin-transform-parameters@^7.10.4", "@babel/plugin-transform-parameters@^7.9.5": version "7.10.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== @@ -798,7 +829,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0", "@babel/plugin-transform-react-constant-elements@^7.6.3", "@babel/plugin-transform-react-constant-elements@^7.7.4", "@babel/plugin-transform-react-constant-elements@^7.9.0": +"@babel/plugin-transform-react-constant-elements@^7.7.4", "@babel/plugin-transform-react-constant-elements@^7.9.0": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.10.4.tgz#0f485260bf1c29012bb973e7e404749eaac12c9e" integrity sha512-cYmQBW1pXrqBte1raMkAulXmi7rjg3VI6ZLg9QIic8Hq7BtYXaWuZSxsr2siOMI6SWwpxjWfnwhTUrd7JlAV7g== @@ -869,14 +900,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-shorthand-properties@^7.10.4": +"@babel/plugin-transform-shorthand-properties@^7.10.4", "@babel/plugin-transform-shorthand-properties@^7.8.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-spread@^7.11.0": +"@babel/plugin-transform-spread@^7.11.0", "@babel/plugin-transform-spread@^7.8.3": version "7.11.0" resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== @@ -892,7 +923,7 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/helper-regex" "^7.10.4" -"@babel/plugin-transform-template-literals@^7.10.4": +"@babel/plugin-transform-template-literals@^7.10.4", "@babel/plugin-transform-template-literals@^7.8.3": version "7.10.5" resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== @@ -907,6 +938,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" +"@babel/plugin-transform-typescript@^7.10.4": + version "7.11.0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.11.0.tgz#2b4879676af37342ebb278216dd090ac67f13abb" + integrity sha512-edJsNzTtvb3MaXQwj8403B7mZoGu9ElDJQZOKjGUnvilquxBA3IQoEIOvkX/1O8xfAsnHS/oQhe2w/IXrr+w0w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.10.5" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-typescript" "^7.10.4" + "@babel/plugin-transform-unicode-escapes@^7.10.4": version "7.10.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" @@ -922,18 +962,10 @@ "@babel/helper-create-regexp-features-plugin" "^7.10.4" "@babel/helper-plugin-utils" "^7.10.4" -"@babel/polyfill@^7.8.7": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.10.4.tgz#915e5bfe61490ac0199008e35ca9d7d151a8e45a" - integrity sha512-8BYcnVqQ5kMD2HXoHInBH7H1b/uP3KdnwCYXOqFnXqguOyuu443WXusbIUbWEfY3Z0Txk0M1uG/8YuAMhNl6zg== - dependencies: - core-js "^2.6.5" - regenerator-runtime "^0.13.4" - -"@babel/preset-env@^7.4.5", "@babel/preset-env@^7.9.0", "@babel/preset-env@^7.9.5": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz#860ee38f2ce17ad60480c2021ba9689393efb796" - integrity sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg== +"@babel/preset-env@^7.9.5", "@babel/preset-env@^7.9.6": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz#18cb4b9379e3e92ffea92c07471a99a2914e4272" + integrity sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA== dependencies: "@babel/compat-data" "^7.11.0" "@babel/helper-compilation-targets" "^7.10.4" @@ -997,7 +1029,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.10.4" "@babel/plugin-transform-unicode-regex" "^7.10.4" "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.11.0" + "@babel/types" "^7.11.5" browserslist "^4.12.0" core-js-compat "^3.6.2" invariant "^2.2.2" @@ -1023,7 +1055,7 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.9.4": +"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.8.3", "@babel/preset-react@^7.9.4": version "7.10.4" resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.10.4.tgz#92e8a66d816f9911d11d4cc935be67adfc82dbcf" integrity sha512-BrHp4TgOIy4M19JAfO1LhycVXOPWdDbTRep7eVyatf174Hff+6Uk53sDyajqZPu8W1qXRBiYOfIamek6jA7YVw== @@ -1036,10 +1068,18 @@ "@babel/plugin-transform-react-jsx-source" "^7.10.4" "@babel/plugin-transform-react-pure-annotations" "^7.10.4" -"@babel/register@^7.9.0": - version "7.10.5" - resolved "https://registry.npmjs.org/@babel/register/-/register-7.10.5.tgz#354f3574895f1307f79efe37a51525e52fd38d89" - integrity sha512-eYHdLv43nyvmPn9bfNfrcC4+iYNwdQ8Pxk1MFJuU/U5LpSYl/PH4dFMazCYZDFVi8ueG3shvO+AQfLrxpYulQw== +"@babel/preset-typescript@^7.9.0": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.10.4.tgz#7d5d052e52a682480d6e2cc5aa31be61c8c25e36" + integrity sha512-SdYnvGPv+bLlwkF2VkJnaX/ni1sMNetcGI1+nThF1gyv6Ph8Qucc4ZZAjM5yZcE/AKRXIOTZz7eSRDWOEjPyRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-transform-typescript" "^7.10.4" + +"@babel/register@^7.10.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/register/-/register-7.11.5.tgz#79becf89e0ddd0fba8b92bc279bc0f5d2d7ce2ea" + integrity sha512-CAml0ioKX+kOAvBQDHa/+t1fgOt3qkTIz0TrRtRAT6XY0m5qYZXR85k6/sLCNPMGhYDlCFHCYuU0ybTJbvlC6w== dependencies: find-cache-dir "^2.0.0" lodash "^4.17.19" @@ -1063,14 +1103,14 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.11.2" resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.10.4", "@babel/template@^7.3.3", "@babel/template@^7.7.4": +"@babel/template@^7.10.4", "@babel/template@^7.3.3": version "7.10.4" resolved "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== @@ -1079,7 +1119,7 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.9.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": version "7.11.0" resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz#9b996ce1b98f53f7c3e4175115605d56ed07dd24" integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== @@ -1094,10 +1134,10 @@ globals "^11.1.0" lodash "^4.17.19" -"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.9.0", "@babel/types@^7.9.5": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d" - integrity sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA== +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.9.5": + version "7.11.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" + integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== dependencies: "@babel/helper-validator-identifier" "^7.10.4" lodash "^4.17.19" @@ -1513,6 +1553,11 @@ prop-types "^15.6.2" scheduler "^0.19.0" +"@icons/material@^0.2.4": + version "0.2.4" + resolved "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" + integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.0.0" resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b" @@ -2433,23 +2478,23 @@ resolved "https://registry.npmjs.org/@material-icons/font/-/font-1.0.3.tgz#f722e5a69a03f20ef47d015cb69420bebeeaabe5" integrity sha512-aIRd0Z9b/HJ/O24KOaP7dNsXypMnXhpWrpLVYvQB/JesVqXYSbioYND200sR+C14a0LSCp+qWnWCnSXmN1hWGw== -"@material-ui/core@^4.9.1": - version "4.9.7" - resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.9.7.tgz#0c1caf123278770f34c5d8e9ecd9e1314f87a621" - integrity sha512-RTRibZgq572GHEskMAG4sP+bt3P3XyIkv3pOTR8grZAW2rSUd6JoGZLRM4S2HkuO7wS7cAU5SpU2s1EsmTgWog== +"@material-ui/core@^4.11.0", "@material-ui/core@^4.9.1": + version "4.11.0" + resolved "https://registry.npmjs.org/@material-ui/core/-/core-4.11.0.tgz#b69b26e4553c9e53f2bfaf1053e216a0af9be15a" + integrity sha512-bYo9uIub8wGhZySHqLQ833zi4ZML+XCBE1XwJ8EuUVSpTWWG57Pm+YugQToJNFsEyiKFhPh8DPD0bgupz8n01g== dependencies: "@babel/runtime" "^7.4.4" - "@material-ui/styles" "^4.9.6" - "@material-ui/system" "^4.9.6" - "@material-ui/types" "^5.0.0" - "@material-ui/utils" "^4.9.6" + "@material-ui/styles" "^4.10.0" + "@material-ui/system" "^4.9.14" + "@material-ui/types" "^5.1.0" + "@material-ui/utils" "^4.10.2" "@types/react-transition-group" "^4.2.0" - clsx "^1.0.2" + clsx "^1.0.4" hoist-non-react-statics "^3.3.2" - popper.js "^1.14.1" + popper.js "1.16.1-lts" prop-types "^15.7.2" react-is "^16.8.0" - react-transition-group "^4.3.0" + react-transition-group "^4.4.0" "@material-ui/icons@^4.9.1": version "4.9.1" @@ -2481,16 +2526,16 @@ react-transition-group "^4.0.0" rifm "^0.7.0" -"@material-ui/styles@^4.9.6": - version "4.9.6" - resolved "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.6.tgz#924a30bf7c9b91af9c8f19c12c8573b8a4ecd085" - integrity sha512-ijgwStEkw1OZ6gCz18hkjycpr/3lKs1hYPi88O/AUn4vMuuGEGAIrqKVFq/lADmZUNF3DOFIk8LDkp7zmjPxtA== +"@material-ui/styles@^4.10.0": + version "4.10.0" + resolved "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071" + integrity sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q== dependencies: "@babel/runtime" "^7.4.4" "@emotion/hash" "^0.8.0" - "@material-ui/types" "^5.0.0" + "@material-ui/types" "^5.1.0" "@material-ui/utils" "^4.9.6" - clsx "^1.0.2" + clsx "^1.0.4" csstype "^2.5.2" hoist-non-react-statics "^3.3.2" jss "^10.0.3" @@ -2503,24 +2548,25 @@ jss-plugin-vendor-prefixer "^10.0.3" prop-types "^15.7.2" -"@material-ui/system@^4.9.6": - version "4.9.6" - resolved "https://registry.npmjs.org/@material-ui/system/-/system-4.9.6.tgz#fd060540224da4d1740da8ca6e7af288e217717e" - integrity sha512-QtfoAePyqXoZ2HUVSwGb1Ro0kucMCvVjbI0CdYIR21t0Opgfm1Oer6ni9P5lfeXA39xSt0wCierw37j+YES48Q== +"@material-ui/system@^4.9.14": + version "4.9.14" + resolved "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz#4b00c48b569340cefb2036d0596b93ac6c587a5f" + integrity sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w== dependencies: "@babel/runtime" "^7.4.4" "@material-ui/utils" "^4.9.6" + csstype "^2.5.2" prop-types "^15.7.2" -"@material-ui/types@^5.0.0": - version "5.0.0" - resolved "https://registry.npmjs.org/@material-ui/types/-/types-5.0.0.tgz#26d6259dc6b39f4c2e1e9aceff7a11e031941741" - integrity sha512-UeH2BuKkwDndtMSS0qgx1kCzSMw+ydtj0xx/XbFtxNSTlXydKwzs5gVW5ZKsFlAkwoOOQ9TIsyoCC8hq18tOwg== +"@material-ui/types@^5.1.0": + version "5.1.0" + resolved "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2" + integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A== -"@material-ui/utils@^4.7.1", "@material-ui/utils@^4.9.6": - version "4.9.6" - resolved "https://registry.npmjs.org/@material-ui/utils/-/utils-4.9.6.tgz#5f1f9f6e4df9c8b6a263293b68c94834248ff157" - integrity sha512-gqlBn0JPPTUZeAktn1rgMcy9Iczrr74ecx31tyZLVGdBGGzsxzM6PP6zeS7FuoLS6vG4hoZP7hWnOoHtkR0Kvw== +"@material-ui/utils@^4.10.2", "@material-ui/utils@^4.7.1", "@material-ui/utils@^4.9.6": + version "4.10.2" + resolved "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz#3fd5470ca61b7341f1e0468ac8f29a70bf6df321" + integrity sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw== dependencies: "@babel/runtime" "^7.4.4" prop-types "^15.7.2" @@ -2572,6 +2618,13 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" +"@npmcli/move-file@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464" + integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw== + dependencies: + mkdirp "^1.0.4" + "@octokit/auth-token@^2.4.0": version "2.4.0" resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f" @@ -2641,12 +2694,12 @@ "@octokit/types" "^2.0.1" deprecation "^2.3.1" -"@octokit/plugin-rest-endpoint-methods@4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.0.0.tgz#b02a2006dda8e908c3f8ab381dd5475ef5a810a8" - integrity sha512-emS6gysz4E9BNi9IrCl7Pm4kR+Az3MmVB0/DoDCmF4U48NbYG3weKyDlgkrz6Jbl4Mu4nDx8YWZwC4HjoTdcCA== +"@octokit/plugin-rest-endpoint-methods@4.1.4": + version "4.1.4" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.1.4.tgz#ca60736d761b304fec02a2608caaec2d822e9835" + integrity sha512-Y2tVpSa7HjV3DGIQrQOJcReJ2JtcN9FaGr9jDa332Flro923/h3/Iu9e7Y4GilnzfLclHEh5iCQoCkHm7tWOcg== dependencies: - "@octokit/types" "^5.0.0" + "@octokit/types" "^5.4.1" deprecation "^2.3.1" "@octokit/request-error@^1.0.2": @@ -2704,14 +2757,14 @@ universal-user-agent "^4.0.0" "@octokit/rest@^18.0.0": - version "18.0.0" - resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.0.tgz#7f401d9ce13530ad743dfd519ae62ce49bcc0358" - integrity sha512-4G/a42lry9NFGuuECnua1R1eoKkdBYJap97jYbWDNYBOUboWcM75GJ1VIcfvwDV/pW0lMPs7CEmhHoVrSV5shg== + version "18.0.5" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-18.0.5.tgz#1f1498dcdc2d85d0f86b8168e4ff5779842b2742" + integrity sha512-SPKI24tQXrr1XsnaIjv2x0rl4M5eF1+hj8+vMe3d/exZ7NnL5sTe1BuFyCyJyrc+j1HkXankvgGN9zT0rwBwtg== dependencies: "@octokit/core" "^3.0.0" "@octokit/plugin-paginate-rest" "^2.2.0" "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "4.0.0" + "@octokit/plugin-rest-endpoint-methods" "4.1.4" "@octokit/types@^2.0.0", "@octokit/types@^2.0.1": version "2.5.0" @@ -2727,6 +2780,13 @@ dependencies: "@types/node" ">= 8" +"@octokit/types@^5.4.1": + version "5.4.1" + resolved "https://registry.npmjs.org/@octokit/types/-/types-5.4.1.tgz#d5d5f2b70ffc0e3f89467c3db749fa87fc3b7031" + integrity sha512-OlMlSySBJoJ6uozkr/i03nO5dlYQyE05vmQNZhAh9MyO4DPBP88QlwsDVLmVjIMFssvIZB6WO0ctIGMRG+xsJQ== + dependencies: + "@types/node" ">= 8" + "@open-draft/until@^1.0.0", "@open-draft/until@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca" @@ -2798,7 +2858,7 @@ resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= -"@reach/router@^1.2.1", "@reach/router@^1.3.3": +"@reach/router@^1.3.3": version "1.3.4" resolved "https://registry.npmjs.org/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" integrity sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA== @@ -2809,9 +2869,9 @@ react-lifecycles-compat "^3.0.4" "@rjsf/core@^2.1.0": - version "2.2.2" - resolved "https://registry.npmjs.org/@rjsf/core/-/core-2.2.2.tgz#1ebb6fe47448998f3b54e2dea8d58de8a46014dc" - integrity sha512-4d6DHIiTJEkUq5vyl4LIxLGIYYKKnHcprf94oVchUtGQvRFjNUDFxeFQoyr90oaxcBMs2WDDcCgjcFaKVyfErg== + version "2.3.0" + resolved "https://registry.npmjs.org/@rjsf/core/-/core-2.3.0.tgz#334c73d2262ef1a8cda477e238067af7336c5599" + integrity sha512-OZKYHt9tjKhzOH4CvsPiCwepuIacqI++cNmnL2fsxh1IF+uEWGlo3NLDWhhSaBbOv9jps6a5YQcLbLtjNuSwug== dependencies: "@babel/runtime-corejs2" "^7.8.7" "@types/json-schema" "^7.0.4" @@ -2936,11 +2996,6 @@ resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== -"@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - "@sindresorhus/is@^2.0.0": version "2.1.1" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz#ceff6a28a5b4867c2dd4a1ba513de278ccbe8bb1" @@ -3022,128 +3077,97 @@ glob "^7.1.4" read-pkg-up "^7.0.1" -"@storybook/addon-actions@^5.3.17": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-5.3.19.tgz#50548fa6e84bc79ad95233ce23ade4878fc7cfac" - integrity sha512-gXF29FFUgYlUoFf1DcVCmH1chg2ElaHWMmCi5h7aZe+g6fXBQw0UtEdJnYLMOqZCIiWoZyuf1ETD0RbNHPhRIw== +"@storybook/addon-actions@^6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.0.21.tgz#0de1d109d4b1eb99f644bbe84e74c25cfd2b1b6b" + integrity sha512-9y3ve+3GK1TsxQ5pxDjhB7E/XJXY+WqcSNlOX8Mb+XbS6AAgpFbkZCw1q8CGzyEUclHsQ6UK2+lo+IRGs4TLpA== dependencies: - "@storybook/addons" "5.3.19" - "@storybook/api" "5.3.19" - "@storybook/client-api" "5.3.19" - "@storybook/components" "5.3.19" - "@storybook/core-events" "5.3.19" - "@storybook/theming" "5.3.19" + "@storybook/addons" "6.0.21" + "@storybook/api" "6.0.21" + "@storybook/client-api" "6.0.21" + "@storybook/components" "6.0.21" + "@storybook/core-events" "6.0.21" + "@storybook/theming" "6.0.21" core-js "^3.0.1" - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" global "^4.3.2" - polished "^3.3.1" + lodash "^4.17.15" + polished "^3.4.4" prop-types "^15.7.2" react "^16.8.3" - react-inspector "^4.0.0" - uuid "^3.3.2" + react-inspector "^5.0.1" + regenerator-runtime "^0.13.3" + ts-dedent "^1.1.1" + util-deprecate "^1.0.2" + uuid "^8.0.0" -"@storybook/addon-links@^5.3.17": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-5.3.19.tgz#3c23e886d44b56978ae254fed3bf8be54c877178" - integrity sha512-gn9u8lebREfRsyzxoDPG0O+kOf5aJ0BhzcCJGZZdqha0F6OWHhh8vJYZZvjJ/Qwze+Qt2zjrgWm+Q6+JLD8ugQ== +"@storybook/addon-links@^6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.0.21.tgz#6d4497933d560615617eaffeacec00ad8a788b01" + integrity sha512-5cRFxXS9BviDbS+DCKElr1vSafDcRhX74iIAWl/yOBUldUZvR+gX3WOZ7bO+OBSlQ1NJkt1NUAMag3aiJa4UUw== dependencies: - "@storybook/addons" "5.3.19" - "@storybook/client-logger" "5.3.19" - "@storybook/core-events" "5.3.19" + "@storybook/addons" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/core-events" "6.0.21" "@storybook/csf" "0.0.1" - "@storybook/router" "5.3.19" + "@storybook/router" "6.0.21" + "@types/qs" "^6.9.0" core-js "^3.0.1" global "^4.3.2" prop-types "^15.7.2" qs "^6.6.0" - ts-dedent "^1.1.0" + regenerator-runtime "^0.13.3" + ts-dedent "^1.1.1" -"@storybook/addon-storysource@^5.3.18": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-5.3.19.tgz#ae693e88db5d220cb256a9ef4a2366c300e8d88c" - integrity sha512-W7mIAHuxYT+b1huaHCHLkBAh2MbeWmF8CxeBCFiOgZaYYQUTDEh018HJF8u2AqiWSouRhcfzhTnGxOo0hNRBgw== +"@storybook/addon-storysource@^6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.0.21.tgz#fce9a6de8b276239dbb49b809f3b5efd9fbcecb4" + integrity sha512-h8bu2twPfBRbWlxg8LRtCM5/r2FxWahJa0RC70qDX6eNdzDw6Xv0B8bZsVxKPWqBNQbwYPz5ui44ym53dFDM/Q== dependencies: - "@storybook/addons" "5.3.19" - "@storybook/components" "5.3.19" - "@storybook/router" "5.3.19" - "@storybook/source-loader" "5.3.19" - "@storybook/theming" "5.3.19" + "@storybook/addons" "6.0.21" + "@storybook/api" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/components" "6.0.21" + "@storybook/router" "6.0.21" + "@storybook/source-loader" "6.0.21" + "@storybook/theming" "6.0.21" core-js "^3.0.1" estraverse "^4.2.0" - loader-utils "^1.2.3" - prettier "^1.16.4" + loader-utils "^2.0.0" + prettier "~2.0.5" prop-types "^15.7.2" - react-syntax-highlighter "^11.0.2" + react "^16.9.17" + react-syntax-highlighter "^12.2.1" regenerator-runtime "^0.13.3" - util-deprecate "^1.0.2" -"@storybook/addons@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/addons/-/addons-5.3.19.tgz#3a7010697afd6df9a41b8c8a7351d9a06ff490a4" - integrity sha512-Ky/k22p6i6FVNvs1VhuFyGvYJdcp+FgXqFgnPyY/OXJW/vPDapdElpTpHJZLFI9I2FQBDcygBPU5RXkumQ+KUQ== +"@storybook/addons@6.0.21", "@storybook/addons@^6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.0.21.tgz#bd5229652102c3aed59b78ef6920ff6b482b4d78" + integrity sha512-yDttNLc3vXqBxwK795ykgzTC6MpvuXDQuF4LHSlHZQe6wsMu1m3fljnbYdafJWdx6cNZwUblU3KYcR11PqhkPg== dependencies: - "@storybook/api" "5.3.19" - "@storybook/channels" "5.3.19" - "@storybook/client-logger" "5.3.19" - "@storybook/core-events" "5.3.19" - core-js "^3.0.1" - global "^4.3.2" - util-deprecate "^1.0.2" - -"@storybook/addons@^6.0.4": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/addons/-/addons-6.0.12.tgz#f57f89e0aa55febfb5437ddc2628a0ccc9f44f44" - integrity sha512-gVCyWK4jys5cUY0d3/Bxi02oeCsgdi6xVvA+T4v+SgeduAfm/k01tdO2qDXL37Sl+2TT9HBQGazDrsIUW4d7Ug== - dependencies: - "@storybook/api" "6.0.12" - "@storybook/channels" "6.0.12" - "@storybook/client-logger" "6.0.12" - "@storybook/core-events" "6.0.12" - "@storybook/router" "6.0.12" - "@storybook/theming" "6.0.12" + "@storybook/api" "6.0.21" + "@storybook/channels" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/core-events" "6.0.21" + "@storybook/router" "6.0.21" + "@storybook/theming" "6.0.21" core-js "^3.0.1" global "^4.3.2" regenerator-runtime "^0.13.3" -"@storybook/api@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/api/-/api-5.3.19.tgz#77f15e9e2eee59fe1ddeaba1ef39bc34713a6297" - integrity sha512-U/VzDvhNCPmw2igvJYNNM+uwJCL+3teiL6JmuoL4/cmcqhI6IqqG9dZmMP1egoCd19wXEP7rnAfB/VcYVg41dQ== - dependencies: - "@reach/router" "^1.2.1" - "@storybook/channels" "5.3.19" - "@storybook/client-logger" "5.3.19" - "@storybook/core-events" "5.3.19" - "@storybook/csf" "0.0.1" - "@storybook/router" "5.3.19" - "@storybook/theming" "5.3.19" - "@types/reach__router" "^1.2.3" - core-js "^3.0.1" - fast-deep-equal "^2.0.1" - global "^4.3.2" - lodash "^4.17.15" - memoizerific "^1.11.3" - prop-types "^15.6.2" - react "^16.8.3" - semver "^6.0.0" - shallow-equal "^1.1.0" - store2 "^2.7.1" - telejson "^3.2.0" - util-deprecate "^1.0.2" - -"@storybook/api@6.0.12": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/api/-/api-6.0.12.tgz#d6ded5c9ac8f989c4915e11a80a4db69341fc95f" - integrity sha512-8+jPtfhUVM1hT22OT4rjHRxkW924gbWrAxCFYUXOw80a0x7BcT4sL2ah1D4FWf0IpCT/onLf9jLvSVXr8V0xOw== +"@storybook/api@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/api/-/api-6.0.21.tgz#a25a1eb4d07dc43500e03c856db43baba46726f1" + integrity sha512-cRRGf/KGFwYiDouTouEcDdp45N1AbYnAfvLqYZ3KuUTGZ+CiU/PN/vavkp07DQeM4FIQO8TLhzHdsLFpLT7Lkw== dependencies: "@reach/router" "^1.3.3" - "@storybook/channels" "6.0.12" - "@storybook/client-logger" "6.0.12" - "@storybook/core-events" "6.0.12" + "@storybook/channels" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/core-events" "6.0.21" "@storybook/csf" "0.0.1" - "@storybook/router" "6.0.12" + "@storybook/router" "6.0.21" "@storybook/semver" "^7.3.2" - "@storybook/theming" "6.0.12" + "@storybook/theming" "6.0.21" "@types/reach__router" "^1.3.5" core-js "^3.0.1" fast-deep-equal "^3.1.1" @@ -3157,159 +3181,166 @@ ts-dedent "^1.1.1" util-deprecate "^1.0.2" -"@storybook/channel-postmessage@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-5.3.19.tgz#ef9fe974c2a529d89ce342ff7acf5cc22805bae9" - integrity sha512-Iq0f4NPHR0UVVFCWt0cI7Myadk4/SATXYJPT6sv95KhnLjKEeYw571WBlThfp8a9FM80887xG+eIRe93c8dleA== +"@storybook/channel-postmessage@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.0.21.tgz#97e8f43c1b66f84c7b8271e447d45d4f66d355d1" + integrity sha512-ArRnoaS+b7qpAku/SO27z/yjRDCXb37mCPYGX0ntPbiQajootUbGO7otfnjFkaP44hCEC9uDYlOfMU1hYU1N6A== dependencies: - "@storybook/channels" "5.3.19" - "@storybook/client-logger" "5.3.19" + "@storybook/channels" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/core-events" "6.0.21" core-js "^3.0.1" global "^4.3.2" - telejson "^3.2.0" + qs "^6.6.0" + telejson "^5.0.2" -"@storybook/channels@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/channels/-/channels-5.3.19.tgz#65ad7cd19d70aa5eabbb2e5e39ceef5e510bcb7f" - integrity sha512-38seaeyshRGotTEZJppyYMg/Vx2zRKgFv1L6uGqkJT0LYoNSYtJhsiNFCJ2/KUJu2chAJ/j8h80bpVBVLQ/+WA== - dependencies: - core-js "^3.0.1" - -"@storybook/channels@6.0.12": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.0.12.tgz#377f8049272f1862f9235a5051d95124d53fa08e" - integrity sha512-0EMtjde4tRrBnJj5jOXSgtMYfMxGZgoe/0hvVSJuOABf0FY5x6xrqNNDfory7+TtgieuoQE4idl2/tdHE6QJJA== +"@storybook/channels@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/channels/-/channels-6.0.21.tgz#bc0951efacbaa5f8827693fba4fe7c2290b5772c" + integrity sha512-G6gjcEotSwDmOlxSmOMgsO3VhQ42RLJK7kFp6D5eg0Q6S8vsypltdT8orxdu+6+AbcBrL+5Sla8lThzaCvXsVQ== dependencies: core-js "^3.0.1" ts-dedent "^1.1.1" util-deprecate "^1.0.2" -"@storybook/client-api@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-5.3.19.tgz#7a5630bb8fffb92742b1773881e9004ee7fdf8e0" - integrity sha512-Dh8ZLrLH91j9Fa28Gmp0KFUvvgK348aNMrDNAUdj4m4witz/BWQ2pxz6qq9/xFVErk/GanVC05kazGElqgYCRQ== +"@storybook/client-api@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.0.21.tgz#6a652dea67d219a31d18af0e05b9f17ba6c7c316" + integrity sha512-emBXd/ml6pc3G8gP3MsR9zQsAq1zZbqof9MxB51tG/jpTXdqWQ8ce1pt1tJS8Xj0QDM072jR6wsY+mmro0GZnA== dependencies: - "@storybook/addons" "5.3.19" - "@storybook/channel-postmessage" "5.3.19" - "@storybook/channels" "5.3.19" - "@storybook/client-logger" "5.3.19" - "@storybook/core-events" "5.3.19" + "@storybook/addons" "6.0.21" + "@storybook/channel-postmessage" "6.0.21" + "@storybook/channels" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/core-events" "6.0.21" "@storybook/csf" "0.0.1" - "@types/webpack-env" "^1.15.0" + "@types/qs" "^6.9.0" + "@types/webpack-env" "^1.15.2" core-js "^3.0.1" - eventemitter3 "^4.0.0" global "^4.3.2" - is-plain-object "^3.0.0" lodash "^4.17.15" memoizerific "^1.11.3" qs "^6.6.0" stable "^0.1.8" - ts-dedent "^1.1.0" + store2 "^2.7.1" + ts-dedent "^1.1.1" util-deprecate "^1.0.2" -"@storybook/client-logger@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-5.3.19.tgz#fbbd186e82102eaca1d6a5cca640271cae862921" - integrity sha512-nHftT9Ow71YgAd2/tsu79kwKk30mPuE0sGRRUHZVyCRciGFQweKNOS/6xi2Aq+WwBNNjPKNlbgxwRt1yKe1Vkg== - dependencies: - core-js "^3.0.1" - -"@storybook/client-logger@6.0.12": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.0.12.tgz#33b4c3cd1f1d98dab32d8c8c906301f1ab18f969" - integrity sha512-MEFDlBbbqcivF/Xmxitx/ky8kxN7TVBZ7K754/pPEI5q6UW32DecJIRg79UWp/1nBPMX/A0U3ORwv+0MjgDZBQ== +"@storybook/client-logger@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.0.21.tgz#20369addf9eb79fc0c85a2e0dcb48f5a1a544532" + integrity sha512-8aUEbhjXV+UMYQWukVYnp+kZafF+LD4Dm7eMo37IUZvt3VIjV1VvhxIDVJtqjk2vv0KZTepESFBkZQLmBzI9Zg== dependencies: core-js "^3.0.1" global "^4.3.2" -"@storybook/components@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/components/-/components-5.3.19.tgz#aac1f9eea1247cc85bd93b10fca803876fb84a6b" - integrity sha512-3g23/+ktlocaHLJKISu9Neu3XKa6aYP2ctDYkRtGchSB0Q55hQsUVGO+BEVuT7Pk2D59mVCxboBjxcRoPUY4pw== +"@storybook/components@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/components/-/components-6.0.21.tgz#2f355370f993e0b7b9062094a03dffc2cdda91db" + integrity sha512-r6btqFW/rcXIU5v231EifZfdh9O0fy7bJDXwwDf8zVUgLx8JRc0VnSs3nvK3Is9HF1wZ9vjx/7Lh4rTIDZAjgg== dependencies: - "@storybook/client-logger" "5.3.19" - "@storybook/theming" "5.3.19" + "@storybook/client-logger" "6.0.21" + "@storybook/csf" "0.0.1" + "@storybook/theming" "6.0.21" + "@types/overlayscrollbars" "^1.9.0" + "@types/react-color" "^3.0.1" "@types/react-syntax-highlighter" "11.0.4" - "@types/react-textarea-autosize" "^4.3.3" core-js "^3.0.1" + fast-deep-equal "^3.1.1" global "^4.3.2" lodash "^4.17.15" markdown-to-jsx "^6.11.4" memoizerific "^1.11.3" - polished "^3.3.1" + overlayscrollbars "^1.10.2" + polished "^3.4.4" popper.js "^1.14.7" - prop-types "^15.7.2" react "^16.8.3" + react-color "^2.17.0" react-dom "^16.8.3" - react-focus-lock "^2.1.0" - react-helmet-async "^1.0.2" - react-popper-tooltip "^2.8.3" - react-syntax-highlighter "^11.0.2" - react-textarea-autosize "^7.1.0" - simplebar-react "^1.0.0-alpha.6" - ts-dedent "^1.1.0" + react-popper-tooltip "^2.11.0" + react-syntax-highlighter "^12.2.1" + react-textarea-autosize "^8.1.1" + ts-dedent "^1.1.1" -"@storybook/core-events@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-5.3.19.tgz#18020cd52e0d8ef0973a8e9622a10d5f99796f79" - integrity sha512-lh78ySqMS7pDdMJAQAe35d1I/I4yPTqp09Cq0YIYOxx9BQZhah4DZTV1QIZt22H5p2lPb5MWLkWSxBaexZnz8A== +"@storybook/core-events@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.0.21.tgz#2ce51e6d7524e7543dbb29571beac1dbeb4e5f40" + integrity sha512-p84fbPcsAhnqDhp+HJ4P8+vI2BqJus4IRoVAemLAwuPjyPElrV9UvOa/RHy1BN8Z6jXwFA+FFzfGl2kPJ3WYcA== dependencies: core-js "^3.0.1" -"@storybook/core-events@6.0.12": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.0.12.tgz#499ae06092103b149fcd9417d8e0baa356adc2c0" - integrity sha512-52yNnp+dBkHiG9S+rQO7Nv3PdSDi0XnBt7FoQ+v8H31vGpgdBLEhy8w5ZA4eTrL951VaU/4/XoOaG2+yPALaoA== +"@storybook/core@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/core/-/core-6.0.21.tgz#105c2b90ab27e7b478cb1b7d10e9fe5aba5e0708" + integrity sha512-/Et5NLabB12dnuPdhHDA/Q1pj0Mm2DGdL3KiLO4IC2VZeICCLGmU3/EGJBgjLK+anQ59pkclOiQ8i9eMXFiJ6A== dependencies: - core-js "^3.0.1" - -"@storybook/core@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/core/-/core-5.3.19.tgz#1e61f35c5148343a0c580f5d5efb77f3b4243a30" - integrity sha512-4EYzglqb1iD6x9gxtAYpRGwGP6qJGiU2UW4GiYrErEmeu6y6tkyaqW5AwGlIo9+6jAfwD0HjaK8afvjKTtmmMQ== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.7.0" - "@babel/plugin-proposal-object-rest-spread" "^7.6.2" - "@babel/plugin-syntax-dynamic-import" "^7.2.0" - "@babel/plugin-transform-react-constant-elements" "^7.2.0" - "@babel/preset-env" "^7.4.5" - "@storybook/addons" "5.3.19" - "@storybook/channel-postmessage" "5.3.19" - "@storybook/client-api" "5.3.19" - "@storybook/client-logger" "5.3.19" - "@storybook/core-events" "5.3.19" + "@babel/plugin-proposal-class-properties" "^7.8.3" + "@babel/plugin-proposal-decorators" "^7.8.3" + "@babel/plugin-proposal-export-default-from" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.1" + "@babel/plugin-proposal-object-rest-spread" "^7.9.6" + "@babel/plugin-proposal-optional-chaining" "^7.10.1" + "@babel/plugin-proposal-private-methods" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.5" + "@babel/plugin-transform-destructuring" "^7.9.5" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-parameters" "^7.9.5" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/preset-env" "^7.9.6" + "@babel/preset-react" "^7.8.3" + "@babel/preset-typescript" "^7.9.0" + "@babel/register" "^7.10.5" + "@storybook/addons" "6.0.21" + "@storybook/api" "6.0.21" + "@storybook/channel-postmessage" "6.0.21" + "@storybook/channels" "6.0.21" + "@storybook/client-api" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/components" "6.0.21" + "@storybook/core-events" "6.0.21" "@storybook/csf" "0.0.1" - "@storybook/node-logger" "5.3.19" - "@storybook/router" "5.3.19" - "@storybook/theming" "5.3.19" - "@storybook/ui" "5.3.19" + "@storybook/node-logger" "6.0.21" + "@storybook/router" "6.0.21" + "@storybook/semver" "^7.3.2" + "@storybook/theming" "6.0.21" + "@storybook/ui" "6.0.21" + "@types/glob-base" "^0.3.0" + "@types/micromatch" "^4.0.1" + "@types/node-fetch" "^2.5.4" airbnb-js-shims "^2.2.1" ansi-to-html "^0.6.11" autoprefixer "^9.7.2" - babel-plugin-add-react-displayname "^0.0.5" + babel-loader "^8.0.6" babel-plugin-emotion "^10.0.20" - babel-plugin-macros "^2.7.0" + babel-plugin-macros "^2.8.0" babel-preset-minify "^0.5.0 || 0.6.0-alpha.5" + better-opn "^2.0.0" boxen "^4.1.0" case-sensitive-paths-webpack-plugin "^2.2.0" - chalk "^3.0.0" - cli-table3 "0.5.1" - commander "^4.0.1" + chalk "^4.0.0" + cli-table3 "0.6.0" + commander "^5.0.0" core-js "^3.0.1" - corejs-upgrade-webpack-plugin "^2.2.0" - css-loader "^3.0.0" + css-loader "^3.5.3" detect-port "^1.3.0" dotenv-webpack "^1.7.0" - ejs "^2.7.4" + ejs "^3.1.2" express "^4.17.0" - file-loader "^4.2.0" + file-loader "^6.0.0" file-system-cache "^1.0.5" - find-cache-dir "^3.0.0" find-up "^4.1.0" - fs-extra "^8.0.1" + fork-ts-checker-webpack-plugin "^4.1.4" + fs-extra "^9.0.0" + glob "^7.1.6" glob-base "^0.3.0" + glob-promise "^3.4.0" global "^4.3.2" - html-webpack-plugin "^4.0.0-beta.2" + html-webpack-plugin "^4.2.1" inquirer "^7.0.0" interpret "^2.0.0" ip "^1.1.5" @@ -3317,30 +3348,29 @@ lazy-universal-dotenv "^3.0.1" micromatch "^4.0.2" node-fetch "^2.6.0" - open "^7.0.0" - pnp-webpack-plugin "1.5.0" + pkg-dir "^4.2.0" + pnp-webpack-plugin "1.6.4" postcss-flexbugs-fixes "^4.1.0" postcss-loader "^3.0.0" pretty-hrtime "^1.0.3" qs "^6.6.0" - raw-loader "^3.1.0" - react-dev-utils "^9.0.0" + raw-loader "^4.0.1" + react-dev-utils "^10.0.0" regenerator-runtime "^0.13.3" - resolve "^1.11.0" resolve-from "^5.0.0" - semver "^6.0.0" serve-favicon "^2.5.0" shelljs "^0.8.3" - style-loader "^1.0.0" - terser-webpack-plugin "^2.1.2" - ts-dedent "^1.1.0" + stable "^0.1.8" + style-loader "^1.2.1" + terser-webpack-plugin "^3.0.0" + ts-dedent "^1.1.1" unfetch "^4.1.0" - url-loader "^2.0.1" + url-loader "^4.0.0" util-deprecate "^1.0.2" - webpack "^4.33.0" + webpack "^4.43.0" webpack-dev-middleware "^3.7.0" webpack-hot-middleware "^2.25.0" - webpack-virtual-modules "^0.2.0" + webpack-virtual-modules "^0.2.2" "@storybook/csf@0.0.1": version "0.0.1" @@ -3349,64 +3379,47 @@ dependencies: lodash "^4.17.15" -"@storybook/node-logger@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-5.3.19.tgz#c414e4d3781aeb06298715220012f552a36dff29" - integrity sha512-hKshig/u5Nj9fWy0OsyU04yqCxr0A9pydOHIassr4fpLAaePIN2YvqCqE2V+TxQHjZUnowSSIhbXrGt0DI5q2A== +"@storybook/node-logger@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.0.21.tgz#5b8ba589d5cca6a67c69ee8f5258755b7e1dbc08" + integrity sha512-KRBf+Fz7fgtwHdnYt70JTZbcYMZ1pQPtDyqbrFYCjwkbx5GPX5vMOozlxCIj9elseqPIsF8CKgHOW7cFHVyWYw== dependencies: "@types/npmlog" "^4.1.2" - chalk "^3.0.0" + chalk "^4.0.0" core-js "^3.0.1" npmlog "^4.1.2" pretty-hrtime "^1.0.3" - regenerator-runtime "^0.13.3" -"@storybook/react@^5.3.17": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/react/-/react-5.3.19.tgz#ad7e7a5538399e2794cdb5a1b844a2b77c10bd09" - integrity sha512-OBRUqol3YLQi/qE55x2pWkv4YpaAmmfj6/Km+7agx+og+oNQl0nnlXy7r27X/4j3ERczzURa5pJHtSjwiNaJNw== +"@storybook/react@^6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/react/-/react-6.0.21.tgz#68f8a318e9940305b06eb894896624a35a9868b0" + integrity sha512-L3PcoBJq5aK1aTaJNfwsSJ8Kxgcyk0WknN4TDqhP7a+oXmuMY1YEi96hEvQVIm0TBCkQxs61K70/T7vlilEtHg== dependencies: - "@babel/plugin-transform-react-constant-elements" "^7.6.3" "@babel/preset-flow" "^7.0.0" "@babel/preset-react" "^7.0.0" - "@storybook/addons" "5.3.19" - "@storybook/core" "5.3.19" - "@storybook/node-logger" "5.3.19" - "@svgr/webpack" "^4.0.3" - "@types/webpack-env" "^1.15.0" + "@storybook/addons" "6.0.21" + "@storybook/core" "6.0.21" + "@storybook/node-logger" "6.0.21" + "@storybook/semver" "^7.3.2" + "@svgr/webpack" "^5.4.0" + "@types/webpack-env" "^1.15.2" babel-plugin-add-react-displayname "^0.0.5" babel-plugin-named-asset-import "^0.3.1" - babel-plugin-react-docgen "^4.0.0" + babel-plugin-react-docgen "^4.1.0" core-js "^3.0.1" global "^4.3.2" lodash "^4.17.15" - mini-css-extract-plugin "^0.7.0" prop-types "^15.7.2" - react-dev-utils "^9.0.0" + react-dev-utils "^10.0.0" + react-docgen-typescript-plugin "^0.5.2" regenerator-runtime "^0.13.3" - semver "^6.0.0" - ts-dedent "^1.1.0" - webpack "^4.33.0" + ts-dedent "^1.1.1" + webpack "^4.43.0" -"@storybook/router@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/router/-/router-5.3.19.tgz#0f783b85658f99e4007f74347ad7ef17dbf7fc3a" - integrity sha512-yNClpuP7BXQlBTRf6Ggle3/R349/k6kvI5Aim4jf6X/2cFVg2pzBXDAF41imNm9PcvdxwabQLm6I48p7OvKr/w== - dependencies: - "@reach/router" "^1.2.1" - "@storybook/csf" "0.0.1" - "@types/reach__router" "^1.2.3" - core-js "^3.0.1" - global "^4.3.2" - lodash "^4.17.15" - memoizerific "^1.11.3" - qs "^6.6.0" - util-deprecate "^1.0.2" - -"@storybook/router@6.0.12": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/router/-/router-6.0.12.tgz#f66d979ec01e15c11a378eb5dde3e696747ac184" - integrity sha512-vv1jHOOGelSzmDJnp9SdC/KR5RpE2am568ImOAQ9/XCmXNDhVshVlIS7ajy6yCKN/mS/63zKflbRNef+3SLU9Q== +"@storybook/router@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/router/-/router-6.0.21.tgz#0f22261d4782c72a5a13e80cfcd8d50aed1f98c6" + integrity sha512-46SsKJfcd12lRrISnfrWhicJx8EylkgGDGohfH0n5p7inkkGOkKV8QFZoYPRKZueMXmUKpzJ0Z3HmVsLTCrCDw== dependencies: "@reach/router" "^1.3.3" "@types/reach__router" "^1.3.5" @@ -3423,49 +3436,31 @@ core-js "^3.6.5" find-up "^4.1.0" -"@storybook/source-loader@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-5.3.19.tgz#ff0a00731c24c61721d8b9d84152f8542913a3b7" - integrity sha512-srSZRPgEOUse8nRVnlazweB2QGp63mPqM0uofg8zYARyaYSOzkC155ymdeiHsmiBTS3X3I0FQE4+KnwiH7iLtw== +"@storybook/source-loader@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.0.21.tgz#f4ae0fa3f3d119f9ace1d3364df21f8f7cf65bd7" + integrity sha512-Duzpz8udadR7wzH8/4F3GnMRe23oBOxTm4jBZw/T8NA+HqBtd9Y16swWw4BfwsRwfdZS4EVw3PtWgsAfoqF7ow== dependencies: - "@storybook/addons" "5.3.19" - "@storybook/client-logger" "5.3.19" + "@storybook/addons" "6.0.21" + "@storybook/client-logger" "6.0.21" "@storybook/csf" "0.0.1" core-js "^3.0.1" estraverse "^4.2.0" global "^4.3.2" - loader-utils "^1.2.3" - prettier "^1.16.4" - prop-types "^15.7.2" + loader-utils "^2.0.0" + lodash "^4.17.15" + prettier "~2.0.5" regenerator-runtime "^0.13.3" -"@storybook/theming@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/theming/-/theming-5.3.19.tgz#177d9819bd64f7a1a6ea2f1920ffa5baf9a5f467" - integrity sha512-ecG+Rq3hc1GOzKHamYnD4wZ0PEP9nNg0mXbC3RhbxfHj+pMMCWWmx9B2Uu75SL1PTT8WcfkFO0hU/0IO84Pzlg== - dependencies: - "@emotion/core" "^10.0.20" - "@emotion/styled" "^10.0.17" - "@storybook/client-logger" "5.3.19" - core-js "^3.0.1" - deep-object-diff "^1.1.0" - emotion-theming "^10.0.19" - global "^4.3.2" - memoizerific "^1.11.3" - polished "^3.3.1" - prop-types "^15.7.2" - resolve-from "^5.0.0" - ts-dedent "^1.1.0" - -"@storybook/theming@6.0.12": - version "6.0.12" - resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.0.12.tgz#83b2099e7a7a5bd3acadb8e4106234ede62197c7" - integrity sha512-hmF6EIbm2A7G84+JR36UQWteElSwSNfGLzccAlUMiZIhdMG0SuCtyHe6FmckAWC226Mv+MW14fr+a4+OuRpM4g== +"@storybook/theming@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/theming/-/theming-6.0.21.tgz#d56051c0b8679c2b701ce08385660ab4146cf15f" + integrity sha512-n97DfB9kG6WrV1xBGDyeQibTrh8pBBCp3dSL3UTGH+KX3C2+4sm6QHlTgyekbi5FrbFEbnuZOKAS3YbLVONsRQ== dependencies: "@emotion/core" "^10.0.20" "@emotion/is-prop-valid" "^0.8.6" "@emotion/styled" "^10.0.17" - "@storybook/client-logger" "6.0.12" + "@storybook/client-logger" "6.0.21" core-js "^3.0.1" deep-object-diff "^1.1.0" emotion-theming "^10.0.19" @@ -3475,32 +3470,32 @@ resolve-from "^5.0.0" ts-dedent "^1.1.1" -"@storybook/ui@5.3.19": - version "5.3.19" - resolved "https://registry.npmjs.org/@storybook/ui/-/ui-5.3.19.tgz#ac03b67320044a3892ee784111d4436b61874332" - integrity sha512-r0VxdWab49nm5tzwvveVDnsHIZHMR76veYOu/NHKDUZ5hnQl1LMG1YyMCFFa7KiwD/OrZxRWr6/Ma7ep9kR4Gw== +"@storybook/ui@6.0.21": + version "6.0.21" + resolved "https://registry.npmjs.org/@storybook/ui/-/ui-6.0.21.tgz#5dac2b68a30f5dba5457e0315f58977e07138968" + integrity sha512-50QYF8tHUgpVq7B7PWp7kmyf79NySWJO0piQFjHv027vV8GfbXMWVswAXwo3IfCihPlnLKe01WbsigM/9T1HCQ== dependencies: "@emotion/core" "^10.0.20" - "@storybook/addons" "5.3.19" - "@storybook/api" "5.3.19" - "@storybook/channels" "5.3.19" - "@storybook/client-logger" "5.3.19" - "@storybook/components" "5.3.19" - "@storybook/core-events" "5.3.19" - "@storybook/router" "5.3.19" - "@storybook/theming" "5.3.19" + "@storybook/addons" "6.0.21" + "@storybook/api" "6.0.21" + "@storybook/channels" "6.0.21" + "@storybook/client-logger" "6.0.21" + "@storybook/components" "6.0.21" + "@storybook/core-events" "6.0.21" + "@storybook/router" "6.0.21" + "@storybook/semver" "^7.3.2" + "@storybook/theming" "6.0.21" + "@types/markdown-to-jsx" "^6.11.0" copy-to-clipboard "^3.0.8" core-js "^3.0.1" core-js-pure "^3.0.1" emotion-theming "^10.0.19" - fast-deep-equal "^2.0.1" - fuse.js "^3.4.6" + fuse.js "^3.6.1" global "^4.3.2" lodash "^4.17.15" markdown-to-jsx "^6.11.4" memoizerific "^1.11.3" - polished "^3.3.1" - prop-types "^15.7.2" + polished "^3.4.4" qs "^6.6.0" react "^16.8.3" react-dom "^16.8.3" @@ -3508,12 +3503,9 @@ react-helmet-async "^1.0.2" react-hotkeys "2.0.0" react-sizeme "^2.6.7" - regenerator-runtime "^0.13.2" + regenerator-runtime "^0.13.3" resolve-from "^5.0.0" - semver "^6.0.0" store2 "^2.7.1" - telejson "^3.2.0" - util-deprecate "^1.0.2" "@styled-system/background@^5.1.2": version "5.1.2" @@ -3621,100 +3613,46 @@ dependencies: loader-utils "^1.1.0" -"@svgr/babel-plugin-add-jsx-attribute@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1" - integrity sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig== - "@svgr/babel-plugin-add-jsx-attribute@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg== -"@svgr/babel-plugin-remove-jsx-attribute@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz#297550b9a8c0c7337bea12bdfc8a80bb66f85abc" - integrity sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ== - "@svgr/babel-plugin-remove-jsx-attribute@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef" integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg== -"@svgr/babel-plugin-remove-jsx-empty-expression@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz#c196302f3e68eab6a05e98af9ca8570bc13131c7" - integrity sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w== - "@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1": version "5.0.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd" integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA== -"@svgr/babel-plugin-replace-jsx-attribute-value@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz#310ec0775de808a6a2e4fd4268c245fd734c1165" - integrity sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w== - "@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1": version "5.0.1" resolved "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897" integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ== -"@svgr/babel-plugin-svg-dynamic-title@^4.3.3": - version "4.3.3" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz#2cdedd747e5b1b29ed4c241e46256aac8110dd93" - integrity sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w== - "@svgr/babel-plugin-svg-dynamic-title@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7" integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg== -"@svgr/babel-plugin-svg-em-dimensions@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz#9a94791c9a288108d20a9d2cc64cac820f141391" - integrity sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w== - "@svgr/babel-plugin-svg-em-dimensions@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0" integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw== -"@svgr/babel-plugin-transform-react-native-svg@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz#151487322843359a1ca86b21a3815fd21a88b717" - integrity sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw== - "@svgr/babel-plugin-transform-react-native-svg@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80" integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q== -"@svgr/babel-plugin-transform-svg-component@^4.2.0": - version "4.2.0" - resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz#5f1e2f886b2c85c67e76da42f0f6be1b1767b697" - integrity sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw== - "@svgr/babel-plugin-transform-svg-component@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.4.0.tgz#a2212b4d018e6075a058bb7e220a66959ef7a03c" integrity sha512-zLl4Fl3NvKxxjWNkqEcpdSOpQ3LGVH2BNFQ6vjaK6sFo2IrSznrhURIPI0HAphKiiIwNYjAfE0TNoQDSZv0U9A== -"@svgr/babel-preset@^4.3.3": - version "4.3.3" - resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-4.3.3.tgz#a75d8c2f202ac0e5774e6bfc165d028b39a1316c" - integrity sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^4.2.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^4.2.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^4.2.0" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^4.2.0" - "@svgr/babel-plugin-svg-dynamic-title" "^4.3.3" - "@svgr/babel-plugin-svg-em-dimensions" "^4.2.0" - "@svgr/babel-plugin-transform-react-native-svg" "^4.2.0" - "@svgr/babel-plugin-transform-svg-component" "^4.2.0" - "@svgr/babel-preset@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.4.0.tgz#da21854643e1c4ad2279239baa7d5a8b128c1f15" @@ -3729,15 +3667,6 @@ "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0" "@svgr/babel-plugin-transform-svg-component" "^5.4.0" -"@svgr/core@^4.3.3": - version "4.3.3" - resolved "https://registry.npmjs.org/@svgr/core/-/core-4.3.3.tgz#b37b89d5b757dc66e8c74156d00c368338d24293" - integrity sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w== - dependencies: - "@svgr/plugin-jsx" "^4.3.3" - camelcase "^5.3.1" - cosmiconfig "^5.2.1" - "@svgr/core@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/core/-/core-5.4.0.tgz#655378ee43679eb94fee3d4e1976e38252dff8e7" @@ -3747,13 +3676,6 @@ camelcase "^6.0.0" cosmiconfig "^6.0.0" -"@svgr/hast-util-to-babel-ast@^4.3.2": - version "4.3.2" - resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz#1d5a082f7b929ef8f1f578950238f630e14532b8" - integrity sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg== - dependencies: - "@babel/types" "^7.4.4" - "@svgr/hast-util-to-babel-ast@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.4.0.tgz#bb5d002e428f510aa5b53ec0a02377a95b367715" @@ -3771,26 +3693,7 @@ "@svgr/hast-util-to-babel-ast" "^5.4.0" svg-parser "^2.0.2" -"@svgr/plugin-jsx@^4.3.3": - version "4.3.3" - resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz#e2ba913dbdfbe85252a34db101abc7ebd50992fa" - integrity sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w== - dependencies: - "@babel/core" "^7.4.5" - "@svgr/babel-preset" "^4.3.3" - "@svgr/hast-util-to-babel-ast" "^4.3.2" - svg-parser "^2.0.0" - -"@svgr/plugin-svgo@4.3.x", "@svgr/plugin-svgo@^4.3.1": - version "4.3.1" - resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz#daac0a3d872e3f55935c6588dd370336865e9e32" - integrity sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w== - dependencies: - cosmiconfig "^5.2.1" - merge-deep "^3.0.2" - svgo "^1.2.2" - -"@svgr/plugin-svgo@^5.4.0": +"@svgr/plugin-svgo@5.4.x", "@svgr/plugin-svgo@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.4.0.tgz#45d9800b7099a6f7b4d85ebac89ab9abe8592f64" integrity sha512-3Cgv3aYi1l6SHyzArV9C36yo4kgwVdF3zPQUC6/aCDUeXAofDYwE5kk3e3oT5ZO2a0N3lB+lLGvipBG6lnG8EA== @@ -3813,7 +3716,7 @@ "@svgr/plugin-svgo" "^5.4.0" rollup-pluginutils "^2.8.2" -"@svgr/webpack@5.4.x": +"@svgr/webpack@5.4.x", "@svgr/webpack@^5.4.0": version "5.4.0" resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.4.0.tgz#b68bc86e29cf007292b96ced65f80971175632e0" integrity sha512-LjepnS/BSAvelnOnnzr6Gg0GcpLmnZ9ThGFK5WJtm1xOqdBE/1IACZU7MMdVzjyUkfFqGz87eRE4hFaSLiUwYg== @@ -3827,20 +3730,6 @@ "@svgr/plugin-svgo" "^5.4.0" loader-utils "^2.0.0" -"@svgr/webpack@^4.0.3": - version "4.3.3" - resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017" - integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg== - dependencies: - "@babel/core" "^7.4.5" - "@babel/plugin-transform-react-constant-elements" "^7.0.0" - "@babel/preset-env" "^7.4.5" - "@babel/preset-react" "^7.0.0" - "@svgr/core" "^4.3.3" - "@svgr/plugin-jsx" "^4.3.3" - "@svgr/plugin-svgo" "^4.3.1" - loader-utils "^1.2.3" - "@szmarczak/http-timer@^1.1.2": version "1.1.2" resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" @@ -3985,7 +3874,7 @@ resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== -"@types/babel__core@^7.0.0": +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.9" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d" integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw== @@ -3996,17 +3885,6 @@ "@types/babel__template" "*" "@types/babel__traverse" "*" -"@types/babel__core@^7.1.7": - version "7.1.7" - resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz#1dacad8840364a57c98d0dd4855c6dd3752c6b89" - integrity sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw== - dependencies: - "@babel/parser" "^7.1.0" - "@babel/types" "^7.0.0" - "@types/babel__generator" "*" - "@types/babel__template" "*" - "@types/babel__traverse" "*" - "@types/babel__generator@*": version "7.6.1" resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" @@ -4037,6 +3915,11 @@ "@types/connect" "*" "@types/node" "*" +"@types/braces@*": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb" + integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw== + "@types/cacheable-request@^6.0.1": version "6.0.1" resolved "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976" @@ -4047,13 +3930,6 @@ "@types/node" "*" "@types/responselike" "*" -"@types/cheerio@^0.22.8": - version "0.22.21" - resolved "https://registry.npmjs.org/@types/cheerio/-/cheerio-0.22.21.tgz#5e37887de309ba11b2e19a6e14cad7874b31a8a3" - integrity sha512-aGI3DfswwqgKPiEOTaiHV2ZPC9KEhprpgEbJnv0fZl3SGX0cGgEva1126dGrMC6AJM6v/aihlUgJn9M5DbDZ/Q== - dependencies: - "@types/node" "*" - "@types/classnames@^2.2.9": version "2.2.10" resolved "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999" @@ -4205,11 +4081,6 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/events@*": - version "3.0.0" - resolved "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.5": version "4.17.9" resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz#2d7b34dcfd25ec663c25c85d76608f8b249667f1" @@ -4253,12 +4124,16 @@ resolved "https://registry.npmjs.org/@types/github-slugger/-/github-slugger-1.3.0.tgz#16ab393b30d8ae2a111ac748a015ac05a1fc5524" integrity sha512-J/rMZa7RqiH/rT29TEVZO4nBoDP9XJOjnbbIofg7GQKs4JIduEO3WLpte+6WeUz/TcrXKlY+bM7FYrp8yFB+3g== -"@types/glob@^7.1.1": - version "7.1.1" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== +"@types/glob-base@^0.3.0": + version "0.3.0" + resolved "https://registry.npmjs.org/@types/glob-base/-/glob-base-0.3.0.tgz#a581d688347e10e50dd7c17d6f2880a10354319d" + integrity sha1-pYHWiDR+EOUN18F9byiAoQNUMZ0= + +"@types/glob@*", "@types/glob@^7.1.1": + version "7.1.3" + resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183" + integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w== dependencies: - "@types/events" "*" "@types/minimatch" "*" "@types/node" "*" @@ -4334,7 +4209,7 @@ resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.0.tgz#682477dbbbd07cd032731cb3b0e7eaee3d026b69" integrity sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA== -"@types/http-proxy-middleware@*": +"@types/http-proxy-middleware@*", "@types/http-proxy-middleware@^0.19.3": version "0.19.3" resolved "https://registry.npmjs.org/@types/http-proxy-middleware/-/http-proxy-middleware-0.19.3.tgz#b2eb96fbc0f9ac7250b5d9c4c53aade049497d03" integrity sha512-lnBTx6HCOUeIJMLbI/LaL5EmdKLhczJY5oeXZpX/cXE4rRqb3RmV7VcMpiEfYkmTjipv3h7IAyIINe4plEv7cA== @@ -4467,6 +4342,20 @@ resolved "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== +"@types/markdown-to-jsx@^6.11.0": + version "6.11.2" + resolved "https://registry.npmjs.org/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.2.tgz#05d1aaffbf15be7be12c70535fa4fed65cc7c64f" + integrity sha512-ESuCu8Bk7jpTZ3YPdMW1+6wUj13F5N15vXfc7BuUAN0eCp0lrvVL9nzOTzoqvbRzXMciuqXr1KrHt3xQAhfwPA== + dependencies: + "@types/react" "*" + +"@types/micromatch@^4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@types/micromatch/-/micromatch-4.0.1.tgz#9381449dd659fc3823fd2a4190ceacc985083bc7" + integrity sha512-my6fLBvpY70KattTNzYOK6KU1oR1+UCz9ug/JbcF5UrEmeCt9P7DV2t7L8+t18mMPINqGQCE4O8PLOPbI84gxw== + dependencies: + "@types/braces" "*" + "@types/mime@*": version "2.0.1" resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" @@ -4491,6 +4380,13 @@ dependencies: "@types/node" "*" +"@types/mock-fs@^4.10.0": + version "4.10.0" + resolved "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.10.0.tgz#460061b186993d76856f669d5317cda8a007c24b" + integrity sha512-FQ5alSzmHMmliqcL36JqIA4Yyn9jyJKvRSGV3mvPh108VFatX7naJDzSG4fnFQNZFq9dIx0Dzoe6ddflMB2Xkg== + dependencies: + "@types/node" "*" + "@types/morgan@^1.9.0": version "1.9.1" resolved "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.1.tgz#6457872df95647c1dbc6b3741e8146b71ece74bf" @@ -4498,7 +4394,7 @@ dependencies: "@types/node" "*" -"@types/node-fetch@2.5.7", "@types/node-fetch@^2.5.7": +"@types/node-fetch@2.5.7", "@types/node-fetch@^2.5.4", "@types/node-fetch@^2.5.7": version "2.5.7" resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== @@ -4557,6 +4453,11 @@ dependencies: ora "*" +"@types/overlayscrollbars@^1.9.0": + version "1.12.0" + resolved "https://registry.npmjs.org/@types/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz#98456caceca8ad73bd5bb572632a585074e70764" + integrity sha512-h/pScHNKi4mb+TrJGDon8Yb06ujFG0mSg12wIO0sWMUF3dQIe2ExRRdNRviaNt9IjxIiOfnRr7FsQAdHwK4sMg== + "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" @@ -4626,7 +4527,7 @@ resolved "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== -"@types/qs@*": +"@types/qs@*", "@types/qs@^6.9.0": version "6.9.4" resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a" integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ== @@ -4636,7 +4537,7 @@ resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/reach__router@^1.2.3", "@types/reach__router@^1.3.5": +"@types/reach__router@^1.3.5": version "1.3.5" resolved "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.3.5.tgz#14e1e981cccd3a5e50dc9e969a72de0b9d472f6d" integrity sha512-h0NbqXN/tJuBY/xggZSej1SKQEstbHO7J/omt1tYoFGmj3YXOodZKbbqD4mNDh7zvEGYd7YFrac1LTtAr3xsYQ== @@ -4644,6 +4545,14 @@ "@types/history" "*" "@types/react" "*" +"@types/react-color@^3.0.1": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.4.tgz#c63daf012ad067ac0127bdd86725f079d02082bd" + integrity sha512-EswbYJDF1kkrx93/YU+BbBtb46CCtDMvTiGmcOa/c5PETnwTiSWoseJ1oSWeRl/4rUXkhME9bVURvvPg0W5YQw== + dependencies: + "@types/react" "*" + "@types/reactcss" "*" + "@types/react-dev-utils@^9.0.4": version "9.0.4" resolved "https://registry.npmjs.org/@types/react-dev-utils/-/react-dev-utils-9.0.4.tgz#3e4bee79b7536777cef219427ab1d38adc24f3f2" @@ -4698,13 +4607,6 @@ dependencies: "@types/react" "*" -"@types/react-textarea-autosize@^4.3.3": - version "4.3.5" - resolved "https://registry.npmjs.org/@types/react-textarea-autosize/-/react-textarea-autosize-4.3.5.tgz#6c4d2753fa1864c98c0b2b517f67bb1f6e4c46de" - integrity sha512-PiDL83kPMTolyZAWW3lyzO6ktooTb9tFTntVy7CA83/qFLWKLJ5bLeRboy6J6j3b1e8h2Eec6gBTEOOJRjV14A== - dependencies: - "@types/react" "*" - "@types/react-transition-group@^4.2.0": version "4.2.4" resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.4.tgz#c7416225987ccdb719262766c1483da8f826838d" @@ -4734,6 +4636,13 @@ dependencies: csstype "^2.2.0" +"@types/reactcss@*": + version "1.2.3" + resolved "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.3.tgz#af28ae11bbb277978b99d04d1eedfd068ca71834" + integrity sha512-d2gQQ0IL6hXLnoRfVYZukQNWHuVsE75DzFTLPUuyyEhJS8G2VvlE+qfQQ91SJjaMqlURRCNIsX7Jcsw6cEuJlA== + dependencies: + "@types/react" "*" + "@types/recursive-readdir@^2.2.0": version "2.2.0" resolved "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz#b39cd5474fd58ea727fe434d5c68b7a20ba9121c" @@ -4927,7 +4836,7 @@ "@types/serve-static" "*" "@types/webpack" "*" -"@types/webpack-env@^1.15.0", "@types/webpack-env@^1.15.2": +"@types/webpack-env@^1.15.2": version "1.15.2" resolved "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.15.2.tgz#927997342bb9f4a5185a86e6579a0a18afc33b0a" integrity sha512-67ZgZpAlhIICIdfQrB5fnDvaKFcDxpKibxznfYRVAT4mQE41Dido/3Ty+E3xGBmTogc5+0Qb8tWhna+5B8z1iQ== @@ -5196,6 +5105,18 @@ "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" +"@webpack-contrib/schema-utils@^1.0.0-beta.0": + version "1.0.0-beta.0" + resolved "https://registry.npmjs.org/@webpack-contrib/schema-utils/-/schema-utils-1.0.0-beta.0.tgz#bf9638c9464d177b48209e84209e23bee2eb4f65" + integrity sha512-LonryJP+FxQQHsjGBi6W786TQB1Oym+agTpY0c+Kj8alnIw+DLUJb6SI8Y1GHGhLCH1yPRrucjObUmxNICQ1pg== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chalk "^2.3.2" + strip-ansi "^4.0.0" + text-table "^0.2.0" + webpack-log "^1.1.2" + "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -5378,10 +5299,10 @@ ajv-errors@^1.0.0: resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== -ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: - version "3.4.1" - resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" - integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== ajv@6.5.2: version "6.5.2" @@ -5403,10 +5324,10 @@ ajv@^5.0.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.1, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.5.5, ajv@^6.7.0: - version "6.12.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706" - integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.1, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.5.5, ajv@^6.7.0: + version "6.12.4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" + integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -5447,13 +5368,6 @@ ansi-html@0.0.7: resolved "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= -ansi-red@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" - integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= - dependencies: - ansi-wrap "0.1.0" - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -5501,11 +5415,6 @@ ansi-to-html@^0.6.11: dependencies: entities "^1.1.2" -ansi-wrap@0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= - any-observable@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" @@ -5728,18 +5637,11 @@ aproba@^2.0.0: resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== -arch@^2.1.0, arch@^2.1.2: +arch@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz#0c52bbe7344bb4fa260c443d2cbad9c00ff2f0bf" integrity sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ== -archive-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" - integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= - dependencies: - file-type "^4.2.0" - are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -5975,6 +5877,11 @@ async-retry@^1.2.1: dependencies: retry "0.12.0" +async@0.9.x: + version "0.9.2" + resolved "https://registry.npmjs.org/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + async@^2.6.1, async@^2.6.2: version "2.6.3" resolved "https://registry.npmjs.org/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" @@ -6014,14 +5921,7 @@ autolinker@^3.11.0: dependencies: tslib "^1.9.3" -autolinker@~0.28.0: - version "0.28.1" - resolved "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" - integrity sha1-BlK0kYgYefB3XazgzcoyM5QqTkc= - dependencies: - gulp-header "^1.7.1" - -autoprefixer@^9.7.2, autoprefixer@^9.7.5: +autoprefixer@^9.7.2: version "9.8.6" resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== @@ -6121,6 +6021,17 @@ babel-jest@^26.3.0: graceful-fs "^4.2.4" slash "^3.0.0" +babel-loader@^8.0.6: + version "8.1.0" + resolved "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" + integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw== + dependencies: + find-cache-dir "^2.1.0" + loader-utils "^1.4.0" + mkdirp "^0.5.3" + pify "^4.0.1" + schema-utils "^2.6.5" + babel-plugin-add-react-displayname@^0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz#339d4cddb7b65fd62d1df9db9fe04de134122bd5" @@ -6170,7 +6081,7 @@ babel-plugin-jest-hoist@^26.2.0: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.7.0: +babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0: version "2.8.0" resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== @@ -6260,7 +6171,7 @@ babel-plugin-named-asset-import@^0.3.1: resolved "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.6.tgz#c9750a1b38d85112c9e166bf3ef7c5dbc605f4be" integrity sha512-1aGDUfL1qOOIoqk9QKGIo2lANk+C7ko/fqH0uIyC71x3PEGz0uVP8ISgfEsFuG+FKmjHTvFK/nNM8dowpmUxLA== -babel-plugin-react-docgen@^4.0.0: +babel-plugin-react-docgen@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.1.0.tgz#1dfa447dac9ca32d625a123df5733a9e47287c26" integrity sha512-vzpnBlfGv8XOhJM2zbPyyqw2OLEbelgZZsaaRRTpVwNKuYuc+pUg4+dy7i9gCRms0uOQn4osX571HRcCJMJCmA== @@ -6395,11 +6306,6 @@ babel-runtime@6.26.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - backo2@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" @@ -6472,6 +6378,13 @@ before-after-hook@^2.0.0, before-after-hook@^2.1.0: resolved "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== +better-opn@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/better-opn/-/better-opn-2.0.0.tgz#c70d198e51164bdc220306a28a885d9ac7a14c44" + integrity sha512-PPbGRgO/K0LowMHbH/JNvaV3qY3Vt+A2nH28fzJxy16h/DfR5OsVti6ldGl6S9SMsyUqT13sltikiAVtI6tKLA== + dependencies: + open "^7.0.3" + bfj@^7.0.2: version "7.0.2" resolved "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz#1988ce76f3add9ac2913fd8ba47aad9e651bfbb2" @@ -6487,54 +6400,6 @@ big.js@^5.2.2: resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== -bin-build@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/bin-build/-/bin-build-3.0.0.tgz#c5780a25a8a9f966d8244217e6c1f5082a143861" - integrity sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA== - dependencies: - decompress "^4.0.0" - download "^6.2.2" - execa "^0.7.0" - p-map-series "^1.0.0" - tempfile "^2.0.0" - -bin-check@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz#fc495970bdc88bb1d5a35fc17e65c4a149fc4a49" - integrity sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA== - dependencies: - execa "^0.7.0" - executable "^4.1.0" - -bin-version-check@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/bin-version-check/-/bin-version-check-4.0.0.tgz#7d819c62496991f80d893e6e02a3032361608f71" - integrity sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ== - dependencies: - bin-version "^3.0.0" - semver "^5.6.0" - semver-truncate "^1.1.2" - -bin-version@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/bin-version/-/bin-version-3.1.0.tgz#5b09eb280752b1bd28f0c9db3f96f2f43b6c0839" - integrity sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ== - dependencies: - execa "^1.0.0" - find-versions "^3.0.0" - -bin-wrapper@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/bin-wrapper/-/bin-wrapper-4.1.0.tgz#99348f2cf85031e3ef7efce7e5300aeaae960605" - integrity sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q== - dependencies: - bin-check "^4.1.0" - bin-version-check "^4.0.0" - download "^7.1.0" - import-lazy "^3.1.0" - os-filter-obj "^2.0.0" - pify "^4.0.1" - binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -6600,16 +6465,6 @@ body-parser@1.19.0, body-parser@^1.18.3: raw-body "2.4.0" type-is "~1.6.17" -body@^5.1.0: - version "5.1.0" - resolved "https://registry.npmjs.org/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" - integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= - dependencies: - continuable-cache "^0.3.1" - error "^7.0.0" - raw-body "~1.1.0" - safe-json-parse "~1.0.1" - bonjour@^3.5.0: version "3.5.0" resolved "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" @@ -6756,15 +6611,6 @@ browserslist@4.10.0: node-releases "^1.1.52" pkg-up "^3.1.0" -browserslist@4.7.0: - version "4.7.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz#9ee89225ffc07db03409f2fee524dc8227458a17" - integrity sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA== - dependencies: - caniuse-lite "^1.0.30000989" - electron-to-chromium "^1.3.247" - node-releases "^1.1.29" - browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.8.3: version "4.13.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.13.0.tgz#42556cba011e1b0a2775b611cba6a8eca18e940d" @@ -6856,7 +6702,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.5.0, buffer@^5.6.0: version "5.6.0" resolved "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== @@ -6896,11 +6742,6 @@ byte-size@^5.0.1: resolved "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191" integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw== -bytes@1: - version "1.0.0" - resolved "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" - integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= - bytes@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -6932,28 +6773,27 @@ cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^13.0.1: - version "13.0.1" - resolved "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" - integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== +cacache@^15.0.5: + version "15.0.5" + resolved "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0" + integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A== dependencies: - chownr "^1.1.2" - figgy-pudding "^3.5.1" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" fs-minipass "^2.0.0" glob "^7.1.4" - graceful-fs "^4.2.2" infer-owner "^1.0.4" - lru-cache "^5.1.1" - minipass "^3.0.0" + lru-cache "^6.0.0" + minipass "^3.1.1" minipass-collect "^1.0.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.2" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - p-map "^3.0.0" + mkdirp "^1.0.3" + p-map "^4.0.0" promise-inflight "^1.0.1" - rimraf "^2.7.1" - ssri "^7.0.0" + rimraf "^3.0.2" + ssri "^8.0.0" + tar "^6.0.2" unique-filename "^1.1.1" cache-base@^1.0.1: @@ -6984,19 +6824,6 @@ cacheable-lookup@^5.0.3: resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.3.tgz#049fdc59dffdd4fc285e8f4f82936591bd59fec3" integrity sha512-W+JBqF9SWe18A72XFzN/V/CULFzPm7sBXzzR6ekkE+3tLG72wFZrBiBZhrZuDoYexop4PHJVdFAKb/Nj9+tm9w== -cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -7116,11 +6943,6 @@ camelcase@^6.0.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== -can-use-dom@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a" - integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo= - caniuse-api@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" @@ -7131,7 +6953,7 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001109: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001109: version "1.0.30001113" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001113.tgz#22016ab55b5a8b04fa00ca342d9ee1b98df48065" integrity sha512-qMvjHiKH21zzM/VDZr6oosO6Ri3U0V2tC015jRXjOecwQCJtsU5zklTNTk31jQbIOP8gha0h1ccM/g0ECP+4BA== @@ -7172,17 +6994,7 @@ caseless@~0.12.0: resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -caw@^2.0.0, caw@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" - integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== - dependencies: - get-proxy "^2.0.0" - isurl "^1.0.0-alpha5" - tunnel-agent "^0.6.0" - url-to-options "^1.0.1" - -chalk@2.4.2, chalk@^2.0.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -7253,29 +7065,7 @@ check-types@^11.1.1: resolved "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz#86a7c12bf5539f6324eb0e70ca8896c0e38f3e2f" integrity sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ== -cheerio@0.22.0: - version "0.22.0" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" - integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4= - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "^3.9.1" - lodash.assignin "^4.0.9" - lodash.bind "^4.1.4" - lodash.defaults "^4.0.1" - lodash.filter "^4.4.0" - lodash.flatten "^4.2.0" - lodash.foreach "^4.3.0" - lodash.map "^4.4.0" - lodash.merge "^4.4.0" - lodash.pick "^4.2.1" - lodash.reduce "^4.4.0" - lodash.reject "^4.4.0" - lodash.some "^4.4.0" - -chokidar@^2.0.4, chokidar@^2.1.8: +chokidar@^2.1.8: version "2.1.8" resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== @@ -7294,10 +7084,10 @@ chokidar@^2.0.4, chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.2.2, chokidar@^3.3.0, chokidar@^3.3.1: - version "3.4.1" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1" - integrity sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g== +chokidar@^3.2.2, chokidar@^3.3.0, chokidar@^3.3.1, chokidar@^3.4.1: + version "3.4.2" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" + integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -7404,7 +7194,17 @@ cli-spinners@^2.2.0: resolved "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.2.0.tgz#e8b988d9206c692302d8ee834e7a85c0144d8f77" integrity sha512-tgU3fKwzYjiLEQgPMD9Jt+JjHVL9kW93FiIMX/l7rivvOD4/LL0Mf7gda3+4U2KJBloybwgj5KEoQgGRioMiKQ== -cli-table3@0.5.1, cli-table3@~0.5.1: +cli-table3@0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz#b7b1bc65ca8e7b5cef9124e13dc2b21e2ce4faee" + integrity sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ== + dependencies: + object-assign "^4.1.0" + string-width "^4.2.0" + optionalDependencies: + colors "^1.1.2" + +cli-table3@~0.5.1: version "0.5.1" resolved "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== @@ -7496,7 +7296,7 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clone-response@1.0.2, clone-response@^1.0.2: +clone-response@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= @@ -7550,11 +7350,6 @@ codemirror@^5.52.2: resolved "https://registry.npmjs.org/codemirror/-/codemirror-5.53.2.tgz#9799121cf8c50809cca487304e9de3a74d33f428" integrity sha512-wvSQKS4E+P8Fxn/AQ+tQtJnF1qH5UOlxtugFLpubEZ5jcdH2iXTVinb+Xc/4QjshuOxRm4fUsU2QPF1JJKiyXA== -coffee-script@^1.12.4: - version "1.12.7" - resolved "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53" - integrity sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw== - collapse-white-space@^1.0.2: version "1.0.6" resolved "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" @@ -7669,12 +7464,12 @@ command-exists-promise@^2.0.2: resolved "https://registry.npmjs.org/command-exists-promise/-/command-exists-promise-2.0.2.tgz#7beecc4b218299f3c61fa69a4047aa0b36a64a99" integrity sha512-T6PB6vdFrwnHXg/I0kivM3DqaCGZLjjYSOe0a5WgFKcz1sOnmOeIjnhQPXVXX3QjVbLyTJ85lJkX6lUpukTzaA== -commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@^2.8.1, commander@~2.20.3: +commander@^2.11.0, commander@^2.19.0, commander@^2.20.0, commander@^2.20.3, commander@~2.20.3: version "2.20.3" resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^4.0.0, commander@^4.0.1, commander@^4.1.1: +commander@^4.0.0, commander@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== @@ -7761,7 +7556,7 @@ concat-map@0.0.1: resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@^1.6.2: +concat-stream@^1.5.0, concat-stream@^1.6.2: version "1.6.2" resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -7781,7 +7576,7 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -concat-with-sourcemaps@*, concat-with-sourcemaps@^1.1.0: +concat-with-sourcemaps@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== @@ -7838,11 +7633,6 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -console-stream@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/console-stream/-/console-stream-0.1.1.tgz#a095fe07b20465955f2fafd28b5d72bccd949d44" - integrity sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ= - constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -7863,7 +7653,7 @@ content-disposition@0.5.2: resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= -content-disposition@0.5.3, content-disposition@^0.5.2: +content-disposition@0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== @@ -7875,11 +7665,6 @@ content-type@~1.0.4: resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -continuable-cache@^0.3.1: - version "0.3.1" - resolved "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" - integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= - conventional-changelog-angular@^5.0.3: version "5.0.6" resolved "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.6.tgz#269540c624553aded809c29a3508fdc2b544c059" @@ -8050,14 +7835,6 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -corejs-upgrade-webpack-plugin@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/corejs-upgrade-webpack-plugin/-/corejs-upgrade-webpack-plugin-2.2.0.tgz#503293bf1fdcb104918eb40d0294e4776ad6923a" - integrity sha512-J0QMp9GNoiw91Kj/dkIQFZeiCXgXoja/Wlht1SPybxerBWh4NCmb0pOgCv61lrlQZETwvVVfAFAA3IqoEO9aqQ== - dependencies: - resolve-from "^5.0.0" - webpack "^4.38.0" - cors@^2.8.4, cors@^2.8.5: version "2.8.5" resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" @@ -8077,7 +7854,7 @@ cosmiconfig@6.0.0, cosmiconfig@^6.0.0: path-type "^4.0.0" yaml "^1.7.2" -cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.1: +cosmiconfig@^5.0.0, cosmiconfig@^5.1.0: version "5.2.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== @@ -8087,6 +7864,17 @@ cosmiconfig@^5.0.0, cosmiconfig@^5.1.0, cosmiconfig@^5.2.1: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmiconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3" + integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -8140,17 +7928,6 @@ cross-fetch@3.0.5, cross-fetch@^3.0.4, cross-fetch@^3.0.5: dependencies: node-fetch "2.6.0" -cross-spawn@6.0.5, cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14" @@ -8160,12 +7937,14 @@ cross-spawn@7.0.1: shebang-command "^2.0.0" which "^2.0.1" -cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: - lru-cache "^4.0.1" + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" shebang-command "^1.2.0" which "^1.2.9" @@ -8178,15 +7957,6 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" -crowdin-cli@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/crowdin-cli/-/crowdin-cli-0.3.0.tgz#eac9989a6fe7feaaf33090397afc187c67b46191" - integrity sha1-6smYmm/n/qrzMJA5evwYfGe0YZE= - dependencies: - request "^2.53.0" - yamljs "^0.2.1" - yargs "^2.3.0" - crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -8244,7 +8014,7 @@ css-line-break@1.0.1: dependencies: base64-arraybuffer "^0.1.5" -css-loader@^3.0.0, css-loader@^3.5.3: +css-loader@^3.5.3: version "3.6.0" resolved "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ== @@ -8280,7 +8050,7 @@ css-select-base-adapter@^0.1.1: resolved "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== -css-select@^1.1.0, css-select@~1.2.0: +css-select@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg= @@ -8642,13 +8412,6 @@ debug@3.1.0, debug@=3.1.0: dependencies: ms "2.0.0" -debug@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz#373687bffa678b38b1cd91f861b63850035ddc87" - integrity sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg== - dependencies: - ms "^2.1.1" - debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -8691,7 +8454,7 @@ decode-uri-component@^0.2.0: resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= -decompress-response@^3.2.0, decompress-response@^3.3.0: +decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= @@ -8719,59 +8482,6 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" -decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - -decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - -decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - -decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - -decompress@^4.0.0, decompress@^4.2.0: - version "4.2.1" - resolved "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - dedent@^0.7.0: version "0.7.0" resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -8814,6 +8524,11 @@ deepmerge@^4.2.2: resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +default-branch@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/default-branch/-/default-branch-1.0.8.tgz#0e2f36a90e3b0d9f73cdf8e02841364ed35b8b54" + integrity sha512-pViUZEnaxd/Hbu880MEXF7XqV8RJ1ssDlkvzx+woQhcKW8px3BrVDvwBGn09zRiKZ+gOLipK7ft5x3no+3vb8A== + default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -8992,11 +8707,6 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -diacritics-map@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz#6dfc0ff9d01000a2edf2865371cac316e94977af" - integrity sha1-bfwP+dAQAKLt8oZTccrDFulJd68= - diagnostics@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a" @@ -9119,58 +8829,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -docusaurus@^2.0.0-alpha.61: - version "2.0.0-alpha.61" - resolved "https://registry.npmjs.org/docusaurus/-/docusaurus-2.0.0-alpha.61.tgz#f347b81c98c66f1de3ecfccf63fa421ddff52fbb" - integrity sha512-qDU3nOA4Xs95tIjjSETnEuRmTukTzgxyTZ5MgMyuG7y6h4oDHtpLcYf8F+xlXuuWHKv3VSxRJNzV8fZHPgnK3g== - dependencies: - "@babel/core" "^7.9.0" - "@babel/plugin-proposal-class-properties" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.0" - "@babel/polyfill" "^7.8.7" - "@babel/preset-env" "^7.9.0" - "@babel/preset-react" "^7.9.4" - "@babel/register" "^7.9.0" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - autoprefixer "^9.7.5" - babylon "^6.18.0" - chalk "^3.0.0" - classnames "^2.2.6" - commander "^4.0.1" - crowdin-cli "^0.3.0" - cssnano "^4.1.10" - escape-string-regexp "^2.0.0" - express "^4.17.1" - feed "^4.0.0" - fs-extra "^8.1.0" - gaze "^1.1.3" - github-slugger "^1.2.1" - glob "^7.1.6" - highlight.js "^9.16.2" - imagemin "^6.0.0" - imagemin-gifsicle "^6.0.1" - imagemin-jpegtran "^6.0.0" - imagemin-optipng "^6.0.0" - imagemin-svgo "^7.0.0" - lodash "^4.17.15" - markdown-toc "^1.2.0" - mkdirp "^0.5.1" - portfinder "^1.0.25" - postcss "^7.0.23" - prismjs "^1.17.1" - react "^16.8.4" - react-dev-utils "^9.1.0" - react-dom "^16.8.4" - remarkable "^2.0.0" - request "^2.88.0" - shelljs "^0.8.4" - sitemap "^3.2.2" - tcp-port-used "^1.0.1" - tiny-lr "^1.1.1" - tree-node-cli "^1.2.5" - truncate-html "^1.0.3" - dom-accessibility-api@^0.5.1: version "0.5.2" resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.2.tgz#ef3cdb5d3f0d599d8f9c8b18df2fb63c9793739d" @@ -9199,14 +8857,6 @@ dom-serializer@0, dom-serializer@^0.2.1: domelementtype "^2.0.1" entities "^2.0.0" -dom-serializer@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" - integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== - dependencies: - domelementtype "^1.3.0" - entities "^1.1.1" - dom-walk@^0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" @@ -9217,7 +8867,7 @@ domain-browser@^1.1.1: resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: +domelementtype@1, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== @@ -9348,41 +8998,6 @@ dotenv@^8.0.0: resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== -download@^6.2.2: - version "6.2.5" - resolved "https://registry.npmjs.org/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" - integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== - dependencies: - caw "^2.0.0" - content-disposition "^0.5.2" - decompress "^4.0.0" - ext-name "^5.0.0" - file-type "5.2.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^7.0.0" - make-dir "^1.0.0" - p-event "^1.0.0" - pify "^3.0.0" - -download@^7.1.0: - version "7.1.0" - resolved "https://registry.npmjs.org/download/-/download-7.1.0.tgz#9059aa9d70b503ee76a132897be6dec8e5587233" - integrity sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ== - dependencies: - archive-type "^4.0.0" - caw "^2.0.1" - content-disposition "^0.5.2" - decompress "^4.2.0" - ext-name "^5.0.0" - file-type "^8.1.0" - filenamify "^2.0.0" - get-stream "^3.0.0" - got "^8.3.1" - make-dir "^1.2.0" - p-event "^2.1.0" - pify "^3.0.0" - duplexer3@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" @@ -9416,12 +9031,14 @@ ee-first@1.1.1: resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -ejs@^2.7.4: - version "2.7.4" - resolved "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" - integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== +ejs@^3.1.2: + version "3.1.5" + resolved "https://registry.npmjs.org/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b" + integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w== + dependencies: + jake "^10.6.1" -electron-to-chromium@^1.3.247, electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.488: +electron-to-chromium@^1.3.378, electron-to-chromium@^1.3.488: version "1.3.509" resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.509.tgz#830fcb89cd66dc2984d18d794973b99e3f00584c" integrity sha512-cN4lkjNRuTG8rtAqTOVgwpecEC2kbKA04PG6YijcKGHK/kD0xLjiqExcAOmLUwtXZRF8cBeam2I0VZcih919Ug== @@ -9521,10 +9138,19 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" - integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== +endent@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/endent/-/endent-2.0.1.tgz#fb18383a3f37ae3213a5d9f6c4a880d1061eb4c5" + integrity sha512-mADztvcC+vCk4XEZaCz6xIPO2NHQuprv5CAEjuVAu6aZwqAj7nVNlMyl1goPFYqCCpS2OJV9jwpumJLkotZrNw== + dependencies: + dedent "^0.7.0" + fast-json-parse "^1.0.3" + objectorarray "^1.0.4" + +enhanced-resolve@^4.0.0, enhanced-resolve@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126" + integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ== dependencies: graceful-fs "^4.1.2" memory-fs "^0.5.0" @@ -9588,13 +9214,6 @@ error-stack-parser@^2.0.6: dependencies: stackframe "^1.1.1" -error@^7.0.0: - version "7.2.1" - resolved "https://registry.npmjs.org/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" - integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== - dependencies: - string-template "~0.2.1" - es-abstract@^1.17.0, es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.4: version "1.17.4" resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" @@ -9717,16 +9336,16 @@ escape-html@^1.0.3, escape-html@~1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - escape-string-regexp@2.0.0, escape-string-regexp@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + escodegen@^1.14.1, escodegen@^1.6.1, escodegen@^1.9.1: version "1.14.3" resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" @@ -10072,17 +9691,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -exec-buffer@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz#b1686dbd904c7cf982e652c1f5a79b1e5573082b" - integrity sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA== - dependencies: - execa "^0.7.0" - p-finally "^1.0.0" - pify "^3.0.0" - rimraf "^2.5.4" - tempfile "^2.0.0" - exec-sh@^0.3.2: version "0.3.4" resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" @@ -10104,19 +9712,6 @@ execa@3.4.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" - integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -10145,7 +9740,7 @@ execa@^4.0.0, execa@^4.0.1: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -executable@^4.1.0, executable@^4.1.1: +executable@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== @@ -10175,13 +9770,6 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expand-range@^1.8.1: - version "1.8.2" - resolved "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" - integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= - dependencies: - fill-range "^2.1.0" - expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" @@ -10254,21 +9842,6 @@ express@^4.0.0, express@^4.17.0, express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" -ext-list@^2.0.0: - version "2.2.2" - resolved "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" - integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== - dependencies: - mime-db "^1.28.0" - -ext-name@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" - integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== - dependencies: - ext-list "^2.0.0" - sort-keys-length "^1.0.0" - ext@^1.1.2: version "1.4.0" resolved "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" @@ -10378,6 +9951,11 @@ fast-glob@^3.0.3, fast-glob@^3.1.1: micromatch "^4.0.2" picomatch "^2.2.1" +fast-json-parse@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz#43e5c61ee4efa9265633046b770fb682a7577c4d" + integrity sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw== + fast-json-patch@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz#18150d36c9ab65c7209e7d4eb113f4f8eaabe6d9" @@ -10436,7 +10014,7 @@ fault@^1.0.0, fault@^1.0.2: dependencies: format "^0.2.0" -faye-websocket@^0.10.0, faye-websocket@~0.10.0: +faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= @@ -10469,13 +10047,6 @@ fecha@^2.3.3: resolved "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg== -feed@^4.0.0: - version "4.2.1" - resolved "https://registry.npmjs.org/feed/-/feed-4.2.1.tgz#b246ef891051c7dbf088ca203341d9fb0444baee" - integrity sha512-l28KKcK1J/u3iq5dRDmmoB2p7dtBfACC2NqJh4dI2kFptxH0asfjmOfcxqh5Sv8suAlVa73gZJ4REY5RrafVvg== - dependencies: - xml-js "^1.6.11" - fetch-readablestream@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/fetch-readablestream/-/fetch-readablestream-0.2.0.tgz#eaa6d1a76b12de2d4731a343393c6ccdcfe2c795" @@ -10486,7 +10057,7 @@ figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: resolved "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== -figures@^1.3.5, figures@^1.7.0: +figures@^1.7.0: version "1.7.0" resolved "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= @@ -10515,13 +10086,13 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -file-loader@^4.2.0: - version "4.3.0" - resolved "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz#780f040f729b3d18019f20605f723e844b8a58af" - integrity sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA== +file-loader@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.1.0.tgz#65b9fcfb0ea7f65a234a1f10cdd7f1ab9a33f253" + integrity sha512-26qPdHyTsArQ6gU4P1HJbAbnFTyT2r0pG7czh1GFAd9TZbj0n94wWbupgixZH/ET/meqi2/5+F7DhW4OAXD+Lg== dependencies: - loader-utils "^1.2.3" - schema-utils "^2.5.0" + loader-utils "^2.0.0" + schema-utils "^2.7.1" file-saver@eligrey/FileSaver.js#1.3.8: version "1.3.8" @@ -10536,36 +10107,6 @@ file-system-cache@^1.0.5: fs-extra "^0.30.0" ramda "^0.21.0" -file-type@5.2.0, file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= - -file-type@^10.4.0, file-type@^10.7.0: - version "10.11.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz#2961d09e4675b9fb9a3ee6b69e9cd23f43fd1890" - integrity sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw== - -file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= - -file-type@^4.2.0: - version "4.4.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" - integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= - -file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - -file-type@^8.1.0: - version "8.1.0" - resolved "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz#244f3b7ef641bbe0cca196c7276e4b332399f68c" - integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== - file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" @@ -10576,41 +10117,18 @@ filefy@0.1.10: resolved "https://registry.npmjs.org/filefy/-/filefy-0.1.10.tgz#174677c8e2fa5bc39a3af0ed6fb492f16b8fbf42" integrity sha512-VgoRVOOY1WkTpWH+KBy8zcU1G7uQTVsXqhWEgzryB9A5hg2aqCyZ6aQ/5PSzlqM5+6cnVrX6oYV0XqD3HZSnmQ== -filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - -filenamify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" - integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== +filelist@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/filelist/-/filelist-1.0.1.tgz#f10d1a3ae86c1694808e8f20906f43d4c9132dbb" + integrity sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ== dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - -filesize@3.6.1: - version "3.6.1" - resolved "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" - integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== + minimatch "^3.0.4" filesize@6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz#f850b509909c7c86f7e450ea19006c31c2ed3d2f" integrity sha512-u4AYWPgbI5GBhs6id1KdImZWn5yfyFrrQ8OWZdN7ZMfA8Bf4HcO0BGo9bmUIEV8yrp8I1xVfJ/dn90GtFNNJcg== -fill-range@^2.1.0: - version "2.2.4" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" - integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== - dependencies: - is-number "^2.1.0" - isobject "^2.0.0" - randomatic "^3.0.0" - repeat-element "^1.1.2" - repeat-string "^1.5.2" - fill-range@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -10650,7 +10168,7 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-cache-dir@^3.0.0, find-cache-dir@^3.2.0: +find-cache-dir@^3.2.0, find-cache-dir@^3.3.1: version "3.3.1" resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== @@ -10664,13 +10182,6 @@ find-root@^1.1.0: resolved "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - find-up@4.1.0, find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -10694,7 +10205,14 @@ find-up@^2.0.0, find-up@^2.1.0: dependencies: locate-path "^2.0.0" -find-versions@^3.0.0, find-versions@^3.2.0: +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-versions@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== @@ -10754,11 +10272,6 @@ fn-name@~3.0.0: resolved "https://registry.npmjs.org/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c" integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA== -focus-lock@^0.6.6: - version "0.6.6" - resolved "https://registry.npmjs.org/focus-lock/-/focus-lock-0.6.6.tgz#98119a755a38cfdbeda0280eaa77e307eee850c7" - integrity sha512-Dx69IXGCq1qsUExWuG+5wkiMqVM/zGx/reXSJSLogECwp3x6KeNQZ+NAetgxEFpnC41rD8U3+jRCW68+LNzdtw== - follow-redirects@1.5.10: version "1.5.10" resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" @@ -10805,20 +10318,6 @@ forever-agent@~0.6.1: resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -fork-ts-checker-webpack-plugin@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-1.5.0.tgz#ce1d77190b44d81a761b10b6284a373795e41f0c" - integrity sha512-zEhg7Hz+KhZlBhILYpXy+Beu96gwvkROWJiTXOCyOOMMrdBIRPvsBpBqgTI4jfJGrJXcqGwJR8zsBGDmzY0jsA== - dependencies: - babel-code-frame "^6.22.0" - chalk "^2.4.1" - chokidar "^2.0.4" - micromatch "^3.1.10" - minimatch "^3.0.4" - semver "^5.6.0" - tapable "^1.0.0" - worker-rpc "^0.1.0" - fork-ts-checker-webpack-plugin@3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19" @@ -10833,7 +10332,7 @@ fork-ts-checker-webpack-plugin@3.1.1: tapable "^1.0.0" worker-rpc "^0.1.0" -fork-ts-checker-webpack-plugin@^4.0.5: +fork-ts-checker-webpack-plugin@^4.0.5, fork-ts-checker-webpack-plugin@^4.1.4: version "4.1.6" resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz#5055c703febcf37fa06405d400c122b905167fc5" integrity sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw== @@ -10900,7 +10399,7 @@ fresh@0.5.2: resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^2.1.0, from2@^2.1.1: +from2@^2.1.0: version "2.3.0" resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= @@ -10923,7 +10422,7 @@ fs-constants@^1.0.0: resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== -fs-extra@8.1.0, fs-extra@^8.0.1, fs-extra@^8.1.0: +fs-extra@8.1.0, fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== @@ -11028,7 +10527,7 @@ functions-have-names@^1.2.0: resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.1.tgz#a981ac397fa0c9964551402cdc5533d7a4d52f91" integrity sha512-j48B/ZI7VKs3sgeI2cZp7WXWmZXu7Iq5pl5/vptV5N2mq+DGFuS/ulaDjtaoLpYzuD6u8UgrUKHfgo7fDTSiBA== -fuse.js@^3.4.6: +fuse.js@^3.6.1: version "3.6.1" resolved "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz#7de85fdd6e1b3377c23ce010892656385fd9b10c" integrity sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw== @@ -11047,13 +10546,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gaze@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" - integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== - dependencies: - globule "^1.0.0" - generic-names@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" @@ -11120,13 +10612,6 @@ get-port@^5.1.1: resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== -get-proxy@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" - integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== - dependencies: - npm-conf "^1.1.0" - get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -11137,19 +10622,6 @@ get-stdin@^6.0.0: resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== -get-stream@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - -get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -11188,16 +10660,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gifsicle@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/gifsicle/-/gifsicle-4.0.1.tgz#30e1e61e3ee4884ef702641b2e98a15c2127b2e2" - integrity sha512-A/kiCLfDdV+ERV/UB+2O41mifd+RxH8jlRG8DMxZO84Bma/Fw0htqZ+hY2iaalLRNyUu7tYZQslqUBJxBggxbg== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.0" - execa "^1.0.0" - logalot "^2.0.0" - git-raw-commits@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5" @@ -11247,7 +10709,7 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -github-slugger@^1.2.1, github-slugger@^1.3.0: +github-slugger@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz#9bd0a95c5efdfc46005e82a906ef8e2a059124c9" integrity sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q== @@ -11284,12 +10746,19 @@ glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: dependencies: is-glob "^4.0.1" +glob-promise@^3.4.0: + version "3.4.0" + resolved "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz#b6b8f084504216f702dc2ce8c9bc9ac8866fdb20" + integrity sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw== + dependencies: + "@types/glob" "*" + glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1: +glob@7.1.6, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.6" resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -11383,7 +10852,7 @@ globby@11.0.1, globby@^11.0.0: merge2 "^1.3.0" slash "^3.0.0" -globby@8.0.2, globby@^8.0.1: +globby@8.0.2: version "8.0.2" resolved "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== @@ -11447,15 +10916,6 @@ globby@^9.2.0: pify "^4.0.1" slash "^2.0.0" -globule@^1.0.0: - version "1.3.2" - resolved "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4" - integrity sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA== - dependencies: - glob "~7.1.1" - lodash "~4.17.10" - minimatch "~3.0.2" - good-listener@^1.2.2: version "1.2.2" resolved "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" @@ -11501,49 +10961,6 @@ got@^11.5.2: p-cancelable "^2.0.0" responselike "^2.0.0" -got@^7.0.0: - version "7.1.0" - resolved "https://registry.npmjs.org/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - -got@^8.3.1: - version "8.3.2" - resolved "https://registry.npmjs.org/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - got@^9.6.0: version "9.6.0" resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -11561,7 +10978,7 @@ got@^9.6.0: to-readable-stream "^1.0.0" url-parse-lax "^3.0.0" -graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -11692,17 +11109,6 @@ graphql@^14.5.3: dependencies: iterall "^1.2.2" -gray-matter@^2.1.0: - version "2.1.1" - resolved "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz#3042d9adec2a1ded6a7707a9ed2380f8a17a430e" - integrity sha1-MELZrewqHe1qdwep7SOA+KF6Qw4= - dependencies: - ansi-red "^0.1.1" - coffee-script "^1.12.4" - extend-shallow "^2.0.1" - js-yaml "^3.8.1" - toml "^2.3.2" - growly@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -11713,15 +11119,6 @@ gud@^1.0.0: resolved "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== -gulp-header@^1.7.1: - version "1.8.12" - resolved "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" - integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== - dependencies: - concat-with-sourcemaps "*" - lodash.template "^4.4.0" - through2 "^2.0.0" - gzip-size@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" @@ -11787,23 +11184,11 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== -has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -11908,21 +11293,23 @@ highlight.js@^10.1.1, highlight.js@~10.1.0: resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-10.1.2.tgz#c20db951ba1c22c055010648dfffd7b2a968e00c" integrity sha512-Q39v/Mn5mfBlMff9r+zzA+gWxRsCRKwEMvYTiisLr/XUiFI/4puWt0Ojdko3R3JCNWGdOWaA5g/Yxqa23kC5AA== -highlight.js@^9.16.2: - version "9.18.3" - resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz#a1a0a2028d5e3149e2380f8a865ee8516703d634" - integrity sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ== - -highlight.js@~9.13.0: - version "9.13.1" - resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" - integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A== - highlight.js@~9.15.0, highlight.js@~9.15.1: version "9.15.10" resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2" integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw== +history@^4.9.0: + version "4.10.1" + resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + history@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/history/-/history-5.0.0.tgz#0cabbb6c4bbf835addb874f8259f6d25101efd08" @@ -11939,7 +11326,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -11983,7 +11370,7 @@ hsla-regex@^1.0.0: resolved "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= -html-comment-regex@^1.1.0, html-comment-regex@^1.1.2: +html-comment-regex@^1.1.0: version "1.1.2" resolved "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== @@ -12035,10 +11422,10 @@ html-to-react@^1.3.4: lodash.camelcase "^4.3.0" ramda "^0.26" -html-webpack-plugin@^4.0.0-beta.2, html-webpack-plugin@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.3.0.tgz#53bf8f6d696c4637d5b656d3d9863d89ce8174fd" - integrity sha512-C0fzKN8yQoVLTelcJxZfJCE+aAvQiY2VUf3UuKrR4a9k5UMWYOtpDLsaXwATbcVCnI05hUS7L9ULQHWLZhyi3w== +html-webpack-plugin@^4.2.1, html-webpack-plugin@^4.3.0: + version "4.4.1" + resolved "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.4.1.tgz#61ab85aa1a84ba181443345ebaead51abbb84149" + integrity sha512-nEtdEIsIGXdXGG7MjTTZlmhqhpHU9pJFc1OYxcP36c5/ZKP6b0BJMww2QTvJGQYA9aMxUnjDujpZdYcVOXiBCQ== dependencies: "@types/html-minifier-terser" "^5.0.0" "@types/tapable" "^1.0.5" @@ -12057,7 +11444,7 @@ html2canvas@1.0.0-alpha.12: dependencies: css-line-break "1.0.1" -htmlparser2@^3.3.0, htmlparser2@^3.9.1: +htmlparser2@^3.3.0: version "3.10.1" resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -12079,7 +11466,7 @@ htmlparser2@^4.0, htmlparser2@^4.1.0: domutils "^2.0.0" entities "^2.0.0" -http-cache-semantics@3.8.1, http-cache-semantics@^3.8.1: +http-cache-semantics@^3.8.1: version "3.8.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== @@ -12222,14 +11609,14 @@ humanize-ms@^1.2.1: ms "^2.0.0" husky@^4.2.3: - version "4.2.5" - resolved "https://registry.npmjs.org/husky/-/husky-4.2.5.tgz#2b4f7622673a71579f901d9885ed448394b5fa36" - integrity sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ== + version "4.3.0" + resolved "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz#0b2ec1d66424e9219d359e26a51c58ec5278f0de" + integrity sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA== dependencies: chalk "^4.0.0" ci-info "^2.0.0" compare-versions "^3.6.0" - cosmiconfig "^6.0.0" + cosmiconfig "^7.0.0" find-versions "^3.2.0" opencollective-postinstall "^2.0.2" pkg-dir "^4.2.0" @@ -12305,53 +11692,6 @@ ignore@^5.1.1, ignore@^5.1.4: resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== -imagemin-gifsicle@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-6.0.1.tgz#6abad4e95566d52e5a104aba1c24b4f3b48581b3" - integrity sha512-kuu47c6iKDQ6R9J10xCwL0lgs0+sMz3LRHqRcJ2CRBWdcNmo3T5hUaM8hSZfksptZXJLGKk8heSAvwtSdB1Fng== - dependencies: - exec-buffer "^3.0.0" - gifsicle "^4.0.0" - is-gif "^3.0.0" - -imagemin-jpegtran@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/imagemin-jpegtran/-/imagemin-jpegtran-6.0.0.tgz#c8d3bcfb6ec9c561c20a987142854be70d90b04f" - integrity sha512-Ih+NgThzqYfEWv9t58EItncaaXIHR0u9RuhKa8CtVBlMBvY0dCIxgQJQCfwImA4AV1PMfmUKlkyIHJjb7V4z1g== - dependencies: - exec-buffer "^3.0.0" - is-jpg "^2.0.0" - jpegtran-bin "^4.0.0" - -imagemin-optipng@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/imagemin-optipng/-/imagemin-optipng-6.0.0.tgz#a6bfc7b542fc08fc687e83dfb131249179a51a68" - integrity sha512-FoD2sMXvmoNm/zKPOWdhKpWdFdF9qiJmKC17MxZJPH42VMAp17/QENI/lIuP7LCUnLVAloO3AUoTSNzfhpyd8A== - dependencies: - exec-buffer "^3.0.0" - is-png "^1.0.0" - optipng-bin "^5.0.0" - -imagemin-svgo@^7.0.0: - version "7.1.0" - resolved "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-7.1.0.tgz#528a42fd3d55eff5d4af8fd1113f25fb61ad6d9a" - integrity sha512-0JlIZNWP0Luasn1HT82uB9nU9aa+vUj6kpT+MjPW11LbprXC+iC4HDwn1r4Q2/91qj4iy9tRZNsFySMlEpLdpg== - dependencies: - is-svg "^4.2.1" - svgo "^1.3.2" - -imagemin@^6.0.0: - version "6.1.0" - resolved "https://registry.npmjs.org/imagemin/-/imagemin-6.1.0.tgz#62508b465728fea36c03cdc07d915fe2d8cf9e13" - integrity sha512-8ryJBL1CN5uSHpiBMX0rJw79C9F9aJqMnjGnrd/1CafegpNuA81RBAAru/jQQEOWlOJJlpRnlcVFF6wq+Ist0A== - dependencies: - file-type "^10.7.0" - globby "^8.0.1" - make-dir "^1.0.0" - p-pipe "^1.1.0" - pify "^4.0.1" - replace-ext "^1.0.0" - immer@1.10.0: version "1.10.0" resolved "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" @@ -12384,7 +11724,7 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.0.0, import-fresh@^3.1.0: +import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== @@ -12411,11 +11751,6 @@ import-lazy@^2.1.0: resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= -import-lazy@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" - integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== - import-local@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -12514,25 +11849,6 @@ inline-style-prefixer@^4.0.0: bowser "^1.7.3" css-in-js-utils "^2.0.0" -inquirer@6.5.0: - version "6.5.0" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" - integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - inquirer@7.0.4: version "7.0.4" resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" @@ -12617,14 +11933,6 @@ interpret@^2.0.0, interpret@^2.2.0: resolved "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== -into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: version "2.2.4" resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -12807,7 +12115,7 @@ is-docker@^2.0.0: resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== -is-dom@^1.0.9: +is-dom@^1.0.9, is-dom@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz#af1fced292742443bb59ca3f76ab5e80907b4e8a" integrity sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ== @@ -12859,7 +12167,7 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-function@^1.0.1, is-function@^1.0.2: +is-function@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== @@ -12869,13 +12177,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-gif@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-gif/-/is-gif-3.0.0.tgz#c4be60b26a301d695bb833b20d9b5d66c6cf83b1" - integrity sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw== - dependencies: - file-type "^10.4.0" - is-glob@4.0.1, is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" @@ -12920,11 +12221,6 @@ is-interactive@^1.0.0: resolved "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== -is-jpg@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz#2e1997fa6e9166eaac0242daae443403e4ef1d97" - integrity sha1-LhmX+m6RZuqsAkLarkQ0A+TvHZc= - is-map@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" @@ -12935,23 +12231,11 @@ is-module@^1.0.0: resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= -is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= - is-npm@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== -is-number@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" - integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= - dependencies: - kind-of "^3.0.2" - is-number@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -12959,11 +12243,6 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-number@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" - integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== - is-number@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -13034,11 +12313,6 @@ is-plain-object@^3.0.0: dependencies: isobject "^4.0.0" -is-png@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-png/-/is-png-1.1.0.tgz#d574b12bf275c0350455570b0e5b57ab062077ce" - integrity sha1-1XSxK/J1wDUEVVcLDltXqwYgd84= - is-potential-custom-element-name@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" @@ -13080,11 +12354,6 @@ is-resolvable@^1.0.0: resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== -is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - is-root@2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" @@ -13102,7 +12371,7 @@ is-ssh@^1.3.0: dependencies: protocols "^1.1.0" -is-stream@^1.0.0, is-stream@^1.1.0: +is-stream@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -13124,13 +12393,6 @@ is-svg@^3.0.0: dependencies: html-comment-regex "^1.1.0" -is-svg@^4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/is-svg/-/is-svg-4.2.1.tgz#095b496e345fec9211c2a7d5d021003e040d6f81" - integrity sha512-PHx3ANecKsKNl5y5+Jvt53Y4J7MfMpbNZkv384QNiswMKAWIbvcqbPz+sYbFKJI8Xv3be01GSFniPmoaP+Ai5A== - dependencies: - html-comment-regex "^1.1.2" - is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -13157,11 +12419,6 @@ is-unc-path@^1.0.0: dependencies: unc-path-regex "^0.1.2" -is-url@^1.2.2: - version "1.2.4" - resolved "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" - integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== - is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" @@ -13192,12 +12449,7 @@ is-wsl@^1.1.0: resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= -is-wsl@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz#4a1c152d429df3d441669498e2486d3596ebaf1d" - integrity sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog== - -is-wsl@^2.2.0: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -13209,14 +12461,10 @@ is-yarn-global@^0.3.0: resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== -is2@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/is2/-/is2-2.0.1.tgz#8ac355644840921ce435d94f05d3a94634d3481a" - integrity sha512-+WaJvnaA7aJySz2q/8sLjMb2Mw14KTplHmSwcSpZ/fWJPkUmqw3YTzSWbPJ7OAwRvdYTWF2Wg+yYJ1AdP5Z8CA== - dependencies: - deep-is "^0.1.3" - ip-regex "^2.1.0" - is-url "^1.2.2" +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" @@ -13267,20 +12515,7 @@ istanbul-lib-coverage@^3.0.0: resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== -istanbul-lib-instrument@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6" - integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg== - dependencies: - "@babel/core" "^7.7.5" - "@babel/parser" "^7.7.5" - "@babel/template" "^7.7.4" - "@babel/traverse" "^7.7.4" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-instrument@^4.0.3: +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== @@ -13316,14 +12551,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2: version "1.3.0" resolved "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" @@ -13342,6 +12569,16 @@ iterate-value@^1.0.0: es-get-iterator "^1.0.2" iterate-iterator "^1.0.1" +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + jenkins@^0.28.0: version "0.28.0" resolved "https://registry.npmjs.org/jenkins/-/jenkins-0.28.0.tgz#72d6fcc452145403b34f6d4ecbd877ee1ab77fca" @@ -13749,15 +12986,7 @@ jest-watcher@^26.3.0: jest-util "^26.3.0" string-length "^4.0.1" -jest-worker@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-25.1.0.tgz#75d038bad6fdf58eba0d2ec1835856c497e3907a" - integrity sha512-ZHhHtlxOWSxCoNOKHGbiLzXnl42ga9CxDr27H36Qn+15pQZd3R/F24jrmjDelw9j/iHUIWMWs08/u2QN50HHOg== - dependencies: - merge-stream "^2.0.0" - supports-color "^7.0.0" - -jest-worker@^26.3.0: +jest-worker@^26.2.1, jest-worker@^26.3.0: version "26.3.0" resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw== @@ -13782,15 +13011,6 @@ jose@^1.27.1: dependencies: "@panva/asn1.js" "^1.0.0" -jpegtran-bin@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/jpegtran-bin/-/jpegtran-bin-4.0.0.tgz#d00aed809fba7aa6f30817e59eee4ddf198f8f10" - integrity sha512-2cRl1ism+wJUoYAYFt6O/rLBfpXNWG2dUWbgcEkTt5WGMnqI46eEro8T4C5zGROxKRqyKpCBSdHPvt5UYCtxaQ== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.0" - logalot "^2.0.0" - js-cookie@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" @@ -13816,7 +13036,7 @@ js-tokens@^3.0.2: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@^3.13.1, js-yaml@^3.14.0, js-yaml@^3.8.1, js-yaml@^3.8.3: +js-yaml@^3.13.1, js-yaml@^3.14.0, js-yaml@^3.8.3: version "3.14.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== @@ -14177,13 +13397,6 @@ jwt-decode@2.2.0: resolved "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79" integrity sha1-fYa9VmefWM5qhHBKZX3TkruoGnk= -keyv@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - keyv@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" @@ -14296,13 +13509,6 @@ lazy-cache@^1.0.3: resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= -lazy-cache@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" - integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ= - dependencies: - set-getter "^0.1.0" - lazy-universal-dotenv@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz#a6c8938414bca426ab8c9463940da451a911db38" @@ -14425,16 +13631,6 @@ lint-staged@^10.1.0: string-argv "0.3.1" stringify-object "^3.3.0" -list-item@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz#0c65d00e287cb663ccb3cb3849a77e89ec268a56" - integrity sha1-DGXQDih8tmPMs8s4Sad+iewmilY= - dependencies: - expand-range "^1.8.1" - extend-shallow "^2.0.1" - is-number "^2.1.0" - repeat-string "^1.5.2" - listr-silent-renderer@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz#924b5a3757153770bf1a8e3fbf74b8bbf3f9242e" @@ -14493,11 +13689,6 @@ listr@^0.14.3: p-map "^2.0.0" rxjs "^6.3.3" -livereload-js@^2.3.0: - version "2.4.0" - resolved "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" - integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== - load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -14554,7 +13745,7 @@ loader-utils@1.2.3: emojis-list "^2.0.0" json5 "^1.0.1" -loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== @@ -14610,47 +13801,22 @@ lodash.assign@^4.1.0, lodash.assign@^4.2.0: resolved "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc= -lodash.assignin@^4.0.9: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= - -lodash.bind@^4.1.4: - version "4.2.1" - resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" - integrity sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU= - lodash.camelcase@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.chunk@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz#66e5ce1f76ed27b4303d8c6512e8d1216e8106bc" - integrity sha1-ZuXOH3btJ7QwPYxlEujRIW6BBrw= - lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= -lodash.debounce@^4, lodash.debounce@^4.0.8: +lodash.debounce@^4: version "4.0.8" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.defaults@^4.0.1: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - -lodash.filter@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" - integrity sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4= - -lodash.flatten@^4.2.0, lodash.flatten@^4.4.0: +lodash.flatten@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= @@ -14660,11 +13826,6 @@ lodash.flattendeep@^4.0.0: resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= -lodash.foreach@^4.3.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" - integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= - lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -14675,62 +13836,27 @@ lodash.ismatch@^4.4.0: resolved "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= -lodash.map@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" - integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM= - lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.merge@^4.4.0: - version "4.6.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - lodash.once@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= -lodash.padstart@^4.6.1: - version "4.6.1" - resolved "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz#d2e3eebff0d9d39ad50f5cbd1b52a7bce6bb611b" - integrity sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs= - -lodash.pick@^4.2.1: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= - -lodash.reduce@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" - integrity sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs= - -lodash.reject@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" - integrity sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU= - lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= -lodash.some@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" - integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= -lodash.template@^4.0.2, lodash.template@^4.4.0, lodash.template@^4.5.0: +lodash.template@^4.0.2, lodash.template@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== @@ -14745,11 +13871,6 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= - lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -14760,7 +13881,7 @@ lodash.without@^4.4.0: resolved "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= -lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.2.1, lodash@~4.17.10: +lodash@^4.0.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.2.1: version "4.17.20" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -14772,6 +13893,13 @@ log-symbols@^1.0.2: dependencies: chalk "^1.0.0" +log-symbols@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + log-symbols@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" @@ -14805,14 +13933,6 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" -logalot@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/logalot/-/logalot-2.1.0.tgz#5f8e8c90d304edf12530951a5554abb8c5e3f552" - integrity sha1-X46MkNME7fElMJUaVVSruMXj9VI= - dependencies: - figures "^1.3.5" - squeak "^1.0.0" - logform@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360" @@ -14829,17 +13949,20 @@ loglevel@^1.6.7, loglevel@^1.6.8: resolved "https://registry.npmjs.org/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== +loglevelnext@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/loglevelnext/-/loglevelnext-1.0.5.tgz#36fc4f5996d6640f539ff203ba819641680d75a2" + integrity sha512-V/73qkPuJmx4BcBF19xPBr+0ZRVBhc4POxvZTZdMeXpJ4NItXSJ/MSwuFT0kQJlCbXvdlZoQQ/418bS1y9Jh6A== + dependencies: + es6-symbol "^3.1.1" + object.assign "^4.1.0" + long@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== -longest@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -14861,11 +13984,6 @@ lower-case@^2.0.1: dependencies: tslib "^1.10.0" -lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -14892,32 +14010,6 @@ lowlight@^1.14.0: fault "^1.0.0" highlight.js "~10.1.0" -lowlight@~1.11.0: - version "1.11.0" - resolved "https://registry.npmjs.org/lowlight/-/lowlight-1.11.0.tgz#1304d83005126d4e8b1dc0f07981e9b689ec2efc" - integrity sha512-xrGGN6XLL7MbTMdPD6NfWPwY43SNkjf/d0mecSx/CW36fUZTjRHEq0/Cdug3TWKtRXLWi7iMl1eP0olYxj/a4A== - dependencies: - fault "^1.0.2" - highlight.js "~9.13.0" - -lpad-align@^1.0.1: - version "1.1.2" - resolved "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz#21f600ac1c3095c3c6e497ee67271ee08481fe9e" - integrity sha1-IfYArBwwlcPG5JfuZyce4ISB/p4= - dependencies: - get-stdin "^4.0.1" - indent-string "^2.1.0" - longest "^1.0.0" - meow "^3.3.0" - -lru-cache@^4.0.1: - version "4.1.5" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lru-cache@^5.0.0, lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -14925,6 +14017,13 @@ lru-cache@^5.0.0, lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lru-queue@0.1: version "0.1.0" resolved "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" @@ -14944,7 +14043,7 @@ magic-string@^0.25.2: dependencies: sourcemap-codec "^1.4.4" -make-dir@^1.0.0, make-dir@^1.2.0: +make-dir@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== @@ -15066,11 +14165,6 @@ markdown-it@^9.1.0: mdurl "^1.0.1" uc.micro "^1.0.5" -markdown-link@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz#32c5c65199a6457316322d1e4229d13407c8c7cf" - integrity sha1-MsXGUZmmRXMWMi0eQinRNAfIx88= - markdown-to-jsx@^6.11.4: version "6.11.4" resolved "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-6.11.4.tgz#b4528b1ab668aef7fe61c1535c27e837819392c5" @@ -15079,23 +14173,10 @@ markdown-to-jsx@^6.11.4: prop-types "^15.6.2" unquote "^1.1.0" -markdown-toc@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz#44a15606844490314afc0444483f9e7b1122c339" - integrity sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg== - dependencies: - concat-stream "^1.5.2" - diacritics-map "^0.1.0" - gray-matter "^2.1.0" - lazy-cache "^2.0.2" - list-item "^1.1.1" - markdown-link "^0.1.1" - minimist "^1.2.0" - mixin-deep "^1.1.3" - object.pick "^1.2.0" - remarkable "^1.7.1" - repeat-string "^1.6.1" - strip-color "^0.1.0" +material-colors@^1.2.1: + version "1.2.6" + resolved "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" + integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== material-table@1.68.0: version "1.68.0" @@ -15115,11 +14196,6 @@ material-table@1.68.0: react-beautiful-dnd "^13.0.0" react-double-scrollbar "0.0.15" -math-random@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" - integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== - md5.js@^1.3.4: version "1.3.5" resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -15323,7 +14399,7 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.44.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: +mime-db@1.44.0, "mime-db@>= 1.43.0 < 2": version "1.44.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== @@ -15394,15 +14470,13 @@ min-indent@^1.0.0: resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= -mini-css-extract-plugin@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz#5ba8290fbb4179a43dd27cca444ba150bee743a0" - integrity sha512-RQIw6+7utTYn8DBGsf/LpRgZCJMpZt+kuawJ/fju0KiOL6nAaTBNmCJwS7HtwSCXfS47gCkmtBFS7HdsquhdxQ== +mini-create-react-context@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040" + integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA== dependencies: - loader-utils "^1.1.0" - normalize-url "1.9.1" - schema-utils "^1.0.0" - webpack-sources "^1.1.0" + "@babel/runtime" "^7.5.5" + tiny-warning "^1.0.3" mini-css-extract-plugin@^0.9.0: version "0.9.0" @@ -15424,7 +14498,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: +minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -15487,10 +14561,10 @@ minizlib@^1.2.1: dependencies: minipass "^2.9.0" -minizlib@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz#fd52c645301ef09a63a2c209697c294c6ce02cf3" - integrity sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA== +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" yallist "^4.0.0" @@ -15516,7 +14590,7 @@ mitt@^1.1.2: resolved "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d" integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw== -mixin-deep@^1.1.3, mixin-deep@^1.2.0: +mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== @@ -15556,6 +14630,11 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.4, mkdirp@^0.5.5, mkdir dependencies: minimist "^1.2.5" +mock-fs@^4.13.0: + version "4.13.0" + resolved "https://registry.npmjs.org/mock-fs/-/mock-fs-4.13.0.tgz#31c02263673ec3789f90eb7b6963676aa407a598" + integrity sha512-DD0vOdofJdoaRNtnWcrXe6RQbpHkPPmtqGq14uRX0F8ZKJ5nv89CVTYl/BZdppDxBDaV0hl75htg3abpEWlPZA== + modify-values@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -15797,11 +14876,16 @@ node-fetch-npm@^2.0.2: json-parse-better-errors "^1.0.0" safe-buffer "^5.1.1" -node-fetch@2.6.0, node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0: +node-fetch@2.6.0: version "2.6.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== +node-fetch@^2.1.2, node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.5.0, node-fetch@^2.6.0: + version "2.6.1" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-forge@0.9.0: version "0.9.0" resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -15934,7 +15018,7 @@ node-pre-gyp@^0.13.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.29, node-releases@^1.1.52, node-releases@^1.1.58: +node-releases@^1.1.52, node-releases@^1.1.58: version "1.1.60" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.60.tgz#6948bdfce8286f0b5d0e5a88e8384e954dfe7084" integrity sha512-gsO4vjEdQaTusZAEebUWp2a5d7dF5DYoIpDG7WySnk7BuZDW+GPpHXoXXuYawRBr/9t5q54tirPz79kFIWg4dA== @@ -16069,15 +15153,6 @@ normalize-url@1.9.1: query-string "^4.1.0" sort-keys "^1.0.0" -normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - normalize-url@^3.0.0, normalize-url@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" @@ -16095,14 +15170,6 @@ npm-bundled@^1.0.1: dependencies: npm-normalize-package-bin "^1.0.1" -npm-conf@^1.1.0: - version "1.1.3" - resolved "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" - integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== - dependencies: - config-chain "^1.1.11" - pify "^3.0.0" - npm-lifecycle@^3.1.2: version "3.1.4" resolved "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.4.tgz#de6975c7d8df65f5150db110b57cce498b0b604c" @@ -16330,6 +15397,11 @@ object.values@^1.1.0, object.values@^1.1.1: function-bind "^1.1.1" has "^1.0.3" +objectorarray@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.4.tgz#d69b2f0ff7dc2701903d308bb85882f4ddb49483" + integrity sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w== + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -16388,17 +15460,10 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@^6.3.0: - version "6.4.0" - resolved "https://registry.npmjs.org/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" - integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg== - dependencies: - is-wsl "^1.1.0" - -open@^7.0.0, open@^7.0.2: - version "7.0.3" - resolved "https://registry.npmjs.org/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" - integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== +open@^7.0.2, open@^7.0.3: + version "7.2.1" + resolved "https://registry.npmjs.org/open/-/open-7.2.1.tgz#07b0ade11a43f2a8ce718480bdf3d7563a095195" + integrity sha512-xbYCJib4spUdmcs0g/2mK1nKo/jO2T7INClWd/beL7PFkXRWgr8B23ssDHX/USPn2M2IjDR5UdpYs6I67SnTSA== dependencies: is-docker "^2.0.0" is-wsl "^2.1.1" @@ -16446,15 +15511,6 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" -optipng-bin@^5.0.0: - version "5.1.0" - resolved "https://registry.npmjs.org/optipng-bin/-/optipng-bin-5.1.0.tgz#a7c7ab600a3ab5a177dae2f94c2d800aa386b5a9" - integrity sha512-9baoqZTNNmXQjq/PQTWEXbVV3AMO2sI/GaaqZJZ8SExfAzjijeAP7FEeT+TtyumSw7gr0PZtSUYB/Ke7iHQVKA== - dependencies: - bin-build "^3.0.0" - bin-wrapper "^4.0.0" - logalot "^2.0.0" - ora@*, ora@^4.0.3: version "4.0.4" resolved "https://registry.npmjs.org/ora/-/ora-4.0.4.tgz#e8da697cc5b6a47266655bf68e0fb588d29a545d" @@ -16481,13 +15537,6 @@ os-browserify@^0.3.0: resolved "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-filter-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz#1c0b62d5f3a2442749a2d139e6dddee6e81d8d16" - integrity sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg== - dependencies: - arch "^2.1.0" - os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -16526,15 +15575,10 @@ ospath@^1.2.2: resolved "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" integrity sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs= -p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - -p-cancelable@^0.4.0: - version "0.4.1" - resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== +overlayscrollbars@^1.10.2: + version "1.13.0" + resolved "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.0.tgz#1edb436328133b94877b558f77966d5497ca36a7" + integrity sha512-p8oHrMeRAKxXDMPI/EBNITj/zTVHKNnAnM59Im+xnoZUlV07FyTg46wom2286jJlXGGfcPFG/ba5NUiCwWNd4w== p-cancelable@^1.0.0: version "1.1.0" @@ -16551,20 +15595,6 @@ p-each-series@^2.1.0: resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== -p-event@^1.0.0: - version "1.3.0" - resolved "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085" - integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU= - dependencies: - p-timeout "^1.1.1" - -p-event@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" - integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== - dependencies: - p-timeout "^2.0.1" - p-event@^4.0.0: version "4.2.0" resolved "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" @@ -16582,12 +15612,7 @@ p-finally@^2.0.0: resolved "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== -p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - -p-limit@3.0.2: +p-limit@3.0.2, p-limit@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe" integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg== @@ -16601,7 +15626,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.2: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.2.2" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== @@ -16655,7 +15680,7 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-pipe@^1.1.0, p-pipe@^1.2.0: +p-pipe@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/p-pipe/-/p-pipe-1.2.0.tgz#4b1a11399a11520a67790ee5a0c1d5881d6befe9" integrity sha1-SxoROZoRUgpneQ7loMHViB1r7+k= @@ -16687,20 +15712,6 @@ p-retry@^3.0.1: dependencies: retry "^0.12.0" -p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= - dependencies: - p-finally "^1.0.0" - -p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - p-timeout@^3.1.0: version "3.2.0" resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" @@ -17091,6 +16102,13 @@ path-to-regexp@2.2.1: resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== +path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -17322,13 +16340,6 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-up@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" - integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= - dependencies: - find-up "^2.1.0" - pkg-up@3.1.0, pkg-up@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" @@ -17353,26 +16364,31 @@ pn@^1.1.0: resolved "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== -pnp-webpack-plugin@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.5.0.tgz#62a1cd3068f46d564bb33c56eb250e4d586676eb" - integrity sha512-jd9olUr9D7do+RN8Wspzhpxhgp1n6Vd0NtQ4SFkmIACZoEL1nkyAdW9Ygrinjec0vgDcWjscFQQ1gDW8rsfKTg== +pnp-webpack-plugin@1.6.4: + version "1.6.4" + resolved "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" + integrity sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg== dependencies: - ts-pnp "^1.1.2" + ts-pnp "^1.1.6" -polished@^3.3.1, polished@^3.4.4: +polished@^3.4.4: version "3.6.5" resolved "https://registry.npmjs.org/polished/-/polished-3.6.5.tgz#dbefdde64c675935ec55119fe2a2ab627ca82e9c" integrity sha512-VwhC9MlhW7O5dg/z7k32dabcAFW1VI2+7fSe8cE/kXcfL7mVdoa5UxciYGW2sJU78ldDLT6+ROEKIZKFNTnUXQ== dependencies: "@babel/runtime" "^7.9.2" -popper.js@^1.14.1, popper.js@^1.14.4, popper.js@^1.14.7: +popper.js@1.16.1-lts: + version "1.16.1-lts" + resolved "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05" + integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA== + +popper.js@^1.14.4, popper.js@^1.14.7: version "1.16.1" resolved "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== -portfinder@^1.0.25, portfinder@^1.0.26: +portfinder@^1.0.26: version "1.0.28" resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== @@ -17761,7 +16777,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^ resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== -"postcss@5 - 7", postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: +"postcss@5 - 7", postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: version "7.0.32" resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz#4310d6ee347053da3433db2be492883d62cec59d" integrity sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw== @@ -17825,7 +16841,7 @@ prelude-ls@~1.1.2: resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -prepend-http@^1.0.0, prepend-http@^1.0.1: +prepend-http@^1.0.0: version "1.0.4" resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= @@ -17835,12 +16851,7 @@ prepend-http@^2.0.0: resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^1.16.4: - version "1.19.1" - resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" - integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== - -prettier@^2.0.5: +prettier@^2.0.5, prettier@~2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== @@ -17883,7 +16894,7 @@ pretty-hrtime@^1.0.3: resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -prismjs@^1.17.1, prismjs@^1.21.0, prismjs@^1.8.4, prismjs@~1.21.0: +prismjs@^1.21.0, prismjs@^1.8.4, prismjs@~1.21.0: version "1.21.0" resolved "https://registry.npmjs.org/prismjs/-/prismjs-1.21.0.tgz#36c086ec36b45319ec4218ee164c110f9fc015a3" integrity sha512-uGdSIu1nk3kej2iZsLyDoJ7e9bnPzIgY0naW/HdknGj61zScaprVEVGHrPoXqI+M9sP0NDnTK2jpkvmldpuqDw== @@ -18059,11 +17070,6 @@ ps-tree@1.2.0: dependencies: event-stream "=3.3.4" -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - psl@^1.1.28: version "1.8.0" resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" @@ -18151,7 +17157,7 @@ qs@6.7.0: resolved "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== -qs@^6.4.0, qs@^6.5.1, qs@^6.6.0, qs@^6.9.4: +qs@^6.5.1, qs@^6.6.0, qs@^6.9.4: version "6.9.4" resolved "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== @@ -18169,15 +17175,6 @@ query-string@^4.1.0: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - querystring-browser@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/querystring-browser/-/querystring-browser-1.0.4.tgz#f2e35881840a819bc7b1bf597faf0979e6622dc6" @@ -18250,15 +17247,6 @@ ramldt2jsonschema@^1.1.0: json-schema-migrate "^0.2.0" webapi-parser "^0.5.0" -randomatic@^3.0.0: - version "3.1.1" - resolved "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" - integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== - dependencies: - is-number "^4.0.0" - kind-of "^6.0.0" - math-random "^1.0.1" - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -18294,22 +17282,6 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@~1.1.0: - version "1.1.7" - resolved "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" - integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= - dependencies: - bytes "1" - string_decoder "0.10" - -raw-loader@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz#5e9d399a5a222cc0de18f42c3bc5e49677532b3f" - integrity sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA== - dependencies: - loader-utils "^1.1.0" - schema-utils "^2.0.1" - raw-loader@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.1.tgz#14e1f726a359b68437e183d5a5b7d33a3eba6933" @@ -18360,12 +17332,17 @@ react-beautiful-dnd@^13.0.0: redux "^4.0.4" use-memo-one "^1.1.1" -react-clientside-effect@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.2.tgz#6212fb0e07b204e714581dd51992603d1accc837" - integrity sha512-nRmoyxeok5PBO6ytPvSjKp9xwXg9xagoTK1mMjwnQxqM9Hd7MNPl+LS1bOSOe+CV2+4fnEquc7H/S8QD3q697A== +react-color@^2.17.0: + version "2.18.1" + resolved "https://registry.npmjs.org/react-color/-/react-color-2.18.1.tgz#2cda8cc8e06a9e2c52ad391a30ddad31972472f4" + integrity sha512-X5XpyJS6ncplZs74ak0JJoqPi+33Nzpv5RYWWxn17bslih+X7OlgmfpmGC1fNvdkK7/SGWYf1JJdn7D2n5gSuQ== dependencies: - "@babel/runtime" "^7.0.0" + "@icons/material" "^0.2.4" + lodash "^4.17.11" + material-colors "^1.2.1" + prop-types "^15.5.10" + reactcss "^1.2.0" + tinycolor2 "^1.4.1" react-copy-to-clipboard@5.0.1: version "5.0.1" @@ -18383,7 +17360,7 @@ react-debounce-input@^3.2.0: lodash.debounce "^4" prop-types "^15.7.2" -react-dev-utils@^10.2.1: +react-dev-utils@^10.0.0, react-dev-utils@^10.2.1: version "10.2.1" resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz#f6de325ae25fa4d546d09df4bb1befdc6dd19c19" integrity sha512-XxTbgJnYZmxuPtY3y/UV0D8/65NKkmaia4rXzViknVnZeVlklSh8u6TnaEYPfAi/Gh1TP4mEOXHI6jQOPbeakQ== @@ -18413,36 +17390,31 @@ react-dev-utils@^10.2.1: strip-ansi "6.0.0" text-table "0.2.0" -react-dev-utils@^9.0.0, react-dev-utils@^9.1.0: - version "9.1.0" - resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.1.0.tgz#3ad2bb8848a32319d760d0a84c56c14bdaae5e81" - integrity sha512-X2KYF/lIGyGwP/F/oXgGDF24nxDA2KC4b7AFto+eqzc/t838gpSGiaU8trTqHXOohuLxxc5qi1eDzsl9ucPDpg== +react-docgen-typescript-loader@^3.7.2: + version "3.7.2" + resolved "https://registry.npmjs.org/react-docgen-typescript-loader/-/react-docgen-typescript-loader-3.7.2.tgz#45cb2305652c0602767242a8700ad1ebd66bbbbd" + integrity sha512-fNzUayyUGzSyoOl7E89VaPKJk9dpvdSgyXg81cUkwy0u+NBvkzQG3FC5WBIlXda0k/iaxS+PWi+OC+tUiGxzPA== dependencies: - "@babel/code-frame" "7.5.5" - address "1.1.2" - browserslist "4.7.0" - chalk "2.4.2" - cross-spawn "6.0.5" - detect-port-alt "1.1.6" - escape-string-regexp "1.0.5" - filesize "3.6.1" - find-up "3.0.0" - fork-ts-checker-webpack-plugin "1.5.0" - global-modules "2.0.0" - globby "8.0.2" - gzip-size "5.1.1" - immer "1.10.0" - inquirer "6.5.0" - is-root "2.1.0" - loader-utils "1.2.3" - open "^6.3.0" - pkg-up "2.0.0" - react-error-overlay "^6.0.3" - recursive-readdir "2.2.2" - shell-quote "1.7.2" - sockjs-client "1.4.0" - strip-ansi "5.2.0" - text-table "0.2.0" + "@webpack-contrib/schema-utils" "^1.0.0-beta.0" + loader-utils "^1.2.3" + react-docgen-typescript "^1.15.0" + +react-docgen-typescript-plugin@^0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-0.5.2.tgz#2b294d75ef3145c36303da82be5d447cb67dc0dc" + integrity sha512-NQfWyWLmzUnedkiN2nPDb6Nkm68ik6fqbC3UvgjqYSeZsbKijXUA4bmV6aU7qICOXdop9PevPdjEgJuAN0nNVQ== + dependencies: + debug "^4.1.1" + endent "^2.0.1" + micromatch "^4.0.2" + react-docgen-typescript "^1.20.1" + react-docgen-typescript-loader "^3.7.2" + tslib "^2.0.0" + +react-docgen-typescript@^1.15.0, react-docgen-typescript@^1.20.1: + version "1.20.4" + resolved "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.20.4.tgz#9a5655986077ccfc58c1a447f92c3d19f7a875bf" + integrity sha512-gE2SeseJd6+o981qr9VQJRbvFJ5LjLSKQiwhHsuLN4flt+lheKtG1jp2BPzrv2MKR5gmbLwpmNtK4wbLCPSZAw== react-docgen@^5.0.0: version "5.3.0" @@ -18458,7 +17430,7 @@ react-docgen@^5.0.0: node-dir "^0.1.10" strip-indent "^3.0.0" -react-dom@^16.12.0, react-dom@^16.13.1, react-dom@^16.8.3, react-dom@^16.8.4: +react-dom@^16.12.0, react-dom@^16.13.1, react-dom@^16.8.3: version "16.13.1" resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== @@ -18481,7 +17453,7 @@ react-draggable@^4.0.3: classnames "^2.2.5" prop-types "^15.6.0" -react-error-overlay@^6.0.3, react-error-overlay@^6.0.7: +react-error-overlay@^6.0.7: version "6.0.7" resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA== @@ -18496,18 +17468,6 @@ react-fast-compare@^3.1.1: resolved "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== -react-focus-lock@^2.1.0: - version "2.2.1" - resolved "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.2.1.tgz#1d12887416925dc53481914b7cedd39494a3b24a" - integrity sha512-47g0xYcCTZccdzKRGufepY8oZ3W1Qg+2hn6u9SHZ0zUB6uz/4K4xJe7yYFNZ1qT6m+2JDm82F6QgKeBTbjW4PQ== - dependencies: - "@babel/runtime" "^7.0.0" - focus-lock "^0.6.6" - prop-types "^15.6.2" - react-clientside-effect "^1.2.2" - use-callback-ref "^1.2.1" - use-sidecar "^1.0.1" - react-helmet-async@^1.0.2: version "1.0.4" resolved "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.0.4.tgz#079ef10b7fefcaee6240fefd150711e62463cc97" @@ -18576,13 +17536,13 @@ react-inspector@^2.3.0: is-dom "^1.0.9" prop-types "^15.6.1" -react-inspector@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/react-inspector/-/react-inspector-4.0.1.tgz#0f888f78ff7daccbc7be5d452b20c96dc6d5fbb8" - integrity sha512-xSiM6CE79JBqSj8Fzd9dWBHv57tLTH7OM57GP3VrE5crzVF3D5Khce9w1Xcw75OAbvrA0Mi2vBneR1OajKmXFg== +react-inspector@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/react-inspector/-/react-inspector-5.0.1.tgz#8a30f3d488c4f40203624bbe24800f508ae05d3a" + integrity sha512-qRIENuAIcRaytrmg/TL5nN5igYZMzyQqIKlWA8zoYRDltULsZC1bWy2Ua5wYJuwEYnC3gK4FCjcIQnb+5OyLsQ== dependencies: - "@babel/runtime" "^7.6.3" - is-dom "^1.0.9" + "@babel/runtime" "^7.8.7" + is-dom "^1.1.0" prop-types "^15.6.1" react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.6, react-is@^16.9.0: @@ -18590,7 +17550,7 @@ react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-i resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-lazylog@^4.5.2: +react-lazylog@^4.5.2, react-lazylog@^4.5.3: version "4.5.3" resolved "https://registry.npmjs.org/react-lazylog/-/react-lazylog-4.5.3.tgz#289e24995b5599e75943556ac63f5e2c04d0001e" integrity sha512-lyov32A/4BqihgXgtNXTHCajXSXkYHPlIEmV8RbYjHIMxCFSnmtdg4kDCI3vATz7dURtiFTvrw5yonHnrS+NNg== @@ -18633,15 +17593,15 @@ react-motion@^0.5.2: prop-types "^15.5.8" raf "^3.1.0" -react-popper-tooltip@^2.8.3: - version "2.10.1" - resolved "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.10.1.tgz#e10875f31916297c694d64a677d6f8fa0a48b4d1" - integrity sha512-cib8bKiyYcrIlHo9zXx81G0XvARfL8Jt+xum709MFCgQa3HTqTi4au3iJ9tm7vi7WU7ngnqbpWkMinBOtwo+IQ== +react-popper-tooltip@^2.11.0: + version "2.11.1" + resolved "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644" + integrity sha512-04A2f24GhyyMicKvg/koIOQ5BzlrRbKiAgP6L+Pdj1MVX3yJ1NeZ8+EidndQsbejFT55oW1b++wg2Z8KlAyhfQ== dependencies: - "@babel/runtime" "^7.7.4" - react-popper "^1.3.6" + "@babel/runtime" "^7.9.2" + react-popper "^1.3.7" -react-popper@^1.3.6: +react-popper@^1.3.7: version "1.3.7" resolved "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz#f6a3471362ef1f0d10a4963673789de1baca2324" integrity sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww== @@ -18686,6 +17646,35 @@ react-router-dom@6.0.0-beta.0: prop-types "^15.7.2" react-router "6.0.0-beta.0" +react-router-dom@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" + integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router@5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" + integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + react-router@6.0.0-beta.0: version "6.0.0-beta.0" resolved "https://registry.npmjs.org/react-router/-/react-router-6.0.0-beta.0.tgz#3e11f39b6ded4412c2fed9e4f989dd4c8156724d" @@ -18722,7 +17711,7 @@ react-string-replace@^0.4.1: dependencies: lodash "^4.17.4" -react-syntax-highlighter@=12.2.1: +react-syntax-highlighter@=12.2.1, react-syntax-highlighter@^12.2.1: version "12.2.1" resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz#14d78352da1c1c3f93c6698b70ec7c706b83493e" integrity sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA== @@ -18733,17 +17722,6 @@ react-syntax-highlighter@=12.2.1: prismjs "^1.8.4" refractor "^2.4.1" -react-syntax-highlighter@^11.0.2: - version "11.0.2" - resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-11.0.2.tgz#4e3f376e752b20d2f54e4c55652fd663149e4029" - integrity sha512-kqmpM2OH5OodInbEADKARwccwSQWBfZi0970l5Jhp4h39q9Q65C4frNcnd6uHE5pR00W8pOWj9HDRntj2G4Rww== - dependencies: - "@babel/runtime" "^7.3.1" - highlight.js "~9.13.0" - lowlight "~1.11.0" - prismjs "^1.8.4" - refractor "^2.4.1" - react-syntax-highlighter@^13.5.1: version "13.5.1" resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.1.tgz#f21737cf6d582474a0f18b06b52613f4349c0e64" @@ -18765,18 +17743,19 @@ react-test-renderer@^16.13.1: react-is "^16.8.6" scheduler "^0.19.1" -react-textarea-autosize@^7.1.0: - version "7.1.2" - resolved "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-7.1.2.tgz#70fdb333ef86bcca72717e25e623e90c336e2cda" - integrity sha512-uH3ORCsCa3C6LHxExExhF4jHoXYCQwE5oECmrRsunlspaDAbS4mGKNlWZqjLfInWtFQcf0o1n1jC/NGXFdUBCg== +react-textarea-autosize@^8.1.1: + version "8.2.0" + resolved "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.2.0.tgz#fae38653f5ec172a855fd5fffb39e466d56aebdb" + integrity sha512-grajUlVbkx6VdtSxCgzloUIphIZF5bKr21OYMceWPKkniy7H0mRAT/AXPrRtObAe+zUePnNlBwUc4ivVjUGIjw== dependencies: - "@babel/runtime" "^7.1.2" - prop-types "^15.6.0" + "@babel/runtime" "^7.10.2" + use-composed-ref "^1.0.0" + use-latest "^1.0.0" -react-transition-group@^4.0.0, react-transition-group@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz#fea832e386cf8796c58b61874a3319704f5ce683" - integrity sha512-1qRV1ZuVSdxPlPf4O8t7inxUGpdyO5zG9IoNfJxSO0ImU2A1YWkEQvFPuIPZmMLkg5hYs7vv5mMOyfgSkvAwvw== +react-transition-group@^4.0.0, react-transition-group@^4.4.0: + version "4.4.1" + resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" + integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw== dependencies: "@babel/runtime" "^7.5.5" dom-helpers "^5.0.1" @@ -18806,9 +17785,9 @@ react-use@^12.2.0: tslib "^1.10.0" react-use@^15.3.3: - version "15.3.3" - resolved "https://registry.npmjs.org/react-use/-/react-use-15.3.3.tgz#f16de7a16286c446388e8bd99680952fc3dc9a95" - integrity sha512-nYb94JbmDCaLZg3sOXmFW8HN+lXWxnl0caspXoYfZG1CON8JfLN9jMOyxRDUpm7dUq7WZ5mIept/ByqBQKJ0wQ== + version "15.3.4" + resolved "https://registry.npmjs.org/react-use/-/react-use-15.3.4.tgz#f853d310bd71f75b38900a8caa3db93f6dc6e872" + integrity sha512-cHq1dELW6122oi1+xX7lwNyE/ugZs5L902BuO8eFJCfn2api1KeuPVG1M/GJouVARoUf54S2dYFMKo5nQXdTag== dependencies: "@types/js-cookie" "2.2.6" "@xobotyi/scrollbar-width" "1.9.5" @@ -18842,7 +17821,7 @@ react-wait@^0.3.0: resolved "https://registry.npmjs.org/react-wait/-/react-wait-0.3.0.tgz#0cdd4d919012451a5bc3ab0a16d00c6fd9a8c10b" integrity sha512-kB5x/kMKWcn0uVr9gBdNz21/oGbQwEQnF3P9p6E9yLfJ9DRcKS0fagbgYMFI0YFOoyKDj+2q6Rwax0kTYJF37g== -react@^16.0.0, react@^16.12.0, react@^16.13.1, react@^16.8.3, react@^16.8.4: +react@^16.0.0, react@^16.12.0, react@^16.13.1, react@^16.8.3, react@^16.9.17: version "16.13.1" resolved "https://registry.npmjs.org/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== @@ -18851,6 +17830,13 @@ react@^16.0.0, react@^16.12.0, react@^16.13.1, react@^16.8.3, react@^16.8.4: object-assign "^4.1.1" prop-types "^15.6.2" +reactcss@^1.2.0: + version "1.2.3" + resolved "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" + integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== + dependencies: + lodash "^4.0.1" + read-cmd-shim@^1.0.1: version "1.0.5" resolved "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz#87e43eba50098ba5a32d0ceb583ab8e43b961c16" @@ -19111,7 +18097,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.2, regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: +regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: version "0.13.5" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== @@ -19209,15 +18195,7 @@ remark-parse@^5.0.0: vfile-location "^2.0.0" xtend "^4.0.1" -remarkable@^1.7.1: - version "1.7.4" - resolved "https://registry.npmjs.org/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" - integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== - dependencies: - argparse "^1.0.10" - autolinker "~0.28.0" - -remarkable@^2.0.0, remarkable@^2.0.1: +remarkable@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz#280ae6627384dfb13d98ee3995627ca550a12f31" integrity sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA== @@ -19263,11 +18241,6 @@ replace-ext@1.0.0: resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= -replace-ext@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" - integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== - replace-in-file@^6.0.0: version "6.1.0" resolved "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.1.0.tgz#9f9ddd7bb70d6ad231d2ad692e1b646e73d06647" @@ -19300,7 +18273,7 @@ request-promise-native@^1.0.5, request-promise-native@^1.0.8: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.53.0, request@^2.55.0, request@^2.85.0, request@^2.87.0, request@^2.88.0, request@^2.88.2: +request@^2.55.0, request@^2.85.0, request@^2.87.0, request@^2.88.0, request@^2.88.2: version "2.88.2" resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -19398,6 +18371,11 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -19417,7 +18395,7 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.12. dependencies: path-parse "^1.0.6" -responselike@1.0.2, responselike@^1.0.2: +responselike@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= @@ -19497,7 +18475,7 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -19511,7 +18489,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^3.0.0: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -19680,11 +18658,6 @@ safe-identifier@^0.4.1: resolved "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.1.tgz#b6516bf72594f03142b5f914f4c01842ccb1b678" integrity sha512-73tOz5TXsq3apuCc3vC8c9QRhhdNZGiBhHmPPjqpH4TO5oCDqk8UIsDcSs/RG6dYcFAkOOva0pqHS3u7hh7XXA== -safe-json-parse@~1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" - integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= - safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" @@ -19753,27 +18726,20 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.1, schema-utils@^2.5.0, schema-utils@^2.6.4, schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" - integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== +schema-utils@^2.6.5, schema-utils@^2.6.6, schema-utils@^2.7.0, schema-utils@^2.7.1: + version "2.7.1" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== dependencies: - "@types/json-schema" "^7.0.4" - ajv "^6.12.2" - ajv-keywords "^3.4.1" + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" screenfull@^5.0.0: version "5.0.2" resolved "https://registry.npmjs.org/screenfull/-/screenfull-5.0.2.tgz#b9acdcf1ec676a948674df5cd0ff66b902b0bed7" integrity sha512-cCF2b+L/mnEiORLN5xSAz6H3t18i2oHh9BA8+CQlAh5DRw2+NFAGQJOSYbcGw8B2k04g/lVvFcfZ83b3ysH5UQ== -seek-bzip@^1.0.5: - version "1.0.6" - resolved "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" - integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== - dependencies: - commander "^2.8.1" - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -19808,13 +18774,6 @@ semver-regex@^2.0.0: resolved "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== -semver-truncate@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/semver-truncate/-/semver-truncate-1.1.2.tgz#57f41de69707a62709a7e0104ba2117109ea47e8" - integrity sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g= - dependencies: - semver "^5.3.0" - "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -19874,6 +18833,13 @@ serialize-javascript@^2.1.2: resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + serve-favicon@^2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz#935d240cdfe0f5805307fdfe967d88942a2cbcf0" @@ -19927,13 +18893,6 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-getter@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" - integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y= - dependencies: - to-object-path "^0.3.0" - set-harmonic-interval@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" @@ -19994,11 +18953,6 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shallow-equal@^1.1.0: - version "1.2.1" - resolved "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da" - integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA== - shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" @@ -20033,7 +18987,7 @@ shell-quote@1.7.2: resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== -shelljs@^0.8.3, shelljs@^0.8.4: +shelljs@^0.8.3: version "0.8.4" resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== @@ -20088,41 +19042,11 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -simplebar-react@^1.0.0-alpha.6: - version "1.2.3" - resolved "https://registry.npmjs.org/simplebar-react/-/simplebar-react-1.2.3.tgz#bd81fa9827628470e9470d06caef6ece15e1c882" - integrity sha512-1EOWJzFC7eqHUp1igD1/tb8GBv5aPQA5ZMvpeDnVkpNJ3jAuvmrL2kir3HuijlxhG7njvw9ssxjjBa89E5DrJg== - dependencies: - prop-types "^15.6.1" - simplebar "^4.2.3" - -simplebar@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/simplebar/-/simplebar-4.2.3.tgz#dac40aced299c17928329eab3d5e6e795fafc10c" - integrity sha512-9no0pK7/1y+8/oTF3sy/+kx0PjQ3uk4cYwld5F1CJGk2gx+prRyUq8GRfvcVLq5niYWSozZdX73a2wIr1o9l/g== - dependencies: - can-use-dom "^0.1.0" - core-js "^3.0.1" - lodash.debounce "^4.0.8" - lodash.memoize "^4.1.2" - lodash.throttle "^4.1.1" - resize-observer-polyfill "^1.5.1" - sisteransi@^1.0.4: version "1.0.5" resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -sitemap@^3.2.2: - version "3.2.2" - resolved "https://registry.npmjs.org/sitemap/-/sitemap-3.2.2.tgz#3f77c358fa97b555c879e457098e39910095c62b" - integrity sha512-TModL/WU4m2q/mQcrDgNANn0P4LwprM9MMvG4hu5zP4c6IIKs2YLTu6nXXnNr8ODW/WFtxKggiJ1EGn2W0GNmg== - dependencies: - lodash.chunk "^4.2.0" - lodash.padstart "^4.6.1" - whatwg-url "^7.0.0" - xmlbuilder "^13.0.0" - slash@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -20247,13 +19171,6 @@ socks@~2.3.2: ip "1.1.5" smart-buffer "^4.1.0" -sort-keys-length@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" - integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= - dependencies: - sort-keys "^1.0.0" - sort-keys@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" @@ -20427,15 +19344,6 @@ sqlite3@^4.2.0: nan "^2.12.1" node-pre-gyp "^0.11.0" -squeak@^1.0.0: - version "1.3.0" - resolved "https://registry.npmjs.org/squeak/-/squeak-1.3.0.tgz#33045037b64388b567674b84322a6521073916c3" - integrity sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM= - dependencies: - chalk "^1.0.0" - console-stream "^0.1.1" - lpad-align "^1.0.1" - srcset@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/srcset/-/srcset-2.0.1.tgz#8f842d357487eb797f413d9c309de7a5149df5ac" @@ -20479,12 +19387,11 @@ ssri@^6.0.0, ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" -ssri@^7.0.0: - version "7.1.0" - resolved "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d" - integrity sha512-77/WrDZUWocK0mvA5NTRQyveUf+wsrIc6vyrxpS8tVvYBcX215QbafrJR3KtkpskIzoFLqqNuuYQvxaMjXJ/0g== +ssri@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808" + integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA== dependencies: - figgy-pudding "^3.5.1" minipass "^3.1.1" stable@^0.1.8: @@ -20599,10 +19506,10 @@ store2@^2.7.1: resolved "https://registry.npmjs.org/store2/-/store2-2.10.0.tgz#46b82bb91878daf1b0d56dec2f1d41e54d5103cf" integrity sha512-tWEpK0snS2RPUq1i3R6OahfJNjWCQYNxq0+by1amCSuw0mXtymJpzmZIeYpA1UAa+7B0grCpNYIbDcd7AgTbFg== -storybook-dark-mode@^0.6.1: - version "0.6.1" - resolved "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-0.6.1.tgz#0527567ac5853c49f6f7a6f68f792fe9322c5a5a" - integrity sha512-E8LIHnVfFhOsPqBc2fLshVBnspziYMXHdwQc/qAjpf4h5ewzrDzeqy4QfJioE+jDoyyZXEtIMugzb0wIaK10Uw== +storybook-dark-mode@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/storybook-dark-mode/-/storybook-dark-mode-1.0.2.tgz#963007e72b628e0efe29bdc5ee8449513bc056b8" + integrity sha512-HBeXTUzYaRgdGJ6YbmcJ3RXw47xp2b5kegZwtcqnSvRblNUZlAKSKsD6UQTWA30hPJ+u3O/5OE5bXk8+H4Zdqg== dependencies: fast-deep-equal "^3.0.0" memoizerific "^1.11.3" @@ -20686,11 +19593,6 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-template@~0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" - integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= - string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -20770,11 +19672,6 @@ string.prototype.trimright@^2.1.1: define-properties "^1.1.3" function-bind "^1.1.1" -string_decoder@0.10: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -20843,18 +19740,6 @@ strip-bom@^4.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-color@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz#106f65d3d3e6a2d9401cac0eb0ce8b8a702b4f7b" - integrity sha1-EG9l09PmotlAHKwOsM6LinArT3s= - -strip-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -20894,13 +19779,6 @@ strip-json-comments@~2.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -strip-outer@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - strong-log-transformer@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" @@ -20915,7 +19793,7 @@ style-inject@^0.3.0: resolved "https://registry.npmjs.org/style-inject/-/style-inject-0.3.0.tgz#d21c477affec91811cc82355832a700d22bf8dd3" integrity sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw== -style-loader@^1.0.0, style-loader@^1.2.1: +style-loader@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/style-loader/-/style-loader-1.2.1.tgz#c5cbbfbf1170d076cfdd86e0109c5bba114baa1a" integrity sha512-ByHSTQvHLkWE9Ir5+lGbVOXhxX10fbprhLvdg96wedFZb4NDekDPxVKv5Fwmio+QcMlkkNfuK+5W1peQ5CUhZg== @@ -21044,12 +19922,12 @@ supports-hyperlinks@^2.0.0: has-flag "^4.0.0" supports-color "^7.0.0" -svg-parser@^2.0.0, svg-parser@^2.0.2: +svg-parser@^2.0.2: version "2.0.4" resolved "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== -svgo@^1.0.0, svgo@^1.2.2, svgo@^1.3.2: +svgo@^1.0.0, svgo@^1.2.2: version "1.3.2" resolved "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== @@ -21195,7 +20073,7 @@ tar-fs@~2.0.1: pump "^3.0.0" tar-stream "^2.0.0" -tar-stream@^1.1.2, tar-stream@^1.5.2: +tar-stream@^1.1.2: version "1.6.2" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== @@ -21232,15 +20110,15 @@ tar@^4, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: safe-buffer "^5.1.2" yallist "^3.0.3" -tar@^6.0.1: - version "6.0.2" - resolved "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz#5df17813468a6264ff14f766886c622b84ae2f39" - integrity sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg== +tar@^6.0.1, tar@^6.0.2: + version "6.0.5" + resolved "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f" + integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" minipass "^3.0.0" - minizlib "^2.1.0" + minizlib "^2.1.1" mkdirp "^1.0.3" yallist "^4.0.0" @@ -21249,14 +20127,6 @@ tarn@^3.0.0: resolved "https://registry.npmjs.org/tarn/-/tarn-3.0.0.tgz#a4082405216c0cce182b8b4cb2639c52c1e870d4" integrity sha512-PKUnlDFODZueoA8owLehl8vLcgtA8u4dRuVbZc92tspDYZixjJL6TqYOmryf/PfP/EBX+2rgNcrj96NO+RPkdQ== -tcp-port-used@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/tcp-port-used/-/tcp-port-used-1.0.1.tgz#46061078e2d38c73979a2c2c12b5a674e6689d70" - integrity sha512-rwi5xJeU6utXoEIiMvVBMc9eJ2/ofzB+7nLOdnZuFTmNCLqRiQh2sMG9MqCxHU/69VC/Fwp5dV9306Qd54ll1Q== - dependencies: - debug "4.1.0" - is2 "2.0.1" - tdigest@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" @@ -21264,20 +20134,6 @@ tdigest@^0.1.1: dependencies: bintrees "1.0.1" -telejson@^3.2.0: - version "3.3.0" - resolved "https://registry.npmjs.org/telejson/-/telejson-3.3.0.tgz#6d814f3c0d254d5c4770085aad063e266b56ad03" - integrity sha512-er08AylQ+LEbDLp1GRezORZu5wKOHaBczF6oYJtgC3Idv10qZ8A3p6ffT+J5BzDKkV9MqBvu8HAKiIIOp6KJ2w== - dependencies: - "@types/is-function" "^1.0.0" - global "^4.4.0" - is-function "^1.0.1" - is-regex "^1.0.4" - is-symbol "^1.0.3" - isobject "^4.0.0" - lodash "^4.17.15" - memoizerific "^1.11.3" - telejson@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/telejson/-/telejson-5.0.2.tgz#ed1e64be250cc1c757a53c19e1740b49832b3d51" @@ -21309,14 +20165,6 @@ temp-write@^3.4.0: temp-dir "^1.0.0" uuid "^3.0.1" -tempfile@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" - integrity sha1-awRGhWqbERTRhW/8vlCczLCXcmU= - dependencies: - temp-dir "^1.0.0" - uuid "^3.0.1" - term-size@^2.1.0: version "2.2.0" resolved "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" @@ -21345,25 +20193,25 @@ terser-webpack-plugin@^1.4.3: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser-webpack-plugin@^2.1.2: - version "2.3.5" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.5.tgz#5ad971acce5c517440ba873ea4f09687de2f4a81" - integrity sha512-WlWksUoq+E4+JlJ+h+U+QUzXpcsMSSNXkDy9lBVkSqDn1w23Gg29L/ary9GeJVYCGiNJJX7LnVc4bwL1N3/g1w== +terser-webpack-plugin@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-3.1.0.tgz#91e6d39571460ed240c0cf69d295bcf30ebf98cb" + integrity sha512-cjdZte66fYkZ65rQ2oJfrdCAkkhJA7YLYk5eGOcGCSGlq0ieZupRdjedSQXYknMPo2IveQL+tPdrxUkERENCFA== dependencies: - cacache "^13.0.1" - find-cache-dir "^3.2.0" - jest-worker "^25.1.0" - p-limit "^2.2.2" - schema-utils "^2.6.4" - serialize-javascript "^2.1.2" + cacache "^15.0.5" + find-cache-dir "^3.3.1" + jest-worker "^26.2.1" + p-limit "^3.0.2" + schema-utils "^2.6.6" + serialize-javascript "^4.0.0" source-map "^0.6.1" - terser "^4.4.3" + terser "^4.8.0" webpack-sources "^1.4.3" -terser@^4.1.2, terser@^4.4.3, terser@^4.6.3: - version "4.6.7" - resolved "https://registry.npmjs.org/terser/-/terser-4.6.7.tgz#478d7f9394ec1907f0e488c5f6a6a9a2bad55e72" - integrity sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g== +terser@^4.1.2, terser@^4.6.3, terser@^4.8.0: + version "4.8.0" + resolved "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -21474,11 +20322,6 @@ timeago.js@^4.0.2: resolved "https://registry.npmjs.org/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028" integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w== -timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - timers-browserify@^2.0.4: version "2.0.11" resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" @@ -21504,33 +20347,26 @@ tiny-emitter@^2.0.0: resolved "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423" integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q== -tiny-invariant@^1.0.6: +tiny-invariant@^1.0.2, tiny-invariant@^1.0.6: version "1.1.0" resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== -tiny-lr@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" - integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== - dependencies: - body "^5.1.0" - debug "^3.1.0" - faye-websocket "~0.10.0" - livereload-js "^2.3.0" - object-assign "^4.1.0" - qs "^6.4.0" - tiny-merge-patch@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/tiny-merge-patch/-/tiny-merge-patch-0.1.2.tgz#2e8ded19c56ea15dbd3ad4ed5db1c8e5ad544c3c" integrity sha1-Lo3tGcVuoV29OtTtXbHI5a1UTDw= -tiny-warning@^1.0.2: +tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +tinycolor2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" + integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= + tmp@^0.0.33: version "0.0.33" resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -21617,11 +20453,6 @@ toidentifier@1.0.0: resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== -toml@^2.3.2: - version "2.3.6" - resolved "https://registry.npmjs.org/toml/-/toml-2.3.6.tgz#25b0866483a9722474895559088b436fd11f861b" - integrity sha512-gVweAectJU3ebq//Ferr2JUY4WKSDe5N+z0FvjDncLGyHmIDoxgY/2Ie4qfEIDm4IS7OA6Rmdm7pdEEdMcV/xQ== - toposort@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" @@ -21685,13 +20516,6 @@ tree-kill@^1.2.2: resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== -tree-node-cli@^1.2.5: - version "1.4.0" - resolved "https://registry.npmjs.org/tree-node-cli/-/tree-node-cli-1.4.0.tgz#8f4028554610d6ee1cdeb98554a60841a3cfa3ac" - integrity sha512-hBc/cp7rTSHFSFvaTzmHNYyJv87UJBsxsfCoq2DtDQuMES4vhnLuvXZit/asGtZG8edWTCydWeFWoBz9LYkJdQ== - dependencies: - commander "^5.0.0" - trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -21707,13 +20531,6 @@ trim-off-newlines@^1.0.0: resolved "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= -trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - trim-trailing-lines@^1.0.0: version "1.1.3" resolved "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" @@ -21734,20 +20551,12 @@ trough@^1.0.0: resolved "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -truncate-html@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/truncate-html/-/truncate-html-1.0.3.tgz#0166dfc7890626130c2e4174c6b73d4d63993e5f" - integrity sha512-1o1prdRv+iehXcGwn29YgXU17DotHkr+OK3ijVEG7FGMwHNG9RyobXwimw6djDvbIc24rhmz3tjNNvNESjkNkQ== - dependencies: - "@types/cheerio" "^0.22.8" - cheerio "0.22.0" - tryer@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== -ts-dedent@^1.1.0, ts-dedent@^1.1.1: +ts-dedent@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ts-dedent/-/ts-dedent-1.1.1.tgz#68fad040d7dbd53a90f545b450702340e17d18f3" integrity sha512-UGTRZu1evMw4uTPyYF66/KFd22XiU+jMaIuHrkIHQ2GivAXVlLV0v/vHrpOuTRf9BmpNHi/SO7Vd0rLu0y57jg== @@ -21757,6 +20566,11 @@ ts-easing@^0.2.0: resolved "https://registry.npmjs.org/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== +ts-essentials@^2.0.3: + version "2.0.12" + resolved "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz#c9303f3d74f75fa7528c3d49b80e089ab09d8745" + integrity sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w== + ts-interface-checker@^0.1.9: version "0.1.10" resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.10.tgz#b68a49e37e90a05797e590f08494dd528bf383cf" @@ -21807,10 +20621,10 @@ ts-node@^8.6.2: source-map-support "^0.5.17" yn "3.1.1" -ts-pnp@^1.1.2: - version "1.1.6" - resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a" - integrity sha512-CrG5GqAAzMT7144Cl+UIFP7mz/iIhiy+xQ6GGcnjTezhALT02uPMRw7tgDSESgB5MsfKt55+GPWw4ir1kVtMIQ== +ts-pnp@^1.1.6: + version "1.2.0" + resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" + integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== tsconfig-paths@^3.9.0: version "3.9.0" @@ -21973,14 +20787,6 @@ umask@^1.1.0: resolved "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= -unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - unc-path-regex@^0.1.2: version "0.1.2" resolved "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" @@ -22208,16 +21014,7 @@ urix@^0.1.0: resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-loader@^2.0.1: - version "2.3.0" - resolved "https://registry.npmjs.org/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b" - integrity sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog== - dependencies: - loader-utils "^1.2.3" - mime "^2.4.4" - schema-utils "^2.5.0" - -url-loader@^4.1.0: +url-loader@^4.0.0, url-loader@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/url-loader/-/url-loader-4.1.0.tgz#c7d6b0d6b0fccd51ab3ffc58a78d32b8d89a7be2" integrity sha512-IzgAAIC8wRrg6NYkFIJY09vtktQcsvU8V6HhtQj9PTefbYImzLB1hufqo4m+RyM5N3mLx5BqJKccgxJS+W3kqw== @@ -22226,13 +21023,6 @@ url-loader@^4.1.0: mime-types "^2.1.26" schema-utils "^2.6.5" -url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - url-parse-lax@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" @@ -22248,11 +21038,6 @@ url-parse@^1.4.3, url-parse@^1.4.7: querystringify "^2.1.1" requires-port "^1.0.0" -url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - url-value-parser@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.0.1.tgz#c8179a095ab9ec1f5aa17ca36af5af396b4e95ed" @@ -22266,24 +21051,30 @@ url@^0.11.0, url@~0.11.0: punycode "1.3.2" querystring "0.2.0" -use-callback-ref@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.1.tgz#898759ccb9e14be6c7a860abafa3ffbd826c89bb" - integrity sha512-C3nvxh0ZpaOxs9RCnWwAJ+7bJPwQI8LHF71LzbQ3BvzH5XkdtlkMadqElGevg5bYBDFip4sAnD4m06zAKebg1w== +use-composed-ref@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.0.0.tgz#bb13e8f4a0b873632cde4940abeb88b92d03023a" + integrity sha512-RVqY3NFNjZa0xrmK3bIMWNmQ01QjKPDc7DeWR3xa/N8aliVppuutOE5bZzPkQfvL+5NRWMMp0DJ99Trd974FIw== + dependencies: + ts-essentials "^2.0.3" + +use-isomorphic-layout-effect@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.0.0.tgz#f56b4ed633e1c21cd9fc76fe249002a1c28989fb" + integrity sha512-JMwJ7Vd86NwAt1jH7q+OIozZSIxA4ND0fx6AsOe2q1H8ooBUp5aN6DvVCqZiIaYU6JaMRJGyR0FO7EBCIsb/Rg== + +use-latest@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/use-latest/-/use-latest-1.1.0.tgz#7bf9684555869c3f5f37e10d0884c8accf4d3aa6" + integrity sha512-gF04d0ZMV3AMB8Q7HtfkAWe+oq1tFXP6dZKwBHQF5nVXtGsh2oAYeeqma5ZzxtlpOcW8Ro/tLcfmEodjDeqtuw== + dependencies: + use-isomorphic-layout-effect "^1.0.0" use-memo-one@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz#39e6f08fe27e422a7d7b234b5f9056af313bd22c" integrity sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ== -use-sidecar@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.2.tgz#e72f582a75842f7de4ef8becd6235a4720ad8af6" - integrity sha512-287RZny6m5KNMTb/Kq9gmjafi7lQL0YHO1lYolU6+tY1h9+Z3uCtkJJ3OSOq3INwYf2hBryCcDh4520AhJibMA== - dependencies: - detect-node "^2.0.4" - tslib "^1.9.3" - use@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -22429,6 +21220,11 @@ validate.io-number@^1.0.3: resolved "https://registry.npmjs.org/validate.io-number/-/validate.io-number-1.0.3.tgz#f63ffeda248bf28a67a8d48e0e3b461a1665baf8" integrity sha1-9j/+2iSL8opnqNSODjtGGhZluvg= +value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -22519,14 +21315,23 @@ warning@^4.0.2, warning@^4.0.3: dependencies: loose-envify "^1.0.0" -watchpack@^1.6.1: - version "1.6.1" - resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2" - integrity sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA== +watchpack-chokidar2@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0" + integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA== dependencies: chokidar "^2.1.8" + +watchpack@^1.7.4: + version "1.7.4" + resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz#6e9da53b3c80bb2d6508188f5b200410866cd30b" + integrity sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg== + dependencies: graceful-fs "^4.1.2" neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.1" + watchpack-chokidar2 "^2.0.0" wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" @@ -22629,6 +21434,16 @@ webpack-hot-middleware@^2.25.0: querystring "^0.2.0" strip-ansi "^3.0.0" +webpack-log@^1.1.2: + version "1.2.0" + resolved "https://registry.npmjs.org/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d" + integrity sha512-U9AnICnu50HXtiqiDxuli5gLB5PGBo7VvcHx36jRZHwK4vzOYLbImqT4lwWwoMHdQWwEKw736fCHEekokTEKHA== + dependencies: + chalk "^2.1.0" + log-symbols "^2.1.0" + loglevelnext "^1.0.1" + uuid "^3.1.0" + webpack-log@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" @@ -22638,9 +21453,9 @@ webpack-log@^2.0.0: uuid "^3.3.2" webpack-node-externals@^2.5.0: - version "2.5.0" - resolved "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-2.5.0.tgz#8d50f3289c71bc2b921a8da228e0b652acc503f1" - integrity sha512-g7/Z7Q/gsP8GkJkKZuJggn6RSb5PvxW1YD5vvmRZIxaSxAzkqjfL5n9CslVmNYlSqBVCyiqFgOqVS2IOObCSRg== + version "2.5.2" + resolved "https://registry.npmjs.org/webpack-node-externals/-/webpack-node-externals-2.5.2.tgz#178e017a24fec6015bc9e672c77958a6afac861d" + integrity sha512-aHdl/y2N7PW2Sx7K+r3AxpJO+aDMcYzMQd60Qxefq3+EwhewSbTBqNumOsCE1JsCUNoyfGj5465N0sSf6hc/5w== webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" @@ -22650,17 +21465,17 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack- source-list-map "^2.0.0" source-map "~0.6.1" -webpack-virtual-modules@^0.2.0: - version "0.2.1" - resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.2.1.tgz#8ab73d4df0fd37ed27bb8d823bc60ea7266c8bf7" - integrity sha512-0PWBlxyt4uGDofooIEanWhhyBOHdd+lr7QpYNDLC7/yc5lqJT8zlc04MTIBnKj+c2BlQNNuwE5er/Tg4wowHzA== +webpack-virtual-modules@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz#20863dc3cb6bb2104729fff951fbe14b18bd0299" + integrity sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA== dependencies: debug "^3.0.0" -webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.6: - version "4.43.0" - resolved "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz#c48547b11d563224c561dad1172c8aa0b8a678e6" - integrity sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g== +webpack@^4.41.6, webpack@^4.43.0: + version "4.44.1" + resolved "https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz#17e69fff9f321b8f117d1fda714edfc0b939cc21" + integrity sha512-4UOGAohv/VGUNQJstzEywwNxqX417FnjZgZJpJQegddzPmTvph37eBIRbRTfdySXzVtJXLJfbMN3mMYhM6GdmQ== dependencies: "@webassemblyjs/ast" "1.9.0" "@webassemblyjs/helper-module-context" "1.9.0" @@ -22670,7 +21485,7 @@ webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.6: ajv "^6.10.2" ajv-keywords "^3.4.1" chrome-trace-event "^1.0.2" - enhanced-resolve "^4.1.0" + enhanced-resolve "^4.3.0" eslint-scope "^4.0.3" json-parse-better-errors "^1.0.2" loader-runner "^2.4.0" @@ -22683,7 +21498,7 @@ webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.6: schema-utils "^1.0.0" tapable "^1.1.3" terser-webpack-plugin "^1.4.3" - watchpack "^1.6.1" + watchpack "^1.7.4" webpack-sources "^1.4.1" websocket-driver@0.6.5: @@ -22731,9 +21546,9 @@ whatwg-fetch@^2.0.4: integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== whatwg-fetch@^3.0.0, whatwg-fetch@^3.4.0: - version "3.4.0" - resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.0.tgz#e11de14f4878f773fbebcde8871b2c0699af8b30" - integrity sha512-rsum2ulz2iuZH08mJkT0Yi6JnKhwdw4oeyMjokgxd+mmqYSd9cPpOQf01TIWgjxG/U4+QR+AwKq6lSbXVxkyoQ== + version "3.4.1" + resolved "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" + integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: version "2.3.0" @@ -22858,11 +21673,6 @@ word-wrap@^1.2.3, word-wrap@~1.2.3: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= - wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -23033,13 +21843,6 @@ xml-encryption@^1.0.0: xmldom "~0.1.15" xpath "0.0.27" -xml-js@^1.6.11: - version "1.6.11" - resolved "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" - integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== - dependencies: - sax "^1.2.4" - "xml-name-validator@>= 2.0.1 < 3.0.0": version "2.0.1" resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" @@ -23063,11 +21866,6 @@ xmlbuilder@^11.0.0, xmlbuilder@~11.0.0: resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== -xmlbuilder@^13.0.0: - version "13.0.2" - resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7" - integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ== - xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" @@ -23123,11 +21921,6 @@ yaeti@^0.0.6: resolved "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" @@ -23148,14 +21941,6 @@ yaml@*, yaml@^1.10.0, yaml@^1.7.2, yaml@^1.9.2: resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== -yamljs@^0.2.1: - version "0.2.10" - resolved "https://registry.npmjs.org/yamljs/-/yamljs-0.2.10.tgz#481cc7c25ca73af59f591f0c96e3ce56c757a40f" - integrity sha1-SBzHwlynOvWfWR8MluPOVsdXpA8= - dependencies: - argparse "^1.0.7" - glob "^7.0.5" - yargs-parser@18.x, yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -23245,13 +22030,6 @@ yargs@^15.3.1, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^2.3.0: - version "2.3.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-2.3.0.tgz#e900c87250ec5cd080db6009fe3dd63156f1d7fb" - integrity sha1-6QDIclDsXNCA22AJ/j3WMVbx1/s= - dependencies: - wordwrap "0.0.2" - yargs@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/yargs/-/yargs-5.0.0.tgz#3355144977d05757dbb86d6e38ec056123b3a66e" @@ -23272,7 +22050,7 @@ yargs@^5.0.0: y18n "^3.2.1" yargs-parser "^3.2.0" -yauzl@^2.10.0, yauzl@^2.4.2: +yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=