From 1284771b509b27d00f601c534ed7c4aada0134a5 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Mon, 6 Sep 2021 16:45:09 +1000 Subject: [PATCH 001/135] Fix typo in Admin UI (#6474) * Fix typo in Admin UI * Changelog. Co-authored-by: Thomas Walker --- packages/keystone/CHANGELOG.md | 6 ++++++ packages/keystone/package.json | 2 +- packages/keystone/src/admin-ui/components/Navigation.tsx | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/keystone/CHANGELOG.md b/packages/keystone/CHANGELOG.md index eb764713980..851df0aef1e 100644 --- a/packages/keystone/CHANGELOG.md +++ b/packages/keystone/CHANGELOG.md @@ -1,5 +1,11 @@ # @keystone-next/keystone +## 25.0.1 + +### Patch Changes + +- [#6474](https://github.com/keystonejs/keystone/pull/6474) [`6205381b1`](https://github.com/keystonejs/keystone/commit/6205381b19041b88363a32e7ff13d606ba12a48e) Thanks [@timleslie](https://github.com/timleslie)! - Fixed typo in Admin UI. + ## 25.0.0 ### Major Changes diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 1136af97c82..dfd693dd1d6 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -1,6 +1,6 @@ { "name": "@keystone-next/keystone", - "version": "25.0.0", + "version": "25.0.1", "license": "MIT", "main": "dist/keystone.cjs.js", "module": "dist/keystone.esm.js", diff --git a/packages/keystone/src/admin-ui/components/Navigation.tsx b/packages/keystone/src/admin-ui/components/Navigation.tsx index aac48c67c08..5597b9d7010 100644 --- a/packages/keystone/src/admin-ui/components/Navigation.tsx +++ b/packages/keystone/src/admin-ui/components/Navigation.tsx @@ -79,7 +79,7 @@ const AuthenticatedItemDialog = ({ item }: { item: AuthenticatedItem | undefined Signed in as {item.label} ) : ( -
Graqhql Playground and Docs
+
GraphQL Playground and Docs
)} Date: Mon, 6 Sep 2021 16:56:26 +1000 Subject: [PATCH 002/135] Remove deprecated packages (#6468) --- packages/admin-ui-utils/CHANGELOG.md | 218 ------- packages/admin-ui-utils/package.json | 11 - packages/admin-ui-utils/src/index.ts | 5 - packages/fields/CHANGELOG.md | 841 --------------------------- packages/fields/README.md | 7 - packages/fields/package.json | 11 - packages/fields/src/index.ts | 5 - packages/testing/.npmignore | 2 - packages/testing/CHANGELOG.md | 52 -- packages/testing/README.md | 3 - packages/testing/package.json | 13 - packages/testing/src/index.ts | 5 - packages/types/CHANGELOG.md | 795 ------------------------- packages/types/README.md | 7 - packages/types/package.json | 11 - packages/types/src/index.ts | 5 - packages/utils/.npmignore | 2 - packages/utils/CHANGELOG.md | 48 -- packages/utils/README.md | 9 - packages/utils/package.json | 14 - packages/utils/src/index.ts | 5 - 21 files changed, 2069 deletions(-) delete mode 100644 packages/admin-ui-utils/CHANGELOG.md delete mode 100644 packages/admin-ui-utils/package.json delete mode 100644 packages/admin-ui-utils/src/index.ts delete mode 100644 packages/fields/CHANGELOG.md delete mode 100644 packages/fields/README.md delete mode 100644 packages/fields/package.json delete mode 100644 packages/fields/src/index.ts delete mode 100644 packages/testing/.npmignore delete mode 100644 packages/testing/CHANGELOG.md delete mode 100644 packages/testing/README.md delete mode 100644 packages/testing/package.json delete mode 100644 packages/testing/src/index.ts delete mode 100644 packages/types/CHANGELOG.md delete mode 100644 packages/types/README.md delete mode 100644 packages/types/package.json delete mode 100644 packages/types/src/index.ts delete mode 100644 packages/utils/.npmignore delete mode 100644 packages/utils/CHANGELOG.md delete mode 100644 packages/utils/README.md delete mode 100644 packages/utils/package.json delete mode 100644 packages/utils/src/index.ts diff --git a/packages/admin-ui-utils/CHANGELOG.md b/packages/admin-ui-utils/CHANGELOG.md deleted file mode 100644 index 097115e022e..00000000000 --- a/packages/admin-ui-utils/CHANGELOG.md +++ /dev/null @@ -1,218 +0,0 @@ -# @keystone-next/admin-ui-utils - -## 6.0.0 - -### Major Changes - -- [#6367](https://github.com/keystonejs/keystone/pull/6367) [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/admin-ui-utils` to `@keystone-next/keystone/admin-ui/utils` - -## 5.0.6 - -### Patch Changes - -- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: - - @keystone-next/types@24.0.0 - -## 5.0.5 - -### Patch Changes - -- Updated dependencies [[`93f1e5d30`](https://github.com/keystonejs/keystone/commit/93f1e5d302701c610b6cba74e0c5c86a3ac8aacc), [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523), [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4)]: - - @keystone-next/types@23.0.0 - -## 5.0.4 - -### Patch Changes - -- [#6087](https://github.com/keystonejs/keystone/pull/6087) [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951) Thanks [@JedWatson](https://github.com/JedWatson)! - Move source code from the `packages-next` to the `packages` directory. - -- Updated dependencies [[`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790), [`5f3d407d7`](https://github.com/keystonejs/keystone/commit/5f3d407d79171f04ae877e8eaed9a7f9d5671705), [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951)]: - - @keystone-next/types@22.0.0 - - @keystone-ui/core@3.1.1 - -## 5.0.3 - -### Patch Changes - -- Updated dependencies [[`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b)]: - - @keystone-next/types@21.0.0 - -## 5.0.2 - -### Patch Changes - -- Updated dependencies [[`7eabb4dee`](https://github.com/keystonejs/keystone/commit/7eabb4dee2552f7baf1e0024d82011b179d418d4), [`4995c682d`](https://github.com/keystonejs/keystone/commit/4995c682dbdcfac2100de9fab98ba1e0e08cbcc2), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`84a5e7f3b`](https://github.com/keystonejs/keystone/commit/84a5e7f3bc3a29ff31d642831e7aaadfc8534ba1), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`8958704ec`](https://github.com/keystonejs/keystone/commit/8958704ec9819cd27ad1cae251628ad38dad1c79), [`97fd5e05d`](https://github.com/keystonejs/keystone/commit/97fd5e05d8681bae86001e6b7e8e3f36ebd639b7)]: - - @keystone-next/types@20.0.0 - - @keystone-ui/core@3.1.0 - -## 5.0.1 - -### Patch Changes - -- Updated dependencies [[`b9c828fb0`](https://github.com/keystonejs/keystone/commit/b9c828fb0d6e587976dbd0dc4e87004bce3b2ef7), [`5cc35170f`](https://github.com/keystonejs/keystone/commit/5cc35170fd46118089a2a6f863d782aff989bbf0), [`02af04c03`](https://github.com/keystonejs/keystone/commit/02af04c03c96c26c273cd49eda5b4a132e02a26a), [`08478b8a7`](https://github.com/keystonejs/keystone/commit/08478b8a7bb9fe5932c7f74f9f6d3af75a0a5394), [`7bda87ea7`](https://github.com/keystonejs/keystone/commit/7bda87ea7f11e0faceccc6ab3f715c72b07c129b), [`4b11c5ea8`](https://github.com/keystonejs/keystone/commit/4b11c5ea87b759c24bdbff9d18443bbc972757c0), [`bb4f4ac91`](https://github.com/keystonejs/keystone/commit/bb4f4ac91c3ed70393774f744075971453a12aba)]: - - @keystone-next/types@19.0.0 - -## 5.0.0 - -### Major Changes - -- [#5746](https://github.com/keystonejs/keystone/pull/5746) [`19750d2dc`](https://github.com/keystonejs/keystone/commit/19750d2dc5801cc8d2ffae1f50d1d5ca6ab9407d) Thanks [@timleslie](https://github.com/timleslie)! - Update Node.js dependency to `^12.20 || >= 14.13`. - -### Patch Changes - -- Updated dependencies [[`19750d2dc`](https://github.com/keystonejs/keystone/commit/19750d2dc5801cc8d2ffae1f50d1d5ca6ab9407d)]: - - @keystone-ui/core@3.0.0 - - @keystone-next/types@18.0.0 - -## 4.0.0 - -### Major Changes - -- [#5397](https://github.com/keystonejs/keystone/pull/5397) [`a5627304b`](https://github.com/keystonejs/keystone/commit/a5627304b7921a0f1484d6d08330115d0edbb45b) Thanks [@bladey](https://github.com/bladey)! - Updated Node engine version to 12.x due to 10.x reaching EOL on 2021-04-30. - -### Patch Changes - -- Updated dependencies [[`9e060fe83`](https://github.com/keystonejs/keystone/commit/9e060fe83459269bc5d257f31a23c164d2283624), [`7498fcabb`](https://github.com/keystonejs/keystone/commit/7498fcabba3ef6b411dd3bf67a20821702442ebc), [`11f5bb631`](https://github.com/keystonejs/keystone/commit/11f5bb6316b90ec603aa034db1b9259c911204ed), [`a5627304b`](https://github.com/keystonejs/keystone/commit/a5627304b7921a0f1484d6d08330115d0edbb45b), [`1d85d7ff4`](https://github.com/keystonejs/keystone/commit/1d85d7ff4e8d7795d6e0f82484cf7108d11925db), [`0e74d8123`](https://github.com/keystonejs/keystone/commit/0e74d81238d5d00cc3eb968c95c02f25cb3a5a78), [`be60812f2`](https://github.com/keystonejs/keystone/commit/be60812f29d7768ce65a5f5e8c40597d4742c5d7)]: - - @keystone-next/types@17.0.0 - -## 3.0.3 - -### Patch Changes - -- Updated dependencies [[`c28e765d1`](https://github.com/keystonejs/keystone/commit/c28e765d12655f802e324b82529fcf571d88c0c6), [`b40016301`](https://github.com/keystonejs/keystone/commit/b40016301dab71630068cc86c04828c5ee1683e8), [`192393d0d`](https://github.com/keystonejs/keystone/commit/192393d0df67e123a694a42dd3f95ffa6d40042b), [`1886b4323`](https://github.com/keystonejs/keystone/commit/1886b43235e50bd2e070350d258f0a3145c19bbc), [`399e6db39`](https://github.com/keystonejs/keystone/commit/399e6db39c51cf9e8bbf3dde0887e5bf55dd1c4d)]: - - @keystone-next/types@16.0.0 - -## 3.0.2 - -### Patch Changes - -- [#5150](https://github.com/keystonejs/keystone/pull/5150) [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed) Thanks [@timleslie](https://github.com/timleslie)! - Applied eslint `import/order` rule. - -- Updated dependencies [[`8e9b04ecd`](https://github.com/keystonejs/keystone/commit/8e9b04ecd07d9c5d0e6aead4705e7a655498ae05), [`714bdadce`](https://github.com/keystonejs/keystone/commit/714bdadce8c87a15cf3a296b44a31b9b9ca95e9d), [`b84abebb6`](https://github.com/keystonejs/keystone/commit/b84abebb6c817172d04f338befa45b3573af55d6), [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed), [`56e5fe10b`](https://github.com/keystonejs/keystone/commit/56e5fe10bc89877be7d7e3013e53012b4d82b648), [`b37cbffc8`](https://github.com/keystonejs/keystone/commit/b37cbffc886a4317793a97b7a8afd95639f59ce0), [`40d4fff5d`](https://github.com/keystonejs/keystone/commit/40d4fff5d63850cbd513c80bcb5e551e5782dc4b), [`215aed387`](https://github.com/keystonejs/keystone/commit/215aed387d35e9d4c896fe76991b12b54789cc55), [`b37cbffc8`](https://github.com/keystonejs/keystone/commit/b37cbffc886a4317793a97b7a8afd95639f59ce0), [`d31acf61b`](https://github.com/keystonejs/keystone/commit/d31acf61bcca96ac059d4ba2e78955513a6a0f91)]: - - @keystone-next/types@15.0.0 - - @keystone-ui/core@2.0.2 - -## 3.0.1 - -### Patch Changes - -- [`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7) [#5018](https://github.com/keystonejs/keystone/pull/5018) Thanks [@bladey](https://github.com/bladey)! - Updated legacy packages to the @keystone-next namespace. - -- Updated dependencies [[`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7), [`687fd5ef0`](https://github.com/keystonejs/keystone/commit/687fd5ef0f798da996f970af1591411f9cfe0985), [`2655c0b1b`](https://github.com/keystonejs/keystone/commit/2655c0b1bf714d80d46e1ff4e414b4bce474c23d), [`29e787983`](https://github.com/keystonejs/keystone/commit/29e787983bdc26b147d6b5f476e70768bbc5318c), [`24e0ef5b6`](https://github.com/keystonejs/keystone/commit/24e0ef5b6bd93c105fdef2caea6b862ff1dfd6f3), [`45ea93421`](https://github.com/keystonejs/keystone/commit/45ea93421f9a6cf9b7ccbd983e0c9cbd687ff6af), [`6c949dbf2`](https://github.com/keystonejs/keystone/commit/6c949dbf262350e280072d82cd48fdd31ff5ba6d), [`3ca5038a0`](https://github.com/keystonejs/keystone/commit/3ca5038a021105a7452f4e7a4641107caa4ffe3a), [`bea9008f8`](https://github.com/keystonejs/keystone/commit/bea9008f82efea7fcf1cb547f3841915cd4689cc), [`0f86e99bb`](https://github.com/keystonejs/keystone/commit/0f86e99bb3aa15f691ab7ff79e5a9ae3d1ac464e), [`5d565ea57`](https://github.com/keystonejs/keystone/commit/5d565ea57853713458329b823bde7a38776b02bc)]: - - @keystone-ui/core@2.0.1 - - @keystone-next/types@14.0.0 - -## 3.0.0 - -### Major Changes - -- [`b97216a65`](https://github.com/keystonejs/keystone/commit/b97216a6526fffcca8232d86b115c28cb19587bf) [#4622](https://github.com/keystonejs/keystone/pull/4622) Thanks [@renovate](https://github.com/apps/renovate)! - Updated react and react-dom to v17 - -### Patch Changes - -- Updated dependencies [[`b97216a65`](https://github.com/keystonejs/keystone/commit/b97216a6526fffcca8232d86b115c28cb19587bf), [`208722a42`](https://github.com/keystonejs/keystone/commit/208722a4234434e116846756bab18f7e11674ec8), [`ad75e3d61`](https://github.com/keystonejs/keystone/commit/ad75e3d61c73ba1239fd21b58f175aac01d9f302), [`954350389`](https://github.com/keystonejs/keystone/commit/9543503894c3e78a9b69a75cbfb3ca6b85ae34e8), [`e29ae2749`](https://github.com/keystonejs/keystone/commit/e29ae2749321c103dd494eba6778ee4137bb2aa3), [`8d0be8a89`](https://github.com/keystonejs/keystone/commit/8d0be8a89e2d9b89826365f81f47b8d8863b93d0)]: - - @keystone-ui/core@2.0.0 - - @keystone-next/types@13.0.0 - -## 2.0.8 - -### Patch Changes - -- Updated dependencies [[`1744c5f05`](https://github.com/keystonejs/keystone/commit/1744c5f05c9a13e680aaa1ed151f23f1d015ed9c), [`d9675553b`](https://github.com/keystonejs/keystone/commit/d9675553b33f39e2c7ada7eb6555d16e9fccb37e), [`fd0dff3fd`](https://github.com/keystonejs/keystone/commit/fd0dff3fdfcbe20b2884357a6e1b20f1b7307652), [`5be53ddc3`](https://github.com/keystonejs/keystone/commit/5be53ddc39be1415d56e2fa5e7898ab9edf468d5), [`096927a68`](https://github.com/keystonejs/keystone/commit/096927a6813a23030988ba8b64b2e8452f571a33)]: - - @keystone-next/types@12.0.0 - -## 2.0.7 - -### Patch Changes - -- Updated dependencies [[`4768fbf83`](https://github.com/keystonejs/keystone/commit/4768fbf831ffff648e540c479a1954ae40e05aaa), [`0d9404768`](https://github.com/keystonejs/keystone/commit/0d94047686d1bb1308fd8c47b769c999390d8f6d), [`7ffd2ebb4`](https://github.com/keystonejs/keystone/commit/7ffd2ebb42dfaf12e23ba166b44ec4db60d9824b), [`6ea4ff3cf`](https://github.com/keystonejs/keystone/commit/6ea4ff3cf77d5d2278bf4f0415d11aa7399a0490)]: - - @keystone-next/types@11.0.0 - -## 2.0.6 - -### Patch Changes - -- Updated dependencies [[`24ecd72e5`](https://github.com/keystonejs/keystone/commit/24ecd72e54eee12442c7c1d0533936a9ad86620a)]: - - @keystone-next/types@10.0.0 - -## 2.0.5 - -### Patch Changes - -- Updated dependencies [[`933c78a1e`](https://github.com/keystonejs/keystone/commit/933c78a1edc070b63f7720f64c15421ba28bdde5), [`89f7d4599`](https://github.com/keystonejs/keystone/commit/89f7d459906072940da1355c38815d1b3ef49368)]: - - @keystone-next/types@9.0.0 - -## 2.0.4 - -### Patch Changes - -- Updated dependencies [[`075ef1628`](https://github.com/keystonejs/keystone/commit/075ef16281a89c8291f90275adca98f042cc54da)]: - - @keystone-next/types@8.0.0 - -## 2.0.3 - -### Patch Changes - -- Updated dependencies [[`6d09df338`](https://github.com/keystonejs/keystone/commit/6d09df3381d1682b8002d52ed1696b661fdff035), [`88b230317`](https://github.com/keystonejs/keystone/commit/88b2303177253aa5d76b50d40d19138af2bc3e41), [`39639b203`](https://github.com/keystonejs/keystone/commit/39639b2031bb749067ef537ea47e5d93a8bb89da), [`661104764`](https://github.com/keystonejs/keystone/commit/66110476491953af2134cd3cd4e3ef7c361ac5da), [`481e456ac`](https://github.com/keystonejs/keystone/commit/481e456ac4158207436ddd9be18fdca0f27b6409), [`2308e5efc`](https://github.com/keystonejs/keystone/commit/2308e5efc7c6893c87652411496b15a8124f6e05), [`f2c7675fb`](https://github.com/keystonejs/keystone/commit/f2c7675fb51ed41e6df8248c76b9322d6de5ee0d)]: - - @keystone-next/types@7.0.0 - - @keystone-ui/core@1.0.4 - -## 2.0.2 - -### Patch Changes - -- Updated dependencies [[`dc58df5c8`](https://github.com/keystonejs/keystone/commit/dc58df5c87d694ce94b7d1c2b20d4976176dbd13), [`a5d7b264a`](https://github.com/keystonejs/keystone/commit/a5d7b264ad3e5590e335758881d22f7f296203c9), [`b7a4b997b`](https://github.com/keystonejs/keystone/commit/b7a4b997bae5b2269bea0ad94ca771e63c26ab95), [`ca34424d5`](https://github.com/keystonejs/keystone/commit/ca34424d58e58cc4a657828b1362978be8ee4f62), [`57092b7c1`](https://github.com/keystonejs/keystone/commit/57092b7c13845fffd1f3767bb609d203afbc2776), [`b21b62ed5`](https://github.com/keystonejs/keystone/commit/b21b62ed59fcd83ef2fc89587544b9d64522ba27), [`2da044a0c`](https://github.com/keystonejs/keystone/commit/2da044a0cb22dc16a54b7b5555c2b2678e8d4cab), [`341ee2b4b`](https://github.com/keystonejs/keystone/commit/341ee2b4b7eab89f296146ff9e14ce53233235f6), [`4b019b8cf`](https://github.com/keystonejs/keystone/commit/4b019b8cfcb7bea6f800609da5d07e8c8abfc80a), [`68d361d25`](https://github.com/keystonejs/keystone/commit/68d361d2596e8811caf00390c60341ef0c233c7b), [`3f3c65ab2`](https://github.com/keystonejs/keystone/commit/3f3c65ab2d206ef1c72f17259e73fb24a79f0a9b), [`bf22d9f2a`](https://github.com/keystonejs/keystone/commit/bf22d9f2afe537111b95571b86d4fd2759eb6a98), [`fe52e25e0`](https://github.com/keystonejs/keystone/commit/fe52e25e04db121adbc6a0ce3bd0dbe1c7270180), [`1c12b8204`](https://github.com/keystonejs/keystone/commit/1c12b8204f8238997ddaf7337c44cf26ebea9ba4)]: - - @keystone-next/types@6.0.0 - -## 2.0.1 - -### Patch Changes - -- Updated dependencies [[`b6498d9f1`](https://github.com/keystonejs/keystone/commit/b6498d9f1341648742f2db78fec53b851b36dddd), [`d36e580cc`](https://github.com/keystonejs/keystone/commit/d36e580cc21e4b77a1bd0615c96c0793b9c5dac5), [`803626e88`](https://github.com/keystonejs/keystone/commit/803626e8854f9b7d293bd1829398d25a6692154a)]: - - @keystone-next/types@5.0.0 - -## 2.0.0 - -### Major Changes - -- [`c9159c956`](https://github.com/keystonejs/keystone/commit/c9159c9560efa7f7ae6ef802302c97b7a23f987b) [#4387](https://github.com/keystonejs/keystone/pull/4387) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed `onChange` prop on `Fields` component to accept a function that accepts the value and returns a new value rather than just accepting the value so that the fields components can be memoized. - -### Minor Changes - -- [`c9159c956`](https://github.com/keystonejs/keystone/commit/c9159c9560efa7f7ae6ef802302c97b7a23f987b) [#4387](https://github.com/keystonejs/keystone/pull/4387) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Changed `Fields` component to accept `null` for the `fieldModes` prop. - -### Patch Changes - -- Updated dependencies [[`55a04a100`](https://github.com/keystonejs/keystone/commit/55a04a1004b7f15fcd41b4935d74fd1847c9deeb), [`f4a855c71`](https://github.com/keystonejs/keystone/commit/f4a855c71e966ef3ebc894a3b0f1af51e5182394), [`6cd469e29`](https://github.com/keystonejs/keystone/commit/6cd469e29682ff41a515ed76919efc2bfe0c7567), [`eddd7e795`](https://github.com/keystonejs/keystone/commit/eddd7e79599e20f5bef61f240d874b37d0a084c4)]: - - @keystone-ui/core@1.0.3 - - @keystone-next/types@4.1.1 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies [[`11777cddb`](https://github.com/keystonejs/keystone/commit/11777cddba45b28a9e17a3149b792db121322b46), [`b2de22941`](https://github.com/keystonejs/keystone/commit/b2de229419cc93b69ee4027c387cab9c8d701488), [`cc987d078`](https://github.com/keystonejs/keystone/commit/cc987d078653fd9e686069f9f885f1269b64a882)]: - - @keystone-next/types@4.0.0 - -## 1.0.1 - -### Patch Changes - -- [`7afde2fb5`](https://github.com/keystonejs/keystone/commit/7afde2fb516e1d3824d73a96308abb4a6b022400) [#4253](https://github.com/keystonejs/keystone/pull/4253) Thanks [@jossmac](https://github.com/jossmac)! - Admin UI layout experiments and general tidy, esp. fields - -* [`0e65409c7`](https://github.com/keystonejs/keystone/commit/0e65409c7416d285fdc4f9da4a7dfb0f652c6cb2) [#4216](https://github.com/keystonejs/keystone/pull/4216) Thanks [@jossmac](https://github.com/jossmac)! - Admin UI tidy: mostly alignment and spacing consolidation. - -* Updated dependencies [[`fd4b0d04c`](https://github.com/keystonejs/keystone/commit/fd4b0d04cd9ab8ba12653f1e64fdf08d8cb0c4db), [`3d66ebc87`](https://github.com/keystonejs/keystone/commit/3d66ebc87c4dea7fa70df1209c8d85f539ceccb8), [`98e8fd4bc`](https://github.com/keystonejs/keystone/commit/98e8fd4bc586c732d629328ef643014ce42442ed), [`d02957453`](https://github.com/keystonejs/keystone/commit/d029574533c179fa53f65c0e0ba3812dab2ba4ad), [`98dd7dcff`](https://github.com/keystonejs/keystone/commit/98dd7dcffa797eb40eb1713ba1ac2697dfef95e3), [`7afde2fb5`](https://github.com/keystonejs/keystone/commit/7afde2fb516e1d3824d73a96308abb4a6b022400), [`fab97f6b4`](https://github.com/keystonejs/keystone/commit/fab97f6b416d7040cdd159be379e226142fc189c), [`8f4ebd5f7`](https://github.com/keystonejs/keystone/commit/8f4ebd5f70251ccdfb6b5ce14efb9fb59f5d2b3d), [`2a2a7c00b`](https://github.com/keystonejs/keystone/commit/2a2a7c00b74028b758006219781cbbd22909be85), [`68f1c8fdc`](https://github.com/keystonejs/keystone/commit/68f1c8fdc83f683d13de55b2f3a81eff7639ebf6), [`9928da13e`](https://github.com/keystonejs/keystone/commit/9928da13ecca03fed560a42e1071afc59c0feb3b), [`0e65409c7`](https://github.com/keystonejs/keystone/commit/0e65409c7416d285fdc4f9da4a7dfb0f652c6cb2)]: - - @keystone-ui/core@1.0.2 - - @keystone-next/types@3.0.0 - -## 1.0.0 - -### Major Changes - -- [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797) [#4132](https://github.com/keystonejs/keystone/pull/4132) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Initial release - -### Patch Changes - -- Updated dependencies [[`166acb9bf`](https://github.com/keystonejs/keystone/commit/166acb9bf211e0ee8a90d4740f6ebc54ffe72dec), [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797)]: - - @keystone-next/types@2.0.0 diff --git a/packages/admin-ui-utils/package.json b/packages/admin-ui-utils/package.json deleted file mode 100644 index 15df8dc7318..00000000000 --- a/packages/admin-ui-utils/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@keystone-next/admin-ui-utils", - "version": "6.0.0", - "main": "dist/admin-ui-utils.cjs.js", - "module": "dist/admin-ui-utils.esm.js", - "license": "MIT", - "engines": { - "node": "^12.20 || >= 14.13" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/packages/admin-ui-utils" -} diff --git a/packages/admin-ui-utils/src/index.ts b/packages/admin-ui-utils/src/index.ts deleted file mode 100644 index 316949451f5..00000000000 --- a/packages/admin-ui-utils/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -throw new Error( - '`@keystone-next/admin-ui-utils` has been moved to `@keystone-next/keystone/admin-ui/utils`, please import from there instead.' -); - -export {}; diff --git a/packages/fields/CHANGELOG.md b/packages/fields/CHANGELOG.md deleted file mode 100644 index 756a557b2e3..00000000000 --- a/packages/fields/CHANGELOG.md +++ /dev/null @@ -1,841 +0,0 @@ -# @keystone-next/fields - -## 15.0.0 - -### Major Changes - -- [#6362](https://github.com/keystonejs/keystone/pull/6362) [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/fields` to `@keystone-next/keystone/fields` - -## 14.0.0 - -### Major Changes - -- [#6280](https://github.com/keystonejs/keystone/pull/6280) [`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `gqlType` option to `autoIncrement` field type. The field type will now always be represented with an `Int` in GraphQL - -* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `_ListKeyMeta` and `_toManyRelationshipFieldMeta` fields. You should use `listKeyCount` and `toManyRelationshipFieldCount` instead - -- [#6266](https://github.com/keystonejs/keystone/pull/6266) [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Renamed `first` argument in find many queries to `take` to align with Prisma. - - ```graphql - type Query { - users( - where: UserWhereInput! = {} - orderBy: [UserOrderByInput!]! = [] - # previously was first: Int - take: Int - skip: Int! = 0 - ): [User!] - # ... - } - - type User { - # ... - posts( - where: PostWhereInput! = {} - orderBy: [PostOrderByInput!]! = [] - # previously was first: Int - take: Int - skip: Int! = 0 - ): [Post!] - # ... - } - ``` - -* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `search` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `contains` filters instead. - -- [#6095](https://github.com/keystonejs/keystone/pull/6095) [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information. - - ```graphql - query { - posts(where: { title: { contains: "Something" } }) { - title - content - } - } - ``` - -* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `sortBy` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `orderBy` instead. - -- [#6217](https://github.com/keystonejs/keystone/pull/6217) [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been renamed to `disconnect` in to-one relationship inputs and the old `disconnect` field has been removed. There are also seperate input types for create and update where the input for create doesn't have `disconnect`. It's also now required that if you provide a to-one relationship input, you must provide exactly one field to the input. - - If you have a list called `Item`, the to-one relationship inputs now look like this: - - ```graphql - input ItemRelateToOneForCreateInput { - create: ItemCreateInput - connect: ItemWhereUniqueInput - } - input ItemRelateToOneForUpdateInput { - create: ItemCreateInput - connect: ItemWhereUniqueInput - disconnect: Boolean - } - ``` - -* [#6224](https://github.com/keystonejs/keystone/pull/6224) [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been replaced by `set` in to-many relationship inputs, the equivalent to `disconnectAll: true` is now `set: []`. There are also seperate input types for create and update where the input for create doesn't have `disconnect` or `set`. The inputs in the lists in the input field are now also non-null. - - If you have a list called `Item`, the to-many relationship inputs now look like this: - - ```graphql - input ItemRelateToManyForCreateInput { - create: [ItemCreateInput!] - connect: [ItemWhereUniqueInput!] - } - input ItemRelateToManyForUpdateInput { - disconnect: [ItemWhereUniqueInput!] - set: [ItemWhereUniqueInput!] - create: [ItemCreateInput!] - connect: [ItemWhereUniqueInput!] - } - ``` - -- [#6211](https://github.com/keystonejs/keystone/pull/6211) [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. - - If you have a list called `Item`, the update mutations now look like this: - - ```graphql - type Mutation { - updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item - updateItems(data: [ItemUpdateArgs!]!): [Item] - } - - input ItemUpdateArgs { - where: ItemWhereUniqueInput! - data: ItemUpdateInput! - } - ``` - -### Patch Changes - -- [#6237](https://github.com/keystonejs/keystone/pull/6237) [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Updated timestamp field to default time to 00:00 when no time is selected. - -* [#6197](https://github.com/keystonejs/keystone/pull/6197) [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. - - If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. - - Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. - -* Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`c2bb6a9a5`](https://github.com/keystonejs/keystone/commit/c2bb6a9a596fc52a3c61ec5d91c79758e417e61d), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`6cd7ab78e`](https://github.com/keystonejs/keystone/commit/6cd7ab78e018fa0ffaddc1258426d23da19cd854), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: - - @keystone-next/keystone@24.0.0 - - @keystone-next/types@24.0.0 - - @keystone-ui/toast@4.0.2 - - @keystone-ui/segmented-control@4.0.2 - - @keystone-next/admin-ui-utils@5.0.6 - - @keystone-next/utils@1.0.4 - -## 13.0.0 - -### Major Changes - -- [#6105](https://github.com/keystonejs/keystone/pull/6105) [`e5f61ad50`](https://github.com/keystonejs/keystone/commit/e5f61ad50133a328fcb32299b838fd9eac574c3f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed unnecessary descriptions on GraphQL types. - -* [#6165](https://github.com/keystonejs/keystone/pull/6165) [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `ui.searchFields` option to lists to allow searching by multiple fields in the Admin UI (the only current usage of this is in the select used in relationship fields) and to replace the usage of the `search` GraphQL argument which will be removed soon and should be replaced by using `contains` filters directly. - -### Patch Changes - -- [#6180](https://github.com/keystonejs/keystone/pull/6180) [`a11e54d69`](https://github.com/keystonejs/keystone/commit/a11e54d692d3cec4ec2439cbf743b590688fb7d3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed issues with React hooks dependency arrays - -* [#6110](https://github.com/keystonejs/keystone/pull/6110) [`2ef6fe82c`](https://github.com/keystonejs/keystone/commit/2ef6fe82cee6df7796935d35d1c12cab29aecc75) Thanks [@ChuckJonas](https://github.com/ChuckJonas)! - Fixed virtual field rendering of false & 0 values. - -* Updated dependencies [[`3f03b8c1f`](https://github.com/keystonejs/keystone/commit/3f03b8c1fa7005b37371e1cc401c3a03334a4f7a), [`ea0712aa2`](https://github.com/keystonejs/keystone/commit/ea0712aa22487325bd898818ea4fbca543c9dcf1), [`93f1e5d30`](https://github.com/keystonejs/keystone/commit/93f1e5d302701c610b6cba74e0c5c86a3ac8aacc), [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523), [`7716315ea`](https://github.com/keystonejs/keystone/commit/7716315ea823dd91d17d54dcbb9155b5445cd956), [`a11e54d69`](https://github.com/keystonejs/keystone/commit/a11e54d692d3cec4ec2439cbf743b590688fb7d3), [`e5f61ad50`](https://github.com/keystonejs/keystone/commit/e5f61ad50133a328fcb32299b838fd9eac574c3f), [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523), [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4), [`dd7e811e7`](https://github.com/keystonejs/keystone/commit/dd7e811e7ce084c1e832acefc6ed773af371ac9e), [`587a8d0b0`](https://github.com/keystonejs/keystone/commit/587a8d0b074ccecb239d120275359f72779f306f), [`597edbdd8`](https://github.com/keystonejs/keystone/commit/597edbdd81df80982dd3df3d9d600003ef8a15e9), [`1172e1853`](https://github.com/keystonejs/keystone/commit/1172e18531064df6412c06412e74da3b85740b35), [`fbe698461`](https://github.com/keystonejs/keystone/commit/fbe6984616de7a302db7c2b0082851db89c2e314), [`32e9879db`](https://github.com/keystonejs/keystone/commit/32e9879db9cfee77f067eb8105262df65bca6c06)]: - - @keystone-next/keystone@23.0.0 - - @keystone-next/types@23.0.0 - - @keystone-ui/tooltip@4.0.1 - - @keystone-next/admin-ui-utils@5.0.5 - - @keystone-next/utils@1.0.3 - -## 12.0.0 - -### Major Changes - -- [#6027](https://github.com/keystonejs/keystone/pull/6027) [`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790) Thanks [@renovate](https://github.com/apps/renovate)! - Updated Prisma dependency to `2.26.0`. - -### Patch Changes - -- [#6087](https://github.com/keystonejs/keystone/pull/6087) [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951) Thanks [@JedWatson](https://github.com/JedWatson)! - Move source code from the `packages-next` to the `packages` directory. - -* [#6045](https://github.com/keystonejs/keystone/pull/6045) [`253df44c2`](https://github.com/keystonejs/keystone/commit/253df44c2f8d6535a6425b2593eaed5380433d57) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed confusing error when providing fields that don't exist to `ui.cardFields`, `ui.inlineCreate.fields` and `ui.inlineEdit.fields`. - -- [#6041](https://github.com/keystonejs/keystone/pull/6041) [`c536b478f`](https://github.com/keystonejs/keystone/commit/c536b478fc89f2d933cddf8533e7d88030540a63) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed `relationship` field with `displayMode: 'cards'` not using labels for related items in the cell view. - -- Updated dependencies [[`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790), [`5f3d407d7`](https://github.com/keystonejs/keystone/commit/5f3d407d79171f04ae877e8eaed9a7f9d5671705), [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951), [`279403cb0`](https://github.com/keystonejs/keystone/commit/279403cb0b4bffb946763c9a7ef71be57478eeb3), [`253df44c2`](https://github.com/keystonejs/keystone/commit/253df44c2f8d6535a6425b2593eaed5380433d57), [`f482db633`](https://github.com/keystonejs/keystone/commit/f482db6332e54a1d5cd469e2805b99b544208e83)]: - - @keystone-next/keystone@22.0.0 - - @keystone-next/types@22.0.0 - - @keystone-ui/core@3.1.1 - - @keystone-next/admin-ui-utils@5.0.4 - - @keystone-next/utils@1.0.2 - -## 11.0.3 - -### Patch Changes - -- [#6029](https://github.com/keystonejs/keystone/pull/6029) [`038cd09a2`](https://github.com/keystonejs/keystone/commit/038cd09a201081e3f56ffd75577e6b74a6eb19e5) Thanks [@bladey](https://github.com/bladey)! - Updated Keystone URL reference from next.keystonejs.com to keystonejs.com. - -* [#6031](https://github.com/keystonejs/keystone/pull/6031) [`0988f08c2`](https://github.com/keystonejs/keystone/commit/0988f08c2a88a0da6b85a385caf48ff093e1f9e5) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed `relationship` field not passing through access control, hooks, ui and graphql options to Keystone. - -* Updated dependencies [[`038cd09a2`](https://github.com/keystonejs/keystone/commit/038cd09a201081e3f56ffd75577e6b74a6eb19e5)]: - - @keystone-next/keystone@21.0.2 - - @keystone-next/types@21.0.1 - -## 11.0.2 - -### Patch Changes - -- Updated dependencies [[`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b), [`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b)]: - - @keystone-next/keystone@21.0.0 - - @keystone-next/types@21.0.0 - - @keystone-next/admin-ui-utils@5.0.3 - - @keystone-next/utils@1.0.1 - -## 11.0.1 - -### Patch Changes - -- [#5925](https://github.com/keystonejs/keystone/pull/5925) [`de0a5c19e`](https://github.com/keystonejs/keystone/commit/de0a5c19e656360ea3febc7e0240543c7817253e) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused dependencies. - -* [#5932](https://github.com/keystonejs/keystone/pull/5932) [`7a25925c3`](https://github.com/keystonejs/keystone/commit/7a25925c3dc5b2af2cf1209ee949563fb71a4a8c) Thanks [@timleslie](https://github.com/timleslie)! - Initial release of `@keystone-next/utils` package. - -- [#5992](https://github.com/keystonejs/keystone/pull/5992) [`543154bc0`](https://github.com/keystonejs/keystone/commit/543154bc081dde33ea29b8a2bff1d3033d538077) Thanks [@timleslie](https://github.com/timleslie)! - Pinned dependency `decimal.js` to `10.2.1` to be consistent with Prisma. - -* [#5987](https://github.com/keystonejs/keystone/pull/5987) [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed autoFocus always being active in the text field Filter component. - -* Updated dependencies [[`10b36551a`](https://github.com/keystonejs/keystone/commit/10b36551ac3a88da2cfeba3d065d6dd36041e769), [`8afbab763`](https://github.com/keystonejs/keystone/commit/8afbab7636b4236c6604311819160d5f1420a90e), [`7a25925c3`](https://github.com/keystonejs/keystone/commit/7a25925c3dc5b2af2cf1209ee949563fb71a4a8c), [`50ad1ce6b`](https://github.com/keystonejs/keystone/commit/50ad1ce6be90f5fb2481840dbd01328b6f629432), [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c), [`0df3734d5`](https://github.com/keystonejs/keystone/commit/0df3734d52a89df30f1d555d003002cb79ad9e9a), [`123042b04`](https://github.com/keystonejs/keystone/commit/123042b047f3242ac95d2c5280de8c07f18a86be), [`4e5634b86`](https://github.com/keystonejs/keystone/commit/4e5634b86a26819cecec5b10c18f9d231b5434e2), [`006afd108`](https://github.com/keystonejs/keystone/commit/006afd1082b474bac2499bed57bcaccf1e1d6138), [`40a44d20d`](https://github.com/keystonejs/keystone/commit/40a44d20d2eda2bcfb311fc3ce05936623230205), [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c), [`543154bc0`](https://github.com/keystonejs/keystone/commit/543154bc081dde33ea29b8a2bff1d3033d538077), [`3be09ea54`](https://github.com/keystonejs/keystone/commit/3be09ea548861b490dad8b50e58980580d366434), [`eab130f30`](https://github.com/keystonejs/keystone/commit/eab130f30d79b82c18b3cce0bc054abe2c1b58fd)]: - - @keystone-next/keystone@20.0.1 - - @keystone-next/utils@1.0.0 - - @keystone-next/types@20.0.1 - - @keystone-ui/fields@4.1.2 - - @keystone-ui/toast@4.0.1 - - @keystone-ui/pill@5.0.0 - -## 11.0.0 - -### Major Changes - -- [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The relationship field now returns a `[Item!]` instead of a `[Item!]!`, this is so that if an error occurs when resolving the related items, only the relationship field will be returned as null rather than the whole item being returned as null. - -* [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The API to configure `virtual` fields has changed to accept a `field` using the `schema` API exported from `@keystone-next/types` rather than GraphQL SDL. - -- [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The core of Keystone has been re-implemented to make implementing fields and new features in Keystone easier. While the observable changes for most users should be minimal, there could be breakage. If you implemented a custom field type, you will need to change it to the new API, see fields in the `@keystone-next/fields` package for inspiration on how to do this. - -* [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The `password` field type now adds a GraphQL type `PasswordState` to the GraphQL output type instead of adding `${fieldKey}_is_set`. - - ```graphql - type User { - password: PasswordState - } - - type PasswordState { - isSet: Boolean! - } - ``` - -- [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The way that the implementations of `generateHash` and `compare` are passed from the password field to auth has changed to be in the extensions object of the GraphQL output field. Unless you've written your own password field implementation or you're using mismatching versions of @keystone-next/auth and @keystone-next/fields, this won't affect you. - -* [#5891](https://github.com/keystonejs/keystone/pull/5891) [`97fd5e05d`](https://github.com/keystonejs/keystone/commit/97fd5e05d8681bae86001e6b7e8e3f36ebd639b7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added support for filtering uniquely by `text` and `integer` fields that have `isUnique: true` like this: - - ```graphql - query { - Post(where: { slug: "something-something-something" }) { - id - title - content - } - } - ``` - -### Minor Changes - -- [#5854](https://github.com/keystonejs/keystone/pull/5854) [`7eabb4dee`](https://github.com/keystonejs/keystone/commit/7eabb4dee2552f7baf1e0024d82011b179d418d4) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Replaced the types `FileMode` and `ImageMode` with `AssetMode`. - - Added internal experimental Keystone Cloud integration capabilities for images. - -* [#5868](https://github.com/keystonejs/keystone/pull/5868) [`84a5e7f3b`](https://github.com/keystonejs/keystone/commit/84a5e7f3bc3a29ff31d642831e7aaadfc8534ba1) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Added experimental support for the integration with keystone cloud files - -### Patch Changes - -- [#5855](https://github.com/keystonejs/keystone/pull/5855) [`e4c19f808`](https://github.com/keystonejs/keystone/commit/e4c19f8086cc14f7f4a8ef390f1f4e1263004d40) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Added assorted accessibility and layout fixes to the relationship field. - -* [#5857](https://github.com/keystonejs/keystone/pull/5857) [`881c9ffb7`](https://github.com/keystonejs/keystone/commit/881c9ffb7c5941e9fb214ed955148d8ea567e65f) Thanks [@bladey](https://github.com/bladey)! - Fixed image not displaying when rendered in card format. - -- [#5852](https://github.com/keystonejs/keystone/pull/5852) [`ef14e77ce`](https://github.com/keystonejs/keystone/commit/ef14e77cebc9420db8c7d29dfe61f02140f4a705) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed labels in `image` and `file` fields to be more screen reader friendly. - -* [#5893](https://github.com/keystonejs/keystone/pull/5893) [`df7d7b6f6`](https://github.com/keystonejs/keystone/commit/df7d7b6f6f2830573393560f4a1ec35234889947) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed labels in timestamp field for better screen reader experience. - -* Updated dependencies [[`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`7eabb4dee`](https://github.com/keystonejs/keystone/commit/7eabb4dee2552f7baf1e0024d82011b179d418d4), [`df7d7b6f6`](https://github.com/keystonejs/keystone/commit/df7d7b6f6f2830573393560f4a1ec35234889947), [`5227234a0`](https://github.com/keystonejs/keystone/commit/5227234a08edd99cd2795c8d888fbb3022810f54), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`98482efa4`](https://github.com/keystonejs/keystone/commit/98482efa4f629fe513fddd6871be1ef5bdd8d2bd), [`4995c682d`](https://github.com/keystonejs/keystone/commit/4995c682dbdcfac2100de9fab98ba1e0e08cbcc2), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`4c90c0d3c`](https://github.com/keystonejs/keystone/commit/4c90c0d3c8e75c6a58910c4bd563b3b80e61e801), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`84a5e7f3b`](https://github.com/keystonejs/keystone/commit/84a5e7f3bc3a29ff31d642831e7aaadfc8534ba1), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`8958704ec`](https://github.com/keystonejs/keystone/commit/8958704ec9819cd27ad1cae251628ad38dad1c79), [`97fd5e05d`](https://github.com/keystonejs/keystone/commit/97fd5e05d8681bae86001e6b7e8e3f36ebd639b7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7)]: - - @keystone-next/keystone@20.0.0 - - @keystone-next/types@20.0.0 - - @keystone-next/utils-legacy@12.0.0 - - @keystone-ui/fields@4.1.1 - - @keystone-ui/segmented-control@4.0.1 - - @keystone-ui/core@3.1.0 - - @keystone-next/admin-ui-utils@5.0.2 - -## 10.0.0 - -### Major Changes - -- [#5797](https://github.com/keystonejs/keystone/pull/5797) [`a6a444acd`](https://github.com/keystonejs/keystone/commit/a6a444acd23f2590d9812872441cafb5d088c48e) Thanks [@timleslie](https://github.com/timleslie)! - The GraphQL field `_allMeta { count }` generated for `many` relationships has been deprecated in favour of a new field `Count`, which directly returns the count. - - A `posts` relationship field would have the following field added to the API: - - ```graphql - postsCount(where: PostWhereInput! = {}): Int - ``` - -### Minor Changes - -- [#5779](https://github.com/keystonejs/keystone/pull/5779) [`59421c039`](https://github.com/keystonejs/keystone/commit/59421c0399368e56e46537c1c687daa27f5912d0) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Added `json` field. - -### Patch Changes - -- [#5815](https://github.com/keystonejs/keystone/pull/5815) [`b9c828fb0`](https://github.com/keystonejs/keystone/commit/b9c828fb0d6e587976dbd0dc4e87004bce3b2ef7) Thanks [@timleslie](https://github.com/timleslie)! - Fixed the type of `originalInput` in the argument to `defaultValue`. - -* [#5799](https://github.com/keystonejs/keystone/pull/5799) [`0617c81ea`](https://github.com/keystonejs/keystone/commit/0617c81eacc88e40bdd21bacab285d674b171a4a) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed field label element, so that it actually refers to the text input. - -- [#5800](https://github.com/keystonejs/keystone/pull/5800) [`590bb1fe9`](https://github.com/keystonejs/keystone/commit/590bb1fe9254c2f8feff7e3a0e2e964610116f95) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Fixed text, decimal, float and integer field labels. Labels are now associated with inputs via the field.path attribute. - -* [#5764](https://github.com/keystonejs/keystone/pull/5764) [`19a756496`](https://github.com/keystonejs/keystone/commit/19a7564964d9dcdc94ecdda9c0a0e92c539eb309) Thanks [@bladey](https://github.com/bladey)! - Adjusted fields GqlAuxQueries function to return any type to prevent build errors. - -* Updated dependencies [[`0eadba2ba`](https://github.com/keystonejs/keystone/commit/0eadba2badb13fc6a17f7e525d429494ca953481), [`f52079f0b`](https://github.com/keystonejs/keystone/commit/f52079f0bffc4cf2ab5e26e4c3654127b59d6078), [`b9c828fb0`](https://github.com/keystonejs/keystone/commit/b9c828fb0d6e587976dbd0dc4e87004bce3b2ef7), [`74bc77854`](https://github.com/keystonejs/keystone/commit/74bc778547623fe4ed3db97ed09384d9dc076372), [`29075e580`](https://github.com/keystonejs/keystone/commit/29075e58074672d90cfca84aba8dcedeecf243ca), [`5cc35170f`](https://github.com/keystonejs/keystone/commit/5cc35170fd46118089a2a6f863d782aff989bbf0), [`319c19bd5`](https://github.com/keystonejs/keystone/commit/319c19bd5f8e8c261a1aefb1997d66b2a136ae28), [`c6cd0a6bd`](https://github.com/keystonejs/keystone/commit/c6cd0a6bdc7ccb000c39fba0da31819e33d9e056), [`195d4fb12`](https://github.com/keystonejs/keystone/commit/195d4fb1218517d7b9a40d3bba1a087d40e6d1d6), [`1fe4753f3`](https://github.com/keystonejs/keystone/commit/1fe4753f3af28aa851e1f90d55937c940be5af1a), [`5b02e8625`](https://github.com/keystonejs/keystone/commit/5b02e8625e18c8e79547d5caf8cacb5014ffee9d), [`76cdb791b`](https://github.com/keystonejs/keystone/commit/76cdb791b1ab36d015e43b87deff52be2ea6b629), [`762f17823`](https://github.com/keystonejs/keystone/commit/762f1782334c9b7174c320182c753c215834ff7f), [`02af04c03`](https://github.com/keystonejs/keystone/commit/02af04c03c96c26c273cd49eda5b4a132e02a26a), [`107eeb037`](https://github.com/keystonejs/keystone/commit/107eeb0374e214b69be3727ca955a9f76e1468bb), [`3a7acc2c5`](https://github.com/keystonejs/keystone/commit/3a7acc2c5114fbcbde994d1f4c6cc0b21c572ec0), [`9de71a9fb`](https://github.com/keystonejs/keystone/commit/9de71a9fb0d3b7f5f05c0d908bebdb818723fd4b), [`08478b8a7`](https://github.com/keystonejs/keystone/commit/08478b8a7bb9fe5932c7f74f9f6d3af75a0a5394), [`7bda87ea7`](https://github.com/keystonejs/keystone/commit/7bda87ea7f11e0faceccc6ab3f715c72b07c129b), [`4b11c5ea8`](https://github.com/keystonejs/keystone/commit/4b11c5ea87b759c24bdbff9d18443bbc972757c0), [`38a177d61`](https://github.com/keystonejs/keystone/commit/38a177d6140874b29d3c09b5852dbfd787d5c429), [`bb4f4ac91`](https://github.com/keystonejs/keystone/commit/bb4f4ac91c3ed70393774f744075971453a12aba)]: - - @keystone-next/keystone@19.0.0 - - @keystone-next/types@19.0.0 - - @keystone-next/adapter-prisma-legacy@8.0.0 - - @keystone-ui/fields@4.1.0 - - @keystone-next/admin-ui-utils@5.0.1 - - @keystone-next/utils-legacy@11.0.1 - -## 9.0.0 - -### Major Changes - -- [#5746](https://github.com/keystonejs/keystone/pull/5746) [`19750d2dc`](https://github.com/keystonejs/keystone/commit/19750d2dc5801cc8d2ffae1f50d1d5ca6ab9407d) Thanks [@timleslie](https://github.com/timleslie)! - Update Node.js dependency to `^12.20 || >= 14.13`. - -* [#5677](https://github.com/keystonejs/keystone/pull/5677) [`e2232a553`](https://github.com/keystonejs/keystone/commit/e2232a5537620bd82983ba3f5cff124cec8facab) Thanks [@timleslie](https://github.com/timleslie)! - Consolidated the `@keystone-next/admin-ui` package into `@keystone-next/keystone`. - - If you were directly importing from `@keystone-next/admin-ui` you can now import the same items from `@keystone-next/keystone/admin-ui`. - If you have `@keystone-next/admin-ui` in your `package.json` you should remove it. - -### Patch Changes - -- Updated dependencies [[`d40c2a590`](https://github.com/keystonejs/keystone/commit/d40c2a5903f07e5a1e80d116ec4cea00289bbf6a), [`19750d2dc`](https://github.com/keystonejs/keystone/commit/19750d2dc5801cc8d2ffae1f50d1d5ca6ab9407d), [`016ccad82`](https://github.com/keystonejs/keystone/commit/016ccad82ed73898a64310506117c1cbae60a512), [`8da79e71a`](https://github.com/keystonejs/keystone/commit/8da79e71abb005eb755620fb3c8f82a3a2952152), [`e2232a553`](https://github.com/keystonejs/keystone/commit/e2232a5537620bd82983ba3f5cff124cec8facab)]: - - @keystone-next/adapter-prisma-legacy@7.0.0 - - @keystone-ui/button@5.0.0 - - @keystone-ui/core@3.0.0 - - @keystone-ui/fields@4.0.0 - - @keystone-ui/icons@4.0.0 - - @keystone-ui/loading@4.0.0 - - @keystone-ui/modals@4.0.0 - - @keystone-ui/pill@4.0.0 - - @keystone-ui/segmented-control@4.0.0 - - @keystone-ui/toast@4.0.0 - - @keystone-ui/tooltip@4.0.0 - - @keystone-next/admin-ui-utils@5.0.0 - - @keystone-next/keystone@18.0.0 - - @keystone-next/types@18.0.0 - - @keystone-next/access-control-legacy@11.0.0 - - @keystone-next/utils-legacy@11.0.0 - -## 8.2.0 - -### Minor Changes - -- [#5630](https://github.com/keystonejs/keystone/pull/5630) [`79a0844b9`](https://github.com/keystonejs/keystone/commit/79a0844b9d5125891e3eaad4dc3999b232cefaa2) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `ui.displayMode: 'count'` to `many` relationship fields - -### Patch Changes - -- [#5629](https://github.com/keystonejs/keystone/pull/5629) [`11814ce98`](https://github.com/keystonejs/keystone/commit/11814ce9865bc14ffdf5ca2a09b7221001539857) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Updated docs link to next.keystonejs.com. - -* [#5639](https://github.com/keystonejs/keystone/pull/5639) [`400d88257`](https://github.com/keystonejs/keystone/commit/400d88257a3383595cf76c9399848b356dd51a11) Thanks [@timleslie](https://github.com/timleslie)! - Fixed Admin UI issues when using `select` fields with `dataType: 'integer'`. - -- [#5622](https://github.com/keystonejs/keystone/pull/5622) [`bb8920843`](https://github.com/keystonejs/keystone/commit/bb8920843a1e0d803b8238bd17e9d65802698685) Thanks [@timleslie](https://github.com/timleslie)! - Disabled sorting for relationship fields. - -- Updated dependencies [[`3aea3b12f`](https://github.com/keystonejs/keystone/commit/3aea3b12fd0047e54671ead796fca15b625ade66), [`11814ce98`](https://github.com/keystonejs/keystone/commit/11814ce9865bc14ffdf5ca2a09b7221001539857), [`b0a72a112`](https://github.com/keystonejs/keystone/commit/b0a72a112dae7857defc8b745e674d55a29be766), [`2b3efc8a8`](https://github.com/keystonejs/keystone/commit/2b3efc8a883e1e5832ed5111a6e0e4d3ee59f162), [`fc9c3d55d`](https://github.com/keystonejs/keystone/commit/fc9c3d55d5a2e6a87bcb9e9ed50a19a503290457), [`dbe831976`](https://github.com/keystonejs/keystone/commit/dbe831976eeee876f3722d4b96e1b752b67cb945), [`53225b0ef`](https://github.com/keystonejs/keystone/commit/53225b0efcf33810c1c91a0a4ec3e2369733ab0a), [`79d092afc`](https://github.com/keystonejs/keystone/commit/79d092afca565abe780e84d917299ecb749752f1)]: - - @keystone-next/admin-ui@14.1.2 - - @keystone-ui/core@2.0.3 - -## 8.1.0 - -### Minor Changes - -- [#5616](https://github.com/keystonejs/keystone/pull/5616) [`3d3894679`](https://github.com/keystonejs/keystone/commit/3d38946798650d117c39ce522987b169e616b2b9) Thanks [@timleslie](https://github.com/timleslie)! - Added an `isIndexed` config option to the `text`, `integer`, `float`, `select`, and `timestamp` field types. - -### Patch Changes - -- Updated dependencies [[`3d3894679`](https://github.com/keystonejs/keystone/commit/3d38946798650d117c39ce522987b169e616b2b9), [`8b77b6971`](https://github.com/keystonejs/keystone/commit/8b77b697187f8d5eb73e862b2c07b8bfbb769e0b)]: - - @keystone-next/adapter-prisma-legacy@6.1.0 - - @keystone-next/admin-ui@14.1.1 - -## 8.0.0 - -### Major Changes - -- [#5578](https://github.com/keystonejs/keystone/pull/5578) [`f7d4c9b9f`](https://github.com/keystonejs/keystone/commit/f7d4c9b9f06cc3090b59d4b29e0907e9f3d1faee) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replaced `mode` field on `ImageFieldOutput` GraphQL type with making `ImageFieldOutput` an interface and having a `LocalImageFieldOutput` type that implements `ImageFieldOutput`. - -* [#5582](https://github.com/keystonejs/keystone/pull/5582) [`49dd46843`](https://github.com/keystonejs/keystone/commit/49dd468435a96c537f5649aa2fd9e21103da40e1) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Changed image ref to now be `${mode}:image:${id}`. - -### Minor Changes - -- [#5529](https://github.com/keystonejs/keystone/pull/5529) [`b7aeb232d`](https://github.com/keystonejs/keystone/commit/b7aeb232db43b32cae0bca3fcb74479d6834c587) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Added file field type. - -### Patch Changes - -- [#5514](https://github.com/keystonejs/keystone/pull/5514) [`8577eb3ba`](https://github.com/keystonejs/keystone/commit/8577eb3baafe9cd61c48d89aca9eff252765e5a6) Thanks [@timleslie](https://github.com/timleslie)! - The field hooks API has deprecated the `addFieldValidationError` argument. It has been replaced with the argument `addValidationError`, and will be removed in a future release. - -* [#5587](https://github.com/keystonejs/keystone/pull/5587) [`3e33cd3ff`](https://github.com/keystonejs/keystone/commit/3e33cd3ff46f824ec3516e5810a7e5027b332a5a) Thanks [@timleslie](https://github.com/timleslie)! - Simplified image input resolver. - -* Updated dependencies [[`b7aeb232d`](https://github.com/keystonejs/keystone/commit/b7aeb232db43b32cae0bca3fcb74479d6834c587), [`7e81b52b0`](https://github.com/keystonejs/keystone/commit/7e81b52b0f2240f0c590eb8f6733360cab9fe93a), [`fddeacf79`](https://github.com/keystonejs/keystone/commit/fddeacf79d25fea15be57d1a4ec16815bcdc4ab5), [`fdebf79cc`](https://github.com/keystonejs/keystone/commit/fdebf79cc3520ffb65979ddac7d61791f4f37324), [`dbc62ff7c`](https://github.com/keystonejs/keystone/commit/dbc62ff7c71ca4d4db1fab76f3e0ab729af5b80c), [`05d4883ee`](https://github.com/keystonejs/keystone/commit/05d4883ee19bcfdfcbff7f80693a3fa85cf81aaa), [`a0c5aa307`](https://github.com/keystonejs/keystone/commit/a0c5aa30771d187253d0cfe24b4b686e136136cc), [`9fd7cc62a`](https://github.com/keystonejs/keystone/commit/9fd7cc62a889f8a0f8933040bb16fcc36af7795e), [`b7aeb232d`](https://github.com/keystonejs/keystone/commit/b7aeb232db43b32cae0bca3fcb74479d6834c587), [`49dd46843`](https://github.com/keystonejs/keystone/commit/49dd468435a96c537f5649aa2fd9e21103da40e1), [`74fed41e2`](https://github.com/keystonejs/keystone/commit/74fed41e23c3d5c6c073574c54ca339df2235351)]: - - @keystone-next/admin-ui@14.1.0 - - @keystone-next/types@17.0.1 - - @keystone-next/adapter-prisma-legacy@6.0.1 - - @keystone-next/utils-legacy@10.0.0 - - @keystone-next/access-control-legacy@10.0.1 - -## 7.0.0 - -### Major Changes - -- [#5478](https://github.com/keystonejs/keystone/pull/5478) [`11f5bb631`](https://github.com/keystonejs/keystone/commit/11f5bb6316b90ec603aa034db1b9259c911204ed) Thanks [@timleslie](https://github.com/timleslie)! - Improved types for `BaseKeystoneList`. - -* [#5397](https://github.com/keystonejs/keystone/pull/5397) [`a5627304b`](https://github.com/keystonejs/keystone/commit/a5627304b7921a0f1484d6d08330115d0edbb45b) Thanks [@bladey](https://github.com/bladey)! - Updated Node engine version to 12.x due to 10.x reaching EOL on 2021-04-30. - -- [#5420](https://github.com/keystonejs/keystone/pull/5420) [`ecf07393a`](https://github.com/keystonejs/keystone/commit/ecf07393a19714f1686772bd082de7d229065aa2) Thanks [@timleslie](https://github.com/timleslie)! - Updated core fields implementation to expect an internal option `type.adapter` rather than `type.adapters.prisma`. - -### Minor Changes - -- [#5415](https://github.com/keystonejs/keystone/pull/5415) [`fe55e9289`](https://github.com/keystonejs/keystone/commit/fe55e9289b898bdcb937eb5e981dba2bb58a672f) Thanks [@timleslie](https://github.com/timleslie)! - Exported the types `FieldConfigArgs` and `FieldExtraArgs`. - -* [#5396](https://github.com/keystonejs/keystone/pull/5396) [`be60812f2`](https://github.com/keystonejs/keystone/commit/be60812f29d7768ce65a5f5e8c40597d4742c5d7) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Added new image field type. - -- [#5400](https://github.com/keystonejs/keystone/pull/5400) [`d7e8cad4f`](https://github.com/keystonejs/keystone/commit/d7e8cad4fca5d8ffefa235c2ff30ec8e2e0d6276) Thanks [@timleslie](https://github.com/timleslie)! - Moved the `Implementation` base class from the `fields-legacy` package into the `fields` package. - -### Patch Changes - -- [#5406](https://github.com/keystonejs/keystone/pull/5406) [`637ae05d3`](https://github.com/keystonejs/keystone/commit/637ae05d3f8a138902c2d03c5b342cb93c440767) Thanks [@timleslie](https://github.com/timleslie)! - Fixed a bug which added unsupported string filter options to the GraphQL API for the SQLite provider. - Added a `.containsInputFields()` method to include string filters just for the `contains` and `not_contains` options. - -* [#5403](https://github.com/keystonejs/keystone/pull/5403) [`d0adec53f`](https://github.com/keystonejs/keystone/commit/d0adec53ff20c2246dfe955b449b7c6e1afe96fb) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Replaced inflection.humanize usage with custom fn to account for edge cases. - -- [#5452](https://github.com/keystonejs/keystone/pull/5452) [`c7aecec3c`](https://github.com/keystonejs/keystone/commit/c7aecec3c768eec742e0ce9c5506331e902e5124) Thanks [@timleslie](https://github.com/timleslie)! - Removed the legacy `defaultAccess` argument from the `Keystone` constructor. - -* [#5392](https://github.com/keystonejs/keystone/pull/5392) [`f059f6349`](https://github.com/keystonejs/keystone/commit/f059f6349bee3dce8bbf4a0584b235e97872851c) Thanks [@timleslie](https://github.com/timleslie)! - Removed the dependency on the legacy `AutoIncrement` field implementation. - -- [#5442](https://github.com/keystonejs/keystone/pull/5442) [`1d85d7ff4`](https://github.com/keystonejs/keystone/commit/1d85d7ff4e8d7795d6e0f82484cf7108d11925db) Thanks [@timleslie](https://github.com/timleslie)! - Updated type definitions to be more consistent and correct. - -* [#5466](https://github.com/keystonejs/keystone/pull/5466) [`0e74d8123`](https://github.com/keystonejs/keystone/commit/0e74d81238d5d00cc3eb968c95c02f25cb3a5a78) Thanks [@timleslie](https://github.com/timleslie)! - Improved the `BaseKeystone` type to be more correct. - -- [#5374](https://github.com/keystonejs/keystone/pull/5374) [`89b869e8d`](https://github.com/keystonejs/keystone/commit/89b869e8d492151449f2146108767a7e5e5ecdfa) Thanks [@timleslie](https://github.com/timleslie)! - Removed an outdated reference to `mongoId`. - -* [#5408](https://github.com/keystonejs/keystone/pull/5408) [`58a793988`](https://github.com/keystonejs/keystone/commit/58a7939888ec84d0f089d77ca1ce9d94ef0d9a85) Thanks [@timleslie](https://github.com/timleslie)! - Fixed an issue where `virtual` fields could have `create` and `update` access control set to something other than `false`. - -* Updated dependencies [[`9e060fe83`](https://github.com/keystonejs/keystone/commit/9e060fe83459269bc5d257f31a23c164d2283624), [`637ae05d3`](https://github.com/keystonejs/keystone/commit/637ae05d3f8a138902c2d03c5b342cb93c440767), [`b0db0a7a8`](https://github.com/keystonejs/keystone/commit/b0db0a7a8d3aa46a8034022c456ea5100b129dc0), [`7498fcabb`](https://github.com/keystonejs/keystone/commit/7498fcabba3ef6b411dd3bf67a20821702442ebc), [`11f5bb631`](https://github.com/keystonejs/keystone/commit/11f5bb6316b90ec603aa034db1b9259c911204ed), [`8ab2c9bb6`](https://github.com/keystonejs/keystone/commit/8ab2c9bb6633c2f85844e658f534582c30a39a57), [`637ae05d3`](https://github.com/keystonejs/keystone/commit/637ae05d3f8a138902c2d03c5b342cb93c440767), [`d0adec53f`](https://github.com/keystonejs/keystone/commit/d0adec53ff20c2246dfe955b449b7c6e1afe96fb), [`5f2673704`](https://github.com/keystonejs/keystone/commit/5f2673704e997710a088c45e9d95d22e1195b2da), [`a5627304b`](https://github.com/keystonejs/keystone/commit/a5627304b7921a0f1484d6d08330115d0edbb45b), [`ea708559f`](https://github.com/keystonejs/keystone/commit/ea708559fbd19914fe7eb52f519937e5fe50a143), [`1d85d7ff4`](https://github.com/keystonejs/keystone/commit/1d85d7ff4e8d7795d6e0f82484cf7108d11925db), [`2bef01aaa`](https://github.com/keystonejs/keystone/commit/2bef01aaacd32eb746353bde11dd5e37c67fb43e), [`be60812f2`](https://github.com/keystonejs/keystone/commit/be60812f29d7768ce65a5f5e8c40597d4742c5d7), [`0e74d8123`](https://github.com/keystonejs/keystone/commit/0e74d81238d5d00cc3eb968c95c02f25cb3a5a78), [`be60812f2`](https://github.com/keystonejs/keystone/commit/be60812f29d7768ce65a5f5e8c40597d4742c5d7), [`115b06130`](https://github.com/keystonejs/keystone/commit/115b06130d801e00dec88935a5d400e71f089853)]: - - @keystone-next/admin-ui@14.0.0 - - @keystone-next/types@17.0.0 - - @keystone-next/adapter-prisma-legacy@6.0.0 - - @keystone-next/utils-legacy@9.0.0 - - @keystone-ui/button@4.0.0 - - @keystone-ui/fields@3.0.0 - - @keystone-ui/icons@3.0.0 - - @keystone-ui/loading@3.0.0 - - @keystone-ui/modals@3.0.0 - - @keystone-ui/pill@3.0.0 - - @keystone-ui/segmented-control@3.0.0 - - @keystone-ui/toast@3.0.0 - - @keystone-ui/tooltip@3.0.0 - - @keystone-next/admin-ui-utils@4.0.0 - - @keystone-next/access-control-legacy@10.0.0 - -## 6.0.0 - -### Major Changes - -- [#5256](https://github.com/keystonejs/keystone/pull/5256) [`399e6db39`](https://github.com/keystonejs/keystone/commit/399e6db39c51cf9e8bbf3dde0887e5bf55dd1c4d) Thanks [@timleslie](https://github.com/timleslie)! - Removed support for the `mongoId` field type. - -* [#5275](https://github.com/keystonejs/keystone/pull/5275) [`8665cfe66`](https://github.com/keystonejs/keystone/commit/8665cfe66016e0356681413e31f80a6d5586d364) Thanks [@timleslie](https://github.com/timleslie)! - Removed the `mongoId` field type. - -- [#5256](https://github.com/keystonejs/keystone/pull/5256) [`399e6db39`](https://github.com/keystonejs/keystone/commit/399e6db39c51cf9e8bbf3dde0887e5bf55dd1c4d) Thanks [@timleslie](https://github.com/timleslie)! - Removed support for the `knex` and `mongoose` database adapters. We now only support `prisma_postgresql` and `prisma_sqlite`. - -### Patch Changes - -- [#5280](https://github.com/keystonejs/keystone/pull/5280) [`9e450d6b3`](https://github.com/keystonejs/keystone/commit/9e450d6b326e2ba5f46e49ecf53b6bd7a627e9ca) Thanks [@timleslie](https://github.com/timleslie)! - Removed the `adapters-mongoose-legacy` packages dependency. - -- Updated dependencies [[`e702fea44`](https://github.com/keystonejs/keystone/commit/e702fea44c3116db158d97b5ffd24440f09c9d49), [`c28e765d1`](https://github.com/keystonejs/keystone/commit/c28e765d12655f802e324b82529fcf571d88c0c6), [`b40016301`](https://github.com/keystonejs/keystone/commit/b40016301dab71630068cc86c04828c5ee1683e8), [`192393d0d`](https://github.com/keystonejs/keystone/commit/192393d0df67e123a694a42dd3f95ffa6d40042b), [`c28e765d1`](https://github.com/keystonejs/keystone/commit/c28e765d12655f802e324b82529fcf571d88c0c6), [`1886b4323`](https://github.com/keystonejs/keystone/commit/1886b43235e50bd2e070350d258f0a3145c19bbc), [`8665cfe66`](https://github.com/keystonejs/keystone/commit/8665cfe66016e0356681413e31f80a6d5586d364), [`fda82869c`](https://github.com/keystonejs/keystone/commit/fda82869c376d05fd007bec22d7bde2604db445b), [`4fa66ac1f`](https://github.com/keystonejs/keystone/commit/4fa66ac1fc6fd0a43da17dd90797733e8c958785), [`399e6db39`](https://github.com/keystonejs/keystone/commit/399e6db39c51cf9e8bbf3dde0887e5bf55dd1c4d), [`d93bab17b`](https://github.com/keystonejs/keystone/commit/d93bab17b69c76e57580dc00e41314215da6d49b), [`9e450d6b3`](https://github.com/keystonejs/keystone/commit/9e450d6b326e2ba5f46e49ecf53b6bd7a627e9ca), [`bc21855a7`](https://github.com/keystonejs/keystone/commit/bc21855a7ff6dd4dbc278b3e15c9157de765e6ba), [`d93bab17b`](https://github.com/keystonejs/keystone/commit/d93bab17b69c76e57580dc00e41314215da6d49b)]: - - @keystone-next/fields-legacy@25.0.0 - - @keystone-next/types@16.0.0 - - @keystone-next/admin-ui@13.0.0 - - @keystone-next/fields-auto-increment-legacy@10.0.0 - - @keystone-ui/fields@2.1.0 - - @keystone-next/admin-ui-utils@3.0.3 - -## 5.4.0 - -### Minor Changes - -- [#5217](https://github.com/keystonejs/keystone/pull/5217) [`da900777a`](https://github.com/keystonejs/keystone/commit/da900777a27264595a68fe1ed0e7a689944eb372) Thanks [@timleslie](https://github.com/timleslie)! - `select` field type now uses the correct underlying type, allowing the use of `{ dataType: 'enum' }` and `{ dataType: 'integer'}`. - -### Patch Changes - -- [#5216](https://github.com/keystonejs/keystone/pull/5216) [`0e01f471d`](https://github.com/keystonejs/keystone/commit/0e01f471dc669e46c88233cb8ce698749ddcf4fa) Thanks [@timleslie](https://github.com/timleslie)! - Added a default config value of `{}` for the `mongoId` field type. - -* [#5212](https://github.com/keystonejs/keystone/pull/5212) [`76e5c7bd3`](https://github.com/keystonejs/keystone/commit/76e5c7bd3d5e4b74b1b3b6b6d6c23d087e81bb21) Thanks [@timleslie](https://github.com/timleslie)! - Moved test fixtures into the new packages. - -* Updated dependencies [[`ca1be4156`](https://github.com/keystonejs/keystone/commit/ca1be415663dd822b3adda1e073bd7a1d4a9b97b), [`9e78d8818`](https://github.com/keystonejs/keystone/commit/9e78d88187d8d789e5f080fd4529742f54ff1ddd), [`4d405390c`](https://github.com/keystonejs/keystone/commit/4d405390c0f8dcc37e6fe4da7ce3866c699088f3), [`34dd809ee`](https://github.com/keystonejs/keystone/commit/34dd809eef2368bba1e50ed613b36c5dac7262d1), [`a8be4c860`](https://github.com/keystonejs/keystone/commit/a8be4c8602bcda63d96fc956ead8568d8c989ffc), [`0e1487385`](https://github.com/keystonejs/keystone/commit/0e1487385c42556c027a6f7bfbc9aa806b3cbd66), [`aa76102c1`](https://github.com/keystonejs/keystone/commit/aa76102c11bdfea02059df66f406a8b1d387c879), [`f448a8b3a`](https://github.com/keystonejs/keystone/commit/f448a8b3a36b295d4ce5ff9ef2fd7aabcdb5dacc)]: - - @keystone-next/fields-legacy@24.0.0 - - @keystone-next/fields-auto-increment-legacy@9.0.0 - - @keystone-next/fields-mongoid-legacy@10.0.0 - - @keystone-next/types@15.0.1 - -## 5.3.0 - -### Minor Changes - -- [#3946](https://github.com/keystonejs/keystone/pull/3946) [`8e9b04ecd`](https://github.com/keystonejs/keystone/commit/8e9b04ecd07d9c5d0e6aead4705e7a655498ae05) Thanks [@timleslie](https://github.com/timleslie)! - Added experimental support for Prisma + SQLite as a database adapter. - -### Patch Changes - -- [#5131](https://github.com/keystonejs/keystone/pull/5131) [`1eeac4722`](https://github.com/keystonejs/keystone/commit/1eeac4722da174307152dad9b5adf5062e4b6403) Thanks [@timleslie](https://github.com/timleslie)! - Fixed type for `float({ defaultValue })`. - -* [#5150](https://github.com/keystonejs/keystone/pull/5150) [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed) Thanks [@timleslie](https://github.com/timleslie)! - Applied eslint `import/order` rule. - -- [#5113](https://github.com/keystonejs/keystone/pull/5113) [`ec6f9b601`](https://github.com/keystonejs/keystone/commit/ec6f9b601ea6fdbfb2335a5e81b7ec3f1b0e4d4d) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed Admin UI not allowing negative values for float, decimal and integer - -- Updated dependencies [[`8e9b04ecd`](https://github.com/keystonejs/keystone/commit/8e9b04ecd07d9c5d0e6aead4705e7a655498ae05), [`17c86e0c3`](https://github.com/keystonejs/keystone/commit/17c86e0c3eda7ba08d1bb8edf5eb8ddc9a819e5a), [`714bdadce`](https://github.com/keystonejs/keystone/commit/714bdadce8c87a15cf3a296b44a31b9b9ca95e9d), [`b84abebb6`](https://github.com/keystonejs/keystone/commit/b84abebb6c817172d04f338befa45b3573af55d6), [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed), [`56e5fe10b`](https://github.com/keystonejs/keystone/commit/56e5fe10bc89877be7d7e3013e53012b4d82b648), [`56e5fe10b`](https://github.com/keystonejs/keystone/commit/56e5fe10bc89877be7d7e3013e53012b4d82b648), [`b37cbffc8`](https://github.com/keystonejs/keystone/commit/b37cbffc886a4317793a97b7a8afd95639f59ce0), [`40d4fff5d`](https://github.com/keystonejs/keystone/commit/40d4fff5d63850cbd513c80bcb5e551e5782dc4b), [`215aed387`](https://github.com/keystonejs/keystone/commit/215aed387d35e9d4c896fe76991b12b54789cc55), [`b37cbffc8`](https://github.com/keystonejs/keystone/commit/b37cbffc886a4317793a97b7a8afd95639f59ce0), [`d31acf61b`](https://github.com/keystonejs/keystone/commit/d31acf61bcca96ac059d4ba2e78955513a6a0f91)]: - - @keystone-next/types@15.0.0 - - @keystone-next/fields-legacy@23.1.0 - - @keystone-next/fields-auto-increment-legacy@8.2.0 - - @keystone-ui/fields@2.0.2 - - @keystone-ui/core@2.0.2 - - @keystone-next/admin-ui@12.0.0 - - @keystone-next/admin-ui-utils@3.0.2 - - @keystone-next/fields-mongoid-legacy@9.1.7 - -## 5.2.1 - -### Patch Changes - -- Updated dependencies [[`c45cbb9b1`](https://github.com/keystonejs/keystone/commit/c45cbb9b14010b3ced7ea012f3502998ba2ec393), [`a2c52848a`](https://github.com/keystonejs/keystone/commit/a2c52848a3a7b66a1968a430040887194e6138d1), [`acc6e9772`](https://github.com/keystonejs/keystone/commit/acc6e9772b4a312a62ea756777034638c03a3761)]: - - @keystone-next/fields-legacy@23.0.0 - - @keystone-next/admin-ui@11.0.0 - - @keystone-next/fields-auto-increment-legacy@8.1.6 - - @keystone-next/fields-mongoid-legacy@9.1.6 - -## 5.2.0 - -### Minor Changes - -- [`aba7c45d7`](https://github.com/keystonejs/keystone/commit/aba7c45d7645aa71b50de070d37896b73248751a) [#4938](https://github.com/keystonejs/keystone/pull/4938) Thanks [@MurzNN](https://github.com/MurzNN)! - Added a `decimal` field type to keystone-next. - -### Patch Changes - -- Updated dependencies [[`aba7c45d7`](https://github.com/keystonejs/keystone/commit/aba7c45d7645aa71b50de070d37896b73248751a), [`9b202b31a`](https://github.com/keystonejs/keystone/commit/9b202b31a7d4944b709fe0ce58d6ca7ec1523a02)]: - - @keystone-next/fields-legacy@22.1.0 - - @keystone-next/admin-ui@10.0.1 - - @keystone-next/types@14.0.1 - -## 5.1.0 - -### Minor Changes - -- [`53b8b659f`](https://github.com/keystonejs/keystone/commit/53b8b659ffc7db41e0e0d9ad7393e6a821187340) [#4907](https://github.com/keystonejs/keystone/pull/4907) Thanks [@MurzNN](https://github.com/MurzNN)! - Added float field type for keystone-next - -### Patch Changes - -- [`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7) [#5018](https://github.com/keystonejs/keystone/pull/5018) Thanks [@bladey](https://github.com/bladey)! - Updated legacy packages to the @keystone-next namespace. - -- Updated dependencies [[`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7), [`1c5a39972`](https://github.com/keystonejs/keystone/commit/1c5a39972759a0aad49aed2c4b19e2c70a993a8a), [`687fd5ef0`](https://github.com/keystonejs/keystone/commit/687fd5ef0f798da996f970af1591411f9cfe0985), [`9a9276eb7`](https://github.com/keystonejs/keystone/commit/9a9276eb7acded979b703b4f3ed8bce781e0718a), [`370c0ee62`](https://github.com/keystonejs/keystone/commit/370c0ee623b515177c3863e66545465c13d5c914), [`2655c0b1b`](https://github.com/keystonejs/keystone/commit/2655c0b1bf714d80d46e1ff4e414b4bce474c23d), [`7b84c4066`](https://github.com/keystonejs/keystone/commit/7b84c40661a086b5468cc4d4542dfb696bfc2f93), [`29e787983`](https://github.com/keystonejs/keystone/commit/29e787983bdc26b147d6b5f476e70768bbc5318c), [`d9c20ba66`](https://github.com/keystonejs/keystone/commit/d9c20ba66931077f6e18d3497282be328cfb629f), [`0e265f6c1`](https://github.com/keystonejs/keystone/commit/0e265f6c10eadd37f75e5551b22b50236e830086), [`24e0ef5b6`](https://github.com/keystonejs/keystone/commit/24e0ef5b6bd93c105fdef2caea6b862ff1dfd6f3), [`45ea93421`](https://github.com/keystonejs/keystone/commit/45ea93421f9a6cf9b7ccbd983e0c9cbd687ff6af), [`6c949dbf2`](https://github.com/keystonejs/keystone/commit/6c949dbf262350e280072d82cd48fdd31ff5ba6d), [`3ca5038a0`](https://github.com/keystonejs/keystone/commit/3ca5038a021105a7452f4e7a4641107caa4ffe3a), [`bea9008f8`](https://github.com/keystonejs/keystone/commit/bea9008f82efea7fcf1cb547f3841915cd4689cc), [`c63e5d75c`](https://github.com/keystonejs/keystone/commit/c63e5d75cd77cf26f8762bda8143d1c1db6d0e3e), [`0f86e99bb`](https://github.com/keystonejs/keystone/commit/0f86e99bb3aa15f691ab7ff79e5a9ae3d1ac464e), [`5d565ea57`](https://github.com/keystonejs/keystone/commit/5d565ea57853713458329b823bde7a38776b02bc)]: - - @keystone-ui/button@3.0.1 - - @keystone-ui/core@2.0.1 - - @keystone-ui/fields@2.0.1 - - @keystone-ui/icons@2.0.1 - - @keystone-ui/loading@2.0.1 - - @keystone-ui/modals@2.0.1 - - @keystone-ui/segmented-control@2.0.1 - - @keystone-ui/toast@2.0.1 - - @keystone-ui/tooltip@2.0.1 - - @keystone-next/admin-ui@10.0.0 - - @keystone-next/admin-ui-utils@3.0.1 - - @keystone-next/types@14.0.0 - - @keystone-next/fields-legacy@22.0.1 - - @keystone-next/fields-auto-increment-legacy@8.1.5 - - @keystone-next/fields-mongoid-legacy@9.1.5 - -## 5.0.0 - -### Major Changes - -- [`b97216a65`](https://github.com/keystonejs/keystone/commit/b97216a6526fffcca8232d86b115c28cb19587bf) [#4622](https://github.com/keystonejs/keystone/pull/4622) Thanks [@renovate](https://github.com/apps/renovate)! - Updated react and react-dom to v17 - -### Patch Changes - -- Updated dependencies [[`ee019cfc5`](https://github.com/keystonejs/keystone/commit/ee019cfc51a831d005524e5427d0ebe1c71a1dee), [`b97216a65`](https://github.com/keystonejs/keystone/commit/b97216a6526fffcca8232d86b115c28cb19587bf), [`208722a42`](https://github.com/keystonejs/keystone/commit/208722a4234434e116846756bab18f7e11674ec8), [`ad75e3d61`](https://github.com/keystonejs/keystone/commit/ad75e3d61c73ba1239fd21b58f175aac01d9f302), [`74f428353`](https://github.com/keystonejs/keystone/commit/74f428353b90958f97669cbcb78e18ca44438765), [`4035218df`](https://github.com/keystonejs/keystone/commit/4035218df390beff3d42c0d3fc21335230d8a60d), [`954350389`](https://github.com/keystonejs/keystone/commit/9543503894c3e78a9b69a75cbfb3ca6b85ae34e8), [`e29ae2749`](https://github.com/keystonejs/keystone/commit/e29ae2749321c103dd494eba6778ee4137bb2aa3), [`ee019cfc5`](https://github.com/keystonejs/keystone/commit/ee019cfc51a831d005524e5427d0ebe1c71a1dee), [`8d0be8a89`](https://github.com/keystonejs/keystone/commit/8d0be8a89e2d9b89826365f81f47b8d8863b93d0)]: - - @keystone-next/admin-ui@9.0.0 - - @keystonejs/fields@22.0.0 - - @keystone-next/admin-ui-utils@3.0.0 - - @keystone-ui/button@3.0.0 - - @keystone-ui/core@2.0.0 - - @keystone-ui/fields@2.0.0 - - @keystone-ui/icons@2.0.0 - - @keystone-ui/loading@2.0.0 - - @keystone-ui/modals@2.0.0 - - @keystone-ui/segmented-control@2.0.0 - - @keystone-ui/toast@2.0.0 - - @keystone-ui/tooltip@2.0.0 - - @keystone-next/types@13.0.0 - - @keystonejs/fields-auto-increment@8.1.4 - - @keystonejs/fields-mongoid@9.1.4 - -## 4.1.1 - -### Patch Changes - -- Updated dependencies [[`1744c5f05`](https://github.com/keystonejs/keystone/commit/1744c5f05c9a13e680aaa1ed151f23f1d015ed9c), [`d9675553b`](https://github.com/keystonejs/keystone/commit/d9675553b33f39e2c7ada7eb6555d16e9fccb37e), [`fd0dff3fd`](https://github.com/keystonejs/keystone/commit/fd0dff3fdfcbe20b2884357a6e1b20f1b7307652), [`5be53ddc3`](https://github.com/keystonejs/keystone/commit/5be53ddc39be1415d56e2fa5e7898ab9edf468d5), [`fb8bcff91`](https://github.com/keystonejs/keystone/commit/fb8bcff91ef487730164c3330e0742ab13d9b3d7), [`096927a68`](https://github.com/keystonejs/keystone/commit/096927a6813a23030988ba8b64b2e8452f571a33)]: - - @keystone-next/types@12.0.0 - - @keystone-next/admin-ui@8.0.1 - - @keystone-next/admin-ui-utils@2.0.8 - -## 4.1.0 - -### Minor Changes - -- [`177cbd530`](https://github.com/keystonejs/keystone/commit/177cbd5303b814d1acaa8ded98e3d114c770bdba) [#4643](https://github.com/keystonejs/keystone/pull/4643) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Add DatePicker component to design system. - Update timestamp field in keystone-next to use the new DatePicker an an additional time picker input. - -### Patch Changes - -- Updated dependencies [[`4768fbf83`](https://github.com/keystonejs/keystone/commit/4768fbf831ffff648e540c479a1954ae40e05aaa), [`59027f8a4`](https://github.com/keystonejs/keystone/commit/59027f8a41cb11632f7c1eb5b3a8092193ecc87e), [`0d9404768`](https://github.com/keystonejs/keystone/commit/0d94047686d1bb1308fd8c47b769c999390d8f6d), [`b81a11c17`](https://github.com/keystonejs/keystone/commit/b81a11c171f3627f6cecb66bd2faeb89a68a009e), [`7ffd2ebb4`](https://github.com/keystonejs/keystone/commit/7ffd2ebb42dfaf12e23ba166b44ec4db60d9824b), [`0df2fb79c`](https://github.com/keystonejs/keystone/commit/0df2fb79c56094b5cdc0be6a0d6c2812ff0ec7f9), [`d090053df`](https://github.com/keystonejs/keystone/commit/d090053df9545380c42ddd18fae6782f3c3e2719), [`177cbd530`](https://github.com/keystonejs/keystone/commit/177cbd5303b814d1acaa8ded98e3d114c770bdba), [`160bd77d3`](https://github.com/keystonejs/keystone/commit/160bd77d39d5e99b11bee056fe2c3b2585126bbc), [`831db7c2b`](https://github.com/keystonejs/keystone/commit/831db7c2b7a9bced87acf76e3f431ca88a8880b0), [`a36bcf847`](https://github.com/keystonejs/keystone/commit/a36bcf847806ca0739f7b44d49a9bf6ac26a38d4), [`6ea4ff3cf`](https://github.com/keystonejs/keystone/commit/6ea4ff3cf77d5d2278bf4f0415d11aa7399a0490), [`81e86cbaa`](https://github.com/keystonejs/keystone/commit/81e86cbaa5c73633d6cb0ca2f84e834201e8bf9a)]: - - @keystone-next/types@11.0.0 - - @keystone-next/admin-ui@8.0.0 - - @keystone-ui/fields@1.1.0 - - @keystone-ui/tooltip@1.0.5 - - @keystonejs/fields@21.0.1 - - @keystone-next/admin-ui-utils@2.0.7 - -## 4.0.3 - -### Patch Changes - -- [`24ecd72e5`](https://github.com/keystonejs/keystone/commit/24ecd72e54eee12442c7c1d0533936a9ad86620a) [#4604](https://github.com/keystonejs/keystone/pull/4604) Thanks [@timleslie](https://github.com/timleslie)! - Renamed `SerializedAdminMeta` to `AdminMetaRootVal`. - -- Updated dependencies [[`24ecd72e5`](https://github.com/keystonejs/keystone/commit/24ecd72e54eee12442c7c1d0533936a9ad86620a)]: - - @keystone-next/admin-ui@7.0.1 - - @keystone-next/types@10.0.0 - - @keystone-next/admin-ui-utils@2.0.6 - -## 4.0.2 - -### Patch Changes - -- Updated dependencies [[`1236f5f40`](https://github.com/keystonejs/keystone/commit/1236f5f4024f1698b5a39343b4e5dbfa42c5fc9c), [`ba842d48b`](https://github.com/keystonejs/keystone/commit/ba842d48b5e9499ccd6f59d1610d55e964ffdb93), [`933c78a1e`](https://github.com/keystonejs/keystone/commit/933c78a1edc070b63f7720f64c15421ba28bdde5), [`f559e680b`](https://github.com/keystonejs/keystone/commit/f559e680bad7a7c948a317adfb91a3b024b486c4), [`89f7d4599`](https://github.com/keystonejs/keystone/commit/89f7d459906072940da1355c38815d1b3ef49368), [`17519bf64`](https://github.com/keystonejs/keystone/commit/17519bf64f277ad154fad1b0d5a423048e1336e0)]: - - @keystone-next/admin-ui@7.0.0 - - @keystone-ui/tooltip@1.0.4 - - @keystone-next/types@9.0.0 - - @keystone-next/admin-ui-utils@2.0.5 - -## 4.0.1 - -### Patch Changes - -- Updated dependencies [[`075ef1628`](https://github.com/keystonejs/keystone/commit/075ef16281a89c8291f90275adca98f042cc54da)]: - - @keystone-next/admin-ui@6.0.0 - - @keystone-next/types@8.0.0 - - @keystone-next/admin-ui-utils@2.0.4 - -## 4.0.0 - -### Major Changes - -- [`841be0bc9`](https://github.com/keystonejs/keystone/commit/841be0bc9d192cf64399231a543a9ba9ff41b9a0) [#4544](https://github.com/keystonejs/keystone/pull/4544) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replaced `useCompiledBcrypt` option with `bcrypt` option which accepts an alternative implementation of bcrypt(such as the native `bcrypt` npm package) in the password field type. - - For example, if you had the following field definition: - - ```js - password: { type: Password, useCompiledBcrypt: true } - ``` - - you will need to change it to: - - ```js - password: { type: Password, bcrypt: require('bcrypt') } - ``` - -### Patch Changes - -- Updated dependencies [[`364ac9254`](https://github.com/keystonejs/keystone/commit/364ac9254735befd2d4804789bb62464bb51ee5b), [`841be0bc9`](https://github.com/keystonejs/keystone/commit/841be0bc9d192cf64399231a543a9ba9ff41b9a0), [`2d3668c49`](https://github.com/keystonejs/keystone/commit/2d3668c49d1913afecbacf2b5ef164e553210956), [`6912c7b9d`](https://github.com/keystonejs/keystone/commit/6912c7b9dc3d786e61e6f657b0886b258d942c30), [`e33cf0c1e`](https://github.com/keystonejs/keystone/commit/e33cf0c1e78ae69cffaf45009e47ca1198464cf2), [`5c75534f6`](https://github.com/keystonejs/keystone/commit/5c75534f6e9e0f10a6556a1f1dc87b5fdd986dd4), [`6d09df338`](https://github.com/keystonejs/keystone/commit/6d09df3381d1682b8002d52ed1696b661fdff035), [`88b230317`](https://github.com/keystonejs/keystone/commit/88b2303177253aa5d76b50d40d19138af2bc3e41), [`39639b203`](https://github.com/keystonejs/keystone/commit/39639b2031bb749067ef537ea47e5d93a8bb89da), [`661104764`](https://github.com/keystonejs/keystone/commit/66110476491953af2134cd3cd4e3ef7c361ac5da), [`dab8121a6`](https://github.com/keystonejs/keystone/commit/dab8121a6a8eae4c42a5a9ecbdb72a3e8b1eeda4), [`88b230317`](https://github.com/keystonejs/keystone/commit/88b2303177253aa5d76b50d40d19138af2bc3e41), [`481e456ac`](https://github.com/keystonejs/keystone/commit/481e456ac4158207436ddd9be18fdca0f27b6409), [`08398473b`](https://github.com/keystonejs/keystone/commit/08398473bb81dfd43a3c134ed8de61e45aa770f0), [`2308e5efc`](https://github.com/keystonejs/keystone/commit/2308e5efc7c6893c87652411496b15a8124f6e05), [`4d3cb8e32`](https://github.com/keystonejs/keystone/commit/4d3cb8e32b22250fdbe04af758b0aad727ba63e4), [`f2c7675fb`](https://github.com/keystonejs/keystone/commit/f2c7675fb51ed41e6df8248c76b9322d6de5ee0d)]: - - @keystonejs/fields@21.0.0 - - @keystone-next/admin-ui@5.0.0 - - @keystone-next/types@7.0.0 - - @keystone-ui/core@1.0.4 - - @keystone-ui/fields@1.0.3 - - @keystonejs/fields-auto-increment@8.1.1 - - @keystonejs/fields-mongoid@9.1.1 - - @keystone-next/admin-ui-utils@2.0.3 - -## 3.2.2 - -### Patch Changes - -- Updated dependencies [[`dc58df5c8`](https://github.com/keystonejs/keystone/commit/dc58df5c87d694ce94b7d1c2b20d4976176dbd13), [`a5d7b264a`](https://github.com/keystonejs/keystone/commit/a5d7b264ad3e5590e335758881d22f7f296203c9), [`b7a4b997b`](https://github.com/keystonejs/keystone/commit/b7a4b997bae5b2269bea0ad94ca771e63c26ab95), [`ca34424d5`](https://github.com/keystonejs/keystone/commit/ca34424d58e58cc4a657828b1362978be8ee4f62), [`cffa011f7`](https://github.com/keystonejs/keystone/commit/cffa011f79a49e2f5c9165f82e6dff09a88a5b6d), [`192cbed74`](https://github.com/keystonejs/keystone/commit/192cbed74267b68be7de632667261ab943be1e2a), [`2338ed731`](https://github.com/keystonejs/keystone/commit/2338ed73185cd3d33c62fac69064c8a4950dc3fd), [`57092b7c1`](https://github.com/keystonejs/keystone/commit/57092b7c13845fffd1f3767bb609d203afbc2776), [`dbfef6256`](https://github.com/keystonejs/keystone/commit/dbfef6256b11d94250885f5f3a11d0ba81ad3b08), [`b21b62ed5`](https://github.com/keystonejs/keystone/commit/b21b62ed59fcd83ef2fc89587544b9d64522ba27), [`2da044a0c`](https://github.com/keystonejs/keystone/commit/2da044a0cb22dc16a54b7b5555c2b2678e8d4cab), [`341ee2b4b`](https://github.com/keystonejs/keystone/commit/341ee2b4b7eab89f296146ff9e14ce53233235f6), [`4b019b8cf`](https://github.com/keystonejs/keystone/commit/4b019b8cfcb7bea6f800609da5d07e8c8abfc80a), [`68d361d25`](https://github.com/keystonejs/keystone/commit/68d361d2596e8811caf00390c60341ef0c233c7b), [`3f3c65ab2`](https://github.com/keystonejs/keystone/commit/3f3c65ab2d206ef1c72f17259e73fb24a79f0a9b), [`bf22d9f2a`](https://github.com/keystonejs/keystone/commit/bf22d9f2afe537111b95571b86d4fd2759eb6a98), [`3be854440`](https://github.com/keystonejs/keystone/commit/3be85444064b8e62e97670594a1d2599ec2fd11c), [`fe52e25e0`](https://github.com/keystonejs/keystone/commit/fe52e25e04db121adbc6a0ce3bd0dbe1c7270180), [`1c12b8204`](https://github.com/keystonejs/keystone/commit/1c12b8204f8238997ddaf7337c44cf26ebea9ba4), [`6a364a664`](https://github.com/keystonejs/keystone/commit/6a364a664ce16f741408111054f0f3437a63a194), [`79ae6462a`](https://github.com/keystonejs/keystone/commit/79ae6462aac5ba9e27f9e95eacb2d94e76ce6a77)]: - - @keystone-next/admin-ui@4.0.0 - - @keystone-next/types@6.0.0 - - @keystone-next/admin-ui-utils@2.0.2 - -## 3.2.1 - -### Patch Changes - -- Updated dependencies [[`abdaeb9c1`](https://github.com/keystonejs/keystone/commit/abdaeb9c17a0f1d8e6eda1178d79107ac8770058), [`b6498d9f1`](https://github.com/keystonejs/keystone/commit/b6498d9f1341648742f2db78fec53b851b36dddd), [`d36e580cc`](https://github.com/keystonejs/keystone/commit/d36e580cc21e4b77a1bd0615c96c0793b9c5dac5), [`803626e88`](https://github.com/keystonejs/keystone/commit/803626e8854f9b7d293bd1829398d25a6692154a)]: - - @keystonejs/fields@20.1.3 - - @keystone-next/types@5.0.0 - - @keystone-next/admin-ui@3.1.2 - - @keystone-next/admin-ui-utils@2.0.1 - -## 3.2.0 - -### Minor Changes - -- [`8b12f795d`](https://github.com/keystonejs/keystone/commit/8b12f795d64dc085ca663921aa6826350d234cd0) [#4337](https://github.com/keystonejs/keystone/pull/4337) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `extraSelection` prop to RelationshipSelect - -### Patch Changes - -- [`c9159c956`](https://github.com/keystonejs/keystone/commit/c9159c9560efa7f7ae6ef802302c97b7a23f987b) [#4387](https://github.com/keystonejs/keystone/pull/4387) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated usage of `Fields` component - -* [`6cd469e29`](https://github.com/keystonejs/keystone/commit/6cd469e29682ff41a515ed76919efc2bfe0c7567) [#4414](https://github.com/keystonejs/keystone/pull/4414) Thanks [@JedWatson](https://github.com/JedWatson)! - Typed keystone context - -- [`139c74a4a`](https://github.com/keystonejs/keystone/commit/139c74a4aacfd5230fc86471b9cbd2a3c90bac9a) [#4378](https://github.com/keystonejs/keystone/pull/4378) Thanks [@timleslie](https://github.com/timleslie)! - Updated code to consistently use `context` rather than `ctx` for graphQL context variables. - -* [`b8c2c48ec`](https://github.com/keystonejs/keystone/commit/b8c2c48ec3746809894af7347c205f6a95329e8d) [#4407](https://github.com/keystonejs/keystone/pull/4407) Thanks [@JedWatson](https://github.com/JedWatson)! - Show list label instead of "item" when linking to related items - -* Updated dependencies [[`038b0ae65`](https://github.com/keystonejs/keystone/commit/038b0ae6586f8673de22046842b2ef993b0e1937), [`55a04a100`](https://github.com/keystonejs/keystone/commit/55a04a1004b7f15fcd41b4935d74fd1847c9deeb), [`f4a855c71`](https://github.com/keystonejs/keystone/commit/f4a855c71e966ef3ebc894a3b0f1af51e5182394), [`c9159c956`](https://github.com/keystonejs/keystone/commit/c9159c9560efa7f7ae6ef802302c97b7a23f987b), [`c9159c956`](https://github.com/keystonejs/keystone/commit/c9159c9560efa7f7ae6ef802302c97b7a23f987b), [`6cd469e29`](https://github.com/keystonejs/keystone/commit/6cd469e29682ff41a515ed76919efc2bfe0c7567), [`fa12a18b0`](https://github.com/keystonejs/keystone/commit/fa12a18b077367563b1b69db55274e47a1bd5027), [`4eef4dc55`](https://github.com/keystonejs/keystone/commit/4eef4dc5587cc06f08ead5d5d05db2e9a786b8bc), [`eddd7e795`](https://github.com/keystonejs/keystone/commit/eddd7e79599e20f5bef61f240d874b37d0a084c4), [`139c74a4a`](https://github.com/keystonejs/keystone/commit/139c74a4aacfd5230fc86471b9cbd2a3c90bac9a), [`c9159c956`](https://github.com/keystonejs/keystone/commit/c9159c9560efa7f7ae6ef802302c97b7a23f987b)]: - - @keystonejs/fields@20.1.2 - - @keystone-ui/core@1.0.3 - - @keystone-next/admin-ui@3.1.1 - - @keystone-next/admin-ui-utils@2.0.0 - - @keystone-next/types@4.1.1 - - @keystone-ui/tooltip@1.0.3 - -## 3.1.0 - -### Minor Changes - -- [`2d5f78207`](https://github.com/keystonejs/keystone/commit/2d5f78207103caaf8f86a4dd05b7e4b0a4795213) [#4302](https://github.com/keystonejs/keystone/pull/4302) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Exposed RelationshipSelect in an entrypoint - -### Patch Changes - -- Updated dependencies [[`80c980452`](https://github.com/keystonejs/keystone/commit/80c9804522d493106321e1832ca07be07437720a), [`c62a35fe0`](https://github.com/keystonejs/keystone/commit/c62a35fe0834ec60e2472b22feedda539d18a918), [`add3f67e3`](https://github.com/keystonejs/keystone/commit/add3f67e379caebbcf0880b4ce82cf6a1e89020b), [`2d5f78207`](https://github.com/keystonejs/keystone/commit/2d5f78207103caaf8f86a4dd05b7e4b0a4795213)]: - - @keystone-ui/fields@1.0.2 - - @keystonejs/fields@20.1.1 - - @keystone-next/types@4.1.0 - - @keystone-next/admin-ui@3.1.0 - -## 3.0.1 - -### Patch Changes - -- [`81a140ee3`](https://github.com/keystonejs/keystone/commit/81a140ee3badc9c032ab02a233a21d011278e173) [#4289](https://github.com/keystonejs/keystone/pull/4289) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixed many relationship select clipping in the Create drawer - -- Updated dependencies [[`11777cddb`](https://github.com/keystonejs/keystone/commit/11777cddba45b28a9e17a3149b792db121322b46), [`cbf11a69b`](https://github.com/keystonejs/keystone/commit/cbf11a69b8f2c428e2c0a08dd568b3bc0e0d80f4), [`b2de22941`](https://github.com/keystonejs/keystone/commit/b2de229419cc93b69ee4027c387cab9c8d701488), [`cc987d078`](https://github.com/keystonejs/keystone/commit/cc987d078653fd9e686069f9f885f1269b64a882), [`60e061246`](https://github.com/keystonejs/keystone/commit/60e061246bc35b76031f43ff6c07446fe6ad3c6b), [`cc987d078`](https://github.com/keystonejs/keystone/commit/cc987d078653fd9e686069f9f885f1269b64a882)]: - - @keystone-next/admin-ui@3.0.0 - - @keystone-next/types@4.0.0 - - @keystone-next/admin-ui-utils@1.0.2 - -## 3.0.0 - -### Major Changes - -- [`fab97f6b4`](https://github.com/keystonejs/keystone/commit/fab97f6b416d7040cdd159be379e226142fc189c) [#4238](https://github.com/keystonejs/keystone/pull/4238) Thanks [@timleslie](https://github.com/timleslie)! - Removed `getBackingType` from `FieldType` as this functionality is now provided by `field.getBackingTypes()` in the core field classes. - -### Minor Changes - -- [`8291187de`](https://github.com/keystonejs/keystone/commit/8291187de347784f21e4d856ed1eefbc5b8a103b) [#4207](https://github.com/keystonejs/keystone/pull/4207) Thanks [@JedWatson](https://github.com/JedWatson)! - Improve field cell components - -### Patch Changes - -- [`fd4b0d04c`](https://github.com/keystonejs/keystone/commit/fd4b0d04cd9ab8ba12653f1e64fdf08d8cb0c4db) [#4186](https://github.com/keystonejs/keystone/pull/4186) Thanks [@JedWatson](https://github.com/JedWatson)! - Improving the appearance of readonly fields in the Admin UI - -* [`c103cde7d`](https://github.com/keystonejs/keystone/commit/c103cde7da198cd7e9adefa763c51e433680e800) [#4226](https://github.com/keystonejs/keystone/pull/4226) Thanks [@jossmac](https://github.com/jossmac)! - General admin tidy - -- [`84e651c3f`](https://github.com/keystonejs/keystone/commit/84e651c3f08fdfc11628490c9d55229dc360f52a) [#4187](https://github.com/keystonejs/keystone/pull/4187) Thanks [@JedWatson](https://github.com/JedWatson)! - Improve readonly relationship views - -* [`549a9a06d`](https://github.com/keystonejs/keystone/commit/549a9a06d9dbeb514aad724ece603a3fa7fc8cb6) [#4197](https://github.com/keystonejs/keystone/pull/4197) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Improved field UI when fields have `itemView: { fieldMode: 'read'}` - -- [`400a6e50c`](https://github.com/keystonejs/keystone/commit/400a6e50cba643f4b142858bb1cac83a50ab020d) [#4243](https://github.com/keystonejs/keystone/pull/4243) Thanks [@timleslie](https://github.com/timleslie)! - Improved internal consistency of field definition code. - -* [`7afde2fb5`](https://github.com/keystonejs/keystone/commit/7afde2fb516e1d3824d73a96308abb4a6b022400) [#4253](https://github.com/keystonejs/keystone/pull/4253) Thanks [@jossmac](https://github.com/jossmac)! - Admin UI layout experiments and general tidy, esp. fields - -- [`2a2a7c00b`](https://github.com/keystonejs/keystone/commit/2a2a7c00b74028b758006219781cbbd22909be85) [#4185](https://github.com/keystonejs/keystone/pull/4185) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixed field defaultValue types for new fields package - -* [`8e77254a2`](https://github.com/keystonejs/keystone/commit/8e77254a262a4c892263e30044803b463750c3e9) [#4179](https://github.com/keystonejs/keystone/pull/4179) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixed defaultValue types for `AutoIncrement` and `Integer` fields. - -- [`b9e643dc6`](https://github.com/keystonejs/keystone/commit/b9e643dc6c66f75bc6d5b6ced74d91ba3ee7533d) [#4199](https://github.com/keystonejs/keystone/pull/4199) Thanks [@JedWatson](https://github.com/JedWatson)! - Fix a bunch of minor bugs in the relationship field cards view - -* [`0e65409c7`](https://github.com/keystonejs/keystone/commit/0e65409c7416d285fdc4f9da4a7dfb0f652c6cb2) [#4216](https://github.com/keystonejs/keystone/pull/4216) Thanks [@jossmac](https://github.com/jossmac)! - Admin UI tidy: mostly alignment and spacing consolidation. - -* Updated dependencies [[`fd4b0d04c`](https://github.com/keystonejs/keystone/commit/fd4b0d04cd9ab8ba12653f1e64fdf08d8cb0c4db), [`c103cde7d`](https://github.com/keystonejs/keystone/commit/c103cde7da198cd7e9adefa763c51e433680e800), [`3d66ebc87`](https://github.com/keystonejs/keystone/commit/3d66ebc87c4dea7fa70df1209c8d85f539ceccb8), [`98e8fd4bc`](https://github.com/keystonejs/keystone/commit/98e8fd4bc586c732d629328ef643014ce42442ed), [`d02957453`](https://github.com/keystonejs/keystone/commit/d029574533c179fa53f65c0e0ba3812dab2ba4ad), [`302afe226`](https://github.com/keystonejs/keystone/commit/302afe226162452c91d9e2f11f5c29552df70c6a), [`98dd7dcff`](https://github.com/keystonejs/keystone/commit/98dd7dcffa797eb40eb1713ba1ac2697dfef95e3), [`7afde2fb5`](https://github.com/keystonejs/keystone/commit/7afde2fb516e1d3824d73a96308abb4a6b022400), [`8291187de`](https://github.com/keystonejs/keystone/commit/8291187de347784f21e4d856ed1eefbc5b8a103b), [`5216e9dc6`](https://github.com/keystonejs/keystone/commit/5216e9dc6894c1a6e81765c0278dc6f7c4cc617b), [`fab97f6b4`](https://github.com/keystonejs/keystone/commit/fab97f6b416d7040cdd159be379e226142fc189c), [`fab97f6b4`](https://github.com/keystonejs/keystone/commit/fab97f6b416d7040cdd159be379e226142fc189c), [`36cf9b0a9`](https://github.com/keystonejs/keystone/commit/36cf9b0a9f6c9c2cd3c823146135f86d4152718b), [`6eb4def9a`](https://github.com/keystonejs/keystone/commit/6eb4def9a1be293872e59bcf6472866c0981b45f), [`8f4ebd5f7`](https://github.com/keystonejs/keystone/commit/8f4ebd5f70251ccdfb6b5ce14efb9fb59f5d2b3d), [`2a2a7c00b`](https://github.com/keystonejs/keystone/commit/2a2a7c00b74028b758006219781cbbd22909be85), [`68f1c8fdc`](https://github.com/keystonejs/keystone/commit/68f1c8fdc83f683d13de55b2f3a81eff7639ebf6), [`28e2b43d4`](https://github.com/keystonejs/keystone/commit/28e2b43d4a5a4624b3ad6683e5f4f0116a5971f4), [`cfa0d8275`](https://github.com/keystonejs/keystone/commit/cfa0d8275c89f09b89643c801b208161348b4f65), [`9928da13e`](https://github.com/keystonejs/keystone/commit/9928da13ecca03fed560a42e1071afc59c0feb3b), [`d2927f78c`](https://github.com/keystonejs/keystone/commit/d2927f78c40bdb21190d06991466566f49a9f08b), [`0e65409c7`](https://github.com/keystonejs/keystone/commit/0e65409c7416d285fdc4f9da4a7dfb0f652c6cb2)]: - - @keystone-ui/core@1.0.2 - - @keystone-ui/fields@1.0.1 - - @keystone-ui/tooltip@1.0.2 - - @keystone-next/admin-ui@2.0.2 - - @keystone-next/types@3.0.0 - - @keystonejs/fields@20.1.0 - - @keystone-next/admin-ui-utils@1.0.1 - - @keystone-ui/modals@1.0.2 - - @keystone-ui/segmented-control@1.0.1 - - @keystone-ui/toast@1.0.1 - - @keystonejs/fields-auto-increment@8.1.0 - - @keystonejs/fields-mongoid@9.1.0 - - @keystone-ui/button@2.0.1 - -## 2.0.1 - -### Patch Changes - -- [`d6139dcf9`](https://github.com/keystonejs/keystone/commit/d6139dcf99f87d78c5e1bb0393349bb52bcb28bd) [#4163](https://github.com/keystonejs/keystone/pull/4163) Thanks [@JedWatson](https://github.com/JedWatson)! - UX improvements to relationship cards - -- Updated dependencies [[`ce6b8ebee`](https://github.com/keystonejs/keystone/commit/ce6b8ebeef39f2d22bfc62500a408739a7f1f419), [`6c3b566a1`](https://github.com/keystonejs/keystone/commit/6c3b566a130fa4eb5ae57e638b4cff7a16299998), [`c3e4c1e3f`](https://github.com/keystonejs/keystone/commit/c3e4c1e3fdf8ffdbfd785860c26d15e665c5e25e), [`39a5890de`](https://github.com/keystonejs/keystone/commit/39a5890de2021b9e32569ce4011c3e2948d4ede6)]: - - @keystone-ui/tooltip@1.0.1 - - @keystone-ui/button@2.0.0 - - @keystone-ui/core@1.0.1 - - @keystone-next/admin-ui@2.0.1 - - @keystone-ui/modals@1.0.1 - -## 2.0.0 - -### Major Changes - -- [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797) [#4132](https://github.com/keystonejs/keystone/pull/4132) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Add CardValue export from field views - -### Minor Changes - -- [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797) [#4132](https://github.com/keystonejs/keystone/pull/4132) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Add `displayMode: 'cards'` to relationship field type - -### Patch Changes - -- [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797) [#4132](https://github.com/keystonejs/keystone/pull/4132) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Handle autoFocus in various field views - -* [`f3c0f79e3`](https://github.com/keystonejs/keystone/commit/f3c0f79e3005aa6a8e867efef4431b83bbdf9898) [#4137](https://github.com/keystonejs/keystone/pull/4137) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Add missing options `isRequired`, `defaultValue`, `isUnique` and `isIndexed` to field types - -* Updated dependencies [[`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797), [`166acb9bf`](https://github.com/keystonejs/keystone/commit/166acb9bf211e0ee8a90d4740f6ebc54ffe72dec), [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797), [`166acb9bf`](https://github.com/keystonejs/keystone/commit/166acb9bf211e0ee8a90d4740f6ebc54ffe72dec), [`71b74161d`](https://github.com/keystonejs/keystone/commit/71b74161dfc9d7f0b918a3451cf545935afce94d), [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797)]: - - @keystone-next/admin-ui-utils@1.0.0 - - @keystone-next/types@2.0.0 - - @keystone-next/admin-ui@2.0.0 - -## 1.0.0 - -### Major Changes - -- [`9d360a67b`](https://github.com/keystonejs/keystone/commit/9d360a67b69ec38e3018fe132b1e34f24956f86c) [#4106](https://github.com/keystonejs/keystone/pull/4106) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Initial release - -### Patch Changes - -- Updated dependencies [[`a5e40e6c4`](https://github.com/keystonejs/keystone/commit/a5e40e6c4af1ab38cc2079a0f6e27d39d6b7d546), [`9d360a67b`](https://github.com/keystonejs/keystone/commit/9d360a67b69ec38e3018fe132b1e34f24956f86c), [`2d660b2a1`](https://github.com/keystonejs/keystone/commit/2d660b2a1dd013787e022cad3a0c70dbe08c60da)]: - - @keystonejs/fields@20.0.0 - - @keystone-ui/button@1.0.0 - - @keystone-ui/core@1.0.0 - - @keystone-ui/fields@1.0.0 - - @keystone-ui/icons@1.0.0 - - @keystone-ui/modals@1.0.0 - - @keystone-ui/segmented-control@1.0.0 - - @keystone-ui/tooltip@1.0.0 - - @keystone-next/admin-ui@1.0.0 - - @keystone-next/types@1.0.0 - - @keystonejs/fields-auto-increment@8.0.1 - - @keystonejs/fields-mongoid@9.0.1 diff --git a/packages/fields/README.md b/packages/fields/README.md deleted file mode 100644 index eaa05fed160..00000000000 --- a/packages/fields/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# @keystone-next/fields - -The exports of this package have been moved to `@keystone-next/keystone/fields`. - -Keystone-next is a preview release of the next version of Keystone. Please visit for full details. - -For updates, [follow @keystonejs on Twitter](https://twitter.com/keystonejs) and [join us in Slack](https://community.keystonejs.com/). diff --git a/packages/fields/package.json b/packages/fields/package.json deleted file mode 100644 index a4a158f3997..00000000000 --- a/packages/fields/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@keystone-next/fields", - "version": "15.0.0", - "license": "MIT", - "main": "dist/fields.cjs.js", - "module": "dist/fields.esm.js", - "engines": { - "node": "^12.20 || >= 14.13" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/packages/fields" -} diff --git a/packages/fields/src/index.ts b/packages/fields/src/index.ts deleted file mode 100644 index bf7cc1b7b46..00000000000 --- a/packages/fields/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -throw new Error( - '`@keystone-next/fields` has been moved to `@keystone-next/keystone/fields`, please import from there instead.' -); - -export {}; diff --git a/packages/testing/.npmignore b/packages/testing/.npmignore deleted file mode 100644 index 851b108d115..00000000000 --- a/packages/testing/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -**/*.md -**/*.test.js diff --git a/packages/testing/CHANGELOG.md b/packages/testing/CHANGELOG.md deleted file mode 100644 index 1834e76401f..00000000000 --- a/packages/testing/CHANGELOG.md +++ /dev/null @@ -1,52 +0,0 @@ -# @keystone-next/testing - -## 2.0.0 - -### Major Changes - -- [#6361](https://github.com/keystonejs/keystone/pull/6361) [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved exports of `@keystone-next/testing` to `@keystone-next/keystone/testing` - -## 1.1.1 - -### Patch Changes - -- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: - - @keystone-next/keystone@24.0.0 - -## 1.1.0 - -### Minor Changes - -- [#6193](https://github.com/keystonejs/keystone/pull/6193) [`14cb7c5c4`](https://github.com/keystonejs/keystone/commit/14cb7c5c40456cd0d2c8408ed46823d2695614cc) Thanks [@timleslie](https://github.com/timleslie)! - Added an `app` value to the `TestArgs` type to provide direct access to the Express application from test runners. - -### Patch Changes - -- Updated dependencies [[`3f03b8c1f`](https://github.com/keystonejs/keystone/commit/3f03b8c1fa7005b37371e1cc401c3a03334a4f7a), [`ea0712aa2`](https://github.com/keystonejs/keystone/commit/ea0712aa22487325bd898818ea4fbca543c9dcf1), [`93f1e5d30`](https://github.com/keystonejs/keystone/commit/93f1e5d302701c610b6cba74e0c5c86a3ac8aacc), [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523), [`7716315ea`](https://github.com/keystonejs/keystone/commit/7716315ea823dd91d17d54dcbb9155b5445cd956), [`a11e54d69`](https://github.com/keystonejs/keystone/commit/a11e54d692d3cec4ec2439cbf743b590688fb7d3), [`e5f61ad50`](https://github.com/keystonejs/keystone/commit/e5f61ad50133a328fcb32299b838fd9eac574c3f), [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4), [`dd7e811e7`](https://github.com/keystonejs/keystone/commit/dd7e811e7ce084c1e832acefc6ed773af371ac9e), [`587a8d0b0`](https://github.com/keystonejs/keystone/commit/587a8d0b074ccecb239d120275359f72779f306f), [`597edbdd8`](https://github.com/keystonejs/keystone/commit/597edbdd81df80982dd3df3d9d600003ef8a15e9), [`1172e1853`](https://github.com/keystonejs/keystone/commit/1172e18531064df6412c06412e74da3b85740b35), [`fbe698461`](https://github.com/keystonejs/keystone/commit/fbe6984616de7a302db7c2b0082851db89c2e314), [`32e9879db`](https://github.com/keystonejs/keystone/commit/32e9879db9cfee77f067eb8105262df65bca6c06)]: - - @keystone-next/keystone@23.0.0 - -## 1.0.2 - -### Patch Changes - -- [#6087](https://github.com/keystonejs/keystone/pull/6087) [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951) Thanks [@JedWatson](https://github.com/JedWatson)! - Move source code from the `packages-next` to the `packages` directory. - -- Updated dependencies [[`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790), [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951), [`279403cb0`](https://github.com/keystonejs/keystone/commit/279403cb0b4bffb946763c9a7ef71be57478eeb3), [`253df44c2`](https://github.com/keystonejs/keystone/commit/253df44c2f8d6535a6425b2593eaed5380433d57), [`f482db633`](https://github.com/keystonejs/keystone/commit/f482db6332e54a1d5cd469e2805b99b544208e83)]: - - @keystone-next/keystone@22.0.0 - -## 1.0.1 - -### Patch Changes - -- Updated dependencies [[`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b), [`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b)]: - - @keystone-next/keystone@21.0.0 - -## 1.0.0 - -### Major Changes - -- [#5926](https://github.com/keystonejs/keystone/pull/5926) [`3b9cdc2c0`](https://github.com/keystonejs/keystone/commit/3b9cdc2c0cc19be109d7d5e0d7ccd43946f35ffe) Thanks [@timleslie](https://github.com/timleslie)! - Initial release of the `@keystone-next/testing` package. - -### Patch Changes - -- Updated dependencies [[`10b36551a`](https://github.com/keystonejs/keystone/commit/10b36551ac3a88da2cfeba3d065d6dd36041e769), [`8afbab763`](https://github.com/keystonejs/keystone/commit/8afbab7636b4236c6604311819160d5f1420a90e), [`7a25925c3`](https://github.com/keystonejs/keystone/commit/7a25925c3dc5b2af2cf1209ee949563fb71a4a8c), [`50ad1ce6b`](https://github.com/keystonejs/keystone/commit/50ad1ce6be90f5fb2481840dbd01328b6f629432), [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c), [`123042b04`](https://github.com/keystonejs/keystone/commit/123042b047f3242ac95d2c5280de8c07f18a86be), [`4e5634b86`](https://github.com/keystonejs/keystone/commit/4e5634b86a26819cecec5b10c18f9d231b5434e2), [`006afd108`](https://github.com/keystonejs/keystone/commit/006afd1082b474bac2499bed57bcaccf1e1d6138), [`3be09ea54`](https://github.com/keystonejs/keystone/commit/3be09ea548861b490dad8b50e58980580d366434), [`eab130f30`](https://github.com/keystonejs/keystone/commit/eab130f30d79b82c18b3cce0bc054abe2c1b58fd)]: - - @keystone-next/keystone@20.0.1 diff --git a/packages/testing/README.md b/packages/testing/README.md deleted file mode 100644 index 66e2b3d5adb..00000000000 --- a/packages/testing/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Testing - -This exports of this package have been moved to `@keystone-next/keystone` diff --git a/packages/testing/package.json b/packages/testing/package.json deleted file mode 100644 index 71dbdb1d15d..00000000000 --- a/packages/testing/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@keystone-next/testing", - "description": "Tools to assist with testing Keystone projects", - "version": "2.0.0", - "author": "The KeystoneJS Development Team", - "license": "MIT", - "main": "dist/testing.cjs.js", - "module": "dist/testing.esm.js", - "engines": { - "node": "^12.20 || >= 14.13" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/packages/testing" -} diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts deleted file mode 100644 index bba900a323f..00000000000 --- a/packages/testing/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -throw new Error( - "Keystone's testing utilities have moved to `@keystone-next/keystone/testing`, please import them from there instead." -); - -export {}; diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md deleted file mode 100644 index e04b668efe4..00000000000 --- a/packages/types/CHANGELOG.md +++ /dev/null @@ -1,795 +0,0 @@ -# @keystone-next/types - -## 25.0.0 - -### Major Changes - -- [#6371](https://github.com/keystonejs/keystone/pull/6371) [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/types` to `@keystone-next/keystone/types` - -## 24.0.0 - -### Major Changes - -- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `_ListKeyMeta` and `_toManyRelationshipFieldMeta` fields. You should use `listKeyCount` and `toManyRelationshipFieldCount` instead - -* [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed all arguments from `context.lists.List.count` and `context.db.lists.List.count` except for `where`. - -- [#6266](https://github.com/keystonejs/keystone/pull/6266) [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Renamed `first` argument in find many queries to `take` to align with Prisma. - - ```graphql - type Query { - users( - where: UserWhereInput! = {} - orderBy: [UserOrderByInput!]! = [] - # previously was first: Int - take: Int - skip: Int! = 0 - ): [User!] - # ... - } - - type User { - # ... - posts( - where: PostWhereInput! = {} - orderBy: [PostOrderByInput!]! = [] - # previously was first: Int - take: Int - skip: Int! = 0 - ): [Post!] - # ... - } - ``` - -* [#6208](https://github.com/keystonejs/keystone/pull/6208) [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The create one mutation now requires a non-null `data` argument and the create many mutation accepts a list of `ItemCreateInput` directly instead of being nested inside of an object with the `ItemCreateInput` in a `data` field. - - If you have a list called `Item`, `createItem` now looks like `createItem(data: ItemCreateInput!): Item` and `createItems` now looks like `createItems(data: [ItemCreateInput!]!): [Item]`. - -- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `search` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `contains` filters instead. - -* [#6095](https://github.com/keystonejs/keystone/pull/6095) [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated filters to be nested instead of flattened and add top-level `NOT` operator. See the [Query Filter API docs](https://keystonejs.com/docs/apis/filters) and the upgrade guide for more information. - - ```graphql - query { - posts(where: { title: { contains: "Something" } }) { - title - content - } - } - ``` - -- [#6196](https://github.com/keystonejs/keystone/pull/6196) [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `sortBy` argument from the GraphQL API for finding many items, Lists/DB API and to-many relationship fields. You should use `orderBy` instead. - -* [#6312](https://github.com/keystonejs/keystone/pull/6312) [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Updated `@graphql-ts/schema`. The second type parameter of `schema.Arg` exported from `@keystone-next/types` is now a boolean that defines whether or not the arg has a default value to make it easier to define circular input objects. - -- [#6217](https://github.com/keystonejs/keystone/pull/6217) [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been renamed to `disconnect` in to-one relationship inputs and the old `disconnect` field has been removed. There are also seperate input types for create and update where the input for create doesn't have `disconnect`. It's also now required that if you provide a to-one relationship input, you must provide exactly one field to the input. - - If you have a list called `Item`, the to-one relationship inputs now look like this: - - ```graphql - input ItemRelateToOneForCreateInput { - create: ItemCreateInput - connect: ItemWhereUniqueInput - } - input ItemRelateToOneForUpdateInput { - create: ItemCreateInput - connect: ItemWhereUniqueInput - disconnect: Boolean - } - ``` - -* [#6224](https://github.com/keystonejs/keystone/pull/6224) [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - `disconnectAll` has been replaced by `set` in to-many relationship inputs, the equivalent to `disconnectAll: true` is now `set: []`. There are also seperate input types for create and update where the input for create doesn't have `disconnect` or `set`. The inputs in the lists in the input field are now also non-null. - - If you have a list called `Item`, the to-many relationship inputs now look like this: - - ```graphql - input ItemRelateToManyForCreateInput { - create: [ItemCreateInput!] - connect: [ItemWhereUniqueInput!] - } - input ItemRelateToManyForUpdateInput { - disconnect: [ItemWhereUniqueInput!] - set: [ItemWhereUniqueInput!] - create: [ItemCreateInput!] - connect: [ItemWhereUniqueInput!] - } - ``` - -- [#6197](https://github.com/keystonejs/keystone/pull/6197) [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The generated CRUD queries, and some of the input types, in the GraphQL API have been renamed. - - If you have a list called `Item`, the query for multiple values, `allItems` will be renamed to `items`. The query for a single value, `Item`, will be renamed to `item`. - - Also, the input type used in the `updateItems` mutation has been renamed from `ItemsUpdateInput` to `ItemUpdateArgs`. - -* [#6211](https://github.com/keystonejs/keystone/pull/6211) [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The update mutations now accept `where` unique inputs instead of only an `id` and the `where` and `data` arguments are non-null. - - If you have a list called `Item`, the update mutations now look like this: - - ```graphql - type Mutation { - updateItem(where: ItemWhereUniqueInput!, data: ItemUpdateInput!): Item - updateItems(data: [ItemUpdateArgs!]!): [Item] - } - - input ItemUpdateArgs { - where: ItemWhereUniqueInput! - data: ItemUpdateInput! - } - ``` - -- [#6206](https://github.com/keystonejs/keystone/pull/6206) [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The delete mutations now accept `where` unique inputs instead of only an `id`. - - If you have a list called `Item`, `deleteItem` now looks like `deleteItem(where: ItemWhereUniqueInput!): Item` and `deleteItems` now looks like `deleteItems(where: [ItemWhereUniqueInput!]!): [Item]` - -### Minor Changes - -- [#6267](https://github.com/keystonejs/keystone/pull/6267) [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590) Thanks [@timleslie](https://github.com/timleslie)! - Added `config.graphql.debug` option, which can be used to control whether debug information such as stack traces are included in the errors returned by the GraphQL API. - -### Patch Changes - -- [#6249](https://github.com/keystonejs/keystone/pull/6249) [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2) Thanks [@timleslie](https://github.com/timleslie)! - Updated types to allow the `'id'` field in `ui.labelField`, `ui.listView.initialColumns`, and `ui.listView.initialSort`. - -- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e)]: - - @keystone-next/fields@14.0.0 - -## 23.0.0 - -### Major Changes - -- [#6165](https://github.com/keystonejs/keystone/pull/6165) [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `ui.searchFields` option to lists to allow searching by multiple fields in the Admin UI (the only current usage of this is in the select used in relationship fields) and to replace the usage of the `search` GraphQL argument which will be removed soon and should be replaced by using `contains` filters directly. - -### Minor Changes - -- [#6111](https://github.com/keystonejs/keystone/pull/6111) [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523) Thanks [@gwyneplaine](https://github.com/gwyneplaine)! - Add Admin UI specific types AuthenticatedItem, VisibleLists, CreateViewFieldModes and NavigationProps to exports. - -### Patch Changes - -- [#6192](https://github.com/keystonejs/keystone/pull/6192) [`93f1e5d30`](https://github.com/keystonejs/keystone/commit/93f1e5d302701c610b6cba74e0c5c86a3ac8aacc) Thanks [@JedWatson](https://github.com/JedWatson)! - Added an optional `/_healthcheck` endpoint to Keystone's express server. - - You can enable it by setting `config.server.healthCheck: true` - - By default it will respond with `{ status: 'pass', timestamp: Date.now() }` - - You can also specify a custom path and JSON data: - - ```js - config({ - server: { - healthCheck: { - path: '/my-health-check', - data: { status: 'healthy' }, - }, - }, - }); - ``` - - Or use a function for the `data` config to return real-time information: - - ```js - config({ - server: { - healthCheck: { - path: '/my-health-check', - data: () => ({ - status: 'healthy', - timestamp: Date.now(), - uptime: process.uptime(), - }), - }, - }, - }); - ``` - -- Updated dependencies [[`a11e54d69`](https://github.com/keystonejs/keystone/commit/a11e54d692d3cec4ec2439cbf743b590688fb7d3), [`e5f61ad50`](https://github.com/keystonejs/keystone/commit/e5f61ad50133a328fcb32299b838fd9eac574c3f), [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4), [`2ef6fe82c`](https://github.com/keystonejs/keystone/commit/2ef6fe82cee6df7796935d35d1c12cab29aecc75)]: - - @keystone-next/fields@13.0.0 - -## 22.0.0 - -### Major Changes - -- [#6027](https://github.com/keystonejs/keystone/pull/6027) [`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790) Thanks [@renovate](https://github.com/apps/renovate)! - Updated Prisma dependency to `2.26.0`. - -### Patch Changes - -- [#6061](https://github.com/keystonejs/keystone/pull/6061) [`5f3d407d7`](https://github.com/keystonejs/keystone/commit/5f3d407d79171f04ae877e8eaed9a7f9d5671705) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed TypeScript errors in declarations - -* [#6087](https://github.com/keystonejs/keystone/pull/6087) [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951) Thanks [@JedWatson](https://github.com/JedWatson)! - Move source code from the `packages-next` to the `packages` directory. - -* Updated dependencies [[`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790), [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951), [`253df44c2`](https://github.com/keystonejs/keystone/commit/253df44c2f8d6535a6425b2593eaed5380433d57), [`c536b478f`](https://github.com/keystonejs/keystone/commit/c536b478fc89f2d933cddf8533e7d88030540a63)]: - - @keystone-next/fields@12.0.0 - -## 21.0.1 - -### Patch Changes - -- [#6029](https://github.com/keystonejs/keystone/pull/6029) [`038cd09a2`](https://github.com/keystonejs/keystone/commit/038cd09a201081e3f56ffd75577e6b74a6eb19e5) Thanks [@bladey](https://github.com/bladey)! - Updated Keystone URL reference from next.keystonejs.com to keystonejs.com. - -- Updated dependencies [[`038cd09a2`](https://github.com/keystonejs/keystone/commit/038cd09a201081e3f56ffd75577e6b74a6eb19e5), [`0988f08c2`](https://github.com/keystonejs/keystone/commit/0988f08c2a88a0da6b85a385caf48ff093e1f9e5)]: - - @keystone-next/fields@11.0.3 - -## 21.0.0 - -### Major Changes - -- [#5947](https://github.com/keystonejs/keystone/pull/5947) [`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replaced the `idField` list configuration option with a more constrained option, `db.idField`, that accepts an object with a `kind` property with a value of `cuid`, `uuid` or `autoincrement`. `db.idField` can be set on either the top level `config` object, or on individual lists. - - The default behaviour has changed from using `autoincrement` to using cuids. To keep the current behaviour, you should set `{ kind: 'autoincrement' }` at `db.idField` in your top level config. - -### Patch Changes - -- Updated dependencies []: - - @keystone-next/fields@11.0.2 - -## 20.0.1 - -### Patch Changes - -- [#5910](https://github.com/keystonejs/keystone/pull/5910) [`50ad1ce6b`](https://github.com/keystonejs/keystone/commit/50ad1ce6be90f5fb2481840dbd01328b6f629432) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed generated list types to allow passing a value directly when a GraphQL list of the value is expected - -* [#5907](https://github.com/keystonejs/keystone/pull/5907) [`0df3734d5`](https://github.com/keystonejs/keystone/commit/0df3734d52a89df30f1d555d003002cb79ad9e9a) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed `lists` and `db.lists` APIs on `KeystoneContext` to have improved types. If you're using the generated `KeystoneListsTypeInfo` type like this: - - ```ts - const lists: KeystoneListsAPI = context.lists; - ``` - - You will have to change it to use `as` like this: - - ```ts - const lists = context.lists as KeystoneListsAPI; - ``` - -- [#5992](https://github.com/keystonejs/keystone/pull/5992) [`543154bc0`](https://github.com/keystonejs/keystone/commit/543154bc081dde33ea29b8a2bff1d3033d538077) Thanks [@timleslie](https://github.com/timleslie)! - Pinned dependency `decimal.js` to `10.2.1` to be consistent with Prisma. - -- Updated dependencies [[`de0a5c19e`](https://github.com/keystonejs/keystone/commit/de0a5c19e656360ea3febc7e0240543c7817253e), [`7a25925c3`](https://github.com/keystonejs/keystone/commit/7a25925c3dc5b2af2cf1209ee949563fb71a4a8c), [`543154bc0`](https://github.com/keystonejs/keystone/commit/543154bc081dde33ea29b8a2bff1d3033d538077), [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c)]: - - @keystone-next/fields@11.0.1 - -## 20.0.0 - -### Major Changes - -- [#5854](https://github.com/keystonejs/keystone/pull/5854) [`7eabb4dee`](https://github.com/keystonejs/keystone/commit/7eabb4dee2552f7baf1e0024d82011b179d418d4) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Replaced the types `FileMode` and `ImageMode` with `AssetMode`. - - Added internal experimental Keystone Cloud integration capabilities for images. - -* [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The core of Keystone has been re-implemented to make implementing fields and new features in Keystone easier. While the observable changes for most users should be minimal, there could be breakage. If you implemented a custom field type, you will need to change it to the new API, see fields in the `@keystone-next/fields` package for inspiration on how to do this. - -- [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replaced `graphql.itemQueryName` with always using the list key as the singular name in GraphQL and renamed `graphql.listQueryName` to `graphql.plural` - -* [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - The `KeystoneContext` type no longer has the `keystone` object or functions to run access control. - -- [#5665](https://github.com/keystonejs/keystone/pull/5665) [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - List level create, update and delete access control is now called for each operation in a many operation rather than on all of the operations as a whole. This means that rather than recieving originalInput as an array with itemIds, your access control functions will always be called with just an itemId and/or originalInput(depending on which access control function it is). If your access control functions already worked with creating/updating/deleting one item, they will continue working (though you may get TypeScript errors if you were previously handling itemIds and originalInput as an array, to fix that, you should stop handling that case). - -* [#5891](https://github.com/keystonejs/keystone/pull/5891) [`97fd5e05d`](https://github.com/keystonejs/keystone/commit/97fd5e05d8681bae86001e6b7e8e3f36ebd639b7) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added support for filtering uniquely by `text` and `integer` fields that have `isUnique: true` like this: - - ```graphql - query { - Post(where: { slug: "something-something-something" }) { - id - title - content - } - } - ``` - -### Minor Changes - -- [#5868](https://github.com/keystonejs/keystone/pull/5868) [`84a5e7f3b`](https://github.com/keystonejs/keystone/commit/84a5e7f3bc3a29ff31d642831e7aaadfc8534ba1) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Added experimental support for the integration with keystone cloud files - -### Patch Changes - -- [#5885](https://github.com/keystonejs/keystone/pull/5885) [`4995c682d`](https://github.com/keystonejs/keystone/commit/4995c682dbdcfac2100de9fab98ba1e0e08cbcc2) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed `BaseGeneratedListTypes` to have `orderBy` be readonly like the generated types - -- Updated dependencies [[`7eabb4dee`](https://github.com/keystonejs/keystone/commit/7eabb4dee2552f7baf1e0024d82011b179d418d4), [`e4c19f808`](https://github.com/keystonejs/keystone/commit/e4c19f8086cc14f7f4a8ef390f1f4e1263004d40), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`881c9ffb7`](https://github.com/keystonejs/keystone/commit/881c9ffb7c5941e9fb214ed955148d8ea567e65f), [`ef14e77ce`](https://github.com/keystonejs/keystone/commit/ef14e77cebc9420db8c7d29dfe61f02140f4a705), [`df7d7b6f6`](https://github.com/keystonejs/keystone/commit/df7d7b6f6f2830573393560f4a1ec35234889947), [`84a5e7f3b`](https://github.com/keystonejs/keystone/commit/84a5e7f3bc3a29ff31d642831e7aaadfc8534ba1), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`a3b07ea16`](https://github.com/keystonejs/keystone/commit/a3b07ea16ffc0f6741c0c0e5e281622a1831e0e7), [`97fd5e05d`](https://github.com/keystonejs/keystone/commit/97fd5e05d8681bae86001e6b7e8e3f36ebd639b7)]: - - @keystone-next/fields@11.0.0 - -## 19.0.0 - -### Major Changes - -- [#5815](https://github.com/keystonejs/keystone/pull/5815) [`b9c828fb0`](https://github.com/keystonejs/keystone/commit/b9c828fb0d6e587976dbd0dc4e87004bce3b2ef7) Thanks [@timleslie](https://github.com/timleslie)! - Fixed the type of `originalInput` in the argument to `defaultValue`. - -* [#5802](https://github.com/keystonejs/keystone/pull/5802) [`7bda87ea7`](https://github.com/keystonejs/keystone/commit/7bda87ea7f11e0faceccc6ab3f715c72b07c129b) Thanks [@timleslie](https://github.com/timleslie)! - Changed `config.session` to access a `SessionStrategy` object, rather than a `() => SessionStrategy` function. You will only need to change your configuration if you're using a customised session strategy. - -- [#5828](https://github.com/keystonejs/keystone/pull/5828) [`4b11c5ea8`](https://github.com/keystonejs/keystone/commit/4b11c5ea87b759c24bdbff9d18443bbc972757c0) Thanks [@timleslie](https://github.com/timleslie)! - Removed the `keystone` argument from the `ExtendGraphqlSchema` type. This will only impact you if you were directly constructing this function. Users of the `graphQLSchemaExtension` function will not be impacted. - -### Patch Changes - -- [#5831](https://github.com/keystonejs/keystone/pull/5831) [`5cc35170f`](https://github.com/keystonejs/keystone/commit/5cc35170fd46118089a2a6f863d782aff989bbf0) Thanks [@timleslie](https://github.com/timleslie)! - Updated the type of `KeystoneContext.gqlNames` to be `GqlNames` rather than just `Record`. - -* [#5767](https://github.com/keystonejs/keystone/pull/5767) [`02af04c03`](https://github.com/keystonejs/keystone/commit/02af04c03c96c26c273cd49eda5b4a132e02a26a) Thanks [@timleslie](https://github.com/timleslie)! - Deprecated the `sortBy` GraphQL filter. Updated the `orderBy` GraphQL filter with an improved API. - - Previously a `User` list's `allUsers` query would have the argument: - - ```graphql - orderBy: String - ``` - - The new API gives it the argument: - - ```graphql - orderBy: [UserOrderByInput!]! = [] - ``` - - where - - ```graphql - input UserOrderByInput { - id: OrderDirection - name: OrderDirection - score: OrderDirection - } - - enum OrderDirection { - asc - desc - } - ``` - - Rather than writing `allUsers(orderBy: "name_ASC")` you now write `allUsers(orderBy: { name: asc })`. You can also now order by multiple fields, e.g. `allUsers(orderBy: [{ score: asc }, { name: asc }])`. Each `UserOrderByInput` must have exactly one key, or else an error will be returned. - -- [#5769](https://github.com/keystonejs/keystone/pull/5769) [`08478b8a7`](https://github.com/keystonejs/keystone/commit/08478b8a7bb9fe5932c7f74f9f6d3af75a0a5394) Thanks [@timleslie](https://github.com/timleslie)! - The GraphQL query `_allMeta { count }` generated for each list has been deprecated in favour of a new query `Count`, which directy returns the count. - - A `User` list would have the following query added to the API: - - ```graphql - usersCount(where: UserWhereInput! = {}): Int - ``` - -* [#5787](https://github.com/keystonejs/keystone/pull/5787) [`bb4f4ac91`](https://github.com/keystonejs/keystone/commit/bb4f4ac91c3ed70393774f744075971453a12aba) Thanks [@timleslie](https://github.com/timleslie)! - Replaced `req, session, createContext` args to `config.ui.pageMiddleware` with a `context` arg. - -* Updated dependencies [[`b9c828fb0`](https://github.com/keystonejs/keystone/commit/b9c828fb0d6e587976dbd0dc4e87004bce3b2ef7), [`a6a444acd`](https://github.com/keystonejs/keystone/commit/a6a444acd23f2590d9812872441cafb5d088c48e), [`59421c039`](https://github.com/keystonejs/keystone/commit/59421c0399368e56e46537c1c687daa27f5912d0), [`0617c81ea`](https://github.com/keystonejs/keystone/commit/0617c81eacc88e40bdd21bacab285d674b171a4a), [`02af04c03`](https://github.com/keystonejs/keystone/commit/02af04c03c96c26c273cd49eda5b4a132e02a26a), [`590bb1fe9`](https://github.com/keystonejs/keystone/commit/590bb1fe9254c2f8feff7e3a0e2e964610116f95), [`19a756496`](https://github.com/keystonejs/keystone/commit/19a7564964d9dcdc94ecdda9c0a0e92c539eb309)]: - - @keystone-next/fields@10.0.0 - - @keystone-next/adapter-prisma-legacy@8.0.0 - -## 18.0.0 - -### Major Changes - -- [#5746](https://github.com/keystonejs/keystone/pull/5746) [`19750d2dc`](https://github.com/keystonejs/keystone/commit/19750d2dc5801cc8d2ffae1f50d1d5ca6ab9407d) Thanks [@timleslie](https://github.com/timleslie)! - Update Node.js dependency to `^12.20 || >= 14.13`. - -### Patch Changes - -- Updated dependencies [[`d40c2a590`](https://github.com/keystonejs/keystone/commit/d40c2a5903f07e5a1e80d116ec4cea00289bbf6a), [`19750d2dc`](https://github.com/keystonejs/keystone/commit/19750d2dc5801cc8d2ffae1f50d1d5ca6ab9407d), [`e2232a553`](https://github.com/keystonejs/keystone/commit/e2232a5537620bd82983ba3f5cff124cec8facab)]: - - @keystone-next/adapter-prisma-legacy@7.0.0 - - @keystone-next/fields@9.0.0 - -## 17.1.0 - -### Minor Changes - -- [#5143](https://github.com/keystonejs/keystone/pull/5143) [`1ef9986dd`](https://github.com/keystonejs/keystone/commit/1ef9986ddc5a4a881a3fc6fae3d1420447174fdb) Thanks [@timleslie](https://github.com/timleslie)! - Added `graphql.cacheHint` configuration for lists and fields. - -### Patch Changes - -- [#5686](https://github.com/keystonejs/keystone/pull/5686) [`62e68c8e5`](https://github.com/keystonejs/keystone/commit/62e68c8e5b4964785a173ab05ff89cba9cc685f2) Thanks [@timleslie](https://github.com/timleslie)! - Reduced the explicit dependence on the internal Keystone object when creating context objects. - -* [#5673](https://github.com/keystonejs/keystone/pull/5673) [`deb7f9504`](https://github.com/keystonejs/keystone/commit/deb7f9504573da67b0cd76d3f53dc0fcceaf1021) Thanks [@timleslie](https://github.com/timleslie)! - Refactored code to parse `config.db`. No functional changes. - -## 17.0.1 - -### Patch Changes - -- [#5509](https://github.com/keystonejs/keystone/pull/5509) [`7e81b52b0`](https://github.com/keystonejs/keystone/commit/7e81b52b0f2240f0c590eb8f6733360cab9fe93a) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Fixed incorrect types which said that field level delete access control exists when it does not - -* [#5518](https://github.com/keystonejs/keystone/pull/5518) [`fddeacf79`](https://github.com/keystonejs/keystone/commit/fddeacf79d25fea15be57d1a4ec16815bcdc4ab5) Thanks [@timleslie](https://github.com/timleslie)! - Updated the list item and db item APIs to include an empty default for `.findMany()` and `.count()`. - -- [#5575](https://github.com/keystonejs/keystone/pull/5575) [`fdebf79cc`](https://github.com/keystonejs/keystone/commit/fdebf79cc3520ffb65979ddac7d61791f4f37324) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused `description` field from `FieldConfig.ui` type. - -* [#5525](https://github.com/keystonejs/keystone/pull/5525) [`9fd7cc62a`](https://github.com/keystonejs/keystone/commit/9fd7cc62a889f8a0f8933040bb16fcc36af7795e) Thanks [@timleslie](https://github.com/timleslie)! - Moved field-related types into their own internal module. - -* Updated dependencies [[`b7aeb232d`](https://github.com/keystonejs/keystone/commit/b7aeb232db43b32cae0bca3fcb74479d6834c587), [`f7d4c9b9f`](https://github.com/keystonejs/keystone/commit/f7d4c9b9f06cc3090b59d4b29e0907e9f3d1faee), [`8577eb3ba`](https://github.com/keystonejs/keystone/commit/8577eb3baafe9cd61c48d89aca9eff252765e5a6), [`05d4883ee`](https://github.com/keystonejs/keystone/commit/05d4883ee19bcfdfcbff7f80693a3fa85cf81aaa), [`a0c5aa307`](https://github.com/keystonejs/keystone/commit/a0c5aa30771d187253d0cfe24b4b686e136136cc), [`3e33cd3ff`](https://github.com/keystonejs/keystone/commit/3e33cd3ff46f824ec3516e5810a7e5027b332a5a), [`49dd46843`](https://github.com/keystonejs/keystone/commit/49dd468435a96c537f5649aa2fd9e21103da40e1)]: - - @keystone-next/fields@8.0.0 - - @keystone-next/adapter-prisma-legacy@6.0.1 - -## 17.0.0 - -### Major Changes - -- [#5467](https://github.com/keystonejs/keystone/pull/5467) [`7498fcabb`](https://github.com/keystonejs/keystone/commit/7498fcabba3ef6b411dd3bf67a20821702442ebc) Thanks [@timleslie](https://github.com/timleslie)! - Removed the deprecated `context.executeGraphQL`. Identical functionality is available via `context.graphql.raw`. - -* [#5397](https://github.com/keystonejs/keystone/pull/5397) [`a5627304b`](https://github.com/keystonejs/keystone/commit/a5627304b7921a0f1484d6d08330115d0edbb45b) Thanks [@bladey](https://github.com/bladey)! - Updated Node engine version to 12.x due to 10.x reaching EOL on 2021-04-30. - -### Minor Changes - -- [#5451](https://github.com/keystonejs/keystone/pull/5451) [`9e060fe83`](https://github.com/keystonejs/keystone/commit/9e060fe83459269bc5d257f31a23c164d2283624) Thanks [@JedWatson](https://github.com/JedWatson)! - With the goal of making the Lists API (i.e `context.lists.{List}`) more intuitive to use, the `resolveFields` option has been deprecated in favor of two new methods: - - (1) You can specify a string of fields to return with the new `query` option, when you want to query for resolved field values (including querying relationships and virtual fields). This replaces the `resolveFields: false` use case. - - For example, to query a Post you would now write: - - ```js - const [post] = await context.lists.Post.findMany({ - where: { slug }, - query: ` - title - content - image { - src - width - height - }`, - }); - ``` - - (2) Alternatively, there is a new set of APIs on `context.db.lists.{List}` which will return the unresolved item data from the database (but with read hooks applied), which can then be referenced directly or returned from a custom mutation or query in the GraphQL API to be handled by the Field resolvers. This replaces the `resolveFields: boolean` use case. - - For example, to query for the raw data stored in the database, you would write: - - ```js - const [post] = await context.db.lists.Post.findMany({ - where: { slug }, - }); - ``` - -* [#5396](https://github.com/keystonejs/keystone/pull/5396) [`be60812f2`](https://github.com/keystonejs/keystone/commit/be60812f29d7768ce65a5f5e8c40597d4742c5d7) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Added types for new images functionality in keystone. - -### Patch Changes - -- [#5478](https://github.com/keystonejs/keystone/pull/5478) [`11f5bb631`](https://github.com/keystonejs/keystone/commit/11f5bb6316b90ec603aa034db1b9259c911204ed) Thanks [@timleslie](https://github.com/timleslie)! - Improved types for `BaseKeystoneList`. - -* [#5442](https://github.com/keystonejs/keystone/pull/5442) [`1d85d7ff4`](https://github.com/keystonejs/keystone/commit/1d85d7ff4e8d7795d6e0f82484cf7108d11925db) Thanks [@timleslie](https://github.com/timleslie)! - Updated type definitions to be more consistent and correct. - -- [#5466](https://github.com/keystonejs/keystone/pull/5466) [`0e74d8123`](https://github.com/keystonejs/keystone/commit/0e74d81238d5d00cc3eb968c95c02f25cb3a5a78) Thanks [@timleslie](https://github.com/timleslie)! - Improved the `BaseKeystone` type to be more correct. - -- Updated dependencies [[`637ae05d3`](https://github.com/keystonejs/keystone/commit/637ae05d3f8a138902c2d03c5b342cb93c440767), [`d0adec53f`](https://github.com/keystonejs/keystone/commit/d0adec53ff20c2246dfe955b449b7c6e1afe96fb), [`c7aecec3c`](https://github.com/keystonejs/keystone/commit/c7aecec3c768eec742e0ce9c5506331e902e5124), [`f059f6349`](https://github.com/keystonejs/keystone/commit/f059f6349bee3dce8bbf4a0584b235e97872851c), [`11f5bb631`](https://github.com/keystonejs/keystone/commit/11f5bb6316b90ec603aa034db1b9259c911204ed), [`8ab2c9bb6`](https://github.com/keystonejs/keystone/commit/8ab2c9bb6633c2f85844e658f534582c30a39a57), [`637ae05d3`](https://github.com/keystonejs/keystone/commit/637ae05d3f8a138902c2d03c5b342cb93c440767), [`fe55e9289`](https://github.com/keystonejs/keystone/commit/fe55e9289b898bdcb937eb5e981dba2bb58a672f), [`a5627304b`](https://github.com/keystonejs/keystone/commit/a5627304b7921a0f1484d6d08330115d0edbb45b), [`1d85d7ff4`](https://github.com/keystonejs/keystone/commit/1d85d7ff4e8d7795d6e0f82484cf7108d11925db), [`2bef01aaa`](https://github.com/keystonejs/keystone/commit/2bef01aaacd32eb746353bde11dd5e37c67fb43e), [`0e74d8123`](https://github.com/keystonejs/keystone/commit/0e74d81238d5d00cc3eb968c95c02f25cb3a5a78), [`be60812f2`](https://github.com/keystonejs/keystone/commit/be60812f29d7768ce65a5f5e8c40597d4742c5d7), [`d7e8cad4f`](https://github.com/keystonejs/keystone/commit/d7e8cad4fca5d8ffefa235c2ff30ec8e2e0d6276), [`ecf07393a`](https://github.com/keystonejs/keystone/commit/ecf07393a19714f1686772bd082de7d229065aa2), [`89b869e8d`](https://github.com/keystonejs/keystone/commit/89b869e8d492151449f2146108767a7e5e5ecdfa), [`58a793988`](https://github.com/keystonejs/keystone/commit/58a7939888ec84d0f089d77ca1ce9d94ef0d9a85)]: - - @keystone-next/fields@7.0.0 - - @keystone-next/adapter-prisma-legacy@6.0.0 - -## 16.0.0 - -### Major Changes - -- [#5266](https://github.com/keystonejs/keystone/pull/5266) [`c28e765d1`](https://github.com/keystonejs/keystone/commit/c28e765d12655f802e324b82529fcf571d88c0c6) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `migrationAction` argument to `createSystem` and require that the PrismaClient is passed to `createSystem` to be able to connect to the database. - -* [#5256](https://github.com/keystonejs/keystone/pull/5256) [`399e6db39`](https://github.com/keystonejs/keystone/commit/399e6db39c51cf9e8bbf3dde0887e5bf55dd1c4d) Thanks [@timleslie](https://github.com/timleslie)! - Removed support for the `knex` and `mongoose` database adapters. We now only support `prisma_postgresql` and `prisma_sqlite`. - -### Minor Changes - -- [#5368](https://github.com/keystonejs/keystone/pull/5368) [`b40016301`](https://github.com/keystonejs/keystone/commit/b40016301dab71630068cc86c04828c5ee1683e8) Thanks [@timleslie](https://github.com/timleslie)! - The config option `db.adapter` is now deprecated. It has been repaced with `db.provider` which can take the values `postgresql` or `sqlite`. - -* [#5283](https://github.com/keystonejs/keystone/pull/5283) [`192393d0d`](https://github.com/keystonejs/keystone/commit/192393d0df67e123a694a42dd3f95ffa6d40042b) Thanks [@timleslie](https://github.com/timleslie)! - The flag `{ experimental: { prismaSqlite: true } }` is no longer required to use the SQLite adapter. - -- [#5341](https://github.com/keystonejs/keystone/pull/5341) [`1886b4323`](https://github.com/keystonejs/keystone/commit/1886b43235e50bd2e070350d258f0a3145c19bbc) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `generateNextGraphqlAPI` and `generateNodeAPI` experimental options - -## 15.0.1 - -### Patch Changes - -- [#5257](https://github.com/keystonejs/keystone/pull/5257) [`34dd809ee`](https://github.com/keystonejs/keystone/commit/34dd809eef2368bba1e50ed613b36c5dac7262d1) Thanks [@timleslie](https://github.com/timleslie)! - Updated type `GraphQLExecutionArguments.variables` to be optional. - -## 15.0.0 - -### Major Changes - -- [#5155](https://github.com/keystonejs/keystone/pull/5155) [`215aed387`](https://github.com/keystonejs/keystone/commit/215aed387d35e9d4c896fe76991b12b54789cc55) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Removed `createOnly` migration mode - -* [#5163](https://github.com/keystonejs/keystone/pull/5163) [`b37cbffc8`](https://github.com/keystonejs/keystone/commit/b37cbffc886a4317793a97b7a8afd95639f59ce0) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replaced `MigrationMode` type with `MigrationAction` that `createSystem` and `createKeystone` now accept. - -### Minor Changes - -- [#3946](https://github.com/keystonejs/keystone/pull/3946) [`8e9b04ecd`](https://github.com/keystonejs/keystone/commit/8e9b04ecd07d9c5d0e6aead4705e7a655498ae05) Thanks [@timleslie](https://github.com/timleslie)! - Added experimental support for Prisma + SQLite as a database adapter. - -* [#5102](https://github.com/keystonejs/keystone/pull/5102) [`714bdadce`](https://github.com/keystonejs/keystone/commit/714bdadce8c87a15cf3a296b44a31b9b9ca95e9d) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `none-skip-client-generation` migrationMode - -- [#5087](https://github.com/keystonejs/keystone/pull/5087) [`56e5fe10b`](https://github.com/keystonejs/keystone/commit/56e5fe10bc89877be7d7e3013e53012b4d82b648) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `MigrationMode` type - -* [#5163](https://github.com/keystonejs/keystone/pull/5163) [`b37cbffc8`](https://github.com/keystonejs/keystone/commit/b37cbffc886a4317793a97b7a8afd95639f59ce0) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Added `db.useMigrations` option to replace using `keystone-next dev` and `keystone-next prototype` depending on what kind of migration strategy you want to use. If you were previously using `keystone-next dev`, you should set `db.useMigrations` to true in your config and continue using `keystone-next dev`. If you were previously using `keystone-next prototype`, you should now use `keystone-next dev`. - -- [#5084](https://github.com/keystonejs/keystone/pull/5084) [`40d4fff5d`](https://github.com/keystonejs/keystone/commit/40d4fff5d63850cbd513c80bcb5e551e5782dc4b) Thanks [@timleslie](https://github.com/timleslie)! - Updated `context.sudo()` to provide access to all operations, including those excluded by `{ access: false }` in the public schema. - -* [#4912](https://github.com/keystonejs/keystone/pull/4912) [`d31acf61b`](https://github.com/keystonejs/keystone/commit/d31acf61bcca96ac059d4ba2e78955513a6a0f91) Thanks [@timleslie](https://github.com/timleslie)! - Added a `config.graphql.apolloConfig` option to allow developers to configure the `ApolloServer` object provided by Keystone. - -### Patch Changes - -- [#5104](https://github.com/keystonejs/keystone/pull/5104) [`b84abebb6`](https://github.com/keystonejs/keystone/commit/b84abebb6c817172d04f338befa45b3573af55d6) Thanks [@timleslie](https://github.com/timleslie)! - Fixed type of `defaultValue` for fields. - -* [#5150](https://github.com/keystonejs/keystone/pull/5150) [`3a9d20ce1`](https://github.com/keystonejs/keystone/commit/3a9d20ce11463e7f73f6b6325375cdcee17d63ed) Thanks [@timleslie](https://github.com/timleslie)! - Applied eslint `import/order` rule. - -## 14.0.1 - -### Patch Changes - -- [`9b202b31a`](https://github.com/keystonejs/keystone/commit/9b202b31a7d4944b709fe0ce58d6ca7ec1523a02) [#5033](https://github.com/keystonejs/keystone/pull/5033) Thanks [@rohan-deshpande](https://github.com/rohan-deshpande)! - Added `experimental` config namespace and `enableNextJsGraphqlApiEndpoint` property to support the GraphQL API being served from a Next.js API route rather than Express - -## 14.0.0 - -### Major Changes - -- [`24e0ef5b6`](https://github.com/keystonejs/keystone/commit/24e0ef5b6bd93c105fdef2caea6b862ff1dfd6f3) [#4945](https://github.com/keystonejs/keystone/pull/4945) Thanks [@timleslie](https://github.com/timleslie)! - Removed the `context` argument from `KeystoneContext.graphql.raw` and `KeystoneContext.graphql.run`. - -* [`0f86e99bb`](https://github.com/keystonejs/keystone/commit/0f86e99bb3aa15f691ab7ff79e5a9ae3d1ac464e) [#4839](https://github.com/keystonejs/keystone/pull/4839) Thanks [@timleslie](https://github.com/timleslie)! - Removed `context.graphql.createContext` from `KeystoneContext`. - -### Minor Changes - -- [`2655c0b1b`](https://github.com/keystonejs/keystone/commit/2655c0b1bf714d80d46e1ff4e414b4bce474c23d) [#4866](https://github.com/keystonejs/keystone/pull/4866) Thanks [@timleslie](https://github.com/timleslie)! - Added a `config.ui.isDisabled` option to completely disable the Admin UI. - -* [`bea9008f8`](https://github.com/keystonejs/keystone/commit/bea9008f82efea7fcf1cb547f3841915cd4689cc) [#4944](https://github.com/keystonejs/keystone/pull/4944) Thanks [@timleslie](https://github.com/timleslie)! - Deprecated `KeystoneContext.keystone`. - -- [`5d565ea57`](https://github.com/keystonejs/keystone/commit/5d565ea57853713458329b823bde7a38776b02bc) [#4892](https://github.com/keystonejs/keystone/pull/4892) Thanks [@timleslie](https://github.com/timleslie)! - Added support for configuring the field to use for `search` filtering via the `db: { searchField }` list config option. - -### Patch Changes - -- [`f4e4498c6`](https://github.com/keystonejs/keystone/commit/f4e4498c6e4c7301288f23048f4aad3c492985c7) [#5018](https://github.com/keystonejs/keystone/pull/5018) Thanks [@bladey](https://github.com/bladey)! - Updated legacy packages to the @keystone-next namespace. - -* [`687fd5ef0`](https://github.com/keystonejs/keystone/commit/687fd5ef0f798da996f970af1591411f9cfe0985) [#4835](https://github.com/keystonejs/keystone/pull/4835) Thanks [@timleslie](https://github.com/timleslie)! - Removed the unused `connect` and `disconnect` properties of `SessionStrategy`. - -- [`29e787983`](https://github.com/keystonejs/keystone/commit/29e787983bdc26b147d6b5f476e70768bbc5318c) [#4905](https://github.com/keystonejs/keystone/pull/4905) Thanks [@gautamsi](https://github.com/gautamsi)! - Fixed typing for `afterDelete` or `beforeDelete` hooks. Also added type for `updatedItem` in the `afterChange` or `beforeChange` hook - -* [`45ea93421`](https://github.com/keystonejs/keystone/commit/45ea93421f9a6cf9b7ccbd983e0c9cbd687ff6af) [#4810](https://github.com/keystonejs/keystone/pull/4810) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Replaced usage of `React.ComponentType` with more accurate types that do not automatically add `children` prop. - -- [`6c949dbf2`](https://github.com/keystonejs/keystone/commit/6c949dbf262350e280072d82cd48fdd31ff5ba6d) [#4942](https://github.com/keystonejs/keystone/pull/4942) Thanks [@timleslie](https://github.com/timleslie)! - Refactored `KeystoneContext` definition to make documentation easier. No functional changes. - -## 13.0.0 - -### Major Changes - -- [`e29ae2749`](https://github.com/keystonejs/keystone/commit/e29ae2749321c103dd494eba6778ee4137bb2aa3) [#4818](https://github.com/keystonejs/keystone/pull/4818) Thanks [@timleslie](https://github.com/timleslie)! - Added `context.exitSudo()` and `context.withSession(session)` methods. Removed `context.createContext()`. - -* [`8d0be8a89`](https://github.com/keystonejs/keystone/commit/8d0be8a89e2d9b89826365f81f47b8d8863b93d0) [#4815](https://github.com/keystonejs/keystone/pull/4815) Thanks [@timleslie](https://github.com/timleslie)! - Added a `.sudo()` method to `context` objects, which is equivalent to the common operation `context.createContext({ skipAccessControl: true })`. - -### Patch Changes - -- [`208722a42`](https://github.com/keystonejs/keystone/commit/208722a4234434e116846756bab18f7e11674ec8) [#4784](https://github.com/keystonejs/keystone/pull/4784) Thanks [@timleslie](https://github.com/timleslie)! - Reordered type definitions for consistency with docs. Remove unused type `ListAdminUIConfig.path`. - -* [`ad75e3d61`](https://github.com/keystonejs/keystone/commit/ad75e3d61c73ba1239fd21b58f175aac01d9f302) [#4798](https://github.com/keystonejs/keystone/pull/4798) Thanks [@timleslie](https://github.com/timleslie)! - Removed unused type `config.ui.path`. - -- [`954350389`](https://github.com/keystonejs/keystone/commit/9543503894c3e78a9b69a75cbfb3ca6b85ae34e8) [#4778](https://github.com/keystonejs/keystone/pull/4778) Thanks [@timleslie](https://github.com/timleslie)! - Removed the unused `plural`, `singular`, `label`, `db`, and `graphql.cacheHint` list config options. - -## 12.0.1 - -### Patch Changes - -- [`6ecd2a766`](https://github.com/keystonejs/keystone/commit/6ecd2a766c868d46f84291bc1611eadef79e6100) [#4772](https://github.com/keystonejs/keystone/pull/4772) Thanks [@timleslie](https://github.com/timleslie)! - Removed `config.db.dropDatabase` for `prisma_postgresql` and `config.db.knexOptions` for `knex` as they were unused. - -* [`777981069`](https://github.com/keystonejs/keystone/commit/7779810691c4154e1344ced4fb94c5bb9524a71f) [#4765](https://github.com/keystonejs/keystone/pull/4765) Thanks [@timleslie](https://github.com/timleslie)! - Reorganised package internals to allow for easier documentation. - -- [`4d808eaa5`](https://github.com/keystonejs/keystone/commit/4d808eaa5aa1593ad1e54000d80f674f7c4d12bd) [#4766](https://github.com/keystonejs/keystone/pull/4766) Thanks [@timleslie](https://github.com/timleslie)! - Removed `config.db.provider` option, which did not have any meaningful, viable value. - -## 12.0.0 - -### Major Changes - -- [`1744c5f05`](https://github.com/keystonejs/keystone/commit/1744c5f05c9a13e680aaa1ed151f23f1d015ed9c) [#4763](https://github.com/keystonejs/keystone/pull/4763) Thanks [@timleslie](https://github.com/timleslie)! - Removed the type `SchemaConfig`. Updated the `keystone` parameter of `ExtendGraphqlSchema` to be `BaseKeystone`. - -* [`5be53ddc3`](https://github.com/keystonejs/keystone/commit/5be53ddc39be1415d56e2fa5e7898ab9edf468d5) [#4762](https://github.com/keystonejs/keystone/pull/4762) Thanks [@timleslie](https://github.com/timleslie)! - Renamed the type `KeystoneAdminUIConfig` to `AdminUIConfig`. - -### Minor Changes - -- [`fd0dff3fd`](https://github.com/keystonejs/keystone/commit/fd0dff3fdfcbe20b2884357a6e1b20f1b7307652) [#4669](https://github.com/keystonejs/keystone/pull/4669) Thanks [@MurzNN](https://github.com/MurzNN)! - Added the ability to set the server port number via `config.server.port`. - -### Patch Changes - -- [`d9675553b`](https://github.com/keystonejs/keystone/commit/d9675553b33f39e2c7ada7eb6555d16e9fccb37e) [#4761](https://github.com/keystonejs/keystone/pull/4761) Thanks [@timleslie](https://github.com/timleslie)! - Remove unused configuration option `config.graphql.path` from the `KeystoneConfig` type. - -* [`096927a68`](https://github.com/keystonejs/keystone/commit/096927a6813a23030988ba8b64b2e8452f571a33) [#4756](https://github.com/keystonejs/keystone/pull/4756) Thanks [@timleslie](https://github.com/timleslie)! - Added correct types for `config.server.cors`. - -## 11.0.2 - -### Patch Changes - -- [`94fbb45f1`](https://github.com/keystonejs/keystone/commit/94fbb45f1920781423f6a8e489e812b74a260099) [#4728](https://github.com/keystonejs/keystone/pull/4728) Thanks [@timleslie](https://github.com/timleslie)! - Added new CLI options to support migrations in the Prisma adapter: `prototype`, `reset`, `generate`, and `deploy`. - -* [`588be9ea1`](https://github.com/keystonejs/keystone/commit/588be9ea16ab5fb6e74f844b917ca8aeb91a9ac9) [#3222](https://github.com/keystonejs/keystone/pull/3222) Thanks [@timleslie](https://github.com/timleslie)! - Removed support for multiple database adapters in a single `Keystone` system. The `adapters` and `defaultAdapter` config options were removed from the `Keystone()` constructor. If you were accessing the adapter object via `keystone.adapters.KnexAdapter` or `keystone.adapters.MongooseAdapter` you should now simply access `keystone.adapter`. - -## 11.0.1 - -### Patch Changes - -- [`a96c24cca`](https://github.com/keystonejs/keystone/commit/a96c24ccab8dadc9e8f0131fe6509abd64a776f5) [#4696](https://github.com/keystonejs/keystone/pull/4696) Thanks [@timleslie](https://github.com/timleslie)! - Marked `db.enableLogging` as optional. - -## 11.0.0 - -### Major Changes - -- [`0d9404768`](https://github.com/keystonejs/keystone/commit/0d94047686d1bb1308fd8c47b769c999390d8f6d) [#4659](https://github.com/keystonejs/keystone/pull/4659) Thanks [@timleslie](https://github.com/timleslie)! - Removed `system` argument from `config.ui.getAdditionalFiles`. - -* [`7ffd2ebb4`](https://github.com/keystonejs/keystone/commit/7ffd2ebb42dfaf12e23ba166b44ec4db60d9824b) [#4662](https://github.com/keystonejs/keystone/pull/4662) Thanks [@timleslie](https://github.com/timleslie)! - Remove type `KeystoneSystem`. - -### Minor Changes - -- [`4768fbf83`](https://github.com/keystonejs/keystone/commit/4768fbf831ffff648e540c479a1954ae40e05aaa) [#4654](https://github.com/keystonejs/keystone/pull/4654) Thanks [@timleslie](https://github.com/timleslie)! - Added an `args` paramter to `Keystone.connect(args)`, which is passed through as the second argument to the config function `onConnect(keystone, args)`. - -### Patch Changes - -- [`6ea4ff3cf`](https://github.com/keystonejs/keystone/commit/6ea4ff3cf77d5d2278bf4f0415d11aa7399a0490) [#4660](https://github.com/keystonejs/keystone/pull/4660) Thanks [@timleslie](https://github.com/timleslie)! - Converted `@keystonejs/test-utils` to TypeScript. - -## 10.0.0 - -### Major Changes - -- [`24ecd72e5`](https://github.com/keystonejs/keystone/commit/24ecd72e54eee12442c7c1d0533936a9ad86620a) [#4604](https://github.com/keystonejs/keystone/pull/4604) Thanks [@timleslie](https://github.com/timleslie)! - Renamed `SerializedAdminMeta` to `AdminMetaRootVal`. - -## 9.0.0 - -### Major Changes - -- [`89f7d4599`](https://github.com/keystonejs/keystone/commit/89f7d459906072940da1355c38815d1b3ef49368) [#4586](https://github.com/keystonejs/keystone/pull/4586) Thanks [@timleslie](https://github.com/timleslie)! - Removed `adminMeta` from `KeystoneSystem`. `getAdminMetaSchema` now takes a `BaseKeystone` argument `keystone` rather than `adminMeta`. - -### Patch Changes - -- [`933c78a1e`](https://github.com/keystonejs/keystone/commit/933c78a1edc070b63f7720f64c15421ba28bdde5) [#4587](https://github.com/keystonejs/keystone/pull/4587) Thanks [@timleslie](https://github.com/timleslie)! - Use `keystone.getTypeDefs` and `keystone.getResolvers` when creating the graphQL schema. - -## 8.0.0 - -### Major Changes - -- [`075ef1628`](https://github.com/keystonejs/keystone/commit/075ef16281a89c8291f90275adca98f042cc54da) [#4547](https://github.com/keystonejs/keystone/pull/4547) Thanks [@timleslie](https://github.com/timleslie)! - Removed `allViews` from `KeystoneSystem` type. `createAdminMeta` no longer returns `allViews`. - -## 7.0.0 - -### Major Changes - -- [`661104764`](https://github.com/keystonejs/keystone/commit/66110476491953af2134cd3cd4e3ef7c361ac5da) [#4509](https://github.com/keystonejs/keystone/pull/4509) Thanks [@timleslie](https://github.com/timleslie)! - Replaced `KeystoneAdminUIConfig.system` with `KeystoneAdminUIConfig.createConfig` to reduce API surface area. - -* [`481e456ac`](https://github.com/keystonejs/keystone/commit/481e456ac4158207436ddd9be18fdca0f27b6409) [#4533](https://github.com/keystonejs/keystone/pull/4533) Thanks [@timleslie](https://github.com/timleslie)! - Renamed to `SessionImplementation.createContext` to `createSessionContext`. - -### Minor Changes - -- [`6d09df338`](https://github.com/keystonejs/keystone/commit/6d09df3381d1682b8002d52ed1696b661fdff035) [#4523](https://github.com/keystonejs/keystone/pull/4523) Thanks [@timleslie](https://github.com/timleslie)! - Added support for all database adapter configuration options. - -* [`2308e5efc`](https://github.com/keystonejs/keystone/commit/2308e5efc7c6893c87652411496b15a8124f6e05) [#4527](https://github.com/keystonejs/keystone/pull/4527) Thanks [@timleslie](https://github.com/timleslie)! - Added an optional `req` property to the `KeystoneContext` type. - -- [`f2c7675fb`](https://github.com/keystonejs/keystone/commit/f2c7675fb51ed41e6df8248c76b9322d6de5ee0d) [#4528](https://github.com/keystonejs/keystone/pull/4528) Thanks [@timleslie](https://github.com/timleslie)! - `KeystoneAdminUIConfig.isAccessAllowed` now takes a full `KeystoneContext` object, rather than just `{ session }`. - -### Patch Changes - -- [`39639b203`](https://github.com/keystonejs/keystone/commit/39639b2031bb749067ef537ea47e5d93a8bb89da) [#4529](https://github.com/keystonejs/keystone/pull/4529) Thanks [@timleslie](https://github.com/timleslie)! - Added missing attributes `path`, `viewsIndex`, and `customViews` to `FieldMeta`. - -## 6.0.0 - -### Major Changes - -- [`dc58df5c8`](https://github.com/keystonejs/keystone/commit/dc58df5c87d694ce94b7d1c2b20d4976176dbd13) [#4493](https://github.com/keystonejs/keystone/pull/4493) Thanks [@timleslie](https://github.com/timleslie)! - Renamed `SerializedFieldMeta.views` to `SerializedFieldMeta.viewsIndex` to makes it clear that this is the index, not the views object itself. - -* [`a5d7b264a`](https://github.com/keystonejs/keystone/commit/a5d7b264ad3e5590e335758881d22f7f296203c9) [#4473](https://github.com/keystonejs/keystone/pull/4473) Thanks [@timleslie](https://github.com/timleslie)! - Added a `resolveFields: false | string` argument to the items API methods. - - This function controls the return type of the methods on the items API. - If a `string` value is provided, it will be interpreted as a graphQL field specification fragment. - The method will construct and run a graphQL operation and return the values specified by `resolveFields`. - The default value for `resolveFields` is `id`. - - For example, to find the title and author name for all posts in our system we would run: - - ```js - const posts = await context.lists.Post.findMany({ resolveFields: 'id title author { id name }' }); - ``` - - If `resolveFields: false` is provided, this indicates to the method that no field-resolving is desired. - Instead, the method will return the result of the item-level resolver for the corresponding operation. - These objects are the internal data representation of the items in the system which would normally be passed to the field resolvers. - - This flag is most useful in two specific scenarios. Firstly, if you need to inspect data which isn't generally available as a graphQL field, such as password hash values. - - Secondly, if you are writing a custom mutation which returns a list item type, such as `Post`. For example - - ```js - export const extendGraphqlSchema = graphQLSchemaExtension({ - typeDefs: ` - type Mutation { - topPost(userId: ID): Post - } - `, - resolvers: { - Mutation: { - topPost: (root, { userId }: { userId: string }, context) => { - return context.lists.Post.findMany({ - where: { user: { id: userId } }, - first: 1, - sortBy: ['stars_DESC'], - resolveFields: false, - }); - }, - }, - }, - }); - ``` - -- [`b7a4b997b`](https://github.com/keystonejs/keystone/commit/b7a4b997bae5b2269bea0ad94ca771e63c26ab95) [#4501](https://github.com/keystonejs/keystone/pull/4501) Thanks [@timleslie](https://github.com/timleslie)! - Removed `sessionImplementation` from `KeystoneSystem` and instead pass it explicitly where needed. - -* [`ca34424d5`](https://github.com/keystonejs/keystone/commit/ca34424d58e58cc4a657828b1362978be8ee4f62) [#4494](https://github.com/keystonejs/keystone/pull/4494) Thanks [@timleslie](https://github.com/timleslie)! - Renamed `KeystoneSystem.views` to `KeystoneSystem.allViews`. - -- [`57092b7c1`](https://github.com/keystonejs/keystone/commit/57092b7c13845fffd1f3767bb609d203afbc2776) [#4465](https://github.com/keystonejs/keystone/pull/4465) Thanks [@timleslie](https://github.com/timleslie)! - Updated `SessionStrategy.start` and `SessionStrategy.end` to be required attributes. - -* [`b21b62ed5`](https://github.com/keystonejs/keystone/commit/b21b62ed59fcd83ef2fc89587544b9d64522ba27) [#4477](https://github.com/keystonejs/keystone/pull/4477) Thanks [@timleslie](https://github.com/timleslie)! - Changed the type `SessionContext` to have parameters `startSession` and `endSession` as required. This type also takes a type parameter `T` which corresponds to the data type of the `data` argument to `startSession`. - -- [`2da044a0c`](https://github.com/keystonejs/keystone/commit/2da044a0cb22dc16a54b7b5555c2b2678e8d4cab) [#4482](https://github.com/keystonejs/keystone/pull/4482) Thanks [@timleslie](https://github.com/timleslie)! - Removed `config` from type `KeystoneSystem`. The config object is now explicitly passed around where needed to make it clear which code is consuming it. - Type `KeystoneAdminUIConfig.getAdditionalFiles` now takes a `config` parameter. - -* [`3f3c65ab2`](https://github.com/keystonejs/keystone/commit/3f3c65ab2d206ef1c72f17259e73fb24a79f0a9b) [#4458](https://github.com/keystonejs/keystone/pull/4458) Thanks [@timleslie](https://github.com/timleslie)! - Removed `createContextFromRequest` and `createSessionContext` from `KeystoneSystem` and replaced them with `sessionImplementation`, which provides the same core functionality. - -- [`fe52e25e0`](https://github.com/keystonejs/keystone/commit/fe52e25e04db121adbc6a0ce3bd0dbe1c7270180) [#4492](https://github.com/keystonejs/keystone/pull/4492) Thanks [@timleslie](https://github.com/timleslie)! - Replaced the `system` argument on `SessionStrategy.start`, '.end`, and`.get`with`createContext`. - -### Minor Changes - -- [`68d361d25`](https://github.com/keystonejs/keystone/commit/68d361d2596e8811caf00390c60341ef0c233c7b) [#4467](https://github.com/keystonejs/keystone/pull/4467) Thanks [@timleslie](https://github.com/timleslie)! - Added type for `BaseKeystone.createApolloServer()`. - -### Patch Changes - -- [`341ee2b4b`](https://github.com/keystonejs/keystone/commit/341ee2b4b7eab89f296146ff9e14ce53233235f6) [#4475](https://github.com/keystonejs/keystone/pull/4475) Thanks [@timleslie](https://github.com/timleslie)! - Use `SerializedAdminMeta` in `createGraphQLSchema` and `FieldType<...>.getAdminMeta?`. - -* [`4b019b8cf`](https://github.com/keystonejs/keystone/commit/4b019b8cfcb7bea6f800609da5d07e8c8abfc80a) [#4478](https://github.com/keystonejs/keystone/pull/4478) Thanks [@timleslie](https://github.com/timleslie)! - Refactored types to isolate base keystone type definitions. - -- [`bf22d9f2a`](https://github.com/keystonejs/keystone/commit/bf22d9f2afe537111b95571b86d4fd2759eb6a98) [#4498](https://github.com/keystonejs/keystone/pull/4498) Thanks [@timleslie](https://github.com/timleslie)! - Removed usage of `keystone as any`. - -* [`1c12b8204`](https://github.com/keystonejs/keystone/commit/1c12b8204f8238997ddaf7337c44cf26ebea9ba4) [#4424](https://github.com/keystonejs/keystone/pull/4424) Thanks [@timleslie](https://github.com/timleslie)! - Added more specific types for `listQuery`, `listQueryMeta`, and the items API. - -## 5.0.0 - -### Major Changes - -- [`803626e88`](https://github.com/keystonejs/keystone/commit/803626e8854f9b7d293bd1829398d25a6692154a) [#4440](https://github.com/keystonejs/keystone/pull/4440) Thanks [@JedWatson](https://github.com/JedWatson)! - Changed the `config.db.onConnect` argument to accept a `KeystoneContext` instance, created with `{ skipAccessControl: true }`, rather than a `BaseKeystone` instance. - - Added database APIs `{ knex?, mongoose?, prisma? }" to`KeystoneContext`. - -### Minor Changes - -- [`b6498d9f1`](https://github.com/keystonejs/keystone/commit/b6498d9f1341648742f2db78fec53b851b36dddd) [#4427](https://github.com/keystonejs/keystone/pull/4427) Thanks [@timleslie](https://github.com/timleslie)! - Added a `BaseKeystone` type to replace usage of `any` in all instances. - -### Patch Changes - -- [`d36e580cc`](https://github.com/keystonejs/keystone/commit/d36e580cc21e4b77a1bd0615c96c0793b9c5dac5) [#4426](https://github.com/keystonejs/keystone/pull/4426) Thanks [@timleslie](https://github.com/timleslie)! - Used the `KeystoneContext` type rather than `any` where appropriate. - -## 4.1.1 - -### Patch Changes - -- [`6cd469e29`](https://github.com/keystonejs/keystone/commit/6cd469e29682ff41a515ed76919efc2bfe0c7567) [#4414](https://github.com/keystonejs/keystone/pull/4414) Thanks [@JedWatson](https://github.com/JedWatson)! - Typed keystone context - -## 4.1.0 - -### Minor Changes - -- [`add3f67e3`](https://github.com/keystonejs/keystone/commit/add3f67e379caebbcf0880b4ce82cf6a1e89020b) [#4316](https://github.com/keystonejs/keystone/pull/4316) Thanks [@timleslie](https://github.com/timleslie)! - Added a `config.server.cors` option to allow configuration of the cors middleware. Updated the Apollo server middleware to not override cors options. - -* [`2d5f78207`](https://github.com/keystonejs/keystone/commit/2d5f78207103caaf8f86a4dd05b7e4b0a4795213) [#4302](https://github.com/keystonejs/keystone/pull/4302) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Add optional `allowedExportsOnCustomViews` export to field views - -## 4.0.0 - -### Major Changes - -- [`11777cddb`](https://github.com/keystonejs/keystone/commit/11777cddba45b28a9e17a3149b792db121322b46) [#4263](https://github.com/keystonejs/keystone/pull/4263) Thanks [@timleslie](https://github.com/timleslie)! - Renamed the type `Keystone` to `KeystoneSystem` to avoid confusion with the core `Keystone` class. - -* [`cc987d078`](https://github.com/keystonejs/keystone/commit/cc987d078653fd9e686069f9f885f1269b64a882) [#4269](https://github.com/keystonejs/keystone/pull/4269) Thanks [@timleslie](https://github.com/timleslie)! - Renamed `keystone` argument of `KeystoneAdminUIConfig.getAdditionalFiles()` and `KeystoneAdminUIConfig.pageMiddleware()` to `system`. - Renamed `keystone` argument of `SessionStrategy.start`, `SessionStrategy.end` and `SessionStrategy.get` to `system`. - -### Patch Changes - -- [`b2de22941`](https://github.com/keystonejs/keystone/commit/b2de229419cc93b69ee4027c387cab9c8d701488) [#4288](https://github.com/keystonejs/keystone/pull/4288) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixed type for defaultFieldMode in listConfig.ui.itemView - -## 3.0.0 - -### Major Changes - -- [`98dd7dcff`](https://github.com/keystonejs/keystone/commit/98dd7dcffa797eb40eb1713ba1ac2697dfef95e3) [#4200](https://github.com/keystonejs/keystone/pull/4200) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Renamed CRUD API to Items API and changed property on context from `crud` to `lists` - -* [`fab97f6b4`](https://github.com/keystonejs/keystone/commit/fab97f6b416d7040cdd159be379e226142fc189c) [#4238](https://github.com/keystonejs/keystone/pull/4238) Thanks [@timleslie](https://github.com/timleslie)! - Removed `getBackingType` from `FieldType` as this functionality is now provided by `field.getBackingTypes()` in the core field classes. - -- [`9928da13e`](https://github.com/keystonejs/keystone/commit/9928da13ecca03fed560a42e1071afc59c0feb3b) [#4242](https://github.com/keystonejs/keystone/pull/4242) Thanks [@timleslie](https://github.com/timleslie)! - Removed `name` field from `KeystoneConfig` type, as it doesn't actually do anything. - -### Minor Changes - -- [`d02957453`](https://github.com/keystonejs/keystone/commit/d029574533c179fa53f65c0e0ba3812dab2ba4ad) [#4239](https://github.com/keystonejs/keystone/pull/4239) Thanks [@timleslie](https://github.com/timleslie)! - Added support for `config.db.onConnect` in the new APIs. This is passed through as `Keystone{ onConnect }` to the core object. - -* [`8f4ebd5f7`](https://github.com/keystonejs/keystone/commit/8f4ebd5f70251ccdfb6b5ce14efb9fb59f5d2b3d) [#4201](https://github.com/keystonejs/keystone/pull/4201) Thanks [@JedWatson](https://github.com/JedWatson)! - New internal graphql api - -### Patch Changes - -- [`98e8fd4bc`](https://github.com/keystonejs/keystone/commit/98e8fd4bc586c732d629328ef643014ce42442ed) [#4212](https://github.com/keystonejs/keystone/pull/4212) Thanks [@JedWatson](https://github.com/JedWatson)! - Rename KeystoneItemAPI to KeystoneListsAPI - -* [`2a2a7c00b`](https://github.com/keystonejs/keystone/commit/2a2a7c00b74028b758006219781cbbd22909be85) [#4185](https://github.com/keystonejs/keystone/pull/4185) Thanks [@JedWatson](https://github.com/JedWatson)! - Fixed field defaultValue types for new fields package - -## 2.0.0 - -### Major Changes - -- [`ae0fc4d78`](https://github.com/keystonejs/keystone/commit/ae0fc4d787ba47eb9e5258a20a57f76124aee797) [#4132](https://github.com/keystonejs/keystone/pull/4132) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Add CardValue export from field views - -### Patch Changes - -- [`166acb9bf`](https://github.com/keystonejs/keystone/commit/166acb9bf211e0ee8a90d4740f6ebc54ffe72dec) [#4138](https://github.com/keystonejs/keystone/pull/4138) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Allow field view React components to return null - -## 1.0.0 - -### Major Changes - -- [`9d360a67b`](https://github.com/keystonejs/keystone/commit/9d360a67b69ec38e3018fe132b1e34f24956f86c) [#4106](https://github.com/keystonejs/keystone/pull/4106) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Initial release diff --git a/packages/types/README.md b/packages/types/README.md deleted file mode 100644 index f5381e29e9a..00000000000 --- a/packages/types/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# @keystone-next/types - -The exports of this package have been moved to `@keystone-next/keystone/types`. - -Keystone-next is a preview release of the next version of Keystone. Please visit for full details. - -For updates, [follow @keystonejs on Twitter](https://twitter.com/keystonejs) and [join us in Slack](https://community.keystonejs.com/). diff --git a/packages/types/package.json b/packages/types/package.json deleted file mode 100644 index 2d5561f9fab..00000000000 --- a/packages/types/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "@keystone-next/types", - "version": "25.0.0", - "license": "MIT", - "main": "dist/types.cjs.js", - "module": "dist/types.esm.js", - "engines": { - "node": "^12.20 || >= 14.13" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/packages/types" -} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts deleted file mode 100644 index c9882a7f055..00000000000 --- a/packages/types/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -throw new Error( - '`@keystone-next/types` has been moved to `@keystone-next/keystone/types`, please import from there instead.' -); - -export {}; diff --git a/packages/utils/.npmignore b/packages/utils/.npmignore deleted file mode 100644 index 851b108d115..00000000000 --- a/packages/utils/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -**/*.md -**/*.test.js diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md deleted file mode 100644 index 2948a2a5d86..00000000000 --- a/packages/utils/CHANGELOG.md +++ /dev/null @@ -1,48 +0,0 @@ -# @keystone-next/utils - -## 2.0.0 - -### Major Changes - -- [#6368](https://github.com/keystonejs/keystone/pull/6368) [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c) Thanks [@mitchellhamilton](https://github.com/mitchellhamilton)! - Moved `@keystone-next/utils` to `@keystone-next/keystone/fields/types/image/utils` for image ref related utilities and `@keystone-next/keystone/fields/types/file/utils` for file ref related utilities. - -## 1.0.4 - -### Patch Changes - -- Updated dependencies [[`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`8187ea019`](https://github.com/keystonejs/keystone/commit/8187ea019a212874f3c602573af3382c6f3bd3b2), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: - - @keystone-next/types@24.0.0 - -## 1.0.3 - -### Patch Changes - -- Updated dependencies [[`93f1e5d30`](https://github.com/keystonejs/keystone/commit/93f1e5d302701c610b6cba74e0c5c86a3ac8aacc), [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523), [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4)]: - - @keystone-next/types@23.0.0 - -## 1.0.2 - -### Patch Changes - -- [#6087](https://github.com/keystonejs/keystone/pull/6087) [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951) Thanks [@JedWatson](https://github.com/JedWatson)! - Move source code from the `packages-next` to the `packages` directory. - -- Updated dependencies [[`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790), [`5f3d407d7`](https://github.com/keystonejs/keystone/commit/5f3d407d79171f04ae877e8eaed9a7f9d5671705), [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951)]: - - @keystone-next/types@22.0.0 - -## 1.0.1 - -### Patch Changes - -- Updated dependencies [[`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b)]: - - @keystone-next/types@21.0.0 - -## 1.0.0 - -### Major Changes - -- [#5932](https://github.com/keystonejs/keystone/pull/5932) [`7a25925c3`](https://github.com/keystonejs/keystone/commit/7a25925c3dc5b2af2cf1209ee949563fb71a4a8c) Thanks [@timleslie](https://github.com/timleslie)! - Initial release of `@keystone-next/utils` package. - -### Patch Changes - -- Updated dependencies [[`50ad1ce6b`](https://github.com/keystonejs/keystone/commit/50ad1ce6be90f5fb2481840dbd01328b6f629432), [`0df3734d5`](https://github.com/keystonejs/keystone/commit/0df3734d52a89df30f1d555d003002cb79ad9e9a), [`543154bc0`](https://github.com/keystonejs/keystone/commit/543154bc081dde33ea29b8a2bff1d3033d538077)]: - - @keystone-next/types@20.0.1 diff --git a/packages/utils/README.md b/packages/utils/README.md deleted file mode 100644 index ad9c3932416..00000000000 --- a/packages/utils/README.md +++ /dev/null @@ -1,9 +0,0 @@ - - -# Utilities - -This package is an internal Keystone package which contains various helper functions which are used throughout the monorepo. - -You should probably not use this directly in your Keystone projects. diff --git a/packages/utils/package.json b/packages/utils/package.json deleted file mode 100644 index 86696a844f4..00000000000 --- a/packages/utils/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "@keystone-next/utils", - "description": "Common utility functions used throughout @keystone-next packages.", - "version": "2.0.0", - "author": "The KeystoneJS Development Team", - "license": "MIT", - "homepage": "https://github.com/keystonejs/keystone", - "main": "dist/utils.cjs.js", - "module": "dist/utils.esm.js", - "engines": { - "node": "^12.20 || >= 14.13" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/packages/utils" -} diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts deleted file mode 100644 index 241106ad0de..00000000000 --- a/packages/utils/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -throw new Error( - '`@keystone-next/utils` has been moved to `@keystone-next/keystone/fields/types/image/utils` for image ref related utilities and `@keystone-next/keystone/fields/types/file/utils` for file ref related utilities, please import from there instead.' -); - -export {}; From 342e908ca0a4511f40c25f82a396fce1da7290f1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Sep 2021 09:03:17 +1000 Subject: [PATCH 003/135] Update typescript-eslint monorepo to ^4.31.0 (#6480) Co-authored-by: Renovate Bot --- package.json | 4 +-- yarn.lock | 74 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index b70c0eaeedc..111a2160661 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,8 @@ "@testing-library/jest-dom": "^5.14.1", "@types/jest": "^27.0.1", "@types/node-fetch": "^2.5.12", - "@typescript-eslint/eslint-plugin": "^4.30.0", - "@typescript-eslint/parser": "^4.30.0", + "@typescript-eslint/eslint-plugin": "^4.31.0", + "@typescript-eslint/parser": "^4.31.0", "chalk-cli": "^4.1.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", diff --git a/yarn.lock b/yarn.lock index a68427ed2d8..ce366e04a22 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3158,20 +3158,32 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== -"@typescript-eslint/eslint-plugin@^4.30.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.30.0.tgz#4a0c1ae96b953f4e67435e20248d812bfa55e4fb" - integrity sha512-NgAnqk55RQ/SD+tZFD9aPwNSeHmDHHe5rtUyhIq0ZeCWZEvo4DK9rYz7v9HDuQZFvn320Ot+AikaCKMFKLlD0g== +"@typescript-eslint/eslint-plugin@^4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.0.tgz#9c3fa6f44bad789a962426ad951b54695bd3af6b" + integrity sha512-iPKZTZNavAlOhfF4gymiSuUkgLne/nh5Oz2/mdiUmuZVD42m9PapnCnzjxuDsnpnbH3wT5s2D8bw6S39TC6GNw== dependencies: - "@typescript-eslint/experimental-utils" "4.30.0" - "@typescript-eslint/scope-manager" "4.30.0" + "@typescript-eslint/experimental-utils" "4.31.0" + "@typescript-eslint/scope-manager" "4.31.0" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.30.0", "@typescript-eslint/experimental-utils@^4.0.1", "@typescript-eslint/experimental-utils@^4.2.0": +"@typescript-eslint/experimental-utils@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.0.tgz#0ef1d5d86c334f983a00f310e43c1ce4c14e054d" + integrity sha512-Hld+EQiKLMppgKKkdUsLeVIeEOrwKc2G983NmznY/r5/ZtZCDvIOXnXtwqJIgYz/ymsy7n7RGvMyrzf1WaSQrw== + dependencies: + "@types/json-schema" "^7.0.7" + "@typescript-eslint/scope-manager" "4.31.0" + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/typescript-estree" "4.31.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/experimental-utils@^4.0.1", "@typescript-eslint/experimental-utils@^4.2.0": version "4.30.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz#9e49704fef568432ae16fc0d6685c13d67db0fd5" integrity sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw== @@ -3183,14 +3195,14 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/parser@^4.30.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.30.0.tgz#6abd720f66bd790f3e0e80c3be77180c8fcb192d" - integrity sha512-HJ0XuluSZSxeboLU7Q2VQ6eLlCwXPBOGnA7CqgBnz2Db3JRQYyBDJgQnop6TZ+rsbSx5gEdWhw4rE4mDa1FnZg== +"@typescript-eslint/parser@^4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.0.tgz#87b7cd16b24b9170c77595d8b1363f8047121e05" + integrity sha512-oWbzvPh5amMuTmKaf1wp0ySxPt2ZXHnFQBN2Szu1O//7LmOvgaKTCIDNLK2NvzpmVd5A2M/1j/rujBqO37hj3w== dependencies: - "@typescript-eslint/scope-manager" "4.30.0" - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/typescript-estree" "4.30.0" + "@typescript-eslint/scope-manager" "4.31.0" + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/typescript-estree" "4.31.0" debug "^4.3.1" "@typescript-eslint/scope-manager@4.30.0": @@ -3201,11 +3213,24 @@ "@typescript-eslint/types" "4.30.0" "@typescript-eslint/visitor-keys" "4.30.0" +"@typescript-eslint/scope-manager@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.0.tgz#9be33aed4e9901db753803ba233b70d79a87fc3e" + integrity sha512-LJ+xtl34W76JMRLjbaQorhR0hfRAlp3Lscdiz9NeI/8i+q0hdBZ7BsiYieLoYWqy+AnRigaD3hUwPFugSzdocg== + dependencies: + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/visitor-keys" "4.31.0" + "@typescript-eslint/types@4.30.0": version "4.30.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.30.0.tgz#fb9d9b0358426f18687fba82eb0b0f869780204f" integrity sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw== +"@typescript-eslint/types@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.0.tgz#9a7c86fcc1620189567dc4e46cad7efa07ee8dce" + integrity sha512-9XR5q9mk7DCXgXLS7REIVs+BaAswfdHhx91XqlJklmqWpTALGjygWVIb/UnLh4NWhfwhR5wNe1yTyCInxVhLqQ== + "@typescript-eslint/typescript-estree@4.30.0": version "4.30.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz#ae57833da72a753f4846cd3053758c771670c2ac" @@ -3219,6 +3244,19 @@ semver "^7.3.5" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.0.tgz#4da4cb6274a7ef3b21d53f9e7147cc76f278a078" + integrity sha512-QHl2014t3ptg+xpmOSSPn5hm4mY8D4s97ftzyk9BZ8RxYQ3j73XcwuijnJ9cMa6DO4aLXeo8XS3z1omT9LA/Eg== + dependencies: + "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/visitor-keys" "4.31.0" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/visitor-keys@4.30.0": version "4.30.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz#a47c6272fc71b0c627d1691f68eaecf4ad71445e" @@ -3227,6 +3265,14 @@ "@typescript-eslint/types" "4.30.0" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.31.0": + version "4.31.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.0.tgz#4e87b7761cb4e0e627dc2047021aa693fc76ea2b" + integrity sha512-HUcRp2a9I+P21+O21yu3ezv3GEPGjyGiXoEUQwZXjR8UxRApGeLyWH4ZIIUSalE28aG4YsV6GjtaAVB3QKOu0w== + dependencies: + "@typescript-eslint/types" "4.31.0" + eslint-visitor-keys "^2.0.0" + "@wry/context@^0.6.0": version "0.6.1" resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2" From 6cbb3d6c32e38954cacc8ab0c6a11636eae7eb8b Mon Sep 17 00:00:00 2001 From: Charles Date: Tue, 7 Sep 2021 09:16:54 +1000 Subject: [PATCH 004/135] Update intermittently failing nav test (#6476) * more navigation related tests * update nav tests * update nav test to be a bit more deterministic * update init.test.ts * update intermittently failing nav test to avoid timeouts on CI * update mock task name for sense --- tests/admin-ui-tests/init.test.ts | 5 ----- tests/admin-ui-tests/navigation.test.ts | 20 ++++++++++++++------ tests/admin-ui-tests/utils.ts | 4 +++- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/admin-ui-tests/init.test.ts b/tests/admin-ui-tests/init.test.ts index 148ee09abaa..de48a86a2fb 100644 --- a/tests/admin-ui-tests/init.test.ts +++ b/tests/admin-ui-tests/init.test.ts @@ -28,11 +28,6 @@ adminUITests('./tests/test-projects/basic', browserType => { const content = await page.textContent('body h1'); expect(content).toBe('404'); }); - test('Should see a 404 on request of the /signin route', async () => { - await page.goto('http://localhost:3000/signin'); - const content = await page.textContent('body h1'); - expect(content).toBe('404'); - }); afterAll(async () => { await browser.close(); }); diff --git a/tests/admin-ui-tests/navigation.test.ts b/tests/admin-ui-tests/navigation.test.ts index b1650fcf505..689c8f13897 100644 --- a/tests/admin-ui-tests/navigation.test.ts +++ b/tests/admin-ui-tests/navigation.test.ts @@ -1,5 +1,5 @@ import { Browser, Page } from 'playwright'; -import { adminUITests } from './utils'; +import { adminUITests, makeGqlRequest } from './utils'; adminUITests('./tests/test-projects/basic', browserType => { let browser: Browser = undefined as any; @@ -61,12 +61,20 @@ adminUITests('./tests/test-projects/basic', browserType => { expect(ariaCurrent).toBe('location'); }); test('When pressing a list view nav item from an item view, the correct route should be reached', async () => { - await page.goto('http://localhost:3000'); - await page.click('button[title="Create Task"]'); - await page.fill('id=label', 'Test Task'); - await Promise.all([page.waitForNavigation(), page.click('button[type="submit"]')]); + const gql = String.raw; + const query = gql` + mutation CreateTaskItem { + createTask(data: { label: "test task" }) { + id + } + } + `; + const { + createTask: { id }, + } = await makeGqlRequest(query); + await page.goto(`http://localhost:3000/tasks/${id}`); + await page.waitForSelector('nav a:has-text("Tasks")'); await Promise.all([page.waitForNavigation(), page.click('nav a:has-text("Tasks")')]); - expect(page.url()).toBe('http://localhost:3000/tasks'); }); afterAll(async () => { diff --git a/tests/admin-ui-tests/utils.ts b/tests/admin-ui-tests/utils.ts index 570a211f805..fceac1cfdbf 100644 --- a/tests/admin-ui-tests/utils.ts +++ b/tests/admin-ui-tests/utils.ts @@ -23,7 +23,7 @@ const promiseSignal = (): Promise & { resolve: () => void } => { const projectRoot = findRootSync(process.cwd()); export const makeGqlRequest = async (query: string, variables?: Record) => { - const { errors } = await fetch('http://localhost:3000/api/graphql', { + const { data, errors } = await fetch('http://localhost:3000/api/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -37,6 +37,8 @@ export const makeGqlRequest = async (query: string, variables?: Record x.message).join('\n')}`); } + + return data; }; export const deleteAllData: (projectDir: string) => Promise = async (projectDir: string) => { From 1659e1fe5e0f394df058b3a773ea62bf392fa8db Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Tue, 7 Sep 2021 10:34:42 +1000 Subject: [PATCH 005/135] Handle Prisma errors explicitly (#6482) --- .changeset/quick-islands-jog.md | 5 +++++ packages/keystone/src/lib/core/graphql-errors.ts | 8 ++++++++ packages/keystone/src/lib/core/utils.ts | 8 ++++++-- tests/api-tests/fields/unique.test.ts | 4 ++-- tests/api-tests/utils.ts | 2 ++ 5 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 .changeset/quick-islands-jog.md diff --git a/.changeset/quick-islands-jog.md b/.changeset/quick-islands-jog.md new file mode 100644 index 00000000000..162a474a9a9 --- /dev/null +++ b/.changeset/quick-islands-jog.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Cleaned up the formatting of GraphQL error messages result from Prisma errors. diff --git a/packages/keystone/src/lib/core/graphql-errors.ts b/packages/keystone/src/lib/core/graphql-errors.ts index 6587864b984..563987e1b40 100644 --- a/packages/keystone/src/lib/core/graphql-errors.ts +++ b/packages/keystone/src/lib/core/graphql-errors.ts @@ -2,6 +2,14 @@ import { ApolloError } from 'apollo-server-errors'; export const accessDeniedError = () => new ApolloError('You do not have access to this resource'); +export const prismaError = (err: Error) => { + return new ApolloError( + `Prisma error: ${err.message.split('\n').slice(-1)[0].trim()}`, + 'INTERNAL_SERVER_ERROR', + { ...err } + ); +}; + export const validationFailureError = (messages: string[]) => { const s = messages.map(m => ` - ${m}`).join('\n'); return new ApolloError(`You provided invalid data for this operation.\n${s}`); diff --git a/packages/keystone/src/lib/core/utils.ts b/packages/keystone/src/lib/core/utils.ts index bafd31201bb..d14f714387b 100644 --- a/packages/keystone/src/lib/core/utils.ts +++ b/packages/keystone/src/lib/core/utils.ts @@ -1,6 +1,7 @@ import pluralize from 'pluralize'; import { ItemRootValue, KeystoneConfig, KeystoneContext } from '../../types'; import { humanize } from '../utils'; +import { prismaError } from './graphql-errors'; import { InitialisedList } from './types-for-lists'; import { PrismaFilter, UniquePrismaFilter } from './where-inputs'; @@ -78,8 +79,11 @@ export async function runWithPrisma( fn: (model: PrismaModel) => Promise ) { const model = context.prisma[listKey[0].toLowerCase() + listKey.slice(1)]; - // FIXME: We will capture errors here and return them with a custom error code - return await fn(model); + try { + return await fn(model); + } catch (err: any) { + throw prismaError(err); + } } // this is wrong diff --git a/tests/api-tests/fields/unique.test.ts b/tests/api-tests/fields/unique.test.ts index 37d807e0bc7..4ec24060d6a 100644 --- a/tests/api-tests/fields/unique.test.ts +++ b/tests/api-tests/fields/unique.test.ts @@ -74,7 +74,7 @@ testModules { path: ['createTest'], message: expect.stringMatching( - /\nInvalid `prisma\.test\.create\(\)` invocation:\n(.*\n){2} Unique constraint failed on the fields: \(`testField`\)/ + /Prisma error: Unique constraint failed on the fields: \(`testField`\)/ ), code: 'P2002', target: ['testField'], @@ -104,7 +104,7 @@ testModules { path: ['bar'], message: expect.stringMatching( - /\nInvalid `prisma\.test\.create\(\)` invocation:\n(.*\n){2} Unique constraint failed on the fields: \(`testField`\)/ + /Prisma error: Unique constraint failed on the fields: \(`testField`\)/ ), code: 'P2002', target: ['testField'], diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 8ac5e0fdc3a..7fb34fb52c2 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -157,6 +157,8 @@ export const expectPrismaError = ( extensions: { code: 'INTERNAL_SERVER_ERROR', exception: { clientVersion: '2.30.2', code, meta: { target } }, + meta: { target }, + clientVersion: '2.30.2', }, path, message, From e2a336c541d5891ed75a887d5b057678e48cc7f9 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Tue, 7 Sep 2021 11:21:09 +1000 Subject: [PATCH 006/135] Make sure prisma error code isn't lost (#6484) --- packages/keystone/src/lib/core/graphql-errors.ts | 2 +- tests/api-tests/utils.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/keystone/src/lib/core/graphql-errors.ts b/packages/keystone/src/lib/core/graphql-errors.ts index 563987e1b40..1feaa70ed55 100644 --- a/packages/keystone/src/lib/core/graphql-errors.ts +++ b/packages/keystone/src/lib/core/graphql-errors.ts @@ -6,7 +6,7 @@ export const prismaError = (err: Error) => { return new ApolloError( `Prisma error: ${err.message.split('\n').slice(-1)[0].trim()}`, 'INTERNAL_SERVER_ERROR', - { ...err } + { prisma: { ...err } } ); }; diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 7fb34fb52c2..ebbe6bd6007 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -156,9 +156,8 @@ export const expectPrismaError = ( args.map(({ path, message, code, target }) => ({ extensions: { code: 'INTERNAL_SERVER_ERROR', - exception: { clientVersion: '2.30.2', code, meta: { target } }, - meta: { target }, - clientVersion: '2.30.2', + exception: { prisma: { clientVersion: '2.30.2', code, meta: { target } } }, + prisma: { clientVersion: '2.30.2', code, meta: { target } }, }, path, message, From 3ece149e53066661c57c56fdd1467003c5b11c06 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Tue, 7 Sep 2021 14:18:03 +1000 Subject: [PATCH 007/135] Upgrade apollo server packages (#6409) --- .changeset/bright-beers-build.md | 29 ++ docs/pages/docs/apis/config.mdx | 9 +- docs/pages/docs/guides/cli.mdx | 2 +- .../embedded-mode-with-sqlite-nextjs.mdx | 8 +- docs/pages/why-keystone.tsx | 2 +- .../embedded-nextjs/graphql-api.png | Bin 85222 -> 360626 bytes examples-staging/basic/package.json | 1 - .../graphql-api-endpoint/package.json | 3 +- examples-staging/playground/CHANGELOG.md | 54 --- examples-staging/playground/README.md | 5 - examples-staging/playground/keystone.ts | 87 ---- examples-staging/playground/package.json | 21 - examples-staging/playground/schema.graphql | 167 ------- examples-staging/playground/schema.prisma | 17 - examples-staging/playground/schema.ts | 10 - examples/blog/README.md | 4 +- examples/custom-admin-ui-logo/README.md | 2 +- examples/custom-admin-ui-navigation/README.md | 2 +- examples/custom-admin-ui-pages/README.md | 2 +- examples/custom-field-view/README.md | 2 +- examples/custom-field/README.md | 2 +- examples/default-values/README.md | 2 +- examples/document-field/README.md | 2 +- examples/extend-graphql-schema/README.md | 2 +- examples/json/README.md | 2 +- examples/task-manager/README.md | 4 +- examples/testing/README.md | 2 +- examples/virtual-field/README.md | 2 +- examples/with-auth/README.md | 2 +- packages/keystone/package.json | 9 +- .../src/lib/core/queries/output-field.ts | 4 +- .../keystone/src/lib/core/types-for-lists.ts | 2 +- .../src/lib/server/createApolloServer.ts | 59 --- .../src/lib/server/createExpressServer.ts | 11 +- packages/keystone/src/types/config/fields.ts | 2 +- packages/keystone/src/types/config/index.ts | 12 +- packages/keystone/src/types/config/lists.ts | 2 +- packages/keystone/src/types/next-fields.ts | 11 - prisma-utils/CHANGELOG.md | 3 +- tests/api-tests/package.json | 2 +- tests/api-tests/queries/cache-hints.test.ts | 2 +- tests/api-tests/utils.ts | 3 +- yarn.lock | 425 +++++------------- 43 files changed, 199 insertions(+), 795 deletions(-) create mode 100644 .changeset/bright-beers-build.md delete mode 100644 examples-staging/playground/CHANGELOG.md delete mode 100644 examples-staging/playground/README.md delete mode 100644 examples-staging/playground/keystone.ts delete mode 100644 examples-staging/playground/package.json delete mode 100644 examples-staging/playground/schema.graphql delete mode 100644 examples-staging/playground/schema.prisma delete mode 100644 examples-staging/playground/schema.ts diff --git a/.changeset/bright-beers-build.md b/.changeset/bright-beers-build.md new file mode 100644 index 00000000000..7267e6d447a --- /dev/null +++ b/.changeset/bright-beers-build.md @@ -0,0 +1,29 @@ +--- +'@keystone-next/keystone': major +'@keystone-next/website': patch +'@keystone-next/examples-app-basic': patch +'keystone-next-app': patch +'@keystone-next/example-blog': patch +'@keystone-next/example-custom-admin-ui-logo': patch +'@keystone-next/example-custom-admin-ui-navigation': patch +'@keystone-next/example-custom-admin-ui-pages': patch +'@keystone-next/example-custom-field': patch +'@keystone-next/example-custom-field-view': patch +'@keystone-next/example-default-values': patch +'@keystone-next/example-document-field': patch +'@keystone-next/example-extend-graphql-schema': patch +'@keystone-next/example-json-field': patch +'@keystone-next/example-task-manager': patch +'@keystone-next/example-testing': patch +'@keystone-next/example-virtual-field': patch +'@keystone-next/example-with-auth': patch +'@keystone-next/api-tests-legacy': patch +--- + +Upgraded Apollo Server to [Version 3](https://www.apollographql.com/docs/apollo-server/migration/). + +The Apollo documentation contains a full list of breaking changes introduced by this update. +You can configure the Apollo Server provided by Keystone using the [`graphql.apolloConfig`](https://keystonejs.com/docs/apis/config#graphql) configuration option. + +The most prominant change for most users will be that the GraphQL Playground has been replaced by the Apollo Sandbox. +If you prefer to keep the GraphQL Playground, you can configure your server by [following these instructions](https://www.apollographql.com/docs/apollo-server/migration/#graphql-playground). diff --git a/docs/pages/docs/apis/config.mdx b/docs/pages/docs/apis/config.mdx index 1a80e925d41..97e0364c790 100644 --- a/docs/pages/docs/apis/config.mdx +++ b/docs/pages/docs/apis/config.mdx @@ -323,10 +323,8 @@ Options: - `queryLimits` (default: `undefined`): Allows you to limit the total number of results returned from a query to your GraphQL API. See also the per-list `graphql.queryLimits` option in the [Schema API](./schema). - `path` (default: `'/api/graphql'`): The path of the GraphQL API endpoint. -- `apolloConfig` (default: `undefined`): Allows you to pass extra options into the `ApolloServer` constructor. - - `playground` (default: `process.env.NODE_ENV !== 'production'`): If truthy, will enable the GraphQL Playground for testing queries and mutations in the browser. - To configure behaviour, pass an object of [GraphQL Playground settings](https://github.com/graphql/graphql-playground#settings). See the [Apollo docs](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor) for more supported options. - - `introspection` (default: `undefined`): Introspection enables you to query a GraphQL server for information about the underlying schema. If the playground is enabled then introspection is automatically enabled, unless specifically disabled. +- `cors` (default: `rocess.env.NODE_ENV !== 'production' ? { origin: 'https://studio.apollographql.com', credentials: true } : undefined`): The CORS configuration to use on the GraphQL API endpoint. The default is setup to allow access access to API from the Apollo Sandbox during development +- `apolloConfig` (default: `undefined`): Allows you to pass [extra options](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#constructor) into the `ApolloServer` constructor. ```typescript export default config({ @@ -335,8 +333,7 @@ export default config({ queryLimits: { maxTotalResults: 100 }, path: '/api/graphql', apolloConfig: { - playground: process.env.NODE_ENV !== 'production', - introspection: process.env.NODE_ENV !== 'production', + debug: true, /* ... */ }, }, diff --git a/docs/pages/docs/guides/cli.mdx b/docs/pages/docs/guides/cli.mdx index 4419dcac954..a5d0f604320 100644 --- a/docs/pages/docs/guides/cli.mdx +++ b/docs/pages/docs/guides/cli.mdx @@ -195,7 +195,7 @@ yarn keystone-next start heading="Getting Started with create-keystone-app" href="/docs/walkthroughs/getting-started-with-create-keystone-app" > - How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL API playground. + How to use Keystone's CLI app to standup a new local project with an Admin UI & the Apollo Sandbox. diff --git a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx index 6b835cae8ae..8ba41dbada8 100644 --- a/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx +++ b/docs/pages/docs/walkthroughs/embedded-mode-with-sqlite-nextjs.mdx @@ -35,7 +35,7 @@ Here's what we're going to do: - Create a Next.js app - Embed Keystone, and run an Admin UI you can read and write to locally - Add a simple Keystone [Schema](/apis/schema) with a `Post` List -- Setup a secure read-only GraphQL API endpoint (and playground) that you can access in production +- Setup a secure read-only GraphQL API endpoint (and Apollo Sandbox) that you can access in production - Deploy the app to Vercel 🚀 ## Setup a Next.js app @@ -290,7 +290,7 @@ Run `yarn dev` again. ## Bonus: add the GraphQL API to the frontend -To get a read-only GraphQL API and playground in production, add `/pages/api/graphql.tsx`with the following: +To get a read-only GraphQL API and Apollo Sandbox in production, add `/pages/api/graphql.tsx`with the following: ```tsx // pages/api/graphql.tsx @@ -298,7 +298,7 @@ To get a read-only GraphQL API and playground in production, add `/pages/api/gra export { default, config } from '.keystone/next/graphql-api'; ``` -This takes the fully functional GraphQL API that Keystone is already generating and makes it available as an endpoint and playground within the Next.js frontend app at [http://localhost:3000/api/graphql](http://localhost:3000/api/graphql). +This takes the fully functional GraphQL API that Keystone is already generating and makes it available as an endpoint and Apollo Sandbox within the Next.js frontend app at [http://localhost:3000/api/graphql](http://localhost:3000/api/graphql). ![A browser displaying the GraphQL playground](/assets/walkthroughs/embedded-nextjs/graphql-api.png) @@ -340,7 +340,7 @@ Keystone’s Embedded mode and SQLite support gives you the option to run a self heading="Getting Started with create-keystone-app" href="/docs/walkthroughs/getting-started-with-create-keystone-app" > - How to use Keystone's CLI app to standup a new local project with an Admin UI & the GraphQL API playground. + How to use Keystone's CLI app to standup a new local project with an Admin UI & the Apollo Sandbox. diff --git a/docs/pages/why-keystone.tsx b/docs/pages/why-keystone.tsx index 0df59cc52c1..9f052823867 100644 --- a/docs/pages/why-keystone.tsx +++ b/docs/pages/why-keystone.tsx @@ -521,7 +521,7 @@ export default function WhyKeystonePage() { Use an API-first content platform to unlocks the power of multichannel content ops. Connect to your audience where they want to be. Ship content to any frontend over - performant APIs. Use the built-in GraphQL playground to query with ease. + performant APIs. Use the built-in Apollo Sandbox to query with ease. WttI~KOCWbZ)vRMjE!3w^8mP%#_{9kIE?egRuAxWWT+Go;i`ieg{cMn`fFqQ&k3iT@<`V0gJbQ z03Q4`Hd~wbq-xU_RY!C~Y&(ool~0&-Lr}}q{aw=>1%!h5Q2+r}+3P!Rcz8p<$AEVF z5ZE~J)_C2M&hdKeWZ7H8LzNd6iyPj81K#b0>4PsqqAhH3qzq5~sD-i?`ki)|zt7qa3`a zfA}Iv_f2Ku8smm)(Sv)cgDEtQW1p#KFCFn!c%#=J`%eg60FdZ51`KIgGgihS)6|M;sl2^bIEbEP_k0iQ7;j;4=3n61*=L^wWy%I0|c6S z>+w8^rF%{(X>;(z2S|UFZa=+^*a-HGK)kxmpvsK6a@*;;y@sAreES z+X(oSm6w#yvnMpot<7uDxXs!2NJoo;5j$aK;n>|8fb*;I;Y$anM(Ty&L!mjWoCV<; zO1DqR+-K{@A=A(<{BDlR;dFxF0pN7_;mspc(_P(){WbxK2VD7rW;nt-lLnT_XB6 zA*XrY-s8PU#>d(rgV8kI%Oo>~U|n!Uo@Je57ym>N z6vh4^CRvE${s42M(mRU4n3uTs>@-Qz;!E%6YLeYky7NWsDVcFHzsekYUMk~LkS~RF z#!%jz#WbjC$(B#nQW~E%f;bg35eTuKrw)Q{F3r zisz@EpK~llW9#CG_VEijCBF1&kmAP~8+y7xQbSVR_n}dyhEQRr+FW+-W%$4=DIBMb zZ{7qN8$42M1@RMobQ^A`M?vxtM9|mZfv&T9T$xWX>#C>sy$MThOUG!%7%Su1@%_a5 zDJG}G5)-I;Z|a4!#(AWZaDI-?J8dgXD~%OBIeqv03Y?dznh)-$QS-dGqp|UZNUN-L zwlu%gp_H$bY?`16fAQU+J{gx&D#sR;FJ3SKoEuIAXXwZ-)@v-fHrn96HF{^%ew0?5 zdYh^&dRk|;Xvqkta^$iCwx5ql9He?mi ziFl8wLZn|*pQr4$Guh&|;af$AMGxZNka*IEG1|+-$g4^{{gm2y*DSVMlG&Bsom-4w zbj2fR^)#JwhWjh`gmaZq^i;UR%EFY?r=Ya6kjm zPd|)2OQ%g|eJDC}`(f3d>r8sN^)viupPqF*4NeuN66Spk!DCXb6U3)-1Bw#>w9I=CVT<9 zu6p}7Et4&dE=MJ?DQ^|_?K^!srFw*;Gv2&y6fbe|U)aqoksS(3;$iV~s99YYahOOE zWz7a3e+jBR>pr^?CCqinl@$U1-UyoQe$VeYw^ZY)5C?q?7*p_@-`%}~e>(l7 zXe{DAb!xL*#lt%fK2QX_lHL&CnD2Pg!Q{KPGq~+Bb}(izwq~s;_=R7Jdn$8FOJ7eY zPbgS9@4MDxUXOxZNuTWjPm31!YUVd7nUb{opHdLCFMBq)2K$Tqia!*SryFw}71W4Y zh;%r<-ps&z_?{+?4iKR!7%fKZ;T zT50VrM*dbteO0j-d=9)!W|s9&nh?Jkr`{fz+%@T%e_LbSaEX%n)X8@cJwNXu zv})M+uZql;SS3@udP9A`kGNG(>9@X5RtP`Vz0OT{T69XuCzcAl?p}jO)0xvT3WnI!c%8XQ zpXSYb5j^g(JOIJ1T)PiLJE}ZXm#6rY%=E2DdqRFOUM&qCG|n%3macpZ@cTM`X&GfX z;kC0C5ni#Yf3j+Eb^B`c*ln#o$QD+J2#i|`Y!7W`3#LajY#U9Nbfv&kY!u#r;VZ&d zJSdkz(cezu6RQPm$0R4+Nc;1Ikkf58(LLUVVyDc8{N)oRz z_N-oJ@7RpXpUIQ|py@scx4HbZ+kcr-li~y}3lEu--4osO+op>H>DiP(e;n}b9;Cyb zcB2ijNyx-xnO;aPV-;55^t}jY3TXL2cSxr?3%$I5TF~&p=8(<{Yk&PJRGALh*+JO% zUZ4RLg?!v#mQ;b0dPrvaPD&7IHDy}j)XPWJ@}*2mI%dw=Zr_JZ>4 z8X5xS1dT2VweNm@Z|AU(T@%HB>ZLkc5Rtu^5?GknM~w^u=mg1AyXMEE1u^I&%h6ox znVudNFQ$AO3lEzL3kOre#(c4`8L{yGDq~@3V>A7yY>dtQcb{8WSaB{`xPSL~jJf~$ zq+%`%_1|}#v{)VK1C{>k5S_V@Re0f7Po0|f&`1-*QoK*G|}(jXxbkcfx?riXxEu&2LW zkbtM({eL~=-_KEX^mFia@%DG|@?`(>TswQO0Dt*=_x=p@pU=PM=@{hl&q$trf3t;Q z5cH=7BrGTd`oGBhU7r1a$o{nai|jAH{xzK3pNGkq_&NHjczJj@dipE;v*L1pjr2bn z|C#5%2n}6=9No=TT`-h>7@ib_#U-TvCi~w_|0k)%Kcv!9|AX?sTK2Ig{6q4rKURc;6>)( z?B$~4p5C73a#_L)c3!7);3*}Ek6fYD^%94&wh}lv8{G~UXb$i7#4k8URkHWQ zpZ8`s1_C?MPQQL!{pca)KNS4*wXgRoydqzE;+^!2({!?QTWIfXv}}4g)Fq8THdHcB zENDc>AUZ#IVq#cU!0uXiSoY|94&JTxmzTF`k`kV~oVpe5*?W<=p>LsHKvJR3xpqdx z+o0WoLWmK?HTXNY2wi3z^Ha11tbD`Q0=7>0M5O8ri9>7bLSCY|_J=2d=eN+QWYp9zD7QcvU=tQ4 zzz~8Mu~DWvudjBi8|UW9vep7_`|gB$wY%t^5!oWkd+Zj{JMNn(FMUl9khVew3~s)5t)T){DE}hI#LK zME_p>;V#tQ)1}Cmgebx5Z^AxtbG{yr7Uz;EW))YMjv_qAL30u+p_Sp$4{%Y`=U$Z% zWfapA+uStKQT-&^-@~)5Iekt{BX9PvNfZGzh=L-3Wr(dtC;Y{b4fEM4HD;}Fac|wi zj=Xid^hV|}7lD-|=W2kz6!j-9Tx+Ybz@uA3XsT0k7~QDNB=`}j5)g}s6ItKKf2~>xiHypfM6;6> zp=g#0=6;bKd70+Ms_jDlT9c-T+bFNL_n)tE&hNcor{$1FtGpuS{A(Zo%&m$-^NNLL zEmGqmaRevPeOHQrk)N455N9)NdlgrPUDJ|($tl|`2{F;knOwipk`+x(mT@X)N@waM zpCRPFo=qC1Sins+@JGZ9(NX9kh1&?p@8AraxqQ=^ScK#s@k(&KRd%lhoNtOnUxXs1 zPzF@ua#R4FglPRaKWyt=NGv*#9%7qRwJA_0j=mN3>0e9sXZtvAIWmelhh<+{Povo5 zn9iFF4i*Y2odA9^CZb3%aiyn3Pa$pP&Y>imj|}Mc?#ih;G;HaTxV>C-l7LfHV!b{( zSqW{mSYjRnqdQNTN!Qoe-HLfw=TC^p7Jpsspp3%d!DcN&i@%zjAyv6ic^Tzf1o~?c z`Kjxk5FU9A-fMxX0Qb+qRvdQwchAAffQ}pCTGZ0=S;6Jeva8O0xj&oxm!PF4Vs*0Y zCcBQ?2U3*6SIHYq=~v)vU3V6I#^)^v@Z*;@m3bEyTunlYB*9OIxG(J8q^1_KoD=R( z5+ujmq9zx^hO{HVU)V~Obl%al{27It3uu#lTc z^rJ`If?{8PhBHWXguE`{toGa0hes1edVV-Xv@|jSo&k6H z3M;2Nff~mPQT?sthF>G8ACsC zh3z3kSXRA%GSJ65nf`w4$U2alvPUNR%?NTUTutp0zV0>YH32*!3;Hf!)^WbhIxQNy z(rq;|HZCr07dZgod!2EQ&x{v*`9b3GXAA^T`<|(CGnJ~3rtjMV?c?iY0l1PH6LB-D zr~NP6=M~w4aFIN+R~y$Lg}D{#@Fd+jJ}-i_K%KnHl?_?Iw2c#dxSrA8Z=puP_4NQnluZuFqW@*0^lK|kuNcN zWiSaXLSr~&Bq}E|WWKh?*yN%mY;UaeN%TE>wFBVgWraQMQUNzuzZPlM4!uhX|LC0u zzcD+z)*GJ=+q|>=FTU?6VqKj!&OMKnWj_5NA+;Qx z&w1kNN5o7P$HL#by2BD4G*7R)`SN+tgvv@w(|+pvcLc1FeT0NaJOm{L4jPz+Ww-Mg zw0W-HbDOJsGoB~m0JE#uvV%oFvl%Ub29_zp$F8-uO74%p&`ACU(4uHvDVt;$lus!+S@q z?_fr!pnpsm-mN|OJCZ`XiMY+QI#4Ao;u{aa!VLL)nVc#%?^4K4@wekQJ6Ze9N&Va# zGxUPKf=0F;x2bmtka`rSNKhu2_GPVQ+n1#aw+EqaZCi~-nmPja`0aW#%D5qIF@|@~ zQ|x&lkr90u3-bCAH$(}*MOixEfWCu!my%Gi2)gOdz|9Pr{3vA-efwWOpg64R?2QAU zF(o&@hbCcluK1*bW>xP_oBc6ln0Mfm>Oc130j@g%ZfG`Ah2_rL8{30&>&zX-{vYH$ z{dj0=rYYvrQqmG*f`F~KrBk)q&E=_|*`lnGy>^P+_M(c|kb9>(+0cC1_OZ?jH;z!t zHrix!vAqiEI`D3)9anEscjq25@4G+g0ovwMm7VTYP@u_Ag!z zmLNsw#x_eUC1*cVunKAnpD?ja^E@f_(BuZ(0%lh(LX#emYb!ZJsuarb36JVGJRr9g z4v#DyS36sq!f(h1j`(Vw0qW;I2dap#>E>|{MY+$?P5;Z)5Jvi&^1E-r^`llt)uS~3e$ogZ@hmBi#P!MGWjO+W{;i;cE{R>YHRpVKnmGT0Z=A%+&s9+WmEm| z){-M$Y}u>rTU2(Cs?h>k1@^3BWXE)c8fi+}pWP`!fYwhagw9A|!y!}q^BdKGGMsoj zWxTu)s9ha}_4z&vcs9}wR>4$)GN6T!C^RV|`{Em@1U=Hg2$9l`0bC z@yWGfTH1vsM;VymTx$j)VJ&^`R{(I|658ykE@p!^VcW zi6`>6>pRU=rRGNPjRSmFqrBS-7{Uk;vDvq%PJzKO8_y?#jG;{Da{9Cx?0^!widF?q za7zh5ZCtPgJgEe%gUJ!#?+|VZC7=sNaSoXT9@8rWGnw%pJ>z)@{d{`dtyeTECIPZd z@*7!n6Q5J|;pf$82FEe&kWQv{9`^W9F38bx`^DXUufKyzTwE%ONk-1Ox=%6KX0E=! zS-5D=$-%)v75Vz?yROY2o5>1fPWC=7Ms=3!Er| z*V(ekZj+#av@I_){p6aph9}QA=4n!tw+iyoi8j{`Ele+KkuJg{=cK(az&?dqlh8lm z9Wf$qw8$0{;emVzFUT{?-RN*qdc6Lq`W$+gxKNaOzd#e<`i`-3ts$J>!6TdGu{xEI zN{Iw0dhr!ue9}U0K{K)JZ|ndiIF1Fc2l^;kAwQb%@5t|kA`z}VG38!X*2D+(wVJrn zOya!Anyr;BEE&RY1cGC;W}Qu0%A1QT3mt|fpa*sm{&V1-qj+>a`06k1e{lNfP09o2N~73ko9q6gD;PUKbY$QmT_wS-4M_fpayG%;KxR9inS{qeVb@*z zBQ`xzR-v$CAEZWjtj2%#i0EEw!?1q4_cXa1ovFliV;!x6Gr{INAwe9v9Ss6kigeH9 z$w-IaZU$r@s>ydE+srq=37gNqxbPuBkZ}?C_5s=VAzhP&n;+8T+Lq39ntIX!^H(#u zUFI(Q%5Vqzo_&rd7{Jmq2gZg}Bt{`!Is`&ce?`1XfNQfMQ@k_!C4%caICK$Bet`+d zP4NG6riNZIm)R}@J#3K0t4k+A+6NvhA1!?S7M)tB-W6|p{roKYpLo{@*Zr2VS^Fo( zB)MAKmiFBPW?70jl}{_%isa9SqmSGhHnW`fkj+K(z$8}Nx{AZE@6pS6k&+iWClTxN zlV%yW&=jw2vXCA>nk=~3F0Ii<*OyhuMzJQ!PAJBAkY8IC@xT3V-w`M9)(|*x`(vg4 zn(FHx0NEe-uyl24_T-1)VoNYJ(U0ClfZbf^AIK7^n2S%!_(Lu9IeBZE&$3E~_PBfP zLCwi&Y1=Q0IC1eD1;gQG?J>)Ck-33D&<7vlWFSVTvX+-<;_oPhJ07b| z_*#3Qbs>EFvq6Bv;KrKWW=}t_H7ZDwxutN;%IigTJXk(Pt9^CnKrP&zbYq1BaAT&MrDw64y2-tu#t zzhEuZ2gn}<#sr$|6#E5+zz2~>N`E;xqN9mPG#M%-x*cdG4PRi9tzkP5zxk021OY!K z|04~o*z!>$_&34&jn7$*;veLzG6qSVXIQ z>!bjApOyBFJj^SDgvpTPoQLC1?h9x!#Z>J;%=%#_niK=-*zoW<2m#`HAR1j%J_Ww5 z`zNX*zA&hSsN6&|zTu9!jB`Pa;}1F)8CEZf{y$IumQ zfH0iw-+S=~rx#LFFrV(kLpt4FK>18=?A1^Fbk|Fx-%p^q5 ze&X{Yu^JI}Qb+HG)2T2<1o8@&-NRuCgZcRc;&5qNF)V`MfvfGsSnF{TgBv@nTlK4u_q|BZmTlEY_z=kEdbrV~4i-&^m_C|o z`E2v{o8ctWric#uu_zI!rC9?TF~8>BlgKEmj8Dewt+?xFysZc`K-4a`r1^c5wp?m= ztCq^-L=!{-OBeeii|bcKP%yiJJgW2;kRx2OwZ~PE3I(4BO7E;Rmpxexx$|~)bgi}> z?FrrXg22~aDphzaw|#8!9UUk7a=cxDHoteel8^i(ZR&qnj#To-=o9qyy61)0zc4W2 z9|T;4R^#EWL9s2d6`{(KyfHz)A7(xNh$Oj3n98HeMwE4xvE$y4o-Y5BIXzyJ8vnlY ziMGSqwCn^U*5``w_B@yY4W;gX46pIs)aULyp4~RL0|?#J*P6YbT;#QqaFMPQI$=&K zHp#!&)MWSvq;cWiR+$a&BprL&j<)bqW-EC}a1u(w}f$@t7d8Y|9sS z-C$?7qnm_3H3sh72NdR-CywipzeCT82Sq%V&W+1#9wXb`)}C;^O&+L^Jfz^p1sFt~ zMyXT4cYp7UUm0T4r9<<)dI+0l%tG>U;Zvr@Q`;a~m%HcG)4TFq+rXTF<%3X52`h3E zRL~DR#9KABNw9*>CcXM=mYciO zrAsUumMnl)&olxrYf7dHGp_v#qb zQ;@P(iR*P>rKge05)02384le0%~l46prh!~NqJ&#^z&uV8`sd|&V#L@IM$5&%k9m` zGXBcOucm~s!kkQhDVS#Peihdi;-KE7KxPjQK0OlG8_wSniy7|Z$7lhUqyLpW5a^zw ztH3_Z9j-_5a6|-0IqQ)b+A8fTMPXxw6o~8{+YTQ9-iMwHZOt=V2zk|=gMX7`7(FZA zgQkGdia#KboUiETvCILF2r|{4d4GY}4(K<$UEKtbeiK-09U>64m5ZM$6SW!bZQRhG z!8`cKWmcb;jeKoiB$LIV-K=A_`T{)6HQok6%|S zoVq}75`aGJ>@g%8R3l>IjiqOA)%QIIkNmN!55dI{Uk zoUpm?H8I(V$Df)_#Sc--1nW=~F#4vzB%Mzc;o`8JCAYdpr1wwd8v>4Owd_h}RYXN4 z+yI|E3l_+}4^72Hu~(1Kp;!B5gULtr>A@t_Uw`bcZ3se^+kNb2k9Tj**e+;U|Ko(Y zUnr`7#nis?Av!fb;+~A;U7$G2GpTSwtNTx62TV?1K+fDx#xdqNef6Z+!bzf|n{^;Yd z4fT0O&1qP!pNDUlzy>@;AO)+C^;WfME1_3C(`Zdyxyg?ttirx6VWQ!&UoEBBqK(`7 zi!7R-O&14??k$z%`JXJ2zJDWBny4W%TWe#+`td~R=Ns#AVWD)5#h0?-cTCXql~ORs zPBKfH4g+V9ZhYvhS9yZJ@fYY)^Ghw(=ay)Co{sbFiBU?>+B5iA%)4``pQ4*$xnu7eRW z&-deT@;T+{+C#Ki^<&a&sv5DXM@7Y+zb_F`*MVB)m$1h}Ve%W>K(-)6LdP%&4k7|p zmJBQeZ5pFSJtBm63yLQz%IhBEIaca2l-aaC4&Vdb6alZbZ3tztWhsz!nGw&@)xR{0 zq~&$#NO=5Uo&iIj!a-&dI3l--6j#f(6^wyQkmZxnN(KFN-))}Zu6p3A6mr>)US)%i zeH~SPcspzZSZa0q#GxB`d3AgMpo(m$U^cA5#<9U>bv3UM5D_%TCor7!0^Fp~0*OLW zM@|CV#z6h%8zXJZ-$Gy1NH4HEH3E*YI4{Ip;!bVmM>wi~ssdD?Vb0#&h0}TZq=Z>zyl8^nP z#4$DJdXkie;LeqpWVr8vK)YtakDfF2&&BEF&K?QEN@A5u+jkga+t_*(CbX}tHkt=Bfx`J4eXs#Sxu zpd1_K?d%OVcr#W<|3FVf)M2|`D_yt4eVxWPY~nqq#%;ZjDVUkn`Bf|OBpIEHGRW@m zgJ!esgn@vt>${pdKattE;m?ZA?8?{02=PvB+CB5#7h6W8Uxy)oo*GX8(;HABIG+SU zRoDbog2yY4&H(I7CS18`!a2Oxx9hJ@CHVu*(8eQ>vni*M>FF|XFS=qDLVz9uer(v( zDN8d$3>hraKnHVmemM+L01fP96jF>V5`4%bb3F!mX3CkF@N8GPCG;F;?XmK;l=%gD zK-KXyHo0voETW+WtgQkZdBDNWzt`?`j`(2Q5>SLZX+_uh5mmcC=U0wU6WG{Fy}~!Uy|DAcRvOcHq4`5n>={y>HBM zbpD|uY{w?Y;F>Q93F1K#pOQz^goUtc;{%TnYqw=Pc}_uua9KlSGm>JDs?2~Jo6)5~ zE?83lq7$hQJV2x%PLQZ@Zfdj))@>jl#)7qqjoPHE>)qjPgVH+KMdePHu(<(mym?^t zVQH)f{PgJtp*z_dDHTfxIG%%#fDC8&LwL%VO-U?iM%7BUoJFH=W^XoUctKe#2zqG) zI71_)V|?q*vJG!4#75U5(|}tjkap|@KM3GGdF$ve&%M3Y{OBD_^hX#0mU1fYB#mcjhpJc;Q(C|LSo%dlSvGpXIylmC4{jW`G zojq*S@1}sSXNW6=;eFRG>UOZ75j9aD0YqsqJABO&F;lLaUY3x>`z)r;Cw*vvaO%yg zt68+dPiXsj0w0hvfFhNX8QB3aAsvqwITI%Bo1QE`wia)ozN;Vq9T}>7$qyMEhkW~% z-{?>nW+$|G1v7X}ui*om2pqNPUa1^^zr98fzXb^AckpuBaN5Fty1hH<_2~~;Y_N;g z?K{)C4`!&_J_#a8oyour7xiDiMC(28OxyNvT4&!@7)Jy=MyBNBY#0ady;PN9TDW{V2wvUTM(aF@aQd8qyQmG z<%x-@iD||X=rx43-2$)6GJZWa;K2G7))@b$Z8ntPKH#1%)UJ%$c}i=}?0!@qZGqOk zjKXBQ15Y!dKe|so?EzCIL!*_#4)zz2uX?R~+m@L%=qyzfQ!NDc+m|CQokG`=Dx9-_ z`Ak0Np9KE>7mkCKZC1mv$-(Ao{X?95qD&+WM@QZ1ciC77m!^`u5c(4`Rv*R)!`S&B zZN7R@6MOy3emZ_tcB6CKl)3AB1>Fr-=fcB4g%zL>0U||YnH$O|VjLnGBf*4k>eI;w z3S{qI%X%;dD&JuNil;%zNH!tw7g{*BfII9dgG`1j8#^^8ZKwc5QssH_mLQRL9UZ4( z{CPfkdZ+w|jn*mD%`Ca8NfO3ZR!@BQ4J;f4Nlo~wD*|fn%{3}Sj_3Z4K9?@D`D$<& zM1AizG9kK`D$t@s7Cn~9$F8Ig+l-l_*HREJ)aWMp6=E6W-ouSHP=D9}Ar^Q9-uIFXn!6v+Bvr6x+rNH6iZ(HLz z!~wZwG&rGrx>d(azBz!Iv)HtD>ow2y z6s(we00w0iRFuaxpYaekHQnC+HC@r->G#q9IILysaD_wE2f0||1;w)&L4d_km?VgO zaZ7rO>#DKip~lLAh~wy^#kQpE7OrV0lCO~F;gsG+vdH{u$X8Q8JsXeHxBc6Ad-DVN z%=yX3+}$eAHiz^?oQ}ywNSoBtUqcMm<{{k&n+pypna>2?j=;9Z9H&c1n(R;^WsmTD zE%0EuIEiy1($n#3u5*<|fmeqMy($v!R`r^*pF4V--UahMZA$D$EFJK`>j}ZDq0C(3 zV)nQuB<-P|5acq|=mP`fNt7Wwb_)-Xp&^%kI_!{8U$ zO>T6*DTO&^p|PR|0ReLaXA_Dm!&kd^^_oQ-w34cJMXC>6}!-$LRMnz=hev zt>wivULdhMqDO|;jmbyX!XC}%5`K+zO8eqwhon=7${pkVqAi~RA?r=&bjrW#;yvcDCS zuZuhvwIJ_!H4RGn^vfYxT0L26!#h{nuPqEUYxddX#0ZuB8o=btoZtVhE1}^tb)I!O zs{e@mtq{|Bu}`!OncdH93b}af)PUV`cZ)ki;FK8Nk}IRF zFW>Upc+<|ABwX1u`AoAit4(PM0oT4-iF2vI?%KHqrVIti5pS&VF^CxO`{MHhPAYuX z-8e+O%&2pIXREj%Yf8JT`13mrwMt$*=Qb_KhrsWZBbCUzn@jP&-60pQBWf1KP;OLW zqA&MJn@UQwNSEPN5Q=FQ*e)U-E6syqa^fy>i6fh9xCz=}XurS&ohlgHAXE+(TWwRl z*_$C?+5Q2&*yPv@8&rG`X@iVr4zDsK{~}{1&CPc6P5TN_`+*(ZG|~N|aeR6xCDu2>x!chWWLH$W6$eFcm0!A#$f1uj__@p0GSd=Od?jd;K}Y|LYemGJ!$^4(uVB)|+HMo2#8Z_erI%?|@uW~^Hgcc(wv-Cum$V?iruMZ%=9whggZ z(K4zwWvMdSq$riA3klC}SY1EkA|2|l$cAJQF1^tw+j?;_OIF31#3-J2Ses17?^3`E zlx#zV(199|t0S*C4@~Nh9Cnq!0~roDsq6GyPIk|g2!A{J{8Eih6Yu-X>SSEV#f4<* za@8_aZ4U@RS>8eQ_j=+l39A=8p5|fWf?N~+7qqARvfkz>k+az0fR~mPXLH1DyBJu;QAGaRf$!j*{OZqwN9NW)zB*)kdqSrs=KX+^VaLzv zZ+o?~6lTUAl(Dg+uQJh(bd}i`=`}rTuA65@`MfJmr8s2{InX!S5C{zFnIA&$?J=SH zfnDx$H(d~by9D=2!UFlY>JS^>2ylxI_ddRcdH4uPC^yQ&`FPNNz7~cxq3;xJvb(1S z9cOyKuyrUa=~|;H8sCcjT*pVL?s-{3jmEh5s(A{29g;7@qNBe(#N?T} zhQ3s91+GLVMr{B@J1$zdsnC-x;<{JNWkqw-Euo~Usoir*Om+KY$i@Z)?LEW)sj9_4 ztO(g2orNs}s9MC;o+%tB9Q^*`N7sqwOnI*MLC!a8$8lGZ>lwcXz|HwF2c+YQwaTQT zO{U6;i-DQH=XYJ#RzEq|G|YZmPeX}f>KJB2of)fC(ggdSZt&%d>s%43P^SLUvI2|_ z`iMLMR!Yw_E--Kf#fGmpft3^n@AnA&LPo-ig8%3$r6LI8*P+nrCBwwMZQ#-2ehuft zfxh1-Ihlzf46ySV1I-C){YjnVq)xTyDSr9)u9KN&V}c~VgkBmU^FgF(1`%&qYa#Cp zWP<9h^K_wh{ry|H5HLsWajGOr&c)$oam$ zBMYaCY)r=JL!L}0i4ETB#c|h(ouY(gZ8{v>q!KE9{Bg5oW$0RCD>#Q9y;ng4`_XU} zFexq#)OTH)EyZp;py!(V1_r`dzR%(c`4ko;NDU>ja$zLPy6Aeo+QvX%di##9)cqq? zNX$;(I@(e!0yf8v@*{^^ppv zkw3eKHmiRgZ{;(%9klbA`3;>7^F22sNHF|9s$4Jc))SG;`Yy|~-%t@jH}H1GkLlYu z2Z;{@1mVMLkH0e&gu!0bd@gMViIzgn2I(A(;S_qqQFz2#Jy&2uU<&CKIzYJ&e~{$D z#mT@5*&qz(Lb=s-X$K7aO3HKmGFGo$|3tnlGwY31I9cLE{>}Z}6mJ(17Rv24DqXGC zbM-w@6lq~|=*2!qob3ktTcGe>Uh0*DFlDE+a3B`fet|l7`%XciU|8A6)f$9rEDQBO zKJ-$^`gMHZ_FKSTrG$RngKTwQ)jkm3FUYEW?263fHBB2z3MR36 z`)J@+Hc{s2ro2sg31k9~h93}ZaIUtz@-!wq4n*ydEhZ1jeTV2|2@V$XUq>cyd?qx( z`|?fNStTn5+3dkE5B{#lUQ3?N5P|p4n|zOMKlNtMqIp*>zn~EJ={1+BOH141m!Kuv zxmcFN-&2K`d~X*dwB~7|1O?qJN~WVVRFxU$E*cg*(emF;PsVkkDalz^;C&+mZ>I|< zk|`gm`mtZH*&rU4>*KVze00uXnF@1>&!<4<7gvX3@3Nj^+P*f2j{uv=2j!LN=*l-G zjf^)=zoh&=p^l{iY4{{lQ+fp~&i3}$FMS!tXN}$8cPYH?!pzc;J9duY+Q?6$N!lzw zuC&lXzC|2WSm<@Ib?EKa!;!^o!)#W*G2BsrW485!s~>)nqmqk^>_U)^@tTd4{d06AU@4;rmT`RTvkD+N94=2K4ormG5cU;WM_&>7zh#^wd>oe zK|5(u*DT4ML?!qaehpTAyRIW|pNek@HBi`7)mV&>L(hIN%Z_7}?RvEE}heUc%%PH|HLs*ReO;BSy%U0&;eS=;ao=&U&tVAAQI8{I zc{&jPGiS^1s=Lpq%aZVdji1t>Be4m#&!^IIe{a(eZGpZ}dwM<0W>*}OZ{YMbnls;b zrPIVM_k0gmx^`_3Ms4byPCW}HihWsS)ST6Qb-c`tW0i!z`Kccih;JP_F5VQeicgZL z;2_7b%SQYe7ZNifU589jSGw`dp=Xc_N_8Jx6(N^DPn}Bn4(K&CZNYcm6Clb-ssGd)UmxUQ7dbGRd7vBf1zzZYcDiF=n{0Q1gVHnqY2tN6p4 zk`#r{mT~}%|3_c5F|}-~_*bneM3YX%mhGNJG8dRu^-fB&DCFH+I5U+Gw!sHAm@`q0 zey$zx%%B#JeoYVh((rH;&ZAs#?H3o-3Va-^2{@R$z7?)MfMD~tcoOy`KVqrsvvs7L zzN$6cFrAY|2s?DND%}6GuL7qVe<&&4^j*uuJlWaDZJ%*zf>rrT3x;y}#IFVVz$^JR z&hA=BCJFUn)dx}Fjmu|V`;a8QNrN;f=8a)6Ujab4T@L|f0s^1PsXYnISt>?PBC_$; zq?1_XIp@%9udW2GyQ*KiB@RBS(OU$PTJJNIgQYG|Y#$*nLf9qXR=Nl-vp~&gk}qY< zfF0t0ymcdFZ!7+et$Ye(YFOF5U}tZc_2k-(Z`_K%^7K24=f0YJh-A#5Btb~+h-U=- z#5m-m1>$_);mzmIoNTOpOw~pQcN(^BjL!pB@LA+^1ZSLn*_MC8C@9URYsMr_hV6yi#&bw(nB#X6}WN(mOIG$cN8} zM{Trz*C&ZgJBGY|sj#6$zEqsBIhZNL4@r7+;$&-BE0b(>_AABQ=c^L#^Q1SoTj#ja zU;5;NfB29mXDk%r^d-;y=4*8Xu95Tmp=(~898)4mARSh!Jlo{5RYN}5TdGZXx6sU$jH)bC zD(ELdqn+~aHwUx|ZV*&`zVLddz!l7EGStW*)aC29RgwapqJhboZju~&?uKgH45Y^< z9Lek#@&`Viqz5BDki&GEL&jYhUd~p?@m6~kD9HF2QZ7S<%elRJ;GO=*)7BDRKi>5L zn+9^l*+@b=ui;>|gi?)4*1{de36hMZl`_xPjh=qoK($ki6n zGx_af0g^}=^{DN&yyqSrI+{WaoutF6;pJU~Dbfh~L;T%W4(jgN;~r2bo<{R{2B;UU zeNoSmT_vP2Eo?hB66ao1enSzRx~ZO$-p|M!YjQKM$my1@1-~GjA8B5&9&m{5MpqdY z6?e-X3Vc_SfcM>Z=G=7d`Pr{wPZO+TJ^S_3Q8S{zrSvxSfeq(^Jbd%a%<`8<4Js1r z3vqe75FD5X1FU&r>#m23%}!$ksRzC}6oo&W7pbV_zKjj!_?Ngp2|2?`N_k}ROo;GN z$Ls9e{M6iu?adU0Pn3@=d_|t~iSLw>?AnO$62V;-jni{uF3CHz67+1nCFkAhdw48; z_{Y@fo;>haW>snv5(b^O5!rz>P9DBsvckg&C-y- z=0XOe^CZWgrp@x3OBrn24BpA&Qr4ITlM>``8K9Me_zg@=vzWvExoY_9>onZ*U(EjW z>Jb(jf^gD;78>ct>bN9)r!GIh3^yg~U{+vJ0tabK%@4c_jb>98`x?43MC+5h9lC|#W z5jeL}@QhF5O}k7dQfFyeB3nHD$aA(m(L-B^4!F)>8jIAd>+z)KJd=LOaKfk7A9%Js zwt62jaN%HYjHj#h-V;~4Th8PVs)5B-h(wGoB^dwMr`W8-L}Xaeb4X@sYD{akh{-JLcrZy%|z zjw2dstN@NAKE?t4A}O65$WhDsIMbiXff}m}TdhIxOjuSQ9#l-u9f`uxtqe`yA3@1> zOLs=4-0e+HQJGM>Q1o$7g%)snYH;~-o(?{aQli;f`@)x}J`#%Ifnm-MiqD1p@!apm z*6(Xez3#w%`PjubLjJ>?+r#|3%^lRbWnbNsxKD5AZO@qiJMUZjX)ZHmcU(nxQMb*1 zLd6HtHLtQ2VIFwW&NSN8{IPjQWU<~&sotX~=5H@{Be<6)pcg`H;+w|pa{}i04Dg5N zz1+SUEoS@1-lswyHAq_r!b=o36un&lUlKw$i_>{;k6FZsn^7=oj%|I%MAP5pO!LiZ z6W?SqZ}qWygg(PWd&jUGDDCg3H3=yiNYiUm;@SMC7VfTi-_Fv8<0Z~3S#5L(RC9>Tr7OxBA3?Vv6MM653_GcJdAz=m< z_~mo@D?63Ib5}W>4z+p<62DsvKbYc5;nnMWdP+$EBdDlj9Be|bUC@l;O*%5Aw7;5u z`AQNSZviLq-%&b%8Q#n>XuW3dJ0k-kGo$t&R`4Lu=J?{!uaK{@CZ` zz>8o4Eu+UNcux1~wxhUs!ARZ!y-z&(4AdHpXPOep$H3or3$X+zV#ro+@Kjt*A3zC<}-w zDuUP_ABIBa)-6w$gZ0wh$=WZb`C&q}QYxxCUXX~thC~0AD8?+2*54lB+{HOxdiXo- zE(mC7tXUKPk)Yj=cfkAC8^O7iJa18vi4cuF+hkH>Yjy6YFg5YIeRaymomTAOz_x^* ztl#fh-}r}P)R$-5`B!~v?cwl;O5Cg8NTs`JEcp;A(IkD+;nHO_KxYm^ziK@ZOxDoCwr^M3pW_ zG48A#NZYXvx}y$G4djKk zt5JKo9#|izQiyspL@Eo@@1o9ZeK#bZWzQrA{Xk{&j^hqYJ!uC ziB;u?5DHuKO~&4Imly0ZZ`QHm*MfU#2=XMJfhe2RPa48vpj_7l$)CG~W}XYhR%SJ_ zzRbYcGk9fm^ZokoZ?9yy7I~jUafmzI@cBGn<41Vpk0Kq|r{hXHZuPI(U!hIWbCaZd zuW;lt+!E)1B_?=6oUQJ;b%j02I6>=FT_?*q;SYb0G1ONww(ddyw#NIxI+G4P;~B6i z>2PIs+U1=Jd?B_*_X&PNt`%YD<#*5{riCo-r#VJSkQJ8OpOW+W#ExY;<&>pxF4|7k zIq7#3rO+uww@sCBfSwrLS@Kw~&{$7D^l_BdmzE}IBnGbWs~y#?UCYE6IZAA;hG#mW zV~ZIYcFl-bt>ILZf3uiDQSAD^Obrj(tQS?cY(y8C%5 z!}%rqw_LXJ{6sC5YG9>bID+Y;Qb-COwYQ>j%t_w`tsKX8j5COnE^#SNZ=n$Tk&%32Mi=nowF5BO8N9>qstEQAGjQzk4Z;443_Xn& z5N6I)!&xNb@{P7YiN({tfDdu(^G7ID{^P*73!w0Ng|*#P`Z;_bQj+_nY&-zO(QSp( zDeFu^m0ElUlJZH`SUPULxk@}Vt2}Sw9#Ct4wunA{2T2*eEXKf5|EDjrz2Us1u3_=8 z>gO#1hHrSAA$1M`i4f$HR9CQrESb#9`a9LiH_1Vs_$tb71wrLsg(PIu-!sg;rf3UY zCNy%C1;t-<--_%Y(5=*|h1( zKbvQL8AOItPGht(eMw>u6bn)#pr%~)@@>Y2C^|_{H(Sa}Ylm&XtV`=n8Vj=eLCJQ0 z$Ol#Y(@5YY<&$eJdW55ma8{Asz_Gjs;B1;{B2E=c4`n$olRqfmMxkQw(};Xsf??R{ zxt~IkN|V9LvIHeID^-^*k#Q*b)xs+EVP)BvCq77!Bh{&Q3aO9g<5K3q&Tu5ub!Uqq z6tGGld;b6_*}k2J6%G4@Q@$6sFy|5}y5x;ry`^z0n^WUsgrB|WKEY$L*Tb6`VnrP~ zJ3y(;ZhaKQygsL$$AfAv`V5-y?Co1%HilO!M@LzMi!2_1Sv*mF3Z?2+ygIM`#0UBV! z$*oE&a#KcNAb!WrhU;y-ENvetBInu}%Ef8#E@{%0sA`YIX37B~9TrGaWrEk+o$9$B zAw3D@N{pcH60KUmdyw;f+7aY1KqD@bwL1q)&IdG7l}Y+-H!X62VV7YnpBU>jVt-ih zJl7e-;sA z!3nTcOC*+$rp#$_RZvnh4BMPs z2-|{)k*|A$$cc?Wzhxj*`84D>oX%tOx6j9SNc}L;JfK5^aK@j@h`k>hA}8+J6=Nb= z!t`f9PNPG17iUSvlcxG;*dgEN*>+t0Q>fQ}Fc6DubU3xs5x>bJak!BA_bhG;Snt)! zQ2ZU?AxlZC!Q?4(jn7^}6#WR_obpD==bjq+!c6*gUZhz({;p2OXHV3EM>ONg+ITGg z(et8H>{&8;4i-!z?ZCTYg4~cAh8}~fC5*xKJ&8FjvU(?yoEjzQumOeRDJ9bl&Hnsa zH4H4|H1f#p)a4%v+DF^*~6 zk3ym*5BT$|@#A~3=;JLo%d<1?((9P4cPQ0$(!KI^Xl4i5^~3Iy3zWS}A`-Iu>LnQ= zDa$3a1^1OxJXsB|rFoa_4$^XaM_Rs}dNQjMxlgFM`HXDT2WfN%f3J=Jm3ixg2H=ZV z8-59f>sj(x{*EsePxu5qW)AtEIP}MOm6qcNmy{7qtRndOr?k4Z-^?y;wz?yqcsDvX zRc$ATV)%^q-q4tt!x`RIfRJ%8dIQh43p>iwx zPGq|GJrTRvq3o)J=$Kp*VW(j~bT6r^Q^Sf48WNxP-qly???ccN%||Cmfzd$o(uC0| zo+li8;=*qVxYrwQw55RCy4mZjnd0Ba)ALQgO%hRZQBFCW*95f#K(_*mk_5B4@@K zff%{LD=7!=!39HP-Yovz6i>qM*4TUY4hU}{q!Y)VZ|pX{4(}3Y4cRX+qr{ryt=YO& zUrUV1iD@x(X4L<{8}MnS{NbB6<-^3!Lbn7{2cEieGjwy-r1eLpA!_EWR>w}w+7Hk> zr9~wZh*QS?4Vf2U-vLA~Pc(k0kavuwBo&;kBsP)NH4s+Clgt?UT zL!W{%JRa2VB}Ce>$;B>WPtL$Bm{qjZ4GpcU#9W8PdC!8_kv}!^xhz)#pk|N4aoa?1 zNeT4js9#^cmNK{Cs7n!Y;F!}gqs@)q5*w_FL4t-dl?pkJ84hjETpe-ro{% zU?rhPznZ_b~_=A>@sO6n`!QC{-aQOXG_)VQalzjPh3%H_e<0#$zM*2S%VSwOB9W*Hhj1 z#qh;w$PD5-!1o~4*o$~2&FR9~;QNef(wEN=cnrSDzduOkX z&p)4trzI2EmBg<4pB0{*$ z@0|+2LUF$Y$c-U~Lc)2c!yhE+Sn6Cz%g$Zd$FI1mBGTv)!j#ytuY6 zuMhFO9U|4iY@b_3;fdn1N?0t-N4ZGGoMr34lsY+DT1AhX$yquiFL&5lv302d*OTm! zt#nvl`IcgCDwVt;=tMh?_SB+`sTcNJITS0>=}APm8X9Ap*WK6JNNtuJ$|O%jXz;&R zC5U+NCMK0uUy_IHY{&gD?`2z9L2uzotjqp+;S(tnZo^b4ABYw(ysGVmZQ5Fj#&)GWx^$8)GXy)s z_t>kWFLO(PL8m*HJz6w%9~>j01Not8OW5AIF#kBA6b4kj{6TnbsEq z+i6*-@!Em-fB-eFF-(bP*c9IW7$q@;S}SVm?)huJ@3x_*CdVZo$WRKptk4UF!y6!Z5(SNEJO@bJf->vXxax~#z>w?)8 zdms8T`IJryyjSi}1ieCX!s{lor|LN2T-30juAta`NL9{6-!Z`eD95=7yKxl0$oa#OTL456C}{JUm%QrVtwr6rxzYq?MmG9iu77UvIs7ADKl{bl z6y8vXU+Wb1Ej@{0Tha}WC@WfFNWUS|LtBqwjj0ZO@6R2cZrwjUsu?SXK+zrZzUqg* zDsZ#>YiWje?=iUfLZrng5W{&*Bu=~RH~x3a*f3#gSl#RSEV}W{7g>piIur(`;8B9h zi+1+fEJ~mpkfkqRapbv2KFlI)8UL(Fw1b$J$1_w8C9x@^nIAF8^$SApdI%*7T!lPFX%$xD(QT{?$A5B-t0m* zc|}BdpMPOZ0!m2FGj*9u)^=OS0?eDH*2k|qYB$`5Gwh{si~tD|q&OqYzz(!W?Et!r zDCCXAPAN0t2?~xCZ}IE*1|cdjjX>q<3zu?YtzQW87OdyRd@!Bz?MCd;OB5sf7yRM! zxva5tHG;6+_VfDUbP7)chh&Gv{n$0I7l?iElAh}Xe@KEJO(CU z*)QO!$p7&U5fgbUJmYaW?BABM#vPG2yxr@E;x(R>!Tuyo3Mkl3R7D%dUrw4sb`~*b()Yg)E5wQW@!|ZP&S9}A0V3W$^#a*s=LF$f1lzlJjjV;i0&Z^wE&f`bJ zbh#3PQFVw?^GOla_ebpMwIP?v!a_fc(SL?{!-q?7qJtgNBB4;8$BP}<#_m-Snwf?h z8n5ro@Qq8BOfac0n^B))O#_J&pw-|YSSUq%uIkaex4yIuc0Y-eRGcvlU$az}2va&; zX%Cd)JU{)i=(lnH_PP(x$@Je^S%n1?F$)GoJoX$rfP%!{IfRbqYrFnS55s?z5|k3h zI4>OCATt;g7Z;aQgrA)ZkSBo-SpNv>2?-~^D(QqN_)qBfKQzHD)4xXmCC>alJB_+G zN+y;Ps>}DLcJw5@#s^fm$jVS8f;mY8y%8&plDhF9)#7Q3&n{n`+g5q#jRSEcd2A(< z$m8Rg)xHC(R_~uYQ^V;Sogycb1&PWVtAc={t&{4(mS7W-MKuQ!>{-J0@{aI}pF#Z! z=T+N4GJc9kx1YXeW#(T5o8euYwCwXq%QMe<>Z7Iy5z1$Pv@ql!FH`V<=rq}c*h@?H z6UK)CGu^`^eYS>Iu_PrHG8Q-jJuHAO#&6X)m#73B{PH9&x`|(lO_!LN1RQl3_BfQ= zuzkro`q%GPx2nnzOYVW=pshl}pz@gBTy-{(ktjkK>sUu?~R z{y2I!2qpIRT*{QdI_4F#&}!_Nc9!mvkXiGV=e+$&C=owg@9PMpy-T6<#Hf=SvDL6^ zK=ul-Br%W9U}&c-OHKWJMn7xNZ8_K^4piQlc%GQuq6Ij)ggAtd<}z6}N}8m_@h zK1XfKwW=U2Z)<$D46FzB#?RbyJ77Uq=o6 zk4@-@^5iMow@fWOzDmF7nY=X!41i>dO6z-s=+oD@nbOWFUziwr=UUbP&_l*)MOr6= zo(L4Cz6IC5gE6)5B|**jQ-8V=Ci(k$W#oZRC;jo>-eha9Xc0(jOij^I9=@V9n4f(6 zW*+OqyO(D(BZvv$>|hv(=wL8eSI@U438r(Cg#F6_hYsP%Z-8iQdA&U2CSfNl^%9dcQU*HkqQ0hLbQQR3U2% zrTaG%IySljVyMKM!d3a#JPDX8?Sf=(&?@DZj^L}$3*i?^H!RLflTl}{T|$vBTOY=2 zIG)}vn4kjLWn8GK&8Nz3RlL6FWV6EzMiu9|@Z=xBA?MrgoZ-g(ouFn8m$Kb;-lC7- zl^_s&g)(NtxJ^5>3tg%pVPquNIW0@Y`~@C>mQvlEb}6%Iln?EPkmb!y3rKSIKa<)5 zKsz<^#jPOM&jlU?^)*V{JGDF&1 z-bqnxy0Z(zwnS$7x|(Zc|HP(CnpQkFZg5++Q~?d~;-Vfo2ERD%_8Mi) zl|v72WJqLCLwyo)GmZwwLc*wbhNezrs5D_Ln?r*5)w z+(mvo(8;>acPpM6&wzxO&~VuNhK$=R@G*C78@Z%<|*o%mMK!l#q zK|HWvew8)*W$bN^vtlq3aIlD$8~WIh9B0^5zMX!j-%lvv%Sk!R-RE#P>Fq}zyWTDz z>wky3sUh{awNn^=hOz|4|7!jbnq2x&bV&Vi2u`gfL?V-xwBv~`aWMSW5L4%h!)UTy zj5^whYoho=2B@h1K)&g4E5FchhsyWjq^XSX)cdP_g-tsHBM@>4;nqz%%S0?C<9op6 zEdjLMZN_AQX8vOvxeo#@YW@T(@WwT+zg?fvhZ_5CeT*c=n5G<*3Jxpb*v0cY?sBaG zG(Jv#*z=4#=kC%5_{@eEKRhaLy4)W@^uTgY3aI^3K7=GZ7A<_GeP+<{J-bUqrady3 zWKl^4mlnP;W2C8?ifYHNmFThQ)pqYL2?&(+L(PlVxOisW%`ni5icbCw$ z#s{HaMR7Tls5X)YP&3(!p(n`jC@0jDejDODT@NBw9!W8=%3P+tA>+pCY0<7Ws*K_BPU zI3l{ppfjl|`gj0_fAvdIQXQajnBhnRXtrLjBl48d6AO`C6FCvr62zJcEcnK5DHK=h zE6R#>`8KSfY6(iCQI6|EM)=O`ktkWuwkLb#)6m|ZXUAtN3zygnY#>^jA0*tIAV~G* zgsj`ZEZ>6>KThf`5f02r^NzI|V)wz97%n%RtLL26gF(8+_~x6#-p{k#daP_GlrO@> zs6om5xnRyIX3NHUgUzzoj_V+W}uX@U>*$-(m+PeVQp2f0g{gmmVX39!n0m#pL zyQ&rc;(UpGz@z=L`=+Jq)mg|ItWi(Nl5&Jg(q+2iabRw!>_@EEsuU#Lj+Rn5cJfgK_{q{+GlnWLyz5OdEf@S(*VEF~P5p^(X%PzSt99A!4QgNg$y>aDl?0!kg^l0L}cKafyv{kE55t!$t?1^W0j(p~^_umAmXs6n@^-e3P(A=T*Qy_f^DB=BmaeV!>IZd;Y^ruyQ# znxB6_YDf{D(Pb$)ML>F0(RTXYO93r;`_p@?bb=hL#iqTZI)%1>{?bfH{*LD&SNQ0= z<(aBiIxM>Y3HJ?<6Yo)g=K)9a#Z0yvHr9(7*g#C4dTIx4i!3DxOnp@+Q>JR zQB3=7f&_PtcCgg%nElM1yn%={W^EwisW91wzkl;OUEq1O{`GF4gFTokl>xZCje7vf zDR_x$Wfl918GW@;NTTdP2qzw)knTnqlmm#4HI7HUBYzC1eKF-^yyA*@s4ek_SSK9? z(McGy260jdmrj+i?1LgTXS=3yZMD&(1w!aLTUVR=^a_uBPa78u4!+($lC<10#8w6nQy!uuz4Yiq`fIfSbKTF zMCTM9-q%$=lwTX?5qWyNHSxX1UL{Aw}RGE^HAkV@BJ~?BCvv!S8+^B z*CdGdQL<&zMeba2Bm;oKo^SW&W5&NhHryVhra{Q}=FhybafBq>8Nf8|iQmr7yhY7x zR)xT`GqK^2VUa6En;?zM+ehKNu#U{cCR;*K=xG>O>zwM3`Ad=Vke$}7e-qXmRXQRr z0`51*V0m6R*(I5m-^v#PKHR_IkJ+}OpSynY8rU6RMUCF>aKJaWB)uK!a#vc&3voHA zyPoj3qPp3d*|uOQyQ4j@XY6^IvQmmBw$QBWDYqSFfHfHs@}1{7tA@#jPJ#j(*kV>{ z^&7IH0(YA~BNuynBEvF3(3Cpoe0uoeb6k0~!^!S6+U!e|SMyKn;45;sw)?=T6J}yD znhv~2#&oRbJVl&BEv$J9@Zrr` zy9VRr^bXWiMbP$~Z3p^E_Qybhl*zNXFX3H^A$(KNt4h55ybfPgy_EgvXcqe06ZnK6 z0nvYQuos9hrR6Tcvx07%vA66;Pj}J!Px3uKE5UA%jp|um8?{$)j=3rjBwLed930TMt1$xOsf?QFjqGI?+YJ6w z@8ai6k#NtPN4H2H*!Pk_z1yL%*O(V1r|aifPPwcOlUQgad^zLZ>|=)DVq0MY!T_4- z{VlA1zFx?vI?F4bZ`2Hg%izp#)=OAdvr9uZ)w;2;00@^7bv+e zi&Tuyz3t`w77eI@7kP zQ3A#St;K~5duNOIsp5g*edDIv?7gfFVq|SDwc>SlsC2O2vcbk9le-9OT48PF*QL;N z+6BY+?ao*y*pnT9x#YXZ>+qz3-{__wc)+l91Gww)icj+|Q%M2y%*_3=Q|D(bouXo{ z@yhSKbdTN^cs)l~M{3Qu&fo8k*xa;1lAx=XZw`s;{FxMOp*>u`c(v%~$P46((b;SjP0c0Z6rNv)6`P<)@`YRsXUQ`b4B#uq-b> z8wO;@7B;D?f?!-D6v^zvPe}I?V5jW66~14S0~a@ztdL#Zye% zgASjEI@nNVG3)C(_NX*pWtERxw7h9pvFbJ~LFG~EuXa`CRR*Uf5L(al8KqpwAQ zlHkQXU|;D8TE7aEB;wzd;E!B`XuZq(igEfq-6w|Y(b^|0fJk1I98FTZss=v^TNHhb=w5uvl9g&rSlJAnH+e=a(+De-~Yh$bZ1#{&C6z~(nvM*Mej4-H`sXoa1eI?o7|MzhOw>qm>Cgy9x7 z=gR8dl^2w15DH&?hTfsmCdgJ0-A0Ii&+%58TNYFtamJNcvAIg>Y^Z6TJ?f4w;UadU z)hU@k7v~3HCmd|J`oy!qQA_W2mz5#-lOpx&^(>qVK6E|T2qtmp_oVhQ&0!% z{alEjOTHoH#gAqN=_;Tp?CiHw-ksH$em==0F#nV16CrAB+xah!7UbfF_C2{IC$5{17f0Fz zp%47KDa7CQ@`=0cT1;CW8+b~d7W-BxIBQNq2n=gbzgRqzOXK_VL;_7=O` z+9UMv@*gVO=KKEpt78chdVcs?EZYfo76E=k?G;jy1px2PjR$|I;efsS>HD-Km_jw> zt5Gjz(iqWP>`c(}xr~$+LL8AKPg>o19K(qp;`>L6cSqo)U1t7yoJC(_=j+G|-gcoD z{_UyiZ$xQYQ4-U2is%SX!B2G8@Oj?@@vLReXy`44d)DgaHK{HS6xYwI`!)`ra0jAn z+l|tt^OWJ71j;b`vLWJ|RqJ?SwBR$mr6R@Uzz8hoX--FfOmDE1qw6S|4rqGvr?KbS z>v%vAcpTmC!pOhuWQ(GQppEl*w!nRu)%|?EtlI>F@jGp;#t6u$jJSCe!}Dhl5(2y; z!lYXU&?g2Td?TsPnaq^l;s`BS9pTHTzW9>70A9;foez-w-Fri82)hvD3XgkS zJZIR645CaApOF?Jt%r1L6JZGjcXHsj=H=xZ_S?h!sc~P&) z{LqRR&0aWgS1j)n>+N;5pnAN*-|sC2_ESO@b_1{Pok0Wt`3iHP-yX^BtRlBvKRg!l zyfK~|5l#+!A2%(MrY+K{=^ytCaLNs4CY!BMUZzCNG!(+7q5%_PK%eS5944}V^M$Gqm_eQ#2|ZS`o- zbbA54W1rkNt%)w?I_RbnR)hh2?n=Cs4f|8N!UmVIY?CEg#`v-c8*B3r?w^Gz_0GSa z&+MM%uL&4`zGq6!egi9re96^?jpW*Ty z?E793VV@O}aaPQ1rTn5XN-tci6ny#!bZ81pN&U>wAfpd`39HqZ1&L zJAJbyKg%H|$~|8o^0S=jfj85|#d4;fuiSqOs+B ziQME(DNl^1R1UZQCB6S%AIq%vMU~Z7uJ7{f**OBUFX%G&Pt!6Z=-cdOlCn*zM)+=I zb&TagLJ?@bCBaoOjA<+lBNi zZT^OG7j0)H{e@<1+QoYb2M{<|P*Igi4*@C%UK;g?DbJJzJMiY@g>mD(HjYS=e`$iq zFpDXs78dKlCCa?8J`}^EM`7q=hS7VPN}Ls9_J3|scLTy++oN5>r&Vun9UW@UrRk$< zT}ED_^H-KjLU0=roOS<(E8GW5HOcw0_>0EDNLH0B(KW-=5k)zoJ?CFSBZ29@E1;%w zmzC(#xilaujssqEs*fA^8jiJ(?;J*?AQq0B3@2a{qr=lbD~=H|I!!$G42fLpH39?S zV1Vp!-_EcuqSd_N&F?Do=H5zl%jb6oCew906j>3N^Zj9eJyW#gH!B3UMuWqMZS-#g zOC9ssP1{h4uWYAZQ=MOA+7-t^QW4cj$893vB*i~On{Yo_QXDsTr^FAk&8KlqZ!!wx z%u&RDoO{^~bAW{D<}=x}(+!QsWo07{gKiv^n%noIj6EciwuhbyvSZJfB zKE{5=>plRLHT<4R9DvN9kx#l=jzy zK~JT`bi%*WwCaKcLoO5+<5tJ3$Z?X~qPY&q=lNQyy@t04njA+XEv!WDkHuWx>_)dV zPR`?U+KJOEjMxO>F3vurA-CpWT08b0K@97AOIHqmeVpSI z%$XnYo|W*Q{IoCN1SQJ!S-9Vo9>Q+CR@#lFm0gb+8toddTjNpxZ2dctXP7r0QoWU# zsCcyNqBH%6i}9{*U5?w`#jqzOk!t*qphB&lz7p6CU$LKEVrq^auNJmQgwsp4nTNt6 z<4UPhZC;u%4h;{#T~q7G6SrCkmdu4Kv1@eH9F5G4v^fQjXl+QEw|Hj?-5rPtOG~-7|Zo({+>dMK{g~KZyyWs0)dp!9@&2QJ+N!8qOI62=Wnl=;WN@3 zq#t5Quk z)T}$Drc^(H<4JIa`g?*GYxG-NufD(NTle$PhBT{^6Z(45#|WIxa!FCnmAfsYWKZZZtZjTIVNZbM@MDO#^zpb zkLs-7y{1ds%C#+VbvLvxk+RDwSc><~s-EncY$QO;$8&t(zbex0k>w`dgzvvF?x>kBiHX25$$gVI(*^ zTTB+9Dr3*=LMJ33c--{F5WOL-{{95*fqn>*F?IIo!cB~z15Uw)!A_weVo3JW2pP>#hcF}_F4UeD)O&GeXLWij#ae13>qkIkDO7~m{>CAo{WQ*r+@&wCj6zLF)N*dzp&)>L#AsrT-<$X!|@_kvG4bPYgrjZ z-`6krvP-w|n(dlN#ULny|LcV86A4m{`^6DmlTV(-tg~nqq;t~NYVM*+*Y@i}?SuEA z#4`talfu7*a09KPevV%TGV^7YC#ou+T9DE}{s9V4e%E_kux{ z1n?vDQ~l6MC5Fy+1&6;lbwt}()pR#4R;^0Rl(|UnjUdxa2h(8vloSp(58=bZOK+$7 z4Yy(k@NXo;jd|21YOvRCuEGMjoL~OSaab4ZHeI}vn3gmDIO`cr_=Msp0kcGOU@mqd z*i2Jxir$Nhx`0Nw=5pMKh{%ANAbFjj<8gbmtxe!@iP{aL0gCFYnx_wF@&$t~x0J02 z`S>aI)TzSp8ylIzy#{l_i!C>ZlJLYq6?BFJlyk;lC)>{x!eSPY9#?L4@AZhs4apOP z%y7rWa?eLTu4$XjzrO*YTW^R;P7G+*o8&dI1>cWi#To|_$eK1;ihzry zx=8X60Ycgf+eI+`q;M4v*lgYE#@JoUNuhn3lH+Wr*lC6yrc5JwVISeSzE2QFQ9bzF zd+%(;b6Z6ngu*H0h8^;mJhUUM%71dhtCyl^!98HrJN@j9OZh!(*6NAEB2JHnzg-& zivR@v?WF3}!S%am4!C){dbZ_2mgr=A@luw54|Xp50?za zmfm2RUHm$n|IK10eF5-|4q~sM{iDL?vp;Xm*YR(|$8x_CC+K55oSR_-xKsU8(?5sS zr;c)`Nqqb<1K}HJE}h>sSY=e>mi-P5`OYsHOiW{u6kGrq64eNd9IR0;0j}3B8}Gsg zX=<4G#6muYZ@u|#l!Un63E`Ta{e>@47~yU%{|lwD4~V9__u#Ha-_oi62g*c0F^zgz zoNAd72k`8#Bnh5FDPTpVC2dVnJO!8q^~VFB?*&jQKeGklJ5O?g$A8}ryv2!yx^8M3 z75ktEs?ojwyPS74y=JL;_7OwGlUR_0~Y5g`50h$fT zI(gt&+dQ7J!w9AGarAOoGVEZ=oU)Ez&82AXYo^yr6taI4sds3%~d!I(4xZ%cHUg}>E| zs%5*BzucH_u&3U~vEjr&!N3>InK3`?$14BP8~4g_Z9Kt>k%d$2{5g0zWQst(`~5*= zUt;{Zh~*`xjeg&6=1QLFUY#FxLoZ(GWw}X=i^;C_8rEXtolJUg-@N@MYDxYYxc=N>I$O#NU(7NFnBXC z%<)O8We~Kek>4MOV!3x5ay}#Z)}akx;^9JpmtI%;259p$EY7dO;Z{Q}(I6jQuE~-Edvz43 zVw&c;nti{#4Sv2t)7({k4xmS}J(|QD&=jZvj7Vrsv-^=HwQ$P#qgH3y#aFVbn%GVgzETDccg11dLhp&$4G(#RgY)m`Rab;bp z=9k&*N~mKzbiH?$uaTljvs7Q?k$5e*yQeowx21JDDRu)8C(A{dix8d7N(ou>OHg%k z0s8%GRLajJd}hWTTZ6~cqs%x}tR$AlCfj@V|55ec;c#```*=j}M2J3G5Tf@IBWj35 zZy`oWqC_Vlh@->RhT%5i4+V{HG zz1Ln#wYEQOHs@PZ^rAPG6r69m7aH?ryd&bT5LPTm7vr@CTQC$!ZmpQiGk*3=!DsL4 z>xJOn#5WPDKYO{g#;2-E{_gY4_ZJK!S`h75JvG*1aLj7W+B(iQ9Brb#q`tBKpY$X8<; z0ryb;6N1y*NE_^|=Ohegy+LWb0)Hs~yesSxIr!tmz6Mgc?^b3%x)Mez{9LBba}+uH>6b(((2+6Gs)5xP{gsy>Rz8`x_T|W#Pa_UVfyr!@#>F~* zUS3#Iz~$n40)J+MvL5f^L4?IOjaD%9`I@QBZ!To>8N-yNA*_pX1Rzzb*>5vBd^3e<2PGx zbeR&>*DPLkPEAh);#IAFYBAh(h>h?mlTCm6rcyjfQuSGv?O@+^`UuNw$C!WFcUYX2)?<0Prk4NKHBM^}sbX!pkv-j=P z{myMa86v5?c4+dWEVUJs48pL`&GZH&`%|?nP zXvQb`0?PWmDc+0yIeep#fJr^z>afKlDzVl%#P~i zfF_0W(cj;6$5oxyIE`H8`)$1J9m+1pB}s)8Hn05(mF7(BSDxjteOmh_zm~U7rlxuJ zW#irNA{HtQ-kb-Sm4J-S6w6UmMm9PTmFml{D}BBbD%3hC7iqD6S6J9W_;dkOjz6(y z*QyJR^ekcV-gviIvpe<7`Hpk^<3wCUXv6dY-FCKW~R+Yh78`N>ofotzWzwd_ zcJfb@V^b8^@ai!x?9!}fA=@yW>BG4g{F1zGQy*<JDs`BtXC19+vjb$=h>h9&)N$*jaD3LU-a zcTg^MWRM5^EW$}C=`>CF;g zZAF_|4{m=1I^kykrAZ(ommY5|c|Y@PXjL{Bb<2~V)1H_&cHxT*uYCHyM$ygWW%lBM zw1J&Km?;}L_b@J@soL^Pn-YCnT^h63Weq~d;8k#L$^Ig-17f)+;Y01oxHNLTd^6DY z`$Djm>)XY_9?*7wfgwlcSeRF@7SE{+kj8A31Cog0`!2f(7SU!R&eWki}o4Qo}rA=mtM^-|vf|F2uhT1bdBAjj@#_-P$XxK?jbDsiP zwxf%l8}jX4&Y-}rYQ$N#0&Db$lt5Yj6BIYqSqB_N!N;tsk^ zRhG{-cl4T4fiN>xsvc6z?h{?a$dO~mxH^?uZ;hIMyf+3{pjy50?NDeIhNt7Ci1*RS z;S!mU4CfMOae}LITYoy#00lAh*>D~#1*%l6^)*IwYY*VO2w>FuQ9L+Kb7Qh*W9m= z%>bA#BI9R?E0kvR)>qtqGb^z4uEDh;Su;ei#ear)--Fqx$VKa|&BkwtFU7#r_Bp+f zm@dxcCfetWu59S<&vcxbVh$fJ^S`wKXx_~t2Z1VcTpW{>fvGK)YL-^m_hs9DV(JSxFmK_epo+4n+29SOb0jw|-I-Qv?Kcq-pfX zBLl)}X5CO!2sL_3(&r$oQ7>*r?iu4XRk5ugk~dcOs9~(gyyerK0j^fHjBG6ww_?05 zvIEpx0e&~jtWg6k7C7J2-`WAmkFH(itm4pf`FTUhW-PVK}+7 z2)|VoaFwm9WIbk7D+X7wj zw=wTRruB@ilHx4Y(_#0#`W{B}RZ1yfMGpPkEC!Q{jq zn#!WZUm5FU{lH^|mm~D;O@{z~#KJ%F!=;Z(YQIv_UA5AoAkSP5)$u+nHDwfBa{WRg zsl=41CHSHVF`mwh@YlU(L!BM_(8+A@9$t8q59{`4{EWYHq z6>GF|ZSgQ-L-=vn#Z!TwGTAu&Gop#S%tG4oOer7~J+##D65}7>%MuCtjWp^|F&=cnb5!0tAKL^NK#QWwcbj3>bah^u^1P(u$B+TbO5vUuH9q= ztVJ;gHNVa7xl}WsH^`#ACPAV+3)TIgm+4uNcpKFqob{;0Kzw*?L#>PEE?veA8*KNzP9CH_!sWW~INXwE8B`9IBQx(()+M z>4j7y_7%>mxL6x|FD=ALSG-*eC#rbG5Ad*6=~eYS)Ors66n_rkEeq7ihoL`Bm*`WcU_ zU+V8Vo&Q~=VKK4=i?d^Ua3D-`y{F^}W&<)@ZSSgBoW|n)qi^msr(UxD5g68D&zK)Z z%+r#vh5C=@g(}haC*^ic&vr0-m<6&kIA@^msAS%W0=9dI)e_f)A+|5d?AX;sY1}$T zegqza4Eo^T=qk-wpUr%lQaZ!iA9W`#7B=$sBK7EW|Nh6M@_C6q#l4?#*Y+KM6`Vid z%sOW^wHo}iQ|QUSK3i+_xcy7D#pvnfc-QtYQbOTbL6MHm(5@>E@i6WKJRE8h8l^fB z>VvFUrz|e|hL=z$1rv78%jPpXb1+5@s%-jf%P7nIt z91KW+<1Pl7*LvRo@{@HBO2FlGM2B9A=pEUgUu$_~JQ}`oQu)?l;a5OlTn)LB3 zgGu>8+SGFxSR?y?q&Xs}ksT?1YRim?*pYs(JKj~KrG81^L)NgyKgmlA^3QyGpHl9# z{q^uCY8eI;1i1p=x-j4FRnXc%bqp7;Am5BEyz~Ea%VoCCP$C|oH6|5@OOCm1E&|d< zXmrNk|45k~E+5d19D~YAtc5ns9V7c;8OVI73it68G}XUx?icqR+jeyukl(=f-)hol zpe}6nxqq58Z%8qCeF0=E(`rP1_8nFH!!q3=z!Ya3CMC(8=!#Q)#mG9bRuE+uS}bkN zG~gH;Y)oOKmQyr5;^|yfBy!Yc<2@V4_0njCAiT?_*{QF0i7qh#{G|il0CtjPLL^1rNDCR0F|$1GFco|V3<5?tVZah6(}(lIuAD~}NDkp5cVLt7 zkANlEj7@I9>RZigoU{>pvu=+pvCny>Bja`kAu4?NlC1dVqEN-R-BD`{3$a@Jb8RBi zcauSPJ$@Tol|VH&{bS=5?qIeOw4)+cI1k48$jy+>uL^3)Xi2)W+74KoJbtXouHHU#HndbRS8(KsnG^u`F7SD-#w~82M9#wMj*)lSNp~7? zFR&Io7lo|irTz_nM;Tt57+AKhz|;Qz*VG~Oq{M$p$NR9XQZJNQKS7M7pdC$p2_Unj#>4in1yR-@&oPMTN-15E_GOfX{(@{h+ z=90ZwlS7%);e!z*Oy=L@e9a%s_(n~BRI8dn1#qd!dv^Nw&XEquTGsYaHNER?tfpf4 zK+s1?@TO&YJjkk4te@mhxd!hB9v>`h4XtJz0u0!_gYGq`E!iY|^(sFtJ@NI7qs4b` zu{Tx-ZI(|GXMr+Y$+eWxjGa7YtlK2AD2}=g;}UsD_SF$q_ZolAjTO{4I{)!M+maG( zt9!BjX)fVmhGqwem?}KeDbtjs`bB%&$z$7%HeR9Sd8}fo~YH?H^8UIevX1K zE@pT4cx#ag-hbm}U;`>>zi|Bsi5#xqlvq_?4%Uav(FK2MejWWP)Q z#IAtB*o8OHKfy2q?&hf@xaz#0e z06MOe(~1q0zB}<~EAeaI>rcmb&K5(dr{=b|T|h>$7eie@a_OJPybaEG9~4+v+q#8?}Qdfp0)hU+7|i!(w57-fb*0s&xDg_hUQgZ>)(-S1>Ex zdxEyj_v#iNZF;^TDqz=Gk%1F8SASCC*^qxYq@eI>gZ+QQFA~d#Rb~a-eIFMzGCpq) zIofd+HW{w2rM?=IECzS|Kr2Il8K zjx?X`%oJDrsWTPX3USHmtD*Qhe**O{fB6{&I}1PM}4e+278>2Y(Py z!53#xI<>O@uH(4J8J!sIB+v}m;>!6A%cRd>q1@65adGG@!WB%R8mL)#TnN%Jb?v$} zAn}EU2lF#d&;JaGS2pj>HN_sO<$duoJ(3F*9W=+SOXBQ~c1-^_KBMj{e_HZu+TW7> zy~{M7aaP)g8p|wSHu^s8EN{>uF77owPk1Nd1yxR_HI*2zXE8l}j?mspXoqPSQHv}N z-f}eg;X#vkd%eyb|Ks$JW>mB9Rf%;prdr#N4-rpp?@Vs=1D*1ZJGO>KQ`fRGI)-#{ za=7@w9Naz9U#}$*AI~Sxbj7X|(Yjr_o>e;_<=LhsE_3{Sv8z%Byy+N73%Krh`B5{@ z13NZ%q|1^cG4=j6@o%Rx`=NKE;dIoB{-P4M$Dq1);_p$R+}N-GUySI&$p2O}*+NvG zI9xb#J_PY1>a6M5p!ng#OhHNNjmLemeqy+OMBicfxs)Nx-A{N0YG82#e2<%4b` zOYXB!X4YpwEu;Cq(Qv|)&S#svGXBiesJ`4SPx?)-P;4vHRIDN(crHER3z(QP717j`pMCtQUTMz%Br&OGH&+4Da`|3yX1B#^We7<+PZy$yhSSW=D zq)IMLFVRgW03}EYuA|r4X@VQK`HmXI92`SM zvhk2=2KI^)%5~j(xu75UauyKiQ+-yM%-a&I)y3>NF%)`7(iuDl) zX(o_>T>FLU13sydIUHF`3cvov_rJb+m_}@w1E>5P?gXbfx^sXt{o~X5^%UL${@5qq z1Ijfho$Bslb+>JO{zvG0LhxKgt3N8rounhgIZ3|x3$VE!UZdAXg;PBq*5NdKa1E24 zPNtYZ!$D}OHT+56SHDb*FS6Rq3*%+OpL@yudfG1iUpet5e=1`bHxlg#o^)DB`|y)2 zmCY4s#IBw2$q^6ky6pkV8Gc~@`P&Z~`4UED{E@z3{{=#uWFEXdg-%==tN!0Rl|~02 zOlcafNP4gIJ7$iAKUC!78n5QH@a^V!bo_m!{;8%Wa&QB~#Ya;uL=iSHE)2yz5-Vk`rq_IV) zmY%)2WzXdh*mhm4KW?4LZ{IS;Ec%dbv*Gl+!xxTQ8~##jnQ>z7#ki13*MZ0-il96Y z<-{D}MaK`3K%aBNzhX*wUz7Cz>w8zuO`mdBk;t=27Et2RZb38-;R=M%_S|r~+lbx8 zQq$nCa+h&!**jiQLF-PJo!nHM2M=&1rx3s1#ky(t#4Q?~ZLT1ca2qRmO1S%>y_L_k zN%ny3OlKX?e|&SqDX*SM*1gAg=JgT>afm4Wd!lk}yVhYCQeiz$?m1cKm$37QGCR%T zXB?>^ElyHkHBIR5j(Z3{)336Y1_q%t{s=mhbcjpCQdb{(C6f=AB z-IX;vaElv-+BAEB)CX|ltEujruZ$;=i$5K1EizwZ^N&{DFI;A}5}uu)3GXAJh+C4S zNu}%{@kWV0qS;jxq4T;H{VL8U!0nZ607rc3V#z)CfA+jY^821A$wNJweU20Dx!`p{ zwHvvYn}>sB5?*e0$@7;^GG_ChJu|q|d^x#$Krr3ZMc7EG6SV41^8Vn$CZ4!~g4N8~ z0WKpEM58l2!xG`cA>z|l!Wa=~G`Uy-7o86b*xz@HiEi#j+~emm!xP&S&?t82#QULk z@{}HbH)s1`%F(8?6K`Zq+pjN$d7wLO#ZJ9hR0rYM#je?V^+_c4fBoK-rHtGsWEt@5 zS;9a^QQZ#AQ{DYChRRPHaEOoNe8$t>;0inyEz0F-fa81oV-5mFd*Cew_uhL34e;MM z-siqxXv@;&KsGfycp^GqfgKmHdGMYE`p9E%)55r;OtE6{}9I+1aK_R{6n&eInmD&(}2%Pi1KZNJEy z2aBY%N=%9q!7H@moapYK?uD6RJWoZ7l^T%2+zrTh2KN^iu`MgmsvwvycCe=l#<=0s z8%8F2?;`R(>JBrJTD*KFNdM<`9K*Z=@5}ez(lAqxa#%{{{+6sibGX4ZF&+=Jn%?>b znpijo7e!!q>+!88N3^}2XCfpl`9CaaczxZ^@OfzNTv9|vuS@vs*sWH3N}#L9bbg&) z@UJVN??WT#3NX5a1yVS0r$o;pVzTld`*wJdcwY1mL*{Y{-V)giz;tv20hoSYPW|h5 zpO(%<#nAgSAcOcCkWmB@x1bNY#M)SrA3Tc1PM=_Nzl{u5rq}ztVY2#5Z-KYf)^Por zWvK2$S=w=ImQ*^Vp-C<548TpEGeN7-Xmye1z_WsQICk2vgU(j2u(#C@!G%dQg4#4 zP}uUwHy|AXmSOO6ng%#su@leozo<~$vWV5)1DH7%w=ci)mS1B(_J=?MvWr@)h*RWi z%zM2Rks0-lX_Xugju-oy&@o?IE}-F=BdRAAuaHUW(VHT#Njvt8%faNFam+00SzG>q zjdah#63bt)jQ+{Sn%1O-Yk;9y?{1`xnYol*OyFo1|tPw_z0ExId@!t&-ihF+;G`L5Asjbuw? zH8)E5Y&d~%9LNo^CWA^3QLMmNg`17T{6?aGDHCyvoRqv^z(3=@Ma;z7%GtB8tJs-0 z21|O6j=~h?l_sslrJ@q3lYxIR-&iXqb_do+I99D6_^&~V^bj?`ITDHno;y9*kCK&{vL zfTIqALoP6QFhNZFjdxD8_hbqYs<}H=@H8t z&Hgg#iqtYwsQ#w}F7eVq*PC}>>kMogex<_?GR1s;hJ8P8yW&N)fGUdefWq%fNY$Sv zjm{65T&v!J8NU5jJR@&WR!FPA`GBthUU)0F`Rl)4O8>cmi9<%JM%XDFUtGMP{bFGr zlrGRK-p0DUxlu%F{o?|m9CA6gOgseYVTqt0sA{Z^!&bLq{RB8iC?sOqA7mtT*^k|w zX&NJO`ZjIJXvHav;Y?r_?$K&!mw5HlGQ^JgLVAdcgYlbs?!6@qJ?{aU!KJsPrD%7| z&hT>;kB2~?%oBPj=)P182x0v2#qIO%@roUUp4v>)zg|^&%ty}QNs;aF$inm3eb z8(-pA#>qqLs!{8kdYuhLX6c2=jEu{MdiLxotSW=PcKDHD4#dI|&5(|fTAzdKxibg| zNL%9gnfb-GE@LS?CcOzr3V@ih%q34La&^CWtDRDxdO{{aO<|*pzc>C_9NsbyqHr0f z@HciX;O+`_TBd-4vG$|Lj@2@4oz^2<GOmfHx6REs=M5OY3F03*xt1$JjqgF42vSf=m{W!@vT!9tdKWw-nYYOq&ors`2 zQ^AGolm)p8w_sCgisd&CC zpq5vtrMh8h_Cfr`OcK(Kx*rQ3hTn!O4`-<^>tXA`l&)fpcH}MImQ_cdxM#ilF%-ST ztsO0rMbde<(bWJ`=gg9mEjhLCG0oiKBs(B;z+h5NhZJH{zuB zNq=$Jl;-OdH9`h{qwIUBN;nZF*z8)X2lW0Tg`^G0HbG_ecJ6JTi~C|K*E}u^!^=*= zyX5j+ODnJ#Qo6h(mP>Y27Baf)1_O`w5iszh9IpEJCs9ZB(AjiVvyFjztpbvX8{zHvB>jne#lB3BTIxq6Nc$LFXk)At%hm;bViE`$! zkgBq}xM66R)pe$7`x*GyA}Pt7I#;?Jvqi6v*x+5yXZGtB%FJ{Zc`LFH`o~Y zrsyobKwom26&9=9f6$}&mj|TsWc&)7g^fH3@w=x3u_$Z3=1Y%#EY||wjdyHB;coc9 zPkJ*CswIZxx?w_PTfhfY-xFoNqS620Mr`ZHoT3z# zh~(*b7|j>X=lA+D(D^6YNokdOaf?JH?}1WLH;hWrIxXQ<2A|#hoaS4*>(@o&hVEz5 z8W&$DNL**CO=GTN&S;Z8&d*yBEB>C)rj>af%|Nbp<1eIPQ+T3dNV?(C-?xU&sMQvs z=DvM%fP>EcE5^5=B4qbIxG!_chsQ>eAijlBQ}^4-Sca;$)yd2i7-z$QVASNb z?V-L+0zEeLf<02~(Z-sHkgzPyE4cceh{1&d=6rTxpL+e}xnKLE-N#?_QtycCFVV7`PP&@&RwfwMm#j^X zczoJnvDyrqC$N-4o|nW_%u~Evd8^aYYK9lQo}O_7nHkL@I32dT;8JZh`c2bqYyL}y z_s)nQgXLCKaY?^6kX3HZWBG;Prp-x$DYx}&R~_t^EB)72QPY81v;RuH{AHFnWnrEW zyr~{j(4My5JOuLB7@=(3H0Fe8y4K^Hv!8va^L!)cd#QZIMhf-p>KQM)O?b$?-x5vT zZ8}jMC2R(iumn)!7|HeKhd4C$Ft41{G? z&wLp}kQc%wr(93+&N|W}U*_9dloUUwsQ5J>UJHnuYg(7h+3E47oR!~^iMZ6st*Ky{ z9NIr=@8a#u6_WsOp1ODkU+Fl0V26TzFZwI>mWS?|cF2@Tdnn{DdrkQ`7_U#tnWOtV;xMIS&RAqH4hQ29nn23VrC3=)BjQ1Iohd=GTr)_57Ft=1Cuv0_$M!z+VskBA3Y_t5zoH1v! zGi$b7(rtf5Wg13Loi$#QBRh+iN;x^yY`#Ys3}<`w1!u?`SM|A^i!wHqCM=ms&=|`S z3f#fJiUyc0M5V5S@xj%ihP!a@PJSIFlx2*z`B%U2fKO*G2^OJrpG3^8j_jvoV!mYW z&m^7LXJfXYxKoqPpD9BGr^zaMclOU7^+KxsMaDzi^%PvZ%3&%%1?S$;LPXqg1Jm;X zBk`hDQ~zP~rjWyXpGw1V5^#*T{|T9k%f5ka!o@z~ zu`O6SDS_%3h(mqoFIk-&$aLC>iDq=ahzxBGX9DLQ*N{8>E*50>JK5&Db3u{zx6x;N zT)j^=X&_i)DvxO=Y&=Th<*`Jjk#Fb)g0Y#GL{dO5S9r|-Zf1vDJ$m7BjbXhDR$1EB zjL)qacsy?o@;;(wCf5{9d($wM?i_>L2qykRKE>a$NGlu0JYIAoCBwjkL!?;x&@LI@ zit`G)absMcse9aq!1$s29Dc89xr`R^DB5`BXRlIka54kuxSdgW8lZCv`j4BZY+b#TvxFqRJ@BHi$ zG1D)S#`oJ;-hJMLVNqX`j}VjSw|GA2x-IZo5J*;8VE)CgsU>*f*J-^nP3;?Lml-G6 z&60iHUscL0Zp43vBsltte!jaC@%U-2s)TmOl?d{lw5|$EK{1Pb$tbugrzcD?&nu8Ooj0t zNW#v>M9=YsOiPf;n|^}w*vmXDhx{w&lUoan8IxU`3#Fi>%my$4en_E2lIAYe6!(Jh zEDPyAGOagX6H~nTYeri`YOm_N&^iG@7j;yV2R1KEA(9KVxOI-eo=^Eo z@^VC2sb8abCjL!3c3*ApN%~##XVpSf>F6-47yN$fPoG4%Z}?+>Y?)%2-;FR?3$tJZ zKOk;TKE}R?rCA*6=xlp~ID5xV@ok+_n6IW~W#Z~p3F&LC!a^!+8!H%+hmsWR}Ni-uXU) zfwZe@32g-gIE$SSzdT4u*l?UsF_6c6%3ih41|jE)A) z=_U1%xxT{JM4rXThQfKs=t*?{)OO>sQhxU05zv}2G5o1_xFTWs0u41j5?%QmoAe+m zNOsb8r|`>Q?ngnoYfl`vjp_r0uLP_oe*{}fZuDhs47PQ43z3PnBd3LNv1MCP>za-v1*?GKaS zFGgWeRa&!`w}9Rn;2^CXdM1W}3X`d`N54>$( zGq`cIf!R3dKFXqc*o>=w4;I#!{B_6fo#@*Afd|r<1tZx%-6W>^9(d*iy2t&}VBcl| z78@OZqe2xo+L%~}Dny}z{OHvEA&z5KrAI}_i@+6!a?NU-eCtr?&x%B({S4A<15d5sVFcIA^|L#VcX|J52INB*GMHKiGUTE6n;%AvyouCXvo3osw@`7FV_K zw-GlmA3g$hOJ1>8N3S*fiP_afG-G$F0OjU)U+FOM@8OXPtf-*~9#yGtn6eDq)h{<< zaJB2&ZB~FA)C^$*$#0#XrJ|Xic9OAzv_UV#Rb`fTG~2w@Vr%if7}`ZNfQNq}w06wI z+%f`Z_xI5Dd1@|H4RE83uh`;3p3U4)87}|pju;46XyPWQi<+!n6Kk2XPy}=gjTrwx zik0LlRN2~Q+We|(uGvj;=-xooL1wpfQI^`Z38bk)~Mte(q?)SDHkEJz63a>-|@P z&&&t=>WY-9%9Bj#>!$b3KBV%MnuKoWkq3mvW~#RVw-&wh!fl1~$$f?&IDioyd|fOW z02Q)nG0$bH_MrP8(*rLJ4>CO$pw9cEMEGLzY~i0L4{M7RHoj1AN&5iq{*(6f4*|@6 zgv%aSsIZ4$4+~^*tlJ+#<*N0QD3=49>zb zF0cpbt$B9UZ@vl^KmK|$`rhjXi4jZTh>a0+fY2+d9ap|mZM>_iv}8Jq7W8T}9gq)v zp7l!%SCB^`r~@4a3jBH`jZ=8B9YdBxHONJQ-yY%Z{ zO&J*!tsahlkMmBCu4XAZIveDbA5UuYP7D>}&f14qK!;TEYi}7S&8j27f)484YLt1p zvZl7nqubiOk~pT+@$VMFTe@3gn^Q|Hx5k|T^_Bu8bWvxfm2p?M*@^4izUp%?G8=t* z&a%Js$N_hH;&bkUBSt*^Ba#81*i9trLy!s0+<4}cMG~5SeN(_*>A30T2*IhJ!pptW#P7DtVtfo)|wX|!DMyNI$!O6XHPf*Q@0%9wz`BskuAqcl zq#M6O6Iuk{#h48&xqYh&qL`TqWvH!hM!e_LEWjMh?7aLpfoajk2(88RflZV2w!|ITr)yUuh6 zZ>ndMf2;%xV}-vw5_iUVt{F&PoKDMKl2H}rtHf<=QwU=dU?xAEFCzeOSZH!YzVp&668|R6jB&< z{s^hIuKUby&JJDCjfc1@y!Kf%HsiVcRgmanet;=He82rdK`0NLHTq*~H zMB@1d@xly}EZ}D7%vR#fss^kSbvi+~JvD={J+#+5KaB`@=vQH*`wf;5Zxap;_#^9K zkBnlA@P4L(S}($rfZ|nneOdafV&kuQTms0t3AaD9_=-C`q2@7v@Q**9r~tA#!7LRi zyxD+1@CvVSUCv!|eheNr|jPILo{TrUNugN{#u;gGl@ znenR?thbYi9Aqn%hRKOdK2HJJ(i1ovj5=M!?d^J`gu6H9=Td_iW(Uo3uQcsEFCbDV zb91q7DDjBYJ1S(6lDudy?%o42N71g|NAY(Y$|?4D1gI!gn??DZCDfUF=Jv-1o}M2$ z%6gv{pjAw%2imu<{!qhP)cr246-G}VbJaG>jA`y&fZzL8w|m%E8b20kHSI1+J+g(U z2TZ(c{I<8N;jzg)2Jj6f^Vd%dg3c!+A)vLV-)*7w+w8u>RmFL1@A+bYf_+sVx{x!o zutfJtEqjC|@1OwAt2b$eiFDRWYgr`D7PD1hZ>j}&t}~dAN$BH4yi~PgZ3LG9a2s9b zIcC7`Iy786yYJXzPHYs}SK2gN{p$2C0BySd3r3NOYl>y^TI7iBJA53TA z6GaonQY}35V_sf%Tr_EzOwEJ=eK&~%;M(+LaP<+qGLtc=H>#$mNFiLE&vI}&eXt=0c6cl%~^x zZrG(pmo11rhDn-r*-oeeI_&Pw zuV{JM7?iMK+i*4?)v+~kTs;FFgQd{^?RuMKf==00IoIXnW)<7-5{b6$%ThZpWZW_R z*X;X7XO2Ynb&b51OVH>9}3okABxQ)E#pc=5;nV7klN~`iFSv_kH$CFS$e$tX%?I-Fe<3U z#FEOX6d>QvAP{Up$R!G3ELd(`Y^SPo(R5}7S7r1V1QhC%EVNxGP-=KtF!q`G`s=|f zv{`{$_M&(m=0t&{J45YhR3MqqIGo#2n;7YL@#XzaDV$WL5V|0pJD_4hiVaRknUFR4 znzJ>uB%_MCkp#Y3PC`V0Z}Mq|SvT{FEAT-{;c??)P^Ay?Y{46|cYK+$EeA>s;xGrM z$lKhSiAGwz{YE2$vf|-!&$JlwYZH$HGP{4uKUk zQVgs6&s7g70mLvKn79d?Q?lOX%ME1jl5SkKk>aHm)u%C0lzfJXw-Bj%d?>)nl`u*g zMMoU)h~ds*rn?jYyzllJ8u9qpv?G{S5BxBSoNITwjq04>&gpz*ElqW}o;ULnY9b|v z%ksxM?hlV_ml46jZOmq#b|Lm5YF%%@IH%JEPx@THk6168z6Oc`p~l5HD%eysy2iwT z9?iE@3U!1?7Oo*oB}1&Z-;`DIG6)Jix_uQF&Y=(29D*^i=5TI-JG}sm(<1?r(puovV^RXYUhL<0<1?g*`$_pI6X9xv|;z z#A3S0FbGME#h4uUMi2K(3%r>GQh^=(pku>Zh%23*R2zdE9Kb{Dl#vcsTuSl%j2_F% zXNv^*eB2s#S3~INCIj}E>#j5&+~tE=->?jgj$XT;(FchIDGycRy3{%i6f3+gs?E0+ zv@(4&J8!${YTqtS3DWh_E!~Jkk8}zGN+>XZgh+#c2r`7yDXGLrcXtlm-QC^I zFwD&U=6~=V&pz7MwV%14b+7eX`_SxiEY@D|e$VD(F4C=X#@Cg}5y)!7pIQL%{p-=p z@Jy#$Ey6(}TeqKM8%!CYWwW6W`^(=KkerG-4Oo#wzYInIa(Ms0%st9 z(P_FtnxWtjKjFu5f)*UEVKr4^XAUxQ9KML_2+EkaZ^cTg8%eRz7DNN9AAh!NTsaWR zE_@WmkdG4IxZB)sOi;iV?7ZF3?*4{N2`_K6 zmpsP!=)4H;_s0hUdM>WndJ)W6Q9A|JUk6*u3+}>5P^rk`2z0_X_3pt(-s6y1SFHtl zgcqFW2Q%P32*x=5>(ce_o%cs4jG) z3F^(izm!=E&(|m!rbi|(FBT*GTa{G#e)%A zg@Fo6z=EnH93JvNIe(!S@@@V(?;|yK=ZcaeSUGTD9Ag=)*ZH0&J0*~ zRfdw3iKD}pDGENSac?wj5YcKS&{b4Zmz`Vv%eBd8V`cJ(<{uTJE7q*f%ZWZX! zIxW2-?$S7R^^SpNcHA$4on%+>oRo9>S+=foEW3vF-|6J!zT9FIW+yjuUW=@=Jl)ZC zhLfMW4QLUHvyGF`F6TD5=r3epF^Wa*UIZO^S9Ha;miq2d9V0uy0@PkXr@%R~tLf;f z1B^LOqvQ*H>2#&lfm<&1U;T)u3>SZhf%k?=2^ad@4Y?7?LzvB$!&5^kb}EVw&+mg2 zwk-i#Qn|yq$qfK~`)A*-Dz5k`WRB&HD&J<9#%ce&`FG5%e#nOD+>(u5w!^%?N zVE>ckj2}eQl>U+#)NI_0fW0=No}7nSTWZT><+2D2a1f%M(G$QS-rJ`aW4$BJ$e7&B zp-EsDZdiKDTafr&9LX6i*^jMKUPvP~f?nP1P z_yXl83g*v&0d71*_HUo_L>X~Aj9WL70fFNib6N2Q7iN8P8$GU+jLBmrW-KfEMjEAM z{^!rYI+ZO#p^0JE+`hyU<|Y30`49c0KHqgQ>VLmbP}VcrJpY?=Qotc)p7jkb+w-3) z=J)^kHEiXbBnYAwN`xohWrFfXqtO2`$5RWj?O(RTy6TezgwULhRqw+EAvKMz{4W6I z`>k_aAiFT=+h_z(pr*$C{$NZy$ifdH^0FRWQzaC5MEdlF;A@^6%#AYWTv+SoibnDn%#98lQ?gnJ^L@Z+nOs&J}ZiR@cT- z+~aQ4^nA*^x4Q{5@Q$L{Ko@)m(*2`MM(tgBGfC?Nj}j7Uk6>ur;Qi!>mhzpK8lfZ7 zymW4rAc=*Jpri-an@0v%LepU}vul7&x;MKQXx)Sb?_zPz&<-_M>b-JI#vZ@tvfoc- zR6dRD>)j^c7Q!|ZqxZ$DiaRKZgzQWL%B;^7VzH~m*q#L{VnJ^-a+R7Cm&tLFw!11+h1@XGUBI1|sd;5QaTyj@>=YotXb;0YJ(jD(JVd zkCNY@B~hx9ZzUeO?m@Z02Qk!%G*yU3m+(fNhW9-5{UYd`)p-<>TL~1egOnjM)X}!D z-b!Tr3Jbi~*@z5LIRr2Q9j|S=4@0UU=y?;)$Ld*pSmwzZW}R@b*cefBG;X#rZ3FQ< zo;SOl&yM)&u-35yT0|)>0qP5&XJQ+-$H;}tMoqaHf$cFJzi)}YS4Ys~PceVE2#)K^ zwPbfVt9DxN5=H+O0ZVm`ObcF63%AV+)jj zGGGrZ^X<-gyJMl=Vkvj-uQAFl)$N$LCyV0OR_zl8$PVt>1?du}#LYA_Wap*UFne#z z#K`O>wb_@|&&Ii3$n|H9wAEqjdmkZ5H!zrAnaM??{&p~MA4zh&R;~L#i6!%5%>|xY z2Q=b58D}a?@`1(k;YJZCsQBys=gg({L%{@28J9RC_?b~2kumWsdXv8-${g>9-5P_K zD61SxAQ3*O8o`m&IVedkD4g*Z_V%>pM^d6REx`oO)=`1N9Mt;|`+Gk${>fDhrxIQ^ z+CQo~;munRb>GB8eoyKz@`^pYV=6P5##}^_hDN25>LFKoLhyC|L0Nq05JJoz^&Hdz`C^jHg`*zJ(NZ?IM( z+mdIjsyG(~yO@E*+tK+doHiWkT;`U8O~v4(nSja3SwCdqe9io!`OzRWcox!q-l6t^ zXUMQD@c4;xkc8e1=uBTf*XyixTi-VQ3Fx7RCHDZ5zdnVYY0CT@RSUUet1eIT-JJN6 z3fZ^>5(rq4&DTeB`l}G<;;M zF|NK%$J@G}#@JN|tKY)M=-OVs`QcNd|S(0IR*Y)h;eWA~PxNg`-P-66g=NnS+$Ch_D z1oB6QY@Y+v_P9%7U1Qh)4_Uu^PXb6*<%Fa4_K0WY?m&R0$?IMCe4AZi_u{64E}8yB%)}{)=!*L|S;FAoEQ`x}T9p3hdoKzeb~2D9QA8272;yF89Mb1^ZFDfx z{0d(t*#gJ1btaFYf9>}mXj-ZiAdUijPhw2g*<8l4-SQ@R4wC;iV~T#2&+~2R8y-l$8AkVoSlQ^|)IFt>^_MYzG zGDyERe2m_j)%-fQH5_seR|}1PV~W{xo9~S^9OFd2u-^P;y7TWsoql_U9m0v;1J$aP zbs4*xSi362=?lznz4+`*&)=Y*;@bsy1epmYqKd_8zs~+GgN&2pb^y!G&Iyi7bweHT za?u9l(`lUm#P{L*J^Y|==)_Atnj`J2uGYgVM+nVdG?~=6K~8JS=KDWB09bcH-1`S9 zsENHbIRo7=)p@PS&#AQPOU?EmgRc47VLmmF+t+VFa3<=0djH4dX6;pfDXfuqBVsok zqDR*Afuk3kg%4Z{jY=GybrVZC%#DGi$HE|_eo%)0~F8$3H}aWQXlp< zoG4%hAG&dK0fu$VI~|T^*R1{^Ae(GbdgxLjsr0Y$La*Q3e2d2{nZySjkwfMNb0F^y@^564#-tjA z&=a##6pdp`yY&?08{0h3Mqf06MseZh^8e{&BmG) z@zd)%DY=8a!KmvwnJ>nQrT&THH_sO?-w_pJBB(WyPOizTBLkUiCyK1AUC~Y}MG3r* zN6v??y*qS+E$$V2LQ^#V&}qYBA%mRy+AcDZV^W4f@g1QOmcyGHU?wbh`S!cQrpeBj z6KDWAmtgeNO$Ze5-h{nLb(7pJP_)KNTJSup3lRdNi(1Y*-Hh8T6K4}}{}B2LOsof! zGO-h!!pJiQ&Hp*Y<^vZBrRU_5a4d##SUslA0YK8XWi3QyJrNc5%WadUR}tnv*ig+# zaQs;R5f%H8VJbZ|p{o5Bk$<^viiF?t!FNyl4*~i0pkmv^oiMW;3q+9wlVlq>uq| zZG3lZqh#qny3Y1v7|(%bT;205*!5~XTd1PP++#!bpqn#?CFw;u#7CcAsDR1O5neut z)*#M&ETn}E7iGuwC{ECBmFoBJ^3epsT636vDb}#5R%??3=&zZ?D)U<|w(-3`q4Dp{ zyI#ICAkI3VQOra~#X%B4U&JW47LB^occbl5NDQ#XcA;36{8+z1cNGHQI*K=^ARXuG zO0Q4mROQ;Gdn;S2CqU~0(N{rZx0p5JR&P{11}ZmDEC_y&V;{K7MFHlU3HB?_}_-WOxcM2zs5w9=hd-R}z_PcPUus%3s+hIiTT zp2?%|Nnpgo`M@xsaU5d+AgA|Wa1+Rr7nD)mqs_G$*=WmWP zEqD37QB&tS(x~SQ&%WoByveNTIOd?dLVu>M)<3cEwzYJGSg*E_O56+{n=id z0J8q;0hKXAw!}yw+Qgz`Sk+?Fg3Cbp{2rt4V&uPVPDl-(kcD6e$TeOE#iRkLyP-nh zO1%EN|7`J{jsg72rLOC%7LQnPsrYCO%qI2`khYxS%0HH}K4|6Z@bf(_4?U@s<0bDN z;^R(YMpYf?fsNg13aE_E*~jT1cvaQseU3! zN!qppP=t7Eu_B1;Omssea>!q19rE1Nq#*7Nf=UI~&Awgi@Z`gEAC85SAs16$=1eXd zfml`a?Yl_;hiUL2pG9yDfuP&Ir%U?RT{PfIF!h`lN&Uy}uS%n)1*GO3LURcstd4el z;C7Q5v;0T;n+g49P1rZQDo83P552`PyPS2f-W47D0Pf;aroGR`%Y7G29NQZf?w3-r zZlL@UdqQU08B}7!p3%_ypR01;2VS}phy^pR)?YE-6{ccW+FpS~=yc=JY#Tm`AUd33 z+5&i$j#N%GYIC@R&M3DU`PF$wp$R%2v#>LifNWH3=)s`_ZLvtYuKUz?yagguj8L}qCLAXfQn7vqR_FvtZ>vVMHEGO7}zRn*9R z-IxFOy6;-gpo8$SX6NxV8!Jt0Th}J{+m`nv?DuB+K^d-doxw6+4T9QJ^oMEBjA;Ai zR`jx4(sYt~d}SXvRD?);{Wjjw$XR3}vAP0Q-6&>nUM+LQ^NbMXj<(z8TV3Y38a)cw zS?k9ud^_1Y1NE-#QiM~x?qz-xBGys5(He$vb@OiIs2##Tl2--`@KYZKgyMrLd`d(@QSLi)n@R9eC^o9l7Abu@!+8^H zP*ex-j!KwCOCrR6%smQn^g?ZP2wa1{U%TALl=~U1U5UB--B^{83_*Mb=U}(S?baCw z#r=6BAGh~l4Vt^lccCW-eSuxd@a5{S_;qUkMH-Buw2>|+Z%u2TIO4m;bO~k=P z|H7>S2`g^nQ^db1#`)u#;p0?jasvj<4$!%U)jgUdWt=yZ1DxmMX(1o$of2Va)WJ`H zS6f1@4HY$JFNxlRIFal;HD6eNHYR|CcEWyauo7vUmstCDyK}%}8owT|$Ol88zrJ0B zF*S^yXNz;p8rug@P#m;#e%B0PJ+a=wwYNG#q<@=|K=UFGZ}MGueIJea_?IV^=c7Z| zBp(sjWeCGscj_9hC4w`Olc_Y1HxJw%nRgUMsc}XTRq535I94@MjY8+49DIJ6u;Jy_ zNuddW<*TtCu5pR`*}1kyTfU{6rp4_auz=bNu&q|$4@8y@roV}$=vvjdPkkL5mw<>j zBO2X5;Wh%82uph&kIQhP^a;(7<#dBNUHMp=)>Q}TURImi>IkN$JBr4wdM~PirpGX5 zm7ZV8TJij9ipy?#j+@(I2qsLE81l4E`agVX<%evNusl<@I4wEfs@V<4_CL?9v$Wcs z=U0PvykL#gk~7+Xqf6{Ant&ClZ9kD(LbEv@LqyMoU4f zE2)6awod6qXaml-=<`20UjTx0!j$Vk!4pS!2J{s9n}W4>_|qbgl(II&Gwt_qhI>OM zWKus+TMN-FfZUz>RHej%r-6oS-334>8Z~i!vX(T+=)?;%8B_o;izV`oUAhrWgu4W} z17s9gKt?mJ3>(kTun=-lqc1yubCyQ}08e}H^gcJO)(%kw(H=6!Kws*a<&ZM^l`5Jk zznD$HqeABL%@2$Z`W-j1gdHW-`*IL3#pkX)P6(|`ka~pt-jI>j2N%t}-6s&8PD#3L zU2OrOZ{Z%jMLZ6v|1Cj3zPWg7r`^;Y)bN7pP=`!>+28gu36?j;867bO>0SPFOW=!D zI)aY5u{C|q`q?qlqUN8$mpahV8&|z(wIYbvxJeJ%pkh6nz5dzx)jsf7v~2G9nff5tAmt!Ni0=kW9U%@2(w%Fy{hPzrskzx!=ss^X+ay%uLRrK z_-lQhpeaHRhb-9kz*;8})J_8%*)HLb_!P-@+vd2m4VM8GNV=3)!WnQzWAtNO^}v4M zx8e4C-xUyZkQS!NMWFAKo5h8u;La#WE+rEr{7db@({bmVpTHj8eCEe4`~7Qt5E&yk zF`WqE37FcCFI=nnoZ1b5vL)WttrLHx)uwbdvvG!#R~p~8N0k7-bIS+uOPJ}OSCIRm zzV`Gcmm?$7d?zP5f9QLi{ySGv^5q{zJbUGycsbssGw8$S5HBZt*E!ejqdCU9vQwdW zm&{c5(3Ixhk^Ho|Je25MaA*DE(>B7sP2^;;zUNEu%6ye&ZpnAY(#U1og5#hyqv^X> zuOK=iP1{VDy-d!TJYS0X&jQMI()^g)a?YZfGB_X)56}9i;Fy+4ojHN>cDf#N87)Qj zX|`Ww8W17rwM=|FH2F=THiUwY2avn(KWdMZ9`zK`rZ~-f4lRS2p1a2Z z*(y=AWO|~$w1Vw#>m1HiqZVIv6UMhTzRt`*NUd{8;-9(U1TV3t;{<|LHoo^n z_x-9M0q536Gc@8HT)YkuX!D0g4up6(mjnop6 z3k8q3Us{|nIrk42+YU&lzSMxqweEzMn{f28dZo40It9sGiq#1cMITIFkIA2jq&M|H znG|JN!?*+faPvQDIy|p;ToR~Xb7LCpHi}eT9B_g}_2Eqx8JfktVR~gJNvZp3?hE8; z;I5Ihum8;U%>j4_+pzfc>UI93j@<8<5w!7dfJ~QgN|KOqbVC9upZSZ2tLIuGTBv!u zzdPbuPlkJxa98vket0hSRWjoAaG9os4}|vg+Zsz;1-KS<0Vx?T4{9c)E>lyj z+fA%nFs?I_=E>|Bu?nst6tTwW+1sgeoXIt-+e9yjU(FWf-6E|nIp6}0|0Ud~Ub4!%pPaH9v+1s;;Acz#G_+i2Ww zJYYDc=7|a}Ni8Pd?+!SUfrm$K`? zdkY3}|If0^%*!HWVDsgN;7+pI1I}m8$u%*p60qBa@jSlWe_yK-_bzzp`bX-~x}K+t zy4nBxc>kq&jUI?UWDr#Rnymgj$GKe+1LY%NZYW2dtHP3&&Qgf~s|YB%1k8Lq6paf6 z;o)cE*JBF5fp4^UrX`SLz{TT^pO+<@jqLQ54I6{lzw#Cww9mfi)i&L$wOl@(BdB7f z6dLIc!l)!y6oc?cEg6TBG|$1O`(V~ASEy+NJzE&c=%v&5WNy6_JG65IZXU>MU_sn^ z@Z0rB@BpT~Yk<>88R+vtM>af_v(_q5r9~OGqH70W4(G*lpi8j(IPh7n2crlUO@Zrf zo%wI}3{(>!&Xz|xwe|*?zb^WCRNd!(L7X`8EXB92G65qgo$ zfI-96?*1VZqNaYujqYRXrFlZbH+19%A`6Q?DW|dAFv4zdQFM9z4?pWTssi%-(@3QN zaKkk0SZY9Bgv}FeOycjv?3-iD+8=RJ9_>ekSAIP=1k^mIhbk-Do%c&Cdgm9HVhVCP z$5bGgM)VfK0J2uPq*tnN&btF%Hff7M5~fAfCXa(B&W`h3Lk4Au&AX%VQD+V+elLzN z|Mnz068LPbEPnpiCo86)pFZxW=BoP@;SV@0T-Znu;Fu|M6JuRF3ruQicZ^b*8u{E$ zl%J}CsFzl808`Q2pbSPKrDyj zm#o|kdb*+ncV{1)I5tB(oVqi+Jm3JgRaKV#8Pge8A#vZK zn04@9TQ6T1-TSEu=nmn}0uH%yIFGSYkJflwcpI`?hH6=Fi1_v~Q{t5M5SXv`N z)5q}trX{?7McKakkEPjl?>1j~Q)HU5D(;o*;QvT_26_&6|6tfc>b zK>698%J@KSp{Ab3<98^?S^Mf%|TxAhc7n3_q= z5bMfP@kKz{cSNhK#;o(t2>uYXO4Jv%HM8`Zpp#oYCU0u&1&0Ti$5B}%^gR0-^1w~l zt7<~ydn{sFXF#;s)$nbig$UETrO!704JsCfEoP~jC%h<)y~P>#tbWxpFX@|rO{3GCm6CX9_0dw+X>wwHzkmrJ=qwaDi{ z+BaX)M?(kRz$Vq(IAT&&lh8SE_7~S%1h0NPfZN30s83tmpW&{FqGBolew;at`U^^! zJwaW4{C}YH#!EEq)$y`50^B(_oRjve6EY%Mp3eI;7GiZSOft(tjTW?NJ9lJi?{Y!) zG5qSqF;R|z;L~+py;V4`3~`>fKEz@E{BipXoR5k}bB)vFrA)$n7xWsx?)*NUZz1*6 zqv97Bsy4#Ja&O5oi8{ls^4=*&M)gFX&ENmswB%LE{gU{W zN2@myNm6zwvM(9Mv;`tyPAD|1E=tDkOh#w*gcqVum9V~WK7SYREN0qw2Z%+!qVG!s z>HtkLT)nra=6G7YTsc8OVARzVnzaxOQbFvEWC%W2aJ9wtk}ue3CkL21u;e)=Rwf;e zU0ypM*+C+Cvr(d_6KWH8QD&2kK?|j73=KPDMid-k|9*2d`Bp_n6(S{ZZfXF)5*-iH zdWum`E?~ugMJsbqJir{|vkKE~0p86Z`=K6Bl~n=5t`}d7Pd)J+Iz5KK2a)`~w*daP zgmdFp40db42YiB4Rwk*6n40cx0Wb2^u7<LfFbJo3W~0Y|ysO3UwiH*xSpPyy(mP)VFhr@|pbS_rh+uB3LW!I=)4A zT|d!!S;BQ^V7IomtfQ;ZZOD3Q$_#HvjVX-_@4JP{o$ z0;|?big$#j40VnxZ!^9agPZQY>AbYGy|_yMSX@H*5}OvwSjw2P517U37&xLGu^$N2 z=S@GuQ3Mgwi5k3BiTO?-f>-Io@F{dl>}!I6E(P`Sqg)2~V)5N;|r019Hgl%?z zUlnsNRO1hBbn#Ls?mMby$PjvRuHu@yaz9(XdEePt-1H_R`A5pWO%~dA;I|p=@E`W& zT34ose|3s;m)m5M>Tuh|mx)qQQUh_>`6PVM+hod!!q4O4VNXZJHC`g)X2E`@L|Y`0 z!t_9$-O6kHmKjqjZf$n2)8#IO5@N(i&smwxnPwu0A$*=pN zO^nEI=SNtdzFrA@HH`C8(u5lTUgMKDZCqEO;qagJPBxFZPXrN(d`QY{zBDN)1srK$wE7;Dno* zq_$lOm4SM#PCkvr#KWCS1}Z|Ah|MeVw<6FicS4nLJ$P9u-j;F%?aejo0PZf?jKswT zj56HjW}IyWot$gA0^Dx^z`7ze|MSb;fHR0y4!ZD~-8LDmFQ?UZxfW`QH4W>B!Ekf< zcur-{y{Sl1wuw?shAB#`kLT#*Tx$?#Ru<}MD!_vxaYba{(-WNy`1sfgtHaYP+cz)& zArD|d0vlIr*;62cVa5^NMr^o8YTXnIJ@Kx2T;l5U>Fx}_c0B~)7>9<%)gtyzj34eQ z2w+j3{?dv7&8nesqo;uTEzlJ`BAZ|>h!^|!&(H17Q!RndO9+EX1%j|sIDTjdz0~CA zj=&!<)TbTLprayb?Mc{_^AkjMu0+i*K58!UeDfI=VI`ae7)P9^wLTrin`z}iK@mJf0z%fEImAd}nZL_=F%^y& zu3qwk-+%6s1KZXtCM>m7!9l9>z~PLM^1TK@PlUgaFLwsX1XD~fx&W>NJ7jek{C2+L zzID-6e+l8b4vLwEIT$^)!DHnStPBsP!sFIpG4ybabuP=q>}d^)KLl^ak}`R9V7XG@ zhYsp7xN^}8{%oR`2WkyEl#o(|!SsZsAEpzHpV18x`u-OiGpJEI(QfG2`6eP}LWI+4 zH5)0}@MEv_DOD(q()|^IdUIXWMz|fJZxyFe=@h!=rT!l~2;YIpVBlJ^=KD!(iLb;x z542`)N*IaBMvLfw$X=*^ZC@gd#v`3~-$NCu#01|IchS!Le-=*CFif9intKf!xY``Vh8FDL4QQwzplT&%4UCw z()sH{+N)oQVGHb84Q8^ZGX0ej+F)rb*tWL?-ez~1T91Yi4SgUT$Ec`@glOvQ zC%s1jvDIC|r1oQkFyvV4_{2nr*gdUC>gf|twcl3iJB4+n>#9J3P~aMTeVu~euu{ku z8nW-%i3^tiSM8Jgwy??@U+GmLV?t(r$v3)fba}AxsIxobTyg?gJw(MYRI|}UuhuDg z?GmO|nN>wCcYkKy%oTqCBt9P}$tnQ8xf&x19j5EM38~djzSnweCZ6Vv{zI`ye0%K& z?7V99ohhl{`cQy=vwi&%HZTL6^T@}&BznOjii(Dj-aaZIpxpJ@Ctk_K_DlE zp5L&LnPUtv;Rp-=L?i{_0*?swOhmTfv7fo&LxwIl+gSuU)*V84j|dv_p+AdjsZ9ylnP zIo$Th;#xC9ZG%1#%a`kM>4<#T`!hwz}@l$;bi)3pK^)*~z-`(>D7!_nW7Xg;A!LMKPXKIL7(GtR^b!t<;~lrr+ja;i;_cbay}QYA(;hv*-az z7^=6W49MRXnZ40S6c!$c=jy^6_;x~`(f%cSGFKxLMie|D-JGMI%Gj)>U6{&;-){4c z>lJF?cU*M-Hs7W%61`+eNJysQ%cDiYkKf)I2NMNW5FqE(lnsu)Hss}a}q)WV4j z&K5jw{!xd)-YkGQ_E_yE*;rlrX3)zBI$?CS5OoaY1ElWb=I%B}7!ez9^y||t*<=dp zM0*NQ2(cZ8fWh&~B26d!_G)LJJje1E)g+UA{gRirVg$0*vNcWGM;-@vN+T@mQDw!? zAFdLpFsk0r}(%4Ns5wQ$R{mo}W2jK;?(i z)keXrBbk|?jBMj+-lbzd``Sfjvlbzd(Tjxi{ z|7p{Bw|dbHB)!P~dH_#oLEpYrWw*GLvQpjZGCBU~jf%>2BP}xwGYwjNPr)my6g>$y zH=@l1as}rm|J6S;xbW&Y4F>Ou#$i7`)hYxxbSLIu>y;S!9S0wj3Vs7IKiB55tnV*f zsyC+~{2907_@c!3B|_G2{`irQgM$6VJ-X1WHtoO8vaqmt8_WCwEy-Y(rSMQ4!2Y?s z)drj3IjWv%Yp3NBl|w0RH^?kh^p{69Cf)6uQ&@-SdCdtxVwEW1t#?dyuV*vbbGP#J zn50j-TKi;B+;bRw0YE`DQ)6E0*)1ekr58*_b+6 z_oY1^=gP1oaa_C@sqblI=Ea6YWPs=${PoMM6ZZ=v@0xpgwrk5;CGs%T<7f$6uP%3T z-{qRi`s?a`h$3+IfaZ36dI|v|4#rX>3AmKK6hg95=!i08L}KB;qOKJhDe>&nx6bce zOT;f!8qo2;;>WGJQHG~yoM}J=nQuK(Goh$N3g*2MUT_1g37}d6WCc*R&6cU0V-641 zu6#A5Dw9ArZJQsUCxV9SIPksXft{atIm5rDWzyB2jl0R5^1<6$M;#{0! z->4<_sdD184bVbP+V-HvmSRfDn%ir?Zf(LRx9_$t^-A7qr-ck`S}$!+|B0yjbmp2n z@)0mf_$eV(ZrdHGwLWplM*h~hRKRBL_)m4R)lwPfZ$TgY0rf3{^&GV%BY~t5@^8!$ zD4+k`J+az!abnG3kZcY}h3byZ>^+7AOfOk*IcIM*d;ek~{*YYHR( zO*}^V*dc!@=|8!r>tvyC4#UHmd7c+IHxcb{ka|7t2e$IU1n7^K#&Qhz znDq2^?5xhrT%!Ika-pFRpKez_Flz#hYWErfOA8$07QKT@z%Ky{1oR!p0Ewy$VlRNA z5zYVRNny}$qT}7y+q$<9TECR#uA=AK882S9PfP3z-fw8o;rtP|PGD~^|8^IJmafQ^r@7^yb;FAbqe$=uU@$$+Q3hu544S$uBCEga}1z1*!j|Fu!D{wX0V+o|24 zCC<~-oHwZ|U(BoiqR4sWCFRrj^?CS7KlT5tq_&#E?=I$OB14tm9%jaSE!8x4kE z3gCkv%{rl!6s?f=3s>jMV1Uhkz-w1MO2++dZ8PA$eO3{A#`y}l{*V0tX=$rfkf-dU zEaOj1XYuxNZ_blQzMY}1pa=VfHb-en`~@NVb=ya!>EQi9;U4A^ywB@L?d>GLS?&g= zIzkOy=&2ttt&@U>sWJ;nD~grT#G#V0LU!Wnq$$6`|NA|##(vv7X^u@jzD*n zn_cd=@4dK@{PFjClGT-3JP_t}rZ7712^F^{+Oah$(K7k9-hX;`M(vvMx+KOxj}$Jp z(%vWJ1x^$)B|44K7+}=;0=XOUYPxFg%s=vPOUW5wNYIRWr5eN9#buyZ7-~MeBly1i z=ioPE80`9z!By@srhUw-hDcU8JdA=TMg`Jl9J3n~+ z{1!?{P1NFz*tQeB5Bd3XUCtoVX(bOP@vRo-_|Z$lgPvMJtg)32|8XaIhm!1#_t8uG zAF(U-DCean(;b>f^;=n&tM&_mA!>A;un@H_;Q3E0_`}Tfe&5V>+u2&lLbbxI-Pg;7 zQpik&bTd$N9i2Kj6y<%LdTl%Icl43DUkFoRT= za|Ls3;ge_*+_L#+>~s}P3k@<^i-b0KTsa$KpcsxoBRlkRXK(=S9(hyjfT8f?^Dnb{PW5g(o`>!W>t7(r-u-KQD*_Q(Pp&*S*LzoKRNoc8U@FGi&JkFPz-Zo#D*lIl2$sL7q9agfRMV#ee4Za$u= zEv$SDK4-wKA)I4$8kn*j{S-1GX8asrYFPJHN$SAL97FCyu(fKa2Qbr9KYjy_I2^zI zwTn8U^#yZ}n&_|oXSXn(gFCv@6xzdcyz6Hd;oi9BViQ>nWrq1x(EyKjMs6>`ZsX0J zBZIVGk@ofE$mDq(_|vfui_Y*vzF)e4kjR>LhOq6J`5x0ETOaIGpHA0LANyl5r_%)a zwONzs_-wi zo7!%%zb3R$H-_I`E#b=PW{a=jwa&qsTgGc)s^~l*Ai_9OboId{()Wccz6OUpXcyh0 z=9NSeLK$B6aRn1p15Nym3`5wza{5A92fK#}&tT}E1j{(1-Q92HbKu(2gov^&>7P1I z3Nh-i0lGYCUwp{;N6|jtmxRGsz92E)Ln+tGgc`rRd?B!mGEqSNSe<>53clRbZ8@*l z;|~9e`v(5#W?==d-&vO1XHLM~>1s0B7)*Ez#Kg`WP7_O}^Gb2$&HCY&UyNA>out*N zeoN@PPljp(;lf%ZAS%rd7pilXS9C&gJo7tK1@ay*UdPgCR45L~9v^?Lr z*)y2xE1=hZn^56563C~)I9$*j? zAnn%Knu^;uq)D|1K(ANFvGZ%kd<1CP*wFg4N>6Zn_gK32GA?*?(Ej&y23BC5529qc zhoGZ7+%=b8vA#Corj(5knKMA8wnUpq%29A0e*qfGJ0UQB7I~kVV;xU4Sz~4w7UaCN zw>TS14nk9gViR4`3a98F*si^@Thx2u`RS!R531r__(3(+M%KW6M5U3=4fv`2NO&Vg z_HZ^__AHteI=v&;jIH~nS=aCNEa?!3#6)9h7c($N@%G0`+w$ChVnF!qcHh7{Ad_sI z@XyoCz~2ix?X)^=WOf4RAA3aLCdcj>n+vme*bx4k-tQ%84S6L-l7=EFV3SypNZvn& zzj9UOUICHoDXD~mB_0xUqmtNe>&{b$FH+VOXlEHd!oON?nL8HEX&m_3W#Oyr~HyrfN1?OacA__Ex*YJ@X38;ZjD#RPDz1@%7vlwSS7Aotbwg zvoVrnHF=%Mm*kA_&lDx-;ws_6wcqnsiXSYgyH8{3R)3fLbKB($KjoQennGv%bHmDCb$ho(=xTcaTWT6yJudt9FS%RfaeCQHxnkNN?21C@`ph7E|}X$APv%j5Pw1Z_M2lNB?k z{M;n=e@ohM8XHU5?cz&X>w9~>?Gx~Y%lb!z?ti~XQC6H+6?yY@u!b;bEFS+BwQf*0 z_UZZ?takc465p>b>-E2M5~y-C*4G0fRHp$3b0S@$|3*cc{2RKd31o@5UufOl{e3XoaFB>0s>MwY4T&pR|`l^5V@= zJB98?LvEdnpC_4Ge2^>ou<3NHhzPG27hgB*ZTbDdn6Dc+sdo1e}Vi)fNS*Pggd?g;E;OSkQD3j#UM+}HRe zUV}Mj*1QI#?sP}DnfSig;J{$W1x0|K=6+ArGv7u2TLta)tu2Uo zo){Ry4Y7Cvfie8C4$)K&}y^%6Acq>7<6ODfhn?*D60BK|G% zFFqip++x#e@ooxh?i?y@?1sP7T{NsO&g>#$n)QH1sa-Tz@Sa*q{!b_gvzVIKBT}Xp z{~=?7S`;nXJDsrGVLzzj&DC3~+^R7c#1XszA*UArxKmX-S^TUM(#Qz^nXZ;pc z_qA~lq#Kd$?(P`6Lj(bpZXTtSlo&!nI;4>y6jYEDL2BqmI#g=tW`MyN24>DX-yhyT z;at}~d+oK>eSdC9D0e^f+hNQM5{7`pP55%frT5LpTT zk~tV3TXQ|=br)!KOlR~o)cfu#T=(yYqGu`gISpj9Jidgk7BpdMVEGQJQrt&MrSSg#HTkU8+hT^ z-TlSxrOJfV8H?UFg#ZgOx3Me9kXTwiNE*gnY(1jn(U+=P!ULS_{2;=+u|(sV_-VIm z9@Te$9M##V5v@SFUUU+_BKQFmT4wzf|C7n`{wLFfxn^(J`O1?ZlDzPFTr8Dm`}C;L zm8Yd(;d^BiX#sQ>beLpF;ptrIn*4%Aj(LDvGL5}jt#zgg%(A6nG8wp~VTamD68J`a zW7(9tMFKw@eg{vY-qRJ~=-j-$guulj6>&q@2i13&zUBQr8hj0MJ$>+Zm?|OA)+=et zB2gG~b@YU_kJ{s%(@p2$G>i3S}h=j$?@yLC|(sf`vNR4$mtY&Thpx97@^&# zZMS|76plG*^|x~}o~O8fp7@U_P^(g+ygw{J*o#hB|J5NNo;G_o28l*B44_JxaFjq^ z&y}9;BL*GsD#*TwsN+`l(PxO78rv9Z#n0*rUv z5zL$?N+CmYy}f^u&BJb6?m&2vg}A0oJfW#0^7!8x*>95#Hf+f=IaRwjmfwweLFz)7 z$gj5bNYE|wFtIaeGVi3g?+}ov;C$BU(m6ao5uYH<+UQ#PYA;M93T^$Shs0wQ6|mp? zjLBzQXPJrBkC#%=5N8a{(j}!IM{s)fYsN5K3%SqoVaNe{eu4{=XO>OT0Eea+UUf&S zC`{EkzjVZ0q2XVHMLMp-C64tZRxy8Xr@pxg*KPRB75UQ7Xj@-Ckd~`z#C#Sl9=Yc+ zExUI$#!^#m{>}JkFX=2=4Q`;NW$OdhDu@x>4nX_0KgixWz``BH@N)p&^{V+i4D{~5k17cI8{%>)uOQcvH5#+PvF z>>INA-;-qRp+?Iq;*Eo8=?Y^qGQxf(q-Cf`T%C(VHtm(wiZWgxYbY z1Ap3D#Y+1h5R`Zg{>5Yg_=c)}d2hM(sf-t&u@EB_B=00nRpM;tu^UmnxJDG}1qJA1SVn3J`?Su*K z4c}xH3*+N3U-Ju#-0BJW#p!Ts)yVPP`o}|#XrmBoxEVAd((!cT!K)Niyiq5sf+(O9 z^7o1a{L#* zwV-~iZ65e;E&Ohk)RL2k|(FVe6@V1M-pQUd&HBq*8JG)*ROEZ)zVH8E+coW_Rhktx|02ac=M~_eBVzq9p4tYO8N-MkA91kt{(4ok6_QTnTtPVmR z_KU5dc`lD_5ZJbd390epWNRSy-Sq_{G1lgr{WJNXtNceTbN7)puNKK5ecg|(;Wyk& zDfqh(lSX3-wUhO4?Cnej@dhm+G1@8i00T8AdfFx8#z7)id)$-&=PIPavX}XatkJC2 zTP5wG!V2!DjLg6oh7o1wRAc&y8L~f~5cVDU5%ynWAWYDpqc&B#K?*TGFlc zlJds4Px~pKpE`j`tP1Vk>pr#T}o%v?GO85lLDkL zqb#lwkjbCs*z*#9AOtg0_Pk;@fj445_nlj~X-Bgp%@V z^+|Tau-Qyr<_=&+c=Acwb)bVXho)8o^4~I1UP2qRdaA_LIg2HB(fnwTC!Kn5pMxTV zb;)mVN5jT9mz(NtSBek;u7cJ%bQ4L{3$G*3R||g1dL8R33BJ1OXUJE?M1H!W`Z?GV zfNFmf#=2BrkSRSjxrnj<&=z{`SR@BijVk2UAu`%CExp1N2$-=rR7|mqq%)JZSp-0a zRbuxYnJhJ!6^w_Te)D`HFR_9JMP#t?QK~X6vEXuM&#R>5%uC_v=DPGBL<_TiCihNO z1JqVGPH`t+L=}~2^}{Q~jw@&r;fi%bDNp&Djb(-OkuH2+5=jv?pUz978d*;q5H)SV zGEwXYdJl6S33z;c@W!mHIeG&Nu-F{Q@+Zyq_1ECXJ(-!=N**D{K4HQyj8!!%G|bF5 zxG%@{6DBI6WIqx$rx~9NMLK2E&1|UO%0s@;8+-@yCa^hJ|9=IGQs`M!@A!G&x22Z{ z_bIu@a`|&3Z!QUBxWgxayWdxr*yjZ9ltC#?mWCTRqp+O*eaXu{k|Iic{h||;fkE77 zlZ$`zz>a8^lP&V)@9%mWATg6Sb6N#5yl^4gNi2GzVVLV)*edLM*sQB(E;^l6cN6Ln zU|6Om6O9OaiukK7AF}ZlKMeuV2!D)598^hEc}H@|{lHm175XrL^@m!leR^zp=PceN zQL_kK?M+&ty8h)s6Z{X6w^)P49<)I~L@4V<3X}IL+XotA0&qn`^s?TjIuy?Z(b4M-8m&$Fn$#cYR)W`QnSSx6hsFc%#LmJ z0zs4Rq~o?GaaYUl%kNO)y|3?JjwI27Q6Sc4%M0DF0IBmM|Fjj#^PaUQJ-|P=-{0Tl zpLue<4f2uhI~#>`1|d&DAJ0@x`k%1V9~#AwUbEOS4Hzvr!78oj$9JYam|SP8^02t> zs>K^Besyw4XIQ=emnQZ38P3YDMU$S2sDM z7Q(uhn40$A1kte;)~5i=u&egC=Vw!q`yZFrLhJ;YOgFnR5K-K8QZ$R~{uf6j`Fzbk1)AFglamojOhPrtvGL zf!|8XXPv>%xbOK#!$V@cMH+RkDuRsz&I;b2!=S?^0!fC4D$>5%G~Q0=r}*)?vWXA3 zliv0Q^gf_+l4LJe3hlE+TD0$>e)TGb8)V$r)VuBLr0xZ~|E?4+Z1i_S#AHUH8W<{r z1}`MfrNfb+aP3zj7-A~+fp$VSGxy6pfJm&-d7PXV9};oMSx?QOREc_u5e%e-87zQ0 z6id{-vKM@2jLP10B#AjT8y`!)vtw!TO3O25FcGm=1jO&MHreJ*heB3PZxup_qs09Y z;f`0$>>V)BXMlU^LDbxi5rtS1R*hTVf2n@sh#yQ2DSG0Owebxw)|5N6joGQGkttPz zuU)p`xni(ZhU=HMZ?ME0v~iLEH-&)hZ6+7s{R6u7sn(EoI7;(A#Zs5ELK?LxH8((< z4q8J4N+X;lO%d@J3sNSV_YXW6sb^mR)iVG$rj1Y-qu+>#>>G?0QrWinSJ8uMFaYcd zTpFwdqgT;2q2d7U6-%+_Jd;um_Cr0Dfpt&5r2;dq@~t85z>~f#OVk{dsamTH6%iw|D<+K=OgW@6w!@gwpm%CRCk;)~2`C)w)Ps z(AL8jS2W6a(>nw~z0aE-`W2RDGVSf_L}eH|#y89wXn}t>52?Xz@yl4TRh5w7BPTf& z0Ktb;225<&vtkK!$g)ARGf?tZ* zhCnt-b2H5IFU^WeNZFK=6Xf8z|! z4Xx-S&>4%jK2Uc@-@i)~54(Wvih4dy-}gh4zP{WEzr10zf)NB~)H!rA(7#*$q~fZ1 zC*|?rZk)KvFzj~Q#&;=Oj`Z7v*f)k^s~Nu=2%mJ_55wj9R|#r>EM$s9AozH5X!?a< zo+NdY{^eh+1DxTbBu3+OdamJms1ie;kG(knKD=0A4mkV~{yFF;ikggr5csE8PegoS zQ$|QPfwj1aBfB|2XmS(yEE4b<2_DJhv@NxIJ(u6R1`qtTQvgVy8O*Kk3@C4@P7KU& zn43s*?SKT3|NQ+-R*g{OF66I>OGW`VOrJ%p(OPM;R-ciPSu`$5H}7%Of&V(*GNbeX zVB*4{Osq{F?HE&__LrFkaX=Br{;MSO7WoMmZ8NAdNkk4cy^%2{UsGSxnWWq$H-3&m zegZU(+Ed?ocm}nB%nx4iaO%O#1=1BGckcg}QgD82anXCVYm#5#SpV2v25tdStxDuw zugKOl>W|gx+UCt4;BHs@(=BW5@}DvX-X^MPJGn3Bomab$h-LHJr7?pV^Rh?RVu>Hv zgSvG;T06XSfu3g0bYEMLS4=W6H6CyrsORM8u7&tV2Tdz zk>C8Jk4-e_Z%b(N9~iee$*)YU9z}pzFJC65%I62pPovK_-Fo|Rv9kj!TDqoIdfK4l ztutmPbkxmsYXziQmwUEb&{USd#LOSkPKR!6pNbnLKEKrZGB!e-qo)>CY8hm5V=Xk znvtdl`-N+$Ga}>?~3ij!IjcjIS*6u*;&w*5nj)w1!1TM!FssfQUjVa6%Sn- z7$Y%PZHj9{t=&rbfBD@^m+FBpSC~`Zy*2>{pKO}llF)PL#ed#IzeH9ns7R1j5@6U-38-8#(Vv=b0}-9oxW92QhfuK z7W8ew+S|PQV3~~;1r3-bdrzLrv8LiYS^v%9*k`5jYyHAT0x7BmemY6^P8NtZSd~dR zTRb~m4C^zGU6vCf+#eTF4Ly%fT_SIHLqSZ!d5((TA+F9}UlR6UukUiP&nzCJLOn5R z_TAAA#oYgf_y(nt85K3`RaVrhU7=Ax_!vug03PZeH1cC~Sy8&F*DDm~+Yc>bk!-1&-#L;1Ka^lb z{6jUqhWS7b(OEQBuDI`LN1$5KQrWR(p#alhvs1+rr)b@`* zW(-^Nc!*BQJW>LDr(*dAI*g($@)+3raCzGgC3zOyPYFR9GLB^Qpe?MG^rhr;bxcdq znept^Mb}3pA)t1c)%v9O!SYEp8@WLrKs=jCrVfv~g^a=onD1=60Ae8f3L=qHh_l92 zm}ZRKPOD=pyyv{eE03C(J0F_&rRVs9IbeELSmvgySPyef)wj<8LEI7rSdfmSjzJJ8TuBn%`WOdkqt$5Jz4(U4^LyOap*0Dy#SU=>y1?|5?O0fYM>HzLHf z`JYaJusO$~z2bz&1K+OHXBae@FP(Kmi8)q)mBf+W{8eZWJDmHJm3C-lTp}o1bSu>3 zyYIrwX2qRZ%u~ae8MS#VZxYM#n&TIE_{4oH`-%>ry%WTm&Tc~Ee;yIM!!0J}>Z~u} z$?Kq#&i>6S(fU{K8R7TG-2<0J9TM^0&jbib-68+cd&&~1m%aI6TKqL^Kqo7Of&rd! z|8a(f-A{Ive0W69TD6H(sIS@)*#WkV$}p=V0S?i)^~!m^+86VikcZjY1AZ)I)q zW$2^978h0VdE1hXt6?bTHwNkA;>Alj)FIx3_oku|D@HG)eo@(KG&1ovgx<=+tz4TW zxQSqdp0>Hd>r|0`A8-pj9*&J9i#f{w+QWbN(ib7GAa+_&3EnDW3;W;wzF8ax&Yn~E z6kt`=LIwl@yQeSzY$SBs@>~5Oj6Ouho!4L-Rzk&>;J!&`nbFrj4PmJ7;Ep#Hcl6FY zeFf1&PtUiUixO7Vf{{@4s3cG{JC=zxn2y|J1u%t=^i~O+P>#_&QJajSj;0su&9uX6 z0w8!QgXmXyo9ph6FXVZ4D5cgXInk}dRl_@9a!lw5opuHY0vP(-|0IdKfT+GSl<*99}WzRY4auhI<^_8;#Ewbz8>I?Wb?ZB$p^A{NeyGfk#S}>6@a>C-% zGEb6|{foyP0W;VQRt*n!&iWoYKJ#)!6XBX$6BhT<-NKOskS^K<_~}Ij;dXxfTZYzO zpXoKbkMR&BQNFG4PN>7BpAmQ)d&&5{GFhcjO# zE97D-w;5m^f1yKca8AAYOYR zy*7BpZ?y^m@yRN`HEo2#Z=Q3A5BMD0n&-t zZ@KyN1hoB}^wF3Lh;NavxR8+DV_t!jF|QO|B8bv!?Rpv;b(}bWGEggEAm$O885wWL z#AvmS5Hu>KI8SSrvUUlUCT|i7et$}>2AkqdPUwHY5IJYY`*hE=XsF$mYysU)uQzcR z8~ox4+60X`gcA2au(ptj;dRU#AFlswq(cQlEE`2^P8V>t`kIIV%~`_w!o&@cTD@x03v&ez{yzjj5G^J$-;?bilq2YIyS{DH)!Qz3Mq^@Vzy8 z`yqlJ%0bwsy%*uOBe*dtg2L_-s#%pRT`vyN%pfBPug1jEh;O;L0x@r%Y@UPVTE0H# zz&6d^X$AX&CpBlx0i9%1f}{+C-rN2FQftPGulIHv zpbEwrrB6RT9VqUg!{)7XCN5`^+4;d6B{x%Alhv->)yJ~s>EmAdzb`FR^ZU~-kk$%z z%bwGm^11=z*RvFAFsqaHwE>qi(-9vxwk{Rp_>a|BxqjI;@@8sPBxT$gN8N_L1U`1W zExz5h3ulqW%LiH=uU`BeX5M}1bGw|02Sp-`%u6+n zud&xsqcEr!fBijvwt4I?mn1G}!)&z#;jJpb{n6zEBL=78pB-;|7m55I56N0pTv`TF z)sRzP|765yz)2UT0J9a}*`_PjU-oUH4w>^d} z$amOQm2&{!zj8T5!L|Qs#6!xCV&TkAdgr&X4TC>>fT9bc5WJE76@@^$D&TYcwNw+C zEVk9QYxv4Q6S@fg3p8#S%mU$vX=;og7NCv}1E#~s_4)vcr_Mq4$Kv35uXJq>mjd7vyd%MY?w=WVSuAXR9@U zm*4YmvyzT_m0$%orQ`tAFZKS}w~*0IC*4xfA;xeS57Se|=(&%3s+qwKU8Bm(ys6>j z%Wg;~ePKtYvr&`1{8#*qBvjL4D~qhi@#ZH7%T+NAMZa-`PS7giIpJ(nQYMsbE}5KO zl6TyRQ;#~@bOd+(5s(i(r>1(W%PoSwnVCBm*{TKtTLG!T`<4-j_?o7aykh|)GcITN zT6vj2df{s5tZ9nh99!?YetIeORo%#1*qK9=Ow%aumT4mYd`VyIFdtYj&`77hi!cNJ z94j|Wd?sh5rTQmKaPF@1e%ZOp*>yWp98)(^*S^n;D3s#F$5@vYUO4pusc_2K9)zmM zP9q-+dOx!CW)6%RHHu7&l7M1A@{b56~Ao06zju!vAAIy**Ir2+~#Ha!GCf36&*^!9peq{B=<_`IWRL+y~ zZsodK87>aIps~ywV4y@qwb55Sg0dH6?xaU9AWK8Mbui_8+ZFkyp{u-2^iGK}bOFUQgQs3%ze6ZL_EQYifn6KN>Z5 zKgX2q=nhiBVuD3?1ySYC$pz1B29z194h}x&;JfPsPQXH^efW{9+$+( z|F@8pnHa^_&DOm+2-~B4-YC1*xa33BLR6ObF7`#>W}Z<#_BcrW{#H)lK2eUA@PF9- z@jNTR*WN-+=;`LV4`*c=?CSM?hU2zkBY)pOrdi~C%9m9)Z6^Ac_hT%uGJ5wxU|iyZ zKA^Z0bzq(AX~w4>`HXWV^wAHV`UE4P^fz{SjF?~DNwd&l5{(an7LLE;*GPky4G6_E z$mlOOS|ZxYWFCcV3s5@1DJ|75Gh=I5<$Wu|z2@29e;MTkYc%R7Mb?ow7FEuHov?qA zmA1DA>_o)z)W^6h=N6}Pc}KD_1tys8-NOK;C=p^}dC|WI|3G|W-(GZiKC!&m7!H%g z{u%2(I0Ux0!09Zz3#dlY+B%5e#`92*2pdrD!-Mv@F{dj?T+&2^6$w!{yI9xck9A{oytU$_USa#aK{*9yyEtcoLdAQY*RTW-?$ z4jO?4er=3@j4ya@JccLlO9g<$J401#Is52E!5x{d@LhIQq+6f1_95DpRZMAI5Y+4Y znBo0zhNJiR<}bk!|JZrnsN9@ZgITwpo#1hfvSLryUK`#TINdn)L^9x~d%32;zegr* zPO*WZSHly=4bOoU!K|)>IWWz3+U=(Jn&|Fm*_b~t;Lo_motlE|s$O=j*>Ffc2r}69lY<(1jKCZ*mI2alFR9$nHPzbk-N+l6t!Ptw*xI6-GaI zoriQ^EwGZV9+c2NVk!fvMW!YZ3|0UKq*qgV$hL<)ungoaWMPo12llok+6jy6qW&QO zY7Kr)27vuZ!pEYnUBKcBM3ee$1%M3hfaXDz8wJ>@7mY2H6kN6$NGO^!8V>}f5kV;VoWsq4# ztsrC+tM*jAxpkYmN3yvbY;*6?G40OsN!T=hUuE}qsZF{9-%hFty_5G!5oct>3Q0Tj zlHmMV`sj-pcIHUe2_)njWVx#mJ|)k^lWGh2Z?t4V#Z8&=B|}VIVSk)VPPVt9t{13X zf98K#=ms_7<6bYWmjO188_W1{E}TzaB+|7nl?w1?vbjq&@kj>36d&lJ3Mhhb)|E47k>7NL-JE{Oua_m_q}viybI17 zp6WER!p%SBE#>)MBz%MdM)Pff|&`+B%U;v@0Fp1^IFCT2%7_RaFuv-XuMZxaQe^(W-YCsE~*`OlGsB_qv z*Blmx;>);nzD)E#Q-6adHS69MIm2$s8nlb(?tsUwhm$Uct{A^(9LzvyYGp1h*}Xl}LN0t8 zy5VaW^ofc;xWY;*#r%zigOgmo@yG?cJr2_`sO^1+#uA zc%N){UPevL5Ex_Mdcb@)dfsev3F6>@a8PcQ4>IDZQ40j~e}Z^E4T;7qBbkn`xOY6Xat7W)vw* z^#i&yI~P5wh4Mp}v_(ID2AY3%y+wYYH+|MES3QF8nXh2<`p{v@oqtsWV0RiiiSW{V z(}h(qPA(@J?WuW{f7|?UYGD@Ox6-xQpQhIahnJ7Ne3A>PyB*IHGZIN2~#@k2VYrH=tx};Q(>~oYbBK1GW>VFBCiPU5V4EW03hE<>Z2R zGb~~{DO$EZDb*$zc>Bk$A~*6{@)?3yms;Z%RI-Y;?a<}!?v5OK^E2U{mvNTz7o)cg zDhZt6Z75_f!1Q6v2NH(f0UkTKEZyj*@S4@0i0Suw!b>gm^#9suB!w-`N;_J5DM3q! zcp#0ui8?mzr)ug2?Pnm=Z)4F;_w97~NDtb!QfZ{1T%=UI4BHUV=0z)|l7y>T#LJr8 z3CD)J#it)FpcQsq0lzB9KJ{6N0=9Mnp;U)6KN}YGiq!5O_rqtXF5V@M3%|cefJSeJ zBy2QB%eQX~=n~Bhi~>{-+gBVo!!LKV8!rUkV@pUnOwo@&_WqJ(vWkR>YJw25DEP2= zC*nfZw?yPy&p9;2H;wz6CT+?KmbjE#iXHK$QudE9{%WaIHDD1adG~`6Q_wVVV?vm; z=eE7I=)N<%bhHQE!pmB43!^6FOBQ23XAzJJvi7@^rD z1bdq#`S{y2MvX_qyj(7XMfl1kHE6F4i5uG>Z<)?Z$6QcM%KU5E5Hrj=z?UdXu~%sFQi|NlPfgqP&p~(H!b8Tqn+oxM z1z&h#DQwbpk(NV&AoUQ_fMwmFn}&qIWJ;iwN(z|0;Io=zS#mYq$RBU(` z_ycZa<)v2dm$8SLq>)yl6(#I}3&1GsTs`34hK%PmyPG1RD zuKmr6q4M0+l`Dgx-6c>f-j{=)WY&GcQViL~?~u4HZ3i3MLF+mXjX~jLq5)d&A^fLK zpH{rQe$J|L7i?ag{t(!i_kWbXlBLfvr93^JFU}^4o^W~IDyWPQ)&HmV5Yghe#2}89 ztw|V*`*#P4qYmRJbcDkek~77CsyWc7rGtkPh}eivq3e-a0%@$}XR$cZ6Mx*#rNI;# zbd<+dMlw00vLxu$cR0A!F>!pYZM8ce zSz+N!%%m=p4c|PzkK4DG@elvk-292mXu05z>qL}?MqV&0N_uEe4Necf`|dZpAAIv_ zXeS=&_=FQ0WNC$W!K2Tsp|9|=b?>S{5X-l`pr~4}38Iv*EAhEna_AsSIR$Rd!8RL5 zfmyJ{`cs5*uw*5cS*+`j*s*tGzPa=YuS=~;9Gn#Wm?;-Gq@keM4{>&#@8{e5w@Q8Y zT2*314X&2)Gzz2T1DE$`znHJKqAMUsaZ}HheF;?8)W6U; zY0a!Tx7PpM@1~QzOa*BS_$u#cKeC;M&sOT;^tIULooRmWc?-jdnrA+@R;KE3&Zt|} z@Vk#&`4T!RclTJZ5Zy52%DdgoAN1wF}glkfxZ%x#K09Q6gKT06=IT#-@X7AoYbt(J&&QuYXk5o_FxycGkSdYxMG z$z%F;N3MRML`BdOZZ3~--rYrSEyq_|A3UZqJk~F&z==iu(xCZd3jvV=&X3^P9B2fQ zx(ueKi@iwn-Y;dCQ)dWeTmMI!bTY?NkWn+A%-(#PbYN=ctIxV9V&8Tw(CqwRBreK!TO=Z z7}Il#cRzpUx{tlrdiA9NJP7GKdiCu-oSH-Cytzg?yNo7K;`8swrA9~j!G~{58c62a zFpT1pF_(6`g<=&yz+eoBEMl|8RXpD5EV>0QpY-!loLD4XThNWl4ZW(K60N%H3hU9{ z_!`ihEBuISlstMrL;S6uAtXSB%f<{{Yb|0H6l6;lngz$coA(N!$Re~;(pn{%r*xW@ z#v%-WTh6FNi)<;Mf(E6XMl^s)%Q@vgCf0Vt`xou=Om}hl@o@a4}22;^81P1ll@M&O#cy z@Gd_5QN(5AnfP#BWEw;!L=Kw%_CRDZMy~^1X7=xEtCJmf`?rLK3QR{q6JmqSg(~5MJ*if@G1EM)FP`M=rV4JWqCLd@VORZ)C$nIHMu%FG z3w)I0e+vNjv4`{qd02{-;9eud3LH#-Pr*NqHg45gJozKWU;}OFk6z zxJF<4@babEr|e8YbBD?sL*ZSB?DIEK`Q+g^jEnTy;I+Bffvp^cL>ZPEPO@=+JMHd4 zB}m(8*NY4XivQsnLWS0e>(hQxt;AnOUxHCgD4i_ zQ%cRepKs#z7RYK+(r*zP?&AL)R7&;5(*2OYKGqpEweG)FI4@pA^@2Zj-`h%hTa%VU zCyPpXaM2HW;qB$G1dVK^eUUpUdC@;uM*!J*d4nbJw}c0WG&c3rH{Kv5#6j=<+#EKpE9m)(M-pI4kQWmVTOTa%GM}8+@ZD z&b75j^RvU$uzqZEGA*E9KRp_IK}coDf$`GHeFI&>kDdCn9amU5_~Aj7K3MR1<1P0+ z%%5u0p2K;Am~a=Aa|};q*O=%lI6QFM*t8|qPK52xMuF3>EVkb=#-w$PwKlEavBKa7 z-(!J^xKA<>XPnPCQ(JzaQA(4$g#9J(MGKqY9XbuZ>M1*}v~bG~Ygz}RwvaU&1Vhj1 zMlW@Z)2HDh%0*m>Z#&IRMs%VOQm2`i>1)}xoz1xISI2YWW7bso*JY2+gq_>&n8h*@ zlX7c+Oh>9kA<-7Dn&v>}A^P4Hb^Gr`$6-$cqNfM8M16#&r(fFe(-46K*K3?l9Wt=dJp$ zcZ3fGwQ%ZlWvhyM=Po`pHLU{&WkT! z$t%zj!Eyo1Zk(5Ll#6k*2K|e@9{#a7ybaK#e9IPN6n(}deGUXm?S236?_)9s5uw2C zkte?!#da-h&HA{xRVsSIw*{7};mhBi34VLlmJ@fM{D^Gsxk}T3hGQc}p-4FXNjIyr z97znd*^=J2X6=%A0+F`N^_Dgl~Ho>P7P-$FQS@uW}ISRmJfO$WMw2`Z-Gy&(ST_MO@K{6H~LjO z4hyYrx8@6nIv~N>yCbM}Kp&Ulz~OSuM~fFb4HX+E!29S~c8X5qNo?n*M^inlM8vAq zjfm+4msoImiJU9L+~+_yQp&aTKV~yNL?;TGT_aAb{4n#?8_oRrQ>&m`D9N^y0^js4 zPQ>UkSQuTfQ+WjD?M2Q5*qVM$e8tZou4GAvs*FmL1!4q<0%dYj*fZ{JVG(T=W1A-2 zl%iV9TLEQsZX6U6Q+fOpHz%kZ1IOS0S}oD?%W#ukU}KD9H5+M5*cNp&R1>`4n>nwM z_h}`)SpIdnwSkz7#J?5rCJ6=6?=+E0E}u3G^%|b|-Rr!C1}jouIre*)vi#N;Z7h4J zgN?Th;H>dHW1~-GL%VGdLFa;##|{Y}*g6GL9*zkzOcczp6U~DQ{ohdba$ERTVz0Fy zISzmQY}-~W=I}%R$2kQ9k(OtjRL^s!2<>=YRfI*Eib2Z5DamveYdy@6$1JC4zz19H zSGzRmmHoFp!@{z20Vp~Ho4R$Oq14@iFS+_-&Cn&-hiJ327ax!pem!D1w8m^ly-Pur zFCeP!p+A0^cf2cOZ<)P}y!fw&5SPZ(DC7m(%CmdvF9D;zmI}WIW$ivGSSGgV`oO1TFmylTCo0VpROXXG@!OHqbP4 zCURNCg{}KBKiM(io%+eaF@W_}CTKHsJm>U<=#y9d1*CfsI0=1t?KJt^Co7ZidN&j0 z7zN!>#{{yy#EP`DGH28PPdZ~~H?bUp%g?A=sb$DuS`sZz_N4_y}WO?tl7b@Y`cYd}`w8tKr~}?icsIat6<8)L`JL z|8=v28{rd@-*Zc)R)WqJjECLY$Xzr(1Hnj8-M|l!6Uy(V^Lmyp^s^AwiY%*R~hZUs| zHlRO{Hm%6Gk5jc7ChaaX@zNE_tJ09?Y7QWR-v8a~nULc}sZgCHy_R2q zZ4s|9^64D9%{)&BYXd7KcpkkW7o0V;u#z>;Rfj_#6EOmNZl-U#hl>4jK}s0vG7<4R zkEu5c5JQ|Jo^r#Qu~6aDLc>%0UAO;iX_VfM)vJ%VUtE4818N|)ChJ*~bfvPq_9Fth zXCGLFew@jW7re|iQ>D_*fZc8M+$KK|&eAz}*abd+NF=0%lX4loIot~V{d%)q4E0*} zAP98W!Ex2!4BRz82RZRwlblL|gG5X%*PB2mH8elUY17il7 z8MPEv4=Cuy^+kkO8pv3gzwqz)pnga{cr@|ZlE}v6JtwkANZBfe(U@h7Z}5rz>Bs3w zO7oc)j!}d`u6hM917iug5*}=Fq{ayFWTSQb@qNN8Eo>}?)>ua(5$wmSz-fVqL8SbtK6^0B?{*`>8N?! zdJO|ni0UD#-nId7H%+dWs-JCS>RuhY9agJYQ^lKWdFe5O&A(~vei`ms=JEX9A=mo@(a z!gHAje&#k`HZVBCU+^esr~i@PK{_#xLs9{`JFO4)(l(z1Xn(i6@WOj34FCjV7HLT? zy&f53K4r<~tN4;gH4+%xJH$pvny45fBfVs3#XbuOWw1E}9gjHPun@8RCZ;M)+TkH< zuWng@FF{zlf4tC8b8T88GewTgoR6MknAsJ5pNpxurQxDOpCQ0FOOxKu4i@O9|H+&7 zScU+1%ZyF7oO|_e>gT#?ooN<3D3AO3pOW(Yms5+`_!(?+V}X2Bd^a<#g7^W&at7x_ z3vh(G?4p;%pG#R<>8hx0Xbq=xBsnlkCCA!z_S-Nq6IVg<>*;usZ z3vako4p;mPR^9&NEuKa!*GT&`17w%@O2VjyU;Er}#^k(^ODN^$j0N(Uskty4aWvb3X9Z7!J3R%n3Nx&??Gz9|#O3Yu ze|(C=+~rZT0RgYF&{kiqjq;#8!||DSvb^4}f4}l@pBk6{h2qtGTy4ZZ9Tdh=G(aO1 znb3i3zN7XBbO#s4_snh>6KFGi$p2)|%X688-DWa^IPU3qX@l?zY`qJRXUy0a@(Z$H zbP^h86M#ExgMLu5742nVQc+(*E22)T%6qxT4Ug>B(Uh^mtxZ~50nkSKUg2bCXv zIh_GYqQ0?v16?<{bnWL?#J(NAF9k|tv_D`AZh@Y5=$V2leRUq#=x&3GJ0MnL}= z8+eYKCHYtQn(lf3x;ut|P|p^UfQRH)X>l1OPD6bZVL%7WU+*qq9g{eEd)^f{w!(uB zWzVg;a^Yf#a8E*L;0HnER;TIYQm-eC`+Wp_*%_cR9Rz^%yH^DtBOgD6B>XoW)_$6R zn1mEI6}G&4g)D0wiNlYl3O?%1t6Z9P3J9orYef8uqqqr+>saAcE^tA8wmD`#{9BtU z_t{BLW#9ks3!3eo78pKj$8<7jiRsin(TCFU!yi=NzyppSobco4VoJTXJ{e;XG(qtm-AGSEBG-F!Q~u z6cu_7yg9?ov{?W7xG_E8`EK?&==A%~VIg+j`d&~sAYW9~D9D#CbUE21Em z-3c(eyR6^?yA5bv+E^{-_7EKP2b^}zsU`@tK6mM~M0rmZhq>H3%|ma0K=I^)>dU@ zZ3=f?oKtymhu>a9Ejq;GuT!!TA!C@|6r@@0E8>~2cb-5~VDxVqNlcKYzccMNM=*kx zU{_?o=qI^1oBVU7&-J#cjhlJG8WYfN&swEfi7_`JVzZd~&=>^J1$?_~P+28ONzdOU zI~8p(qSp;g4x>uQtZjm1`vOn~rACsU{rI&ZHfNA>D5DNu0=Yn|GF={BVs6y=OOYh%z_n+T8C%0-C83v1Eyn@aO?O5Z8w-eaO+#`Pq6 z;`6T}u_$IqDp+%5#a;6s9&)<}1u@CD?_K4Rvx_|G%YO7LR=}4u4lL1k^2P@ySqiyl zZ&k#QU9mhQe2ndJMH?U>n6C~!nggD;8D~uV{9R}-f3oMZV4o8d59hzBYp?MY>xYMC zGq$%vRP7V>Le_;+;6(070kl(PZ&u2NJhFdOnel`;^2J9USKSp#<39bNIX2$L139-O6#`x6 zs>TjMZe1y)e? zF*^)zx{;16*oE0f1npz~%nA8c$mOJHHdLAlD0@Y|3pEwH7nbyosr(eq@W~&4ocgHP zl$KI(F9;lg15FfXEB(bIa-M%>Ha0}dPe@Pj#E1B&DbYaU!reLXbF!Gqs|TxkTCDO04FHOi$s*KED&bggeLWSb2TQ*=bvO`>H2Fu816&(JHH1c?R10lWr4a^>gU& zpFcL(Vkl~;keWV#zbeos`?h%2gf?tRot*EohQJzqhK90KLvYA*kY}T#{}vxn5>cG( zxjk&KYhPqT7E7-88SX3NWNdD`!f$Vt9r54=RxgAlrFB93tVoNyz~=tN!FqtN{u7(> zIxZhJeP5`(#2cDpQpM|$m^YB0Ha=Nvy3@S5Ea}D6x|%F2Gv6h`?4_Hn^9jd0Gqkqo zJJtkn!SehH4i5TeQ4ZrKe_hS)W*DCX4SMF{4{JDQpIbk`!?cXEn+M~1e0x#kpHA~# z8Mu^3wSlWY;<*TwCFKp?4{Y|%sGW5WFrYyc8bq_ubN({PXph6<{OhLyLZrz z?zI4u)SrS6L2}_D|DOv$oM7YDTtQA~i*s8MqUW5v^I7GF^^q0G=6n!45$e`i-#+~d zk{o+gcmz9tJHE^f=#V4C1)_#NVGs~E7nE-ZwY9D<@vDHZqIkPXxKN9NIDRfdmBoev zrHWWa74_p5Sx5ZokInUS`0J(6pNVVi^Bs-vc2a#a)M|G2UN^5xKmr$_RqwNnA=ALF zRB~{Jf-d*ASNfS)UrAgT# z{ATVyR@tPVe$kXl#`_{7*Bfg(R@@i0Hase-eoMqsC(VJQ1YQTX( z7||2xChNCk-izCPa=N3!BT5AE=%XN~w+@6P;jRU{1J5r+ljnH1FaMb7Hb^xHX&fg{ zGTUzl-njM}S>n12md?DO!U{ZZnj^Jx|B_ zz8=B2*e^M>D8U$%zsz7xk&fG6eujW6qnp(dDrKWI0h-&FrV@D775r4CK|ON_1i}#L zsSzzDBTv~H7Pdtf4^DVsg z=Q-uVuM$7+sH05yq=p@8W7nxuLob?pF+0B-BxRk`$I#G>4U<}*FHuAz~7e7(LeNf$rS(oy<0R}MfNRk6gSnf^L~zdjg2H?0KwWdndG4U z?q!Z`sj9Vy&jmWp0Q=||=?01s8(8%Lu7gUu0ej1%1?!L@XKi^aHd~$>F(sE<3!^|G zZVlgZ9g95M`^Ako?x3*$Fjoy$M;Qk&HU(>&<+f6b~f-}TjCE`k62?a%0K<%=3m|OlV%Sf zLr9~$*XrJ6uJ@tN-*}TcZZAgg1!T}^*Yw$Wx&ueQp$P?*>%mRqsvo|}>2 zkcLy}g*N4j>{X={)IDz9}f9iS*59V+#K!@F!+R-)|twr z?Zt96Rl?RT5Uy9zt}U@;j>b7y)I1YZj0!Nxs5`BZVUU;LG(*?ip7q{|vmM~|h;Bun zASaq>i5A|czVQ)lp2+@;N!nxAi_X~8O@@g%X7Hd0O-7CW>UYJN27qPbKb!8S_D{Nx zW+f=B%kq|D;Lv#_H^(~==hUDWbBsF0{;F{48J4ka4Rv41n&;d_bC?>+pK0H37sk{G zpPBe2apeeRzPv)sE3LXmF~jVOwmi4pENf#-n&i6#6XVg8e^|Q7;Y((gc3AmI}m&NJWpUqXcry^{m z$96OQ`)WLSOpa`Gn_pTopb~#b z*AGMBR^40AG0tN~N9kBpOMSY_3`nc)z=whA&4PdPQrlJ5Q&J1z@~uTuQtg0iI39w~ z^sT_fjw-YEBw6QhsJ$_9Kax^`~qK)jpq%Q4T5wy<=YR&z!(QsaVRJ}=eIoAMRz=zM)?{;#tz=e52$!P2J7y|}9zDz%;ZH{{El`F`6#NFQf`jfX-z*6+H5&$sL9PU@ zKNBY4gU(8@V*`El05*ogl_(Nfbdh+7ऴP}!dbHCoyjc`G%Smops#~g@dehP9; z^y}$hUz#eFcXLq>yl7%zAt5M7*&hnoxfun}jh+>>))zXP00pgk;-I;OKer1MUAbIe z9TYk6&#hVnJHYcI^EKINxU%v%if4c;x?*szX>7}6P-54z@#Q{XOFR?Th}cOuT{w5= zDjj_^Z>Oqt{mKwpO1c((Y-k73{OMaU%UkSwIrx!6S8vCyxP%fFGAn7`6q&F-3EK<= znc)s{Y5KDOQ^~kVIizP1bfm7=8YU-O!z2Gwoe&^p8i8lvnT*Z2ZrRQ8y9N~PLEl|Q zWfaPY*aYT3AyIKz1R^P!6?=os4(3XS=I$kDGCGSK_#*GJUW-aoUhvG-RY%gv$9E!s zIkNm(yR4q(#+4Y}KEP5&kf9ri-}}k!%$fI3D*rNWb~dx%piJ03yWwcqzpkH6(DNdy zA$BW~L%@`nIYF(MIMKI4XP=_-3ll`sU*oh?Fb)Zno;x{U@7(X~;6MafErkfgw84r% zscI=gHG@UY`<8V&J)Ewv4{lxcfpdx6G}@o|z`OX!JP>Hvqr!=)rD(WIg+Vj*@Tzy! zL^jAg6~eV9fqOqaj59)3EsPe{dr%jkx|vrUN3Z?j$oXV{KRZwsBVmzBFwIWjgiKI8 z!qYlU%I2!l7g1{NZ90NUZU7_C(sCQKi+Upu_w1X791-BfBgLCHBZ{zhPRuKcrPEVw zr$tR*9k+3?Y2S~DutX?5;IOJ{I$n0sa3PHg4 zq%)A5_m?%kzv)HyGUP|V5E|j3Gj6{b&J|tw*>C7X!ebzlPSr_lL|t z;NP~11NI)*>L&UoF7GIMk9e{Ac0lZD=5vIPw9PM0-x-&RC04>00P%kFPU%hm$GFXe z@>cq2*UFXYuN9XJwcQc)0Xdn|@J&>0`F93PkiGu}#p}<{+2&dOZlxCP4(LVTewk!D zD=+0T+0d;Ilb)Pc;k_?s*c7*wTXos3pdVaEhs|MQnCXz?4wwl9uYTiz8xBLXP87Gb zc`FB#-cjuTDtiW*+ zgJ23MELvL+Y-pfQcU2ZIz^@y1@lo{!G<=o9FQ-Gx*Hmfoq5hEtQTlnS8&KvsZ!}Mw zcZAgqpb|v56+x?psCKgU=k(W~F|R}4r5nK0{)UdU?2qx5EbY)d4bKW8fi(^0!#eT( zx_7BMWY3<%?N&*Ay`(lTO2cpd?2FqdKc;GMxb8rop^@x`9!%#G-cioyu1%F#lg*sw<$+kbD`3UOp)= z1?BB@mldjo#&tpJ6IN?zkYcGcCo$ORA@+-IXD%PpU)OeoQCHHf*|Ues*ZclmF>K!9 z^>J>h>aQMD7Uel@8i~6f8Ty^X^dL?R8%h8>n;4}gEVk*@aSY_n$|JXu&4KS~Ds;U3 z!%eN=)6kp-jZ%eb9? z2sfOuz9n(TkhjT{4=i~CQQ%ytZrf3zNx1C|v>I5v@^cM(H3TG`z*e9qBM6fP4>ZO1 zpxmMIsI+XtYWhFAO7iL+xl3Q)5fc9N%gzO`Jtw~O%lUD2z&UM<3vA$M7E)fZweK-fl1{)exFDiy$!{kPX?f9=T=gqMj6Z#RjRfbJaTa>bTlG;~dlOXz_0Ygc{kiE`JNjj+MrGoHL z38?3pxYsN@zTv$?n6(IKV5MA;DdOQi<|!WKJ1E>)&kx^$S4PaF)G<+{M;ZnBHasOI zP@Z+RcDnb}2T)JHsQBI64UzstOgwd8n~NY{O^f4#exFoWE-txcN2pb1tQRF-S%UYV z4vyUN&@V?wGizz$+Yr(h1BQ>Y(g~{^r`C5P{sE4c`bMmA z?>5liUP?C*XwmeXC5^vTYE$(b{Rqc9g{iFpz_^0^`6J`q{Xl-Crj)Nl3RH6_UUUTK4;J6oYw4so$Qtbs|Ip00A}CBT|@MyS2t>Y*kSeg zK#<^n60!*T#B6`O*uRZdw}$T40u4mCP^H|_-pv=+416)1zeO7rd+VJks>y_Eom3Vy z;y1GH+ZrCAc%^=^^rW1s-Wu~YQ_1T#lhGFLs}z|uC+Cd``JNl^TN)KF8n4{;Oi{7z zWh8fzw{2xC1w5n$IQI=uC*FB)dn=gf{YENoa2b8K9==H$lQ8&XEC+f>e7##t!1%7s%Ur1F;Z388 zb|FEJYI*;u_~Sk0*)zgF=N^|UfmCR(TKHzVsypU4ld@~tGvLE_Ag`%_NS@nW5A>$O zXBV>j_~%}Cx%irl#0eCVhKhCNyi)*uX(?fr*DHW<`)e0E_|qS4i9;N%G#*I8UTv3a zDSWR)6H?4*?#*-GU4K1LG*~(D$+a6>SO5FQFDl<0zrzwt4MT}I@T2&q{G{&YN#2zz zfHv^}_Bi*H3YSh04ha0jxNX9y%nTsy^PQla(71emfxOG-=cV!{Rhsm9xj{a#pM*>A z%1X2Vm%TUV@SHJBlo%^a^6%g_3Ju!7`*H9M5t@PlJaMbX>Gn?T$90bubQ_V6{sjVbz8K)n^p>)X#KQ8W!L5OIt-`GLmK=;+XCAwzp&$5k}Ho zthz-xV1xTsS^tPE@z{${0$!dcrbDCPu`}cg`51DZ#-G}sK_S@7a5dR@Y1xkuX`c;x2C7K#@;ca#4LtYS?NQk9QCgG_zB zFVa_qJhh-dnFjF#WQS+U93DO%NsHZnaVIi*HAXGX$5cH6p@wGNOg4NA%b&~Wq9bC3 z#rr$gMjAvDuC`|4mYft%UR|eBS1Rt)y5J(#L4aWY z;pN}v{*4ug9*3m*)4G|gXB5XI$I!w!@uxSjgI?dn{Mr;4%d%BE<*}OsJVml@u%hl# zL3#Xg-!g|vSt*@%{YC<*sT1of2o}4PIh05O`hgud^hZMa5ODc~)TQd7WC+SP4w{2v4(4ybs-PP=0bV-gkhmS6unIZ|M&@mFfb?+FZZhv*d zE9ei!KSrXLA>^4)^ul=5%XoKxa_3jn^*Y-yGP?-01c%j`wA1dv1qp<2sF}6-9`Gff zjKHt8n-O73d~Y9llXE-I2NTV#r`bo)1^a*?p&K928uQRW3`e;8J(&QJA{&wlz`5q} z@%3R{6$z9|g=-6xEJw}*@0%TmLjlF59~erds(IIW>BS^HzWP7a9tY`;VQ4EL5&9hk z-OfYD$i8r=b(G5XSrZTPE#42|10C&86aab;Yzr%QMs*z1Z8CoO&vPTWZ~O*4r9$Mt zn>LyygBSDV@m@a3`M^QhLW)}BIIs@v9=Nx~DMjQb1lUjVaZ@Brz1ymw_EjK~*m4Ap zn|v0{(L`>=iMhYj5b3|e?nD^KJbyeO+{!pY|4o6eOxf`E*>fo zCaHkyDtZG!fSpY=5UeVnzs9w}${F=+m+fyii!bapY>h{sV{q&v4W}&uxK@7K-KX`o z)a|Bg%R(r#Hs}!@xGr!B36IVB@zi@nWuE&LwR8&6Qkvi^n;(qh4>`!SygN&FBNYoz z{RFXsv}k)sQh^ikEfN}=W~OO+(}+*sfU5pEf=cYV7DriM?jvwelUo38vWO!rbEGiT zV7ZP~IGl-&pigp0N?Z-D4ZMFb)&A6W|KCvg^8=)OG2G`z*N$76CCxdFj?OuqipO6C zJ%Pu!{F8EDZ-zQD+OhIRB?xn!#B#Z}7>)n5$*`P=b@-@X0CKWqNRLDx$Ee}72h5b2 z4f$l<2SX{DviXp7qts1kLx-)w78+xIlf|rzOTtK0^?oZtuLR<*?;e z;57`oF3dQ4(xV*S8UU3NB5OLH9b1@OkcS}{m2^RRGD?YX=W6j4@ScskwFHxTR-GYE zEfM|&rXgeCICkSJw004LgV7?*Dk6^2OXud3AY0BpCKdie?iapS^1%snA^94W7SxKK zusrrs9Yqt%$y~pOrSw|leIxAQ>l=5_?ky>c^3d^A1;x3o_oq>6-YeZ`OzURT$bibU zOB5_%CniWY$bGKUNZ!_0l_JeJg1nhE-m;J(GvZO0n zaPs&|3$OD=wbg)(bHjk z@Id|yhKC&iocJ(c{WNchuFGSbVeqv&BQuMeXrKcuqP)Hw8y;KMXQ74QvO)ceKu_7wvi zKcVRJXR~7yEQ9>DuYcEWwxbu;hX5ABUd4KV?sw8Sigf>vkjfHTamOv&f*;Q< z`Nw5H@04)JH)- zZ>drvm8|Bp-_D>2s&A)9WjrvMw$6T3suw~S2g{#a$+bLl@!klcX;XFKM9}?rqh}e4 zIaSn%Ng`cUxMFHp?>OX|G1WZ9)VTZ8`9(E`(nrb!bf+c_3f4Oh37=4EI*5y&K}7uC z&*_|~2RGBdI$7b0Ptr69m>XxvtVj0tPA72Xt)L)zUKhm+%>C**@k61IAD)BA)v%yp zqz|z&RH5~0KT!#hEZ-jxkZ2RXcc6FB<#5jn4-ldOYDHbX7=JnWa>Pe}e$JJ!>{^WgDv zq(GHOa7;%b+u>^uHubgVGuaifqAYy;pOR??rd6zgV~5-;TunX=Ccm$ZK515>viyu+ zcZ4h3DW5Ms>_6Bj1ye)!^e?PMF97Rvr_IaZG60{V*Pk|^Y(ebf?d?b}PD0q>Zrw@w zO+T_SXCf6^8T6X;0JQ(y08Ypwo4TQ#eMBBm3+$gL&35R~n)}}aONhLbq=Mi}(;@T* zNw@WCH}_=xo@wIIs|iY}&!Jv0il8whc!oFx(>F|xkUC;u3L%NGlX@^g!@$@>aI=uic!z}IgH+MVJn~qn!g75ljS*#yss8!QaMl?Z};vi zCHm`9XR%hQ7nCzFtW2X~cnj~OWrnu1ZgCUK)tpHQ&n+C(^=BebM43$XdU80EMxvR% z-q-Nv)M~@(W%ZMsrf-%7M{JfEr{Y?2{_&m)CV=x@9Q*+KiUH8aV8{u*VY^X>C2K)%j{xV z_`6c`_{iPeqRF%J43lOn6Kp#*60oMxrre)f5%}$OPr+nyohIF@ieIyiYTe)l_d!B$ zP>@Y|FsQVx-?M)wrkBHiIf7SfNbapf(Uzi=azZu@ZlJsI+IfPbK<|hj&qhS#KOFu@BqwN8( zFxJFzVflMk6LVLN`%eZViy^7fXlxmypIYFiF|lEPjx?U2o0a(&$YIYgZN2deR10%E zi+jdnwYr3^!^%qZ>C${RJ?98ZxRBN^6J0V1eo^`UHf@MMrt;v)m(_9GE7CRI2;QAx!1*kYsHVoFr4?x% z(_Yil(|nPqeSwVXG`-oYO*Zo!^YE(UW2oo^930qplXk1&xO$_G`=nst5a>{pE{0Yq zFW!Pm>b)M|1j2O;-ihL}lt4Duv2M`Ay=*e{Hrs7QF&fW!JrPB^{W6WuQQ(UVxrD~4 zThW1uEa-*+wdjs#p}~!wDce@w*QDkJ=g0YkrK|@VoTaIG2HKn3M7y^t25&Eakl}t! z9qYsFYVwT?6ZYzK3rKSfU*G#v?{`Xzoa{?`0_C>CsGx8(BNjo2YdGm*wV~QUTtxMG z-BR>vH%y-flR6VyHVPVX9E9m*OvB7-@J&AMp|77}PxSEZVP8&n>(C2gQfWP;=E03Y zTpjYjob(-f$o&gBh)^smk=jJD?m$}SCIlF`S51Hsk(`OdGB5&qTFVu7#uYzV#0A zPk(Pb62q}znr+pv32BFG(kam0Lf``?lhES^n0J$^c$oBm*4QA*-rJu_#10TR4q_G= zGnAz{nM$&^n>hy)iqnM}7gSCq&Q0(pc+~BW(Ldu)&9{L1inj-z8o&rQ?fLYa# zW`C;+Ogg}cox~jtf$fBq_riC%?_$wW;Cnh^5G>xcJd$R>jvuP zE>{9&n@QfQS4P$1whnFD<1jT&DL18wd-t|05?{uu z{yae^tIv#K^vfmjZ61LJAdnkp5m%^D@ddU=IAD3TopU|cJ)&mnEBVMG64vT%t)zw9 zFK~(G;O|&>BoWom+>yBj?Qrn>%C$d@CBOJeD<_xFyZOkSI0$2);gO--EMY=DY#hZ8 zwpJNVEY2z4w>xgOLbUqxS8RHEZ6O%_D9RK-XG)Bdcrty(xEem+#T5Y{qpPqm92YTd z1RQHY*E{`QF}ZcT*GO0&zPSvy7C9@xr%OX)V8@Ev;1Qa1qM3gqih^uVZ9OCcydQ>= z38|!2;BU0`gCy5|)cbYNc|!`0^~-^DXb&2oP?0*&aGw{-{`xt6*!S zy!%woa(26Mx4LvJbPv|i%hespX1zWJ3DC#R2Kq}}i|6OwN@z(j1Y+Zg%KJ<1{gf&P z3!3+giS>Lpr{|B)kmm2Ap_eVlhA*i*UbDQBPV|H2*1^}uML42|__?rv)Tzx_^6AM7e5F0%dlk467Bu^f!E|i=G{T^~g*8pM%V#2Y; zI0QE5?aUzxi_rJ~zVTJta0JMMFMl@ze;QGn9UPUD#EE=|ys|x*dw_Xf?WX0frt2g? zwC|TXL#};y(x2kzJ%Qf$0>kJq&P0-%kwi3T(8|(0;5g947o~6U*F2z`1IuhDD{i!= z3D?(xOxNTxl%$S1+}Uo;J&wN!I8k11Ey@24wf~au=As;AVpZ9M4h~ z8&dl;v@Hy&DQ$|&;*`H_Ls#YBaZ_sl^R#P^a>kfG7F}9->j@W%AI+E(yz!l7^&5kp zTm2m9zz2QUG>FQMBhtL$9gW6x>eh?OM{Hla5NZx9ttd} zKGaFrU|RLm1!(o-LA!Ih0Ihq28|Cx__%Plkr!#HUFl2*R4izu7`o zxOAf6xi%?ssW--V`F$>19J^Vfeb}sN`(N$bc<^H8@NCIiowc|Y?Y9C|$HPEB$6HV!Z`=fa&V zxd1K~=>o;UtqKMSz?N=LAd38ER3p>r*8xx)Hd$3HJhEY5`oa@XtOBZ3dHVZadLjO31_ z5MF=&_p+A12h*dnd$n%H$;%m#M%TRh^YJUfI~jCx0}P+KBl*RYSC`1xS{*Qsx4LY`!dxx z-H@5598+yyA8oRHw%H-^AgQ+MPTL)HeOh=xEo38LgFR;i&7~2sO#b}z+)Cf|tn4;L z8MQ3(Q;csr0jfe=Zzn;syShBadPay)P}iO;SRtG|atEe!^@8N>z7;R^-tmv?7DmmP z`Ld1%nZthJg!I^jKSTYvPW_FH#%GU>Nfl4@%BDjd58E3%nP<0Ko-7=b{Oj25T~F(S zqc>UEEfJ}KaJp5*(J|E7+!kfK)c$(^DX$`py81o>LF;83*v_v!T=D=IFJ#4G-i=;w z>!ZscUsRT0fKr18gQ)BJ!fTuMdoKEkD^nPo#575DA>mi4<>H%U2?_- zJrZ_QS5Q!_UbNqEI`@_RQa!7zxepFz3|V|n+q`CcE4ELZ`$7HH;#S$1(-*F#Vk}7^$NpRFzE=VJdDJU|WK09TX%l^ep`3TiYlDLQsM88_ zi9HJm(3b*TK@{8jVWrQlDDAh>RN>TiJMlhU21Ph+57o-D$kPmzMeeah$^ z+pgHjOPvbO$MVh&m&k6r#7j(~!?1#!EH9Q9R(h`@J87G+h_nAv0|)g=qyP)v`@RR* zgn#qf@T;cOXB&pHB0ywHtK@JM?Rmkg=EvHTFJ~%kXNK6?%)>@EDKeusTgwQguCo8) z(VqxeDKR?vZ*5dOebmi7eYq%0QqvoudZ0OcG=uo}oq$m4iUTIh@{*UM{AI$Owb`2! zD-S8<_+*?59h8}Ujj*DJNb|{%qun13Yz|M~Y+g~uAjgWmh>es$k=ltIVG!7`Wwsi` zVt8>K(-<1Tck%?b%E$Te{FfADUlotKbRDtC;K8&w60tKx2XVzkfz7U&1Qv*^(E$8$ zk@}WCDfYiAdn8M2%Ve@vuV6oME7*pmtL+9pn&i2z$#Ezpk)PkZ z3^G)H1=!CZf7toV1*~b4Lasa8r26#qm_!_TWLw$v`0FJBa@Lf>TithB-P*%g)FbY& zCOrw_ylH#;T5Hx}e7-$>Eb>_<*xn_4<9Elo>8Y}>i`N3mf33%MJYbfsm4*c;QMuyn z07Fh}O61rF|4M=P00E@LRk$JSOqN=1SJMHTOVA5ec4+@+If&<8+YW2&gg&U9RCobA z@&Xw!b1un_>2C#$J8-*|>n^iD?oD1ourPM5jf(t~-b{%4%Qw$nde@f7AZ{iG1Z!4) zn0KDnBnHv7aDbY;Ilb^96b{zI#&$Cq?s|+~fgL*!fJxvK&+*>B$AjVPC@U@-?*Io2 zBH`P|8T9HTQ1fSQ_^_JyPvEz5A~KpCU!!t@{x{fkk-P3bBoIH;TmmmPh755W;2q$( z!al<4e6T%%1nnt5V)_yIzUush<1PK0EQqC-kCOSuFTE%R+}+>L&tlSLJQ9|AC*|*8 zzZ;#?ZK|B2xdQ75sAk%LoqeWhr__)nMWDHbG{dHarxUqqS45#PR)n$v{k=;>3z~;GTinS7iZYL58Z8sZylMIZd9AV zhnfo}NIsO<#ziHy{@=Q0^;4XlKRElOWczbNxY%42LO;lR*$y>m=WLk}4j!wtLdK0d zQ9o;*(H8nNOn-Wq+6tIsOXk2}jL$h8G?q&8GKUcV7yFkK5{1wHTO*Z3$+Q2K)o-x= zDB*w0L=P0(#N=*Z=u3R!yHzKIVU1Xl%cRx<@J-9>xidoV#_0C76RE}ou^2tBm~F?hW!_C{7;X};pc{=3P|IeAq)X~Nbb2c z-=c);v9!t(Et+)Zr_UqPy7}~-2EbDKm`EBq7WN9~b_&PLkI$zHW%Ft!aINT}kdd$r zrWJwzWmn(+79vu%TqjDNYyY2jvaRKbP?iEd~7D?k!t0M@Jj z1HRZx-40m+QlWUaazZC}~UN5dX8pot8 zcvnLp8LrEgd6^U@gRj?Q_>#bzLz{0*PiPVa&ts~RA8Gm;o*)ZvJ%^BW7u(qG;6-pd`3DB}RJrn~ zT4o84$Rngz>CnWp#+ z+&}Us4JT`oUJ+~xk(Exo$>6JjJ%7V3^P1Yr(W|iQKtI4)Pf@*7fFLO@qVKdVi0ZJV zNkJ)NdAe3qY2#xJmtnE(3q}&xFL8DjUME?t9KP6VI=~YAB6F|cCH@}%H&mh$CjSL% z#&qx6gOHmDyA~NcJ@lb(Ropg{FzbK5tN%0muic(8+psR0geqtZdH@ZcX`B>oyB)*7 zUdg*r0P5A$3hM^4+v%PtRW2wbe_w$-{1SafA(?A}5~I*Y1d%EJ*55QOIEk3FiOl}~ z@1M9MNtto<`h*Kj)KKVliywm`#&NU^`1e(zy!%;_=gevAAHf_P!WNGOuB zhrb80$-jyCNc-wK_Bu&C9NquhLU-`5MWJJO|EoukA<@K6ph$cSN`nN~UnD`Iixlgg zw6Bt&zTb>GQHWxw46Mgv{sE>&KR>Nh77^XDz`!>jbzOcF!(J8s=&qEdfa}m+xUc`r z)J;4Y+i#@esI|}|ozh;VVzSJXK@){LmNUUwdXb;TzFfH`!4AXee84i0}25II?ymNGt>juprO3zOqhqortB%S6%%6v{mQ~FcgBwOW&Pz>jrM_=UQ?p??; zATkMQ5t)wRcoI$S(N|YN{;L&-lw3i{Ejq;=i{FNpaeJw5;HVS=!vRsA^!J;kh#1ADX#SzIDpPFCRity-bRH!rDury)R zY8OEOp`JX?BbAJd>=QQoHx6O3IEDG8os?mu5bQpdjW5!fq-Uf}MhTr!av5Z5oY8VE z+EFO|_ucAV9Y$Bdp94Lhr)_iow%bI?KOm8_l)nf}uMQK`CJvTP_agomRzj8h=gJYl9o1iQx&~1)2?6_^;Mqd64V^NF?iN%(ZQ)lpaByJ zub;SYW{R0{37*k~>O=a_HNO88n@&jc1eu%nzce;is-xCdr~pi#N&W|XgLeEcp7DQ@ zUL|cYD0t{m!Kv5_-CigWZ)V`k8BNdyY0mh69--Ygf;|2R@mj9;>rx&F&qdkur&nt9 z1=EWs+vL+I%!mICk`V4W>{!A=_@)Fp}}q6}7rcguS5- z_;05<8Cw7C=D(w%C-&Ob(>{o7Dx*E00282RIzTfst)8J?xZQMZI9{Qf5`3K>f(ZKY zdRI-c{o}pP5Ra8)8H0i$a z!TOQFnPHA5l@L)|3M)o56d~jI?_Jkc-s<5^%mNeGU|9Li7V>mL4;ULMVDlU(A)R4} z542Ti2f)+>tH&h{Md0~sxU3%>bfczNex(s<83lElB~MVmpX<6y$jG+;T^s$sYkRWn{<+WY+qK+c!f{{a#|2qyrF^CD183H_FPlHMpJ z6!I0yl%l<_qwxQTdh>9q-Y;xigp7xhA###=h(w0OF%Ovv8B*p@WEM)cd7j6Nr&6Sp zDO2Q_=MXY;%(EQx!8v=s+voefzu&e0Jg&>LpS_-Et##jP-Ah!HeQ5$~tL|zmNnRFH zTy{<6rj)d|$m=8{qr-kS+6&+4(@f0#g^DBF%3O)pglF1=0mI21!>HLDv=)1xv3EXf>auw1r8irmKC9C~ zI?ju8aJHo6!na1_#7-_j?iS1+gULnYG)giTw#phlnLX*AAt!yv( zETWH*1$xtMc`NBwAO2p=jFRy6>#}mNkvi=4=(mYZO%OCR`Zq{%$+5e_`w_csuU(@gms_%A>}En_BCWWe%spqdsUj#JM0@JlbIA!uE7yF!}zYz-kmVV;XmOaE?g|J%Wf+|eqW>GI1hHwp>%$mvg^;xV%;T+A8G zsI`s@oq}rc6+xz@3D(qnqK!`;=Z<9epf;m`fpX28J6uGSN7jijM8b92;wR0H1(Le)9XOXNvL6tviBxG8JFLyBvEnV|ai{s@~D);I|Qd`%_G@ zZ=)39(dJ4*O+ExQBL?lXc4)uowQ1&&JT7s;9A>tnpho+%y%Kf*h6w5rjOOI~e_8;~ zJF!N5q497|h1o=oBhRjrGpD?CNK)tja1-hRuLVbuk6YSrYeV<`zh|Tg0-M(}bU-QE z2@j$4+K&d|E(Hen^2uvDA`mr8iDXELAWDmI94RK&vFY;O3i<1Q%n2Dzeun2Sy`p*< z)=i^;Q%W^rgkEn~^8dN|?={YvBMgvM52AweNB!NB^jC8PD6UT>hQtTI59cYNTxhn{JzGiZM)ZzhV-MQHJUkuN7KI| z?%C7@B;}Qwp4;@Cz1BU8zRGpHOTT$bKWs`Z?XdRr3+Q#gIzQ+>j1h&{5Zw4krk2)% z(G4PIQiDBn1z(Ce$#?!K7;%*LC4UXh9kU07io344#{YT#vx1N`IJFKl zP9-W$2EqaHq*gr4Nvbm~GVmkbk=NTm_FXA9IOMU$A@HL#hqXj1WQSz9iVYa_0!<6dec>c^O>UYFr=*=%R6caUAz;{QTqI12eq<_p(E>E zo9F8acy@zpvuv1vxs6-6&bldb*TEY?p?XmV+Kx}%DLHe@)T!xe`UhL_#X3CQO1tb$ zC3nHX?O%nJf8-H&9e-aZXk;);k5%FaB{WzeHaSJcWj`jG+iAreN{#6Cj@QGyQCf!mvcW z>OPMoTf;DP9|{SDMWoK|gR`$tc!D0LkYtrA0at3u@{5h7NR-k#W|tAdF~}|ToMc#? zfXVZ|c@Ap9s9W`#WU)uOw6=E8(Ae=nCe`>>*0oKCqW}i~juftfW;{~bKDP32^yU5w z5YJuMc>BX1@CESzU-$t{=kNNFE<133oubt4{}LXuz+@P9fcek7M{Bju%o~129k2D1 zBoW0#p(AwmOIQ*5V`5jbC_ETBPS2L-pG3W=7ueM|yoFBBB(_JFYEv&*h6ZU0joa zIXxOxIKIJlYV13RXgs##fG=3RTh5BcXLwvPs#8ej9#r${_PKj6vV!+Z&irmWv;Dhd zv9sf6413;^&)k0@N!8D1narBjSx8Gkm&jbsSxrFfqB^1EH`Ui5!+wG*ljslB8ob`4->%#5J^_ZF` zW{>#vqb+fC+V|#U!Ta$|*2ENLzW8~G1bzwoS8@tv#V!+E?b^4#$7S%%WHSDGdPn~%$@R_J zifaD0%2^X~$W|jkiXdj*V1Soyz675!fm-;!B=5p%(hQ;={z0|d|Lmo0H2YxEaM<*_}c|G^jYNaf0M=&W*g8s;}L@4SP zKVHa>=hh;S3<>@r6}Y}((gO`&g4jznMs|7M=8V_qmAb={3S?I9Hd(wM*;{Ph^28_0 zT3-*YOS(Bx!Ht&q{#4bD>``38-4XMf!g4+QaBg^sA@ec3vL3thoyupap-k{~<&%id zkw^*>u0hN->UT|lDeo_&Q`m?Yz-Wb7a=0OR0-x4qZ^)*ljndiO%JQxp!-Wi_9!KjT zjPlQ7a(0bG9y{RD<#NpLR8pnSkP_KFV!~(9VQ4pxLZCTPnb?0w)Ni5lZCAKb`QWPQ z(T!H1lG@Z8hSM1j}5FwpW5h?6+;@*l2hz1LiLa9H@2>RoVEt zj!-_1-b5qF9HeyY6X}FVjXI(0kmb5l5A>|O>2>x1`-QVJW(Df7M!8C=*(a(EFmHNI0-TQLc}@WzP@XQ;~tc;%_U8*B6XIZiYM3SGFDx-rwrjb z1LEkY&Vs8Hg7~=L@rHrYNykG`qp$m7zbQaFpz&QYj1UaHa2dyLzL0^p=H1MH*v0{7 zttSyWClKhC3h`b^xSLtk_y80;h8CfZk>@pL1)yw#>unt7HZ7ZMWhME(y}cae6&(S? zo7`i+G-RxA(PIdbIvpgx)hQV@v_zEBGmb6{`&U6^5`~hH%?y#VmuyuzamxE26X$NW zn9iu(W9ol03$zaxg+sMRs8HHw3|H3bnIntc`qBd=1C1q%C_6Fo`o)q(v8A}PEN9bl z97+u@M|~NGlHeE6J}eaD{txNcbUnKuK0^;nz|q*X*I8Gd_xjJ|6lk&Y9#{Cqa|biC zJ(Z$lGZ2!h|BKP~cdg*;1`MyR1Bb6pGT=nmWVht#0LaQ$ ztrC<@&6ko#>NK;xyqq!K_RZV$von{wTfb6F_`ujY``8?{xJXdtxU^Pp3pwO0H> z;JZDvd#XgPxJ|u&p$$PpF@0pM|7C=hpZjuS!g$H1?YQ>NEI|x5p;fqE69&nJiMGte zPLIBHepHcfPl$AKfb5^SHEBTBd-7I#98myxv}2y(qxr%v~uJe zqLoxA!rk*VBD5Ad!mU*z!j_lq$4tE_YMaJ27cN0; zJ+S{%jf&Ng-^GwT*TAhsJmVY)4Oko~J%~)gzxyUzJY6d4+#DzvLJ-?UB{{xU1=fKc zNJ~j2vxDT-{0lwS-Lv>}J3Nu_hb}}zCoGLts44b5H&cF&ro`HWy6`(YE%VaCxW
J6inFjxIQ0V{iL(^p1SIFa`A(5M6BA@3! zEd8ubRFjl)$C7=4tBk@drYE9u4_Y!U((guR4jpy!z3QNTC2uNbb6wA?RL*!tVYZa< z!U`KYrsX3?zk5Ybyo}7Q?+;eFlU!`Y05hqFRj})M^eUz5^l9j zhWReo4J1{sw*$f3wB};R`~(`PHE^{=;lFx;v&(x;72MrGO}MF8_s})&WWgDb_gOw=MV9;Bk`m?fnKnQ)mBRmYdj;^XclYUD~Uh?ZiC3*UB##G8R4@80@M` zl4{BT=B{hn2K>dWmaq*S$?B$G9RW=Nc!Es

Gp9Cu1-$R|U6!?PL6Qplf3u4Waff zJ@N-Yz1Xu{v=>#jC0y)WBHfL-q3+CBHEu7wk)QI|6GT|7Og;5Nmy-7!05=gT$NN|b z{Nx9{mg=$QARn3r0_u3HzkOTpw2(poLxlN%6h8pd5SWH*z~Ffb5w`fh5Uzb~BZs2c zyjzYU-r$GLZx(tEx3vtyIdbz5&S$1(8=`jVJhqSJC;RrIxP8@wblRE5E8*f)o;Xd< zvv2ny|Bmy3Rk83o^{1=Qc z|60TzK+&M*iuVmuf5EbM^aQamT(#n~5Dn7Xnp`eW?4-vPI4Y!q(mwtVTPUpVv0Rt) zT6;qL#OOAY8Ql0eDC)e>#h8%DMa^LT4mt<*G478G*Hr4Qnd06QNaSNzbaBt>!))#; zXGGO2HtG8^fT!F=b0rC9-23zj910&DLb4ysa?g}pubm! zeP!Ft>+br#x!OYQKigFPk^PnWs-iCE#l=}G8LA%1$07sWp0(WgWrJXf;+=DuyCodq> z>*Bbg(dQv#W$f88`%33eYhuZ$3xX?LL@D?`^j^ngas6hhnZ+Cg5he~3OPwt|gn2nM zGBf3w`SFcZjFh1lpeTV8N_h8K1YDrhF_23BU>>fjU;Kh5z$EwoJ}`EX1aZ3(K23Dn z-WAZP3>a0fMEH=!QY5P0$U6b_M%nOQ@Gjvu?@6>iTRJQ$1xoV8O1BXpgjtV_Ji>iMOp=p7jMXKo6o}HS&!A;TS}&W3gi~;wZ2W zHJ&3=G0gXVHw?3y`iB5|8)`}l^5*=x0KE(OxN?G-!4+ZZOn`9=T*Imd=N2%YpzpJ< z|7KAPfB6ok$Zuebrs!ws)!PY?EpN|@9WRibmOV-rikT;i=Pn&;b;#o_C>OjW(7ffe zZDOWZaP)yL`7*=ag@9IFZyd^{msJ=zj&>;i77E;dCH4*zL`D(TgukK(oAg3?*&V`m z@RVvG9;G#5(Fhf294o+zTMy6j7!PhZhuPfz{R2|^J5*l8>paz|SFwoMM{in|E5S)k zYyxrRWAel)s^(C|4@6jg_-Ozpj3hkTqx3rNgQQL$AJ?oYFM>2kvWu!x|85tMD`O1e9tybb1oekdnEy4wd%9VE74k zhU<$PRLydNT-7KW5$%RHi!?ZlK0uZq!Q2)YcH`Hd>2hKsBIr?fet%FXFVX*izWx;@ z*Xe&XFY&whL|iymtC*Q2GQr~+freQjP6^~c#zqeS(*)!$CP=)iWEaXZB@;Tyh2*+V zmt}aY=v{Wn$z_w2Lvhih=)P_B*KfJ6Xa}o=jQ{?wde`z*u!AvYJ2LTG(7n_(cgM;i zMyY+q_p-E2lmVeofEutFdh6q}`?sG#GGlWs;q7U`2sRUmV{Ssq{7%N_U+ri87oZwU z#CM?`U%)Ti0zP+cAIzRrenh+-Rsv>tt8Ul>7oa!v(0)dsu0$c*cai;0C`g%T+h;@2 zx4MuCg^l8uWU*WBaC1y5Fye$|;M1QG*O>^2J_Sq}Usj2z9!EHB0CP#Gora)O z^lF^42>O$=xX+zwzaDhURRHq*Sy^$ka)uhj{kVMl#;OLWae?k;#J*)N0Wk>iEouS3 zQ`d)`{?JRE>p$mMF8uVDpr(-gbE|lsNeO!^Q4fg{zj-oDnWXp(W~EW0*mG>6^Dgbq z`zJIF)?or%S#ICy!9U@Rs2*nUHG+8icG;yX*&pS$wrPz~utQpzeAR`Tv&0upF%bWD zfDCX=%vlY^bRtGqSNA4i7+Omrvg;oITthWEY<~(MSPBy=k_Qeh9{^)@KE2R+vxks2 zr@!a4S0OY`4m$i=KA1~vNg$bj)NB~T%)`R?HJyAHMdVC*`POEoO*11H)uIB^ZOF?tfH3P?Ma7{(tgfkT0f`FqM8!Q<2#xDuRRD{ z)M+pj2;{S&oItB8DJ5C&rYN&ZKS)pi1n~k_KiTVC{DaQ`V`SDELA~gE`z9vfo@?y5 zk^C$yPyTcqNWBenEZsT*)X?+@>H{Y7+^&(`()WFRIAaHVj0;3gL)b*T?n92lQ+^wk z%~zpF2`1|G{(zg5jPdAQF4}7%7ecT;VN_3)mFz($N^;S z2hn|3!^ZVa04}5YF9JUp#=xaw=v9QI;;l{*7pPgvEadMGpcNoyL&MM)SGbz28IV7) zq+8ogY{6R1Ad&uo&9R7bu1=kD(xZOvvT#yr z9-l;%c89rcKmWvVLHWihblxG2d-mdN2hSjeit)vytaLgSpHgcjay2H*)Voi&SjL3z`pnYtXs4wqWbN8Sk?)~h_-j(dAc!^@)dtY3xz5H z<`70|(FN7~AG`_`a;=x*ztPw~`@DZ1ZTgKF{6-ubai*KY91S2RTSN88SFw+(;|Xw_ z6o|8whBLG?K$@0p_~>>u=6Nd+M;0EIe&9s%tr09{^nd#dU&zag*K?LUDLRh4gh=~< zX%ABQGg6W|0(~a+uaew&XaE(;;e?+-f6JiTwiBFltw#;qRRJH*?bCcq=m^kl{oNjS z1J?F9)~>;6W2yJhrsoT}hyF7#@)MNzM<4}Io5f1_a31pc>c5RwB4@u#f*i1%2N5?> zx&K%P9GA*{Q*Sf9W0HDlE&cLIGC`0O1EY-Rowt{8=SD0GG;qI|Mp!& z40EKguGdJ7+4oIStJCVTH4x4DYtKZzWF^HaH#&bK;_vzQ6V=6IS1U$OZ}I zedbT9a1VukCxQb%yq8dL7$<1A&I_pl@VUp@!(He%*sZx;ZcRGk-pV%*>e?gW%e+Mlm|L+x%Iw9?z&M)$(jl+sKDZ8ovl zy#1>u)ud{c%rC7C*eIa09?E)X{X5#v`uFZ>%hw)c)yrp&j?{5+gn($g1AD$MexsjY z*#WY!MdGDrqE;S52!i^IlB0_Y?e?n`Mr-KJ5p_iUzh85i4#q_g6)DAKx!{3txY+DO z-Je7_$%}A3hHvGPlOMrS?WEdgmaBQ?RINl^5A-4h{>dk(LJ`uQ77vW=j5SiX>ysb; za3uDGxxQ6S;zOP*E``t!iy!TGyz(YTKjibb`Z#sSpDX}4M+q(P&x_kU1o>N@IpF#G zZWw(fK4_Tr={@VEErBD|E?-GM3E^Bp)CFf20uRL(0c!VNi+5p&KQob@U(GUCUvbT7 zQXDafhY$e?&rZ-zyfuE_YU^%HAy-odpH7lsVc|A z(NrEnS|0?Pw}hJ*o7PE6&aw+tAtp-Ai3xXlkOs!rF+W$a)Xn-YH{0ppj;@yYis&*I zZjJa0lP{zdIDC4uo0CdVttZG7zBmMmaLCd;nIQk70+!-hEeXc6_+#UOyd1A*x59ee zWT#J$K?IU#ch_?_qG;Dkg?x?$rYq^t%AbKA;clm(??>pa)*W1*v+DQ z)c_Z${T&Ef)yFLXy&15xy||QsFY!7ySAh^q5`XjQ6la~^H%Z$!-mWAGmDQt@F%Pt# z-DeQGu$`sEGvO$BnIcs*;~YbcJUQl)igH0&y~uCsLoYL%=3TGD$2j3wz$(qL zqaT;e#!!EBjW8Mn7Rx`61#XEK5(~mhy#N2$`A3uD?|oOX49vGuGTBq>S==A%ufJv( z!*$2_D}-OHQCr37A?axc^4@b+AhzG!Q;sjuX}Vm7s-04MaBRz4CMle%$5|1wrEo`s zBvHs5=ac{ivLRZ0{N6ZTsq*%nYqAXY{)(p3{jEUrp%~NQBHjDd-6Bc z5lFvg*I4sM%~#=~Xt>|7daf?Rf>rMo^yhGMpyiN8S2xajh;L$gv1tDAXn-q(>?lc~ z8mes@ct5vfVxiV$@%;ecNER=RqLeeWlf$b-&{8{%em{tKm+3K!V7n_&|MTV5UFIZI zs}>tkOnBq3_tPe<4eLfjfipgY5<$N)@-3m~Xy-O}aCb3=>v#EKJ!oOQ8FOfeRBfOoZq2*a<f3c2%0*0D9 z6m}Iv{z~4^Y2S=m>M;qgJ?f`10r4zz)fh-_ka-(u*wTd<72M$_j-%<9wB|0gYNoXw z4{MGZG@6mnD-HZy!go6M5!dr})c|73bsLwtrzb(c`tN<4GsphAvk5fL%>6(#@N;+! zC|FP7|IF=lH^=WrdU zX--jSreC>-ud|Xz{yugX`nfsZA1XMhf2%jwZJr;l^Rb|x8a`e1X%Mep9w0W4mE}8Q zVmDj~D)_hPY114H&$wtYuD^4Jo$}7U;q2*Nz#zS0@otgOa8rGiCdV=TGiL6+F`tsojt$yp zIxg>9PbzedF|?36(0KKaSMbemuli7+BB!UtS2750@j5H-%lw`}D5@n6MJ&2H z33G(rU?)BDXZ6Hslqoq}`dlyoe)QAI7Vih`R?>y~=#LKz0pjB zDF(zNO!J(MuVzFXd}V$)4V8v(!m7j-U-KlgzEu%jhj4Q^$txoDSpG^aF0v zvNpP&cx-3gJ08U#sS5)Z>v5~LG!qAy<*An{Z>79VQsg3jfxoIUk0|vNr0idqLrx{o z6PaTuH{#X>UVf4BQ-8n&gpSf35q<(x?NI6+jw^1Ni`-V4JggoQaerz32PwBeGnZGJ zFnh-m;?m`WlBA-?kw*h!vs4S>$bk2tlQxul3@G?DjTXOi0(QxAjvLzM^rr$M+&bqp zLfiBe82{BT^`{SF17TeotOdjYfrv-)7_e5K%l!C2-?Zu|#&trR0JrRVi=Kmmw+$@t z{G74Ra|nvWtu@Pilh2R`EB9e5pGPuEfiz zW)J5IMD}m$w|l*VL@F*@Ju@|Uc33z&$_|~&zK>w5_Ax!$RCWcb#2+!>7bVsG#ZDA46?7uR@v)V1^$R9Yia0iQ9tH z7gy$nB})k3;)|;=qvGJeQoAMDwjgu}Z{OnUycqUEtRDcgFDnLiZ zcVz#jM{8s$h4yuM1wh=3tEly9ILiP7eb()kfY{|hEqxK+TbuO@^wtCKg47Ksb+Z`0 z*RE$5c|L{{wbZqhfnAt-?k? zx0c431ZaMQ_(-kz@X2gBis?TR9{V62;}gZ$?mKpn#HbQFp2c4s76Y!Q0|G~VL4q#(Lw`ssuw;LRzr8H3Z8DybrDYl2bW zop-27vJZ;6ZRWEgA1<}03mPi~MjoX^Z8%fwGhroPe5M#1`EK{Nw-A%R_2R`q`)2`X zqXb18i{&3qP5gt!O;c|_(}LrikFzWP#5!a#;lC*2eX=}bPb*jZ%ecS{g2eb^Hn?g4 zy;$Ot%JW}gOw2eC*#gb}G0nQ(g-mHR>isl<)?v9U>oF&1Jtp6f>BW93F`iSf1UQd!LP6MH|7?aRc&UL z;<^gA^2F=@-QxA1FHWggDMTN%;V>o^83!n=|DyF=yOUV;iWlDU^|WitL{0HPk_If~ zBRzG{f7;?SgKIE#AxpQpVqYQjy)m%ur#Ia3d5UTW&AuDc-YrI;3HzhX4@U_?#VWNb zln5#la66-Aa%T6HcI8lfN{hG#lF_AR$6h#_h@CE-`XlR*`~0ba*ObTPG%TW*$7oy< z&^Aa|q1wIxPb&$&NfL6ww%wV%fe+> z139;WS+{X%R0vbv?iVK)>OwS;chj%wjj-~Vbwt$M2+HzO)$~hMnSV9XVXlw;$qx_S zV!wgVpAHVTs%#lP4!7BT9AK*cd?)$x)e+P$nYw}$zId7r4$sg^NcAx`vYu~bC-!|h zNZDb?azeTN@D6l46!~O_rX=#JS<&!w3;K-j1&6R|t!c6;u!lBh=G1(!)Kn5iRQmFx zjHLd9nd+z)n z%UW0hVMCkX@QwWXirneydC_Sv?>SxhS#GROqmv#ZA+p zch=U8i7z@|T$4hG0>5)anm`Xj4yrA5--U@>8Sj2jRiUX6Zn(Ku4mgEC1=gUqAFvAS zlb>>zIZ34RoQ!GAIAIcOkr84RZuT{Y>)Oq4e5RSy6WE@5sag=$M*#*Ym)2N*+r4(T zIR_Lo1wDsVKk)LPq$S~d{mgeW(G5s$bEwpD$6(>vokGMNN4~t24)bQX6lE)!jq^1@ zE1}xq+go?sJ((jyO!GqIb`3PnFcZ+L(VP(AZ#!0M9dfKxd+vZz!PjD{bHd`H_T8&w zGQO|7nFtC1*wNB>F6TW%vo@=j%%MDNY|H&R*elSkc}S_lMg8uqW2J!+2?`Ai36W1C zp!pcF2&iG!rWM6zdn^)aSoZi5r4cJNjDHHS9IUgjHRs`#Q zfnphOYi!;QtO^J>|L&XUo>Wu?g_oYYzJuU6f9yH8hbQhzONV9$c-qQ^jQh&lpz|dYII++=BUVeRMJ^d*oXawH#S*wDVVB z;YsbG1`XX`)(ISPVO*)bhzHJ)qP~=GVT9%|WsH661~9#t3vH2=P3&Vj^>xQO<~A&k zjqoQKsLSArFuIjCCxzlc@%E|v@8WNBp$piH4PJ9*){`%)4r>h76LPfC7EPoR`+y~k zsuJdw%|-Gea@T(Jr=TPpY_tTwDqcXf$YBV(J-#7TMC`Wzk%L*l9owTOzQ4yo+E>JJ zHf!Y$TX~;uR*~|(N725n_eP97?x3dQz(?!f&N~@vfnO ze2+;>+{P4Sd>TS^Q4H6;bmRIBrWMpKdu9a6Vvqks+BsDaYJ=vXcswFzGx=kqDeD8r zrVRQY&d#FeDK2-q#TnT!SU5_-XVD_{IZpMrRB?3(RjK-!>8&xC~Ck9xf(5iaKT z$QdeV&$8jB&ZLuAeIAVnntJ@o%o~Ecb$`+8u)Y3Y@A`)^m56za<$$FR9Hvbp2!_sk4nO~XQV=74QG|K=Gtw#r`12{hsJClw<0 z6BzZ9zgybx{QWYT`y^=67_rn4*LPHKr&!qhAyCo*AO}&?Wl*P5yGD(G8bqqDowfz+ z(t*eJ#@rY?TFc?%EE6B-Gziy_(${qBZV&OnBIcVqEn=Y~uIkp?e|v9lm$@uZpZ~sDa*gC%Ym1$QxIcJo(WROq4!d|M|i3TJ=_y^~p!Z%aq^-cRa zXOh?!Sb+!W2%GM1KfK9|D@&rt@K##?$1K))^v^*hTg4p4T5umS5`$NSlb(BaW{`faso z{``OM%LH>mexi5Ej%;Tak*3Y->g+$}`tC61{C!#?@1xZg=JRVI(hdLq^bzrR{@Jtq z_buVRS6X$OtPs!ox~-_dK{l{%9m3*b;1Sr{cW&vF21QWN-sHIKLTE!aC%19zYwcEx z>$Emp&N*(ZDj=9euV8BC5EP~SxYs(6^C;&qrUQ4bUaXn_+&C>OgPsDBiy5AlL`s}w zBv$O^jv(0tsbhA~f9$nzOHeYT59%KSb)}GQ!Gm(H{fnnPb{rOz235JlKiNx`5|{=Y zA{9qGC#JJwuKNx-z)(}TDBTtqay(x|n*mKH_h&I6HfTc`j%f%7NZlN zeHPFqV`8f%b%cyZj6cjS5|fgIyWpy{$2^1>@Lm!GQ^?3Jtmr0cBI3`TwR=#Z*Vbam z!G+?)93s`%3T;p&>#=bUwus1uzq*RyxVRAl(VrlnQ~{YpH2ow-2R~g2k%TA4THpJF zdiW10%Xch}G@0k?<*?J#Yl#6@hTNuXXGy%5E^5O=nr6wc3MEkWUY}vkiVfH4R*cyG z__&?rkm2iN<7Y9{WE8Z$>(G?v*OmvavX@V9_)FD;DEg}MEK1r7u0YSmru6H>Uvn*m z0CSJTjp$Evss?ISN&c@70jl4M3|^a1Lm(S_UUKW1gS=!?9&^_Ah-_x$1aGwL^}~wg z^~b}w=^n8QC8r5wZ0r6FXL*nsCC5V z4E5|BRN-?q(EYN;>qVDX;WpiL_P^Q8 zZ+@;K(FmTy+!92Fs2xKD&#{d4%!jdH)6FWn5Z)ijq-d)%5jEsFwG}J2iSt*PFfST_ z)r$U^TV9{db%W@XUM(eyzUQ|rSu#_Sn&fC%+e=5a$lJOT>a2oyM2jxFhA20UW zJwkCR>|FnTw{;gYpAb@RM+NfVz6-HEaZ_#nOypWEpG$$hPyk2jB8_4dL^2{7M1Gt< z_%#RoD!+{l5+YkjtsjU9VKk*3L6@|b*%a1w&B|<^o(CXN z%={)V|! z8~5W`puyZmkQr#W>78lQ9s3N3YYV#U#gz`(_viBS=LWpzh<+n3`U~eQ;^&<@>{)~K zzwhctOp91d)1~ee**%X z?7rxzr8F=b zV;)At=kA|Fd#?`P4lb!AGbn%c5p|ulgP{i!(mrVwNTUVFT_|se)I+6GC0mF5-+y(n zS@BGecL=1Z-hW1BvT&u|WKGjYh{|Ybrd37sX(*lYx{$TJ1hMhw3m8MVL>z5fHqEap|=ror^ z?T;2L23e4N&fPl1GS8(P-1a>->@kbmWtmlxB|kCA2B`=vXLhVkECCDicxjgVlHF|; z#LdZ6vfwfXsbiJDreb$|oPiVH8WR(-_mCEP=oI}=jnRNxeQ&@d@-g1y{@Zj7nJz+q z>J9?uL_z%H-DwALFCF&BLfTS)XNf2eNAGnEb+a^&4!vMa+3rzqsmao=c7Hm-rE0VP zoAhH*vHIQkVzbJ=!c;R)7ORSt%5vM3t49B@zNaewR})IGYyub_ny^utntSCL5FT7{ zu=M99RKBQ-nZliFm$~n=Wo4bxKPG$)+AXZ(ynpNf+_-2o$6)mA#HXw0FG1(DB{kEL z^J{DGxToFU_1lA99ej^;GW7hi&_?j^POXLZK|Xs1TZ1`7<0n;Uw8_V{@7@NasaDit zdMDx24z$1LzRMQyqReQRZj|hZ%fV64W!-;=yph*4ZXr%pH==ooD{jkV_Ubop zW;vdK(qE0u@YMX7Ab+b+Dyl8QmlRwwnd18OdRvW_8^57;@kAK91YCbd_v2xEJVbA@ zL$FMS-aek2XQ07u=%%kyspGd?CPKK(JZEBfN{Juo3j%rffg9D(Nif@PMl@KM6LE-bm_$q6 zr3{dxxYkH_po?xrWIHp7X@yJ=1AW0k|MFww{U;axxmPsE;3_!q|eaWFgcd(v%b~26NTMt{0;ol7q)@ zgXZQ~^hB7MuX-G4s zARdY+0#fFn5Bm6MCHdaTd~h@S3V<6ai782rJM|)9NigjL$lo2z!^Xv3pbrP6w&a?< z3klTW7cdn3fO)lZ8ce~|)t@wnWPR}7$X)vRRV5p*6p+*{f$Dall`W=fMQ;1J4ixww(2AJEP^g6 zVavyqXS^C~Q$P~D0)6;^TzW_L`Wcae?(Tzs^`}ZA8RuKgezZWFN`*4Xj%&B5{O+wI zZwxn$w$_M#f+QIcUHke!AX%WvrgqaK;n5rU5$!srdi$^ zX50CQ(i7DknZz(pAf15wH*Y`@Od6+x?<-{o(*a4(N86A=GDZ=Kguc?vZzil!UCN4X z0OCee>tA)~?JgDR@qt~amuzB}P?_~n@wd51UaTz}KB&Y~Bh;@ZHDs^p*s zYucYz39NUGGN>{o$w`DcZuC$K(*!h`Im~~;WFH6K4GU8t#pYtZXEru{-GX< zZ9{O^0ujsqV}Fjt21AKiAU6rQ|?q9H6azj&Qk%g(>Lh zYLg+#2ry8wm$A1mDj zCt|jNrZbQU14bcw#kDx{dV@T-uH2U8^U}_%lC* zJEQlZ#AT9-%|P>x*-dsf%V$1e>sJ~2LoUx!b;KH%6(|Y);G|U4L6X8(*LP3Hs@H$M zJ(fsQ$84{D-~7r|zvzW>ovwVA`_Wpa3;OFxpYC2#+F2!f4ovTT4Dot_J;UqmULkQ) z^xnBGYXxM@V+#FGSPmCmkRl#`YnfISBmxNb1ePNddH!*tgX&EkdqbNbD>_K~O$MjR zDox8bD#v%Yt3O3~{;9}gWZg*TYlqoQ>)z%!3a4wq*dkcy!t%&vKE95{%X9vQj9C0y zVRnBns3;!Ass_ELXnNPKU|MJQARH9tVN|(#Q=<$VQ~Q7_1J7>cE=<~Ic!>A3gAlvx zV~{ArRt=5zHLS))`_OFrQ^UsL}^rDIGn!yqaxsHO0B`wnrG1&^o0;}kkQk8h(RALJkPpf;izBW~T9 zS_tr-#bvl(2%&zonepEKuzpH|jz10oyMjZY78+~Pt(d;wfNmZj@dB#z#)lo=G!Km? z*}xL7PaZ4$b7x4heLA;CZ$6rp)Pq+1+A1h%H1>m?=f}ekKC)(Z3F3aoVP)SveX7TT z=q&%W_epKM877n0g`?hHa@0Re{Oa%0`&V4Mm4!Sj_+YnJkh+61_Wrd@`)6{dXJ3~j zSEM}TWWMpest!jz)bHFHx+oD_`SX{%r=;$#cD4crI&KA`CJ*o4c)cVDQaTdh!D z=lcTpE~t5x&5swqez?*9nl|)Z!yOQjb_By;yFtDW+{EHyQaOMl_&}^As@saRC1qGm z=K{WgxSRFVqjTRa7}0dhZ{EUV_z+TWXg>o8RV|7S~8oG)8Ql#)bKQ(Jye4$?) z@c}qL)GjtCOnB`au(@yCzl5-&AAyTD;}E__)Y~{24ibb*R>13I? zC_X{{7Mmn2XTnxl6HwAb3P8FH8iP|7^3Ml5x_S;0K{c6I^TPO`cSUdirIv0-cl2y7 zwE0~|e0;LbZY#Oc(nmrCjmU>~nmN7ZrJGOpXTO13j|`}ZZoAIcn2O*B z?)}mt^-VP#UP_~REi94+R*`({8bSGv6=045@Q$zVem-;!I!%Tb%IQX$X9UbZUSHmxy_2xh2f6SE=T}6=yP(dh8atl)_3V;d{7rx%GAt@L?c%DSPR9%ILG|v|im)k1!73>kR5~2~j zcdm}Pc8 zH;fH9itd1a#o0nbm^~v&c5TA{2;&6vQ8rgt^X~(c&%a0iAdq^4O&S=5cavtA(&!oN zojY_mLc|4S$FJnIu-}80_8s&lbE#a!`-uEw?_^_x?QCuE<_O#fEHML#1JKfIiHJ-u zH7(DJIC=LA(P0$h_Tp`*punXFKf`zobClnU35ksGbhNE&m-JXbB8@+y@EFNa==oqw zPYQjdD2bz5k*q;G9v-xy#)Nc*QjCb2x!>{-AB-Ntv*Lp+R|vlf7Zv=B-}P3An_O@L zD$ayT$Bi!xl5d`%_!t8D+cld-f*$6K1uf`Nw-*rbHkrwF`i8ZVxpkJ`m2liJzNST; z`rkdWRjtp{ZAy|B{wK({S3>b^f8QO1GP^+O_dfO^2Ney%;ZzBtZ}5WvJlPQ)`lVG= zxh+6JlH!^tJc^pRLvCpQ(>HQ=Yw}gTTQA;43=A#>mO=hAX+Uz4UVYo+@ULdA>XqA) z03#*%v37T@#O2__9aOkM9DYnEt%=fpo%4UoIz%{ z+?IbK%oxOX0U?6KId!6#YdS8NhN{P*$E1ku#7G`F#4E8`Fsvoq%}X zkhJM_K)r`&Xz50x#0a;KJ*~nwnt6NWz^g&)i%UZH%VVn*~{*A!lgU9PqAsm>?5Q)*({am#99zs<2s&(K?sJBTTy zDu13#3ABg`b{O-ACn{OojPCTsrc|+~v~EfYkLBro$yE(&za&8)9UYa6@GjA?`V`!v zl-Nwe>Ir_n)d{1ENTIO5<)AW;>;Cktj=^#QYb=W|C5%4}Ob=gg4nDi+t|@l|6eQRy znX&ykHOl(0pto4$FEl^Y*$d+q6aT7b;2$m{NRsJ{jXfgZ|Dw9(<&ut?2b1T^Lv{DR9t<#+T|vf3zT zneoh?Pt0$ZBFA5e39a~0KF?c+4A~&!8=DaCCj3tCx1N>j=Lsi}&2cuLjt)qS`=|%J zn#epYj7dC%Y-bVjyyd6fcv$+gFBhV1b0Z*)OKLLS(JE2$;W~1x3b1c8E~&PodQ@z3 zp@@}T3__M|O27%S!oful=U;3rd(ni=IgefcnG)HThH6s(nRwN}saN~YQMEn17Xe;W zenubNxbvp@+#z}I$Kud>m-#_!H;c)rfXG^p#~z_-{DpjX$%b^cE#;erVEB=m?qT@i+%*0JxOd3syE3Gi_)9--v=ZJKBS<`oQF2l z{l;bK@CA(CAF1DQD3-oI8aFjB@wGrcu@GYZ4zH`+;EqzgK$Cyx0lTc)?^k{>CM;sSJ?pqZC6Mn1$9l^7SR$lf{%dm8k;VU(OiIU ziLExizb_Oz?>^{j8D!E@AP9{u;-tA?$?{``U5AT*oW|CEBrc?>U!IPg4(-m9htWR1 z{6<%zaal+Kr-SV2A&KQMh)^eDWhCHbKLR&EH*OyA1=1+1Vvf8sIF(ORIasCJHvHk= za*x8|&K+_BFo#fTS#b{#4%S|W^e=|CV`4@LOCZ0_u8g99fP(kG+l5~P%9OzIBfo(Q7D@4VP)3bZOL{rWX2ES3j zIVM4_9rm}-4H}JF4B8|et$kvfg>ub(Y+l(aQ(i7c5YQq1VjUTSV(^KXr$dpD0q-f9 zu-S`C^Jp+5gEq!c0$UHATQ%%gTnY==3r0iAZVPHoGwa&%vQw_-lo~^p_e^PV*)~9Uf|9 zj)Q6UKGnbcd%d$Bb$|S21j=UJ`F9b@%&g9pi%?WN)*4Puk4hWp(K!_$)$K(ixy|3A zDE^ryWz12l9B@`!x8D5YgS~nw==ye=C7n}+i$0NjEM?zZ1UAK4**SZx8R?Bxi%sR`zibPeh}^j>FIRly-#A-SKQYdcyJ@xaY=Y_ z)oSk3-#vsr#J#xnjOI)CkA%Q>^E&Gfp{FRCwQ8)#ptL2cLd1MpkgGA<>#dK9G4WqX7m1@*csmS6SldX9?5Kkokvt_Yo znOpo#aE50Y*=-sO@eK-?uSIw2xtvR=J#|Z2lnG9Ys@;mdJzM=&)?}F#|E49DY<({I!h3WL z79YiNkN*icSjyKC=EpaDD)j{Wr$+gIClD}Sg3di1`*0Z!Hj(X*E2XqyJ~>d-{KBB>@#khu5Q7sot#qY-HsR;U8sxQ#Fhr+W z)XsuVv1FGwC^}A2zo8#?+aBlE#~H30SlT2YMxXE|VExfKmOg071~U}bdp;DCkCT1* z6sGm3+N9ZH!T&&#ANn}94RaA1ct(md_1x$ylRrulX28=&WM7BgUM>=Dq2xq3TbP>R z$TIr`q)|}=#A*TloK6yt1Vsv`BFK@{gsdk5{XdD`yosb~ER7ph)+Dd6W5m=em@qf1@{L@Q# zLJTc$E3o%d`)Ux~nK^R^p3#JBLxWRLhjcRS2lE}Yd#mZq`bGB}4%)Z2$|8yOxb7Q2 z{UJ$AvBXJDhrKHpgW4*KqGJvy62J--$USGm|DXaG9Tekyc9!qrN9@?cmzrrP%M#t7 zAuUv?Bv-(t_tyLS*Y~*ZclF$Y?AaiX^+e%4EP^~VtQ&D4DGcPJ^@vdRu?`YDSwOEF zQUNiQTANR=uCH}^4(boXA1=8lGf-EQ5DUgIS^U393he9*5_nZlQ2A&bpgr5#D@VXV8xRvZ9*tU_O#22rS zI3{#q+qBGVcE5v@47jlS-61cLqCbNUFEm=}V!$$sjHgttqk42Y z8+*YtMF-Vm(29ipq}_Ori=U$=WpDVlR`aJHMpmFrbO3(Uc_xPD$Jt_Tv6An^f`?C# z=Te3*HZSWOb(){N{>Uh90X)u-Y?$mhA<4Nw&)I3jK)NzfXE~PbvSw*A;MI-tFE=MkGDz`;jA;f|18*G0zSu#f3f~J#E>2g&rXNFkmBL$ivh#FmUgr% zw?8Y}DsX+z8kziukCkbjRg+M!s<07bzLYP)8_4BR!B~D^&-8vDB{pELBG2Q_Z_WZw zV78D8_A*goA9aU1H4OLQ*xP8I;O)*A`0vL?(VwlbH$3CDEB!j~1{IN^q+(G)Z}GtX z0?DVH1wI}0qZA3=Wb-l>@)98MWxX?P4ZG%8aHTeml2L>?QDQV?DC-6+NX+ak1iREe zQf;?<=U!?Ut%YAS`e#{kNL!N66>8bU=EFqU{+!O()g>lIhF-FRp!Zkb2h7xZxfnfH z!7izr*1Tu?_PwAim(!UPEK9f(WuS2E)+l84HuTmJ)4iB>IDwS874%>h;4M%aYGt~0 z-gIVYcdq~49~o$WTIN*kajxf%-OXTpS*Rqdlj9qkK1w$gLEk)bioA|wFGT(b>;w>HU!61}Y=O5y6WHkiO3-YQ`sIRF>*i6?qVgO-9*T`Omlv ziLBYp*k>3?IQ}EbQpyT@RJ@(7;8SdXv{JTIY`k+3b@}X#XG_c$Y!szZup@b3gf^GJ z#hsem9E%S^3%9yhc272c#=GfK;=O|#XPy?)4w435X~5?LtGZQz&B4w-@1?-o5aDzez;c-iCWy3xkn1k7~f zk^Nrk#HeF^!O!lv_qNN#IiKCfChbVT;O6r6BF=kuhcWS(QXo(?*64N22&%K1MP?<; z9p3wO-}}RFOSXrNUs!t-Z8J=pvXZ^duq*n{4$snB5Yfx8h$!NxNz|;*^Y;>c&!nlq zKDWg?A@gvTO{8z93yyi;z4H}`aaUO6_A#6iSX0;T1k=cXeLqT>@2`yt$8oTnGy&{H zJmA%~=y|5=vB82*1CLSvy1OOd--nViAs255S%3k&>QFlox7Jawc4Z1Q@A{ChC(d>? zCAE3-Jv4+WUkQprX5VGLwq3jHop7kM*ts18A3#oHVI+r0-EW zE|59YQ-gE5n@0t-bixbM7$x2xUkX1S!lek zlqBFatMbasrr3|GY|pbJ2AZZ1ui$d-z)M3uu&gX6GK=fK?rynuC~)^~OYH6^hLPDw zl)gM2zE<7zEJb>sHDOH1Zq$gj;AAv5>*^ix= z?X9yn+1ybcd?XdK-Wy+Or{P5YkK{CU*@6t~p}IT36e8-h*qr9A)}@VUGy>t?C~Q&v zcrFgJxs4(h%|%}P%_b0rXGt>U`@7I?MYF0EuuE*(=nz)RzXpA7g=c`>ulyTGaR!NL2D&Pm)YJ7*QXRL6WU*}cktxi9e|BoTxs1yk|0+sSS6MeGhyVc_4>c|S zmPy-|bm(6r(2|HVWo|f5jB3IlKb;nY9|WppD9s}EnsJ!VV|k0>QP$DLzc7vPg?pkX zO!LZgj=iM33tC{5Z2h3YpJ{vedwkjA&-(?BvjmX8!4M@(_Ooh+{+X-680cFl{n~r= z)3gdpMQ)V)X@a6mx??u3aQm?}cryL)R~46KEZ)yMqZFy6w|&3KfBgWwb3#GK*H%wphp3~vQgOM|Qi9LxK?2gMpFC4_*awvCwcpds_oA5zLg!Qif-pIp`|E4w4 zg)hm8_2GS5u*4+(Y+q9u8yT&Kc=Kd1^5y;ycrSM72;~L^15P0KE9XWiY5&yiZ*$7A zJVAF~8%S2jrm^7Xp81dX*;mM`ZQIdyY$xHiUzKoXViWhqA4ZY>j+2ZZqCf!~_r4xK zmBPb)QEDr#YO8`07K5))FOn;Xs|)lwU(LXJtb14k>rX5%gRAcfA6af z8p6Zam=?F`p9z%m4#p*JEQg0Srd5oQbgj2-3nDMBg6b{|!{J8%WO7>lmDq zhTY+W5FArRv$d{8{W4EJR~6g>GqUG(KOUGEe+8|R{#g9vywVeKjG}^cU$OQEw|ghO z_EpqQ(ezrsY}j3EI)wLbk^9V)r1E|d2$1&}4QbRq7*y;Da})Wn?jqYeL^Ep|G|46! z|E@?>7OtqC&?52dmHA|fakp^B;h0g@Z$Vwx8@Z#=m-{>fk#*7;-@Odc7$d$sc=6KV z)VsH6?)^jwWw6Zn!4`rOGJXJYTb|3#Yx|96Lp}_q_b~PNRz!ny{H->!8WkIHmDFkG z|HN4?n8FJ^FY}Wgpl%5O4;wM^=~_F%_Le#`^`)S2r3 z&pRsKyp^$~Hqu$Tgj7j+1qpy_=|f z9%=z8*6`olpY`M4PD0fOoJ{yUzY$G0mG4r)9>na>eEZL5Wj&EbwD9%~=5gV!PLp;v z(aW<|Hwgc$|3SuIVWD(nb(A>a64sv&?5_2gKaAqe9x@fSRNP#ix}PAw@$|f%3dmqW z_%iYSxc8_XINDFNYrlw>*egceaJ+@pC%~UPxHhPye<;awQ00l-k2@IJeCe*hM4WQI z)|v9U_IO}V18R(gQ|hd*5S#bAU)B-vOd8saVB)J^=v1*c9_UuSIxr^@SZ=0Q&7zCS0-0T_zcnyfe!f* zy+Ki5zk3wNU-8qp&`cGDNt8oG`1><0K-C4R2A6WqPGdv|rBT6;a6=(P_a+Wet=>%% zn~A00uQt=oKO|je@K*b!pzC%>E@J3Vdy8?f%uFTw*HiVAq0QQ57 zCecHb@e0`I8zs2npEH(WGTntQN~XS#XGLkYdt`b{iFOO;kDZRt?+1UpIpFwVT;|P7 z(xDpL)kpnO0V3@ks#y9PvA0A!!=iZ5H~8;-*`O6(9dEC25ddTSrAOgo=uPXo_MSq{ zm{s`T>z-X3(Z@4`DsO044C=WURy`GMsrtAqjFWM(>dB{$p|2vKhp~B>?poqtmx47> z+4}M(^t*WUEF0`*KoHR@ibB^pmNw!Z7e*E{QlWn~BvJP{kO zTKYpD2eISH7gv$fTOrJ*@25~IgK)320Jrb!?=22LA^N0^spBbCT)R9TT2Q!*jAmO< zu+^{}9;3V*)N)Q`KgKGZZ~bKsz&4~exsNd}xgZWMX5D9s{{GsS$!M=QrcXFvlf{a8 z%?kTEObcQDk!APyF<^6;Uf^e`Bm!rZ^1be0O_NZRN2o&79cIs-blf%Uf^#=5EMrar zKSyx4SdqO!UzOyvV&&7D_s&pCSTq-XK`zUr1mbS@xUhD)?=!zv!A}PQ>HOebe6f0mgG;-ao9D`YPC?<{t`mFPh%X zfQxlHsL-keeP(b6-OCSM!f;if+YH*%+qq}9=d-`1bsdBY@wR&~iH>VS5Cx1Znb!+zI1N1<1 z-W!I?r8`5aga<>Ykp$94Q3R1lC46QCE|x90v5^_J_=PjP^q=D6HwNQdZO=V;<(6vQ3zJk2#Zmqb^i<{Y)q2V-Q+Ho3M1^&L(NHCn+Sf(Qzgw)#WhOPAMcu6El>~t z5yD9&TqXk=Hh#hTt&|fpY<1;~bzx{1dE8bjW_6r}y4|MXc=QMN#le*E0w2e()3hiU zN50oaY!XAM(ZeW_KwhT9fYVZ)*Y8K*8p7!^nzHt9lxAPm4|>e-Iy#vu1%T^v+YO5X z9=IXV)Ib^~D!IjolP>Z1!LH@z^*2Sb?71`{XU9Gp^E%fU-mmF>5k=~W3;6YxcCwz_ zL}ex?wxIg~eGj{t!?{%32_6C-C|j8P_9;gF}BML2)0DyrJG)-36tbx07qoD--c@%CUYW3t=F zqa%y&EoLDZYy!#1DH%AwdQ|VYCWvd)985=w`?sy4-cD#XxQx4YdRYp4UN_7QDIl;&5gyO&|F>;du9N&Mi>uRD+!;!^h@s3doB- zLvv$q12ecN3S${khxyiI|6*947dwsLKuzCmI5FdN-9 zpyUJ36#PCI29`SG6Qir7N(Ozu5r<@-E>6?8({sun4{25P&eM1O3QqmV+*@=a-Pj*x z-dw5AA6ATy=+`$S+*`Ub7FVjZhH%%Xdmd2YLgqz7?OOE6MC-2NW>&}FmGWH}UklJ( zWskmpeF(6y>77h}8~@OP0}2F}{eMME=cGbE>Cz*G4-tk-L#Jy)t1u^P3U)&4IQVe+ zGF%*oT>sfNmJF;3$X^k66Uq3Y`XKob#`$`o`oYh`tkUYY+o3Gi$(QJ}8H9{=pcH^N z8<3{9FRA-5GyU`87aWXFlpZfNHXc;M`!w-^USd)~_ydvX51W&72Py8h{Eg$JCsq8} zi7oKM@Z7ws8PaMTHiz{@o@+mbP)VMVpsor#KHv5JU#5Fj&h}jReq=L$An-0d&hOtn zQ&f<8I2g+)l0wGGzG1!6Kl!da-)W5Rr?<)K+F|1J8j^rOD>bOPC3zpZbOCrzs>Eg6 zoy%SYfY+w_OVUg#)NM7s0*9}BJE-1?otYBrb%C@Tw}LdFUo}eZ2Ql<|O{xnQ2mG16 zRaaltYP?462APIS67QzNnzCw$!KFNhpSSW8U4z>y1oihIzg8^LXH`{RygeKa% z0_r%e^U?Y-t3KyE+(-}iOMBmEj38mHX&vELyPNSK*EHd>b0-^mb9-f$T!FTAbJJEv z113ClYeqeX603M%f{4XA4HR^sIRcdf2F0wW8(1=?Y|F+xiW*5j`*b3N1J0yE8P}2Y zGBq1FpGq>8Wr#LgKBG`^y!*$p`o5#E4_0_O>|&>pp)Fh4GvLo=Fn%XPM;i1I9?GLL zlh5k_5PNj3NB*`|D2;F^Wf(?ossfl%-{=-i2Tz4LRZ==vhW5;2_%!JTq1ZMpi>&>` zn;d)N%l_7+O|wh>=)4@HzAx7Q{u@(4dw@7VE95`$sEcBKC;K*_S@aEfZWjuchvWZa z6JYtOm8jYg&<4gR^%*J8KGnlvwKU?isZ1Pbrebd#9LRmKn-uliVOaaKTv>=qMPvWn zcaml78Nmj$Gh@pDL)&K8C}p^cH7zM~z%}}ogRhCapV&c*W&sp`x;4RH^PdEV0_4g( z`Sy7&(^H0&S4!>_gX_-Ez=)|XpC1rJ1wY=B&mv&1wz%w6(1Pf87-p*S1#xbv;_HP_ zQI!$K_14ATzBiIhxn*2~B_0iDN1(S^h3#ux0l#D60U%?lR^fXM-)njf=B3v`BAER z&|Jo?E0$-HoZRL-am-Qv+e$1y?t*Hkf8p;h?YX)}1xf}=2dA2=ti0Q9LyuMn#W64Y zZlYQ0^%9#bxbBGl#?_TsHP+q2!vM?!opvVm7L?^D_GDJ@9_>T?kbS1Z zpUi%Tr_Z^GsYS+qlD`fnQ@~SFlH$Q%H|!kuESJ|s)xPOt74P!S!s)>1t%F^59l$E1 z8+dGxcFNzPX9KBUrW`(J7wiN2j;!RGt`zC3Rjr>R)`t#aJ2u9s0WGk^d;KW| z;QBTWUQnGXa$f+O5Ny8%>v!v}n!f#UJ)I0#?xQk84-V||hv+H0+DmYe2{SVyTOPl^ ziIx27CshIw8hY=L)BzcF@!uegAhRaZg!#e_>I)DSsx|&ctuXvO@y*uwucSBay9b*UN%A_f zSAu+x6T27NjWc=C1U1>I>{al+O_4BEND2#9a=#^bb?!lY6sqYGbrnDhW~M=ep-XoM z8ke}3YF}{uG%?w+v-qe7plSz%3g3yPzJMO>BJz+$VCf627A-l}CB>)#e`6nZ>{bbH z1>2w^V@msPy4P!|7h^|8hm#WC{+nL6wkCR~jn?XpIP-DJ2)h=!{jwvn{32AyEY8ce z=BbY6ZDEq{kCutUki}yL>~0= z*jZV}i7aW4iH;TK#+l$(ebVfo3j50FChWjs(DU-Kc2kz#qlFxmOxK9#0A$mzpGrl< zR-fTVSj0&dW9dcTBiDuT^f>E)Zryz^fV^K@K=$VirhBb%!7P3m*8wCXN58h$I*lay zbkDmpF5%boty!Xe37^J)qmP;|UsDL$pLGVXbhYqwEb{ZNz7)GKan8`v^Qk!QOWH6I zDfV)ay}aVf2gq8sikk{U1Bgm(qcRiTflr=)57=ker2MwieDH3^FO;7)8*y1dNQ+vt zQr$13*DoF4445UtWf|eCmX^DG?%{Kk|S@c#SRp|lX z`89pg8}=ti)hFr)?24}EoziuFoXN!z=kL^HTv{;Fo;%?G^dw!PIX#J>fn zjXdra;Jt8p#ID^dm=4{kxD(BK-h(gv zOMhWz7iUqa;LsIZJX;lyVC)n~GFbAF;pc+flkZdi%|^M~Pe1M8V2coO*vp>lQ1>|? zJc)&)5lg5RU@jDw6zCC&oG^vV>hB5|g84^o@(k3P*-fP)sg)+HU`wrm?y0p#Hcma_n5Wk>!nw zL+8^%6Kwro-&o}{>}rLzb;u-JomnJR`^A1UC`}7IAGy|^EjyEkih8Y4-PqRx^ZC~~ z`kg?O)=f=jTW3d!%3b-s-<@2}b)>M*M;v7x?=Ml5^Oc*MAQ>UMEl9i=L+0(63I%d7 zl*@s!HsPhL!oZm08^-%JbsXq4s3UrjYcOgQH^u5N_-2L&R!~Km+_nq5H`FJE4@;f> zeR#atOwJgSZ?DsQMSNjvwjno`$!WYOiM@+{3O$&|6KlV34 zKkp~V;jTm+Wa<(M1cZNV{z*jSP*CWhgikK?ghE|o*mOCYzXnR}^p;30xx#2vqkipp zZzsFZSa8KQD5dHlvvQ6R!KPFLpJXRCe??0zy_7MQ@v7Fm8!(#ukZu#3_(Qo&Ds1Sb z&U4{@aUJ^>Q{$e$-XL|&bT;o!aAu{!TcpE@aH`O3J78_r2M51=K*z+nUJP-fxxyUZ=pepA_NLASP~lFr=%a6B zglzEUn0JEMFo(OrShhfIp|zv6=tIbFH6Q;}xPH7*=q>MP+^1^I|8V=kO#FvC0V3`l z!*z!0PP0EN%2re;sGGOp!F+1eAg75$w4d8Q{lVb(`EbFFWbp>7=NT>80mBwVtzWIN)PE=F+GYq41{%;AjclYH5i}c%Dks28V29-5 zeU=kIUtv?+eZy0s);tt*^+A)LUmjnOlK=S_=k;|uclOIE>n0XPJC0i#63U9a0W)2% zhm6i1AJFQ_1$0^28McVFe5EF)7#!buuxwsF^Kd6Ynd@nl999-QPd~J>4Oq*x zzBZdMoCaR370Iqg7=uEKL9$emT$nX{J4a_eq3~L0<0E+=E;5dAZWN))-jo&;&Dfa>>fsPP}g zxM27KARHrrpKWFt-e>t6m(~fDna$u5M{hHw8Wz-K_rCj#qt8pXyC8Tb`a|`+KC!EK zezYj5eujNN`cw`2Ch-j0!;}jox0AW9^|#J>xxiV}VyM-J;O>I6L9SnySRbf){{DNPa- zMBKz41~(FXo-9>D6KKI0up^b>rf}->?TgFboDiItBNfigftM7^wQvmkCV#o9DJ{hr zEo_-boxhDDk>pd!{;ihKaLZ5;1Up6yL#<%(8tEn5p4*c;l(Y7CpR1h6z=dG}#>d7@WgVl9TeN)!mYn5!w+p>17peiLbCA(ZOEjfD_$x#3M zW$vof(JR}Nxu4c-8N;IxCMMyIxl;MBRPK3DCD`<6MX0#4$ zw)4G1B0UVl!3JMT`xa5rJiS#kGAxURrtkCiSp1^U_3WDQmK&)rLgpE07OjMZXvr4W z|1d)SxSO>AFM&h^cV%2V`Y($|Umg5S9W2Zyd~NHn#2u!?N2MfKgjA}3_3dxy6E>NL zBWtj|h3#x+HMV<}vnCgw(YY3X>MGM)x_S*9?+3ErQ4lAw?iy1#A@;dn`AmgZhY8C2 ztzUgt#)(909vz`7h@Jr*sV?Nx{i|D}9{79*E?RV|^oY{)-rwrU`5@t;cjXYXxjW>? zJBCWy`}n>#7PIL3`Z~;WeMp-Uzkr$k1~)-=oV!y|sVGb^jO;bI6C*bYqwI<3#n7ul~`$uIZ*BfneF-eg{U^Eua5=xi~ zNlb1wchUiyh9$as9Duag4uowhhUAvMNpk+O_EiXGmi1yF z#OA~^Fuy=|4F8S)B;ozVwT0*X;Peff?7=7YxVMzwUS4V(o*nG39>Y1!-%AlvdwOnS zQ5T*19KmwGymhi99KT=|2|}1oEW*gx4bYE3kddEn9(w1eh7O%N+8Ls=3F(B*jQ{Sa zrI)M|0zS0nd@oB=i`DSzXrEky(we%;t$0N7smfIvya<1t9AAj8|*V$sLlK__FbDjL=p*P0G?h+nr(3QV@ApxeE~9D=wI*&+ zl?=D=r&}l$%c;RJQOe!_<@F=u^bcC@l-i`41QFP^Lde7P#C8bhr-Jf_;myCYLkbsD z1wOCaTx@m=NFLq^-%o&PoD+m6I`d%fRyI)pX7TE!?GHcI7e1F?XzVxs_~svH>$S{Q zDkvRw2MCGVwr#q_WZf7rlj@XIxmOO*MaKmc zGC}K>S3|@>^QRJqL$or!{9XQXDYHD*tXc@M>i$I=61DhgLXdL5_Qem3kTSJ2oJ;R6 zRnKKz>#8H%N4e-EdZ-FBbg6-k*2%&o#=KPiZ`L#G0=j|djuYy%T&;b(!a?;h%C9Ya=NGuh5+NSzh}ZA|IdcjcV?8acve93-@XcuO@ zO_`YMSM#BHdfrc{8He>*p-5%9M-Y+6w@ul(;~de-UP@r^(&evod*D&KV;ufbyVhS? zCv<-`pxyDdBKT3OmSqida+$)h9^rz~Td=*3GcLf1wwCP>QnWujDAy0FCe&wwp;~n9zE81h$(D z)H%STPAonX4Ytxo_LV(iiWdlaD)(-Z`_?T3F>0+-N}mmmihY&?%i$ZLmCOzku(8!e zcAsqKXKCR>_8D@D_rEWT-Sn4wbE+5 zLT@&@#-*=8I|V?&GEE!bs4s`2))utgePDCi?mzoA54DN1_;>z>TIRC@&+6frGOS?r zS}8S;eH0`ZPEc;|TAG4-EJ4DM<8_b>79fxvcuqAkEJh&wF~~+__mz7mH(> zt<^2eSTmKSVtlj{L8qTuMZ1;F3-J@*x4(V=0azIK1q(M|zMFElSX6fz}knWPDciG*UJAQxn-t#$}!yj=x_sa%Rc!NMrF01aD(n@{cph= z5TDBG78+)9?;!48-bHw7Ou-Up>{u`7n~!y_!H!KkUWm5@3Y?^e+Va9~2GV8-%xZ=z zHi;HJ#K9n-U<|rVnTCNMJf&%L20Ox@>$TZf*J7I8b;au#a-{4q-E@|zX}aCdPuL7r zX;qYif%SNkbzTT~`Ov`r!t#v=!&{_fjwZSnz@{=$Y>-u|9?fDbXLB=!BSS&ejRg`) z+W8yrLI$%^^vI)@%t!$V`Aj|E74J#J({t(Wo_2gM(Y5;`w2cW*HV1nY_XnAXy&))P zJgsN1Ff1YI%0XDHk))V#7vK&FsZmq(AtgHu``3I|2I)1X!bjVZs;xsHSaI=Elir-T zX?B5Pj)%^>H6_0O$K|Q4PL$n93i=8-Xo;VH-AO!X!2rE5WAIh`s;7S>Fr7;jYC*wIi_X&Qc>VhF-HbFWF7TdO6OeI9^op zv)ox1iD>n3Ulu)XTNa8RcbK>pko58cAD9_P5r#XV-Qp|@gvIPd>yY_ zU(HXMm0neWzE^8==>@qeBB9$ecvSD;2Pp*usrM-}!bj9) zy(w$7(mGOBe)@ixvzrq2#CEYnyaaF1pn9$ghn#kx z-E@SJEK;=Nv>_0g|9TRl(vXsU7Djq^R9xL12T@fY$HV#oRbkG zt!+w{v)Kg)2R5pfeY98VT_3H^&tKEOjYUgX=MuK6C8THeXGXB9@(ChQ*}!H+1Xfh6hTyOMTx)s!rA}2e2&A^QS^go z7i~e7DRDY|&FaiNKcIJAO_vQz_WSVL*9EntuyfTs5wT6Bss!%)l>X`)i_3iH{b}yI zz9!lBo=LCjxtTP@$rHEBE$s?=F56k#;z16=gU4rNB-kzZstn27o+;76W409#X!8JSW3Yy_$RBQo>^ zJ)DSQy7~U(k?5{Q!$3mPT1l3uI{9vF4iGe`$iw{fH&7n5F1QR+aGoBTDu9oi4_>o@ zlfOj~hU`D!2ix&MrHLJpH5vMqinhe$GChCrQ!voy6Ul7W0WH~&gY_N29OMam$99mw znofY$XT#WAb65ri2n<`Oo@Udsz&x3Qi3^0aUQxZLn-d<=7t%RvHaFQ0#!s(chkS2D zK&CqdnEfBjwK=UUJG*zRKq|D0~gq^4a_ScUES?^la%CEoZQSKH|M zJ1ba_Kxuj)Y#d8?26Zk#>+xl9N^0^1I&$9>?Uv^lZoFchjbeG_!!RO2-l+NIg@8Kj zB!wVBI-T*z?@pjC9}NOO;Pu{hD2-SUNBGwCYX?YH{Wlw$29&%Za>PRhT~MBGLGlai zyT~(LoasG2OZ{Ub9f-jqMvIX9q91%Nk|#Rq{|prR_MlXd+<^SAM6j4X`HRX%V3BbY zVh%2%Q^i7UH#SgTfe_+1$F$#{2%5rgiRwonPZsE141+VNeHP^t%|c$@PDXG{@B8w`ZHqgCF268!7UYiw z{e^3E?pzF^HQ?{_Z<3?sDYlWvVJL^q4viSVF8WFrQny#SsT_tgL8QatI}s$$D))8Y zj4MOG!U5&^K<8Gw%9xD=Ra3Khib@j5Vv*G>MIjXY+KuVzqu|Zw2BX3>3L~2+V)bJ5 zx7o>2_bi@>UjtSbkrr!4Qpc>R-T$;@h@8G5uWv5~INjFzj0Hs+j|w^cmY(BQJZR)F zkL+;bvt}>~c))A#0q(d@y5d1FYo1{Q44e{KXn%lZX>@dNiPS++KwD@aL|x;8V^Y)<%D z!Z?37sj%0|RhH!}jUO}%`f}C(NKuC(^;s1Mn^)#bEc^rw$KM%cTNzxaQ~Lq13LD(c zp{`c@i#?Pt4a{eKMrYs8T?kLgIEz+XWSRgfOfK;KE~O|or>p2qT7>VkfS=B zAfEAM7ylE1TQ?4JuBR81GNtBtc-8auKc#xvIhd|i8;i9^Q{%6|smOzH1I^*A%XSV>%3WjWY?Z)aO z$_!=F*nUu!{Y|E++Exw=c+{$P7N=4kYrS_UID&jH5^2owVbKs3Byw0#w=B(Pz(BiS z^RxvKdOqkcZdO4u&{``rGxEuZvE*BcuJ3oScQ|{6+f$js=BdTm$*JYEZN!Rc{9Dp! zp6I#TwcV+zDQAx1*K^KQqP;A=BSdoUb8f|l`^*=FDWoqV4Y9DM4}a1(DK`}wnHa<- zsu2q&hoS889-CP-dM_hQz5T&q{BPH@^iV?Q-H>o>0OAhEYBz<|Ky+@GZbD+_?x39A z6I{_R%)AeOl}Y2o7a8ksypS%lKW!23xEL9VL(6-+vTo97bIaKmP)$uS&~ zyemLT|9(g*W<5W);dEM^McCvv(jWO^;uZCb<34a`4I|qP-lMW&*=8x7f2IyCc^VV? zSqMLQvz|ep93lHWLSlAOmd-Jnk-gud%>RxLhdT!*_6%|D!x3^<&~8RpW6mF^uYbo| z0v>hk4P;Cb;eUi37VT>U_xe*a6n&CvGIM0Pb{ObKKYE+~X*|&|qJJ!{($F1$?aJQcH=lXhY+OV_0CTl;nUZ14^4lKX|g7-}98ClqU4YG~xt{ zo+X}gky^OFjtaO*3+{UVxh?DGDes=2)l+*%U}0t)6LHq(Iy#pd17^Rr z+pwU7Hl|R(&ahA$$l5f zfxp|A*6{Q3L8o+IOVc@^2~lZw zbyq{Z1kJpP_QcJb&{Gh!?SXeC)N&)x^H=wnqp0I+<9%bLoF*rg+N{53u6>t5kVwiSt#Jz`pFLThF7 zl%>0z?Bp@(6o!6ky^5n3&p%N4TS&da>u5InLz9aQH_VNr51}1n%x?tT27PsDi7Ksq z$4HpqM9`HbqG7%*mG_7i>16a=K|?emzW!cA zDi(;Al#Abj^lg;!^wFoHQqL8Yd%ZF3{xwYM;i`>_3(teSSdQ5qbP+ziYk0aVp!C#y z_@w0qB_TM3!i?{+cUV6=)8^de*`)=K(GB{K@elR77d%iGU$FhW@Bp?xRsSHE+vZ2} z+_mWyLytx%xWB-f*-vf3}EOC>7GVs5_DMzju=33!NsfG5}$Jm7$=**mqTGH1r~*2wVzv9-KB?e z`hfGm=#7eZFn@{y6j22`1CJxWyxGzp!8h@&6!;7(9$7xdr)CnWT;^4J_3uQ8-|h<5 z6#61WY<=S22R$W4nD@QU+J-iC1!!2WnUe_A^S`X`yyq#814R<-!tWC2c`=esbGHWr zYLzn}$C90~^2YM{+~5h@xe@hJOET-XNe6%!6`C8nmp-FcDD^%4fP8#2%2Y6(qNFIy zCb^A}qo8ZR*sL~!2zz4YFnaEs(HAVJ^qycEh<^~N{2BT+1^rThdfEH$-^h#~ZAUig ze#lpbB!}j2K2+zz7QH>=|5pPpH3I)$S_rLc8}nv>m>tky(tIw|tF2n2^(9{C@~=x@ zvEy>!MiO3R#|WvOrfF(W#^j6Nh{TM`i0t-Unee`Q#5NifrT?Ybva?wUqi>G=<9A+G z>qooT10F@#Gs@kpfjr~IH4+N*NER}CEB+89>@$?{Ch?A*8@vcJQh!B9aGl( ztn~ivZ@pmwaKEdRfxjpxlp;sL$yc}b`fc6|!Q~n|FMZIIc?)UpduEy(vWE$84jI=r z&a!|1k-<2NZvT{i4pJa}wER39G86`{79t-=PK5}ZN8L58b^k7CQqkS4)bezAzV&#$ zbdm8VZhmzc>9R>)^smE zM(ML<*t7j{4MB;9Z%^!pIdGl_JHO%pJ%%RUwbLDSC?>1ultliNv4iY}TR1 z`-fUY8%|HfAVr4@GL|OyJ(aUWr%Bds*N^@Aq#c$U~M30HBo(F~{Vu0v0oD0H~rig@$!s0$J_;X>{gYj{5M!)3wy+Rk6}Y%6$ve+oi& zCu^R4ulL+QxnTwG#GK4eEb8ijGR!InSC^WDbu7{er>Y1EHtVV;zJtn0k+~ohM*V%2 z8%VXQah%WuQh-ITL4@R*_GVachzSKJP2#0~8vW>F;BL!|K@Mam&XZu zK2u-6M^q<{kS|l#ube)6z2bovMs~-Xn!}8;B&}5Y_lAfCQRkCqB4JLbu%EpBX~uR1#cX#%@2~FW!2CWS4S!e1_%h zIm=C}llZRcBDoZ@Lu&_i^;rJ#79gnCU_X^p?&^V5UigCJwz1M?wG zHte}P<@@jwYxtfNQJivKCFB%I;$Lp}6_`2`!I-YCAmJbaKugny1zi0uje-~eiOJy3d+aQ zBt~3ivt9}2ls?#qx(lV`KRwc*ZbnZZxildZuXUL&Ab)0T6+_H%Xi5vY#QlR?{>)Wl z(RS+M8BO1G9va<(dU4j{&cKG7Ca8xJ+tm1p=2pn+*MEX4}+vH)IM`x7_){Om*(-Q@!eW`}X|7$oAm2S<6F5_FY8u z6*;Zm)gT2QjMM^V#6hGB^|xBxct?hkKa0j;}VcfMQKMO^N5`i4A2W zR;20lAjfjxAtX{lAUmS~sSZ+OPDS7u4&orpe_Dgc@vJ+hyOlt>u~G6xkbAz+oD>yu zKHFj3yNzp!u37g$`gxPzpO#$9A%{7KCR_4>z@Cc%9@Je$sc*W3ITmeMl5#dH1fw*_ zfwtm!F_l!^$B{?Qnr3pTI^5?hR|O;KKQ4Y<^?7q+fz^CILbDYW6*5m^weblpNYNGD zWI`txx_YPh9b7yew9=1Y3)7p#?jITY%{*57=>2l5zXcq7*&1ob(n-`$Qb&UYb!S*DKg1*7RzMHG9w2Cm{u^vW2Yfnkexqr9kYI4P}L3@6G6NmR=teK6| z?ODLIufWVioqd#$UbXVRS_GIDr14eMC{rfE9`DkN@&5g-B$3rA#VO^#g(~gA-fq-X z*H=hwJq=BFgt%oUQ?iRgvm$>VDz>y_NraFZ--62i$F-{Rafx4um*&G}d-CK3CQ~|EBWn`x(0<5A|I1IQNQy zoJK}ROt}_w=;ztGLn*iy%AQSy8jqdGV0wxObflaLn&;r~O$3+uTp69iZ<0?16I?or$a~03L(X8U@-*t+o|& z4FQVo2m2ygInDvMsj(<*3zNBaCDgrn*`yM7jL;h09bH%!$cL!{pOk^AQWfjQGsAM{ z{!?_~K9rEv`xeseJwrM6ngQxF>|FLm1Tu&Ri&%syBfb#p|6Y$1&iI+S$vHZUEv`VJ zj)C-Aop;kc*{ifl9TpkV6o~uAvk%TZB|k<4^Bcyhx)?{RtCVMj#62Ee3c4V>tWYR$ z4#lCZ%M!TQ*8MW|QWL*)a+oO_frPM|1fCs?SPD3S;;#z7z@pVSn743g69r2qtNw#% zoR-gWXgJ#nICOj0DpWVQ7nLAJVP4{(7!G9+8EmssEI4S~bvJ``G7ixNG8nzu|m+L~N-S0yBT;D)q^BS^_hj*Nc; z(0a7xdNlbaB9ru03#B{*ODDyfziCmaYE2sjhC;H!`(f<0emhe3O=*<+bYEUuPc-Bk zU+-)G@U6MoD+nQ<_D`>4)rDBkg_ zB{5&B_qa#2e5Dsi{52>>q~SsZ4=i7SpLf-Z$cd^R7r5-~86=y*`x8M<)F+ZyL^l6d z(VI6bCZV3@PLZEbZ4KiBzcab;`}jkoXr`HISz8wxmzp($VADQ88sq4ZNg%7IY8(8# ztDG-GLW6VO=Q>_+0J+1X{0}dXKE_@v4`omeI(J<*^dZCJYu~~E z24B&JPv#s(=U9zyR=Tw}s5+Ns?VWy}@|I42M*NYOufJ(BB~e$V?LF^j=!Y?VUMycJ zjLHpJJ{VjD+&~Juq$r37Eg+pZF$>*J0-OPs9`sjTw#5^hl~2{g&6BD@2uI-0$|Tz| z{-r&MR(M-`XDstPmmI_;2_a0p7U1!6@6}h)C`MiO;EK2Yg+-W*TfWS6_LFMnL)@=( zt@J5Pi^|OK%0tBheacmj1jYqv=J#F7myUG#px_v_e6o|4Tt(dA;sfvn)qUcVE3Tk6 zWAo6X2GjJj`PD&Z0ie&iFR37Jy(gP&uN92Wf3|f$fYg{8_iGzD!Ri7iR@#5;iAp9B;rU;qXuRnY+&oc4d+vA?lEy5^TS6hUS}I!E&?+HS z0@o_KG`MQ|BbleL;1PaibAFTd$~)S7_J9;|m*q$)vOOU4-p10yJIho&uQJJ$)cBdk ztOR)LF9fvD_H1v_+z!EI&IJjZJWpIUJ&hYOe<}XDLDAB6hqG}RamDqFL?cfB{T*1^ z$GWdpiyd6#7?cK?X=TQK61>km&Pd2dtbzN)7mUOb1DW>;!wwDF%M|e14$);ux1#Zdub(8x^fN&(Yy~+~(<_&#emEy02TnhZ=7XdP z$5(-y1z$mhv%Fi_r@io%MqCUojegv>S!9VTlHuTorJU!-GI?7q(htxfSTEf6nUY;9 zMJn)~EETXPXl5+x8lRYcm99cw;J)1r2o|uXkyu^s%XzravUvP>^qKO@)^G|xeQwiH zeI}{+bYT?v_$7bC3#=!I!uXK4Vvf%0ElmTH!H?+%RU`JWx?=8U9-s$q`C#&x_BivG z%_O=hWCn5E4KC5dvZd)Kq}C})^!b}e1P~=0yNsWbSpx}I&2;(TfJ8xZwob6ss~EW% zO*->pSHt>}n~V~TWB1vlpmBr-@yk`h`f{QX$3v=ZYgyW9y&EIfsJ?eqUi(=uXhoQX z&L!M`{THZ#RHiyn`!V?Wc!D?VtVvuyL|U?saJ){zU;9OM7YkDblOy*)RI|lj~@*Tt$2N@;cg9#|Zp*M~JCX z7~tv8tT&%-KaSlteScX_{?%xlGq59f!fHBT^}E8N%+XlN@O8d1FPV=aZ`mtGyP<0w ztslB=#5q;j04>tTlqWVvH93#*iJnPqpw`9su}DGv6%XwDKMA;^EjT!8FcEgnvFc68 zEq!&;Tj~S)X%$;gvHWCz%ExkTOB!;SDwQ4jiAP$F{~)ZN#6G>Y6v54(pkURDimM{U zt%Fss5FP5EZYTpcZc`movh z1eY50nfIh<+w^(tFm3E`axWr5ZFR*Zbzt{8TAY{4!CmyxvqO;(7v#8G<~v60{>Jpx&ly@NYd@e|*ZW%7My+vk9WxpM zMThra+8_L;b>Zh%NHcE(NqvICn+B)NLOLbnHEUqiAo6+liy1=5Ahbb<+BdXRt0uVN zEV6TYO;gdwPr+~;qJHNYJ>6v=BkNF=En6#+t6y;@cMSBypM6dqGFMZ4HxVHyEIl%i zJNFIIv3@dH}-r$W$6mm`-~?-0sr$yD1^1wlK!tcrh_9n(3k&v z#+-A!&c9wzkOLjsz}L7$6WlVGx{QRmwwr_S5eYbnI7Iz-OlxFemBDd zFB&t*dbEu4$(95)NwVFIp$Kr~W@&B@)zeWn7xqJ4pf{>sh_t&DoqL%E8O|UN*R{=- z&Di>vd{BHd-AD%jmz2Gubwa8zaqpmWHMSR#iadS+l12zRouFDZiU?kW92&@9mkJz6)NvMM!Lhareb2aWOa;wFoTyYW<0 zXX<)~RHmt$`J;RZTPYSRE(11~mM1rtFw1mNs=psuQ$EpqO?W_z=UeLHb=m_am_KxM~0MW9-~ zw?lpq+Zfu5Oa*?dvnK$*BYH>+4(KxYqGuOpo*LbKem+{kZz!%%Y>7_AAm)bsE6%$N z{K5_kwdcIV-<$v0qGZEfBHyykY~{DU{Ge7>(Q_UCym`XlGC$o&_x~<#svPm($NYCv zh4C}18osNsc+(G%XAh8rgb(^?3NZlu?`)Pr%PSf$&pUh42YD=fNnLqL!fq{a?f!Cj zm4wOw86}})@yp##8U{98_4^FlA%DI6g+!%Koxg_bU*@h}qkH*w0poB9dhgU;LsPnJ z>b7{Kt9_&tNK553013lSRyE<9f-AmtS7bWY8K@=hf}PH*fR&`nPk%UUHc{FPm6ki%!}; zZc-En%=z%Ed`=Ns1p$zD^=-lB4Z-gBu-E!cn=h}U{iU5M)iPuXK0^HzZ-S@wiur`l<){yL$_maZ(sqfoTE{l}%h-kdtoesm^ z`L$XM7~FNZEgwOh^dfJfhd>t9I}Vx1*1a{E?mgP{uOB zvPdG6STUT#`K!Y>Xfkm{ zS7)Vra~G8I{$NG;ZSwNYsz^4`E;vtS&l!E2EC)YmCDyZqiw%e|A1tw#V=0)EWvi&7IQkKyy!>0JxPOa5j znES*!!g+EdFt<-PuhqD_V4=Y32T97SL%JY?Gt|E==-4xlfppW z6R=Rf?p0ML`kDNUa%#f^<(y`xA9gbx(^WzaRoy*O+g7;fd!^+V&AvWOpdo?nmF;eWs9LOb6S7(7>Q5+11&I? z>_d(RRHf@db4@cBLvpQ1L@t2mDWc=tiXg+kwd>bwhy!SreY9bPEuRI-@44chFZhas12*Jvy#dgK z--zk$4y5rR5|8jK9zd#JMT*)%$+}(yIE;=)69T+uG*-?WL=>evrR5Yj4X&Z_%OURT zE_+JcOBW!Ud$!lmxMQz_@2UgI`HIvPN7?;S2Zx3bZ!7`t)620XsjgJd|)6YieDJSm*Ge^K+fm)GwC3bf)av8bWj65f%RC3{L?_>z?h78uK;WFjQ^b64+agP|J4 zc}xsh`KU^hZ09nV5;+)fJKeV;Q5*0tH^MdH+)r__T_-|%*I<_jo7nmdGpVx#dCRj0 z9+oX-DCL}tE?{@qy&WkWhcw09IdCE2dw02&o}#?;ke0r1c~QxY9`w3+@gWqoWO_)B zb(*OhQ(3Ls^U<^WQqI&5sC@>>FfGEFGI)a?LTAjRDPI*xP&&BTaby}R$CEByo;>4H z^V9@^kNe`^5sR_z{lQJ#8!Ab!Kb*E0DYs*+IeKqswb){HkeG)SL3f7YCUy;1QIN0n zjb+o9keBlP=xNEUYCY(<@cmKhCG6hv?sxx}Z4%~>Q7(@+n=)r}(*2{4wr7mz*jO>D z8INQdb%jM_JW!loZI2H6JY0G_L>jMCb4Vmb3Ex+DZrFV4v%h+3Nvu7V=Ia}5*9gZW zu(5wUXHdx!h86a=LQXdLC7~Vnnw88ltJbrA*hy^fk?Q5Z+Z(ZWm|+MD@Yz6@64r^Q z``%|1)MMtL?lRTEU8+)MvENCgY^f44>hC^bESXC67M=)x8l-$)@yYdNL;ibawsN@% z#-|7Obl1jsIqA|P@mF z#SQ*rTN=BBli~xq ziNcwi^TLK%jiUA1ZN;p^!@>j7L_I+@$5g|=)f7~8O5JHWh@3>Cfg}c{TdbP0bnCe5 z*b28h<87zjn_84|%pocIi%#w#(>5}|BCJSXUf}WdsFso;$a$zZ_>2DmJ@!X0U(Mn= zKo__chGDf3T`5E&d1Dv5cg7ti+s_6sR-c5PcW4k43fo#fzI`%9 z$%ssz8Z}9tac+G4K|0Vq9yE2Gvl}6caW{Bz>~&k5dDR<<@{ed*Pm$ltSs7C z@uMn>maq=(ummi9%vn(_t_O!8`CxIK$iIY^!ORDEXV!-xNZfi)#9ZALrt^do(DEPr z?{136M2$R?UUW6~ug1?Q{fn*}7jtYc6KT9hA8oilRmGP%L>E zwJI%$v$$cQ=CB;|w|))v`x6nQIhZO7wG98iFZ|u}6FJ>hf~EH#|2dpwbvcm1x0$Xs z5tWqrci7xd5iSXAs7Ar%IYN~YemP3NY{E^NWy<6Y++|n~)QO#>;jLnW1MbPuL-ORu z$&l>pDu2;KFTxxg-RND!>2`na-7sb5)^`Yg5Udu;%z?U73H|CfxqrZ3bo&{iADAVK z_F9g1^dI2sz!yIt|0r`@&p7iZsAsB_nTln*S>O$0ltp_S4L;V4xw_SxfG6Y)BDE!- zKN#yHpoJf{tXWsMgpaQ;&nr{|03n7{!e3MFpLo1nyY^ zbzrXS8Gi@SYZThNTV8O)HJYxG+fI-=K6&$ylWWQxL~Inz)6f1`zOw_cu-@*4w2_|+ z=5>$|VRYrkGA-?#HK_z8;prI)zgtyxv@xY_5Q`y>|d+3F- zCrw-!rX7SFTchoS*rr6W$KBQQZC1+Of6CtCP=ak-*Mh7s^3%G!xC6w>#yykDu5m4V za!3n1Ahd-K>m5aIBWLvEaj~zRri(Am(KRO?y1|2NZ<0o~!*m7-elzWj-Q17dqwPsU zxi${Q+MILR7YMX+D|{>5JmIvr#h{T=FDfZ|!ojS^vjoazkiQcVa8d61NkR10dq#nN zon8kaR2r%CfA$%Du)(G(A!>i8uDc%%Q}h}Z$q1^m+pwlVo8t|6_4tY9H}VS)aU08n zD>bZhZTwBOJyC-)*NFII9V{~pM-ZUBFK*GCp<(HU&QO%&Y^~5j`fnk+51p9Bkky*h zxs)$|j50HoA=PYTzkWXSU2!+dC9humuZ8;Zx6*@HAwjl4U##ha7i4D|o!AGULl?-~ zu!MZ)k^=<=pD6>@xz823F*B*R#ouULc*QA_Wac`-Z*)ZC6VGs9duuH8ra-9nD>G^% z^+!XOeZQsti8dyAbnU)>Cwdfd<$AGE#XbW2G5@0k=z;wJ&-?3W&rRT8q4_tA=N27M z%<28wK@a#xcd_TiC>#)n_Pkn0epR@>kp&{ZhA{BMIDm6=Yh4 zRE6bKuljG?Vv`~8O6?!@S{_}u+2-yD02+)xAphQ(@|z!BNh&LhlRc4p*3o$M!L!YT zk-(`*APm;5XWT3>tc=SmA|@NTUAVb*Tz6SaHyIMyu?=LPV zPZ<52Ma1~Spl(CXO&f=pC9xkigTm8CWK<~|OTBKLoZN73Ej4yWW-}rNt-1!p%Qg6R zxpiK>&A;H??5&ZEB!Y@QI2^@l!zo|43xo}7F<-UnMs58?w~EMvk6oVF3u%HWG9Vw6 zbl@OG#AESTfpl{2*i>NuEVcVZ7I2$%06Fql-idzcc#5<~ikeh`-m$7nJ%lTsSBE`W zt!&bmjcw&-h1Mc5mr+Y^>iV-L0DUC;8wp!jvB&vr}5 z{{d@}DJ=gVoT6ZN#U+wMJhKN??8G8r`Dxp|4US(88GVrI4zSSnLB559?iL0K?JqF8 zZ|Nfw25kav{PQiAA)?U>hPa|v-zUXyh(}En`M&JlG{wD*f$2^wjifdi?$Q2ltArYj z2V{B0tl&J>gWW0tPsBx?e7dn3q54NzYt0`;w8^1wJi1ftk-V9yO4JhHloy zuk7|Ef+W5w!V=wA@dpn|Z%HZz`nQvb9VY5}a(@Xoaz}i%Mgbe^Ay3CG!S?-PTvv&p|R}{ND6wKiHretBt(xOoCE@8 zxR^y>)YxeyTJqxJkLUWgeL}cB>1mnF0cB0|66vFadu0;Ii!7})>PY7|!5GSY{NDy+lfVPGq<{-35nzd0EndAE*q#*RE(B`72BB6k(&=xovTk6(g@Ak zBWRaF_okwHX#AV5q10IfMQ@MGL|5nFjP=NSwbvX+sj=!maN(pVAGIS$9P5QRiL5&& zCwOE^l3+(r=9NQGchg&j64c<%d(W#+zo8F?&Vv~r(08m-jo8Pp;tFKA=~-5f|=LX zV(#%!fVxE{MeDEMd=4r2fPq%Zih9n}Kd*kH2o&;$7HwcSt?{PC{e1YwTt|5`&|e!w zV^S)lUlATG7SM*9&iTgF6Q=7%Do!7bcwxNLmGNyE?oNlYG9zZbMm2X?|UtZ~uzjprvi#+Pl@>Aib>X z!Av@Pq!nWS&kLX@=9iF$9{!z`rBxSGj}+lzB>b92zhh~-D%$wAWRsxOc8%_qFt9OK zL!ka(8?9jkRfAstAoMEaEchDwo=p^aHqSDOln!ROwXyL9Uda8SNL=mnC`uurMe4#? zEgVt=49Q9@%E*WY((YF-%N(n;p6P?689DaFjELX&Hp%P$Sf1vwxpYa{a24&_pxk8A z?Lt>hDAdPFu`bKu{bzRHvenrmB4;0C%UulbuJb1=NSN^$g(vJlB8_K?g*D)0>AFeh zvWMp0b|W(YQSmqCMS!0xocU7!1Qd2Xi--Q4)jNyzg9gR>gZio8F`p~SpYW&qUcB!- zaf#S+oLzyH(Y{$_M~z%e3Xb_1Ochf`x+U5lJI2{Be^V_lljy=oBZ_^I2I!SKhUL#U zNz%h*me#x_&4q!}x9j3(s>lrDSf#kB+ZpPvPxxho*Lx%Xsebpt`Kzf^!eH)>_fT3X z8OIfILE}D2#w%i$H&}Syg-JLW*sGV=yA5Xxog_Y7dS9$rI&8anDDuGD+)GJ*7#HDR zcos^h0UWN0r0{%@HkHG=zBdA)MuE}n`kO8dXYY3E28)*nMKW5_gkKBDj@sz~-UEJ0 zLI~}ZNYNSIL$rQ=7Qjtmd zb#J{DTsn*R=}OGYCcW6QOFPct4BTRGV&}cg%yhrzAEN`0SRr4&#Qdq+Iy$W9%yh=% z(6ZM+Eu1eIozKA{ixYYHy{!8IdCPq1>(3@IwMidbFW)R%B}6$tf7fXqGMj)OWUB0P zO|S)QtSx)ea;`?I%-s_^Np?FJs6+HV*bCrwSw6iWku_U?ivsmZnh#r&-+is5>NarH z=tvOJt5(<_rgCxSEra}yi(NnwyW%*DVtNPF@lF(m z!&)*9LD(0xn=Gi1+3!uY#1US!<7q?P-GZ0rzxX}+KRms6IMx6EKc102vqz3iMrO*$ zu}2vpTTWI;D20YRt!$1hp_7%Fy(%1=$R?reJ#y@Gj&siQcf8);&+j_d<#JvAILA4U z^L*a#x5?i<0XtF}a@}A!|C91LZ$9USy&^m~mfAR>3AC^Gyslcqb&|n5&iKsX<~oGf z6n*V<&Eq-|A(R*g$2Spi#-?f~vABPXXDeSmGS-kBT5T;9bBqboo=h100>(wnoJ=P; zilD)-W1QF)-d}Q!e2L2>hbbI}yk0pNd1IAo0KgvB?AO;-CFKd3q`U!7IoTnR1K+D| zi&E}F1trV{&^1cz;f#xhi}uj>-RiZ;Xn|TO{B*7Eb1wOpj6sfj&(kztSyjo}Qj(g) zaq#$7E`+?33s7Sq*!#k#pR~SllA(&oM}1NM<@#kgdHT0@q_2g*rs%0UNEXl8mb!!# z$FubS50=30gXxYwV#9O!HEbZ7ml^?lF(g>zmD%)#()m_tzkeF(aHh+n+MueJF)G>My6{D)oq9tt3|E_LcfBNF$MoipyY^DEc zC|LIDzpZ3IK34u>Gx_if{NG;k3}X*Fft!q4!3htP1IdEU?lpZB1mWM*!?^f9YTR!j zz?3Nw&oxWRz|7DG)pguT_pqORx%Pp|2k=vY$c1&88G#2w`N-3YdJn)qwIfYW&G{OlnTA6e=HkMfoE4r_5m>u7~O4g279 z94vI4vkAcYZab8tAB`;&^LPq&BMr}yM4C>?dzd6qA%twzFb|)eKBaLThqoQ~+W&XB zjbCwHKZm9L2H(|Hm&*4$Ee5|;gaXGQ8(pf8|uI5_kMg`qq^VSmLc0X`NY${(4{gAlhtU57_pgvYIN+!aRs} z(81t4h6Bh@7;d}c`7es&P{E zxhk##PL;^H(vm{$)5U?`-nv#P#L`70C!4k)w(VmK1Od{tWPAb)gorLmalFVO%nxtz z22+)PD3c7ffKE?Ny2q+ikM>`RcSJiPC#de+%k2~*_p5&u6RgdEF%Zw-ad$-N&(X|A z4@A42_}l9(_3f+3-{Y#iu9wo}9GPzQnKG^K=GCihO9}cHd+p1}7K?aLgHP_)HAe6n ztSAX2>Z2CO-(XgWe-!?9gvjS-`wu1|iV4=5kPis|91k3r!V>-F7#pzd+hx*h>Ct&=g*Z80bMqihw#Z#R0m{@Ec4G>uTAScElUGw2<&aho2B z&F5#d9=mz;w&>?i3eO1BfhJI^otKz~XL$|%EKy*l`L{2^f>1!}?^b721K2*B69c zG2X!Uyzpmta=^{e(l3gA#c!9F5Wv45@-O-|zMi%9x$Xo6QHWQ9aKZxZc$vSXa-8pq z2M;Z(SJy(BvU>)0~G$kIHC-)3TYXHuE6DAb@`Vu3DCc~blu)j>@{|K^6H(qX7 zm;N9jUDtVk3}%RiN5SSXV*mEE2(X$*4>lFJx%#d+g>X-NCV^)ZlKkL+PvA#)6Y9A{+m z(@4;r<~)1sy8X^=JZJ!Fps&~eWOahB`JpX0gMcU`#zy(NtEsT&OSeVsFa}6-i5!k4 zBQa+MsWb|6!^m*=93Dcrl+%fQ+-IBf3FMbk?_L(Fkx}-d35#l#UW_Zwrcrv%J&jRu_sK5Mx241}=a$qQ)Pu z&m?gFIOyYx9BHQ;GZn+11~P6&i|_zFLQIB7{Ey`LQwYAIqDWKK6A#-q=LVxJc?+k@ z+LDoA(*nkz(RVPl&P3HJICu~t#W=uz0I)?H-;PR_TnFAJnEuAGyt(Y~3UlVV9pS!~ z-1qVFpBwL=^6^8P(NaD8ra*A!YIYZI_yTL{q%_JCG3|&h4w7}M4N~*`T+!jWovhC* z9tBaN!5pp4?gU#qgOb~T`|?l}ZSdPjIu(zQCpKRV1NNknQY+Q%&Z-u?J?S$#>X z3sx;Fe=;#MUh~!-Gv>A-7o`@LkgHH;NDyCsS~7qRoTUG(;QDu)-Y)kv?ynW!BZxN+ z4B9X7JN4}QQSJgsf&F<_6?DTlFUN10*>CK!d%uM#^7_Pq9?cKkYviw_m?VNlk0(jNnN)gBKXJMsD@1DtX_3E4Rdl>HXYF+I$IFKFRjZO0T`aYX%m?%$F z@Dt=0A*egJmoPux%Aglv?wdVUFlK-*HgTgEcMK1Fqo;+WCHjDGTQZ?w`%Bl<`UBYI zCCMGD5YU)hysu#8hAF@RD|$YQCQjXG#w*iA|067c*e3%7$Y3nY&bx9F%y;25v(V$W zXzT8U(j>6!K%=CKFpWFQxHCcQUE7Hccx0V62Kp9%Nxy6pVi1F;q&)ovo0qIYV)FhR z#Fei`%bo8O^7C}YoMpnUib2nN{?_`Pa32AzGe3GEWN?qqqo?a|-|M`7sNnHDZF|gy zP!1}gcgD{QF6Z;yr?Lf};0C{q<)48dJTNcE*cF&HgbeFa^Iw!K=gg$ zgZEC5$wj|E&FZBUliEg^%J2Pd)Asc5`fOZ7*zdO2ZTb@o|8tf(x7PN?SDR7y5Tz{r zkMh}xKQcqwzKMMY#3t~py=MXVO~JFO!;SC3iB}q(FjLd`JA||2LBl@8tKY5BgnWWR ztbvHb5YrIo@kmd8b`$EmVS<_0onDF|?5s{BTiAUoQ1l$h#AyGTnZpMvKPq2Or&VQ4 z(iv_-!%UkE58!l#L6KC!mVHQC=sR-dT0Ll9H+GL$F~G&1%Amfi_6j!!{Q=zv(;GwO z*E^yRDfXxz*X)C6r6)usPFEL+g|Fc#?Z9^k9eWDy_t-6|SDVSjs|`160CKUV7lM`I zc(Kln*O5zND%^zfS-`7o1WcZ%ulvz=u_AIjN2{cm!r>KD7(7+ zrD!wjj!lBNgkTRRqo#*|<~#l?D1Z68O3Ds4l=}r5ui|b(GZ~;@T=scOR$MM9Z>xE;V|gx)Zu~phrX6I!&p+(!L=hm;-f*K+{a~OhZ0hJ>gr$@NHerV znXSZd*75>Z{FdO--LGkr)MF1#u&3{Nn)JDb^HL9wec_{=`93e_p%Su^`k|BoZzmE` zjQ^C9U{GQC@_0~7o=?zf4pZePwbf8pfIgH^H^a8BxiN zN@AdqLmXzvhYyoF}U1&Mj2I@#lwEU-ArzLJ0;P={7GRm`aS<+CKC*ZD;% zj_P2<*IUaG&3S{x>Wl~7JP6P_AR+Msqb?<$&9Q|4;=lhbX@=r`IzhA94O{qE5_(Yk;b2>h) zRL8MIuONSoLiAhYk0GW~pV&`}FT5cf^5rW;W%GrCcvh94+;aX7Q*(vrdEZ*qAnb;- z0aYcqQ-QazJ(p2B_2dSxELOd5FhSR~8;R2G#S$Q4=a5LslcLb%f!|=PL6@H$8VC$$ z{BVDqPJBug0bWviJdHCwCckAPdc9B+R1WF`=*Ua}*C_5>z>g4T2753C;SeCa<1582Kw zYCYHi^m@C_AEOXm#hlNH@?~Z4vh629I?9jb55Vs@vxAkxg%gibJCr-Nj z4^F3j^nm1Bl1*Sk_Q}EqV3dPKm)|?U5PA69SX}W4h{Xjy-T<8%H*wHkT%GZn51WG? zoZQUpJw$Oshe|Ez%F4Zm;HQj;gE;$24S|fozGR>Rp&uD&Poi*mIRf56Hd(0gH|i-#%5o8mm6 zCn-BLq4U1bQUA-J=P{8y&{kI8(OSB2YR|Nq8frNuHD2DKyjKnKL!X;U94s!x7lq7J z{abJcr=R!Z!51^5FUvb|?&(}3B&1p2J8>H*|0m)|UQjrnrk{vbXnhn~zHkL30TRw& zGfrfsWN7O!Q>%MT#=pi+{*nCUc;N$R042U44Q7aSpE1}-dYZoz+YgB{?Y_n?AqDV) z?-VzVt)po-pa>9!VKlI`SX2kK)i|&JbR`Zl2q1E(hG!T#LD#?fSt|786=T$UirY#N zD+z~Tcl77S9!=534^R7w6aNiww$rDhT0i?^(Fu3&JIkoDYAtm}bZC|ll?SOtlNC2> zpJ63KLG&jv&SG;M$46pmw)KbqHe=#RXOu7OB(B7a)sO6k*L+3xpwrMwV7rd+3@kr9 zhHSW5+7VO;SHbjjs0m=%1pLnzAhGcu<6&V5D)by?l96T(vs2`=8O)c4Mp}|}PNb72 zbctABky7<(mhYo$))D5o;vAYv|Fbxi;dDNt@xclcyoa_tvTsvDMK!1o>T#iSfs=|* zaXpxLfnkZcn~AIh1b;on@0>=>!F&L7d%LISb9lyY7XJWd>c{%uK`tT6Gvr%>fYQzt zWma`?<;YZ#FZwb9IK+ruTrhld$EwybO;YK%LeffoZyM3I^TJ4}Ew`>_@xB{W?cfI@|Rsn{cf!2Vci2fe9kz=DG4{rukX;llf{h z9>)i0ICdn{?3kxSjpFfUnAfhv#W9=l818OswSc|q3Y zg{9Oi*8Qy_z`SpI@m@7Yp{G|yt%Wu%`q zAO(;=31Tyvi3h#$&HSimT4~$J=$iuQsi=ov3=}ba+sSgjL&rqQ2fB?<+T9U?=wIw! z-#W_E@H{8UmQn2`1Dn8J{c@sjYi-6YoKRaC!Mb4+wx__&!67jR-dS2$A|p!#Zyj0; zm(qdCc&=-f{h*N$sO!S_C_3LB0zB;8Ld>#+HahuZ5qJEr18nq5i`az=s3)p0m1{=M z;Y9Itjq)k!b6pd1-&gdfi5x^1dW?vbi~8jR!5jHzY`Jkhw_o=!=4lt{SN*$y23Bi7 z(0Z_uebibC9X7eV=%vgmNs5>fZnwTgu4`jg6435DR$KIf(j<~j$mezbTDSG~0qh?^ z75D8O*nUZO6R~Pxi>=y3s|E>vFTp*-kqPOp0S!MO7uJRiXeQL{H{v?*DGdetfG>{= zTNN3&-=OIUDrm8Nn3*(++XaS7xU|?wL*5SI?79cW7^8zo!mBPRBCLkwaTf1ykRZIT zcM#mq>aRX|ql`nm*ntFG79cuPLIcrTDbPfqCu9QPC(kj8|CNN#eT1c5p1u(0aFR`m zVc{x!hccZy_!PjbY6pw1gK#C-GfGCcx?Nh~xf@mAkyYqOay5?h-+qYq=v3ZAnhCCV z3QEcCMeOZz4l9js;2*~e+!>7rM+Q@g>a3;jW8drTXlSLiP08m?9xqPhj%`#_;7evd z#1y<%i*LUHPS7DWA7!|@x*3M=KJgw&c^9`fCvumR&mtVSZ&e5iopOgo(`B7vDjsh` zm)H^k!Jx#KC(B5mPTz$*%ucJ+ec7s8~hLGVS_DWsc~24AD$f z^#@&Li=5v>Zb}D^!(wr!1yFOxJwBibkkeBqoTgJ20~FN$Gzv3~OiAF^cLh3mHgRESY4JO~U6{^$ubiTW?#s4pYVC zn*Duqobt~hsC~I}_>aR(dehZg;xDvzX}&gu-Fu$ClzmiSOk?WF9PA;e+R^*i;3h6e z>cQInK*8QME_&|eiTf{A$#3EmEhJD?lG-JzZ5PhF@iwCK?oL!j!HB8-)-Cy>0knI9 zlhj}g5QPvRI#uWuxy{_BFfub}u>ydIOd^kfvST>W%mY?}lLLPEsz$38yyf>389if4 zh5$A1w^xx&eN$oml`bFbUhVQ#cHPlBE)`h;R^h!+D`}Zd`f)`rf<_*mdC=xI%G1N1 z@|9Wn?t-*^qy69?0)xxSX;p1bO>Xj+!>cdJL;E&krP6Ktdp)O8>Cx?#8JK$XFY-#7xI!u0f%6 zrYIRjVTfL0mF6GStZ6rhlW8xLcJaK`(Cw-MmFbQSYCEa+DpsHDEH24U8IzoO@#s#Z zsd&k~P)^>2Yh>z29@>HrTl6y@3*mCxM-u<=_E?^MY-J6!?16r_pC_<1iL5{u+qe(* zQ4 zZdtR4j$id=K3BCt8HiEubYDAKikx`-C~T!<>i1!U2<3VBi5^>@pBH&;O%nU$^RzF^ zC^O4^Jp9{E16~^@#SJXmQkGGy!HM@uReWju-8lTp|MNsq{v{gE_7E?A15E7$z;97I z<2S#tx1LLNPTUYQkq;+MoS1AOX=-`I%kOuc^D zuP=~u;whO>1n;04>^rQm0OZik6R+$d|LxICp^pw+88#ai40W;-H@&*JC-Y z;BC60{oC&tn-2*3Zy{hm7@KgX9ZJ!UhifzkUCEl2ym6nqz2G0V9S^X|2(9mq8D`*(b3mcjF@9#W(8G)JS&H8H^|yp5ZeEPsf_ zi1R3tYfI~l_ACN}R?_~RP(bYTjfMtu_@_kLfx7pkUABW6bP#3Mfci}{KC~1|s#9|% zE$XPrC6A)nV}`rAYv!JvGS0dL{Q0E7MLVqK8QPx?6n+{J4IY0`W7jG@u6lK69Xjrm zMNA@Ki%SHU9(?-lHwY_+`n}KpGLD@lE;EdrPl>c;vH2lK=PcnqYX^ahZ|c$-X{dSn z?4@{k6TRi{=Leccb{{(6y&V<5gMQ`tkAHN_jR;p1-KqMpZYP{3Wfw1A+TP z=m6FJro=N|t%f-w`Xje@;jT-=S#Eg=CaUM7#aPlNU^@w44C9NV zmQmt`zAX*?z~pRv!h;A|{=Ljpt8*=$o<#Xz#8mb`(j=%1k@jgVDctnVmN4yeeGV(~ zo@I$%H_Jt@llpHnC>2s*`ubeXcQ>!y%Vvz{u!TP49Xy;fp4{|SMeLc)_E25PqVc0yxCCed4SOc7l@5vXDw z3k76nlb=;i_yFXJAhypf4?ogU5l7isNrEQl*atkc*;*W@JkR4iCN*;AEVHoF_$op1 z@^Q4i@hz4AoU+j*nNU#%XDs|y%rx{mU??h=Oq`4E!Ma#h#SS1EkkQSrEZe1i6GV(z>#bIpOuw=t5jbg%lKA#$`@w5 zH6?m~V9=yfwBZq;Bas|E&<)vR>`9#!NbY#}_22o1*S%Z={m3hOaFtQ;{tnQ^@J#ph zbId*#&YD*VG5JKzeJq^d;YZ%6QYwN_`|SQ_MXSy;V7>1$nL>&7r@&^B4LL3xje7hH zXy(K|DzC;|Vim1Gu%L%9IiuLbLnohO1J9wYrcA~laTmQ2HM!KU?7f8slelBy*vOzqi_qW-tz5dH zd^W+b9G_{CPItp0b5`}-7(vv^W4K+7eY@#R!qs4NY=PH<2*R$Y;O*PR5d>Z^5fncB zPgkzq4+(zFKMvO4`#DhkL+2Esq)QP{9ox3YClm63AQ4vf2yAb5RS`PYn+MM2{%X8Z|@Iy7UYAdk}f1 zr~Vz&vons7Pp`wlj#H0-E_M5@<9*!zY33YER8WAo>^Y%}I2pmFp=Hm@rwFBAju6A( zFnAII?$J}#RrK?_J@omSu9imAzN6`*(9{7x(TOq;kY%P*X}K)b4f~t zWti&h`Qqa!tcaQXK=&fg(>`f_7J{>?aE8`n*(+N={Wq zUKdcd=E-#IiF{4!P&DzJ<_+?4`-+2euK- zY71ib>wki`hzr=o-u#L9y-MnKBB-7m!9#yMEi*hHjNo}o(f|lqb_I{yMh6F-CXx7P z{fy$5N1NV6ti9|~Xr)#Wi*K^`mp{HD%sSw8?d?S>=jLjWhrZ-- zUA1EbjgOtgfttTy{M3~0j2MpMEVPKOQb14V}TGw*=K%tOCeAdycYa`c<;H8p3m+CWEyOL4}Aa73+X$;(*6<4f)RI=wT(XSW>k0=c2{Jp^nH! zr1`0S42mdMe}+~`dqnlQgHW-L7NZ?|&j78>m;nVC0_!DyM8)8W1KzU2{d(o}>VoCqGimAs3wdSJe*Fhp10k3&Gc-Ol@YLqU9p`L}#x3>K>)@CYu{L)opbWJw-gL zAtI;=!+e@#XLm)?8v5`mW>N!1wdly>l|##}5fLcIz+)@GIdtz8E{g&L1ZD zNm~;cip!&rFmVN1^HNDR`2T3CFLK}fSygn8C0~lPxU*gU|2zaQUyhMV>KahMoLD46 z*%~Qc?NH)4dx@ial<7Cx<4g){6+5l~;@WdaoIa|EbLxKpWV$`!eXbK0%Ayo&5fqRdIb8sXoD zsRfs*-Lw*P)CL#f`n;%>P_gbSAy!|gGk#L_$}tYxRSuwXLAITA6p|HG5#`PNeYKZy zT1B1r`lO>V0Y)bnsvP7-|FH8vqs+#kzW?WoJ5D7~%2LYdsoYCx$3%S!k(cwGT}Se^ zC9)j&(lS*a`~P{kI@TN$MCqtdoN&$Wc}IvAVmO?==Vp!~i_i^fO1*9$8xmgXDbiM(dPSKT*Oj3JKj1I!`K)eJdvYE z4GvAp29Fy?KZLZaecDT!B$N!|_2o#PpU$5Y9yav? z6_Lj!r3UxT5%K!j5o!ZWCIMacvkYe=mtE#RE0#C^%pxU*9zM<=(m9p)U_xdgwv0P8{_EbY5 zhN-U7V>!32O6r^fJBBo9n9#MPlj4~qodm?=lk|n24gpG^u)zyDWdk0Mh^TGp-A$(Q zGJ>F25>Z#ZeI2g}**cO;cFgAw|F}O_T>N6|k0B9{yJkzzZBVyvEFyN(+RalAzp(-f z?1Oo8(=d7%;O0=7PXN&dXb|o$AFvn+jybf<0;~Bt=h=G1Y)C70`RC;Mrj-&C0syDT z5XX0?zciiZ{(0K8+>ouVY=c!wzVIyU~t-`7ju=>nBO7izp@lnIY4HqvCVM0`v zUp($2{yVD|=T-6%Kub(H&VbTAbcnL&u29O&txAk+yH4+7d-d`a7EH}dR#QXdLt;~?P%N61SoRwYPMT>Q}u~Bvfk9TNrR2-ID&}v(AFov-U z+G}xu$a;;-B)xdMaA_0B6{HR}5F3YvrXYub^mQo8Htt_;p?{T6?W>tPGu2O($$f)g ziY1|?;e=^a|*`PSD4KEv#`O-|uY7Cwr_Au(Ewt3K3M zMh{?(_?2U8KI}@Ntk~?J7ntD+Og+YHXIs$wI3$fts;?%K+>Xsp*5A70ZTb7S%v+j+ z#RDW}F&$_!mEqw$bx>)QM_`?nmDyhuNkIv?bc~?ELf-aka;g!t4e7cPZD<>9bZ2Fu zNvvVFnAj|6!p9!G@cmkGUk&UD;dgnGAfaO?$s25Dq(U&f`@gIAEyj)iW1R-v0pky{ zZFV@wYsPv^%_Zg;!V9rxY6gPG4^2CLUzJglRe92>=HT;GK58q-&!BF(TZ|ntV=6XP zAHt+)_wNpR(n-3%wfZn^rN*p2$NaE5@vu|>WH-E1G+u>t;g52eK|NxqN{ZluZ~Eqp zcW*_Tq2<#OfW`s|v}p)jGXR|k-XDc!|Jo~hkXgByOqvC*8S$qZnQ#?E(5na)DdUqz zTyXoi%qtiLRJ@QI%C^s-Aj6ogNp1J%U(q8+h>QY=r|~h4Qo&m$fVaLDVks+(eAaKc zYx#aX=o>HBXZ(6}b~ez=sGfp*@ICEkRmxK`tuy=jo~`6v7V_ItL2LRU^j_lI zUx_s%YsbK-NG4RNQe|7?Av2CglSDt(*4f%nT&Q3a6e4k3G{%%IAx>5{h&Rsz;`0`( z5i?;9^{G29*7|LOX{0P$*#5s${htJLE={aK4Zb{*OJe#mRW2&BW{95eTE*o}d^DX`fZXXHC^QREeD6qU6xYiE5jgmqC90|4ttg*Ze zP|?=FfwHV4SNt?>ktM=s+{pu&Iofq8bc0`)$H3wJ3~I?l7QGmd&;{;Wj@stPE>hc- zXj*-y;~mvs2kJEDxo&D&@}y;z_W%B|%h(549w4;v_N7Dw=f-C+{rhp2u!HW)zAQD} zUSeM2^&94UfTJ!h%4>ba;skR{&jh*6#Ppr&WQMxoKr60h{c!|rVXMlVV68)`qIid* z=KU?uWxN|MMFv+XT<^^W!*5-6N%Z}3Di+7R$N6=Oe$FV{aw}Pm;;%t(=-D;i;4StI$?&iOfUSH6W@iVADf6E1WPj;d4|wOr<=p61xa zK&~pfHnJ8j*$vt;CMlG~GZ%Fs_vh{1Rt>JJu}0e5pb-~j{>&3JWEc_=4twEt#AQbe zTIZwLiQY~euyK-9xI)V>q`!MjsG8I71P-_{a@YEzUBJCqcMaW^znMr-%9`y$B7Kuo ze{K6dMGh+i)tw>_+}$u(`au;Heo7gw!p_zW?KQ)|g|pfL!*lpghv9N5kgW^gUOfAE z(}4StyFKJL$7w6y3F7J_gg@Ox2#94sg49uW5Cx1$IB!)~TrQZDuFxhw++$P!Z~6fP z`1i)R+p+A-%AXatUr3mQ1QA9D_{RPT|1KR z>AIWwdDj7KV+}B#fR&!gP$js2wcmvNO&xkd7Q7wrkVb8PZz%YWTbb!4Au>;+M&3No z0FH)xI=mbmS>rd~OX?@Medw_Xcx2U|EL?~(&mrBG>VR;G5ICtDV0!II0O(=6Ad@aPl)Jk+jEt|-y9wa%qsK1-{ zlHjE{;dmP2t2Lpepqts!B$jW4X8U}kOji!CnmmlvkJI!#@wyWQhR2PJ_E5fKW20~I zu(Zo-h|07AE}6Y7W(m|?(tlNP!z|ln%{J3t>5dki)}|tdAlfQ2w4{wt%mXq&$Uf>} zO=AHS)Vspya=%eTrJ7|9_?VcRvj7h#vyP+mYo6u^keS}n;Z~{}Q5Z{$IqYc@fW&ET z`E4R+JAoUCz+%iP74)yc*t@$kjo#VgK-X?$q^^8;tQK$555oKIHw0Be41Hqm1cbWi z-!?QcZ@ix2^Oe>_FCEZrcA;n+*fiZ_z3!75#d^0zbpJBnghDpc%2#n?o`{!iClB3h z;u>zKD17wR8&b0!JYh99x8lKFlBPf`vZ>ELuwL_xfCcCt*fN|Krw};wxMU4jB9$0` zCqZ2z`-6qhs4A+-r7{UT1}#aeU${w(I@>sm^1W^LhBA+CUECS`hV#eJ#y-Vs6F#lC zSJj>(b{5jM7Amv=Eq!fjMLNb^69u&?PYrqet1HCPLby>AbY0FRJ%#bw*zLnQrio4R zQO1~V;oE!?3_1eZe(0_!#z$q5QIIz#e6LoOe?^>=qXmZjwrTnMnMs#cA{jC|;8)&j z=S9)|V(-ZW zoico826};kMHYRzRmz-97hE8K4kZ=B>PN+h?gWaUM<^P_Z&S=laS*(&1?5N484U>d za0)7$GZQ9gc0Zl4r9vC(!5G{^p{?YM*J|l_&EO@^*_JOA59$oqM-YOrp;xBZ{bwaF z_HP({HVL}Ib5dzWDwO#8>@Vy!Bd18Yb&&M)M=ieHt+t!4Cj(WMguwk9 z4ixma@66WkUz8xu6^B@g_gq=Bk_kJ$x&i_F5|eYd4vy_y^4AJ=+@pJ=my za@C&2)CQc8X5HAcOfjqg(~H3Qs68QL)%xVC+0We$q7XLks8QBIO4dqF+S}}ZRquc- z3>h*XU(qVZn^V5sut|U&pSs#&FxGi$rtb~|Q8W66M|`!j@Yl^)b$fH61&dQEK9)bz~Zzr;1o;vF<$uA zD+`aX773ifUg=w~sba+-+5xlRjQ%dM>BFNy!vej8`&7RJcb-wJUC9*XdU<^wNM~Lf zgHod!lt@iKfhn7e%FMjM%x|dB&vBU(1Vc)Ea$C5NhLT`*QY06L3zwb%@dKgu`*Z|^q;{;TG}8O~cV9d6+zqWtmw)5kgACxIj|kC>VrA11`W9useRIb> z;RoW<-2Wfr*o-Us=#MAkO>-x(%xK6FU0HuJ76=+7hdDd2Y2=9}xXs5jARH7#ec!kD zc4E*=rn9u$tm*=`c-H5qr8z?$!&0M}N=Y2~LYbl85e0c`vLiv?*1Damf{wuhRJ8oqb+Qj?&fR>oc_qZ08vm|hgiShuWr`Pm zcmZHDKpW802a5vB&?_oQ4z>hh#~!Pr=L(E+k+SKMNB+Z0+smt_Z#RK6^*4h~`Y@q{ zY$fZCW@-1-<6UKk*Jm@*1>Ug?Q8?x23;grIN8Mz#-LlATNR|n42o~ak#)eAQ=qFXayV29W>Zbuk?zU|h& zDCD}022+(wpjkNI>B{fNb1Sm8jV~H2Y?WbpSFvxoRF-uH2mAh*0RgEQ;}y1E-t0^J zzZ)&N-EU^{;ZKtrBsn$(DQSg?JEne47?v@`Ev{IMm|l(bjeAR3!oXpQHVWAL?Rg>^ zibS`T5*tBTiuT$ab&p}iOK%MNS}6x+ztVb>2vURov+lB|DV(3)+^zU{8_5Ya^|*gL z{r)e=^Y8cXCY>8n52U}#axM5zGHnGfQf(|N=?lBli-IIq`D2ffLhRDt{@v7h z1U)EwLbkx`x4}04>?ts4sNRXb=`(EyZSC(&gYs}lXPQkv5YIjM(IK)jc9yG}x(#ML zP^IOt^&`gm+;63h zPOk@uA(W+7=LHO#h`;4v^^!|D-6F(Ik>-+o+QAh}68tz`dC6#N%KcN39GU2lwG>Qn z#qpI%qwhjlPSotvNSwfaeo(<~uit8nI}K4qL*hw`#F(qU-nb#1Nf&%%^<~wd-7Bt# zq0_qdQvb}v=Yce8U!Ju0gqtyazeGE&-%E|q-d>D9zp}T${Tb>FVNAyN>E**b>;6yu zLkv>-{~^R?TqrMIs%VM=H?pe|20hAfbvtAm>aALHIOj_|x_AaEA$DULo z(0OMFok@itt6WKWg4>b7Mf>rBYsJt*?qXhpbz!ghqdw~7zqy1DO^@L*Sv-YKT~BPk zd3-Z^xerUJd)DCUoVx0B`z#|I-hBTm3Hp=QS0MCk+*j>Q(m$ z-3QR9GP(H|oNs^YzO-L@nRWB*ZIMxYDnUuuY{R~Yy`OCIRZ5_@SmqAA?YuvU zS*(ATtIFOkjPPUFN8&9Op0Q`cig`3I{NNV+2l5u0EgcwAX|lu)*hV%P-Wh{tXI7a9 z-Q1zWDUf5zsdQoa#bK#k#ZOm}OEA+saOTU0fxJM+YcpT$`@@>lQ?lR*>1w;-A+Da2 z`K9sAIMwkZ)LXZ1wvGO7RR~pT^gC462)9LuZlsbtR%{{Ds`dN8Zn0yg?uw|((!&JB zb{(g=+iwQHVdCn)Mj)N$oo$u(XtyFRM}LgklU!&a%MslI5H5_a0a<6W5x>t?ZU{Pp z_pg9Yl#|QeUP|(wYue&rQmQo2;D3S_NL7N5#T$^|3b7D>$sRFcdu9^!M=!J!d4^=z zhE!8$-QDwb3=0&j6dc?Zorvaa;h4{el~yOm>JJY;cr(B$CEG&i1RD6JkQEBDd;MdS zUVOrl;&mYLrmyX%@0)UMrRIGSIYB`GqwwCWzs@x!aWrIcL!j#{_0JH`0R_?aL2Y1- zr43VOZd2ForAtqPP7Q&v9NvzYJ&3lOALtd>LU`lN#N=#cyk>EiNzt`(6~305?}w0d*7JcGkr(XU5V{wqxuMRQ zxr`2;ALdss74?3)bA2FQt);N0N|RnVVf6K66xCBj%H*G}UudoKo_}TyJ|uWaY6s4!@0rqf$`Gp{!7pz~ARfHw*ZXX<9q7PP9v})LWG%0wyoJ1i z-ng{$@Q`?BAJc(b5pa_fLOSK|#MhG`83R7l)#<%Qq{(Hgsz$yI{3QU{W#`c74 z5T3X04h&jUhz}moG)t_4pH?}qrXtr0kd0T*`=jy0DY>ua))F#xa z2QrtNL4gIzkmX~DF**I*1}i>d;@p>Dss8dP*!JCs+}>=1Hq9tw8&`7n_v`(D*ZzPn zvVEfQd690M$$0sG2`7yCH963}*j2-nDgs+kxc@zXl+tj~T95FIB+O|plKveQ&PTica|_}aX&17k5V$p;}DmU%-F9#<9(`JZV_erTNiiFDh9)#5PlO!;5Vae2(aG zZ~i1hk)zU!mL5lv1nXImEfs&DLA@$`w<5~rQ7(85M{@?-=_I+#v&eFvsNYE!xtrOC z9eI@W*~a(Dp^Lc+l{1R*!dHHXj z(-&g;D<6+qaDvxge$Tr-e?Quh%UY9pdyAP}n&yOY=VmZhm@d6g{xV86Z`hfj9|C>3 zkB?sw#L}LKghLt>xNx!C(1x2=R$(0V98Uk21rR~6RK(QQBbthwT`g&4n?&j^O159> zt6oA0z2)$jJb=99tWO~Z7+@8~ilp9C;E7-}E|nsO5JIv6WuvSFf2#T8eVqmJDVg-W zCqak1pA4&pqg42sm9p5qVJujZ!OX3(oAozLZN3)PG5^dF4EKGeN3AwH^3S&XUyMsT zYa5#h1I)#&UJW%PrDZ4*)S0jkorBO)^@R%6 z*xctwK(XfL=*!;&oZyi^W=BrLvD?aKU=9EILWvt~7CIXkz`h&IPfUviEfw0*=wUL+ zO0C}wH=Is?bf5`=kcLb}pDCjZqa4w>o9mA=XGV0;@#RzmdI}l=#Yr;|d7DL>D<50QTyFcL>&)zC^Yua98k+?cO1=O+ZAMK=y^}uQHMN`%2`M zh^(4JJL2lz@INkVxAU$OnK7!>Z+Mp$_7ZwwJ&E!?oPIV!5BWAMCNN&3zpsos;n@zk z%Pvvf)JXc|jlHKUca=@|#~g{ACoxmuw0K_T3}q>?$K$c|Nv*GoZd6}UugI5;>uP#= z*OUU`Efp~mL>KXa8{Kn0f)&Dv3tEssCv986o~6upK>nw0LfrvX3>uzbPt%LMkB*d$ zs-lT_-|6xBJs3b_Uk&V&BWgj-(_)sDxo$~nNia}7e&Lr*bOj5Wn5SV85MP)GZ zU*h)VK((ED#SmoL9!rrvuGcX304(&KmUX!ygkE%#^H)cf=epHRu;i*K;@ z0TH@4jKpW%1*7Y7onYW1*FtCsNT19bQf*3gq!Y_3?e1Iy)i{wfOPkTNFDR6 znXr9#Z8bG9-KZKJYgxW#dZx}_)pBtCA$M;yO*m&#iXi%(`1L~Ya28s+iR@}JTazOy zT|w7VnQKKfSQ$Up@T7d)QiN)Oi#)aU+)-ob{>suETIW>eY|E@eV_APOKz$PW3hipA z9WOW ziF|yd-Q<4I;6x+!Mulqn8*@n(V%;GrjSFtHT^R9(RbK3!C@F{7`$Pm^SizNj)@u1# zh?&wK1qqf^4mEKlXeVQ}Gg}>VX#}hVG?UqLI70cWMVs^(%H!;_{ryr5 zMDM)R2+lYBJH<($FE70c3ZrHiqF{6&+cGp!fV0MY#aAJ_XYr^`L>TUu07!?LK3-?} z(75EKyan9c1a^M?eNpJAR7uXLFJ#pMzIdTr)_6wVC61W8p47aif8VS0v{{LwD>ZmB&FIwqt6%k=TKuTJX9#TpeLPbOb1Zl)16nN?G6cL7!lx`7*PL-5Y zx3IcsxCG1=ZYPHzZoixN zE~(#|Vw;}XB~QDxKlAWT$wFk4=+uv=wmwsHDFYDw5mMel4P2AE7w|6;^nX7bx!k?> zrw)-c;so$Ba7smW!<9p+YwSfsJh4$|k5$bpBz2k9;MO7r#XX9of2}HFsG~a6N$$KU zslNr&6cKg``D)en$&zg#G!d>)lfFKjzEsghCUZWbkb=6tJ5`zdooD_5jrLruB*mTj zg;;;yW1|QKV!^u*XakU$IEEdvf6^3$+(uik_=$&v(hnm)EkpFPfVOKW%aa>BNVD?< zELl4}#wOsritv;ll8PeyPn)?3*Q<`6Ta*L>$udwT>y^+G$YLCNjW2jO3rj-fJm*#% zyD9XBhBqR5bWrtfgwNAgjHQgu*vlQc)51!uh~$AE+H{VQU!Ty&RDbOBNqu%n;mDRl z@O$hH)9VUi_GPrd8d^j4*_y5VJ>GylOAiaNW!?S8#`IAjn_mYxHvQ=ziupdd9}j1K zj)GJ$B<(0KdtqDh?2t(^yAZyI~xHqQf zbstWFeq)vA^m!B2rX2ggt)i$yi*;#Jt%6IB%+9+rc_?{+XTMB}U2bq|QX2btsfS#q z!$dB%GtL@)+AdC+`uZgDqvm-!*I>)b8@cbwIo)!6u(1}Pg+g=u+wjJFtr4<9Td-Sh zpasYCMT(IWH6nAW=uc4G>h-iiNVrkqA}`Ir)E}l=XYeAqo+xp%vX&}ryQJrEl)NrWT;8-yQd4z?xroI>9=msL z?88qI)7P;}P7)eZua}SvIyP!heC&5z>o?9Gr!)8$9O}%J#udKVrpAVxmsPTdn+E}> zna#MZRm6$z3z*_-&z4P=ra>1Uft4H-JeZ^nRNIfa*o|<7CfUy|*onP;vc1Pup<3=A zpfpb}DT2N2ptBe4don~Dx0{ScO0(tL;+(c>8iZk*t|PSSQT4szaCyGUfcMu!-6i1C zTPj)qp@?xVyyC5)U-4yT=P6D85#RB1a*r)!u_TXN-T0o3Dbv0{Bl-L67E`ews$}ShprII%F+-o&ibD)qz|^nH~R^q_Ihg z(U5Y^%?Bf7 zja<(Rf`COE&j#|6lVsRuQ5HDvvr4ed^QGOpKKgi1e|xv&GaK%&rF*WEf1^)P4x}y; zuIT5XM}VR`ymJ=u}qTeEq7HLG!MT{tA4m}71<*RJ+nw{tJEB0kfs>NFf zVY#bLx9%?mEnl*39$swGqB1QA|0znZ_3h~r2-ThOUhqnP-i}Qf6ij(ayG=)_DMA`H zjh35Ll!yfHN*Y;AmzV#uK6`rd^e<|+a`zqg?#|a-Wv7@-Rrg zSg_ESQ1+=Jz$<`HwWia7SB>8Iu{>iB2fxao3!u2Z|NCMt4b)1k_+2LZ@<&qRcAAhE z_JUev#cS|bugLHrwRg`vkG#}BvU}VxhnC^d(IswGQ80p;@C%Ma!F^!Quh}SX^fOw3Ci>N1mX19o87(P6b zU1G6k6mGGF2-E|G>h+N7572PWm-|aUN?|#a?M`IyUOJ1~CrrC1)xk`X_Mazt#3yt! zEu{<=SGjWQsfF$xokhNWCS;vRaq)JUf$y@@kLru$ko}$T)}qjivm_S;{NzpRc2RkB z1d;;iFEPMw1|kOjJ=9j(7rP75+8qAN-%+VjBzEq7Iz;uMU9@Do%65hU`ha&Qp7_Rh zUbHc^Z8aC9*9&9DJ6?rL>Ko(b8M{`rRoxZ73LTJ-Zk&2gOMbsWK^4IaD<7Xd_3j8< zmUlVKRLf+X|0&~FM6_vrpSQyUKiQwETD0|4+T*}}yEy>XiBm2ytu;W3dm}3ruqF!p z=}gpw6i21G@q6x1F15W?hbM+J^uac{5E+5#jZM?v-8;Lh+u9sZllO$YMDG?|^u@e!bi(KNUzy;iBAA4~Bgd%LDUZfB?#9Ol;cD{d z)||4+!i4*EV(Qgbs%P*=pnA+Qc%OmI6zt7yN?Il&`?;0upqK;SV zdPw-Equd;E5aE4pZ?&F_x*-sBmjk1o;%?)#Q317i8M z;R`vxe1$uNpIOuMZxE`kEEEeN-Voy=tlCmpPo(-R0wsY_&6q3e2}*2@B>>|yvsEdxqOTy#A^ucY$ba>NX^IC6MtX^otuhpZhFl0`(FVKleKF`N|U+7avMO>4aS|Bc0 z33$E@H_!cBjSLH&!_P2d!eO`I~C`RPSckSsB{E`!E*u&n=^MnU7I|f zf3$qo(f_bp9#_9)9}ID+t&1q{0#AiWQ5BWCnEM@_m(kv6QR*c{OxJ|RKy#9D#uCtn z^slwXo*^5aw&^%DjCDczo+FEd#i`hY$H>bM z@y|nz32?ee_hDYYA?E$Rp8ai`npvSbv|Tp1T)vuD0gK0TZ>Od#41vpYOcC8BB7Uc0XIL%bCHGU+Hzt$g(7UVWP7yWF=Kx`W z4_khGBd_s`iShKZ_E8ez)Bp`^dGiWz7pHrkLVuSSb1IDOIo&`x3>Of;=yq3KfVhbX zBCJG!mC}Goho+W;=sAr+tvymL70F56W zA-4VeDD#u^+9Pfrls-bQT0Q&k>)q`Au8}aftD6A5O;t?-x-h4L zeqK+jJ5}|4{>qq&aQ=MSeY0mkqdnQP-&SutR%GhX{F@`&qS4ma+>=Pt{@IeT{<)n8 zRWol83(rWJ7Qz%~FRPjSx<=xX)Kdi^2AlT-#(gW@+nY~9a!%=C$X{sq^9{%< zLCurmZbEhGbo<0FXwGIPeL8)9>Q4GR+P-f-Y2t>JHL|^NZ_H`0K^c9KdUQAy)x_)n ztH>HJ>2^hJMiPI@>G3xvX757I)hqrx82Oibv{tw9c5Z!zxO%w16s;zHB$MeXbum_Od>H^`J5-#Cq%l1f*=4B@3W=|Ui z>>8?^c|QC`k}wz8WP1)|O4* zQC#8XL@+HOmQxb-D?fG7EDQJz!PYa)9u;AvD8G|Ll!ZVckcuh+#z1X6HxY4+Qd{iq zV123~BU`Zk?>0Dg;ezwBHIH3lCl@`D!i8$@s)lryaBPZs7Uu(>FS&8PtlWe!GoSuj z^RB_F{AB)b*$zKerb}CPXc#J^+w`lrA1__euimOvc{>=K;P=8v#Ai6+U^1cv?nRN~ zM;pWPqkX%t{H6b;L!cszR>pe2F#&b8Kb|-kUZutktff*w&$f}A?bMMw52L|B?bP>H zH^9xXgUH02Y-%&=Vp}{L`vbr%b}?)l?lZ$S)oS5MC-rXng!h!DOWt87X}h(9}M43mO8NU0I!@aVY3I_e#+cc0$c zJ>eu7JPRx~Fi7HIJ_%{<0%MuLvK8*sH?1WidON@IT5@4++y%YKzsUzeOXLshxoHl0jZB!g+Fdo!Zq~hwM zOg_es$8UTV-U~gmE~Lu%!lD|-`)2E2&NoPko7h0zE#J}-OOg&Es+pH48i)A&1>yCy z_t=jg9*?8~m+!44RF**b)GzreTUL;@WAFiZr5=4YY-+TrU!d&AprGz8E_SgD zaWRfN(sEpkB)T?Y&DV71fMmgFybG6WyGCRg9vZDv6@!7P@%^%p-$0S`G?F#h%6RR<0m&)E-LiJ zqI5Z3k$&Zmw@Q2bK=HqSP0Q$2>*pL=XGR^~@Z3+^Uy^MJiQcDuY>fRnFkZGy^YjuW z^4)CMDBXqgF%Rz@tw}%fU)-KM;qCNkhhIv~LvZkbMOL%1bzVFZ0QN&QYnIBfa!MnDu&s!8c z4!}=P`bhmGHUtoHEDg)Lu}vX9665g|ZhK3eMCKIy1+@tf6&x0Cu@Qu^U)8yfpu_^Go6RVG?L zTr?`o{6JOce&F@Gzk+EzddRxuZ-wE85eYkAW{|gDda2DQ<~Xh->@v^8ZEuYCW3w0$ z2`IB4QgGrI7~i)wse#HWv)SqPV>W$$eDcDhsg(H`IE3;9W4n-*Lv`-wZWI9(m;`j^ z%}05c2~tgDBN#+NEiTni3RhT0^sszq^-ucwq{UsxVQ)Y|mK?O& zFXQ=#b-oZ!zj4&%WCYdFBVxivie@!$5Uf1g7!WFdJdQR{MRz#}o?YJj?Qf1OWJ!7J z=GfxpI_1HKiiC1?z(lwcb%T(AcGCjdl|ykB;y7LG^E_Z;Ii%5d!fd|QS8*;SE!A=- zZRX~a=kxG5e|4y@P1)n`r)g3M+ue5tzab*tJ2zXW@p-qIvJamc*r1upRO=p4`$H-nqGCD(zP{04EkskK^pW7xt5~z1X=FKiyEhBg_A>-VaZ`Snf zw~``!yCazA<1g)w{@N|=jc{EChIAJ_-ZA<7y_gd~vedlLP2sMCgMyFY`#{zbmJ8Th zsH1_k{dM6Gj<2KkOU-IGM409~H=v~q3FfTerDKRKz;drj5cTZPMhK)45XDOwF)Qy} zYoOQd-4@A+M)~GTm_r{g`?1=`m}r-Nje&27S!Q0*Wxe}gi9*trUd>z88ce}hM2qv$ ztaI6#>nRLzFiAnj!F zEg+wmRAKa?_rH?24T2fQrc+;Hwo!|Mv>rNN7dNm{GT9v|FP>s9vgmoT0bZJfEZ2+B zvcC|&&-Gq)k&_Tgij&krO4!XUW9IdwZwhvFrk`jWu{yF?TTz=49p0xcNq#DF1<7-E zhRlpK@`FXm;g-Qsksx;L(uh6P)HA!BqYi`Ru9W%_D(JEblU)<0U~+p}wr0l#+r0H7 zQ+W2tO=Cec6*pS(kpX(dSxwlFQ$Z??A>gji#n-s<-Orpi49I|IDGX{do(#|*bPz>G z)_uhkuR8;8z(xmE1y+cr-< zms~7>% zeE0`UR^kU9cpWvhJF=+ZD02w2FYsf?b|&K2nla9fvM%6+#=ks>Fl=)dD@n?4m;WRx#&T!IY&*$M_c3IqH2C)N1M(Gv5nCOE1@$DwKDIEYX|u!R<9fq`D{8hP zUHf;z5ygv9+79wUIkzbU z0fwCLk4?5o{%4D*PRO2%=;=%S6 zqG32P3)DG+cS*%V8peej8oANqD3fB5bHhT;o1O@0ZXF1PUCij|ap6BiUi^BIILksj zoIx3Mdyar<7l57teR;w_fyY|OAogF6uTR*dt=~($#0Lxus)UPp<}v4*Kst`VCL;4e@s?J~5o$%ZmW!{@(nAW&E8m2ByxM-n*+5J@sq)4iAB7Bc)qBeil3lzg5 zUQEx%EP^fje;c*b#=Lu26{zaxP5^z4he^cT@g>d8e~@BZR%^C z;X*);H9k+=V=IyWp^c4`l*-x7oE}WE?+_VE0vdTyw1OPne7y==ZdK8SwEjAC0qGAw zcI(t@=CdW?b{b@x2Kq~@Vo{|H)wx|?w@wJGzd~e%5el>vaiW^-W#@dl(Ka&JJwbii z3;NSnqDkX)oE9l|}W8hQw&| z+qT#pF1=k9T1US6=6N#=#xirAn9W>h^9w6H1alDDv8jhkQond>tCCMlTNZHz1!QhV z5viC8h(?j)QF~Hh%2?fACF@x*@1PW8qv^^UWpgJH{wXhb)n=uFX@D~XzMJdUMo#%~ zEj&tKC`|s|E$M{C0!Q}E)GP7Z)~0r^`N*~|-B&Mu-_I!~<4_>OU+2f+s;6F-f2Y3K zR?uNHaO9JI#>}%;wB<*SdrXAaWA)_rtnjsbd8JL5JN8L1M45<(WX{e1w2*>e+21 zo&&3djGRrFzS~A9X!W3KCng>OWR5M%cec{-rt zDwOQ{LfIf>Fpd(ySV-(63ISz|O%TrF5@`OaRM#$e0gn68BRv+aQs%?4VtLtA=2Cyy zF+xW*YCFjbUkwSyL;&5RSn&R=zF zdJ|qtAU_Vkk6LQTS$MdhFnLNCSaluay#@q;x;SA?My`ZI&XbX!k1hLQ{{c+%;q&6x zL&$6GSwCKELTty)3vZZ1ymAB2z0<`7K|8*%)19nNMy0D%k67s|c*PKQ86Dpc8x1TH z&3bvFbODJJHUwjq$0n5AG~y1_yE1ppEm3Cefz^yhN1aX)_ovITYK%7~d z1v#t`H;ikSfxRLY+vQ~~SN4jMn|6O+D_@4ma`^Dhy(U-udJ*Ki4k>iJa-Vc~UmZT2 zk3lRI2V3$G_U3XxO?vL$SyCUjREcl!4F#fK!j2SL?3rqZjUo#y8 zi`8)oo#%5voPnf}gUwAlqo6q!_YO3FquW09{5SUop1Y4-z+wf$$qpGm6+{#K?VEaX z=V*^kSEoS2_)oM*+wWk=Ws57NLGNoiK?mzXuMKKR(Kor#C8GLn^U0Is>^Ag-ly)MA-JIW=SIJKB6A(yT_t6tNqFW5ezWO-p7$FA>J`u zT4xCt9Y=O0dV{yuHV9DXVPq5f>nOFFJN}!Vi@H_;g3OUydK5h!;HgPE|Eq0dF^l75xf7kf6pk z^Z9xH?501hx$T##=ba;jK8hPu#5l1z6fI4E0@>PQB4^0^O#by0ydH*U{;Op>hpnTo z;ZUzd(s6~ibH8f@E||Ihs?N?*U>$$ zJrFIas0c4|b(q=6o+By+W*@L{{g|fSf2Q=Sj-*r4+9;Jx_%>?HnJTnkRT=d}P&~Tw zs-JGbn{zmOc4$|+KC}f0z7{mPy`Mn&l=0QMlknRRYul9X3~AQ~q(}VhrP`Xtpg?Aq zu0WNjzz?rC$5FBWlKRJ$kMHatA8oNSb!kHf&lr{NKL^E!NMOPCQ`t5&bvLUOMsKnL_-S_~Q+7X~bRS%U?-VUG z3^__`^|&$19+R;~@=51s$^tBm^UJL}v7cfkAAH z@UzdKMDBvJCsJL-f8L0jfdWJw88gXw@V*WtKx}0rhAbz0`@Y47Y-U*Y#I`ZP<|P zf&>2BV&rB?@r`8MKsmi%mlo=GmRBF_K^kyc`UGRsVR};#UseJAy`V;9R|5@cNw|{iOnS z3hn+X&ZiB>8u%F|*bjAbs?lEwn2HG4a=%2UHfIMvcR)wiyz`jE2IU4NHlT?yLUBNp z95}rmw8)0r3`2aPr9=b@EC~g@l_!#H5${twlTM+Ek;s92Eq%X`UaqbFuAobjGW?bu9`t`19b*GJVaz$8y8 zPqyN1qsM(6OvMC!{LAbun*mMP6U4WH$F9PnvGR$+s*dmKS24mzV1y9!9l^(_Xev9>n$!EvXoIulfnuaB4yN&LRRHDnlFazXM@Q4uJ72p>X;x5NnU zH}o_#pJycR{|{V)OSD(y#;mnT=AWlD-yQGq)f{-8j;!C&lhJw?rnVxws!woPGa(1B zGVnbubFz22V8Cp0CEqlv`h9sxxjroQNVoV^ll*vQRZt|oY{|sD4Oj7b5p%(l=DyAA znyjCb;wB24$yFMLsCm>3-yiV@I;L`}vHmQ_0z9F-&45y>!dvp6*wO67;~k@CL&IxajC*Kd+nH3Eyb+$o1cvjI}&g z#CF2jJ}t4EA;J*>f`^YeNJyMCvm>9}?HS_#v? zf6tZ{-)msgWo}y5qAoDV{(F0qj7{bZVfeE4%(H%ATy?7Q2UaQ`HGUen7k3Cdfj84k zLnVNQI0^fD1a{tZ1nb()n@9+lXtXl+j5tCke6NXQhrLG%>ul=lYpcC4v56wO^~5?U ze;_1bttHeuR-AX&VU8V&GJ#^tiMT6*C4E7ZQT@_9G;Uqd2?8->^e{JODW}Va?xwx>gS}8nQRV<2gB1o+LUol9!qAB+S4F|usM|G8hji+M7k7Sdo2DB>ilsyaThL< ztv$=(;LDanr*V@7{}oTudrjrB*D$)1B--B;dV*ke3eR1z_wN&!WLbZ|R&it!E7tol zP;nfdYX9Wdtp^OZ+g>$x$E8^#8)iC#qv5kx>wNe34QhtzY{)#Pup#?r4xn;PwoVY0 zgVygAlrbYLS;L@N<%m`+Nt@N8b#3KnPuzy^Iqr(upT-ySFRYsWRg?BQXFua%zge4X zp@}Gr@IPFdKY{MCS-<{5BwUZR&&CuIWJ`{|b_Bn~1>8N4AvKXwIN)lw=~6KTHLpm& zxf)$(C*`Y2UZ3mw`z05Q{a0s*^fgs1j)oE?^QyOtsAKXU`){lku_;*>z6F~QQhnl_GGirnwk0x$8X z)1oyWK7TVE7 zo}YhBg;vwD3>ezlGijww=8)G$Gl!k^!)Fn60=HxQJIohw@(M9663<7y1svE z7%N*Q%G2Ja=K((ocJjV{3JLJ#sT#O1K_&tocikM$OG4G^$1!L>Uvi3rD$kyXSZZl_kK>>gdv%adXFdVz_xO%jaR1s2^FpOV_N;N#2ed5K@h91 z2+igdO*EI|_2>eDglX9%+Stit^?PFsL$bCQTH_GLwi_CPZxwDX#`arKmGWV?*mPy6 zI-nn$ATxTl_^HpKT@sEx{H~}2$^oDzYA%o0w78kK%0;dtFLF+z7Z5^Iz zn7p4gPgtm=|RjBC?AM(8v*TJM)}~6vSBL?m*{vn z+&b{;OI&;0^YvAO2%CoxH|gPmiF8O{jvmATbIGV&`DE|6GCWX3Bv~izNen_jzt5?i9iIgoN#^5Xh@Ep(7C8YHbYyu)vRH!XC)^a(W5H3uDpTlL)=O@F9=t1Ir{jXWS zx~Mp+HyyYU@1m@4FL69Vq{CO98WLJX{5Xx6le7LKagsOpmA!ZL&b?Iw6YFxr@dHoeu^W+eIh0);6)O)0bB0B}ktD24$yhKT zvdxT~>y3j~C^+fvmf0!|n27Ho5A|jo*vMTxI(2!R?uqn=n>5*@-z-&mjlIsLuzSg& zIvK*gl(OXBpLK`{mVDj8^773X90nF;B60l!#E>7PW}0el z3Vw%ie}2&q2Ro6f0sbNKN%D+4bBoS^Ihlp>Y11gS$#Bl5?=wA#WB+!qP>AA+(4fdF z=FXdQ>EwAcYrYT+30mGa6W|B?!upXpUq7l*rCc)o7-vDR_UVNp7h3Y^pQZX7Qs8YA*- z`gH$vW5vP)5U^+IH^ns3T>j*#_OH-I{`Ij>p>)3dJPJU1JVH%9ta^0W;N35*R+VgE z%7pkwmD4j_C57Kof--I+t@&HmTLi9tt{<~6zLsQrYUTSUqLYH<&-gIakM7&wkvse& zgFUi&(i4xU6SQ{I=tZ%6G{XwZzggY#s;NUrv%}_YCu_ot7tK=LrG}&+c-3!-cX86R zq5en5W=r^&@rFXK^b5)T>|4mL#d(9}1MBWD6QoulgG=o^T;Hnh(Zm;P6chox@>#A zG-+OOdHU%aX&AN81XR`HjyuUIW%T=sR?1hCOM>0hr?BFO$omX91ihCr znBvXz38FpBC-b|mOY(K>H&3^Df02aVZGzRaE|}HlK=zNhHc|P6cfNS#*FSuA=SLAo zsN!t@N+!BR9a{22iln!YAC9Vm0si$Ba%e#8~oNC|&XjPhaP1oa@S6dQK zML!=uRkHIs+iN@R+l@)w@%7^=Tx4^Q_vqU`{dHz-bgT5{a^#!Th30@bRRyO;k0(u) z=6$GzSu_)^;uDb%Ja@Uf5CzO)a4qV^)SSZOu4j}(Tg-k6)3MJKgt%0ro~KU#xcC(z zn#lP4@>t}1q+{bBbICDPwH3U$_FKl%roK@LC3`5`+B+x;LK)?>Ju z9la+FG86#ObJ}nQ==6N?YCsL?nknZ45?hPfU&{GOk|EhK_)J&uo=rH3mdl6&H3S5R z^Cu9Ak|VBmm~~p!!?Wi>k#FXq@pXd#x{`vtm-t!elzoe^NEiBrS6y*=(jON>qd^Y^ zgdtUao+>=|c1{VcRV5!GM-mWbmX|hzqTQBK zlaqY$gP9t(1?_}1b9Pu>G{tH+kknl?i|`)uZ-q)vuMpoX!)ExWu&yauLZXMAo?=PR zU*2{>y8FWdkRpbLqJ*LBaU>zHI+k-MEsQi&JlSS(90pDMuM^7=0ISV$F*E7O!0D1y zJS@+1%kehtHsPk+?vFW`K0gcS*;mkEzs#<1<3e&2(L9Qk)L@1^f~~ipbEg|t9>3zd zdSWl@v+|Lgn_*Y5AV6o?dj(sZij_)CEWD`)UJ&S8lw95KMJ4+x_(`fo0$tP+Xip$>VeVjlvv@D8o$iw z@r2?fEz6X_4`ujQ!p2Q3wlb?3@bdtp6DS+j9Nu=Zf!S7OZ9QYta<#p!-6wc$f4*s! zU5%(7Y8qb?iR8G`y_PArq?JpH&kPA zVK6n|R^G!IyJM1E5|1{&au<7bx=8}^-A2BwF~Qa4u^*GzDWA=1APMZ<{(thU4)gRu zNC(fc&*GrIa$k>-HUf%)PVRvK_1n&AnbG2D!)GdOnjyZ79im-7%zblYvtuqPJWxYm ztAbs%Ub9^IG|D8Zg2hs-W2;X8OxJeScAQn_dXS3*5ISAyjAr2dnNgai#Er_o*gG)4 zTXR!bVJW|{41aqBeW1+>w!FAgSTRiQxy*oQRRmgKQqQXW*}Gid>rfDzNRM68Os6X4 zmuIU8@@N95cRs<~xBzT&BZ2LZkEDpW|9*5rR!;OB@{LqiMB(4Rvz7Z+9{r6T;Fybg z7%g?g{IId|5qYmIhcM4-lqKjrfjdbC0-S85t?R}mP)kFW!q>vCIcZH`8SHG=bgw7CjxdG>in2d6Z_q}WJl0J! zQT+Yz)k08J5WU=NA~SD~@0k432bTwKob5`{`Rk!0jgOa*ZwC@2&{gz)#Wu#cCW^%m zdndheweeBkh9!ErJilBdX?Cu^Qag9c05zV!EukW{pEV-mFo(!P&OJV7jiA81w{4ZV z#5f!Y;YM0bqS#kP;`?B##*p9AN(j$AoSXWE>&t{DR@z4?p0Xi$rB&N z>SunU-JER_{R$#EsJfr_J_#_M12F zT_!Fmv5S>qS6N1C=26~tsvz3GWdC6fg1J5#y5D+uyxA2vf;z1YlWL3Xr9su?89^cK zY*K^NBNV)|M7j5*@QrFx{=;ML%P*ew>BfV5@kC3NLS5a$vV4hr}-ZQNymuh>Z zbz_INW2oQdaeco;fBuy}IdtgTu~*`k(@{0LuESCZ7Q*?F4Tr)MekKm)4r}L2WogG{ z1wlqzTD3p3oAhWKI#6BcQfZHI6c2Xi1KaTk$?~B}nivu$Y6&R~L9~neag-=ZJmXa>GVQ8_67h@{s)WgcFNxW8WDb{F^$fcEJ^i05wi?! zH|VA(FH9#8RuLCDfTJOsH6Rr#fo@L#+n)c4JR=R?mN*i4_JJYr&hak7)fqguEdZ+W zda=TPZv8x9dU=FRaXKd+6rK1y;5g0_x(L)NG^reo&=G<+QNJ??XetIYH|`E4_9rM2 zt+`Yn$NM^$Z1R^P#JhB~O`DzX01s%+3e3Kj?^&_RBH5k@Hb%9ZKf8TW`k9Han8bU7+M3JmA zPktQdZ#zsdH9y8Mt&Eg?SsLMG7u?NI2mA?AlhZhpt(ZGoM0X>gON<3N>Jsk$&8ac6 z0*r(mT-$EJ?#3HNe)vxl+p>qc(G!h^s}6#USEM_PKfV9V#I4jr&A8{O+;~u5oP#Uy z`*_W)6BPb$?)~3@a{_}!3C}J*Sw%j>Bw&yUpOxZ>MtwGs`Ult(f3M>)-C3?Wjx0;~g-|P%?EKCV+;!rDC8Vza}(iZhA0u#Nu9ijEsH3|3Z{=_BGRU^%f%Pb&SS#}z$?o0`|+P>-ZtXigq| zKGkKiwecq!0vR#>19zam&p?V*-*-=lBdSo&65>blxlO*LieWCmfORj93{q4Qy9-r{?*wC~13gLHVI+_Dv!bqGof0xn!8J+o5fjIlfcex;fG#a2; zM>=^708eodWh&K->*=^@HE39yG!jV_>Z(#8>c5!%(*xecojIT5XZovZ+^PbaexH># zkuqmy|5<<7t5`4J_kI-kQb3)!N4l@4!U<3eZo1$E5g?C)yOK3t0aC94X;+~y4pn!L z5B{Oq+=*{bRg+)DTc{mHaqmfigps}Pb;eD)0r(FIy|)}G_`7_H$}ryE#cI8`Z_amI4VP$CYvmGSr`Wadx9C^apr;A2ZvMcj?@AB5)J51%l zemvS)A5P@XNz)^|)7@B{dFv`}1g5mSz1L20=fHRTYl75wNS` z;CC!NIw*AhvH_f5V7SZ|$@uTjg+6Vi+?x*-^%JSxv(AiK)c9yzI=LRj#R}u@H&!UGlHzn;zQXePe3OT|=lE%{@(QvM<-#@i92iLd7l)cRX?k8iTtP&9z{320 zT>P;4p|XJ!L>K<_PfDQ^!lJ~6flts+uTx98JsjL0CE>IE4nH>yb~n2Jy?$OC7e`1q zT+AVu->Y3s$R~O-t;3^|@`>U`xUxDu z`_-~|rU1d`$O_)PAinlX@j<)TX;bS2JZe+lW~liiS<#aADSQPnBr-FY14JE8zXwC! zU)_Wqj=(SRKsx^sN_Kdy?Dg~+fY$}$l=K;UYK4glWfmoLO?4;(DD;Ni? z>3xiscjJdL(c6n#D>EY#ztn8Nf4!T?hfZ}E&WBtizZAtyeqNcZ;X^V2$@C_+#cBSJ zvd$1IB zu{PArlFYfBGM@y74J@Js`e&kwKRdSV;-jAt27Yw}g?LC`7Py$irzB#J10G>J2?F=%+NlUCk0|3*kbN;0A>*HqH{W0+)d3VI7ZswgAk3z03-twrJcsvAC zR>v*~|118b(kh?M;^|?wZ8W)GJkv__=AF4S$ zKM;&}aRaT>MhzPJfKT^mM&GN+ujxgl`SeiezM{!?q8@dk1D*)7NjzCil}{DbmV1s! z(>&yZXQIy-*yi#?%=f343%tvuBw3AX&=gv^r5Ig@hk znHA)X$22tG-PUM_&VEB&aW51?Qj|2u{d@nDw|s1+QeI1|_<5^8CdJ;Ze_TN2<#)Q7 zI{T*bhiyy_OH;vkl&9eg+D}_M3X;Psq>~1_omYbZq?GcK6-uqZCYo|T> zlJs^t#X~g%GPwrjKLKRl0zw(kO(=gEYHA|$tOD!%X#{?gy(FynB*YK!se@Mu`xm25 z-}wGblT%Poa50L=ck0UP(l*|)%&k%RG4z@KE1<#@Xh2FjMr>m~p+=YCOEc~>q=Wo# zx8cob0;qaDNu~=iXxqx-qR@!kam$?EaI_Xt{iyEv#dd=J7(L{kVxVPbWa5>pv&?$3 zhz0c2Z?XMtx=-L+raw&G!-ecM9a-;HzRmoBeJg@_2xZ(_PK*hl&a0tP$Z3z1e8z08(@}WZ zAiqXbMowP*!duQFG4?d4@QB$vxpy+&?=zyuS1QDh(_)CLZ;??N#?UQ1T%|HnoYlXn zy}mwk49ne@hbkN-_OPe$s^#csn--Ndq+uj%D7@IvO?zTS^qBuLH2**eZKq>9c1Z~_ z>2&8SJLvEOlJAFjiJ6ArDYo_}H2V5Fjr@>>BvI%mw&g+SI}nZrSa9K{Azw52DDLkV z9yV|tPrz*A{T+1>*^h8lrxzCNc$2z}9bwG5@DO@Q6@+-zKkC#bnt~OLVE7~dy*q+I z*ARi**-(aZgE{Gg_;eBEdMB%xuW_yR{ z@8;DtuS6-%FB(PcVUIJes*!HdY`$fk917xy6-%)RvlZqtG&g=(ZT??d_Y*G8G%43% z7D8{WcLzf#BO=|+5V#~ZhUM-<@JRFnIuzvW^U3)KY8FbVeIo+CZJ_I1{0>q{`JrCN z)sK}s_R(xY&s+Q=y280gowLu~PH2;smQvf1Sc)8$qWN^p>##l!7q=s+<)(n$Z#K@q zJUFDbeC=FGI7o5p+EqO;j-ubozmDANKhUg-iWuwX4Gd)tF7xp}HE}EH8`MDs5 z>3k>&Z%@`O|6_7EQLdj3)F}S}W|lG6wlM?uT8Sn51dF$Li9t_eFY@Yt{SJcpZ=`Z} zM)>`{eG5}uGxojOnz?M#yhI&vv7@HE2b%)I(gMUs0pbBCQ3si~Y^(gx$e(WFJBCj5 z(iL%r)?d*-1`oe;Crx+1c;?nyWsAq^Ko_E(WtQYS4nB#s$EoNPvZ-h}wT;XJ9Fc!K{@SDtr5H>}V>jV@mD# zk&8iH?&?=IQ!531Cvgty^(#N6+x_2M%@k;j(8GNR%uC=;)uck^(?YH-@D10_RG|q%*pZu45cofbu?`#oFwD-?krdsfstaqPs zO-t0Cmqe)k9BNu%J{fF5Hbe`5Ie!~$*hf-M*lVz)u?E-K$#<@ZbGxq&KDr)Nsst?pP+CHlY}?tR?b^D~7QY>LLB7Xm;^EQc^iPkea_B&z-gkTV zbw3WCQ2)f8x>zhO7&w${#Q$86to*iAXWX@QJDDla*fG&n@v3QT4) z*w)Dz+ps^`CzrT<)b=RlC1ftYd%&grJrNRqvnM-O!1`69?Vc(h+vmKrUMM z%2uTb;bzDB3ab%}7ZYQ8J|NX{$B2ddli{1kaDh*cJqu!5N~P=@ov+_)S*7(HQasez zh#4|XG@}}F-{MKA_6@)JSSeXNzdb+gRNr!0)>Zph$$AzSiC(j+=cc^G2iY6p_yGe5 zhNC=eB!Aaap`_fq0j|A5@v~u-p$v&tPq+0f@&Og`?z!YECI8+56FOi$=De-ZAJ>VY zZC~Pu?E}6CX<`RhC(@=q(dcbh=vVz{+F`3pWa`L6h|E%{sFUrD(?-@hVnRA$2y9`J zp0zK@{7_!&Z13{Ygw16g-kS!=lTg_YlZGUlBY{bb@cUGe3b{!<^U>gmB>c#39|W2-NX?0bmnyS}|uK?wowX zI1_9S`W+4{amQl3R}aMy4kHcc6VFNHN(pIqskn7US0v}}XG<}Gt2MyM(J~Vw)y9t! z_Q0}o88U;9a#o+kbuf?Hloa|mTQPHvf&5$xUKEtmD zh2H)pH$jfj==!YzUyxKvpQ%RUf4;=*ubySjH}`aH?qKeWsk&kw&vUt7B}o6;CthWB zk^~L?(o$|xa#iq)vj;a_+qizF$S2z*wOkO=(afMm7#oQ+F$e8W5E!%vbRk!AUxe0v zCG3e`{K2nJEMLVal|_OF9LGr*f2I9-*S+pKiA`Xl06QyP?&B$$ESNRWeApmH&U{fH z{ACY9Ld%==Px`L4mDug{@?E~9$JER!7m-K!zbSE<-mAY~4N+&*l zo9BePSFkkH3!WS}C8D+scKnM+IU~OQwy)=?oSSY8)+FDvW8d7$>XTxIr1G0l z_{#*`SBH0lAnE9CE92w4htNn{M}6?7q__wV6wP*yYRl%EeUe+pQY>*e4_&}F90>0acs#}DdXkvuOI#2Q1iR>kujoT1Sqz$k3io8dSWxO1vkvsH z0E*yiP^uf}fPv(Ch!LjLJ=t&A4|Zr!T~EkfQpS3Pps84V<7zGj_OVp4p+)&J!7BM z)J(vR^kqT3E?Fs|wd2=xrE(w%h)4_ZOIE$hFEsQFdHkkX+$SoF!A|RE(slDVi3?wI zUlKMLe&Yq%Z!d^m)%CLW|9ZDWA2qeGIgh5#-sQ#kuX?Y2KB zyXX5n>DGw^socUH$*sxOL1BQbQ`G)&OyWr|gun!HRVr9I(Bhek(oi~PFRoD7F|Lm@ ze1^VG!iK1PZk-yI&k(Eeh~=rELuCv!6G<;W2Ibb`*d{wXe}C@n#w@TLz}fQ#dW=82 z(B5Ht6Qt6bIBT0=BE&5wU;1>g)ny@qdOd)_?O&scAH+@HGj| zu62fUWJX!Yy=E9Zuzp)ryi){BxmuHHU{5zMr;9ejzy9#Q`6)J!B9)&yRI(8D8k#18B-;w^HY!DZzj< z>t=7_S(6}IJ<9T%6+ZqX9to8KAiv|hi-sir9#^|$>S<$@W#!v1Tp65S^6@+?s3<7A zSmJkivDVwEil68@psgf`FE?sO#W0=e4?{X#JN7YJAJ$CHL);!L2C^5|7Jx|9ag*5n z3~=S^C%*(D`V=up3R>YdiDFzl|Fd!^BRF-MuMlzwRhXf>{MGt<6)?xIBS*81_0Vrs z1~(@v{-ZdQaT0HS){!}VqUqi)9+1KF;DW~UD$b>7u7`)wV_)_MEeO_8?_9O|S*XJ3 zPyB|h8>Uv4OQzDfVO}|T&&~hSu0x2NY~ ztbUI8j%FXVqR^hSpR_w+LPi{*z$ACsI)@~rWhX*821>muJphg2eErE5jF9G)pv0Rz z=lp~8gln4O&-nhGbwf5&G7sO)gy^zeX29-0RCB{Xc>+*kBGjY-od@Ms-rTi0ghN-@ zA8OO+?AwUAE>g)lPz&2}?}P2+D?>JIs_gd_&@K_tLSeEiVw&2RSh{13=g4!ZUD9Cp zX@BL*nKD|ajL8q6izuv_i99!8pL4MS5r8LKYe3_TWgH3czvZ8-6tIQ~{qX&w(Pgmn z`XN~}jHS7EOa&eZKvVabtNhIHwQGRk^KX^xMl{zV556RSGf5G#<6!3U&%4}`x)!(` zgyj`Fv-q_5%EZi`rs%%S_vGTFGO;V#Sw8%7i?!G9-(1)`hrO!w)N9ihuRbOD{lis& zWBl!EA$%~V@7$1;gz5?bMPD5^L+6i|Ax%asf)`<;P6^sH!_C;B)zCQB3;p18j*#L! z**-9x3T?t$Q))rer$el;#5+S}?AvWfe>_#|W)*tJX(f$D&^6<4q+lGoL7IEe%WFG- z-@30RLxVZ0jMdc-B9mYAk6`~%j&KwlYU+I^@NMW{3#H*!oTn6Ae2yIx9zc4}ho|10 z@*Z~;$3WGRYI4tSfCeotXi(L|@);WXQ?ivhKy{)Ot$iAw6KL%b=)3dT0^M!Rgr(j( zO+2MPx!V@4dOdcQD8;M(1NuANf(ubU(b4o?Vblt{^h3UJ<H&p17xBzbx?^7c3uU@ZVeLbn8rGg0@T(wt@>9W$!}&;W(LBA=CPA z?=`Oxn57Sq_RpSy(Ovq&Ti!$1lCm**a?LQrK;Fz#UYF+7Gl&(Ty;!4bc#ARYzx#LZ zUDO@iEc;s3nLRPVUHxEYZ}ft$!C8h^NE`5~w!=cSvOkfixKSEEO}=q+O5M)0 zb8MRAx$~U~omCb%S;r12EP(63H1&TR>$GfJK|682+sZq27+X`j zo?m&|dZ0k?UC^sw zUV>u@9$Dp0{*M|9;lrL)^ziIk4{78|PJ9VkuxW-dmvL%FucG%Cb)cJ5H}^aHMnGbd z9ntL3;)I#CoodQ|uaV>Cl4p=m!iVWGLi8~7QifW}>NLTC5C51BZ-$TLHVuDKFPX8wn|CPv)gwaDC7x7TkS(=iiGgP>lM67E`^~dhI|# z`T-kk(loy=#+E;*XG~g>Gu$+0|As7~l#5ZE8zP$M>bPyw0!qI90k*PY zcaIs^l&0$kbM8KMQ|5i`1ob59h1^w*CMO6YO<(-_WK--Np4tP!8+_V@0oTM}1fmn% zg}x5uljb`7?^X`!?2e)y277!eUn3wB7SE5JUYr|*aTdzY{+scjJ_*E8Z^8fOCBigY z^Wk$PiB(e+EwJ)5IX1}ZaEHUDX}{A06E&+k6Q72P-$k2~{JgoJ=#UKls}qEtheDA; z|Emtt9AgfXP8nEv7OQzofa0{(cix|YGE=cs)@%y4Oa?7laC%NdJ!r~ekdBIeAq-E8 z%;$J`yl>~%myBG$I;(llb4U4TQiOkf#$Cu!{N3~vCv?N1H^SD=)f~c|rPuJxM%m zZ8ltSf2row(2HosRDn+~NAHAIe!Dtzk$W-ia#(T-SQuH#xmxLcTw?I;St%T&MJPT0 zlK1j=6b$mCvZ^QYSXHkaq)(6RJF)zJZ+&7$6O>rSRCV#NGOoSE=5?nhRmd6BF->us zmn3sfp~1u7f|c!#{_2*HgAwmT?!VX6{;V&%_NSY9PeYerY?Bfld*oiXAhGvFJ*0a= zTF3eg3pedqG?Xeldcc3#)!zoHbsOMqL#VslhUdAI4^h9sq^cd}s*}TQM?LBsy8cbr z3;>wE%{uTK=aQG{i=*|qX7e}Qzd{EQUn<|~Ps z#;JicQG$A(RLH)vu^?w`q6E>nY|WpQZ@xl z0qLi)7l6yoUZB~N3qQyP3|qtP^ge{wt1kkUaS4JGQ?)2<8p$c1hpFt!`0M;MXzp9QT7J0j1gQ*nB%9ZF_!lx83nXW}Zt&s&4Wg zv(B`k2=B}GFsxG#>FC0;S0qbKk?H|Rk%9ej7U z^dsT6Hl3WH=AEAB|L5WT2|--Y1Eq;yd+sm$z1dFm2>o)9wH5ftD)z<9VZ&KsQjS{R zJn-{{FGQ)`9sy~kPas$vwXYre@{JAQUW3L3Jmde=R6ZZ+fz&!4vG(oKtgJ^i5frxJ zo^i*G@-;*H1Q|q3@%zv#B9JmF zw~7-OS6{(Ym}zb69!ia2PKouS9r4J28bVnX<%P1JPe}n4fnluOlgXBr#j_(NBs3sD zdD^ds_@g@hpQU*^30X)g!?Vk7o2&uK=%Oj|G`M#$NpaFu(XMHc7I?@WKk;qfq{E`k47(!B5UR zqEhb6p=ne})}i=b8dm08GC9_U3vuIbH&}_01AGSXw%D)78P8v}7|(<|X8O6~vb*68vD}0jxIZ$A6t@)EoyaHip#bJ!OEt4y#D>Cg(mCz<;@uRD2Wt@w zhcj8#1~ZYdY2_92q>Cak43=ezjOq{xH*MQo++9g)ZAN#v626c9F^c$dlYgcj+cki8 z$}B3p!0b^X?e_laQ z$;S7@=Q*`(zML^fH229fY^{2<*ltc#b}zMAZYD&Py(2v7+Hl04=B6|DT~i22zGQl} zmks0S>cf;jeBM($I!PE9I7(HPqHY!A6bzkA>*d+P96 zCs(Zt4Hx&7E?rX_1q~nu^@4(u`rUrC6#)(~{!4+q9z|YoDa_Y$>wv!IF}%3agZwmr z{tPjRUQM)HM|@aZV8gts%?w_x1k3`loP!Nr-Db|}`0{K> ztz^@rqLmDrj;*IXpe|bEhkjuP`*MygwQ<)I*?b7a@AikIu|x|I%5^Q%YL)#RQ+yw{ zVtMueX3{SP8k4_dB7V^vG%5z@7uXS(nCW)AUg-q2oaR-TlfR>)Om}83{ZwH45ngp_ z(LDk%J*=eJAC6S`!Tiv=&bw@mFo2jcs66?c7yP$N`q*RUYgY*2$Ij$O1+0kglL6dY zJ%%kb_CR7ejce!Y?s*lTUnCVDNmnJB*DWW9Gn6B6Ryb(EqBT@}22+o$Y}J@(JzhmN zu*iRz9n#pjn-iXdL`}5c`}+NE^Y4wfCx9~xIy;kF$IX5TXg$fp);@z)%zSxy<%Y0$ z?@4%JT=DM?f9r8OLB+>a+jC6@U#eRwLrB~g`~>hVbS!*Qw1?SpD;^s;m2Y=y-9}}7 ze(og_F^Bt=P$*b+re*8u`FxtThy4(%x9_sm z5utR<4|Prgp8&G<7GSm}PT#-Ujj*LtTR?J@cMXAFhfxf}n5bO~C}IM=Hw)x2@_w`2ketoa%k1AiZezX>QbPB_e9^X7iiP-jrom)%l5K>&=9rE78U1?I(Cw;hi zh33R>?USXjSzsc6uAV0t7k8d7B_icr>|g>AisL*n@{qHme}6NqToH;&e|-0BX~546 zEF=1f6ruWmKGfqi5ScZX?+%?gj$yo5j@!Tn<$63R>-rDjjE0`1^%g z*C6-i>+3h$f3V~(UVU;W`rUk3U&i^O+A~(7#(AZn@~gU!_g|}VS22zX%3hv*gSSlY zAWG5=d{D0}RGIu*FSekWa_1v`&>>SdidA1&@J0v?JLcp18GPX434hR^x2lQab8j*} zx+?RE^k0YS@lxL+g~d=J+-&AyXnC+f0&rWzO)aD$wklO})AgX&?a1~WvHg;~sDcrf z275rZ3lNa~R=Jaqgs7F}n4W9$TUWka1Kp{x+uAuS&vBjk&)DVT84|A9A;PUYJZvJW zM}|x1XCf~3L5s^nrw)o>U6mYUaIS$$1(4~VcKXDoQv;(K&|51^4KxSvns%+bu^MKH zm?wL@3-)tc?mUa|{vPH8q>KcdYq0$XB~@h6ZAVlxKnD(To+;Q;eqj zy8q8*WH=9=5xviMY5EXy_z5R5|4m_X;aceWNhP)UXRKQSGVnFD*i$U%MH`5F1^O%R zJ~&x%#6HoiCrBD3K~Iz}$jmM@C^xK?q>8EYvQ7LJJqQT$xmOZ<0Y+$ z4;UD4{;lycE?rhzEPeNxakL3;G;FO`qq$c;Dke>y3tsUudYP4r*HDa+U~GUNJGXcC zlyF5=wUS2vc}SBpsPOYyRGj$dKjt@%-)&rF;ff;C`YoZn>8^2vNVdqZ;P_tA>9l8x zyar7;ylH9#R?_!33cxa5>YGH2E+BKsCh(mr+}}sy0yc)b7+NK6CJlx8oXO!mR2Ts7 zheKQgtb&i+h+Ra?tp(h}1qj^W+v?ubaZ;W0Pk?jX-+8f(v%cHY_Dx4y)z{~5l zgX|QU#)^X}P>G%X34(&&hnzK~9Y-UUD*1tu<(+tuEJ9`UGEXA*JY{bTAu!T?6MCHp zgUGIvI`p${qyK|T2)=EUV-0p#ixguW)RmDXxasiE#~%@W8l@FEf3D+F!fy<$K5{qy zigX+xp%a1o<(4iU7j5{(kjQ&(plk=|z9QCn1Pw}>yop!66tCQBeNFHLWt#pUv*Brn z*kbWBO}u*w)DXo#LwV*=T~OJZK6P*~6eB=q!3Xqw=M#zHnqQkK-LM9%skJzd>tv@~&EixAtYjeTKUsPHuNc(%nbHQU|sEv1e$_s17_~o2m9O7<->f43x}nui!I)Zj+%eBzy zT6k)Gllu76MaWEsV#*HrJN&$VGVX|Vv1oy>>E(E{?V17kDqY%>89}4_lO@Q#h9MED zkn0Nu;E((NTv9k+@}|s#5K7YVMDRZ9ve>Kpm%s?r2WRp`_F{zSS@&=$&${Ma4BKCz zt0Hj{8j43I8@-z0gnFS1kSQcVI|_!ej)FeqhsKcVQDcd1Nfgu^q^%YTRNjkRGU~?{CR{*j=ek5FlHvFd3r8;Ti9y?)e0nWf;r=%D`zb_L27!ck>^cNX zNv1G+RJ;FvculNyo(p*YOXz z{62}}f3gj5o1AT(=35_PM$DCqP-3y^%4s=Er+?5=K2l?v&wn7EA10kFYj#EUc)9^z@`ip5ZB*bVK21Nyfk`u# zC&=kv7a^$}!GlV@V+$AZ59`&+5u(BpYC8^u2?x^-6R-XwC~(W3gKV#sOsM{j+%d7f z%#1VrOTZ}py^H6x^Sb$3F2Y_-!Hqm~fG_z}H32^Xz(sedrI4Jd1+L#cglq86K;8g| zCC=`+{q@0iJbT@3)j_2tTCib#L#AsO+Re~sz*|ZUB6~=vsiQZYn8>({8yI8^=GLEW-c&&grf5 z$$;Lm-7o%B?#p{wR%xQb6wetP>aprGAQ0-jN$=MjzauylY`RMbDs3GkhjHBi|WtQV+Zgrp5?= zhhl)?U+|mT3pqg>bb-YXY^sDMV|d!=1j`m{N|w1mgxtb8-CRIibcrmxcB-n2L>Qi=%o{_+_9>CLlyEi;V#=n+~@&p2nEBrvS;B1LG|IZrXWi(C`cQGyTe>(8_$^Ht!xYhrHPqsK1WzimiJqCud%D^u zL1<~ouEykVTK_Fy3(M?Iks@y-+`14gcJcj$++yij%eQxo>$>zS42g8GDVa!0dg|Lgj>e(a-sq9ih`-K}kbRnj^l-Gji%nCqkO5WP{+~mOLGwH`ZQL zQHP5kaSjL)KJZhkUvTDsST%?{-p_>t4%ts*)F8e!h&dPfc$ZAC7;{cm6G9KOzf=)b zS?%C}laKF8jq=4VjCOFmxw=^Q+tPC>>YhBm>3rQFgQ(JI!HowN18A2@K4j~w3~sSA zA{YGsM)3vQApR^u+Q#~%fc(urAAz@iVk6_C{vdc7bK%CNiTC=k9@m1}%)jdi76wjW zFPzlBh`%T;bICi(_E)fEoS0-^ZAV1(py^4t@%1yE<*P)$-`{<;9*z6jMVjy>R8ZYWV_V_3ASvd`fNW#lX8VF*=4y+ z)y&nq;hdw{;W_M1;5gg1=D7pRtvl;PSv_!>Y>*4RUH2rk{@z2*1%qimz4v~U0^&5^ z&1Krx_je5t{mz2jB1@vaH^-E@{Vl&zuDh+HwFT2pui0}^r6)%xl*|it=|9;5Kkgr0_gMi(b#7u=;BAM~U=jG=d^oqFaT z!+NE%BjAvjql&oiO$N5oxwj$^U)%CQ%DcnwKawmQ$O>N*1S)&KK%vx3>YrLY5Q10E zKBtvCK0u9W?vOi1-bQR=u%zoVwSHLZgGJO-;q?KMT2va|zHH@kzOA-XWhjaY=DVa0j7Vb{U5v~F~r=MBob*< z)KwW1LYFMdsDx{R={pC{ANF1i)3}w@zpK~(N!QDa=4dH(dUU9ga$w?&XM(-D`mgtQ z8h6*uM^D3S;EDT?hBPH9UvXYC5rGak!5I=N-#~Fh1Iowu5R9yZ$!h5BC51$ciy=H= zG#i2Ni+cPQPFA)S^`cW3tA*}r(9s3R(0WO~AeU#0el9AfS%wJ9Qd0tsHjnLlOp5MB z_0gRhrQAw@*o8DMQWcFXO6J>lT<0F1Vj{n}Q+yXcpbUAnGxb>NVNW&fgyE*2JqRkb zBpcF%*|5@n+2B|M#3&J3>ugTUjN<2qpe_>XY>Wzpef8C$xWjGo*V-9e`xfT>FG;Yo z>EjZ6ajXYV74#^mO*8F__f`AwIM127|Jb{ej%rR5`|m_j9+CFR!)h=saE$jDPm9B||_=2+_C!g;*dtGHJ=ubqIa+;^k;Q`h6u ziq)ra>%b#5@$;k5S84N@HlZEj83#Ku=Q3Q*cN24deFH9mCU#8IhEhiH*b9OpuhQUL z)LOoF(?W$}=qbE*pkK+ONt;|Bdvb##`_Sn1%*W^A;vqGr^zn*FGW%JjtRf$dEe9U* zj?I|<)xpE9>FjVU-~O4P=k^UwGmYC&m1xAs+|!xr4uWV&=eimwDj^Pek(Xadzwf&K z2iS+C`*kO{EX5KIBcjzH5##gPH_PBZpLPmuk{=-^oh|C+IpwyW^u_!>XsFqZ5RrP% zf|6I{Z=vSq%4!_>`kFZf*(bc3bnhGQzjHK> zg%vPyd<8{$6h2FZpyS?e<1)hVZ#lu){)pc>s&2RQJf>=-8LxUBLW+{NI$N2Oung?N ze<-wy+5@Ih1gz7lp7TsIkJ1x%DquizMCO~+9CI7iLl51w5dOpMTLJ!q?EMd8|= zYq%Dh_uGhIXYCCG`i_P>E1zN+ceq#X>N2z6nF$v0?pV_GsnO`w3VIYFn%rM2bY^)V zEA@Ee9mB22GLKX|omC_{;5d!JIZ^-EFMyQht2^rQ9^lkb`oO#Ihh6(R%e~mdUM2)` z>J-TnQ!RVp?*1R(&k5omJ$!t^-Gk=&jdY9mXx6NsUdCY@OaHznh#qE^N z`ge;9LIC-mpw8CKnYw2^(D1w;)ug%kv&!t-k}dFBJs}!#4v|PPq4$QIEO+U)hUYQI z^Lr1g3cy``)6VeYttbP|J8#D5iu@Rp=hF;#vcHpY4Zqa=o~BCsJ^kCVHuSwAt+8ag zc4F#TaDTkOpTDbw^Oe*eV zaqMrUkKfLj*_UYMxINi$x z)z!2p9J%)zm<}0AWa!zvr0_vq(8X=k=t@!^bL}Fr8}oFVT_yts2^}uC&vXKhly!bZ ztZjNvU=GjMA-8<24ojTKQeNrlI@`9|@yM?klg1Ybm6Q9<&_hLP-Tuj2zT<7gldgrw zTVk@No+*DhY%^Hj3;gzCMrmcXOWYbevr`>oQiKM(MLpD1Oa8=dg? z?=d&?*W;j6Ect+4)k8v;@4t~*c-ic)eFxwPunLIxC9&?KkEJMSpdrMS^nL|2Ky_d& zgN|&s-G@8pL>YZf*%>1~cN^7kVmWU9GlNMl5aL^`NQ<+)^{& zvwLO+RVlx~qcxnzH9$>LWJnX@%H@s{plOu~*%dw^qJ#D|`UDI5mnjVPG)oO%=x*}R zv#eH~PpUOipm6AX8)P@kNnw}8ceZB{xZP$uwYP4LwGvbh2hfj}d;I<)v2nVsr-f9` zrEvyb6W4NR?RMFGia(7gki<>DMxu}uf5F5)2Ac;skg_%FgR1-3da_rL{VXHX#3OfS zb%9G_o$ z&XW~}$ydZhcfjaZzPyl;1d!`m+T%($2Fl~#F98~$d2@%@177Qj(vGnNnOp|p(BtY; z!rtFP{@$#wzSZ+8aQ*4Z?o_MPpD$h}QE^7&Qaq{?FyQUhs9&NfM{i#t0dubts!7B8 zZXkL%UauebE_V9cg<-Y!lg#ojQGlJ;1`eF4K@Qo^{_OV+UF(>vww=TkMroLRC zj;wqDCFvaNH?60#<3s13cT{c{Lnl1>HV-^#6`j4>`y8jP^I?%R)cGvgc7h4Z!*C%v z@G1!&OOscRe4!Sgj^wj8nYcZ3DcjVoBrhP}`sGyg_Lh%)m4Wba)8I=I=^Ule2VHm6 za?(6`BWEXQxM#cfy!u0eVAH{Gq~tw+d%KanOCLI#n|*5*?) zCdj>@rj;7@@WZIX-VW%d)6O(>wz=j5JVdDv={S4m+D>x>Pgd_k_lQ&Mb=wPq3=MVU zj>4#cH}OzAz0oMEpiBbjHvPG4!(!Qx%VhQf)c*FO5M=$~ro7M&>pt=snKL*6yMoj_ z!Q~wcCkW!}KFkLS^m%;9vDbP;2b6L7HI1&0xz!8WO19el>XcQ}x46F)|5;96mXLY- zsV6c|oYzi6O0qr6UR%2-DJGV)me`RVzX z5-IoVcED(%`XL5-k%5_gL=L`U6Zibc8fY`)mNnyYYI6;o^TqIIsX3!G2}P>YW&SPP zQX+ScHSwR@Wt#u=UO!EMe#zb3x3~Y%o#6jRq}6)y^ktCYis1F4Nui)t5*)SG_QTmJ z2iUQqe3+zDo1zUB94$eE0M&e+Yz`bN{w z6wgh$SVwk{g9=d_?jtk_$i`7!s5bAoge-N*a#xBX%LNuZd~MMj&LrDREB0OK68mPB z*1{YoD9Zfc5d+e4{xja>i@3lI3o%w_@8ncLsmBIcmOH2X&d02e}FrD!2~pzL`GubQy^Ig-fjwi|7Lu5 z7vP)``!%QmQu~vD!p58c7UIxt_B80agTT;gR%DPjreb>+`lTS1tGFg zZsRj@i~FEu&Frv|P=7ZWSML_*HWO|^RmTA#3B(THr9Q`LB2$|8wvrUoEPvP5u!B;+ zl;mdBFfF4qHA(|vg2dw`%zDLQ?z@Jt`H@uOk->G!Os7_c)i_b(FhvVB8Y7{Hl|A1B`Ehh@q4WON)+ zibBf}i4;X>PT`VIZ`}g}`A&@dL>z%U(}S$gg08R^6`e>8(bAp`jKk4`gsh2|HbaO%M4{ol#Ia+9F}{Rhqy$(C{%c3rDT)njbXzjxvLbzW z`{WZjasCE@;hlfd%G`eq=OFer*|?_*_9M$u+s^L{k~$g$x~JAnmpy%>V0m7~8A~F* zYcohZDplo!A{C~zD584NGq%wP`!u{|v1x(k(|vzI<);^|O`D6$!c-K(=Po=X>xGB# zv@Ri|3V?xxi7A^v<9)Ay-PpBl>m8_B`-psT6@AzGHU+iz1z)Lq{56^^3*9_p3jUFF3GUk=H4GldvJ(~H0@sP-q&AR=%K zXorTdDlUzSbB;|BWv69B$eM{L36bA6HBUI@vo%_tk+;2`7Iu_D^;bY+B-u&xq`6^+ zn&I41Y-H5l+T@r7%l3v8qV9uD%hqYfTz2UKDQ=0X=Osi;4*?S>xP*GbI30sz?Jz#guTG^Lm~j=j z_THnuBtN7NsWET9g8E0UPlsqV0^WQMAiJ?ZuTvnO^!wn??N>xhFgTY6-C@Us!uP&0 zqxO#Iw-zqvCpW?z+B+MTnV2+$7H@xRxO#94ReE(sE18z)9RB4XB($+sj>j$^?o2M5GmNC;XcSr?YyEp|t9fgktLL@Dw!Zb+j7 z*hM<4;|m<{{Rq@(={Dn1QQ zy6hs+k~Tp;{~OI6clYzGx_%?`On6zNiKrXt(PTqt_XqUnkBgxC)8^CsO5>+QAAUD@ zpyDzA_}P8=28XycE4lfp=@vqC(C!@tGqS|%bXpJt)gMj9%-xtusvucLZ=+t|THP}z zOXh<=5C-tYZYM|oHM9!uJQTK{0P(L&cbt~qn${lftRb8FUmjH)+JF9ZvNY6MJKRDS zFWyI9LF#(s-Vr9VTN@Fho-K9WJNkumY=P1v$Z=3uwAbdV71Z&BGQog|ELo#t?;z<@WzyrtrGY}4DdE# z#}=A8%ri%?-1GNvHp z^Fm(Em5(UsgKum66lSXJ4H8??Y{z$8PXd1!`@vPaohBI{af#Xs=-a5pJb7-B24r%t zVif)Ru{_t{7!w;^JEBHZdes$bVguX4+bb*@&o5bQ*V0X9>rAZM+^9Ndxt`=xDC~G| zwv7542{2K7tUr5wK^o4zL_YcaQ26iwo44PSnB$suq}`kLr4u7WykqTPo^hIAt@lR!xo2rGvn@Yl zi+ZM+x^hHRVWu79J66JHbBD}LF&V&p)=S(!qU!nb`3ERY#vbKkA5_}3lz;W}XgaCL zDUA$R+!@z<+N~M$_6BJLt+-PsdFatQV*7Tl0vH1p5fUgO`W{qL4M~%?l|b)LWTfJ! zIe37Ci-80duuBS-FVA}1vfBgw>=891Aexhe^f;8QNHSy7>g-O)b28#pn3Mp8FF*M| zOnrGYRPp< zlnb%B_RpC5lvr;7cM7cLazL_pLMVL|O$vUxw#MyM*gobqp7)VFi z4{`xZ|2$E+?1mlpsbUM0JAef;P=vtw5BB5lI{pn}4Au8xIYch$Wr$F6#5ZGJ05l zXLJpH3JptbA{lh5j%!gC@sZ5lSg7dHCD!r8sD$k@$*{<(FyR8D%kKSOOT9Y%G&&*A zhv0$w@+qi#bE;$=^IJgUAhJlJyedFFzZrt(=n4pq;QOfT`->;dI8t#FA74tbd1V$% zZI2=zO6oqw7GXo0G=N1>T=}hNTKX?$j#oy)5u>@B-9RV!bt7klEbyx5EIJ@8P=xxJQ+FY-C|4`#xQQwCY^IqhS4q)v<5r`U<4J*KI3tn^n8k0Z zGW$wx!?50Kb#Hy+g7iN(2-WQ#7#96MU_!*WB;o%iDtk1=UOb0TbgIPrdZ{ z%XUgQ*Ha#scNO4Rdf5ot+Mj#G`6i|+k;%?<}- z?85l7UTIl1e&BIBaP%x_q4e`JtFp-}7M9mJ#3IfL-x<7R%}Ba4b0#?0uMb`BeOsGT zLGfpDBX0G_h->>?9BpCz`0{{Hh?(}Ya-sIjyY1piHNx!A`CX5OhCngDO+#h7 zsgK~dFIqv|jG7x7-JP>!FkH5~a}!fZu{2HXP3grvgpL&)zpHESw*WZaR+#3_-yuP^ zqLEd5)Od@Xd+rA;zRVHIBYo5#fw2@d=R+HhC^+uw?64vBx*20v1KiB2I?pcW_7L(!m|HR0P$4*hw|kT*xa8B!=@XMjzOZtrgf$r+Kv)32Ti4H}-JIn* zDEq*+kN4t(b=Q+vioV%eW@V1B1;whuYqjIIe)AzXJl_@zPn;PLj zdZyt0)pMY?4x3gUVgUT}jL}%M}9@>q{Jxpz$DI=}-UEC9`(Rb44A=R_me)z4{YS-u)j91*{e) zw}rw3%61KFaB9f092+cAu$R>sAkXPWGhI{h`0(DL<~k%JNJkTbOKQO1?XXQKXyqjW zT{1j8EXFon1|&9R?}KOG0CsbFbcCm*ICOIzhX-$h#&pyyiW6ox8gMVBFc(A3ZwuNd zdtG^xND<{5t;o6iHko}r|8m0FkEo0-qHNIFrKfk(t~%dZGM8+{Uwthze@1HSnpErN ztKeK(7so-!#zYzzy8%X9N)(y#fZRADPLX*in-b!>uJVLIpbgyy z4|pC+JaE!rBnM<0m1{tu2DC9yXn559twDsPK%R%_jMx6bjS)0d2eKk@KLfAUSh4F2 zYD0F!$uIfS{=Q%{XU*`%-0l%{9dp($W&ub z(8s&?Sh*uNFkPA&?TeB76JLX)el#AHL8aM{po6^oKk@>OK(e|Q&Xle)i+l&f(NIO_ z?wt&KfDDxjp;Cg3S*(Qb)mp2qrMj`lMx?AFBSXoh{t-Lhlg&fNl zDZ#73k~B&ypfve;FPktC50vPHMGO-peiDP(G33UOh`7&e#}|_Tp3v4Z8PvuNhdZ)! z#HR2L(c1~$UgFPQy=A|H-X;KaboX23O*2q|5~s@j!0tmFd$C}Xm%(dV9s~+zP&KrHE1Z)S&Df;KN?s*eZjiQy~d4bkc;%&JOjLZM^)e@kIHkLY|x%W zXjFWVJyX{PNn0lZ7T|?AU>4Gqyy+X_c^bN(!YY|oq@MEq7|)V9*L<2rG!0B2S*+py z`c@!b#+qj)-0x!~L5aTGk7?JIjl%Q0vXIQ1p9c3UN_wAYo&;3*dU4J+0u};QwTkDR{)WPf(*D9qQYN1IAZq z8}Cf8tPKgV?}arx9}ZsD@iB4-bnY??1U|t|e!@*Ap_lM64i!x(76&M3mXE-*agbc6 za#3r2Qeo&espg-~zzGSif8Jij1oziMDD*nkS7jM~MWlee@hBhLcTkoL_63hzgKpkM z-)ZR46lM{(X$Cu1E80qrL3Eq6Uyx-{8LIe7{=@ni?ccklM+V<5eZMBf5bBJ$VUgzfboI9CbF2p|cJNg$;JVrESk;|x&8F2$W4%vX-7lI4h zKVYti+k-n0xoj~up#S<9CSX@i!Zd(T&7zRt>{esR^@FRIAoii~)_L4-HvtHyb}w9a>O@hHP)J1h)ty zQ}`J{u{YrC?>(04(U4vvvKhU%5vR|&`Vf}{Ge>);38<|ED@OGypfU|HwnSHc;#i%* zv8WwJ%7nt?V9D7Dwf@C`XC zI{F|4BPso;*W4CIZzpzLH7S~^DvCTkFK9q>xGLqmv_8izwv)}f_B-N}hRDOzi(UF> z-`03oHT^`|H>$4D#q*|~JKCMDL^cb`v=2%$>iP(fFFw5&Ap~r!pgf{zxWhr6`)5`J@tjcO`k^+ku%m1XC1d5V7tb->t!oy1j^5@KZs&TZM;o;>!3qBcJ!8m zI4UXMuko!^>+O~YJ%ZzJPAz(FkxuH@3Rva|~h-39Sp~QPdmXQ*WDU&Rwj3 zZX%NRpoA+ReoA&s7Zk;!m@CsH9k3*S?FCReKcjCji#mK*ej^^}7KWsOUV>>8>h82) zk8oK-hi<1;qB+!_tTmg$V@abKQ}9zjQr;VdMcjI%`AL>EqB`+6bk3eB%p=J>$&5MD zI99sn_=MsYI@Xkkc9euTf-Z3A;Q82jJEm9mR)|-vxAS|x;5)x}tD;R~k`~QfOawlN zO&1M@*0|UezSk6;OgI``HlQc)$BU!q(*hy^(mK}(yykl$xFQ6VB%uc4&3R*ab-2`< z+z!3I>n!Ty`9qr#>3vZg+TBO0aOao#olgp>uP+S;I<=m9AXsP4v%RO$+zS@+R`>T8 zt{eirLxOpv{f-Wp`!l4(s9iEP*9gT2$wGPG%7%yCw7^7{TTy&XCybV-amzwy=d*wj zosr1hM)z!NU`7|ys9c{oKW~U?COMxeK+G!}03b`v-N_(U%pPCON^|q^|7x6~qgMIR zyPMoiOSr#|V|RJ7^w6v%mJUK=2{4AlzbkG4q7BX@PZa}RsuO11!aU6p8qR4^K&=jgpPLZiVPhf35rDu6@_`G)! zK6FZ}GJO8+;9Z!G3~QURt{6Kn;SjQ3C}E~|@K^d_R-q0micraqN+5qVz1MPp%QP?M zM_SHF#uVzR9(7**YO{k!kZ0WF9hpt6IzlesiSz)$w440*JK~fG*N;* zcAJf!?XU8|Xsm@RDuMBk1RlC94*h|=TaX%)7)vVPJUy!XtOc@Q?F}$S*JYVD<7{6} zVP=tufaIx9r=i2jUp~-uw+*%}L2jK)NvPW$vIYm_LCd;=t`p|f$)6lJ5{edgCq2?( z-&*s)H#-%mK0g3WwD>xL+0kv@=7{UkavAEcnX4IjSRZS@hRDBDn*G8-RAW}o`i-+! zlmqt`*I$lD71wR$*D&Ty_6kngI%ERrp9tj8zSY7k(?Z@Va+n!X%D3+;6c(}aC}CS` z7xf0_l5CQ>t+{st&a~UfI{iK2N{>O8|1eF32;55CVXkxMi6TrBK|;gEjarhUeHJ*6wgG$@D4Wm zESqz`;{>$xjGeXOcm{y`U}Lbj5%|v?FT-wcgARc_fOkEzMR%+J`#17}f`0#QjbxK3 z6CNAyycP=q@b%)%E(cXh8jr=w>vW3hUf+(fO8>XD#;Dl4i%}B&lSxB&d!sYS)z=1Z zID=SG#WtcNo$A>6oI=o?!2?jRmPAzl%%6zv%p`&xV*| z5+5%O;tTHD86bm-uP2x0TvuB^FB-LnHPad}k`XEH=9C_A;p3Y@cRs}L`gdjSz-zxT z7ub@?6F{YK{~Ox<7D-F*WL@Vj$c$u1@t4Y6A14ZEu#N;wt05+NqgKnDC0$BZjDY2` ze9121QzMd*5{?1npign)s8&;rWjF8MGfw}Ev6mcFiwKv#-?3WVzNaw}lIzXGAbROz zKRDY{_B3xczAmyj&$}_lH}1xb)NEX<;cXe zh8gk!JMuW&keyW`Ej4va+eR$fwgXci>&5Pz^=*?3>X+=j=&E_yW;3P@SpU#?7EIuq z(YvNFAPr3z==m*?+8kqCSC?*=5yzQFao$H>I8eGXPM&0jOO96iWyz%}w!fE8iNx-< zH&AIoCf)PCV8QB0(GuFv2K@RJw`;ybBl5w-NH^@|ogbIChr8VPiNNac-~ODR3YSJ8 zVuGUFAaYohDy)wckwY?fsK#BxI|Sz5Dq1i0g}ifEt?2bP)64G|o0Himl&w@BbPN(u z>@@>l_DxLcYr`0Jj!8M^dbS`1=wS^h3kkc5D(5|U2#_n-g4?5t*dc5AK>TXS&LL5h z2R8g_joaAIzY@S^aMkJ@X=F|=wMNjr&N@SZW!w^}+jQZq1#9E`%vLM(BKQ}S2;)n5 znl8oixN0!p5un%MA~+l584U;@O<@0Kzwy!bgiy{07~BD zr>E#vTIjX4T^SZ!w7AXvHl^vN4X_}>6k8|&arqO`B{~fy>5(OB)Q7|7z*t-B_ zQ>N3v2ECYz8Ke~UQT1mkqKe)x+(=~|{RMYjWGUe<268S6&+Y4m-Y*Cq)!JPu!ysl1 zp5w8-GSv!KEG0?0G@N7F*di5<3o3)HI z>o9=KKXfU~{^@Y>z5-p$Mq{ypc=VCFhzdwj#W)%Hfa)YXD{dE`3UGLkBG4ZA!QjPEl?=CIU*`@7ZIa zmYQ-8lm^~UV2ibzO&5vxGDV~p0JBCUu{(Xn3~oaVp`Vp-S~K{}2oiqsS03te6P4pP z(gKmrr@`I&9OWZ0C}8RW$Ys%BTqhdlh@IP^?ATt!&Iy*w2qXfwf#>zZrb-=wa6$v= zV>sd6qWu@K?S0h^QrE}3xu=z(p5g9=b)v9DUi0%cFWvCz?sK)b)mCo$r}@0OS`)1< z5w&eE*cm}N7&L!g^(1`DQ2!8`nDF+Y%30YruvkK1fZBqh5T4ThwK$bZlQL*X7gkxy zCc@<30ni}|wdZm(+Cc||U$H*v{*KRHrj&B3U>o5ylnuM2Ur{k_sIySA6Ic`iI(;Tx zH#X?Rd0u0wSzcou?`~7`yC1r9u*kCF!s0Vslbh=*YdZQJ*&lJM^ArJ=14H2$)ku}Q zs^(IUkNzH~%e7BWsdHB*$XZ21@~SKjjThEqMqpr_BK$=94DG9F-v#|gXZD75VB#|% z$sMJg*Z}eY;iv}O%KE@(1zi?`?Yf1ALC5;g-z>P~{zpEOCE{=ZsNCj-U>=Eha-Y~U zP0zL|uj30rQa?Y;=+#$W@l^HO{bI$=GX#5n{q0}ph%W7HuhaF~A7dM~EA}6(UB&M) z>YUC<3|R<+*SL4RL!Eu_ep-R?j|0?Ty@j=?*>L;bWVx+(hK-ptE2A|YKVuAQc;JUU zDV_a)zlRyrN$h&g9-1&-ZtDZ5c^GjS-QV(f^!i#=A(r@wcT$*Hm+i$Bj5&dRGBMwj z;jh^|VR0aeDzzc((OvTxGd3c1xi(2j&0^E5dXL#JlzbBaLosGFcpMOm$i4REwTQrQj*~fYR!?Phwpq=OHd4J&HdvUuN8I8K4cHbZo;`Lkcg+YYLpL7TqVqxKQAcfVq2x^4vWjYF^^3Ic~mL@cm+0c?`0fVxb+=z7He2 z9a9TGUtWi^xhnVlE&l@K&9oi*VS~FFKEwIoVjcQ_k6IWE;cP&waIeM^RFft) zhD<;&FjV?{v(u@E+&gw<_46{S%R*57#>^gx#$AOph2VjJj6Ou96-}E;5s;#)G^hDPa<&WmqZZ;>YImgR4yG!J5C{~J; z=(^UPNOzp@|5let*3||JUqOiacm2i9QA%;->K4EvT;oNZB|?_Vaq_Sr|_`3^{3lHVIG| zmq4MSsmA+g&b)}-7cfoX*m>;Is+r2T0y)P~Aoepfv(VNfjsU*IBH0zYg7;@P93ZaU`&g$|}HieGvb zB`fQpKP-~;j%J(~#qfwZ!N1(h#xOIPrf>Azh?u(5`_+iA$v?EtAk!(~mdNmq#G(V#KYL3i4-M=>} zC}RdEx4;j4@CNZCpYPVYq?IZX{e_|}y!2-KGyeW+#>__7Wk;AqyF|j%2&5p}|{PT*{bseBbx((e}_P;uL10<@=Oq&EBl7+HZ*1yodvZ&ZL!p(!>s1K70 zgJyAg(R%^iGd9;hd}^Kv1^!@Py?WJ`uAu+XWitJ#;l`OJ>TPb4<+WYpikqc*w&bufm#X_3G9u2ht zh#|;BXtF&^*d%vzex@R+UQ@(mt-Jm!XZKT;0nwug&$!|utyqaxTV6vvhn0+8qCyea zY+JM5PvtU<&Jz@rN1hbmwv2ps%7QJ-j-?^h8(8;pi9r37o-)w$kofJ~Lf@mA|7tzq z+JXSnHVKcd=LhG*F zJH&6R+7CW?gc^%%RU~)-2rRUNvP}^Wo+(nco%nPgipd9_`(6x*{>|c}r_Q059zU@c zw=B+*Z^`-tqCUK_go3`bNpn3EGB)D+tVc%*xPLpHR_68Pru~~B3$XDhN5N@`$8^({ znMENVoi?j7H{9>wG5zL~eWR(iLnhCfxvIk#{k`)_RGlM<#X94yQ&3cXq7-ZXdrE_d zUVAN$Iduq(u2p@1KyDCrZPF+BME4jOfTi|{a1$AnDO15uy zaBN4@8bj7?DTb(W!Nz+-T%b?NwX{4^siXnW=bwj&(t7o2_R0)0nR`ll8UeRgH~w*U zXY;8zj?a7c&H|TXP3&7GlA#WlJ^Xr7Z&dkW&g{_~=his1PuF;APDe=68C5K2Rhx{7D8H!r7SO(Ym{Uqo~DJhOR$ZX5}*e&rb zjl4&PX=`N#&!HU5^B>~S&!fICvH+J2h3c|vr~VOO|130#BEbFm(Y=Sj#7kgBZllU^ z+YV>NUg9+E&MD}i#&*w}@S+&?(dH}62D&U4;Q^AVd0~!OF)25dWtbP!_R-Qb|I~8v zpGl3s&N`dMjesem&{nkxxR|L4EBa(ut%3k2=C0*`{%ToxWR8F106({2FT+Y&#ard7_0!_Kro#C>*c-Sk_V=TXD&-H;3WV5S26ZCs%O= zOMr6aY-)eKzC3qGW3w>JjldQx?x;wBepsT*Mlj5hj&zOhe`x@8rf=n+oOeuyY_A*1 zU#_BRk zNm?ki=}E#@gQxncx!TvKfPzNfpD_(%e-t16I)+fXi{|ZX^Y$IYW}WDabGsuFbg|T# z#og5kh)_@m{uI9_8I1ZA96+ z+&ivZaqG>=m2ivB;^p9{pD(|@8tk>XGaP_oP8}YwBGj^7|E3(X{^^?m8v+pt2l`wY zn;*QlD-lEX*l`TBk*+XYCYK6-Vr=KQ#(XuO$Ay(!O|4Sr`IU6<#P5Ataxl0(tr9<+ zVD@nL?qwIy{`iBD&3719_bHP>cxT+WE1yV55&v@k5G=kQ|7%~wCP1a^#- z0Z>edqy*Ksinl=De=+r^36J-lI%QtYWtKIQ0H{sJPP+{j)_3ASPR3BB6YjBP5ZUQ- zDN!3`=ay&*K5!As6FS*eVq>Mmpa=^ zyUnQQ%IWw%k#oZDXQ(G~{@du28rT~pCG?n|0aoU|poCXhg zk|mQ!TQ$4Ba^iz9<*FjZz>Ektzw%-o41!@=%3W6KCAJjka4_v&bG9l)`3K4)sdgy( zaN4I`qCU}(1$mR|1N>IbLq8!^Eg5ewWC;$=b)>q|*57W|?f@-ckioG*>y2<|4=zY7 zf$#f}kv!z=kf5KJw`pNzK}>I09adDnBxT0^J|GtWw(G|ov!74%%2=(O2g@8N4}ZdG@B#*5TJ<4OTyusGsX3CMb*QCc&*tB} zDN15v_IRR}^~1Z>=UXC{vkA662QdR@-nyUJBzbA+z^%}_WY3dXf)Pw$2mSiFjBC%N zVx|B714{-{z#ah|jY+NW4O7R@WxaKt?+CSg8Vw6Np=t>;M4IkjeM9fUqS1mGA;CVH z#@=J5WnK2Bu?BaqqKF5n+^qfYqoEm2M>DFyU1uHWtL^Cz@a+p5EK!TdI28X;N6EXM zH4EElny&Ic(ix_!U%_GMz9fKL#hDMuN@zYxGe1QpMb0*-_b!f(~xdQrqr`_4M) z*K-9dddqJAknKI8AQ5|_vC-L=(`xoQzt%z3sny2rfYi8e(guM%(=sZaw1_=j^Jq_r zJB#OLX0&V!O%Jg3V-Lfv)2-7d?6es3(Tg(SopwL2v-$G389JYZsWJ=)Eu-C!tc2kW z>~jBR+1&}kA54c(i|F;6@GYHlLH7Xog4cb}dY$l+ATM*q;h767?qgHPyet$=xF-RK zc_gIZp|R_92wR0I!3MAIwyycfwcq6xM6OHNjbu)YxSd>E!`wRvC0%?)gDP`ybu)T_ zRUun&$&X@dkSlu3E-!pqz=!2?s6 zp&OBPlaDsCkKGl-u-Rsk?ninVs(yXCnt-esbf;}7qzbT%AHi8q-z234p_RxGROZ)|_Xw zFd5;-?$B(}*P|jI^Rs*Al=&{i-MjwolyWc6oPcL~v(LkN7yi7B#$%&;ipN%^4zrg3 zSk1#&mB8B|hl})?>VxnxHTR-`Ju12|wy_)SP5b9>g})tr2TWQwfYF;)0pQR-rS@1d zbpDJ4q_~Ya1EN(i1slL0=fLAXZ?Fi=?3&BlL11&v;I$G8>9J;dq3hzqF4@B1gxymE z;Djig%>2aZBU`y@jgh)Cjbjz3`wy$N!qmTjv>?bV7kPEVaP9<-MZ^R@&(E*-krB|O z2~}<9s0;&v6bi{R>xA}gWaD>M5*4_$ z^?u!qiai9p2hkEV1(wS=C^8J*`fGoFl-IUD)l>Q|}AO(DmM;UOoBGtM%SbU|w zMF2SKz(MBY`M$>?irqOL>Hx0RQh)sj`>*3WSvDCz6yZNc5k$H+xIY|cf1W-i_b ztCl2nsi;|?@A+*ON02$|HjSp}^sSX6??3%O@3%Tf?XLBpD&e{^R2^20daT znd^Gs<6L1=^)UgpXA$C_zxG#kk4IWw%P*H%zZ@e9(u}Jc9!oHiuH9B?Cp;YtWMwGG z#Q_FWNW}iwuoc3;9~P1h>>8F|gA$iZ)Oz%R)^6yIm4CngvRlw!>KDM6oe_W1)s=G<1HLhv%7c?3VEpKGfAQyKlp96!qx3y6^A!oS5JSl&1wta56*F5Uk@AalWR-i1h!k zgpOJi6xV9l*0N1mErFE2H$*P}%K7*Qs_W3FS6{az1@Jn`2Q?TvF^LK+k>L8D4?;Ta2$%aaItzH@cR$B%^w5Wj6LC9!yOU->$s`Pkx||9LGuRnQ|~tft;<|>M&9+8 zW6*^6)l>NNg|5_{6!z?U)L?lncr*YC==@Pdu0EP@;`VmIPH>z5*4o%v_LW#bx;Cf& z3ixHfjGXj~4lQBT6&e#9W>B?_)0dkojc`wyY#u zi)X(;ntET$_0hhT3Dd0T2il1Td&!F|CkP3w+zp^j=D7YzeyjYj>HNQr&3@g0K`L3r zwxFkxxv%vpX8ka2B5TdGI1UE5rp0hHtai0S3PNlFBJxvL6n6_GK~@olEN^cW_jUQl z5FrK4oopZZI0)V3z`@mRszoT;mIp0mou76R9r}wnbxxZYz z*M>T0Q`!xZv4nLlB32w5GyAew>x^ys-pwKCoov#>tZ{v;1S!0BfP%B3VDF~9hhw&V z_x35^3Bw~ReL48JBQ4ll8_NQYfNyVKaqvFuiEV3fEEq#weH zsw|xn;~IXbejp=raANONBvY)8CuOwNpJwky!fqK=kE9t?ExG((7J#Xm`^{JJVrHbC zS6zC(guyGl(F4ZcVfuhHJtG+XCYR--!+7Ug>fa`5FeRUP_Iv)=vCd0xvUO>FdJJ6S z(3NS743i)bdYA&NztI^>f%Hm%^clcZe%FbyyI?bPf{uTZ%FP`&p(8{-b{-Xxs#FZSViYuONPa1S92V2kNPyuocP?Gc@ zxSwmkm@|^y1ao|Q1x!-_)u(M4-jmH_pQsve-g4yqs&x%p2|DjJx4iQ0JK#nX^SU|8 zTHsgdb^<382XNDsk!mIA*0=y8!UeEqv)9XXo<9fob#z0% ztTx$py;zu?fCdU=wEFF-4$W<|`MqQlaJFgMY4C$nT1bw{x7BQ6Y^h?GdaFW?5*@+F z==`~7FolZyO#~og`bT-u4T2)u5^RmMW|0gbqmwYsX#|s3ouTkPzO#0>|I8oynW~o- zbrpfJ{kk5G@NO)cNar#U@=|}{Hb8ObxYK-R@0ZI`f3n@qDc2D+Y(v~Rw!zTFH_-=L7#gYBqyM@Swn+5W*C(tQNeUJ^4T_nNO@$$*el zY`W@@|Kyf&_!)w5bi1unaf4ca`g%^nrbZkf{;3PIwmuTPVlT4E%j%c}o0v4$pNLVTowM zG;6}D3sY_#<)e9$;qfwk0mU$Q?~c!hSLz@)oLXJTGE)$hBoT zF8JB13XC|^&V9X+J7R}ofdeai=%2%1kp7A6uAN{vGt`!X_3e^|?a?Qw)M%`_<*hrz za3M_{^XYN}TVA%%6yac>>8o`_6#H-hGybJ=!1g)oV&70XbQzD?_5H=V0;w*2UnJ~A zm0b%-;2QB+?$pBsV`njF^tGi-x?jIFTSLH--GyK20mhszeYYIe*1Ue+kE(SiOh&4J zU0?1=$MR0gSUZv*cvCdAY%!YiSAf5LQ+gYexYCz*{(j#*fNFky89bD;xq%BrXzotB zmq9v8AK}OAZRt#CPh3J&#nq`?s@Uf*wMdZrh5n6~D`rnvT`5{sZMB)tvLTNzLnP2YOfFf4o3x+#H9fe+`Z72l zTc4MND<=n$_t|^aR?>h2+rZRGgx?9MLfDL$aLDQEM-D{ezzH_F3tto|QJpF_Dh)kt zJsgZf6?73rF++A>hJ>(~;3$y8rU()WU-Hc>8RLSLnFPCO zf98tQxEqrG3mB?pA|0HnDQ>Dl(_Lg;Os0c&BGJ7 z53QU0L!OR@etwI(X7d6rkDl7_oOp)7(%?UM{i=!f)2YxG``X(tNqnO7T;4uuMO+cW z**(nM+nyZwwQ<^8HSCV)5DHHo=UehzysMZ-ju^qtEffY{M(x%!%EV0@_s~ebNi9Xn+Wv zqgXOXybv695)Jm8ku8RyO1=wjwKQ%_M7@GhmSW*JFCBw`MIWSA8maOQ8HowrMDH*Y zIR7POJV|O9tgb9^J$aDn@-gEx?a9WMIPb9^q+&Q|Qe0Fe_ysJW?iHDMl=b{czb_cd z=)DQr!D6NDb{s$orpG)vPdAT~V(k&t3JlM0vN$A58P3VCxba1fAqGU(-PF8Hp?B4C z*-05pVgA6E99Q598u zlt!0LdN0?UfLLaU^(s69?Z+7W-b+W5hC?m3OAzS5zqAW$y+gpW1A)AUGr2BwX@7W} zeO+&jfby77y82HMYY2s-93u&(`|F%dw3U+gal5NGHo28I)b5^cR<|MoW}A~ocFt1} zIYg0izX;24!h3(uH2RERpxW^SryGThF6$wi%~=2Q6Vt3^=sCDpDc6adq5B4CnNllZEu#)EOs$WkHjTNkk=$1&&B~S zGtE-&_F}$3w`&4M1V-Ix0`xcCYJ^s>uhWlj|J%U%Sq_K zeg(<5;STADrrV&>7PRD3NQz-&sR>!=OqPL-Tg_$Wig9qd4)VM7FTx&_Ew^W2##vtA zbou8A)a`*#Bf84I2Tx&Yi>bht)n(O7t65d1c!uvnhuTUO)^bcwG7mZ%zuq{cb>-+w z4f-cOKK=_v1rlWOP@M*4^hlGSqrUhb_nS91n*kof6Dsb7LAum|zAfxT5mb7#pBovL z%BFgic|YerpihIPYgNuY7j6AN^Gn2H&6!_$pw#3`w#h5F|IUs7rW{%D25X>ZnxvFx zCcKLZ_$NY1qiL7CSFUOJ&q;zRUUM1Vzi;%dd_9>ndFEi-Ui&>TT?9R>OP&g+0&S3v z$UzTtP~mUf+6QPem-}lq;YC!KO{mn(plqYS;t;`;**^Y4rx*3RooVGrmir5-o~E!K zZIgQy`)@=qIA^ZkCv4P_5iO6dS&iO~zjc5;wSmk#HQx-hB7YRfE|MeykgteeeM;bT zis>pr{A3GPtliql;U-+&F_n9&hj#3|Q7p=hlXup70q$;-^&K?!vb_`Td3?}TJFXCE zv!fB<*Y6q_B2*6WLb;EMfkW4ap!L-IVh+Gp5t~-9LQob$xW0k#H0}dekJ6Fuwy;c4 zUAZUnS<=}kkIDxp*l_U=ax#727qonh)n(BLarN<}&7`jY*dplp^Q|(!jXOAB)yH#6 z#C^4o!(M2otFLV(S+72-EqF&gphuTkO8F;)V%&1fSw}>_o51X}1HYgZEwEgJD+IuW zJZ0`$Hs>YAKdMI}n(n3KefhA?UX;*mu2TmOoKZy_Vw4u{jSiN+zTeDqL^xn{_pDfI zM8Z{E;8|rz&Gd*6OOSYz)zy0L?u}>Q^lL#XijR&z*;8N$z&dWX1_|ci&#foxM>Z`u zF2zwICph+dy0n;;(E467ac!qF5`msB? ziJU7t`MM^gOGSwWNmTLx7h@n}Rj`AB%M^5b!!ia#3+~Q9ZRXIze4*{`6KVXlIr!Ix zM(5NJ?R78Yd1Rzn0`^jjQ_disf6r>43QBhH&R0~Z|ijuFm8(MZx7#k zuo^&d&4te;ROTe_9uiBif>u{T(uVV(_k=X~26H4&brl1j*g+aF)+In%Rm~hx^CeXT zKCM1guyx=SWo_$Ocwedp_%l7gaRI8`Z1|n+3(8tYbEwIK(m~4RT^LZK2g>P)ruBa@ z$OqGmL#R1)1I*=HPf!5f7#^bUrsugqM(fq~C=^H#b*MY3TdUW?k%Z3npVvSyJg1Pj zIRlEVw%_b!4(KZ2TjG#&eFi~#?hd`j#oo&tE{bIf$TCC5J%;8K!|huM-zYC{KttDh ztssg^KJ8x&^9tO-)%WTq`SRVWQJQf2UlQAwWL@s)YmfR!w*X|TET2>xJJqv;dPLDP)@1g-2dy#$2LJ0wx4@r}e ztdulxn01vNeEACsCb*_ittcsc;GaB8rRtkd5xhv#b@s-WJ_l2=n!c$&v#2bmAJM&m zy3B|bmk!g?z?Zi`E|*%$#Yh+t5ODFJbaMKutZGR7pUeQvQT!B6x1k4q>!#AnaUq6v zkCzNSa+2canCjAWo<+A3cGEf*5J>IX#SoC z?mrUSki;r*611CzQuzU&s7pKzrUIc)6iiUuEN2^DyS^2Ql@`6Ey=_{U;8XVaI3_e= zhhWMmW!|2+u~GT|=pHTq=^k;Ni}s_Cavn~k(0ko7lr^~QW|lI0bu^x0G)U~(LS^Mt-y86X!rmRW+}r$Qg+{RKt@ zRP7tWlFf?Ue>!>G*`>JSX1f(T0DLz56VxpSS{*0+k1OW{UwBaFvRZrj9{o8s6pO-X ziWFtn*e-vfCp1VJJ{lo@?n(~r|0z-Z)R0wey-W9(>D#nkbgR!`j%pK2e#e1(n;yJW z#4em<>_WU1rFz`yWCh%rf-FN&^t*}kTUE}JvuAI>@tXeduf}vOA)UfnLjNg9$@1qw zQ;2Il7jfo44WP+ifCUzv{y3WmPr~IXyr3L(RUyJ^-NX3xA_sA!;qGy=m(HKQ@RRW+ zHuHRFMK|SRMXO_kOKU!={EFjoWR-x#YA3f%F)M+We%yQY!Goqk=&I)f2t@|r5pnUl zhU(CZ|1IfabTPsrL1nLhF9LN|U@O()xR2%OrUB{-wfTYHfSc|D`eriqCS~D63D15%Ltm4$AgoMs z+9-h~jF!ji>>dLDsTluBO6k~NumS36v#Py^Yw=u#=U#L>N^#B6_C2g>+G)vr83EbzZ0USGeR^%Jwo6o+wRO<~=tQ$G)RVFn!iDT$K6N=X90g`qgW1*GSeu2jBt^qXiLJKnoICjT}pvqiM(9$LX~9%2Ydf>y`mDJlO<1=Nk#RP7gk_1a-) z+6y~gKn{#myZ%oY{S`Jv!7*P}1jD0+l3kiG6CIVG99Ij`(l=&p^H!seIm-T(k2lec zk7DRmj`5JF9E!WX+ZgT3xi zG?Yr^r1nkXv)VBfjwi4$j+_tNVC0#@ZsUyhOA?&EO+vFj8eKojN?xcghV6!Y2I4es zZJ1y2N)B_%a!@XXWBVQ%ITmvqe`P=XN~JJ}TXzla*K03mh@ixYtN|8ma%p{?DVTnBm%Du52)v^8KPjeR55{pFNPif{Bnw`r zd?IN^hRzmU@itg;KRE5f+=l(xj%~)qc3@)iul~21SpeojZFR`Z*E+>P)rV1E%jJrE z^vkKpO+?E34-bzwd6@hdl`3Q3VtY*pE68J(7WWA4`k)3Aj&V4dsh<*3QpmiT40Vx5 ztPh3{A_4|UTXbSzS^_1M-3TmzoEMM|FDyHIj{zOgLM|AH*x}4r{OISzw z16S2)_iA{+)xYr_>I5&N=Lqo}o4-4u1Zdg3n1Ufgnr$c|^!R*t4`kpJ)u=N3Ki5FT zeN@ui^JKyn?9FVyYH`7fH&M^G%K|;kxsvV z&v7QaRobSiZ8q5v*EUFZ2nNr>nS!KF$Yc+n3FZ$NCDh%sIkQi&;CdewFi7Tjpb7b_ zQ4A^l4?vB4K*udN^q0h`O&h0v$>TNOVX1VJEm1=jj-#8ansIcse5XJq^}nkgGuK{l z?{M;BqNWGYv~8kRm)7GJOBVkNdCCXQ83^e-TP0XgwgMSgj8&F<>u+Mhi# zF#c(n|Np&CG%@@wQv3+dy&LBu(IE17Mj}(e;iXo^@MFhUd`ukA=L3Ngv99$v8`-{t z;rinfv%rm_<#jsnNRysgDY|_0JZQ@#o!ei@gu=){I_4zDlZfMqNMFHpXMfp6?+WiK zx1eAhZ{fFiuvTchFdq!x?I$aedm^!mahuORQK0N%Aacz91CX~RbQ0p$Ys|~vw}N*l zI>vk;^2|dqsyOm(ZgeKBsU6^0!e|$KrkvmT_$!Xsjax2`2s(Z2)PcoL%Wwi+JA?1T zCagE|4Aw5ky<$7;-sd_#e0WEmw+#h7axFNLON&$Q$?OlmyfY3mrBOxjiC)WZ3|=zK z2U-~zuconryDuor`Mj_>q!Z*4e4R{09ZO=5kHksA`2o^wj+Bldc_NM%IChp7)|<+J z^b#`Qac-^4%n7rf|0f7PW^VyXI)xCCtp-b&WJvJ=h?r;SHMkY`h$V=pke)F{w3Xwk z$B^jrvBw3naX(OuYhxXU0XnhgDSOR3*TSPh-Y{MYh(7X1;^*3VvlU=xYpBV8?w$*A zI6q~XriXJS9?d_)*W=caR7N8>(BJEOGa(Nv3HA8DIo21Vx)`;U0*ik$f^uNv7K~ro zu)Cr>@Gg3TGVTY<*Ad!AkoXPnUk0rf;4qcZO`l-JWh(=jwLQKF+A*{vQZD=`z9~}h z=%W9j*t_`cREsvma$r2!@cBnT3ptL#Mm*?EojqxlShoE+g0wQ5Upt?`?~?H9ZrbX< zvsLUY&j}a<9Gjj+Ks(PhTzp0vN8OJmzXFfrOFV7p-oeKe-0rD(;xxd5G6{ZQ1h(w; zOoAp5{LL%A972ui!190&G5&za?dqsGq;1(*D(b%zd$YxX3;53v0*^wpROdJ--sr3H zup77d2HEkXJ9WV^&sdc!Q;1b3eMQn?e_QfNNkW5RQ8Qg^KFcY!Ui{SJr54VrHu1-T zD5tdK@BM$>xKc9{Px>qCQx51gZ;O%T13|*H9(1K@9&2y9K$Rgr-bul!Wx>53zwli75${^#H6 zPEI5C+g)N@cP%4AH`N!G-qV%l*>Z(`%x1^Na$Cbe?dD!ieSxN`LdreoksDKb6q}69mk$_w4!pQLFGX%p` zJaEpLSsA&1KN6Swp$l2n3Jq=JB#-{-A}TZ5MquQ%0~W%#Z!~ES`F!bo3wHAg-u4V= zCkUmcH-xkQ5|4KL(FVa?HU*w!%^9b9--Gfc`CF5Rdu!{zt@y@-y>xU{d=e^)h_aDrzOQNo9D3o!$bj;w>9PU=Rf5K7M6WvJhWj2vFjWp zx}12}o;a62#0<#~R(g^VyL&vqw~xT)kOMCeq(*hcGP_0OI3=F}8O%Jjaxsbo=v+r{ zDd4*mx=&i@pMXaT7p==|QZNn@Rh=IzEk2Z)dw#Qr0|4O+M>yzsw3vjtiSlxQm7B0^ za~;jXqRX}?s>4^HYv6x(p;LUhv9iG4InR6Tk>O5MWhK4uS;=Ng;<}$Z-{^)t=&$J zgk)i8y=MobEPOeIE~O4eRQoRuKWS!c0~5cfnc}FUHtadF#d}IH5!sEBg+5Shxw?Ig zuoVJjd6Z`hlyG9d{W}0Hby99^HM(5sa?I}+?zA$9BhfiRT#C(gF)3!ZskK58x;Vp6 zwhUkgB4g>!wM5Cnh%ucv@KO?EBBfA_A$N;FUJM_2p&fHN>9y5W+J%&-tJN>>g(qT< zQ%)@Mf`3Bf)Ffa@w>;GHQV*6lmz<=hbVG?y%J~!`ZV})TDBr_{vkNre2!e&%GbN#_ z7v-SF=Yatl50W&^OoJhWSTY3?`pEEp5$b``psgBF2m=C4v;pV0p#|oMUtu(b)Xh6s z?VL}AM|$F6-|Vgjn)a2RBeWHY*9BRbsFITDJ>AY*U8gOp?!mYr|Ju^==k zUEOqYrtRvfIW&b)y5=k8+6uS9KZVErt&Cy7=Kc6Z6mC2%`K^Z9wb*a$TqhpS9SN!S z>UfWj-!^5qN-|aKf{&4INc3zcL==2}-8&h^x6Xs$C8MdnQyO6IfF9qSe|NLQ9>iiS zak)Ik;MT5nJY;6A;!Bw<^t$-WTj(Q&ZoTT?t2y_!Yt^MDp*3WxH|1BO3@C2R1IdDx z6h?ziB`|7H1s_iz6D>eICJT+dVE>&sE;eFxj*ai92koDaeN(esyeEIQ;l_3kj1J|l zuXK^M`kK68A;onV4R>MkP`^IhyAr}OY)&<;?7w*eB{_;3L~4N7tkjCtBj+AUb93?t zLnE<0oVh9AXfY;1xYJNx94hNL`?HFDD;N-F(G~AD!#dqiz~%gutSIu$3LrhPoWCs& zy>H#OB3PXX6qv&VlF*apX3o_RM)XjxR%^v|rgGfp+O+Ds*N=Zft6@~b<$CB7H1ioM z1ie_PNVtvy{&HmEny~})bFT8_aL+MBAMf^gR?-07R(?SRXP+{LzwfnVl_jHwXu?ZD z6XoH*%>s;SWsO!Lq$EzYi)LYjtc6`c((*=LO~0R#Zfng-63{24YytE2lEjnBdaJV- zid$%b0QK_T)jjlXR3G&Ad*}s;B=%i4COpUpdJF|B&w8827v?9k0C1iq0zeG#-)yAm zNL#?hR>1kmX}ORj6=qXFUG`F$`hP=jG{LIs(CVKg;VJ_W=XNyR9RAL0t>3nG45A%G z7LtJBc7@HQ-HqYG4N{@tJ~mkR!GrR|=m4|;u!mVdlF>OOjPtl%obO-U5r5|+vcib^ zk1JpXT4I|0!Ch5Ho`EkrFd71WSyx?*D`Uh({T{_5`X9C;5^O)!PvL{CZO6Kxs#&?~#6)$a&TUYi1$k=;AwB12yR{X=Dtc%C%AM~*m zI=7PQf5=U3NU~CvmLlQX91N>XTp>7r4Ke5HNirSl`EQ(`Rz`82C}$=!R_OSDP6pgM zvQWBg6e}<^C}Xjpkz)z_FNNwF*=h+J86~rM`%K2fT~PY#pFLA7gvJvt5tX*-l`wS0 z9*2Rm*^2(GS&vR^wjj0X6n}*7O=Z0;%V4xHYPNcdi9n5XKoYL0Bd7cc_$9dz@s!#Z z<7P`7ui{e^R}s9(->57%jSDhkZcXY@Md;z)hzz#B5gwOOIM!<5equh>&UPiWI2K%4G={B5TK!bH2s0wZ%BBr&#z9%@ClduYaGqX8CeUS#=KPX$;Gt5D2oNq}tXsTCpY&btj zIg!@&Tv(YEzevBNoUP>WuHejUAz&Kt1MZc>8*rv7T&fa&USZ$ zMxdrB6z{x!0tb%DLa;j*qKO*RqHY70#aq9U}psPCQ%=wochWR{*|v zgDTJI)5Tz?6(q120iS3qKldmy$D&@0j9K8U>2t{StV! zrZ5hD{=)YH9wCSYUynVG@hjPhIcs*SQ`gBL9qFZHFZcBK*cM_D4rG@n7y$bj6}PKWzNykPuXVs>;zl;ym`6GX%UG zaX*%vd@OGGT1!|Ag+hocAY!kowN`f{nt0D9!lf#;l z)NPNBEUzi4n`N^_C_k?=XXZ4NIAcAMJjYn1H`Oiggll@p&)q(Mt#1pnLv_f*D$C6o zlpBxmBtk-Qv#55<|5^TdKzj3$$p^mX}>U593f3Hr6a6WG% z!hAl6-6>toaq`QJIj`)&jaez+PI$`u*3~@B4KVmOtV1l3|BF}hi`e|RoE_3c_w*#@ znD8F_|K7Y(>u_Gj?Nu>4uM$(@JxnxyDwC7U zmdDjW?ni%BVfa+BwXUMMDKAp_NPawep&8>Y@n)UF?(#n3v^W$#CJS+V7lruT<4GhJ zlSO!_xe5{x+O+cs|K78UDEY&yOaoxSZVwIglrT{+=?aAlU-YOEem)lH*>N9cqMgx&34>09_)l}Q3ko^ksZ#BDQI2q@VVy%y292{Z?nY0 z{ZihxgN2WUCEI&UBLrztwQuv9??tRdcjv&GOuf>>v4sc1w_3`csTuD!mFDeW7xZlv zzymdM(fgq}vP3L!>TuNf5KaYoT7t6w@E)CWKg zz`v}o2g6AmLMt^SBo)bbBu-gPB)uoGo=il5>LZN+ORuqZkNIDWCJCdn+am#nBYLiV z+#D9v@n(dR$SGbZd! z+Z~~&QC;$HAKrfV-6sBx95Rv{tq;rt9tC zSo^t=roQcs$L&My-}`LyFjv8&@J3i6mW1*unUsb24gcn0)8pVsew=ra#RA6WF!=cH zL0^N4V=i^Sx|&X5i1nCzKGhJhjJ*9O;7ViA=@X>kwj=BdWzpe5WdYx_op1KmRL0_) zg8k~*{ZA}PJ4kj|N2z-XB5zB3VqQdz0)kq{$CKE~R0vTCHJ z*O#5fR)Sned~XDau{HLO%yYneDrO&vJSwD=5b*`QkkvWkn}#KfE>;Xyvtx%+R*y*9 zj~Jfy`@2y5CFOjyy+WP~@sgGF^XtAhdz{Nn*!b8rZ0$|RHd(mM@0)KARJ>3ETGCwr z9|kSr-wkAKV0Qt>qtTe{lJ_8X^1yQiPWyjoKS_|5?Ac%mD31Ut^7<=T7oaaI)jSY; z&=#69S^hGEgYEtUmvBIy+&>AAN_K_-;`#rZfx&l0jTN4D%BO&O-3gyR?+Tr2*W|Kl zd|dqgJ6GdChw^w}a3%H0*SA+6-v1RO9`h+=xA$K>$ZsFU0QV#3O+Qq4VYx9nvp^xL z!2^z~^dY8wyy~!k3EO34TUmZx>N$Nlzkn9l$I~ePC~jQ-e@p#dp^X?XF)>Sq%;?3( zibmvI5FBd^ns%J4j_N1w-pS6fX$oSZl@q;5e@(Y0gr13h$mr6mt*&0k|JjCzW8&2x zmYdp^4cZ>)amTItz6ZX0{(a+P^IB3uq*t#}V3EJrB9fJK(dDT;uL5Ani(e80=&=(@ zUG+k{CEG|!6xa$Z(sn`mjFDnF)=QAuBR9GVi7%XFz#^RpG|4+}K?kcH%uFrxtyl0- z@RBoUN<<~%hEP1m<75D}Pa?vlSf|M=E^LlZ~pP+o^O|dWXSA?l|v6{pT7>KEcFl?E~!n z)o%C`c}6jS#0Fq(ARpuv0HRH@pT6z#BI1+}N_Q8Kl<@ko2P<)hu%AZT)YAP3y?}3M z$6m4^!dR_KoPZJtx>Tl5;OIhiq2jGRZJ^~|^zpe3GD<%_UZSPccH&)@=CWsIYk^Gq zhqFc?c!ka@Qu68csbGwQztm~=sS4c-{NbIFS^;SniWEqJi*JAS4j52GQHl(oLx9;3 z85$Rs3mG4cc1LB&B^ca{qUx=ZyN2uzwsy|7P1e82j>m&oeqy~G#$gmA4B zXg1<7gS;y5NWHI@^_r{htih{pmi|99WkHLYP83;f2l!F}8A08k+ox69OZ$9Fl8~(Q zWruE1(*Kx1VETY~IVzAlFQheb@M_MLf3;a;oS1T^@kAqp)%I%W!PXy~Mv^Z-KTBTA zmn6$m#i_6p+{tqsbK`_?7bvks6dSu8k}gd;rNeDBk%aY0W>pk$l&_;L_C3j#^^@hp zkk*p4UfqKWZETqf^nB!dE?QYV9zcJSw2W4w6v@67#b`qEBEG!ael2^~@XuprKVp_w z5aYRQ`z4%m^Hvly(+4k%->K~Vt!st&Y-h`C|E^-{^afl3(@g9_1SyJx%*A1ShFok|aWwU^&3r+4vNtonFk7$+P9>!I%O7)=opS-1|iNlKB%6*Hi)y20d5AlGdBTv&&-yRlH2d9%Fjk zGNBs;#}7xDUvbmAk7(uvYI|ff|3+MPUK!9+;X_A%eNfBJXY+wnO1H27?zHdvCjntk zN&%1$JMk^92hA;DqY=xqz&PgR1wr=9SY_mO&l`m|!iRuFAj=B;Y9042BfS*304@na z{!$30+-tVOg`hMy!o@4a6p9YRULmpaDJshQ9fn_JokltNLP^fm`e1RW!qEYvNSRB@ z^m?Z_dwG(%#&K5^_OY+I5F=_-K`>iL;Rc*8@B<+q`281J+aD zq0)PI!!$r4nqf?{6yN!_7^pPuE zZ`|Ru^XIFghf#Cgk(EPV1)xKT_FwDnaqj(?weGx(YbtK|BZV9$FLE4a>U?U|#=E$Y zS+yvnbo_XpWY2ou&Ww{|R=^wQ>ATKW_jjJvuBK`VSvK6h7z=yJ{`(W_@^pfURAafu z66zX2M(|7hi^~zKP|hg%O5OT0y}ttWXI{iN5H^a)LNN!3so8xTzG9w(hn-n`j7GNA zba@B1yNAr&D2AB#iNAlpiG9?t;!15%qfPL z@0ah|9&Ktj&Ai%wH&Sbb_FYMkUT?Q{`L>Mleqv3YY&zOHEX*b>tML^8zkub0TdSBk zy#4tn#YJ5h0wxh>T>Y5RL~oRcv;T#P-8eM?d|@R|%aM_!9Pc@t!6ABA8iYsW6f>2} zdVI2AAqio|z05Xt{SB%%Ch)`^dR(6%;D{*tu1FV-y2tF~^Je?jMWP?r7-Rm2;SxV( zK8fk#Z?!kH=O!OSp1xx}HGEn8T<+CJ8;q561Mz%G0*|GOl4hB7&Q0%=;?A7{H7`)- z^wLi4VCH|{f*X&Tu@@b4Z$1q3Ta3sZssGI7YNEU8gakCaA$6DEegn+3L->#g1~In> zw#&FBr?u(Y+WYR~g-(4_Kg2Bkb7V~~fl`lVG{}?Y9eC{iQxoXLHsK(F2b6?f2c8O}5W$q#mxv7z0r`J4ABB1*-APJb91$0L$pU+23n`?jT0~S?{YQKZ>PdlP+@?1jy*f`n z_?F9FzB}0j90}Z_O5SenF*g|mtaxd1U7+*vLI2Pdmudtgb5;_PfX;_KwuZ!Aso@Xo z4^e#7(bc)jNw2*Yp-a)-5JzoQF?D=(6)Vg`jr!N92)u!6FtX%0{y5v_YUfA5(3>TV z!E8Tw(a?ma=UXD*i+YClxr*IFY`WtB%0aDP*K7c0*9cqzQCVVP7RU7NmYx0v> z=kjC9Z(&$Lp?6~tVH`|phIg2ScXcHAx$(YTZfpzkE#- zpngZ};YT)NVKfyvfa=Ir9)3r&+n9a*o~ZLw-T2}Ds_=X;6)oFhkkNzJI>Z~S;*`L@ z5IY5%K@~gnViu=3CZ3WTZ*zIKjv2&^e!yMDE!#uP0S&v-6jrEF*X7V^SNh*K3fTb? z#9BX3**vYn@(WGXXrV|Byao@b$nr(Lj z7TV25a2OynpII(#IKJUaJiIHR5+tc~LPk)~vrfU%`>)x$Fss<(dvWWSaY%9xkO^xA zHX9RZ&7;1bQ6YHDY~66vBPiGirO{GIGIjTlxGp&_a!LR@`v2eMMb~`?7?pk3b7R) zeHu;dI&MhKy?k+*5l+qBakMX?;KzRL+E(fEhkkk=L+h;Tpc-_&d7e?E9q4pqTKSow zV!fqPpGa-(}neh;i~lE?OXmi{91G z-ECovpZ!vgy>lU}(UwKhODpJP=o>QVw;MBvjzK9 z5N7b-PhLKImZbl{~Xr%uL(Wj*p!5 zER9EAsdwXBAw9D2Gs+|aj5IhS2q_E#Uqyf>KF|QR@N{8gk$^`jvyQ3{wSK-Vdp&xZXN3&`jOnzrI8Y0}gvP#HwJ{V0koJ_B6$qGv$Tg95I{JJ~a&`ublv#$gSLOXDSJM$>`&VZ&!lPz7y!Dyv(dc-j1T5V@KcKN_1u-PenDJGIfkhWsM!@$x=ptOp}r%)l1|0{Qi`cRYsYpJ!&xu z;`kNMC1fym%u7FJ8zFJ&-iyvm2f;N8`@4vDE?mhJnoBVk+=UXEME|`A|$am<1J_ad7GHX^2=2Lhf8Y|r! zbQEa{-9?`+#2}7@9lE-^TwdpQSRJ(r&jy!(6!b}p=gI}rbrk-s{hiaJ?>{_s^gZFTNpy(IQist2vlqa zQ0UFGDbgf`W)wr4v)7buHMo}@|Lp?T)I!rKTJ@|S_X_eo)nl~ny%eAYBa$m87&)gh z2sGoik>rej+GlR)r9GHL#Vb)S%lUNoK)e(`0`{I=z~oH=%z5)bELN5T)O>CX1+|I~ z+bdag9UTCk(B_th!JSu3yzJ`gTair)sMzJl!HS(hq#f>iyF`Ju{8wW)D~>?~TkbEs zvK!=x*Npw8+?2b&nBdC@ZP9FFTpJKbQy#gLcT3h0%gp5w>m1_ryFmg^CCni zP3ed`b7Q|+K5=iPHcND7RdH~2x zNnF6&e?n_XMC#Qv{)p3zo&N54Dpo+lMlOT$o0R59X@hc}KwhRn$+5tYx_}-`EMfVX z++}L1vWKSpCqd&7`$7~MLmt8i&Y>=SPqrZfGTqZbFLV1^uIvKv&nhHCV16M9k^g2M z6Ua=!E~10sk)3N{DXKdcnwJeTxvgfgPUvFSAQ-(BieRS6HWYb@TZ4L;9;)ACwTf$2 zSNxTuIO;p=wR8I-YZxJ8p;C|(#d>2y?a}P9n+#Zz$Kt%KQJ961d!K61guAaPMEg5`Y=gI4L&lhW7*@#9nKF%Nd zi7J(hrJfdS-*ejketP+AM%Iyi6H*>jS87H@C=T8~Go5@b;BeVHU#$$0oCVS2F3)0L z=#kfws*?G6va>&nSuSXOOv66zE>5UXZ~P05DK3nBf;OKXO#0k3E|X# z!1U##!}kt-HRwz5Ym+8T&f^*BF3BPxtL?xeA;MPaBqL>0+joL}D53fP%K~7Qu4}6C z+Ij*&lV7U>rfU*gF*9z5KU5wMoaECNnR$-QZBA9V|MXzWKWZMesg%+QZrTwKwvFGf z|Ljvh4lWZoM&>2vfff1EZ3m-)u< z*vu%lf4jlQBa;${De%Gy_sKEe&$B${XUwFXl0W8Lu?af)=c-j}P0;J2YeILv-;Y-o zsV#c6$l7KZ^P+K-ly^V14aLP_^YIz$dDCsW%dO(2e;+@Ur@XhX3dgpb1cP^3T3Nm< z>H#_;LP^Ta(%e>3AnQO7zK_sve4Krf5gA}9l}j}?C7w4Pi#Zu9%c5?~yOQphTqG0R z@;&TpJFfUIGbI_m`vCBkfhF}9m~VV=+7DkukEWuCxT%Nk+@BswpJV0l2$8g)h2%wg z8p_|`l{(#t7zIFVS73d8TEQt~N78M5>>bz*!GUme66XgW8?7qWkXiYlg1TVF$ zWDW3nx2$Wq>5RYnu3hMfcKRk)z~iOyJW?9#UbUg&>7|>C=I1e5((?H8qV}LT<64t6QO3O7C@fC>p}9Q$!7Je*#L zrwb?)(ij1chHOPOpRO-^U4?y~TA?2+Dq?4*8+MDu2kwPZXFn9Kt9qd@Yd~%xFH_Xs zTFkZ}i|fPLLk1)aI9m-UG&hH^6u;1 z>aN)A3&)o)dTwO(k4qQ7Qo6=h>?#dO+0M_^$eZt#>8!?=c@A~Bu=vrGWSbZPUj?8V zD)J@8W4<_eBZ*JMroZ<#o1b~bpHA$IcI{*#vXP#Cpo^b|3N;pu$3eT%Xx-$Wpaidz zDp;5HrxE2AH|IIfI=4^xQm{WzIhq~~53yHV_J5kj?Ss(z{*(PAYb>*lHj5uijs2k* zX?N5M*QhC*4)v&m1&O#BpZ%J91P%ni$N7Yomh|UwypnN-zMN&e4Ek-C@GovujNu7ytdo=&8{;bdI?L55^KFakue7Gd{AO4FXED(7ZyJJ+U zPhP<`qxuPal+-y?qzTLP)7gO~WbFM1wUkh?2#>VFd|C91&qzVHi&+qw3`j# zHVyU7?g-(^_psY55cip*xEr@f$F7iq!`a&CTOSwcy(l@ouk7qN|FCm_Q^jUcrY^L! zO6F*5-V10A;}EpRgColp4fcdMk@{COjNj=*^9}nSe2x_m{U)RrEYI*qem}7&8tk(X4W^$533oPgQV&USSqjS} zZV?~Jnb&S@2zs-`KMWMjKB|NN*fx&>E?56jhmJz(q>7GP zK#Jpow54ZiC$1U=VH!=lwlQ9CfItYeuLs!C#J*xC$2l*ngF*PG6bRoB{(UijDxwEt zVt!T8j>zYj;F*l;9VIP)1oWXiR2PO1{VrR+=s%?S%^IY$PM!c^FAuirHWd;3eC+B} zO)KqQau4*ARpuzhmCVv{xsH=L zA(0m|1B887{4}Fb=BYx7>LA)ci{Q;-8yH z&C1_AN9oo5_M&~x_5{-Ok+I3XaQDth?Bn@G0|`5|fw~j^!GmlTmI8cb94)@@tP1CEU(#$FLZF^3Hoe+ncCCI#LF>wTChcL5Z03BM99jXm z_ULuatb>*UemVkUL6hDn9X|49j^>ZhYd|C|6jGY_nFH|_ojcd2*-lmLu>6xC=d|=x z#24*WM-#3#BL%i4UaWGTz9JaW6+RrtzxE6Pe*$i_HssGSDt5Za7xgbl%UPv8Un3#2 zDf{??{XRp-T;a-*Xo9p|^Fbuz8LV_Zj-M%$D=q2{~sebRjqpxoxxt9Eb;?m;F z`y&k093ERW%mR5mMKmK_6(BTJ#KQfE_yKeqbCvR()sxL8JKXhuRQifrjxe| z(S;de;Eucmlig{RqDSv@G$Pr@G36*dx?dUPxFy(np9qbYLK}aZzg^J*t!B36omQ2# zezN)eurpp4wu;X(J%x0yJ8ON~H~WGeU^%wGImst^=EJo<662EJmJZd;qcZXxoP_yY zGiX0qm3Jeh8T#B*-H~S7^z4IV4=pYqXO^Kl{`aOlrD?Lj^bAgxR2Q(4dopZzbmT7)(bDe4LgQVwmN_LNNDhibbe`C$zQw%NTk4o2yrZ zuRH~Q4K#SJJP=gYe# zi~lh3K!4jb4iHU$e}=-%+G=2dj5B~5;r>gWxetkp7%qGwWZZELWef$P@*#VuG3ej0 z!fGEV7tIw~ga%&2&4JjX*W?#i~O`TM3*eX`O{Np$5b%qt&g``#{@p$;66Suv@lyodUI#NUdO@uJ0o0YHqx zgWdFnjQNGi^D|GmrPeo;=2u;Bv>;GeeJnLw)3uzh5EbX(`3u(};`KR3SheYu=T>A_ zc*9%YoUB{UX}~%w{dYQwU@>%uM#c4^A*A{+q_CH^F73ktiZ|uvzvj4d<0BEf+PQ%5 zvF(}TC1Vwq*`>al;Q5**%o%B;{oaGAlOWgC_4NyWAqp+}m#0a?*B1{2mBvyPmzHg1 zY(3Y3zpu9fc6wZGX>EYIYh`UZQ0Ugg*XkLoA<}S=J(ClW+ce^NeN99XXI&3V2JUSK zzvgaC63@Bk9ys?*G(b7;Y*%9Hy#h)vX z?w5;%pB#04lVqe{)#DR7)2${UZGV_iQ8?iXkG|J$ed$tRP$~vl`8sD#=?Ffmj|T5l zD}v(^t^r2`6uI>N#>=FR+a)3?q?>n;UqYKa8~g|f4W!CprM3AgS8%y!U-gTJUS|l5 zjoZfzq&FhZ&zybEqvY?DaDenHU)Aty|8$Og-tz|BjycI*0X%e$Mop<^371CJvXybv zJt-G1Kader|DLAMlC{0+6CEr zH+E0uPtMF)+++PHl?k{8aggC7$J>>YLCyC%&4B4 z^Oq)LdP#^M{W7&H$=c3D7tQf)z50#N@t%z?fvEM4YAsv&QJ2=QW%Y-12OHDFI)0m= z=h?>(53U6}%_RQbCsJ-!@oFW*W3TzH)u?s8YV^{EA!6XceJDw7)_KQ_Nl8@W4vOkX z#d7HEsWw?`-rSZlsaTpdyP)qwmD>zu4i7kr8N|-xVMAG*n66((uB#K}Jh-FBknVqi z$x!WhJr`ZmBjzBsws1>yc3hE=;92!edo{WRd7Q69vMsAby$Sm{dBSOCdUeI*%v)8? z*4vSV*B7wKO*Ad+M|UsH`l!!7qj2DAVCsipiN@B<`Ad`^ix~QN$=#$(4Nkj3BEq-tk{_#ryhsaC~o1&v8%|9j2F=JkdWNQVHdt%(ld#g`hWYr{Mg!j)i z8!XAG2;#V|oS$(>KJHf9eA{&%8+eFdDQncpoKOa>SSN&Vho=*|{cy|<)3tGgcfCl@ z`mJilrbCo_X+L^n!%6tr+ABZet1eoOqR9hrm34(jcfTD$bY^zA_%`;F5O6PoIc{c1 zQ&vJSaxm0<+@V;+Z_Sb8)@|Pn=T)@-$C>9-Ab=hh8R8rcxjT`MZ_ z%`)%2^ke>PXgavZhz4j#G)iCV0+*@kZ2!ha{)Gl-il{!!&h=Zfu4j(ds)Sq+8loF! zzsE;Zlo)QmU%d<6DZxI9BonH%gf&O=0s~)B_eNa`)Z83k)01b`!*}yF!n(8n0B?_> z3qliES<$L^TXJVlEOhd`E){>{dLiHpr-Gj=Gwo^ZlScTrAbmg4N2};&=2-U|7k%z` zzv1EZC3yysG-?6Q`ni1`5e=XgGBKy!^cV{!^S0@k;SgaQhOZkt7j8V6N`&%3{mmp# z%miW5H@3tM(_{CxUKl+%`QY#Y?cyWFY-*kc;rruK#p;8Q?QH_>zuY*S>0C*Aa^v!O zO0DJgj2~sNVGEC?OVdOJZNDPSYRJ4R$f#ys zta|hZCe5VSQVx=C5Gs)xjSB9g8oibYDuD)pP(a2L-I_4bg4~a$w@! zC~+Nj)@R78HI}=SXEERX=}DDdKE)?1X$~iA8r3OdzmRXdDW0>}AG4Nol4HX|+-PRQ zx__O<{T0OVkoL|tNVnX)13E5O7a=pRQG{w2a{Su8E>HEMPe4<>*kU~yG5hh)xG#ST z9}K#PkE>ovN#nL?&cDsA=p@HjaK0hEy1Ve_@w-JUxe3DAMH1hWak~s%T(k8r2|0VcXu1)u7ca$fhxh(<5+B1b9a!KuwGgR67Hof znAfxwg>gevA|tBi-%L!P6iYI2)p!{-qa!4kAnM4vOOS$qyw>C&o$}CbvpB z8n)eHOjUj7OYOcVC>3@FWT?6>s#uT`@++9MPR!9hFv1;j2tR^t6ZP;q8_xQJ*{RI~ zOuZo5;$GaFv!jd~*BVws&}9xux*fCre~Y#-rIcr9HWMAHZa{JV7PXGV!A?LxCTiRz zl>4hVQL*{(epSG0_wk0~o)I?#F{}MK9M;1z*MA}nuIV46>2vyu%MHZv*#FiWs`I*n z;K;1VG4M0iIvhZNhl_DIB$8MWLU?bq+2=qgL&C38-;jYHf1U^Cphss`a3hfIw)ju0 zLq;v6yQg-rq6`h8(iJY5V`3eIvt!jG%P+RP4mgK)y+K)?&(g0fSwP$Y|9R2>Kr7R` zq8nBuh8|=z&T9bGI;g9hFMG}TC%C}# zWN7pyv9gpjjjorE+b)KR#yZp}QO>-1ta|sk4d@Eb8TDd+na;CCwc!s3w$WwS>0R12 zx9@CgQ*8!M2{Z&0+yu*7WQznOY5{~yb%f}848rq?%o_9Sl@*1MY)vPpEN7-deLFrA$i1HJg##?p9`2N^VX`aI|0NsZS6671 zmUL4>&Gj!lt+NN6AzM>fBJKzJ)GxMRS-UCD+?n_Z3xnHKhy^EtU#nc2W3r@x4(@bupVnnQ=s^4HF^Y-oF@Rz;x*MFpMF8TkoeMG^-m&wkzNLQ;NgRqSdveDEsV!a(mdmtS`Y8{0xb|EBM1LVt9!AI;^k zn~kSHMCPJE))itq{qFh(=75h1(}WU3Hgb^V{+PoO&7e`e!-=z6=Y*^8T)RLz*o%)Z zAKH`gwwmibL^)VC)Y4nFI9&h2MGQH7R>@~)>oM3+@tb(t5S@3+kNj#;HS?q&oq^JC zJ~VlLs66op71*mgPUx;W?$=&;EjxC61|;M9L>4?((PdftOKD372ChO{-er#P@LjaCMsa_R7vu8Rc$M&?pmL)POl1R%wyWkRp6})R}|BwsRY(HUZRn1e;T-|X^EwZbH=d_9y$2cNx?oyN5+H5V4TiG(()gE za=2#+#%(CJ3N42C-0!c3DfpIzFw4L+vklFB4sE+iKaGf~$GIFT0=NRmi_zT>Xh6*V zVwwBWJkQp9LXET&J{iXxtJKI92=~C;7Je+SFW5w2YZET|U z(A0;49_tIh&OhCWWlw|VdGz6jDJst;#m=4ka@2x=-EdFaMmA4F3a&tQT*zQw)>A7I zGd5u4w)4*j-}B)t;iQGZ(;;R$JQh6z7UxFRh*@Yq;G24U-qZZV!-}k{m6%7!HeiOR zF%~)(;&IvaJUmbdUGFfdZsmLFaeV>sAm7RE=fZzElQzp$K}W!X+9wk4hh za}zaRb(gy;f*hOIoKx~eVhnn7lfr+U_fXB_d%(c*!#qxK{Q1>%C&}qlQls-}zAnYi ziQ;@2-b?!p>|fQd;6%8>hod^Ah{A@((#kB5RA%$_qC!l&dQ-0hWE+J-qEj=*ljJXS4*k2+{1Mkzr2Xch%1 zsHp^~SL5T9DKeO5R3qSR)ck?91vDalN)lQay(a=ZLErXtC` ze+c#1`xz|f)>*o2zSd0A9bm&XPrD5^9>hnNl?XwBb4{3Yp?8!^sY`6SUSqa3V$cPf z8s$^5Cb!>(h7d7e=hWuXh;sFTEg>)mzoU4HaH#A=`FrCI)HXm}a8HVqsuO__Aog%` z3x%n?Mw}`4V5r|S4Ziq^Lq;fR3OHfVQ6-f36YJ)0FB0)@hO6Bn{5cMa%z@fw=X(x% z!h5$CJhzQiv$20L1m)m?PfK{MSqaG>p;wfOkg~N=9TIDvOthnLOS{+Lpb`-OlsJgj ze*aV`6!BS2cx(&m4X6zNt5-}@&STKSW3o6qvSq4pwR!NIkm1fw2hydn`ll>ny#PW@ z>-;(NTbq?sef?tlnwt9wQwJ#g_DUC|W5N|TqGbl2 zppTOfl5~DQ^K61yraSVde0DW=rHeVo)&2EW|8=i? zn$kx^lPScSwCKGR*%|{vBv9sW(gv-6Po8W&>AIC2;$Qt36B;wK_eX283r8xVi){-? zXl(Wj#a^928PHwR3tm4M9Rkc*M+YI5zRseVV_`(B6aA@9=biGFrhx!rR6-ZZfm@6f zr^yRU`%hbyLPIx0M-xi6nV|0v%d#qanUud zeT~OQGjD6nxEc|$v4hfH6djs(M4zsBjL%No4z26?lx)>G>#Na~9|rh^eYwNY1wL|{ zA8H?>0@;L`{94;LYwfm5=L0k~Qs)%q&hWa3KyCX(<(x6tB(R8N=_n*&M+BADM)OQIy53=ZCXxXZTq1V>e#>%QcsE_bgtSP5BNlKBq#sMrF%M2q-Sce^*-`iQyqZcjFWKvde-K2*f`6dFzZST+tn4PVD`uF+aYI>lbvVlq4d_B#E zRFr#y28HKE(*y$)?aQB6{uLSe-j?u@y7_B++9np$$b(&6C8C15sy>ZfAny)-%J-n+ zB8LJJ9R|Y6R-d-@IsZa<4vT*vC-$PMI35Y%1PZ0CgCzfz))E){j(^?k?)50+urG;; zw|M(Nc5dVjTxNa^!Hb-&J`sNnyE`s?h(#Ja)+p2Vb)dQkCx$WC>)`Gthqx249acj9&omc zUo+Ck^}|xJL+=Hk#lJ@=M|jE8W)Wc^eq*#4oiPFp3WW-FBF8hD9bU%F6@I`cyGO*h z6~z(bIqVrQ9r&zTPi2;?Q}4@(gV&V@64iHC2HGVik>0p+@#7!J+AsIHaE$>C^6!Xr z%f~|>D{@ir#KEf^<~2uSJRiQ2@|d!wNK?;i0|kGY#aroLoYQmuK|-iZp4`^{Jz(J6 z0N9{idH1&ev<UVIQ5%{(wTCa;lYB~QoSww(=P<%L}XxxZM7c%aCX}^Jbx#$Rih=Q8| ziJi1FMu+=J8+Ti7o{L0&0#r)-c6_@KK6HM=cm7q>V-B6`$!W6V0;d0*Z#XNKd+Bmi z)QIYGy_*xP-wZmKI9=@7Ql%e^7Nbc?aQSF|!Qr>gSioHmb)uchj|w&lnOsWL;9~3x z&)$iJ(qvR=42k#M^%!#LdM-tpKg6A5M6RXra<&glNW3NX-w8XNox^7Enoi>EK%;&& z_f|!S42nmN{W#_XadrH6QY;QT|97xX!4%{PewvQ6T+WDxw^bkI7NiN(|1Je2Jb}Dr z4;El}>0-Fxh>w_Ek*| zER#G&iZz`Ojgd}-Zu)h#_S=*NXwiuO`DYUib&|1ykZdf?_!T_b1`*nE@d4Moyhhf8 z>h4XXmq(}!#00Cku8nW3h0{+_^n+mJKP^i$&#;rjsC)X<^k#l z$ip<>ZgX>j$T(*|U-@i^c`^C>;%x+2`88B&zi%FAz_NEoI5@QP$+=J@X_r^%cWF_` z@{H-YuH{5m({78y7Cf_F(v||L|DMhr#NzMPJglVK$Qix&NS@+Gxr?cW&kmUWRTMm5xg(J_-3HUjOjg_F2DPBbA8* z5Lei^_aykVA_sLOa|ctmcW0BR+q5x+B@q4fe1vl@L4nPy`s(3(0bO3L?%!Q=#X>V_ z0_W93?bKPkb6%-?8nhpGm3+s&fp<~_|702)eAfFA(3l|G{k8v8@I2y-I9c*aEEEeb zzk&tth`*>e%n#*`tQ(Uw0V&ku_wwuCa1UMR>ju-QN>Jq6luMU!FDRwvm&N8%b#ljD zV$y|de?u(psi>oo2-iiM1nB3=;MF+f^%-Y_$Jc zJ(RqdK=XTL7h;)4-nH*rD<7>iRq=c$e&{p5K!Wj+7toJ%maDYtcb2VJJ^mS~*i;dYHb z=0Pt`;C;O14CCUhI9cLB>jjK6rek45NdP*vkNkV;<)C*0aNcnHSaBTzf#rQ<2C8)N z5K%;uWD?Y*|J99GCQ7gsIi?^+DVJmo14ue^BS&6ulszDW&(`xXMG!kWvj$&q>AG5Jyni>n(Ma1EDsG zZc__jBvt?jzhZ4pd4ZmI4YpPmKGogWWWC1MqBHhqeD2=M?%$$gk^o;Hdc(5fVC_#Y zyTRt##YN-^DJn4rwY%d9tTJxxccGJZXevA?E_lgSkb7o$_ONMp$l}NAQ;V1YV(3WHX3DVd;r78bK1go0v6vC+-$J6>F)M`6 z)g$?{exy3a2{r3>@~o`O)U-6k4yYq@Xy?_cyoUso?~Oxl>dDrMKS3$cV?Hj55tO|_ ztTRGq_54O6b2NDYy{*T#;Ueax&-Be^$cnN%yvn~+T0Vl;dB^NPT%oz~_Yk9UDga!l zXRn#n|DjV=3~dK3I_hq$;j2$pTB3dsu*!g-5G1ghRp6Onoe)$7_mgD*HH8y}#-su% zq!$53g)vmh4Ouv1E;u$yQwoMV`LMoG2hdAb&}pOmqLD2b8#MMVX#?NP<7Jm(qQnoi z5c@{1qV(I8bwW~Yp%+@?#9?bUUE}CB6-Me=T`+U4l%JI2`>}3kkg@Q@o+*oGJh&VB z)m}V}_TG8nzHjX({Nx%R$gSw~=Ld;t@s_q|xv7gcPyG9N`L|f78T0fm`=!32w=X;g z=f7m-U)Y!A?O!kSX_5UnB?=iRw*p-sku}mb-9Xg?8(lDB+xx4@jwM`##6kCDVV9Z| z5JuC3vi9l!j`;wbYXZY}rJ%1bC};`Z4l=qbGt$XglH2x=_dL>*xC7bnLA8H7UEO~b zMs5;$ENj$sx1$Gn^qpKsi>nPIVNV8}2KLV{k@RRHRa)gB} zxA;-;F5?3Zos&0%1s`v{xkVFH+T(YSt2GsQfL%7WMNypgzhn^RkpIdT?SL;KOAe?C z9*f|D{@}nLiCCZ1{f#LsxWU8cSpa;r2AOBs9WYEQ zbk0$B%BhCA8Uh&|TE_PYn?VDep(VRqp7{nur9|MwIu`ro%a7wt4;0u%`tqL!B_h=r zI>D~3i;gF3__TZ%kS0mcSs>Rw%i-GcAckt?iM!*k*EME!KQ==W%f1)9*St?i5m)mu#E7FJjZYtQs^PQS3`u3c&1fS$JDE6Df z;c5cre&EO4XKU6$OJ7*G!i!cX8$P(Y9Z7)NBmFy5?o1-K(HC)EESYDh7}GEK ztQ1uBrD6oQA`MqqOj4Coz2DQSNBnu4@cL>U&1zhh#<-Uh(c?a+fOI=%Hw}kPT2l$Q z3=4Tw7-8t?g{I5kcS(}z3)w@X9TfaQ=h0th-og@!AV=ssk~BDHIskgk;+CPB)1cb^ zMA4=Y>af<9Fh4kDO#knoJ-M}nA$(%_O4hwWyWj=w0E`+rIgH;)qQl-jFf_GwQKNg( z095y#yF zc( zjRW>@$jcAhIFO>%>u-C*fo?Bs(N7+1)uAo9ngEN6Y+z~5tP_&j&RjkC&uFWp%W}`J zdTymonIQ-6isj)l!#-_4Vbbbx!dRf-5IW{NRRNSFCjK>7GgOovm{RLq0qmm!# zV7mqxx@9he^e)>{d%|hT#ut?H%`sT=A>|q*&2ua4#?npeckRSH>H_T&H91KLQNtLXbw#iUbM7) zeQJ#lq#My0fdL``m+2O#70F%t^}&)MIPg`if)K>qgtL5e5|RF#nXlRqJr(xjiJ0JfaHg z*j!RxRHV0oqbfhfet!i`+=LTFtRlp^xGH&x!ut?9A)r2eal7HG`)tE-ri#r=ExMHg zJL=+K=F~3;p%=jaVA~mnbCsR!%{oSK4HJ2`mco5W^EYG|89k}&;8)rI$Hr~Abc3Y8a~!T@DkjOkp>s|A1=#EXt?gdbk6P?)zB^wPL`Q9? zxA@a9b3$ZVgWlb^8ezvfb_btA4#-8kfPw^Q9oI7HYmA%<*%Je3fq{ivOut> zUL=aBHFqWoKjLx97)vSxH2T=CLbPdqCx91xWC~uvrA9au~ZlN6rLQWVe zP&9$e%X2~hAR7v4mT|~j7?CY}(48PU$+yK;F=+QJ)^~fhA3W$R+T6f|R2dRaW_K@7 zoeoa3*D%oO2+dLg|Cp03jWs_&f~gp`d5jt9B^;N^Lp z$|QNvZo{c~<-6HU?+r)x1>6a@6trsVUC(cm1IIr5AlOgWwrlfzM2~x)oob!=$o!+W zou`FSnMiwYY7sqfc@9x=iMTz!x0(<+-xm+t^Bmzly5`$WG>9ww#S^dE0@*IeB z?F!_JMJ9GkGGsM*A#G~BDs6*ScVA+38qey3={}WecU6Tv6CKaYrV^*3*=*d`d#`X& zjVU8_Z$Ac(;Bs@DuPP;Cyx-5EZ>+qd*|F}Wc!qjBS#ecxmoac?uV)usy?VA7s$Niv z`wM4YdpZGO5#NuY&1bDB2UCcET=(&t?%Sl%nQAB3M5ViN$II@@ekl4Cz=jx~f+v$; zwZdAR8nI!u$S%y>Nx$&pT#$GNI{e$OUab8BWbl9=*b(d$h+1jqgl$yi3uih{Wa*=G zh{{5%Z-TvPbb@m`UMCc6L~-_YIpm!aPm>e)MAwqCV4dZ8lSoq;AP4t}}n2=gc`qFbXJQfwexCJB$(6cC?nlzq0*BynlyF1AW~% z5fw;Bpa)EN%s+wsrr3&4fxmli4^5QVf5bYDvdrlR*C`#tL*he=aC%B}uH2)1i% z)uB*srBj{>R|B11+r|x!*3M;tX`rht*>gYos;2L#`jk&r3!(o2;b6qLAC0Y6g06~U z(x^L?vQt7y{GQ1cLH!<0ko4-WfN^sW8B>AVpa+rq{$G|(Tj)f2e9Y){xY#s)Yg?M2 z7Zurd2ba=sa>-te{p~Jx_u8P!`(lUB7Ph0NX=el2zNK!J#WGG!@W0!A`+^?Lq$B`_ z`z)X@5&gfo%I;;+L9aHtp9SL4Fs$Q$BUl5%5w0F~9_qfr=#0bWthM834ZtKx|12wI zMo7z(`0cg#CT31{$svo8$_#A@Lfd-2o&#;Dp7J209$f@$Y7)Qm++NC8CWYjG5G!*VG_#ou@%132M#UN=1* z6l%lFt;R!zTs}fT%NUVQ90(0uJrlIv@uHgDa0-?Mb+oo9aNRL7VOY3+ouV|xDc+FC*~Hw?563o2XuS-cg#B~nXQCZH<0xO>p#vA5g?OxBm7 zDHFymrejKp&_uwIo#20tWqUp_ei_48b_~Z_nRT)-LsEr#6<6Nb}Ak%N;J+&kw#x5Su+(8;_<;ryw1N)NO8!S7ZF?9tn{8MR!)XCn%nC zyvMh6{)&V{vilw?S`LqPcz=tGG%6#O2EaDNRc>8Lfnh{;Y;byL1yT+(6UJikxDV>F z0qLc8qvKZr5-R*Vc~9jVG3Asl*b20Ut*PAjdUX=BfQcq?^o=P}C1E*|4#QCr6LC@s z2xlxaip0nG6#}On^pDLdanojnV)Z&}GWgG2xkgFo_Pil5Rwh zatY@DgcCrha463z-|EtR`{3WB_kMzsX9wg@1FiJBEgYL%XW{O?N_i}iBlhWiv;X8) zQJERwevE*y04I9|GGE0BaCZrPvuQa*58(?~;59MP^s282x$O|Y!IRoVel`1`9X@I= z#0#JImta)hC8!sCMa`NBnP^HI2Xb4Wk{yBbOiwJ!1_MP)3%hJs8FXXo7-}kK?L~9(Ir=9!Gs>~ez{83C+MK3G}^VcCu4(q0A`@}*=|9%Un zGGoNqLO@Ki5a3a3{*gizKfFRH+VmvzzlP>G&fudad4lW|q*hGr{SJ4KPfaJb@MTPg z2SaTf6*nyPCkS~B$#-%!_jT%5zXff^b>&^yK6elD>h0geEFn8<;bk{n`DSDVW*EYd z{BL#gh}N*Xbo4AN_wK;^hPbI?9mK&cpYb0V-<~Zd$en*1nR%YjCK;Wl`mkA1=B7Pf z)yHd2cDmr$dME1bXkm>orLO-bdQ68j_Z0V9>EI|maz28I2Mni|8b)2CWYrGd zWy`79MbF8e(C%S@mNVgFdKm3+p2B$M=!pyk(8@nx8B3%U%^Cs;qs%SgFTu;_0Y-#h zN-i)T=+`|Ta}R6KSYnAb@LPMxD7hW1yEJ6wD`dNJSV-e-RU=3Oo$24q33BJ*`tJ_d;8wRJrd$l)|^$2ou zN*D{@w*in+JvPbgOHPvHvK-r&o#8CKk_RuHQ_kkuU+3`bnYgK@sat0=g}2e z@*E@>mO?$ge>4GEu7P7x3fM_U-mEuiMW_X5U!C+ve`>jGS3U~8X~52QrydbqxNg4Z zAYnOo%w8goF`qwP-hz_xuLw~l0J(>p!5vs$VACG2f(H!Q{Y^+&jSlqcVHa8@dEX_J z?aR77nqFY^?eMf9bG>z}i1k#n`MKnxt=z!OHPH}e%o%!~(wY1nkKp0I`w))RdNJy& zSJzKZ5!3MMuxP3_o^cSAo_B_N(N3?UncOTC-P&O>Mlz!3YmOb(p49=8DHK%-*EUoyHW zlzvqSlEQyPK$|fzmN_;hC);OEijI2_zv%Vp-dpWu-T|vqU7r)iE?nvU>Bz=j(S8np z{W0$YgFG+OyUG{;#oP;I;@4 z^gR|@D+>=<={xnbH7xvEdeJpg6VcN8i&ejSHLTW4 z9J0P2i`V&{pzu(;^6Nx`4&uc#{!hJ=XUbkT=$E!=z~3!W&KT%lLhjsun(31^=!EMI zJgKd8_Nd%dA^Xf{#KYhAD9RU*Lt#sn?4T(O4Eb^KVZSuQs+(8u8RlxB5H9R;Fy7qI zI{{x|2~k1S{I7-Ajt+klfb>qE;=?dD28fuBLi=$g-TZo6zmd&RvhIuVkKkHUN7bEWOj}4GX*^N=D()pO^-HvR?G~=Wg7z} zD@fVXRwwxl_~6(G{x1!~3NvGG{7+mD zFPnqsfp(-TA#?FoMt7gTuV9kyy)laSIei;8OsPh{xcS$q!W(ZvpJDOtOIC51ax}N8 zerRn+pQXATUr^WfNERFd-Mq`s1mJ#i!-yvUj#Ykpti%1&0mLkU<8PBbt6ANxU> z{jHE3pCj-S{HF-UeEnfO@e5++`UNTD?v+A~0;XRmD({bWTv(E@I~a|-$6(yh)IOb7 z1ycQ{95^&hj4!>)VEV^BQ&p3gYvym8+e18N+()773GIucGcfG;5fg^Qvs1!5zP^4h zVz&?$U^rNOY-~r-yKX--crbB}hxNZPIqmGR_*iJYn<@XrL#aWp@(c8a9<_3Y(M!oA ziA$vgm&^Ee|33?WrqHnU=>@N437DpNzk=bM zcL*vv?}Q1MUgy;x^s06-O!Mg>5^*SYw(^r5m-6jsJ=Lrp4VxX*FJIvNEN2puZgf#S zUGjYP&oVoaRfJLiPsHHZwOHfRQB{K}KlR|TOp?GbYL{4g?yZY#(UEncrBUZ6a{lPW zeUT_ZV!WJx_FB%Pr^K48^GVC0RKh|5#)e`RWpPg860@;u+_oUhy z^uFS|#%0#M)oCI858X=KSDXOLsrc&bOSzm6_lngtC5Z4dD18LdA#}!`-Z%m2pwdW_ zu@D?X{_m7vy+Sy{n_o~WlC$wB>-~jsw}*3;M|o7Z+zXk|OhZ})?!5@%d|8fp0lmiq zzppV)9rx648_?U3(p|}pbni|v6wMKs`gl(4o_Ps;wW42Lx$_S50Db144h}t+wh#rZ z>JFnT=`ya@EhQ6^(`7+P?wvBg7-(-;OE%-AN}n^MH-y?n(s9=(lcBcqqnovI@eqq8 zq0tjL1C4!2$Yl}2k1^CE;Hbk4HE3+Ut+b>`thob5{^ErUZ~Fz4S$pydz@k|bZw+_? zE;M%>9l#0d#=`&O)V2L&l?z+yF(XAsV!1AjOZHg9(!ySYhnx$qT0Uo=`P4pgXr3LJ zL>`Ymw(q9$Z>vxImsU38uYeZdeDJQ2GFdwl2!iGEJo-p9^@sfDPN47mS}l!apuXi@fUgG@%!BP z@Kf{XJ$QW2^47DK3!-5@stq4RNA#KBGlp%cT2Ya`OcRKQmwD4;kRJq?QmN7~hf#~| z3(=P!-fnyQ8{n9KXtdigvV2d11zBtlT=f>@ zm29Pu11tq6I25e%_U#u1ykg_Q1opXrlg&Fjv!{~&%OcJuL)|U|=6c=XM{hkJ^%ZMM zJMe9=_cIjdH;gC`lRB!KMB0IQ&srYZ>TVp(!XqCj(k&~7aw%ljmI1k2Q~_odKm$*W zX>YLaz^TMLjQSy@AN0%=>FPE^-hYWqS?NsxcB&VU;#MaiZn&@gXqwT>8o!{XY?P{!k1K*!}l!5hA>eW0=~L+P{qYzg@)OO}sh`N_x#nB_(7&0=qK$fAA*}~0)IqgWFpDaAs3MhlL`bXv z&gD_lu0FWA^W9xpHCO)N<+_#Ux3z2(%?(itWxq1_Za7jaOg_I}oL?woqbMpE&0Cel zTJw#1|NN{E>rl{z^XW8CxTreG4|xWhY{A{fZKrn7L0?LikSz!0@A_P;DLkO7Q>cW; z*zx{XM@c5?$`%Klb8(y*I(>KpPLyRWNjK2Y3&y%u=>4tM_K@+|qcqd+8B`xM=s`(+ zLlWZjeN;a|(AucJ4YGzBRx?5A-^JaHz|Ok={tp;OwMyH8F}lDlu)l^{xjicNK{$fP zhIeKC_nDbsqoQ8R`#=y)-t9xJbZa?%_nWU-%2hYY#34KJ3%#N8-z5364D%IR9a=2c zq%~>XkFK?5bzf34PwoR@J6BDpPSsp*>^ht{&ZGX1ZR`GxDodsN_6l^*pkn`QaY%Ry zQR7cg4yQyj{x0JF`|=V{(7@)HYMwJpY`~SZR_|>~oE-+*`5KhiulM zAAe>q!&JL?uzDDiiflhWj!4BAvNcEUCHKaCT!7m7%*kSJH<_R1k?6ybcO!XJh0_+( zHJGmnlY%u`RazKUq>RozJe7Mj)2B#dHs|TYR$zC`u3-Pu91*9WR#>MucSwIV+HoGe zL@&s!4r|mQ_0bdx&5a|c*ZJ2MQ^5?Xp}zcKyxCLT%LJEjVMoAU5R%M0lMekEC2$1W zkkDJL(EWyIuN(Jv6zg#mjje^6Tz4Zzj?0=!M+jJ{>nV^VWQp&3z~HeA^*|e9AnN(= zw;Ei*4Y6^Z!hUc6MvmRS(N9v!+kFW`V5iU7#V*~d;CXUU@agMlV>ScyVktcz%P%*= z#l}pyV=5pW2ZqIU5;^qJ75*D$P1wqwY(KYqSqb_deL>`3f%}Tgy`?zlvMX>IuGg!0 zNQ>3#wN1s8?Ft!FD$1LR_- zzlzvr%{Z|46BJIkPqjQMfBvrvRC=4V@JX7Sb+1spt-zAK(D{jm19yuopU%6m4d0WN zR|%sk0;&FU(odU#0i~gHotRSbdBT&bP12{iyG;)Rd3j+kEe_4~Vl6o>Ko^IK&TD`Z zIQdOgoef=V`YjMn?tI`d%6fR7Vro8gfi>rAAt7riIW2d|vNOb~8vdF4BZ%xKMG87v zUyIB~A$MW!?_gkB;8xY*=3A{?`;F0($|;Zf!BDTQtFW3Om9n|5egH5+mbiLesw+ip z`X%zmvpbZt0)SLp!-7gG#$5uKi0%5JBhJaLhi;8w7E-Y2avESA`fPH|<16*tZc6;Z znLvFVTbw(ya654BA~W~pd-tOl9Z1zcOmN)97lU!X9C)6~tue&YzC9)!K& z4!jC@@>r1>6n6EkAveYh#@!$DX-E3$rNFlpPwRDp*4gNdB#T8rJIG}REt?8c6~rm! zTf93M8z-%LN+b-m&_I1(vZilkCx8mTaPc*TuBAzl|BLGZHXCgtdRR z-J@x47L>k=Q(5jA?*}i?AcdLNg zLR(s#*v|5_<(LNe0=Rx6ZEdjb3ooV1b8HE=sj0vx-pNpyQNdk~_$@(x~q3r|_t>-)8NLH72w%cQl6wsND?Vn*Vu|3 zJs~x3>zECA*~m+z4)*y_CS@Zzfp@84!PEG~Lh{|;#pn6kS(r@8mSl|n6f)MBVK>$K zQi(i!QX1zo-T?7E)mzQ7@+`c0W(H1A)muL2o*j`sWs(tgzNLo{*dLBRoi@j3b%AmW z9ey1~5OPw_wg8T*h136EZ>Iup%^^wt_Zd09oP5YUuehWI=CUna@Qy(cv+@KtH-I(mLaGBju}%_ zV!yXd0z~>7xpN<`*c${5^wlm<+Z;3-(kF;|>;y;WOsik41^kh;cKUzXc@U4~qkPC+mFkN-OAsYH}Z0qXdnz$MRw$16aG5NH0uN;iy3G`6O3np#6R z>h^a-Pw88XX)dG+)7Zxff$HSNWwZV=Ajc38((>>oQt_wgXtWqX%Wq)gOwcyQjr8-D zD8OIen_c_Ixp}Z2ibxjkeFa7VM~5OBUJv5y0e)R7%3#S;pv`)r(J*CFFvEOIdcn}> z&692;8Mg3N6H$#o8Nauq&0f|2=n^v?$)22(&3>e_i^7H1MmfPAtNC$GYDN-l0gTc+ zYK8(Zvxj`t-Z}a`I~5pd;GQ@zrxX>m>|wMcJWYica1Mzzq@j}Yx1{C{|Mjvt&bjPDh#%&)xC*dFNFi{V)+bjjN6&B|=?-Cb^JtwGR%bK&<5yVa0f zP4^$$Cjm~FXKr+=+8-<;T&I}g5&oo^)W><0Eb2(p7UncSCw_5kOC#^FA#po!x35$6 zwy&{P8n?1E~QI(}Oj~>%wEZY-aM*oI0cpl?AjEKu? zPnII{!BdI|wr0*>$Zr=u08T(R7-64I74VDL+_qQ&s+z$9Y!vbU^GNGQ>UmwSxv~3! zxHm<8&Chslz@4K(5$d+;8Sfg*!L+NE(79)y*w(OPG6@J*K0Bg}O^rt`b-xtgxbE?h zqD$RdbR**4`E6rGE3%yX{Hm=ehIqaXbhE|LsMM?u{hIM5a`_wd<1$4zLg;Kj^zSWf zU%&@+)-|bvzgtXJa#W-x=e=Sc8PyGZR1oj^8Djj%o4s`ACw%L>KUAErY7_g|zwZ7R zb8(G8KNW``$(tS^?(prca(P{Nh}3%C;=j5^%~NZn4#bn z$Qwv7;D7fMT0a36A;acx{x(0v@DQ=vO-sRt!%*n(H{vGa=2BWx`Qg8yZsq4=MVlR2 zE@@xSFBI;d+uN3v549?SZq0n%Y|Lu-(*#TED|CETCNi*1r@zpZzC>ExKW`@oE>sl~ zZ!935#x8iiGqnwecbloF)ml-sj7+@9G3)h?1QZv!w6X2rHF6DodR7iK!6AM^YOy~m z`^7t}m&TcU?U5J!oM{=oe%Ll^9a6%!%5!h>V1u0wy_ng=ax@SV4KL=hXdvVIqKe<`VG)oJr9pB)8l*%CiJ_E~Q2_yoAp}%FN=o9;DGdUGj0%d1NJ%K*(5Zw$ z3PTD=_YBOO^PbV~z3;tu{nq)%KU|BMIiGl*z4x;>?(Q<9PX6Bt4O8-WIzbmOJ5Kly zJy!mK$XR&Cz8Mn|f!eB&+{nd`keQnBdA-EI7HR19h#Ae~S7=FE%t5Y*c=iUD3I@-WUI#idb) zbAf4SwFNEc@3qwqw1>|#w#$1kg1xsPxRQXM8;1`J2y>JB{hT8J##tZCQ8g)ue^!6| z)OAPsEY08ytFgT=Q#lZI)-ic5jc$KBzxJDhn4Pn}eZmmkyW5BK59q(|eEA8KfuZMHa?j-X{+?Cl~8V)Z=NK}BH zl`$kjiNWUWUH*ouef4*K+^hF@t86SAv+d&Z-l&z$j$0))%E=u!BnKpmg6ruF{3;!UKQda zQ{$jYwZcx#V?Q(7;yLMqoI-ZpQ3grUDhDG2^uFqbT0Kk=M6 zlE}ZhMRZ$fC*OY)`%BD7R3Y@D#buu7owRr=8uM-j}Wck?*J(!|6fGH^-s`J#4 zurt|Rdt3_&zoO5bUJMii26S4?Rmj(7TYY`d{hWQ8t?O-cw6rHt!jG?=SM$3(HzHu! zsGmi7`sAAob2WK|!XD9~Aphq!)Pc-~ys&MX=}X`s#`)W?xHfwsczH(YvrNW=-K@H? zu#QNqi29oDEaPu|kmaPYZsIQE1<4FD58+Bva$-AXRdx(hg;kA%X5Pwp*X{z^(Yx4_ z#Niddvol>1O1kr(I85S(F^A^aZpfe1oD7eTu_q!gD1ozXrY+Y4@o-NRE|9Ek8D#@TCMxs`lrd`9GSJZF1KIgzb!=88=D&%5~|R%~@=@hP-$ zcTH^;4@UC01I5%mh(+3r=y}=ef~2{(Y*d0IBg(U5%)+P6c5-znkng~=7pcsZzfb3? zq~8Wu7~u~d3sD?qgE=7T_Vh!OLmc(TS;prBx1s1)jIbijV80y3Xs}g~j--!~&HM^f z@7@`Tr-~lv@uMCC-+O*>H z@8VYcGN)MsLd2r=sm2{$#2i!?gv$C?Rvb&8fb5xIV<3 zI-OTf{ClzW5VM$JDH9^$nTg~_c)d`%Cqcr1=83Y$Sa;2RED@1L(NRxC5P)sKwkbBT ztP9$s`^39fKE3D$(UK(;`*lm@T8C{^R7EToT<*Q&?tCocZNjGuv6ds~16PhP_WOdBmLEEdJINyVsa(&$_#%5BFkN(fg{=*klF2JihRbgV z8H}T_w=geja=9UzR+tveWGF63k#S91!G6h{`SPd4cyTqh%9-E+P&eog6k>SY9mUKe zAf9M={R#CO3T?x7A_*S zcK<0i*gC*$`0+>vscV<|*sp^1o+I=mSu!hvBI+?0;~CrKngWRQCTgeIq3gtwms@b@ z)`7{Sg^e~33{6-xWvAm7H{7%@Y!~FI9h4@>=hCPoL{IG~^KBQP)^_N^a^A$Oj9E*J zag^&GU1zOfZe)S6wg>QTriLOAdAB-%55&Zdf2|ZbEs*oF^dQW)^vnBY1goyX6Ja+B z@i34Nsj$>80}uQNLQtQ`mFx4KEm#j~m}6=MDv7c~7%Au`0sFTNll^kJuAr_BN`vQ= zDF|#j;7uRxmgMs?tSwq+?pV#yp3`&>5@igWJgNJ}{ga@mMEzcugOyPB&bXayVRO$d zRIo`HZP>I8p7GG<&vNT-j%8_2t#pxPZz zkkQlNA63}nYesCjZ07UZ>mB~2*G%T1-}Z#FXceV-BJeR(Z&x4&ml*|dl6eH!gop!# zD=uhz5Pj~tKrew`OBh|G`JA^zus|^X`@)Cgk!?CNY}yUyHAEtK!@5)0Lk-Uw_#>13 zZ{*jn(x)$+G}z>0hfT_hrM@G$WCy_i5DEXGk^dKwpo4nz5+)LE_1-M(gFy^91c}9T zizc3_1D$c&FKC<=vGvfq0~61If(5GFY=Bz~={df<&l1KXQ))ZG`FYvCB2ja86J^y$ zIu?`9+tRz-loO1uU+8hi@JRniFshM@C!JqW=pgFa+@4$ZL%FAI-t#KFM;}I!({B3g zGK{OM$irzx>cT)g75q|<>k6k`Ps=k%B1=L~cq=D&gS4hE1k{`XYRSKR>}ybOyKHvs zhaAK5tCpXwZ4P8O@{_kPNsmDsoPJKV46sl}7q245kiyh3*aBU8OByklMLwGJVmUMU zoHCo{T07^igAA7dG`q4#^w}air-2FOU^ccv+j&{&T<$Tu4q2_6tUG5wF@7 zv)gkSqz(IgNao}f2$^wkW)V3rE8}>73&;t-mD)^5IcIuD;xn%_SMAWN0pr`lF9#k6 zh2&PB-eSyGsE$^tVe0za5qs2K+P8T9)|utCL#2otG*pP=!q>7LC0l_fOTM>e?!mIO zz_%LkeKu!oF9UOYCi#E2t3}D81V`XapTB*)4ud`{tP-=DzVW)R8)FasT0(>9&)ap~ z_<RCzlnD$$7wv^T^KiErPo4#ynio_N%=%2m35!>xPLs)2g!CyGuXWQ-%8{44d%b zNe#00_a932%{YyuC6r*<{Z5kXQtAu@T!z{vMf#DN91l9c?I%+q|D!(Sb(D5 zlI0nXA-;5RGV{Iw^g*wlTB$***3H*?oF|B&@o?bftMzpbzlNII%#J@&TMaRc5Ru5O zO1%-6rv0>D$zsZii#txH(<;8kUb>{32!0`UcZH-NfLF%%Pldys0~3+h|JPF>=B`DcLNuAwfKtMwNT>+B|A`9w>3+s93GToT7OG=|Ur zLs5!a`;`BT**dzR2)fW$Mr(I92IAi=cDS2u1RSlPqwBIvp* z1xP5-4Dk6Kk5W(s{50}u=FcnT0f#hS>jZWNfeQim)S~jTtd5=V>Mrk4&8lKQWwUn8 z>Tm8`rnX96#Fg9)r3A%MZa$&ka_oPn=58jY0`^Z%!HHQ~aW9c-OT#YUNtdb5aE|2+ z;>?{)xEb=m!Wk-LHA)83qY_3NR6i46_EFKiF@d%lhb{8^Aj$WTfv1F}DA9}sr9#3r z&eVxPkduX-dydV6$9^kgZErcHE3^A7Mt4VCCPELOsJ63*aaRRESsAEK>@eVL*QmWh_m(%WJNcfN%unMIVaUF#GR z^-AO3-OtdH#uwx{u)t-wKvdZlM(XLKx`I2seLy55vnY{fApwk!sQU94Y}_vSjE5Ol z9_nPXdoWR4GTDu&%kC=!3Wn)_{0_0aNwR<`go)wRjf^(2V+0(-r4)qHxWx-wY3cvB;yH&nDNS69}#)Z^bOd@mxmo~```5V{IOT~gBH>4C)xHpnc z$=}MM%M#OSx1#I+@RP=-&nhNMxvu#Hv&O-lM+&lKPQ)W6Vd7NL!mZys5=F0PrD-+1 zv~N>LwE|3^z85UX-aPqp5zC++1b0GlUsyms#$PatkOb-iaAezl++UR+EY(ti{XvXC z&Jb8CcBKK60H02~a}rgmg^>C)007)tx1FWbKRv_ioY&a?ffN=g{R3G{qaeB-v1NI#CBS#6e#Zt7tKrmN zP_d3p+QOtbu$f-l4rY2IlVcJa6Mv4M{`2O>ZTS4+XNIoJ)CXn|y+0b*FtPuWfMlIY z%c?>Oh}vrQfwWX6(K5UiZj65B^M26I6>x^PM&<7`*0=^zA~W4~E0d+UlC!!}2+ z0x(Mnwb1HUK@xKcB-A5)$OsBxBcV?0zvhTzxV@@yifNtp!4}^b*e_fVQ?cW4S%O6^ z%w#9MYugT)j`Y8da2_>|j5G|JEh$LdM3u;&Jl6PmTJwua zxYZeaXl_1GLF(?Ug5s&W;#RT7;E;0`T-d-5m`TD-kr3SCAJ9@N3rs%wH!rR2?(X_M zVe&FMaXCaq>iv|Z4WZhs50rUN?d)f3BU)j#zZ3+2(|RrmPTvuz_) zUqMX|FIs4x5fykFf@XtgcGF8CIIj1<#m-t7aj+l>THLp4hoq`S)HGT&8>Anr*?T#< zj7iS^M2rPrAc#C_@Hb^6=y3MW(ZYha2fvvJn$xR5xous_`^3FJKilrwZqan0^%<>h5EF8* z5wC6|=i)y#?V`IzfT!wUivDd{S>71!yJq<3yYeuQZ$Q8M)KbG4zr${I zQ~hqZBt--(r#ohZ*K#=RFN{wMQ_!x-9NP#k1_`BqwTc+%^g1f>(TB8sHJOj_D-(P| zrW?1=oSDe=hduC#P23sQe!)_+4eac}Ki9^JlbqAAS_i^@Mc7}=`NYdah>!6j0ZSG_ zGQ@)dspr$P_Jtp1909Y~(_eu=YE$*!f-~@V1NRv^8fyZ6R-UIs!u>}2YGQzfqWE&m z^;omTpDQjdALlFOHq!WtC8>X3O+KlywMfeb8rZzR{w54?W$GJ#(S6{N1ncmnPr&m9 z>8Zj**V`h8Cw=UNHJnmU9Lnls;Roa^ZU5@~++|v2`tEN@Tw#pgV zB4Em{_~t0?1$08(O%u|5KP#)5ipS`CDQIuy+}4Xw`d81>X9(`bdrrK9bKLKVC@xBT ztvKQut{u9AvIr4PTIf#9`pO&K+VT47`O3KuC+J~grs6Y6{*5;qBk4S)gF1@es=G=|GSPW%t_zLnBwJ)2mrnMOo0N;e$vJ;+#gmVZ0_w7pG+uie2T?G%T-?Hc zi}pkkkCedcNkWuyDm$Ip!L>LZ*_yE;g0Qb#h?*Kj^@)Y2(B!3OZ`#;UwiVJ)P$B20 zkc+SLWg8u<{=m)ifZ7)qO)A8afXv6MMyByvaQRMS=b(R!xVXwxMQOugupRf}$58t7 z_87NVzFy0$O*irhZuaTfDKJo+#PjIv5#_wVUk9rJe^;QP-ee!~(p+n1M|U4Z!B++7 zGwG)=BhMO+SCi`Q?MXI(oz|;6=)=c+0pEgGdrC@1J2)|L+~@wmQ4Um!Pnt!|-yuMW zfaZkh2TnHr%f-6@1>ZO5xxz#xSWeY+Bg@&0A+lfmNwAvZZ#t0>Gw;@8F;D}o?g`Y5 z&>zXj$4-hnMWlD1M;z5AYiP&ym|IYI%J<}>U4fD7b$@`;BE9~mqKd4)H>ToT7U`jOc z=nDkDJqWn2ArF7P>_U@9@M7Fc z8QUoM{@sY)-SB0QvkXm)qwi;Bu;95?QkM(IX*i2(3$wT`8mHf!R zo#8(vznFvOVY%^s-7e~A2uZ!(C0+9kdNbAvC3emOBE`KB)!9q6&}2Ev^B_U#9d60{ z1U!i;7u0@vD@S@BeI_#l$N*9(dZ5#?5IeB`YYUefuCEn-OIftPTCFR!>-itASp}LH z1ps@#+OpH_xd@=#!lUUTSZQ)jGWmF8xRpd!TV#TMbeu506`RSpEI4#CViqm{4Jde~ z*?H@-p+S@Pd$eDM6S`s)hFYjw(;!?iQ0O*j8Km{Zij zXXYs8dStO_eGYnfu%5j2w!+Vn;`#+h5AP`tp5%w8Nrw<@DEhDAVHu$J`U8>q3)I8+ zvdBO$8N>{?eC-NcH<1GotV}Tpal1D=gmuN;TYoI@zf^H(ekRtN`6f{MvFc^vAAP3R zgH}dA*0<)Jl=-dD%pcj8+ITL>H6oxT;2a$!T=?jr{#E@KSj8PgP=93}>wh%;32@#! znXmmHnttX5S&x~D-x*L0-@v3|`$bH)W=eIi`#jJCQHeY-gYtKi5$L*S_^6#4vJ5~1 ze1#VhDVi<6zgwU2EH;y*bM6Chl&aJ5^U?j!+p(dWuV=hB%I|2BTb2zRFdG|?;s2$3IKPRmF_|xuP#|wX_B$7!HD1+0-USX z!hogB&wFCv$UCLqpP)J@H?-j0ShDCcLaE; zzq2**nqQWIFTyV8D*fj<`I)PDv8zm6*_Q4>oIR1CpH5s*kbiE?%NKT~ z@!th@%(WZLAW0mlF2|=V1NCoFPpJ#neS ze@_f~#}m1BM)mMDonjdA%owx{WE@L_OnE^X{!C!f4v+pPl6;YSvUBy^mMlPE+0E&4 z*B;$ew|zb|Y5?Q#3aLvC2;bRosWXB6k&?8OT+41hhE5wXTiG$GzPqm(rIuuKf2Ahb zsYUDx`7L~;YSh|qeU6vi6eQ@}N+bHE2pH%?Ozg`o#{_f_M;2bKGU`$43!Rf@IsrPv zBgk2#t2N9vEoE*jIN$G;#8hGYcbUL~TCHKmed&kXBkj;El+p*CC0~*BSNAR_Rz7uS96Hn__t0iqtM>L;4 zwHJ7qrLE=tjHU2)HLu#`j`JbMOCHM#mP*C8-D1o(-+pbsXR7J=KI*zT?@fC&)}w{y zpujo(hD)7Odec@Tt6yhBxic z(d*_*{iY^#By`+_%rxi2KI<0~mXASI-VK0{n5VEfT7$;+RAQ1D^t88V9wp4mrp1}O z_Veq(wL})vjr_lvFN&Yvm)m^G2PzRt)WXU>S>lQUx>D!uS<`zkxQLcjg1f@ z1DV>O?}k`?{JYV!pb?6lJqCh@dICO*5?NWL$-depXJ8~hhNH!Q34k}u_3b$QG|*Sr z{X6&=UUSP;+ZLe3RwqWA=1oiq@3jBY?|K@MF#h)dGZCMIG<{Yc3WfYr6&v8 z767q+c=&*Cx%i9sKb(D&twN$#GcRFPGkX@zkG`7;3bK&#dGe#Zs9T_zB4P35JF-$Y zLOX7QMR!}}VQ;4K6$RD@*)k2yr-c=iIkg)yHUhL;t+|RcYENIPX<PyI58;=)GcKF_!}VBz^>xGAkd*p|_Kmf46Y{D4$aQrA(205V zjB@`+Npe3sEX;=mQXM#P4mAmI>CQDG^OLhEDCx=Dlg*3KA`7y@Oy(E=qU=hxugems z033_SY{sIq?+MV|>$!=|+Ze6Yv&nmTj$vp2TaeHFe+Buh(9Z;>9z;d7FLhv%fI*1G;Q|{~9eT&t z{m$}P`F-~BuLH!2;|oulqk6s7p9VLK9y?uno#~;Ur_?qqUKhKr92%|*h- z#%!#_mT9Nw!Zb4S>j|SxokBXOzphd+H0v4+6a90f7VZHuw5`@qFKl=9&Iu%dy;p#q z+8x^~KprxCdBSHDn3_35vgt%`?qtJN&nBh^qXutEGH-4~uT1lI9B{$}oU@5U%C$}- z7ZJHHu43}y8Gbv|MvR1JQ_%-{TN0tmfnsbD*4ZqSSd% z!A}&z#e5=Ox7E1>5gFLh5hVfRwgB~#!x&9@q zFRXa4k!gu1?uP;?%GogZ{wVTSX93TCvoWQ=mdJ2v%VWS#BpqX5rQJ=X9C1=Zj>Q1a z_*TfEJ^gPWIBdCbkvTEadKqD;H?4KZ`Qh4t4fU;fE^=1uZ6Jg7yn)0~gD(M*1!h6K z4n5fB6SWzT$2TC0%{YjFp-Dx+(c9F>hZrEQN zR)N*8=36fE$ge5ng>YBdIb2Z}nEnqik5KSRp18S#zVKVRF7Mxk@y`gzHX&Mi@#bXh zDsmaKRtGb04Yi=(*YDk6Ta--;kRZ5{oepI;Ue!CLIE^6F8c%u8-y%z>XcAB4FeDj@i_@ujl5VCh=Z)~=_t`p>1OtBt zrLzZR{CRc^nefi^+w-rYyYytSNXKjP=b7gZP(D+*}%9H-j-aux*< zElGD`CsxHLV9GF+PI3st1E&Y~AbQQ}mW2TYKZ?m#G1GW1Ub4Wr7o>IZiVc^(>}$B6 zV?%T^MKg4GIIzLI0+CY;;Ic_5t$ zrgK2?TGEi;EN1z-Z@=#C4Q7$^J>~*ZOH0rUEJCOQ zcv*uaw`Z_RwYN1_#aIg%O!U=FW_@bZ6y;)%%ca&~~uVD9;g3a|RLU)y@HmPCvo zOTc|xK)wugcF{YW*F5jEa^8t0B6^yYUc;Hm@R-WAlwVi2;x^|_I}I2*Q-o|PWe)}JiO@z8@uEEj%!?~1v5 zX0~tS^%unUNBD=s_2}>Fy<&p2>^1-5+Z6m{R@PDLFm9V7UXwgeA$ZisuKSIX%+%>9 zcLIwC$k73>UxDG6CG;*XW(mDT)2+OWREpKw-#tw(GG&V35iViq(mSH-v9_XHY-87) z?w%;-h>!^@dcH})%(*Hv+%vM}`;;^2+{RuezDwp$k#R`Lx98CjU);VN@MTf+=w9ep zIr-U%Ocnpz@PenGpF2Cs|LF=$IBvFJ`3Sh$+U!e)>L{+>7JiO5?FW%v zXHoxT7L1AVC3wurVmuU(DiSjKYDB;pWlC5<1xB3_w=4Z3IdkSuQ<~%%r2}(@`;461 zLDS|HiDL+lV*kpx1Gq9R9bW^aR1-OgZ@V| zjlQf7^-g$C>`T6oo6G zu+|yB%DtO5tX1-<0@ZIm>D;8F#WU%8h{y!evkIk9<0`eYrkjVZ6508nGpK2d6KfRT zD5{9nN+hOyOO}pA6BThw|3Zs}GwcSy_?aE1(q@qsk{L+qo8nD>M_-K^t{#>&KX`fz z)NK7kms%ElCl8kfBS#i8N{3R4#4pm4pP-+Ypg7(&9cxi&;%W{r3EMbBQ}tEjsKaxj zzb$~8{l|FMdu2u$_A3-v=+nL^kFuB8M7?)Y==R$K5t;cKf!rH|kU>eoT}1u76Ms0j zoL2>D_V>oCQ3i(_^lUU>j~Mp5|3s*4KY{H~hqfFGW=sMbo=p(=`{XFMjCD|D{N~aA zvg=6LPS@0YX?f#q904c$=>ZQMD0o!vc3&5ATaDo?tj@n*Un{(6Tj;|(p$Umy9c}v@ zHg?^Ppa(ph`V5S)VY?K>)}7Ix@cLq@D;t5s_df>Qio$bR9NV3IPQ!ecNAdoCxUVVv zm$bR$x_*CkaU1q<4Q?t$klaRVe1%9Z%zv;J{Xm$by?%qGwlTG zSF-etm8rmPfYWK#ereElH6Mp(#7;fN>zSLE+uv>8i22Dh$c~BC z<)b0@?@uHsV*kqv;INJv!g)kSqRjjb{mNL=c^)pF(ek&=(4

xymxUwGd%N zsK4>G-84`bFuo=BV$gY-!I~I+e704fjca&+>(`(5n-A7gsi6MRXf)Zhp-*5-ssCUU zJ($zt!1IesnIaZ%r^|<041YHf%hxuM33{&@iMVhXyvhu~%73w>ypbz{@kDYpzU$T1 zKtm3Tdx1^-kh9ui+s#zywEApW?e{c?u#aV1sYmNg-#;BJIfSr(M*u)+o2LPBp+YFN z_NhO2iluhntgM2I@xg>^mjvpNk$ZJlPf*9E!usVS$o=;m$@o}RkZ&tTC(b+By%qN% z!Fe1_yeqV>WR!nzHg`Kf=+G>4b0AoZzer5kkr;El0223IjSzZ=OEIr?+&et6g$dwo z3NX|9`WgowZbZ$68coibY+-A=kkys`1Pd|15S|IBFM#OxbxpSGL^c_D6uy|K`k)$S z>IPi0ID_fwiysf-ItYflxv5@$YVve>rl9`3E0iC`d;?r{t8r$23LdOBq_%@91988 zpj7zdvOr1M9D*eVq~S~Zc7%Xu6O%Lr<_UkYn_)pyxm{D$vCvZ~L9)`zfXV`nzEM)l zsPCKnjBM9!?O5QmiCBi}gQY9BL^n8fdYH9T+(gweReBcT%3o6_Z5!dg$@zw~hdvbJ z$-kgG>cL2I7QDf!VIuQ#5sCF}{Ufkd7eRVBFk^XN79SR>rfJN9CuzKSUHdR#*J%aE|#K;1qG8^CF z@d$_oWN}vx4_bO9K(i=MYB_4$&mPSCZ_p#KjsxNut>fIR4h0d|hE^ql`+RThm)K)X z7ifT~vnHBC5#ZE2JM(a44&gPHs}%EF)~fILl#Sj??C(RgT#=QmWI9bKuSpJW@`DIKu?`X2RGUEaw=I*9=Ab|CfhR3N-ErQE0b7FIv*S>V7LR zWXnAX1xP}v@qY7%QzS9o>^5j&h3B|GVcIqHYacm8<2PX8G#hbH707%L*q+^Ty1+s< zxjFD69(bmide|ebYmS?Fe%vi}7p(6q#v!DmJ62N175{H+AS# zYNw1zHEMtYdY2bRUtd285==oliH6MzUvoQ{I#LZ@Sa{RzGkt0r_2fZfGB4d|(_8mA zzK1-8l9wAhR*Nhs6lY!-hT`kM?YLSdR>`lO=x?Eyh!1|T9BvGkHEgwwId$#)(Y9#G!4cwjE%kJ^nD>H*Fkc8q=yY7c?`{dN=SIM zx#2fBW*xSDRdsc6tCkM8i60mU?OO-uC{y}wbYP}zs_02?C>|LaU(mJB5YJC?x>BQ@ zvGdmA3Xx%MTBr~HfAt|>C$3E2>2*t5t*2|4EBc}CvGD2Cvl9BbXkF^}$Yi=i(~p-T zDSM(@=DSL<-UQ*2h5_O~X>mRn3*#cTRgX!KQm z)djdnb&nxbb0~JBSiW{-lcILVM3tMeO19s|F?H^<=aCe0vw=%4KNVW5JJM{J-z9mh z+UdB@SA16VZK2OsbV?viADFIYf9xA$B@P}R>PWfx0t#yi9*-NsQXcR-79E_4KG+GU zc17FH2R0B2@7DT!?R1&JE`-nc&(IZl{F;hNMgU>n!z}s4KiWs@o+Z;lgDbrEo$!ko zx!x3&I~GTs<%P9*J2_*oZD~gH&XhWx9{;-Es&w4$X~UQGka_lo1(37u9)M7L_&Rj@ z2j%KuXx#LX)TI0N?!5-WfT_pKd6S#WPOBbIiFe;a;?dR&ycaKmymJf?Coi@fx2Oc{ zWqr-Xw!*PGXjSjl`~K}<+vZ{U)#eH9qZtII?ryp4mJ8*a^(@p)@~=IK8XxFfSLu#D z#n7m}(|h)4-F9GXJG-6dK3yFy3#vqPE>+c~R#Waz_4v0bnLIAH@s#~)GSP)-9L0rER-4j>3Qi<2(~K9v0s;b1u&TbAsYe;mR;1mJRPbfPhS#Q z6zi8TTg`&0A8%jYOkgO6M{n;0FsZ=~G9o00JHG#K&$8^tP^-}~hCn;7X?l=zdpYii z=f?st)G;Olv5tO`Tk{~$@krnP&*a&$*XK4*@=0Yw28Ne&ej)F+LSJ~oH~`B=S}9(y z@}EX$XjA26BS+5Oi})rkx3$E&nntI0d6nwt=tys`p|Np6qSIps!n@1W z!C+v6xoqI~Q14D;=c-bF%B4eH+2&D(sF5&v4>45O7rVR^y7+n#Pl+hxR+-p%G#zUT z)J?(Lo)yY6o9l#1@=2bCme(iVJ!CF?hZ3lb$10~Cf5tI{D-=4YNwp!U@O)gv2VMDUHsvQYckMa|DCRiLsbckt(^2IIzi;?`28_ewQlHv(6tnw^s6D~vvEwNsioT?;*S ze4~U<{##*i+4yHbNt9#MhIOkBP~Fi~b^RtD?6r;NY1PyDnu6r++eFnT&m1+`?-Zdh zw>LEW(GzA3V|E3VYzQhl7ooU=8eit6&(rNg`xs7s7tF_HPyYj?%d_NIB95|huT)m~ zhelYx;4mLz&$i03>}#MewW#3XSo)EJ<8<-R{!1wMOIUPx;P*|pwHKKObpu#PpGWN& zs=Wy6i`e;@+pOX=Yo{TxDM&;Dh3(wR0gmbG31=j+zcNeJj%c zw4toJJ;Z@0Jb9Ky*w>vIPI9UQbb&K|@JRi1)R`{!M zBocdh@6{6+gbnt0RP)3{xDv4pSKq@SZ5`L6Fuj&GxvJhg(d8L3x=yKHZ8C@7=qOqD z#2t1E4*;Q4=YyU5Zx|C-@01`aVI#!Zsr@%QrznLrzFcC7-_=jjFa-en{{ zs*zLZr><|3nGdjq`L#t4@ zLHTP8sLVgli3%FT!jKM3wISpM2$bFo5lhHV-MR(|Yw$b_`7y-ENC1r!Q-sHRxTe~9 zz!@}u3bAX^jb~=r{_h!0nYjch(Lcz=%fBBRfUM^n6zIa%@r(2{Zo|ppAgsY7$ZF`YhC$cBgQKbb(%4_1UWC4DqlECS*37!XA2V+dNi?!-IeAU z1ky-*vH=t2VOybq9}Ca=WJ9X$_H)!&v4PmcOUS<_l=P%De;)b%fk24KwRS$L5EClz z(3Z20jC@J18V=?b7856^ID%)}CXIc6+egNgy*&Nc5Zu~3M~vUC%69YSDb8z_ve0Gd zTyY$pDa`%THn2Ixxwn3JqjVMb>hCGw#%{ zp{RL_!ceA2V%GAh8Q^!T&e}JH&Y3sRDSmhCMnc|a7H50NZoeZb<--Byd}rAHn5hTL zQB29s%6FtmytorjoFjW%vZb^)Y=f%29+xeFX;`9t*L^0=oDa?@LmF4+dCnI88NxMe z+NR3dg%r<$hpL#G4dQPu>)4+h?PI|v{7x9X(5|z76o%{*kYsef%)9w9u=W9hDtuZu7|M0~4P+ zx5f-%?WOvFbsNAHay~p$iQDZ9w8o|3-31;|Q62T0wMeiHbc*;hsM52e&QSI5rsYLm zlzS%Le?H}b+$&iroh>sVJ}<88A6C|aoTj|8q}W8ywTStXEFKWMEWH^TN$r|`Q86|% zNUt_|@k?NvocC@ui2+J)(UL%bJ?+_ontWd4Ssui{#$Z1=oBAVWvFDdzZvP*7e%Q&F zq8dwlc@mXcDgjAdGV^*v)C4Wuhy!w6mC`vR^qF_hkS$`T7UQ7HNmCz!c7BgGjwwV9 z+#ov5bi(z9y*o z$~S!Ztr$j`9mT7H&1K8>7_s*il3mJ_*98*8|29&G&IQ zd_?FbrR&5yE8n#^kkP^L5F9JHQpWI&!}cU-(Ak(aE#HB{YB}^eFUoyA_LmL z?=TFTv`A%`s0CU~FqhA%kn|hF=q}z5-gI91o+K-w#mJM4#Gcw(`a#%#OzGcg7~iyt zO8xx#GI1?LZOtyGCl>*E-)p3&ORloTDYjx4YtMqd%7unvBxnXxKJlPYvS;~8dA7EN z#dP+y5oq5EqHd2RA>u})ZIh3Il7ss}Fz|*we62w|!i2PGgw6@=n^IL{_gfPD$6YrM zW%dy*QnPU9ps`;jmEw&@gUdzXZR`T!>C?WKTWYX@tzm%&JCm*Mc4_gfk z0MvG0cMwRTSR_6eZ-gS@Cc{Un8+;N`8&3N1;*l;~1AR+C{+7iLhoH~vOObA1v_Q8c4Zs_hL4dF}yDW<_=Tk7P=&760m_6Y2{!{UbnN0!-# z#tcvQmm8jGj|FbxqOa?e1uMN{YmWZz!D#OngHw_zq7{>0KkRbbKLQ&6geD{{vG;n} zSd>rPDJ6^xr655?&);rM45hNev%w6OLDP6W9jffZsG_NRwdYDP*X z%n>R$tZQ>YSr@Wk{93QkeNL$I6!7!bNfNR*HulX2BCY|2&R5=2ZtuFc#))irV?Z#C zvY=BZPOJ9=MO}~D);tWLMzB&!rn&32yaTIv01+4GiMH8GKk4!HR^tkv+_#r5TfjAwUFp zu?_v^LHFmjcX4yHF*l$A6_>2N$;t-Q_^)`2{R^DHZLi!9aFpj**XmrvCQ|)UnQH4vum-rbI{NKc=|)a1LZZE?>1yw||E zHgOCbnhU73t@z|Df3r7aalhwkFVta~r|CuX{y@)$(*_R=Ut8pG?_&t5#(7S}z=uwx zYPy54ohDi3RRfyjJI65P<9|}<3WMcjGE1D!Gks{co>g}t!5>6pIg>6fm14@@0hf0i zblZ{BO1#uYvsWA7#9&z}PduE%)_^qa(le?-JF(ow(nkZqx9a$%1ct>ZbMaTkIf!#e z?>O7wKGwz>ZAgCOE^B%HPw*h6XO%zye%6!NfhvzR03O}XnZXLRh!u`PmJ~CrjJ(%4 z{d$_6yK)8IdCemVesgo2=iYzMCSTpf$nQNJA1aG_JO2n{DwcX36B*?^`(>pnL^_9M z$Ak)5VPi-fL0m=f%wR(Y5mw=6i=&BMwL83I6aCA889=QeTl(J`+8&I*IG`dfT?Z|B zeN&i2*qx3$_#y@+70TJ3BcL@~_wg7_2Z6DnybFpcLoQZCT;p`+gH|JZC?WD8e=ye} zMv3Tnh^C&O316Mu$J3Cst7^Yr(D$0y;(UCW`v0Tr&BLLJ-~a!zreqgF6S5^+vSb@u zsnAp^$}+N-Eho(OfP@3V=R;ioN{7ThwW26qZgPo|EjPc zUQ2%>xGmDtO)}Y0-=kD}SE|PXHhVMWoOv~5%C0X--bO50IgaZVXAh}{+m9y;A_kPr zcT-*V1Pl#DcYP-{b=|-HT=TWQe7AqU@%cT-A5TZ2l3W;)_J@9b*Yed82A5mWe?(M} zoQQ{i7(eVFF1GQi_sk;GW@}s;%8}l`Zd0E0-MXHXdc0w|Jf#FA;99Sn0;2xte}SvZ<6yKn-?y?IiL|S&CRj(bAH=?0*I&9y=;=}Xd0gD` z{z>4Eg*)YHW9>pSqv(RY*$g&z<8onuDdwseDz*h@OJ*!)2DjJI#^fE6$D7Nz3UNyg zaLj`8)+^k%iH?r%1#L$t|GX8kNxz;o-L!`8y8NF7{=T+1Kdfq0W-dB;-;0wTBMNqG z#J8Leixjt2iMidfL5I6d-Z}i(AuLhTumPyb#93uFDT`(Sb#1Q?CX#xL|1)kvS&{uq zejB;~1u3UANR5_JdBV~T@FSgmQt;T{w>~J;LGMDP+Y%!$e;j)p3H=;WMv)i9p(o40 z1hKpekmdt!8AP4jIP(6NClt-j{TaR9cJ0_g4@`e(hfzVLHU2N!_y@$IK7 zw2a5gI*TahKEC_R$?mDXDY)OGBvoiqr0M?SyoD;L`-6>9An$$}&Q>w_%afHAo9$=S zzqfl0&INvjaqwHqYku9Xd$T0ZX0_Il2yi|qbp5DbW@-@i{{A91*M*159$-Av!>Wwk z{f-ZSlCpi4O;)yhd<|s z3g%?19zt4w(_=tbWmyK#&(}@~(o>Am<>~w|^uDA?$Y0Pir$&>f;Bd;D_s~KtI$FnQ z8e87CM3ypZ@Z!>`Q$7yJTi$Cf^E!EBj#ZiLlo7AMu+#nE%?sABjfpoQ$WC$By|EOF zAmuc6jVtT(21x%Or@SAP0p656ceSx*^5wSX+|~J_^KaJogsbLic~*ILYHZU4Bu!AOdS5F|)+^~Rud;e2n;y@X zgrWmN%irWH9t^}@m7<4Gd%3^%hEfwL$|n;@oVanv&hW1mnI{>NZ`FG1V7u#gMQFhs%b27E)7xYFGK6h=U-;r6iw-g8~f-w!lf}EVw@*U?F08;73`kBL&sOhOjY{?o(j*o zEmq|~NKDLZ&*oX(kn1kb-RtqE;?*bHG%L3~jy^b(Qa`~%vS{gPj|WyPpCgSW^mL~lCq z_Zd=ajmW z!T1~dbq^Vb7s+caXZ?1BvO(!Nj7aM$_7F##YdhJ2G`|B-WgW4rwzRL~`tuXB(Nd?t z=q|u$3M;a#(Owy*X}dX;F=;Fke~QX&80UPh^vh%Th({gF})(5A%-&qPeZuyy8Z7IP>-oMRs1ggLfA_`)P0wTc`sit8_O) zT`;_yhFv%gO!Vs*fvTr?`k{NcIMiU4{_EGUi8gAi_@Qpv3}WKO(I#uXthb+<(1S(I z1%~7Z?`u67fi(fN6PrIfV4y!+VEs@hou7`YDyZVb)SabH zgn+`Hk&ub(>syc)VFI>!Z;*0LX>0wo3RF@{dXYBHGEQe#SuwTtx{Pa%#t!SxblII* z3*Gf3d&&hMBk$NBJ4Dj76VmT%4fKk31qbYg9`pvu8G2s(YXoeg_hd+o-2&uS9WbBl zE!{6mvS17-oysz98CI6@Ex=j7@WJ4SAB^c&p?Tuh{Qz%`+ZfmJ)%td~_h6#%(lnY9 z=v!?c?%rZb|FRj8TT?sCf(IPb*bqwFhgs+tUOZTd{PbrN|BKInec_Zn9P|RuC!D7^ z5UUQOvpx9&?>=%l*%~~P*oQ2LhmNY5JJVrH&fPNaBqBGu<|dLgJpU}mTHDqLmZ2ko zJqhs?$(D{~KEJy4_V_=WkkTH?oWtV@QJ^Bm23u`Lk_uOlYPblRA;O?jK zCYE8An&;1>V@bGgq@GFTAz<(hh2K&73+UBwhf{B%!wDcOL_Rl=xxxX zMrH93v34T5g2zw)5P{-QIr-lI%g@ZSG_{{10qR@4Tj0vU0Rn&3&h<~z5MTs1Mf0{^ zB!D%1buH2yU0ajrNWv}V1q-{*yKcoi4jx-!X{(w?hclgt#!slSG3MFi`HhF?XY!~K zW11pl_vI^FQ>-l?y?y2>DR!iyE?kscbHT>`6y=%fBP@Q&c$jziEv>B$y zSec#EdUK8~DddD-Yr=tbnk7NqG}cX)p^0{K*?zPu8ugAv?ly(0wo z0uo~TFw!~eslYx{3!rFevXPCv{-vJQvlx@^UtIHy^0*3Gyr<-K)6XgM+YIg#xU&$> zss-V^M$0u-+rwFx`rm^Zj`(*<0kZ1Sm`!yt;iXn6AWUncv8VgnIJ;KuTxss;XYX&Q z8TdE*x@6QJem%a>?{sXhYMD?pN=0>-tc^>pBta?z6TyK29ByG`5wz%Lv}}4X!8pcE z4lLKaFn$Vf4=Uf+^<(}{h`SSj;iJ4DXYM4Ef^1nj9e_<%v#L{4SLBqM{0>9vcGFfD zrg4!#W%*DbI0E62%0s7o-D``ERIGK(IBOxVuQf+R(%{$xhS(+nNPTLp< z>C?KwdxC^GsOPX7rOlH{CJbp_=vyNfmGduV<&)hIg~Jz@hi}fRr|pe4d|JnI%AR}N zn_Nphv}`eueRXexUF4=pIDZEYmEoJ`Kb2KJoZEx^_4)g3o=85yB@ zWccx53a8MEt!gXjq**Qxvas$CftQ)7^GrX?f^zhNQO>W9L7}1)&SSSv!M-eJurJG{ z5@Q20CdS+l7IIGt!!j*#aI6dtd@^m`U8=tUWG9%A<; zFTc3^$XTm*?^SENT4>Y%Vq#0&9-2mzgsCtSm!oaC9vY%65}q8Xl|2ahuy`~UEvAVlGxFm zL(8Q$h^jqf#A7jc&H9=exz&67b3K3~Pc5NwyH5(~=1@IDlcs8S{_f=;<@F(6CF488 zV=WjYbN%lDrLCX2E?sZ#aG|>z+@zr63wYL|t;O(gcVkCeV&;*+(wZpGlYsS&uKh7X zia0;SEZ!9hv4U~~pVgPypi^}Fka3~bX_OCDcn4_e4H!J0$i_3{Po2lAjAr<`zpII2 z)xqukId2wgvb>^TooVry2KiyU3&$?cU1YdE#2~s~bOHs_=f+q^37>t`#0)&Yv;yAm z#y5tUeRpGX%Giruom8|Atl6rw@Ux!gSJQC8leZG%viC@>QboRP0nmVgGcF-y6@y0h zpL(l`w@mpqJXknp#Yj;5!P4y3YN_G8_%ZgTax9W3#N1~*#B<1`=WC+a$^#4lsaG>R ziX&BVF|K`21aQGcR+WOB+&J)b5pC4`P>8f9PecW@i!oqo_P5WS=vVKRc*n@G44EL;_cJnE50iqHddzEOI;?W6+KVieJ9{WbR87D;J&XbJ5~g$juVg}J(RbM zo0n7BJt;zjG6&0hj_oL2gT;qBfOX3H6R#y!6sB zcn3L5dBkQeMV8 zj4sO*-O~4S|KqsAaJ9?Zh&`iJevk5Z6pM<-2{m%h-UxcmPFV(L7<;2%4S1usHhLTs z=Ya3bLMIY_exaaF(?AbHEPRQ8YA%Fy8SVF6Rm2u|ekQZ>E7}*XDm*{ex0*K}ky7xH z$o~7pG}b2RIRDPbg`0wq2qTZgv6K&*$dS*~CGpjDDX{-?tmYvi={~o)FeS(PlCf-q z{pe8&7MxXu!kgGR;gK0u&EGAErxlGUFJ45#pd$>w|R z{2^E45>lQ_-{2fWqTTcGuvUqv>~Ha?>9B$|cvRDSw~L}TSUPx&pNJt^*-F4XX? z?P&D)>q$D-Q4y$r_=&SEh+IqYFTw+|lYBwnKePag9nU;F{rgwWtCNtv_1Ao@)(aQZ z%3ml&4M3@GpNlz>?zwM0$XDw49het9goVbx(WWcHghZ+dX1Hsoy7vr4nWw1as>!&k zN%h9*{e>!)ucZ@}%8b7szC!c+xJ(?~|78S}qseCuy@BQPw`X*JwVFSRu<+PB>^X3e zab{+yku)~)K*3bgLsAxiPquP;5>oIg&JzqN?dgc4YNPLYXbIxOpQgFS|5$5zWN{;I`9@zHnL5yQK! z7?MZnpQ7RdS8v|>o#dDTCeONACVnPWt%S=|hq12udFlWTkNIs0WlV|<7v0|K zj4Lz1Yo5ATp;l=1d})qeQ+~7Kw;hwKF8K%0$&D+M1+0XLN+-R?ddB87x-Gu`tR*J` zd?vZxa>)9o7cP2Z2=X7QXPryP%FO)rVv%irdw8Vl%#?)KRr2Tu!tdRf@ksnNL+gQD zpw+Ghltq85zkZ174<)vay|W1)v2%zs&?wkqdWF}Z-0!D4SRIFOO;Vk4C)FA%g~(v3 zFFLByYzo&xOq<3rkS|9c@8*<&0iAD|0xlJSGb)4i#sPZHQ>PaiWD`ybysMavsjFe- z&!gdqG$F2$ znur?CPrAfrc21p;ZCJip_73oUy8NIjX85?248s_FI%)Q7i>CN?i(#gtKp9tn*#fYc zr{MwyUn-+1&^)T1ZhFzF=oL{=gRUv$`MBrs?^k&c7PoMudJJT%+D>X+H7iHSNKu5m zlQof6)h7@&8C8$Ny3my;#%=YF)qGZS%z|_oRvojycvufq8krh>X}UYbtr=D+fs@|t zbi2w1hIgfrs6owTo{fJ_Y+>D8Mi`}J!jDg|OGzY|Zk_kjsx>6Ff@+)BP%A|x%4~HQ za60@N9h8=gV;Y(74m#L(t(H&GaKsub_vx}&{o6u z_9#Wv$wf@8wxXf2|1Nx{e_d@fPUHD7^D8&gvZrKLtzji?=vhgYQyr2VPqiw)dw)l7 zD?mqdia@y`W)AyW#a@%v52 zQddie1`fcvd(~}8=U&v+;7CI4lO9b-l|?P`8nH|WEP2|_VQ7BtLo`P|Jqc^1$iEt^ zY+0^sUz1@#ao8(R&?(emc>0>$@2U&$D|&dN2gK4={_KBQ3e1;Y$H;$IYQxbR3=Qkh zCHN0$eI%U!^^j$!G)t1uv@<+o;zd4QYUZhGzGV^=E!7KT*1`yV=nHLK2suew*}A+8szY6 z#&&7}yh-o(+ZNs{8fsa6^$zAEou)aD`;^wNQ>t$uZAg?JLwHHBnFHO-0-NmN0Szvt|+*`ny2c7{%BwyWuI9Icf z)`zbikYk`{S9bdu_6hmo8D+T{O?rBN9KzTniYU@;6X~;<$=sW=9N-k^c{|6gQja~z zr_qEWf+z8SV=>Sgd8PR{0@=N{*4tmZvoBeef+8tMf(+d4-XbvcMlXJ7uB!FPRYVj{ z74uaROp?4dEzb%SaMtb6SI22Gyib(pr*>#!r-z%rd0R*BTiH*m-iScu$6y>9V^o6y8TEDYT+Hzu(PX#>EPgNx z4l99U7~2s`BJFsYcfc$#R{*K7FUxL~+eVw28?JO6AlUQ(}qpJe(YB7J29|5pagdEQ78dg25s%QwGDhTbYu7W@OK zJd`>u%gv!aBG8w=KjwvWueNyJqB52bxa~J0(WRw0vbb5aiQIul_`?pc;5J3k=7~D- zZFAO_9v1gI>k&V*H%ar(hjqPV%*5J`tWEMFB%)eL?wqdNXKr;TE!%!R{@IX zx&B*EkU_ti-TsSw#&rCeFuJwrTmWo8w$FVa1bSfyhk`zI0U2Wx>6Mvaqk3QgQLg;b@V}}bP+wAc$yYI_U$dV5z4IS zf70MJa==A}r}4cgVKA%yWcI_|CmS05E2+smK zcV1HcJE}9edugxg9Dv*;l{y3=uW1qLuHKksG@s>CjG z{qSN>otWY=j|;w#^ziE!r^3l^G*LK@7nf2DE>GIkvz}A2Bx;|`a2KICyr0Qi__^7d zT2;1=ena)lXp|o*9r(AFdYU~7wyviN&%VbK?4?@TGCeF&N1BPB) z3VIXc40n)l2k_y$ltdl&t0cUkq6AnYNP^%z?I29{X6JnCvy$nZ|J2E;qBdy0dRo6W z_96X0JGiqhCm-JnWmZ(-Yp<(Rc>Jh$%;wS=_}vNN&;!P1kwnAKfA6zX(4?uWWQ(pE zF|+BfIJY2M=_Pgn<2;`-8AL96znu%;e3W4M#i7@Cpo>L3@KJD3(DXE-B8>SpbPT4) zuwKu-W~7el?i_$%WHquc3mz5iL~^7Y2%it6&x_O0udLUp0vqi?wk-p8EoW%>`UF)? z>eXM|UN%Ud9!8Yu*wnr}Jea8uq;;0z|6Jc(yQ9I5W`Jq+dmnaEjUg1$ zJ2DJ^fhZ70d9S#D6lVT-sxFo@Rcz`R%}KK~A4y(@J|lpcXo3 z2N>H_ti?mH9o#A58x6V#kN$T|Jj8uo2jrOxrpSi2rps0&Kv&PTL9ZYfm|nvE28Ipg zG4aH^L?YROWbQ0}$l^=>Y9({z{$G_lkBQz|N9FbDhe~73Hc2~sD%YbGvoud)2)EU^ zyh3j_1$k&@CFRr{{!ctPdj7u=g_q$1hXkvmNJSXC5(~->_%)?>pmQI=PcgJZj~~Ft zd~vx4Ce+<5QAoM>iI&>zenG~~XfEIuB{n9LoIQ<+LMEw!SB~rL8n?$|d(KrPWo29| zg&yiOD4vKSdmNn~vYjol?C`R?EEw?wrQQ}LPis^Xa_?^S%NGY&)|@1+1NQlR%&lu6 zZBO&gJr9^yzymh!b?N^isE?BXx$16c0Cb|DVm;q56Q#C!a%?XuI)4u*or9ETAv zfwRTt%C60Xh~xy7h%&orUR7S_VVULKiowi(Hf%vg;*Y1{^cc#8Qi=kv)dA*eN#g%b z6FO1<7bsP`t`8=|?$Ccx3ow>t1o02ca^TU1MuDd}_!1d4P{E)S>O0mug;$)Fu z49utbY16GcG%>pB=M@Yjdd^-kzqHtz;zE4>!-jwH`PAtC&o9mZRq>Q9_W2Lo+xmYZxpkqZO5_Dh0oN}2y0OfyIY5yBJX6|ZBuRl< zKgH*AC6Zz014@(8?S?Wjmz?XwU@e+sYdGng2Jg)6|*>9vT*{Zoh80qVg$dW~GYNcJRRQjDz`W*ZE-74?0g6 zeTEJ?39C>4|B0!)2MX-}LkIk?U9#mips{Owuai^kvL;`$;TK}1*J1Y#A>WsYoE+rF zSYLWsg7^=K_a{#fyDybK>*vjPzn-wmtl$}p@aFt)X2+jl4LZ^q1|PK-tze2vY=Hx` znlu!0mZRe)$g^^37yCeNz-11`vA~G-rj$h;32-*<_5yPhQ!}0mxJ`MTo=JYvP1-R% ztj!;XY|A%IsC(kIW$wKpHN?(r%|}OTj?*p7t{wvl%}nZG@wDOEC6;48N+x&p+zaz2 zV;Gk=4$y~6v|@X-YLA=Q%cqg2gy*lg*I#^IRS4-hO;V=oWUN? zl_$RsAWrl;ZQhX)B}ko~4lp?KAJnOw!n%uoAgis|2InV75#5ETi{+JIMEHMjZ)gKs-J$ zaZC4U)A}@rYx3{@=mUH3h%;C8O5tE`ei+aixWMYj2E87G&D;~<&%1>LC^3SvdIl8F zt!ZG4hm7v79|=<6W}T9Pvpy@kve5Zkl+46lpjVU8d=s_ALzMzkno$P`5w#F7`rhwr zSG?PN&?W7b@((;RGly?k+Ove&2{t>@_tG7iYSZwzQO>Zd=zJ6j{QN0XqTqVD(LU}9acl)R5|EpTj0IYJf0s8vC#cb24z#g>Yyt$s zA@kPLAi?;D>+g#9mz1toEL`|-S4UIdVpgPGd!TwqDmJ`0M;~ki=#_ zi{!r3jdVNjyFsm%P8T-+ii$Os`y zIqTjAX)?v?cE=^icDkbpID8-0a>HK%W6p-lT1E^XaU5-a`?s=0y?whfYO;sk#!#>& z3)oL&>}Tw?X<(oq2u3{^dJjF@Y|?d}PT(v=<0q7C7fxG!99$!hQ@7FR@AaK2XNrVfH>IM`48<@ zSI{{ChuA3`A9W)Z+D)k0Nbg)F8&5dsBYbN$h`lxkjt=Fe6VJ}mFu-~Gb_4bw!Lwx{ zYZ`M((U>yu>?3EWzH#aCXW`R5vx!>qh*?+QaXK%AVTx>MqP6F62YNR$tSwJ#|^$McM%=!bmA^h7>@d*}m{j2*euWtz0z9CPZhXJGx_2S!bI^fT}^z&AH z_Ciq?ML*+-v+7W@x%I_=zL5w~weQy{jG`uY|L5;{XRe4+9Sk=-QvPJ0WNt z-?Uf+^8Nv=+)?G=ZQ*azBI&oZZ~=CO@jCV8!*ap*Ri-Y5CO?S-n7|Wz$d=~sDNAo@ zo9K>582{nQnzVdv*G{c zkIFsm7O*-Pcgo6oO_{$!&mxrmWC~`tG#s#7VD=yU5M)vN2LC0(vhVmzqls!qz^mdQ zL6f0IR$z7skVe;bOtCKDvE{-L>rDS62t^svCZkB$Z82ay>8}?oI|zH>Nt|zzmyhLr zN03t!ZZjwiQI+~EG`x5zD;*_A;^45HN#iJLPCqjyd3&pXJ0)66{6=Ue!|uBj3EJM{ zN7w1XXksRL9*e*)O52rsUbvbSemRQ@XZjgFD~pBC@Do7kyz9A)|KMsJU=kz*8%NF$ zQr#qec*0`rJ6lA#`ZtPBx@o!lGcQ&EeI}(6n4;DOB|`c>ry&%GzQuHgaUpzr0ov_M zmb=kiDnC-UW4qhiEG7Jy7nPCC8t~%k_ef-4}F_mbaS8d*~q-6sUivCnNJlsiM=MRRK9#F63YguIEXhTrbeT6?^iJ`rn=AQ0VD zG6fz=Ut=8KeSy2l6n^+)@n_kcx`{FOqjql{qf=u(Merpko{)wOBH;N1A$UF^-KpXs z6Lb-sxEuAC2o^(9xh`U|$m3sdX^zO9(_pEjV zTw!3Tr#E9auyz0&le9`QVE2@pP+&vqv;! zayL+3UWPoiyZ?swWQIcGe82#$L_%vS68CVWR5xQI-(Rzy;6FWB|&RV`q28VUr^sI9h^C z_gE}=(BD!$Q)R3EjkWfnX4`v ziWYxdGT5Jyh=9{zqLm&{kA7k2$7mm|LDK!uLH-yD@1NhdgnGf*oySicJf{B29A08K zC|5u>rk}tI77pzzQ1S%SW(LNuCFl_TSOIk2_2Q@2<6#`6&FO52ejs{vV90)ye*WzP z0)VfA!90frcxAK6x|6We>WygRl>)NyPXX8f%jt|=9E{cvItCnx&r+BT-(bEMaS#5v zFo(S@q>}n-0*nzoO4qWZBD8ywp2O~P_K#3=RI-0VV2;Xt&8a|-*JPV%0n@VZVA1oc z4(@I;-`Y34Ym5cS%z=}%SDQ>4UK2v07O%L!~>LQuW?5r1k1VH z95%fc?Xab4Yt^lqPqrdf5v+Lo9;4c^mN>!VN0YuU)%INwuBI|3Lz-2e3oDhfVp(cOH8(N64qG-D{gsoNdjKc+>J@{_@dh)3>DU z`zR&GY9GV>*?300pO16$pQ%2Xp8F;kT_;L9Lt*?L38wQl0cYTDq%drq{^}4rlP#C6 z{ZHWomWZ~%b&(Qe!z+m+s1bC~(E~ffIT#4|5@OQ0nq2}byK}J~F*VC?bBC8+!x&d! zuYih20X75CAMK!a@Y(wDqb=|Ld88!vvFb^HOYd&)B5jXeY4@CkrdXTodMBq`_ue$HI{JqcyN2&T&8{Jy${o&?WKvk7sSXx zUztAz+~uG=$%Gw(bb;B>G9n^XR^$Ycm$kFw-yW`w{>pzkeAx4&I4-r9xF(ugj7d0` zZ_rU2tT9B7my}hy*o*!`V#UTwI+Z;I#qYa@K_j2ca{Onr319dW9L9WQz*nCvzA3rB zRDLt=e2Rh&G%9=+OfsQF(B3$J=4uAWdCu88MMzt+JWY%%=t+PQQU zvD+6#`5BWf+`n7%=cEU^TgMk01WKN9w(ht^S7O7%8cEgFNUP%UJ$TEh=&(CzC|6bC^I`CTusrL1PG?7pDvo3+ZB z&x;xaAN*!pF2ZO%h!R50Fs*V2S!WuNNp%tsKUEj%#Ti5+`z||wUr(2|mU=d5^Zi@v zpHGjji!LT+*lku9UgQA)lvH7k!LxXb*`r0EAmb6?o+q}7^T^CR$CWdZZMd&2R9Ya1 ziO5Qcrq+X_hSR|C)jH_D&ucQ4jBi3Tp}934O6K+jh>+$-rrkP!%)ysej(_g7GTx^k zz-R^e#}-4wz`9$rDH%BUB=Z_ZyYZf=n83nuzh6p#G}#dZ-q-S7)l?me@eDLeC~NVAE3EiO}6nP@vSS*X9FC; zQFiWU_Zh)S1bN2~L~QFjhfpt??sGboPHl;UsyM1Pn6}XqzPGc$iP<&k?jQG>$XDRq zU4SlA;8}!rC>|1q#Jh!HpG0e*>=E#+mL_$LsON zdBTm4+rM3YP6#Wo`+PvV>Pu~K0pCB_!}&ICx=6#{ zc7A{}gntS{N3BbG+da9`<dv$}bdXuq7kG!qJBd+ju z-4G*OK9hrWBbM#FPqH(T^45PX@KZURuY`6;K~J@TRd@JHY{c00l#N|2ZumarFfHJX zNa8=3n-Mc2kZF)kVe$u33Crh|6sQlm>6YVi7rEI}9DT<8Frc=Dgm0-sSXriP(YCB9 zwy&G~vd(i(b|gyo1t2<9PlDFVHTY&br^e1*o39Z#3CU@$M?f}Sd)8GHr@(sLFqX9K z@ReHCF*6n=tBSGr$o%eJ(DFvFZ8l1rYnrA|06$Z0oi8DwJeCuY*9I(kt{8p<*IB*` z+;zBK#d5`1O>o8lcB4*mFp})UsZ6xAse-EZm*J2c|1J~}hx_2!NNgo199nma${hH-Lg4YMH^{XaPurP-2-y#kw_Y&L;(T|} z%Aj+jFffZ3EtaBW1B&cVgdti`_%Jy)+s$j+E1A3jX)4fUuu0I6EXb9#H39B9p5n#C ztW!y*_Bf?GE4<#fghjQ3ut_&^!21>&=@Ji-uB$JYsO#TYw)Iynmc=+Sf<~YEa1Q3JfVpiP(AWu)vJkRvwHC$h z*%1>Cz%rc-+2LlMd?@nk;xR(+e=B+m&H|*?571hV|MEew%9z;tjOdwbfSTbCk6S() zlv4Ww$YMUf*v-NQ-6q<&vq7dOcoe~YdXA?>BkWtvOGWys+v$42+~|7Om5-SFx76=V z&GRsWnIA(gYEZG5>ooO%IAg?;SG^BqfFf1BG2HxNGCQ#9J}iJEOt!yi;=@Xq_b6swM6D<_*z#3%{*c(nO`bN5{7EYK#3JrmCcz%tslc^-DOcUH z?KW9`;w^P4&&Fx&Egzm{Je4B)q!UlSt9+@3ZExObt)N7os=TDWkVohtw;|xwOYGr= z7~!_k6dvBn&{B}ovijO6fI4I|%uXUKkZe)~lJizb`%r4Rze7uZR!jHKp=;blO=h!* zbIkq}aYPj5*sl1xn^fFs$T7fFY8Ks&M1Q6DMk7xsiuN+!b50FRpH96qfLR(4r+NuE zQ-%i2s_y(OWic~@(XAutJDMe&GZ~iTz9XMHohyP!Ggq!~B^h(iV!+iSK!E3yGaxTw zHyfB)f$#r8*lKo57S3B4fE}q@)>%nB>xgz}0kIbW#%>_%{{9uWR}iiR*`YT$t1ZUx zim(}42@1TlU1f@R^R$;P*x_eMPjr%m+wly;l(bQqosaX9OHJLM#BsF&UW_yP&TY8c zN2$xaYN8;s-0KH$et<6|2zPTE0moT5HO$}GjUYQ!QIbo2+^<3WyKW}nONSR+yJjr2 z=r&{mpuiIkoPkDNLX55(oVNjFzflK5_?+4e(8m7jH$oKZyO=hX?|Xdz=4i2(;kSD~ z4=@g|ZkCKF%7`KEXZ-PruzVQtqrKnLqosU7q>e*!T_0jDS)S@ix%$xR7WD&pS!uC0mugIN{eW~rL^=ekPR3o?>V6) z!pKspqLEilH$i<&($(9!AN0?qTXs)EK{$?4C31N*bZ#2~2N{Dy)M#;U8Hk^v$W#a2 z6uUa}fdrj|mb{LLRs_6X6H71ObQNXnn()l$KmO_CBV!w85Bxog``LFh25&Gz#m|%n z2Nd-Oq*9)`5^VhpJ}_~>kI#bN^92$|^Wgt|nz8G+DeM=@jQ*tlH1;65DR+Z`NFpOx zhnIj@;d_1(Iv4keS*AN^OxEQ)aiA(ieXe&cuy<4e+ESojN&$aPi@(lM)BC>swcufl zrw1xwmWA^ZFYbK=r4RmRpgLSEt7v2!&3*{A8Iq7a1|5Sqp)_)%*sYcXvH>Vea=2(% zAWBl+Wn7niJ@e#2-uBWEn&M+c5HJP)451`Z7NqvH=z22S z$1794$VPffJu>S@_gksJ&}*e5^2XBjn6yds3M&8DHV@QzJ^89O!i0otNF?LP(7yty z3EPC9MZn`l2UqC{Tj0h6LXgJ0i_EupT8{?AShc?!(6N4MGn|lYd6}-f3Wy5JPraIQHx7uo}pVyK2P- z2?4VRrcBuHms0Kq9sB#v8>1RhYxdDiXd6;FtaTmDg@Gx1kl9IG%Qh55I&RmQJulk^ zsNiRi>&VyTC35${qZA7!FbsktBYu1os*Ls%V%43QP3SVDX&ZdxVI?*=I5^PfZ<1qp zgKvIx3jGkhl#;V+iv9g?nRc_=q{r-6*R#*V-}*+IKB>-_1-uM91}}rGV}lVtnVce! z-yS#5sgjL%-W{w>*&2bCf6G4znP%j_y#_QOi9J_9A@F1YVD=KQw&66@oZH5BK*&}y zf}Dzdt4UNq2!m%pF)-tc1M?aqAh;|nH;bY0?_>j$gh%VBKfJG?9%&YLSC1U04|rCK zL9U?f1vkEHw;L2R6L`m_^Uo5C*7q&TTp2FYT-$IWjL)w&Yl`uCq>Cm1&#bPb;ZRshm zoh|NIoWp7aP>&=tLSl4eH#7y!$(Hl%WdG$4vskChk6kF4EA}jZq_^&j4@vrd`<43Z z_VN3lqA>Xp*9t;*9OLx;x9aq`TQCCfS93V>tc^R}GZ3kfaDfYei*x<;gYWwen4!r2 zjQ}bXb|AJH0iQ35?6My0MUX49yC&;B8u+{|&5fS(+VyB7tsk7M0YNW49dix3j{Tw) z^11k)`!3v(dVZ^(lWD6`RJjbycx~#E_gVUF@!Na8kER>)|A0-QZuCFmRR{GI0-8?T zGfjGS@ytP-cL_#5?7cyOix^pZ)-*erv2VjsyhmJ8$zDzWUNSzb$sY65{FNpUC%iN+ z!}({(l&TB1At;#tW*?NQ7U-izc_IkDJ}(B%%%3nnuAVqGXfGO467zF#Q!A_Nhk$Q* zCioCl=`)pN`AfOfX<&LtB_~@LXG1;xOK56Z$66*KPY8;!f7Z$ICfB+LJP&rA~0R#8S+8u zgp+3M`axlPuvd`bf>ciRU~ZT!nH~AmWHnHv!=_MNNXixMnBG|whgcP;6WxZS+pE{A#18pnuy7nw0>8ITXnBB zeK}H?7Yy(6rh!Rd3YZ2s0XBdg*t6H3CM3oQ??yDS&muT(CIE}>qPslnvKBmTa4b8j zVeg(nF{9e+Cb1a$YeLs`yCh88Y7gTw{CYqCTCFHk>yEub<(B(aN{c!=o*a)!%D#pJQYnUShjiA`B@CCYYvQHjKU$3f|+Il)Wt+76=$-#_E4M+5Gj< zRk)o@m3K+HOLyU8RnF1vA&)w!9+EJegrcO*M5T({YK5Zo3Wdp7d9fy-jQ`dV3hEdQ z)c-p(7&4-;Tb>4wO0oeQz?+jVkX=Wc@bWLEq4>1R3I&O+Lf2HN+*d^l2R~#BWZD~` zmu;OWbg(J{e9<=a72RhmxBon{K$4z0UMxY6nmzPaSsvGvxQg$GU1gAr%H(a;Nb@0 zmYc9cmA5Hs$2&!kNsD?Fw`$(pe%#v}94QvjWcG`)1TYU;{xO@Be1@IrWQ&@o)ENNU#bbW1x*i6JS-j7fIyV3j)rB zr|m*S*=@#s-?RG$;BN6cVMzUI@z)_6lSXd7LFdY|4re$S);-5Rd>&-I^D(htjSxl{ z-3ejy9Q~PMLk+y-bnj7aM!Km+MxKR724+)OvL*Q(d`5wJEfqnL4F+AJZ~@$?Xe6yq z8rg=T!@iy@mL3c*Be-aA?m38v=*2*;v(agLcsMA|;*F@t@5CmwLoa09f(NmQ<#+A%C24{)OE)1fZb_EdO1pLjw@3z(WmW-&$Le`s#H?e974VtyU$$rsRk zLF^P(xVm{TiNfF79dgRJQQWV9oVzg`&7O`Q|HD$-e|dxH^Imu4{Xq-i3~LE}(X9U3 z=l8QdoGQsbwUl`J%9vu--A8x$XAI6zB{@yT917Nx3q^pp{JZ)yGLhi7g1#c0Ozi_} z!QrJXr1Za9aq^&$+K&}iO5R^T$jaD|5+rIJqEp-tXrv%pklwq%j50Lx6L*g_cM${h z^XEc)xV`Kb8wNIS=}&`RmLlI{A1B>h)&XbqH1pcSDHytUxU$|T3ePTb9UG+A1274a zkr6Y{obqYI7e0PMJjlVUizj2xa{KKqG9;@X?)%NDQ5DZ}tj92q9As1_dID|euGYez z|Jh~!wbp8dz;A{&(i(oxzM0&HTWowigj@gJvWT3Cphl2b52F9-L4p4c7{=cOciwGa zL~;@il0P6wT?UIiMQgqEP!tr{_*5H=pd{Z5q9Arr>p0K!cAypIDBrZT4rTZ$q9ZSk z-{D^^TaNr}o2NwR4+lMTWJh0xjbj1|lF~N%&fWFg3F_1=V%d%<+S>~~)k6?<(TBaS zF=sP@20C)IOdawMY|OP^dj8!odY|=jSh4)rkCzzyomhx{O7HS282@_xAm&|GAmUyi zBXN;P)j=G*g$yP6yOVH49K$^lcma*;J$TG3)P$H~GMMY7qQ+Q|p_$&} zXFjH?p&0T;zi{ewxv*Yi^2Oe1Q&Y^JeEFPk?n~t;ny>%;O8EcB*PBN}{r~Z!?JA+D zBs8)nAxT6`$r54;k*%p@i6qIA?OjQ>>_vzvB_SqzNQ3OM@5I>mZLBlnJ@5B@jXvLd z?!D*y?(ttv$1Jbc^ZD4G&v%-g&9Sqs3g^`(bkO%Ya+`;$l-uhFzU*DW!)Mqz@zaH8 zwlKSCadr}9)l^g>;VjPR{s@R3C>1k;-%a}8mTo9hRQJz zh_X@!9Z#V`(5NH-iL>)qL>2Vhl?8L^vbpNRBY$SXONZ1W!s zqp-dQ+|&MMz@E19nS?$j;6Jr>vp<#ZWT_+ptVu(+j5(SKWv>!u^_tH$BBxd87-hbL zXcDvXv7li=B&qXg_uKD6A1}DozdM*EzdF3+Zh` z&Y*BucX>`X=oV#_zqdd}f{Qj%ub>LyMaRW!0YCI$r$e(%rVm`K5h291$K1Y7bd8&4 z_9$W--S~;K-Ntsr=-qZm!sLA=>dz#&+#5m%&3A6t%YIjQ7<%*kylGuhC$WcR=6Kz) zzryH8_E4ATr~Z++micpLE4ypT!f{Es0q)fH$F3bdybo|!+ZEDeeYl7szCdYBDIT8i(Hmz2*(0rK6BmSTs)Wvem9&!M@W4r!?U^{Ohko~cUoy@txj zGzLJKpmGfobYU!Yy_`ZsFYleQzx#pwd_F_rYnZnaKN$Gj@I7O<3gsMFqK-xv;V$sDj`4m2J`0f z=^cPfc2hnz9fnTkiy#UIAoowhXi!@qS__4v_s7BH0r<%&9TY*tkO^@{lX^XBFIrx} zU6dlo5CF%QMzp>Csk&E(6y^MpoI(M3o-(t4{64?i;G`sInLPLyN=y29?e} za`{hV=11s7{pz9^?SJy59@Rc~{)@%(KPW7*n0h#>$E=jFBm44ypfgPO)QDSty+<*e zvgIvxL=Cp0iQbAa=lk^u(z^Rc@rMN?=UE^Wi24=IRHC5tmmy7mXZFJO@qgAl(Q{v`X=<+{KM0VZUjaV~xTy(xl@Nzo-9H zKkV9i-!8?{t9A!X)4!R-9>hCHTsY>3t&;Bv8Tk*au%P}dKfBX`0Io6r8%8h3KyCCp zOEz#89jl52>GJnuM0l>DTUUq{yEE48APsY937d?*&8s_f5p6-Gwk|qqg@gQ*#d)-C z6wQ#SUG-4?uw}G(QKXz+In_J&)17l<^?Svcjs7o2E(LYT!Y3BnIMdqk>FNI4$JR#5 zk+7*4qRV%z-FgrJC+)i#vL{LjyD$IT@9_e7Xslb2yo2Ad<1BkrcWwlu&(TBMTV{8H zudtvd3kkpq?gsZ3cb;`3lvLl!EaO8^6{89jMa5Wy!PL31XeA1Ex@4epJ2bLQ569kq z!?T;mm=sitJ)KZIQ|Oe~^(IPh*R4*&>U11K&qbrb!yLoJuiGgp zm+8yZWFL!d2n*u>WD6>B<-63sSGZa`b;KN&hMNFJnIDAFas&3*8v&kou*v=2e?@mZ z7Imq$kGlH9Td=G;Z|$n+yU4tRVePic2QzOH2Pbt`wM8ADt_*a|vyBKrE7BKxM39$- zbnoa(%&UseX|kkZHtioLgqsR_ha(@t7aZ~iI|BCdD*Xg`5R-jczabCL?X<8sx?asm zel5YT!L@zhsbo;>at7gz2=3sgOH zVwe1dNI%!~_I~&D&a@r@t0R(Lw;Vc!EA?4=+$R(YqK~`rj+ot*lFNAw>dBz!rFcq& zc(MKgN%?XDx&I6&v(2@ToYnvaX0{Lw8hNqlCLsSHF-rU2t7l=pdL{!xyQrG6HE|be zX7e7C>l~-ce;6jU?P=2Xu-jH9+tV|luJfkg)gQ;TFNv3prTO)R6r84)J@LER6#XbR z5jR!9H^(Za7l_?{)#}K9u&N1p#un@HF~fpf$nb|wS+6k75dRu%1-@^L^giQAN0JBv z$^<%e^9{%dN^iuLJh3$E`@O``O)}pyD(yXcvZwR#pT-d!XtDGZCiN7AvM?dbe zDOZ<|ARddUk?Tlunesg2F4-=d&{1uyyeSk4$uIxBOw7G(y_g#%`)iDQs~{x7O?R_| zcfLEUzdfqbMHY7X@Nhfy+Hojd0L?U-#HaeoQuvRF&EmNaQiFvXtUr+_?xBz}RlosVgqzLO0A=XrDtzcHuU_ZR`kmLh@G33WpvDQP%!+^K-3}ZI*<)7BX?yiy(aSokjIN!aA7>vQwzq_lwlW% z3cC;sdF50~h-nbOVQo}Q*U}EveQ7@~pX=yby%OHltCwTvpkHR+^eE0frsT5XYDkfe zAd7$K&&lnEdb(j2qwB)&9af>o0~rRuTEd=UW8 zL1`EVFQjuqgXj=?>lBLWpbTT(uFQ@Qr$Y@GoHTW|=>e+ML;fLVyb~J5l#(mU$#=&7 zN#qfwTgOnl$3yN#JNB+UIClE}E>DridVeh{ z8DVmlBix8->)CS#VY!}s3(Kc=jVM*-n$afcQ@sKx>lf&ksMfiML-dJhcJTe_Y^x!2 z9w|qePz{(%i}IyFt{)`iEH#~DV26p4RfM%s*y&<1nY!LRnvhlf8nr-w7wEe6KP}!K zwZ_QPe@czeJXGA}`63YI*NQ>|?v6SfZaqY`35G3eUE#SHi1X)I`59z4qKR}Wajz_- zP2;^-dxGtMRr%c0K4{!!elCwQ$)Py)lB=tCjYgrstzLZH&zIg&hF&U!YMnzR%N-L$ zi?tt&mE6eru|63@Wz;ciB2o~QNQa7YFH@=kAQnbHF`=f7(CI34+hzs%jiGdPE~W(E z%u0`z49ckc`?Hwp7ID$xnC-#{I!~loYfdc7udg?u)|ofY7H=THAYnLlF%@+t>=?6H zb3g|P=}p)~jzl33X`5X<^6J2=S+lF1UHeSK%mF1TZmXDB2*-YAk4$5{R z{av*+Tr&_XG)lrCm(WrSfOmHRmiC{A{tQ$fV{n+!8cDCQI=3AW43Kk6!DB<^`fNB~ zKsDHC?RR`ND8CxwxTeAm#u~P^1T-%s{(1krAY^NXUD_qy*z@lSUUGDp5%`j2Q&ZVZ zx$F|k+`#a3^wenDv3FmGDTcrz(!BhQL$|;>sITN<-tGy%RguTkN|``ilCC?YA>1VY?~z zssk@=nq8OQC3z!X!DCjz)P(akI#NA(D=zCkLp zumyv56;Z+k=c3TVwrL73Q$?Itw0w%D&+6-I#cC}~Olp4qBqlL^bvjeIa7@Fdl|x_Y zd0eE7*TIn(HQ}?tb>Q2&eqe@^ZWE%wf+QI#`kx_P26V!bw)rR5xc^gEk?JF8FxCDP z3M^u5E1=xq1^}69^ZYCCff_ZZx9*ZOOLBWV`owqa#>Ux}aH$R=Hg~Wjcx8$)9lM)< z>dEivTt&zy&eVS+PZ#+(J>530a)jKf5B`4Km(WRqOL_SgXc5=7^S;_|f3rcnPFbaD z8A6S%$j&&RnSY9VmMEH)EXZVF%y>v;L^Nc;9xgAYXlsN;$#Q6&``wZL$ zhn2pTNS1ftd939otIaH?FAP|z>Q$dTR%`b(-L&LSZ1&m`)Z>mn46$@09jLw@JR!jsaJ=r=(4So0;J7oK+@%|#WIj@&lIkWpyJYPOT_87`% zL4&wBeNEyGRs;s34?Q8!${7sdoN z!OpXFf#n5O9A^OcN(*DXK53U@aZ6uM{0{9rEu3Mw;Q7o&Ar|95!%9@&)Ta<6@xEzH z*#&w3SF`@<9pKfxRYe=0k^Ufug7iYLW{3kwVTkAe9q{>FnJxgAz&FP&ht&-`%z~E( zWXkFTYN`>wIap^emsblo_)vwRmxmsrjyU-=y#z0h(H9LQ(o#YV3*ckM7hQtj?Q0XN zy#zmy3wcA6IdG%y(#&9|Uk9WVlIad98WL6duSFfaHSW3_(?TDca{G>%$9`QsT>*>^He{;DBDFHUGUoH%*_0Bs3 z<^S)u0Iq}gV8a2A)Y>$0+wQvfY07!D=l+eEhtX$K8#dZ+6{p$9%hr@+Ez9K1+|23j z=`U>?7qd&j4cuBEzq##qGHCh|BMErH~m&&_;szw5Y!8^p7X!U&6EnDLFq+s?wQI>#leEgON-LL{{j%K2J0nT zgKR2u@>0kyCRlQKjm3$a&>G$o5G^C_(pqtGPF!rjn{NQ52GcL5jC)=9h3T!oppkIN ze`8-g-<0V>>Y7UZhfa^5_5P=SsW&qn-`4_*#uv6RFF$5h8u3>afu%RJqE**VQm~Xw ziPZxh9gLzzQR87>A+aTC3EZWh7m@qwQOeIBI;Q=tn-xOUkU*G=CU2m6{Ej>=1=;eu zJj`K(<%{Pd&)jc|jSogmf-FnKYAfctL^61Dkx%Wi<~E$pI)467Ga^Z^;(s>p+2D?! zVG4yuTlU@GL+6H%$N&xV3mdDMO%*<2)(aR1=Dck@O9ihE=lORy0xOzKo5N6}s>+z3 zQZOTsre*7NdQFV%dKsv1AVb(61ruBr`rEolV>4gmOKA2fU5v!8t6)4tXGU^|=TY*x z&Sdj*OolVew}e$CC`(h_z{a0!u8-lU{Zz9QAUUI0wh(J)4srB8W~A3i$L{P++w8Ii zR^>8*q!3KxF8QkCGJ8CiR&Fj_o0hHn)pt9q`2fTGmXhk@GbUnAp4V|9k;W>q;a-hC zSNp8JbgVX(3WADnPS=q2Dn#0`{ge4JNN+!8q6h(RTjY5N5CN31|F9!dhI6E@FD(<_ z7l4EzjLKR-nmRjUgSfoDU+(a(L1WidoawKyEA*-SzK5|YBfpy7T{uq33iI)zcRHet zQ(5qbpn1x2TP9>`Y#h#ZY%{5rKg!RmZCegKJ5;r^ADk7vW9r^7xw?#P<3cr*%!(#nZM1sGJ;e(^`=O2WJ+3 zj-^(A<`FL?abCXFXM8r5jT~#dR#kOqqwVFLi0)=ny>2|~ai7=8zUTp`L1=0`R?bmJ zRmQy2^z#WOZ##W*tzhx^9llV;TSu8@)MrtMbe2&jk5068F%a|#y^iRyywd6Tv~T6- z20_+)9bF->JTl=1CKxK+{08zxgV8V)Z`&M6^{0kW-Pql^HqPA?KJx1#r75Y>A}+Am zTrDUh7A-hqPbXlc8D72x8EvUnCU?BqYXtpQbUk;u4i@=;5L(%R7d?08meQR@V<%>G z@r&~RJIJU<&1aK2(DB{=ACh$3snP*px4}SRpnEmo%u3OaccA7H`7H)dJ@86O8{RNL zXBlm{pX(_pEXRI89`nu%^=~KWO%KEz{^l@>m*@-9?oKOM<6hAWr^JF5Xa#R~I;Mn9 zI(i78L+devoeWt~)ALsFkkDbq39`#Tcq2p@HQn`N=okyB{H=5INX|@)|UIZkyw1O<8csruDD2 z?KjM^iOE6y2Rv+?Z4_HYRzkgpxi~~ZeL73l&rLZq{Cl7kXn_t1g6>*_=iGv_?KYj0 zLmvJYYYaqa-J?ay$FGSk8tmUpFn)Dal1{8}S3Wi5CM0@%w)1C{BL9W;55p-UhN&c@ zu3SIPk^jls$Pq%ldjv=vc1GVIsP1q+?OxqFeA{A|^x4|H=|ld3Bre|DC^NbYV_?#b?L%rX9wtBb z$zbR1LtVDSe~U)rld}F?JW)7gymgBI`cs?8{FB{H##u^u!tGzZf3el}cux}pexizs zF0aV*X9X9&P6&ne_ie~s47Gu;Fl+Uuucz)0>Z7Aqz>=JK0}Cn?`Tf))X%SRN3AW4d zfox&q@!-?SVI1xvby@|k5nArgT*R(%Y=kkY5lfVxa|j(oudqq^p*Hn%n+hW3!3D~P z$L$0kTdr-C(RLA{ZYwhK=je|V-gM=tJt{_h;+bbHYVxi5mVTFe7p!$HTy|d>h@nUx z8zs;CXriClcD+$S+6+{s%*qIQ3Y!efe$6CKpd>V-Tj(F9=I+}Dx)rr6v12Qk6$iA( zaXZa(Tlv_KKc>M$SxNxOY&TQY(5XJO#G#AJ6+~5$+V^c|lWqmhOD;KHhRJMHD4m9> zB0X6{(<~s1XNyfq*z&j1w#EHq$L7Qb??R_LFd%6d`eyfyfT*u85R>v_7`!%sm@?rB$PlujugAcv(-A|>981ng z#*mbik?s-K{s~ps;d(eUSvzJTbLx<|cI$*jrineK`vQs&J_M$|&dp>#cd3nXt;YZ83xK&8&R;L$S?!YF((ZKIS zUj!QrH*GQCd9`U7W2nww?Jrwf*xGlwJw%5v!93tPmXeP%(jSy9YH@ zq+Xd_T_5noZD3rjhz)lTEIo$x8JrwuA=20TqNfmLny4T+$i%K+Z<8qN=V`{o+os!z zZ2l@wzm~;5DpQ>38sW?m*R8g2^fa7NS8g*&`QA}Gl&-`D*Tp;?_-NdFT=prof`0m+ z?3lhOJMzeivt3OiAB6b7_LXjmcR0>1P=e7QL7&C*MZz&06>D*A(NWk*3MH~0ffEK$ z4YbZ0zZ33|KOfIHjucT=yArR}?F=R%Q&?}(EsaNK869pvz3Ic!Fg(>O85lW{4vC_^ zGtkHkF&Kwj8ZNv|$6U1=%EOKl?)}tzBU^zPBncO=ZD8@+N6Gzl@l~73&7R$7Sh2kk zalB`pPCHKZ==~R2>enc_8U2Dk{wLRWXU_*$Df9LXZ-9{C^DHx@xk(cfrEA&PGJEI?j*KM!*k5D-Dr17Z!^zoLPWSCo56%~B_id1t?fSH#3AnC8cspwV&6cO2#;qn(GW$+pRMDFHe?6x|X zZO}n#*D7x>ni{$J!(cz)lJs#5RV?~2V3+ZfutIIz8QWKvW-esg2s*cnmR_CBXxQq< z3_vEEKU-O={hMSNW7iaQKrsQjoaAbI#L;HA@rAsPd4UElRR!+_`GAPAhqKcU*`v1C zgH4ak(9YRc%*M`t=wH|_x#0IdhX=dZb#-EZfddDJrxu)P%T-7JCDL4{SxV(_Z|-a7 zvE9$88{(8E_A$cl8Ef!R9lQzb#E7yxO#%7iQmjU$DY6IgMfIjo(dyKfRu8iXb7`Eh ziBsQVq@M;|I~{Nm?>{QY45H8C=e;Ik;B7*=qj;l81AO9MYR zB|75l+USl~p}xoIAe>JAJ9Fj*1cGhET&A(Iu?~T*VIvH5%`-ksMbmi0kT!Y#TW?kdkcu(>yzw?j`0b=jk8hf2EQP+OR3KY-y2! zeQ)O{_`h8MK&zO!AzuA_67M}k@7yRSJnsUXB*HtFo#x-=7Wz+@7-K2~j!~rpFrK}iw||QwRsC4FGthU2I!+F z60~$(!j000EtkrZJIg$ugcZ}Lp9h{ihVx_Qti=S5aIl%l4(A7A`_KIU#V^UbmY~@z zF+M@u`d=sG^6kTpOB|#4ll^LlR@EEWOu?d^{#g}?0MhA1so)-u-vZGSG2l za2Ik5;^g*s{k&MRU(Dc7;^{|s4H+5jDmu#ZhCQt-1vmcm?qa>SBv%v z06kT#yI}35YTB(v-iO!SH`-y#Jk8+ub8aj#j~_>(U6*b=n6)ql&ywd<-y)bQ zV%XR)Gs^i(Z2QJYsi9TX9uP_2{$FO^mpXH%g5WmbQoZsPPpNEM@R~Ee>gY4lbrl*R zqJC3W(w>wRi1B;{|KLY{DPio!!)k?`nHLsjHCv-n6U=S0$4G9sCP`wRZ4 z8ta79?(^p;#M!~Go%lbaD)$#8J%Y-J*O&N@RQssp-Zga#ZnL{#@nhWgahhGAar$(` zw?29y5BYIxzn0Ql5;02p$P!k8VRrP1Pq!8~wB!E~;>*H6qE7;i}@mQWv(*mvT0FV4v39y39mzzLOKzcy0I6muO9Fzxx^ZV;&y z^Y!7{;6Q68o`agj940_g;GSHOJ3cT4U9{gu;BUlh+3z&I@nVWPRxUar1 zOhobR{eutNWm)TclYI_E7jP+vJ-_DgG_5Srk>>0ydKRblwg3J5s@Vm{WP|!v&uRF4 zx7fRdSI(@UZmbZmaemzq)>Vm5YEr$vRd4GT!W9oin1|K}n5RxOsH%c5|NFb%M^TQ= zArV_jgrpdSgF+a-D`Kt98vubU4TL*{#;NZ-Ix^l)k*1~0(J-4}Yq9At)oo~x-)K1e z?%T;!|Fo;~E}E`K8`cI0>>cU;@o$A!&lLF5Ngeb`wb36%+fxW78FOATKDB(b7$0@d zB4?*(^e%y@j@__~&)NMn?!Xv6LpSx@5@#l%Cw+N%`9Csj`be%6ReS>P^k$hwml)Mc z(o331~uLcRy<}{=K0W$34PtqICH9lcpZ~fCpVO2}ZwxL|c&0_Y>i9|Nk-~BCXD( zwqYRtA1`WJ3ah{}KVV?fZ)NIzOq-r*`OQ9u;CQw~>E?aUG@N@2ZZ&?6)5NvGeH^-C z>6?P>^<|m4Q$@kpVqW)NSZ(glQ)kx%^CrE??qo9SxU2UO(l(BNM$iNXd;?gfG zra%66k0eX|Nx_}5E??G0phz&H%e~&JXI*l4z&<`!usv-U{G0M3T;Sl3QQePMC{7mR zzQA+s*Q*xJ4}2RBPjqBA$vM&`bxx*wDv7LT*ms_>PGxuXBsV_IYgRZfoP+62aK53$ z{2ZkBKL|Ke^*Wk&P@1aUwc^xN0yu*)w@%k?CQo+^+ngV}S|kpff{D^uoD}sU10O-E|Z$!>ZSVPr;^OO)QZGq@R2l;-8pKg#e<}?7nrFWc+iIQt^f8 z(Fa0;kt6uZk|H&Bllb^Iwq2`tWxDu8FuG()!opR|F#dl*kO))=H8F~U9hX<<#QEHj z;$yeN!v?!Fs4VmJwmq6U#fFIOlq(Q=gGRbU^2GfWZZb3}-%OwOeq^tW4s-L=)%!Zm zCjCU!t=^i*ya0A*6E35PyCAKBL(Jgiwq<7U(mHREdr3ZpJBAPhVwcMxvMLs`9advB~+O*im@^=${+iKVAn9{#0wg<7M;m2pOV(1I=`~W#a1{Y)Oh13%X&zd)qeM- zaUko~y^ij6E~r-3TycKt@Y4OvcD_Ra5wua%b^xM!uUWZv|5GB+h zuRa_?k@W?tQfhS9U$KKHtwXjMRiFRmy-~o3xN%Ac)&c&AFUU0!W5Ecf!*TQlqZ*Ca zajuSJeip?QJy1LGc}~g*pI*tegC6ZvV5jjx6tmPYQXO~`zNglqEA_T!ZsUm*K}rwO zmHT1e_vX&@lTkhIzrUn(Go$bPW==LFWG zRJ_=pdK;2_c}?@dqkBoBvm9%hcGu2*nSDK1`&aO9IM^h_rBO0W3sZ0NY*4e6O1f0) zWAy%%)}Z^;1n*CWAD=sS=S`ni3vSHl$#1^!JZrq9GCAi`oKmkty_WNCpwhOADCMN} z)E0Prfc%OssHqLvs17alCvd#C`p4YPLP2?SwgG5s;T{4D6Rl zLg4L;575V|$lY*39~}I7AL>hzqxU$%IU+PU2Ww6Z z_VMCfA{@q4kxFH#!N=UUB7%MlDq#_~!VatNGnqXEIdtDy!oH*&`lKjWJL)T)X=#+# zzHss8mS5NF9MS?g{#I@TK$7W^TBDYQR}>nx=zgrX4xpMQHPB6wB1yLA+ER94$(w57 zCD^erwGkxlC#K>5h z(YOEC52@*|6S{yI!LhIaPGu-bJzU{n9TJ zlelk{VxzZh=Dgx~E8b8sNwxd$jp#7rRXmOKwz@;G<1j~r2qi{Rqr9=Lns6yxH$?ln zw#`>+m&`YnTYfJ}*6fd)ksiEYo>&p|GQtWfTF6IXuq>w-CN9Ol>By=7ERfuA5hKwu z;nptRCMWSaf%y2Vd7GGwV_qQ?YV7$xmG`IY#M_b7jxV?jf3x`I@lVVocr223f1$}0ac#}8h zqiL36;^_(R1ER}lRPsMBZH;?FLa_oZMI(=15Jw$L9<>Rw8$G)#-NESXuXa!s+$+pq zXBpKC{l(p@w3~~)x|r3g=ak$t41%M2-`Br*2v?XLD_OVls^1HG+txZMuv?*HA!i@c zxktMXtT+Y$vd&CgE@R6uRNg>r_1)KyH@wjpwj*uNL;gsSOozm}sA2MreKV%!Yd#kn zhu9ANub2n1Rg^HBgO$?WBf#k5SR(jGpzVI09i4Mgj04Ek)9z9q`e{Rb){n!+u9wh1 zlQio{jhPRfTOPhG;&p!b;E>Wi9*tlR?3b?I!uCt1p4u-cI&n4Fz0Z-k?U0XK?G@&5 zA26YNHg!Dk>c*hoSW7U{J@aab7~m3ji#`k%4xnGi@+Cv-=)hDS(Ys;gyfpP&#h*Zk zzdcRZ)kVMp>iCf_j7Z*B{CpfCUS*+iY~6tr9!J9=`%!H~W}rt6=}1jGci%=y73o=; z9Lt^{6MNKmk2=4t3}(MNa;?K}ZKs=MqE}4DRzc&rP>CwI(A-`I_14ETnZp~vyrjn&;@24akJs3~A_}%oHeAaTlD9!({ zq;q4aJySR!y~=w}fAr^U8&5@6+#Wv-N8Kt%aWE;JN?;E7I~i&Vu`OXEx6p{Tem7JP zQMr+R8w5|h9a%bZ;qA7fIRB&H0(-gAS}l%U*Jlow&t1>pUcG8F=XNdbcb`-5ijc9S zN~gw5H~Sq}t}HDG&cI$5SZP{h!tvMtXZ_eFTTwZ25i0sHNWL;`j^MdZQ4VL^lBo%|1}zX>wL)^juA7w zB2+@Y@U7#sw7McIDuAZE#ZrhJsZZ+aQ$kSfNR`1AP~6_O$JI2BK?0~K$f_6LkPm@C ziO$(Ehyjnfza1`Ye%5KwG=JrRzwdZ{b#ZoeV~m64@ULI88@aY+gZ~9w2Wx|-dljh% zE+q7MA0bEHf1!p%sC@>9kR9^bS^j@MgzZai57sIim1P*x=nOetB~=V_Yc(iF0&%I! z9v(bgcw@)kap}4oCGb? z*<^NMxclDZT`SjH*%Em+Jo*LcV~|v0crz)JF-5*2w_%_4%|;<|WJMgv%5$TMf`9gr zj9%kab8G=n>=NMg`pk|DGN(c;WuF6(R*IIRXSr+6m!i?6EASnMo6;5d);;KyB{%&W z#pY}si>Suig}3f&w)FNC73F@<1!dj#>1)5g1*^D>;$QR_A_u?_sQxW+9zd{g3gTB^ zq5i1Ns|uj|zGZz}%OHDfE1w+?^G;LQ{xJ`|QTM4o4pR~%699cwo+d0{T-!CY8|WM6 zw9k_Ky|=axPNuOHHt@P1`Vz{*o{M3cxy_eodJ-=JB;Gbq zZ@P*tlIl`V7BELRiU(EUOR&osOMA~bjh^~x7XLq9Al69P$SMGdF-nLnKu%s z@^^DiTMvP;AT0llM#^nyFE8-h!mhNgfGxiLNH`j$P=i{m!el}11$9>aWgtfiJ_)`N zRMG4mpkP_0tuN4`6BV;1!HmtcJBJd0K+j8D&F;vwBoW>24L`& zA|X4zW94(OYdI^Kr8xyj&&NCMMp2%b)G4P7egQBb*EIX$N!d%<+G8b}?HnGjfq9&Yo z2+k{BI`}%Ec_n7jXr}LBu?6np1yi;l3s29Jy^j=>+R<@3$UcI7kIc;B8s7D^YtERT z7-O89hA(7`)^R?;u8by}-*x_KVWmpw8!I6{C#fIDMDqf2Ka!FUKjjk*8dJ{`bDX`E zasMOPbw&M7J=w`g1 zId*8=@|5S?5;Tf+5O}MZ-(c8b)^M+g2Nl!*F2F904v;Ba2l%EA?3%e^DCp+y{K5li`Gkp2T;*Ax-mUpl^XcRM{xjDjs0DgPEf0(CUxIlros$t^d4}{GqOgMQm<2r! z))5BFFe>im%*luTxG7bn^A0w9@+n7m$ETfepNJ}wcU6vNL-9j6(RUY3d4{0Q9WQ&X zj@?8*Dc}aypk{|mD%V^>LA&v4rbnb%S`~j>&qjxM1P=P50y^ zxr!<~{-1Zqt-*WuAJiYjDQ-dc1z}#IPigf#M%C&WAw|22=9t?>dRLDN&f=R2(Wda$@9N=B!(Qj_uo6> zKq7e00#B@gRE1oD@vRhz3mF^hjJ?Cgq^0E)EPd7S{ru0FwW(^KVX+hvgXE2_lo4oM z!-r~(32#{tVRR$X2MrQ^ujqR3608MVoNaaKH{ngsH(l21h(Fx!0aUKvq|WEp|4T-5 z?}NsDN2W|)tG|BLpn0BW;Lqw({;5Elle5oyn!irps8gMZ(|KeG^_dplnTjzgk!ag! zw@QtY8vfdoOp*RnAk!8`aTAB|VUeWF6n>UXxk(1+WE>GU?ZAcPoH(_QirMf7Y*vPw zIb5N^mK%->Lvb({l=}XQhbUrK0d+0}T?tzriA}Vmj$@airy7+W5(cRLBrCcf2lmK9 zjd$JsZ*JSDU-^s$YgPV%TV?dNS2#cwsz?}YW77Su+1kO#?`JL29h79Ky-PV9C zZwfYbi=)Bye0}kDs!E_4;(9Pk_;Srz$J$R1WM~uLU#UOdxr7Ls6DhK1G3D~ zCQpCO#FZ{~c0r=mSG~13pycD9aRm)9b zAG-=aDh4QM<9iu?QmV%)$(MrDM#(i;QN3K#E7xmCRW@030_X#!ljj4@{o#``u0+kc zwHCYTLHapvXeFOFEH|Nq?Z`teT-rw@i+vcoPpNk!9I z3Gj|Og;sEr=OvMHmFJUFl$ZcJ9WWRui@*78_rgKg9~R2W=J2D2Y>wFh70L48%WH#V zFo@VqI9>JjJJ!e}_L^CX!3>ttHAN)76_(Q8)6?wqccc4Lm~PY0jYLuBN{9Kj$l1nI zo!GpFE`MrQYrwl^(v`asuVDi3mF^6AvDix3haW8g3eoEl-hz~r6wAqy=@KIrPr{Ru8 z79}5Vr#&B~p3L8TC>VRpbC@!fSvhi^>)EmHsOOH)=>3QyyI-z4PCRhGwky@E<9NKv&sz(*M}KjYQX>y8Va*x# zml{qptwk8@ZNf$}5djB-cLI7w`dvj}Zb?vDq-^)9gbaSjKvqQj@l(e^YfiwwtpiI(F)i(z_ZUz-3n)hRGuy` zBzhGvVpwilb-qeCaYNSScBerJ$+JE*%G0XF>(w9KhU)fA%Z6cVx0?nG9hG!n<&lNu z$(P3*V~aKZmNNrZvI?byms`-6vP1a3UE-IoU+y_D8^-ok?QZtudy}Mpdt(k+?GOe# zSdza4Szk*_Gh*s5!_wP7so(-hxi(`Ezb<$L_OB^q;;%eoSX0IBwD_fWhWDo#rxHIr zgCySvfExl77@33LNg_LzASzyljYG$|Xi$?B$KsKQ4 zJqV08#XPdw^3R*oc)pjKb8@x=F`JzvB!74TK@6v8(!ChywF$4RXc87nLpQAFphT;_K6BoYr{cOr>cea8DQ_XI)Pp&0L z@4VafH)-wtj}E2hGzHW#&4i2VHOYWBp?&3V4f$v)$A8{tzyWX;`coMWiQH>lh~R&2 z_RKI1k5+TQ%`4v64=MbHe+=1!g0tSd)1Q4Zt00%_~maBLX831hyMXp=2{V+ z>j$+FTvbx-3pid*6(l+@ub|V_=A%N?tm`Opz0g=cFuDKR5A%rntoh8w4JkR+>uRP^ z`x%<48LIsU4CKsIRMM=#=?e@yBy20EA)?usYk0`StcYmI%AcQGPBS-KTUctH( zHcYYys{F(8Y(JL=J}z#Q%u?G?fT5aU`G7u!-Ccpfi3gpAz{hv0|hIx_cHE<7BgO{WxiCRt37?9s`u9`+x6*evlZW} zH7q(1DF&+N!vHMVHcuSkyF`2BeRbdeb3g57w_{%D2h&i`)4p~jQ=Nx*17bPtv->3O ztZiJG(*qS5i?IuuNa%fjmYGjdI+CFQP<;47o0})tPY0k4Yopj2RE=Zb{*QN^Hzs_C z(1u~@SwaT~BWm9wbnXx85DR?^(-t?nt8d-fXEMHROpimZJK|BX(Nl+uE^V&}uWO`= z?>N=i>F9`={gu{=@pveRuIHv&L~*+umG;aaDo5|ApdJsFy0?k{oYY!&0Q=I_t^(P8 zP%q#Qb4kFR#0oTf|FGr|)HwYNtbmfywCMjRh|Gj0i~o*Y?wyx;c%{Ovl@=xZ!Pgyk ziHg}gT{<69Uw}#B`}7Jl7c5AsH{oNZ4XF5XU#)EA>A~3DdJV~=-2=Jh3};nSh`i|QV_0J; z?kuUq=wGj$>)URj0}<4jDoTp*eV&uIEEGdKNUh2Rg@wI8vykF|<;sf)?l%_9>zybX z33{IXSQNQ|exxuZUj4i25BIKBzk9F~@dtOCd=_=Apt?l{T|8rEayHxU%_ou5W8-xS z7EG66^gw;u#G`~$ZmpANV}CZwocmsAAUx6@yUg0FD4@GJVsKTjlGn^wdu0JUweB4c zSSca>M-Yr3O0L&2WdyN3e7+!{CcFi`xj%(M^7i#lck;FsvsFlhJ@8sWrfGO^hv1!P1xS#?Nvccy?VKmUgLdN zq9XcPoORu}TGVNY!{S7=*$8%u{0BOmTz48xd1V7%N5q!Gb~K}3cANUC{NB%;@me#) zY@FimMoc}4Jwghd9Jszo&na&CXxTx2yF8)8b8EjjSEUT#F?3 z-$-3k^G=dG()98FV(UGinu?lsVJU(LQWXS*&{64%0#c&VL5d(2M5A;Iq9P#mP^9p%^|6OP4LPE^p?Afzto@eHnWfVNVzaFdb zRE<(TzGE~i9W2_I;OnF%FQzn7n}4?Su+JC5;JOHG)Ul=uhHm}c=s-HeL#-FGX#SCXdaCAZ14|es z&F;>Jho@@cb1#v;GlK~zNV;vK0ay{ojil|P2(veCJq4;yB5 zt~ie%ieHQf@KQ02nnJ0{JovRNGljh&u`WmU;w27dC2WGhr$C4Ha2My-o-~va{j6oh z$$;&Lx#{XTSXBMCFUbAfb^duCiPUX<0Cj^Zf_vbkMvUcCMtzdkGv^9KLBdZp0ap+< zyN3AgYyuACiIRk38b7UQ4|jJKgh1lSjZBsuPxBS{V=05AIXUI+7q_acJk!9=>GQ{l z11!k}mh#n&LFAl+SGl(2x*gqhf3ZLesYuNHmt>)~aIhiEy51E<)a|rWTe(FXr`t&B zwwWN%j4f=0;hOMN-a>Sh4FL;ZLrOc4SVkrZjW9?4xTuXhMwg%QDXlLC>rGqfmrH9? z1XI=vvTPn#tv-1mwKQClTCP0Xu&TV>qN+Fww|)8eS>TkU2`~Cor>1ykgZl}jB%|v% zmj<8Kcl#@WyRP!zG6JXa>M?EwtSUS(8D((q&ehBfarzlK-d}zQpU)Lb13hSXyOg$q zG|+svy_Dv1Wdg%Q10MnmhCiA1VvW%D+V@Vn+#pJJqo0xa*H5fkfABRYyK4_MZ9C`a z=B4{8RKKvk@v8+~fOF3vf*Y-#cigW6MnpkZ(XN-9EGmpV2f3X*eDK^0SHQD(^Q8yP z%38KBTg}7V>;}8%?XK#h%Mm|!X7m}>Tn$>kZ4f9vd3zP5cP3i;_&)4~1pS`*52YZM zIjYM0|D_aa|2L&Deqo~P5z(ByCKUjFljcA3dD4WzpiQ7k#RPe+3?ERziQawW<9i-iI{yL2Geg0RQLXv3$x_$sr3V#Gw z{mH(4sq3rT9%X#eD>$e0s+GwB+Z=e)D5dH{rQ^WJTh*U4FCH|f+pVu@JkL~j75Q_^SH{tv3B;6JlS`yN`(MHdAIFh5*Z%ne(hPw;P#d4UC7Vs~jQQk{Ui%&=k- z(hwQ-&CDx3>BkS6u^`GnMyLT)t8Fyb$EbxPbWR8u%@iO*)XQsAfJ5q04Zzw>9o&dH z5-v;gIsoHRudsNAh zowdJyM-ToyY)6i-Ie=8&BKSTXqGd}ifk3;p+$!}OB=)?jVRky5O$lYs~gRZd#6j#8(m{aQ=m%_wB?LQ z>y}IIF~c>Oa@=WB5z-q$HvjXkwr8{2$LGu@ZuPfbBdy1aMhnB*Q{8PCG=G|UYPlF{ z;3g`fX_Mvthrm+HBd7#yx}!j4b4=^3Y0!0=p~(gSVS10uRhk}^RdQ>e)sV#;UhQ4WCAs{8eE{nZM3s@E3r6@_$yw|8^-$jZ zAn&+EaSeWUBOD%G1R=eW*!C%~KmX}dMVi+U5;5BgEwB9{dM(iQ=fSPcPwJKxpIJrm zqii}=L%6AZGRyQgh8-571G_S9PH!&7)@R)QZX&RHZhGwk9H)Zhr!`m=s(@fVqwEk? zeF(+Gi}XDmw@rwhP9lpDzmAiAj&4#;YZngmT?%498k!NCiTsx&^8Rthv zoPxF#m9IM9s2^JrTox}(?3g?Pd9UXo@9oWld_rQ6BZAwZCu%>4ezKTXiWm5@fr*Ce^=v4<%$c6 z=s(M7MBU>*AuLrVgR+OoE5qT3QJxD4eYm~;ykqpCg)2FOQ93)z0&IzcV@pdSx{!r; zsHX>?u=}(JWIQS03T3&WXZPmmm)v*NcjwGELUapyD#!EEtG<*pq4FqjML47rV?q{R zz!CVaw*HgVq!uFX<3q3y}?DDhs8soQrd0Irp2i}RO#Hh@D~o~yaX@9;Il54+tq+gdxVH633W4?ctEuJs z0ayW)q<;Qa`m##DW=DkU8%oVAzm2_l|gyf!-j&PYvc zd^*h+-I(syP1i0-2!Ym| zjc^;wxNK4a1t`AnVE}Qgfzx z@U6&F;$qg)h}&(Z{^<6aNR)yQbfQ&wnJR~}_fHPxzm;eYs-IrvsR3}lq+q5mF-7pD z2HeA#hk=LWmNq$zaxj4vt%^>9}7t)!PL zxK8#5DN=?=+oY5R2gxo^jgdE67zla9LQjgPKHzaq5*w($*SPR7+JtlH=jiv=q2;Oa zeFI;{8%t9w;*N1X$9yU4eiIN8U3lls7w_bQ8kM(x|2DN)ebzfV{S|x2fHZG4&`ID- z*Ww^5a)>~Nbd(BNI6zd+iZAQj*p5G%Z8RxqBcdx7+E6DsJUf6=ErnDdogP|pMmR~d zBKO6;cOTpy{RTw~lW4;W`;n^tn(^C2$%EGx_yf>QsK0slO-3_@AA|S5(L0)JVzkBBTEshyzaa(SIGk`iXD(E<}_QXeHG=JqW35Qf;!Y=}zpy^dSGgQKAP*UnYWY~DW84tSu+`L`&a-SP4S z6`$>8(7jd1Q+0g+zYhJufR3$dlt;>!m^>x#dKC7LSLY_DDB&eo3Ph_@`n@1AWSZ^9 zMaoDZ>oDF~sUMikn>RYhV6K+Q_<+;RXcCI03^ZW=CzJWVr@rjIBhQ;pTaVRfx58<8UcGvd>#`jM7SBmkYcLh|Q*QZ>moCRs=LG!slFFNW1N=d`9H45)t-NujgSO$T>NJzh z!BUsj?^$5(XNJ-8QW_4)B(5*VbJ~_Vt!|3xsf3yRIHxwh(8tCay?j*?6#ATpm;OjN zRkY%GCtVVso`ySToKJ`XKS}q&TkI57F4+5!Yk3)m&G9TI$ah9m`9b03v6+891EE`~ z+Ij`AC}kccqHA3}Tjpzf96n*r3Q3N))8NLe|%6MwwT@U{tD6w-=Cy2wcjgK(+zHd%jRCf3AfWWWHhfGH0 z&Ei|9J5E?udhEGKUFeIpZn)UTg(R)v+n$#Y3409tgAQojKvcCS=TRT>7_;_$hi8Y-w#H6{az8e zn7}ijo--@oG#*2CRfz>by|}u4Bpiwo0@a|AatDM5C}#%kW{+!OH*`b6o;d|n{Hby$ zeJJ$xVfxtG?k-mtLciI$U~$anjD=MZ9>l!et)6GhgLbW;1DsT_;k=ACS(xU^M;YTt)Es3&&pnbMXz=6 zy#y!7^AX!uka0Za*NdPa?&TKoF5G;?u?MtugI88cTg=(Uj@w-A#C=I_uas!rR}@$B znK`Y@t}`KLBuC)U`kNq0`K^bpiyd)-!QDG*3US6~6sOnp;c974w}f&=qa#G*AA^Iy zR~d12qE7_#=}HnPJQ`w6G`7tgg|Hl!!cDrL9cWfub8Br+5;L@WX(PD z4}jbLGMcxC#1(|t5`HYDdJNH{QF`G?BI>;uq5uQ={sS6=TitnCQ_#;bw~mA+GzVn$ zdKni7crF~;0!J~N=V5`u+wMbNNZ;G;(H6AX0`m;6nIL+R5!~9X)ImDosu~e?p7Sf2 zJl+00A7UGKz0wnashOF1=CpghVUL{jKx5!p&L7`KvxGpl^65A%*1UAWPk7#Z_8l%u zzZ{hp(k1ScZ`0p}SYICA-MA(O`@BpGPPqwakKO9Lj98XAH$WLioLq*9hL>9zyG;@_lBIUQ^hgOA+XD#vEoSD(!{1BCz{DS zqt!6pk;!4b!Uoj6GVF+ih;aidq!SYV@dW8-&&?Wb!fyR$-TyCHsH;Q7m5}5_%>OR& z9{|@Ggi{9DgiGg-E#C`z>Zulz>u|)=cH%`@BruY&WGg_ zq8aDDNlHZvoZmuyF-MtPvX#EJ@>oUrF8O!+_~1SwMvbz0<^pgp1a5rYAR-T}qY>zR z0=*aR#;}2I>?yWTxVpEAlge`@j*dI04M-9Jo6k~$=i|wQZ?(g7iq+n`U=w{iVt?DO z4>vbAef;PcDFYufEcf_;rnDZ5@;_;ZjcRz6xt;8(*z>_v1ovPVgryi}wX-w?q3Te0&?@1EaRu*{&?#IB=`0 zvb=q;%s5fu*cc&HFqCk#Y5X(!^aI-qH}SG9Kx6^?#2*fX2+qw&lPJ@2Js3i-py4i8 z3OcSn0=+iSN9Q>Z?*l878u>O>RwpYOFpGN`z#0h_r7)PPY0$-Ji{lw6=}fSDq;)Rq zPxao7k-WfTXj|5qrDhZ|TNH;(+(NG6gG8!!SiZ-B8B}{x`0kkslNn4s*9=zO&K??u z>u1|>gMB{+$wy8yT>u6D)dEn;yg@rKO)LyzDp>k>POn>Oo9ocFjZja(&#||H9sJ3` z4#$5+7<+sgl$Y@qTKR=ay^-Qac%WE_dE0iy89LjrbCEE><277ygx5k3zLb?bA_j2nBh zaknS0q7h`K4p%pDey@+bmNUBM6I8W9&(LHylAHC&<-zUOZ@@cbBWAKH8z*w#vz_%R z_;keC&A_#!nf=FAamvyw=`ut`Lo$Bk1EPOnQP^?=VA*^R5HUg&ug(&Ru^qDCA~+{; zzt=HJhJRJw7~#PsiL~ok1gnr0FqVx9M!FQRyNa;;uf$ankeH=EEJ?wR6Sgs#f`}+V zJ_*N@1R#o%FBf0~yAwo4fC3av91^BY> z-5)||qy*Qa@Z9=w*~wWaKHC%YgIA>Xw_XsJ+1`#G(Zl|{oxnDdhly1A$<}3YPqpN( zw)vBUihDl@6|uO2*E7z;$wgIe7vK^-*&MiRxC$8*NS?~Sj3iKTI1gq@f?y)%?~qP^ zoRl9M-uTPq|KC%bCa?+{YlwOe8-x42#SvXv62VT-)xpf@qB3E< zz-ro3e{!_tkx7r+gEn(pl_#pkdokY8zIupec$W}@b!Aullp>J46=lB?P3 zWRP%oF%{hYMgyNSEl1L@@^y@F}PJTQK*dhz=)uh zG|ceg)?+*3wGX#vS*XPcOmUg*@UsnUBP;~XI5R!02bv(AegZe-jm!{4`h(5S(ZOv- zRwmM|cSXR-Z6R=9_;BuuJoq#|dE}s~%ZVo{&H{^3`Fum8vYq!l3pLY!v0G%^%jEen zipG})FTr=km52}eJuE}W=gO8~8?xTfP?!;Ex;65i{yQoaVIz>? zf`~guWKEjU|39QtwGAK%2(}3wVIvh7QBwV3r?sc!)D?;AoAeap51tAMsJKp=MeHG^ zjz+ZfwFG9@kpV>=BTd`zv!^eObP>drkl@-MO~|_}MwYsu#ck)))^-Ovl@>!u`jPk) zp>X9kaQ4k5|LILW*;K|P4u^|gK3jim^5%;$v!Kc4XqUm*24KF^6n*rn|BAVly@SV)rq{(larz zcUYSmf3e+vGr98i&5GN5tv?G^9QyQqizyzf4l18=9=3XNirb~D z#l)kj*J1S~a99)m0B%?jMG@cEmRT_56$EZT2Q; z&D_aGw_kei@AI7tcwPKp=mnDGXRRjw;UILF^3=hGD>K{QNb{#&i+B=KIU|(mSB~ zjD+jE|FNY`gEhAG49n3X1(n6<7-jhyz|E<$b~N*cTTQNAT652DzU&AYHqr>x|Q-}~(mtQM- z8|^}tBely5k@$ruQZN?~r(`_AZefv|kIBffjh@*xn&0dL{DV4APuwxT{#;+0ol*HS z$;~E*aadqIa5**j-J~*Iwi=i5w;HuC16r4ABwtFzm`(2s_P-;2E?8Q`e`|^!Lts3F z*i<0x2CD7ENx)RSj=4mXBXLo};BW_|7OnxB!cA>pNtni2ssYNqB~xG0f_iayT<_=# zZ2xiw5>y7N0+cPVw@+)15cBcFq%hqraQ6Bghc^M&RR7`>wILCLzB@#V zzp78m9}IpmXV^6CU|y7Zn%lbt0E2EV;_bSr5Sf_1GGZzK4oF_e^}i(^!uz`e|Yh&IH6VC8??BKwQKn1ag1u&08fXo<6zb+2x!O@mLO z)-uoC_S}np;;O4_$Hpx9MqBw<=vx_VK0)WK2fvnGH;G(+uJB@c?F>GBq-+V5acdRD z!SViBsVs>Hn2Q*|+F^1;=g?S~jv@FhMU-NqzLx$-c^K_lW}e@h+7$cZy5jTr$4Zs! z3@@CXz(P!rNPhnlo}PIZk(V6Shq+#R7pydTTYU-RxA5XC7@q0!*y0y^DzDeBJa(XZ z9qUMQm}49o zV14%vrK+j?frBNw_9^QAl0 z|F-%y#IiSWhfH~TV0Q9U8|JTh!~eElV+oGBGcUA3sf-s2#iEa1cJx;;8T1qQc3WEK zsB&zLLu79L+WRMS`=KqTDHTT1)V8-?rw`&d`Cs2TB^MEQEMfgFiWZ!pivA!norro{uaisG^D znC*P)!S|}$jM+meQmJGP?`>$9X3}KK{n4HYS@N%aXdYonI{_T72&$!V)?S9Y?k)mp zUiBwWKKkfsUEIf^;FZHUQUD*XC_4O&PB|iwbI!4)&HA?e1k>Ob_;Gki!)tm? zp#YO#oCwMRawB;7;cNM~>zis!2$Fo^Mv#R?f)>!(p%{XAbWPz*VY_-Ox)oYPpQa1X z2lSX7XOk6ZbNYOe>jBMD@ML}c?l4pgNL4^`@7hk`3KX4u*`o#FE!YC-XLd8uFmvmOwXP{q( z67Aa16#A+EjLDn87IwPVpv#5$V4Ox<3VS+Hb!a^B6KqRYvPZbBxJMd=rQ9etF!Wwg z*6X-H9`7lnhVwa5igcPK6f{EdXgu`o*gm;+YoQfPf<`e~3}V!QNlhDK=SI7uUND|y z+_~#@qll~N$dt`;k=Uam8b-0>jVR49C)?U%8fdJ`Df0;c!U^u|4z#mLNCM=63QG#p(2c^O&6rrlq4l_VK>i38~`8 zMTHY4{KA+HY#k@%g3Awy?OA3DNS8Na>=+5>gEEj&mNwB4(&vsRA3=&wsiy3>rU#$D z$lVPmk@qt&_`{Pg_Aj9w&sQGu6(=i(%Qexx&ypQlZ{Zlc8>dzsnkqzj3ReJ=i~ksa1v~q zZr~E!oH*;=F+~V(UTDb`b6odgiQ8W7Zg@V-nulTaFS>G+Ug%J_S!Xf zGUmy!h~hQ<>t&=fXOqg4)=?ZZ-=#SzCaKD@R}w9@j#Zagk7`C&n0d=K6^{Jg&82XK zR=N~y9Zrkj@D6WxBe26>T~Js9zEfr8ZHrYTHEMt#G_z6TKOIixt$tWvtDj1if4mznxi%4>EzTKA=V_OVUM5M;ceo00HMx%m1Q(PP44IiEn=a=80VMr0t z;&&Z>?V9U zh_i`#aq*N&%wplU_ut&NP#y)2WJ!YYtHyY!4!3TCM7QBKP$<4*QTNTb_UV*5FSkTa}1@#lCwf{NgEW z*zvPI&jUn9C3JWj6OYR`%@pj%5G3zurSm^RZlZ%GH2KfKc<`aja?cK^v%?1o9=mKa z)=ko~B4-}8AbZJpp5sYP$YNa<)lG9aoJHijwZ!0@d-q;y*%#NOBEV-W_GO1~mKYR% z61tgwvp(&u&Q^Xu$d*PG?BGT)TXIP7UG(;@hlj)?c7|E4>icOsJL&_zV(5(wy=J;NBAOS3_>NgIS5J@p zI#~xE=iuJH{rQ-5N%U*L%O}x0^OcH1p)dPw;E0kKQUmnYjWi%0D;}p_2Hrq5X9{M$ zoPYtyQX-Xq{;W`{I9<=R4fTUovB0=;(m0|nXHt|Si8Nv8afgQA-i0>bTq@iyL}L4@ zRS*tGhV0EioFMZWSvR04DCv2e&YfHHcm4L|Fg$eTKQZC*Yp7WNGVfyp`pia_XJNgu zowTYMmmD&Uu}Zah8_CNLwcHdPla1B|J_mCM84yq!TkfQewC;c#>@4@8HohJl0<^8; zHmhcEi0hy_k#S-HxcM31dt%5tZuG>?P++)286b|qRO`exuTDY#PM<|6fvy+|PM~n* zoqH@6fW4;hSe`~Qdh2fgtFoX9mGvx>m9}V&Pc@8!(uUtBTj&|(dk^e?+FfPPkp41k zzokb(7-9@v$M1dZ!PwZCE4zf32p#=i3r(bD&*K`+RwG1b|i*Cyh4hN zhE-4G)8$AW%EQ0Wugd+?=MGa`vA{S}Lx7JzqYACvAp8#G!g=Nwl~y1z=?@e+LLHe)U#Dxw@EiM#`_Y=f1NYzdkG1G8(^tL_;U_phI~kL8qh0CuOlGDkg9ZryHlx zwYsYQH-n&hIySnKKpP5n@4@K!W~0;D=K_mAM~mYHV#3G>t@ov@To z`%XPkTEQLo;z;1}uJ>CUs}v9X z@|(DJ{OHAXfjr7**M}bKt(;$OJ+kH#Gf6m+8K-=cmW_hGExKR8^@+;^)=PKhANWnO zZKxqBkn^*%-itBIG}!yfTrV_kW&D4vLS306S2)naQY|HSg3dYBT^otO==fem zCX&TR`BaVqTG3$6MO1I_#}z&CUYzV?&VeLKoN{xw2xYBbc+Y%C>9}xPhwmRq@l4qZ zQgHC&xl1{S_h)25^70`PM$C|iA~l1FM$_Q~C5I52@6M-~vomlwF5 zBrBz^J}{Kf)@9{=CFbMvGU}qA0-?(;f!*@=a{Wi?>LcT`yiy*VhXa_U`ij>})Mp~h zJK1LqPbtv6&MQ4@AWW#k^>xbU;+mTJ#x6UxjlPNfbX5mtI^+KBP+z(z61A(8#} zh}ghvte9+!7fs<#=keFK29vr&YZ)1~q40-Lv7F^4q9pR4EfhW{T_Z~(*>f1U6T*`V zWQdxgLkoqUtgmcWZ4sWX?0c?1PB$5iNj}w^qH)|v&!(=jhOKPVWtL4%9_L>x?CWsY z;TqviU^Aa>tz-d-1N2R?gjRX&)Mm(#6YeugQO?**@4nSR^-FzxSEM9!91taI8$aSE zZf0;t!7mUTTt0Trn578j`J0y3_z~m`vi!>cqaHl*G43&+p=@SD7TXV_AI2Lie_G(P zR)?dIlwflF8wclgm=XW_?rRi<4G&V4j9@wBXn_{T?-oMK_dogta!S`Kewe$>6;%*Y zdyG&{L)RRK&atnv$Z*&Z6N%5WdP^qXmfp1f^j>l9Uc#9V5+*~e!AbW$_G6VB(8kf# zXZ6%1;pGn>S%6i*32ydLV}jBp)>EYE$dJ=fMhjoh4#OvM?d%-S9t~d|MOP{DpNZF! zjf#t$T~>m*$f53&n5}sc3vx=B$l6f6JjoC_MfBj*u>^7wS>PDHoHt`EQ^lvrzWD6K z!;3|@8BFPv(Sf6=nOzQs8tVJ~MOsn+!L$Cmm?(K6Bwd)!ex(Ytq5NtT8F$8=o`~@k zZa9oL*Wa1r5?mzD=V;kfMw=Yvr!%v(7Mp(Cm#jWlFOye^XNH&;MeI4e?%1%AF@wr`DiM;tvpwLQao1uZrVP0W#*h5vGr&{1v%wt89Q0`dl@@({k94cn2x^s zWP$|a?pE<{wLmcQ2CDnKrJs1>P)-yj?tplFB!TU^NcL2r?vC!oA}SD(+BVKT^dZV9 zYVu0`;$!54l-=mR@O4Hxq^qW&mq2Qkfk=)Ce$X(xXiWndFk6RKFg-w7OYJxk{Ly6u zlZ|dpUpL`wC}i77vFSDVT=!U<JB<1i z)HbjJeVo>zBn(Av5UG2{i-Jr@Ac zkt3Vy4Z@bmF+#}p=Awkj{qlNZ7P@4MDd)BIjcY3G>MA1M#FmR7$A{FCI;7woy}!wqmVK zXqFQ)<3(beJP!FD)O9Vy32UB=CA<0vBd`n=C`myS2*#J7cfjuV<%4v53~EB%_Fv3p z4Jano4YZ%%z~yANPFXyz1!(8-2hsZCajifCWGw0vag0qMX4~qxSBJDhLwT`#hW;CZ zE4{gVxY9;|(pV`7Y00BVELiVA7k2%cg`w|*9a z4e^?I#^O3y9J=Mq&U@L{0O$ce1|dZ|s0EIvq(hQBb_R+ECwlzI&OiOnJAChkl_Iy&D3`BlAP&j*^u@%Re$rE?H=lZ3`g0?> z1@&AOQqd@O?IO;e8%y5Z$=%VMrFiD?rWnV3> zzXwCki6SCU4~jz$us7#9R_ahjR(KVA=*wuTu)|m09Tco!xiA&W`3_`ww41 z6%|@JZvN08FP!`xX9FB-t2+*#9${k4F!pchJ-XJFHWs0z$yDigS%Bxmtk3Yq+%w~EdcRqkeyZ%sw z2+@+7m;9;Vy^T|uyPW;`1IYSsAmB0c^d(wDcn3=s|NKou{Ch6Av>O4R8gu!;PO%IB zR_%{U9|7J+iC0!#8{wVU^FOA?NAuDWrvxHVe=(w+6%#QYW-7y>Ngr z8MwNp()ge9mf(~<`tYEf+;fwCk%mh4RSxcY5zDDfhm{P9#oaS+-!Ne5Kt$f2)9SdS zOP_y5%S}JtEkv$hO4Tz)a@uyW=ovP8``|BM zOWx3=IM>s12m?A(VPM$Lfk*R-P%W}mOpGYJlYc6PYO1)y-Jl^_YCDGQ{GIE~Ol%na zxSf?IM|OA9pAuQI>2wTYm)_)EZga#%}iQF)@78w_nx|jIZK3 zWoxha$T_z>xBr^6evF4twaG!y#JXeas<-ux-=&(7DYjSm<%}v7L_H0?JsABCc>S4K z)knZjN&pyHx?d0esP6?qqG|}77!z-Z54j#ojw%(R^vRK$hc1yYJ25M`<4)B59eR#> z^Njlb24>V%b%`s&So6dwJ&uAR>=Xl_%$32)%`UZ)kSu|iSx6W|!%>X3Lzo=JusbYw zvjZaIwDuF}<08v1AE<~W>mQ{(7b-)<9TI-)Ob&0(TEu=Id9UL@h>X>0y7TVGBPSJc zuco-C8oSS!h><5;N20pO8JD0q>2J46h2%D$48JwY*lkYP@7OL!IL{fd?ySh&dSOd9 zUFZ}w<__aN&!KN6Vt`M1epkrs4WuktGqc}>H#2df{ty*Pf5kG4q28M=?|Z7BB8Hn$ zjws<`&e67?o+=MyCwe)=pRG=SiW*rji>Lbi6D&&P}pL#w37NF z`T4CR`%E1!Cez({Vx255#wUY7&d1ZFB(xqY9n|r1n-SHtyci+v-#?ex{GGn5trL%A z32XFP;&LQaC9n~}I(>QrwN8y+9@q*YUf%HD1X@05h3(({?dpR1V`jy;OB-!4LdzlH zG-}VT^nxwb*CKHfIw4{u$@J_D(e3f7r#WmwM2EzHzP)+jME=vUk`o&;jiCXqqfWN| zGZP(kiriT1^&>}8%%%=FN@c$KX8ZMF+3Rq#+X`IRH2-K0HqRu5tCs^@e248Dn0?XH z*wqFGE;vMll9ZejjK_1l&aPxxew!5BTl`dB?s-Q@W^4A?mnKMqFLN4w)^m{T;Nddk zfAd$YLmK0(u#)g(R|U6V3Ss=|p8uWLaM9{yL@e$bl6z+33bwEcF$B5yk_l(2X?!ob z7pGYZJNoO6G4pUs zk9pqtngq0AN#ghn^ujb2BniwP7dyfC1861g$RY1mvCJv%Sjcb!#7q=+TCQE%xg%3CkUBkV8Ca9pERPFV-$ zzkHda$s(GSt0{(Uy2&EACr2mvAd5z#xcv$%;KlI70@K7NGHd~C{%)*9NpfH|lA6-4 zU&3x9_!qwUkknt7gcVuFuyRHD8J*?)a$|N#;qDaS$=wd5fz(=y_uJuO18Nv_&=JJG zb@Xx{gt;lL02wuX$eD;e*aKpb94QG&9%cL}mrr?4P5tC{aWp+8-o+rs68M`dy!BCu z`|$=!UA7Bjq;&UjgK@)o{3$wGUBQQx8_7J(!phgz0!$J)J+wmawzKVT0KJV7hrq|H zg&c6mK1xzja`0tQ-4~a0bo~o^YqSa$@$bZX!~Z(+Yb43Vt4r~39-L5mEJI<|5_>rz z{ofeG-pyQaNV~IiDTfl(Tld~PZ(TKtms2_;$1WZ%@jM?#_mGOkQ5v9PDE^cGP#l7k zO8t#t0_(aL{XCIq`0`3juAyw1{qY|UAKiS~_`{|&`V7Yr<&2Y9`yY9CIU?T%*jRoM zi`h|0Z}d3V?nI<8A2nIqFT%Si|M5sbFaT@C89Z%kw>g+{&F#O?xg43zf%NgHg2?lUccE%QedqBgUR){}!CU@U zPMV$nNOBnU-mCW`+!cxsmuEmFL>^r{E3hiH4Gr~~gRV$#!G3V|$~%CWfm6un#xjJh zp2Vf@lp}zT(!Qo3rhlZ99fyvK>1S_zuxUM%WGF5Kqa;H4h;pcCs;^f|qcO}F( zPZQoSKnwfvp?=Q0apn8vI9v|;1{;cu^@xz!GP07Ez z!(nrIfn%oHaexX@nJ32VLQ-F*MmW5&2x{!dh|S z)Zd?@X4-nRj6GPX%$9RuXP!$@rcn#smwv2_i&-OZ`(nI^i-PaK9}VGeN;}T9aqgW- zS;%(+(8^nDX-$2TGhxBqy}hU2t#k>t2+ECGtN&xMR7kZ zYOvQA^3PRRlSz0gNvq_w5=z%4m=ZB>VU@~sE%jLK#bei3CM=&ta(YjWFZ%2D{w5kj zIl9p-zxHZxWb^;Ou=ecyNjJt}>+>tf@CXFwktFtM5>>OUwT_;-|AvHQvG2i07`JFj z#3JM3`glAevPE8K_C_W0&% zFn|nY-2m&;(1)7C{qTM0el=3Nt_8yOazSt)d3s+%=u_#Edo(X)iCBf2$Bxj|tCVrA zE#y5=6O4yifX?Fay}_dMmtF!`t`#>aiNNsphe!u$WA-qAVR%KBU&<55wWa1>x=i?) zcWp8r?tR;zRv|RZrPoMyE2Uwy+6ZPm++ypN@jpO(^p=w6OlZqt<;*DXaH!kkV>5Za z;};bKx%7nzBrY0%kr?O_N03aPK_o3UeK~_#m25>BpjuJA0W)%mUF^N+g=ax=M?`;f znV?RgVpOE0u&yQNB~J!bTU-xgH{T&hcOR>dw=RB ze!d|;RP)iSe16z+PTATFXG^P7K6H%pFAT3a{68=}GXld86VA?dPfS>@3k-I0*Wr2^ z*I(m$dy7pK>XanJ%3me{<(_xtWF809b{Im7BE;{uF#?MnAG_4PZTT0#q0;8(qqn{S zg_fDMmbfFYD_PtMsHR|>-qTR=4~Xx!6Zzjj{Hh58%XvM3{x=YRK4mP|i_hORGvu;P zBwtb057BV0Ae<3@RGXi-ITAgwWRqhr~g;7zN*OQ;s$1$BV?K`mF%;gmQ zA*qDTt1Os|MKyEh$-=MO1&^om-9vW07r0)3`2Lf5nI5)PyZL1F*4@eMTsQke2Wik2 z->z@-csJLWHbNe0h5LVrl637N+Ng|(x!ZgY%`EyKlHcs(VSmI%^)qzvA09u2)7ZrD zG77y@=J2!y!akQ*saR-4E0WVutG%pZndwFV?e#^h$PR>%tm7U+;JCJdx%$J$HJ>KQ zdMK@;)Aq=s8&_)GZe|MtW~Y zzY-x+PQ#L6=1{v@Hw4?~VBHM9DzHIoEI_m@f&|U z^*mL5?f-D~-r-dK{~x$LvPVY7QC1=&SsACOR7BH=IwYj5QbrCpnF%M!$~Yvcki9Yv zju|;tc8(LWIred!bKk$a_vib&e%JN8&YzrfUFY1d@q9kk^H?Kqj3QJw&>iwhK5zBW|L;3!Mox}kPZggi|mG*t<1fISYbZ{sJT5DM^-bE~tl{>7C z0Nl4hi6siVCN~#M1fJtOH%GR{J2u5Y@0cFaeeqtwq&cdY3g2g`ugx77Hi{GlOIqgJexK5rQR zbH|ClaVAyZn#D{X*JI%)W1QgfBXvy{N5WK4a`G3hQ1}el^CX0r5D)5|_*-`-?H)@r=m#FzEh7cX1My_;l3RQ%C#_p1xp&0edW^ zxOy|6d)pcX+}TBpm8Q`DX$gv}X^ID^UF53q4j>2Q0Yea`foY$3=@5MdC@jc~ab)e; zt&|V5XA**kXl?QSvE4tpu8k$p*3!^z61Fym&hXxjVB6$Rp$Z&l8*?>US#&s zZgt^hlskuImoabnN0;%B1p*Qbw_yq$Oq(LE)4qM8Ykf92WBzLaCtyv zHRy;cOr@IslQ|&jc`lUwkEQspgHZ3YhJ4^_=q>J9g#?szJN9d1iY$ZVJ%)SU&bf>= zGbx8-w=XN?ak`nOiju{SrYLuNmZFX40aaGV(IJiugJGFHaibLbKZQ|ashkNd8MUJK zhnZcBhdSm`IRvJ6*C!rdM(ceVR(I*qU6Bf%OH~&-W}TRG8-nxmNWh&8#!^2*V{kK6 zJFQs1Ykk0Xo8olBG~vX7Ib`@1kaSm;gE)iVoe@74eHVKE2512y3oq?|00s^{yZJVe z{uQ_Yd_dwEz7(nNS}W|9as7|q9B3Nb224zt<)Nk}q{Y?hYjU6{8s-JqVL3|7ec<0+ z^1qitw@=e5;f!iC%YyS%~^p;yC{(ohz|}S&NG*Z_CxbGvcI~c@8wD)dPb)`R@xuvbV8-$ zJp7GHC2x9ojK-XcrtR(dElbnxk3jC^T6UIYf_&!k*80oouT0wjwNwJV)M(hn6HP zYRApd;XX#tkw6f9u;t0?B3-4wpidC(;^gZa15ksh<%nx-2$NQ0KPK>)j zv7Ayb&&tIj0$aONRk|L3>NJk6D4skixPSj5vg2Jc0}NrPEvwU7>l&M?&qW)Gg*UCR z2R?54Q^>)qJLHrc9>D>(+=ie0bUB)1;z(KiT9u9mA}gF4=a&gDo<%}#mA|Z>BSNBi ze(_P(4}oVZp=)8tBh36kAAlKz;_`#@&xb(|GFDLJ1DzFl43Xby)dCn_7TrW1y|O*x zM^^;RS`}b~_Q~xl1~B5ZI0PosSf8Ku=4GP$2*RII24(coNAH3dI`-uditHoC57sHd z>nS^psS7K)^PC6@!1ZK5%5fVn-)z039o<&sYVFa zzY+Su76A9-AFsY%xEu9P1B2Pkhh=bt>||sB9Sbf1nTa4PuI9gH6h6Pt!#kuO@i628 zgPl@*oO30P+d54FexeSb3;m5lYhtz(`=Ogy5h<$4}tA|%}8dhdShdi#hY)D z#FnhG_l9 z7%J8z0{jT&L02vRq4RP;!(*|X1Z*!Kgr!1DP@Pu%j0_ogV5UB%FtqRCq!txTc?)uk zEAgD3?upAE>|rX;Iw_zfrshsLT2O%USE|=GG>voZN=U{$#XLcDD>0x|Yaav}_tbTw zm_sgNq$H|vZSu(+I_$_*&g*gVsT5!{Qg4SCs$SBIVp>MY7s8maz* zo`j1@3qEqt;(h|TK5`sGhT-Aphh~ML?9v-2KG4+O-O+q?{#)y%FxHQk%&)XmK&M%n zC1{;(oy$P*#G{RS!9Toeb$>;B>%I*wq;q1Kxh##)$mtC!lh5C>L_V1ptqOzRN30`) z4)!SBGeuwD4CDKXkVGuyqzK3gFl-=d2{wnL80V4A7%}xvLLmDc@HKcIh-8GB%YQJW z$rjf~^|QOEcSdE%7&(B=5qf-f(Q*ePd7P>o^Ph&4n;Dkyp#m&0kn}(87>nY{%JhE!SQqzpAe(I8;M_w&Bh1n}!ax(aE zW#$uM^hirs=Kjv%ZWF!w4*7M;<3#Q~$-_#gX>e^T{?*-9J__f#qnz0?KaG#8{+$_y z@f(X86EbN4hu>dl#Z6#h& zrsG0o*^cP0Tzi|j%FEIsjEp z*WYI~qcHNx!^O6&eIBHVX?&4i$M?;kD=k8NhWxy16NVrED`$+{7A3d&ZkXrvZ4>3e zE`PWQMCRb8H%%#ukMwikv+f_%2`lVTUBqa{MTl_;;8vg~UI$1A$h+f+RVs4vFk39h zg3O16HlK)q?9u-o8}0!R1D%4M6PG}LzwjQ7Z91+D=p4_apx6??nTfPhf4&@!tmQfU z=FsJ^*qMk1^-+;p77H!SAX+>^sV_Fynwocwy z)zAC4qz-K1{UFG8CIR`MP_-DfN@xulfH?&zDzYsZ$J_^itO(JN@_{w?P(6v)(`Omu9{GMl*UBSam25wW zWD%5U6};x4lJ*hddT#p1Kw0W(@^vvvK=VewGCcde5YuM^RY6Wu5d1j)cF5&vg~wtsw;f&Sb$gluZ{{~i_D{I zHqncD;TrS*w<``4;K3HJAU1I*RJ;d5!Avam-c)N2Q#+L>TKitBtF%{X*68=0p5dT4&Nv@aO4UbcfK!bar>YHwUw4BgbjJ~iKry>r(o z(1^k;cOeMdG>s2!2&6klKBWKdkNw_Go%umV+1>TnAvU<;+H771Hv!h<33z+=pKSu> z7OuM=bB$o?gQrQK{~Zboon^`l_7y=N(8pK+(i>q=3>w1y+c}^5#>Wu<>gWNa)B$p5 zho@cjE$)2SHfCE*H?+q)YX_GH^?h0bw(B6X-D)`M;6|d3z+vV^;Gfsyy9oe$9Ig_a zj+mUc`7j!e^p#l^XA@EBMSQ%>g}(F1?Zz3b(77LkvQ2>>B^Tbj$?VpClKaRKua!>I z!vu$&=WYMgxh)J{vGe^hOk|iVoGCL)-S3lzADz`Cbyu5=rEsz#cH5fS8?Wwqn&g8| z&Y0O%@XCO!#6?|Msi{Md6a^E@ez`9aqQM;4KkJO1hxmkmI0th+08@s38{0T|js2?t zVFqaRx){u4SFS^~v2W;ORk@eGCD5-5!_<_e3cvU!zSwRgHt{}#c*PkUw!Xo7> zkiQ(K z2iNYVs>kDLvi2mb4L|rg2YBVzk0_OazYLlpBFUFMY@U?ctMeD5VyNfg73ia~GH#BZr7i6{d zh?-+Q9(B@`Q7`H>Re8I)6}u6WoBj~eO2)!Z zU-)C-$<@H~pYPNkw^v-dtEFU~s;(+|20e6TjT8Ert|>e8>nhL9d<$OLZsnGZ#2tS` zeNuy%Wo9SwXe3Z<{?Qiy20@L1ax9=hR|4O!%0YbRby@s|Q^)sW;1?*P)P;lpgwKQs z)zmHg$9++?Ly7rTQGb&^_4zN|dbitkP0tTjdb?I3TxhcB%Cj5*0cjeqvJimutk;=uV<{^2fhAn~@ zv}h42Dm*YCCr;Cybv1bNxgXxwjE_eN7d5WOE!1?!p&0bPl8Co95Hoc2EUn3 z6iF_wk&Tts8V?V00d{V{=cO4mH-XbT`qYr}m7sJ>=#zArnyAeHs{8v({dnP_MrZWOz|A12Vojusovw(MtE>SP0hQiqdQ8 zQ&If_DD?|+C3J_w3hm#|nb<&!;NBF5lzYu_v z6jfGM^eqH;%!T*QQxcK1oojbuig653(yzxYDL87wyYidVI=4Ajwjk91n+2dnlG>Z> zxgyR7f%A}pq`vQmTpG#glad2H-y(zGXxC?*H!qd0&V;js2BPptXiKN0#a?lf|@K zn(VUr6&u+QShZ&X3FmgxS$FSl&8g8K!9Q!sfmNXKL1A?PxA)_%a@ba&1k$R13GanaqB0%^&*erQ1k zICqu|Bn{>`28pfBFtl8my)5{1*V92xdfr7K;KZj-%>-or<-hlvgybC2^*g7BImz?V z7~yCqw<^qewQ0oJsA%tDr@#2npt_>b-syEBPQTEOekJuK(jyC9)A|`V-CtObA-?Sq51Jn*b|~fzg--=PqH+W}%pZL7rc){su(I); zyI(-q895op%x^VgvA-^hcwy>4A*CE^q~kRv9eh)Nq zUbQ*Gl=+FNxjM4){qws($?Vt!(#2Wh`ctNA)_2JHmwYuLA{e?16v&A4rLLSc)nqT1 zov%ph@V|=}5Gz2pMytC{wbk%BE`Qp|IeY?t?Tj#mPwi2~f|vU$(Qkjy0@`JQ!qUKn zg-k=}m_*G{FM;RoUiYX8-Ss5{6vkR-v4n@5KX>bo@A9Eo)%>?R9Rm@K^BYbze=k(U zM2&=;%-{9nexv3;$C%oM!;JhMfCM0wFLkR(&p#i%=d_gZUm}G_wTjaBdwp8GJ|o2y ztZ$DsEq=b9I*ZM?N!sa1W zc3=!@0{AuvyDoNVC%rDd{GA~LnL7tGxffoAyPN`FUL%w|_}vU(O~U;rQ;2121uE2J zu*YTCzd-rZutgdBzgL%G7Yj2DUhJ615#`6{%0(CCY0n>9MZ6tpkPTL)m`e-`ix^e< zeC?>6)<4CHJ$?N%3~N(##^;ar;{q&VIsw*5XxhYbf`P>rpl-kSZe}gVxAWNPdqA55 zW!}Flt-tr2jbsNlheCc}MYy%mD~VVh1e$o4^uWZVW?h1B8-Y$ttc`=d{|3dIvn}~E zwONypte%i`H#F6R(aoXdfloa`E(zY%r#oGLha^AK2oi~8fHv+fDq3<6s8OqRC~6-; zwbQg{)vAM~6fDna?>!&KyM{k1n7bNZitN@mjCm+70S-nvJw+iXkpTqP8-0)35N{+GJgL!)jaAD zWJu{t)B{a(r=HDdS>^XqfUdce@Y0zR4fKSiW_IimGSzFeLJJLALPoS-D0uc#c_0ee z?0Ps*3F?&47_Cm97D~z1<@4L;if~#<@P4LEAGD*1!T~kEBM(6n%Wu!#&6X%SvLkv9 z@*1nrE(}`DgMqaaJoT4alvXh=`Z2T-{Cg=yeTK7JZ6l986dbGbu^X*+O=+++&RJ0t z4Gwz+nmS;3Q=08BapdT4vTx%8wq6u)<0>*WmYH&EzpdcTz!IILKY>TzH9Q|o*JZr# zQf@aKoCrZcC&Zt`2^~O z$9D-xzBmEc+h6{#lL`@y1^kWdpaPCvB=@0mAq?%B`kCAc^87a!GKc=30O8QT$P@XXbg zX2n^e(vTFP47Z>cfOgASu1KFvgiu~<+ceIzg-9EYFL4~S+i*5(xvKoFCD5-I(kZe} zzU>Az<4Jke!^dFdx?7laq1QX)yOX)frnUxyNGd34SsdUj$HWKE9+s?B1P2qql4 z7vn;FILb~oZ;cpop+jZ|ECM!*E9&KL#eVKw0>16)G#NgG`g22+hX%`@g#t$A7w#Os zmjB~NLgpW0R(@+x6YkuKEclA6@zC?wh7>8W{xq-|?>P(=Qq>se0z#I&xR~3%kGb_t z z#i92#oqAb?iP{|A3r+V@e3UjAy0Bm~?zS*O_MG?!qc2xhmoc|Iwt@6r%WZ><1#I+{ z&J!08{=-RfZH$k_Wu1D>b~aAqm_>Vn{wYE%8VM#WV9k6 zUE_Kq?Mtgn8xmYaj7>KUOV!~a>MD{?)-;|2OPyuM>#u#6w=eS!wyE>HS+li@E!jJO z>$N!bz~R%zJeG!AHz*U()-UeHC)~5dcbA1)qL8%SlI^kx(jTt*2;1^U#`rIqjF)<~+tC8f+8A5~_ z_|w{0RtJCK(vBZRBuPIbk4`+u(r>AodSX|D-e^&G8>ne&&enQ7#SQGVsYU5%doG3m zjlVB(zeLlV);ST>CPT-+J#LW&MH9Y}Bd7`f#;vd@JVqMbvRSJlE(beE-ACJw;^?nF zhwrRp3YhMv@b@Lr()~8_9I1r?qo@z6724I|VeESms}w;>QQY!11+!Hf=xGHhgG(gx z>(}?{@Kowp37w;oZAX^aOEY?v)r^FWSYnMEzs;?G?7E3(aBu@<#k9b!wU963GUAT7)Y$He^ll-&Q3`>j$?eOyNm;RLd*_dHZ^??yjSS0Xr8y z>W7B#s~FoY z)kA}4+3Tu3Iqit!Vn2R#7lO|dHL z6&rt#Ut2bApI8E)+H*%8u;x^GDm-*WjfVR9bFF)`)t{ptmyg}&!uQmQMt*(oHjOoL z?D)%*O-v~S%?EEESciK3y^Fs5`O6nB*^+9eZem?v-A_-_-#@F1m>t>7b+%P6=G7Et z%W}0EF`By0Ez5Mb=Vwa%{A_k6g-F5yI%7EhumI7MhlEP?wkp!fxe2n2>+dB>n+=yb zsaV}$gL;=$H_U40L=$_1`)`^{jeq}*FzXoKxu(<0!&6|ER$${sbJfWVdS4YNd+|?Z zXtB~8oy1SW4yae0Bo^-~#OlF`hx5FsZ`A3N0TRrB*+?15GGozHtrWbKC>+ri$@ z6glw#=SFZPuo|6Rk5k~1USz=TLa7@4-ezR6&t5`lGQkn)k-EgmUXG%Tu0Y|4jjQ{O}2~9TS}>%cKINe(~zu`s}M2 zyr>bB<~=fD^(W2g-Tq%fW+<`8yQ63%iU9UvqaYfuj(OYGC8!WzjobGl4X|#d8gP}n zTIuEYWu`TT)Q13tmN_*%dThWh)rJm8y1ljykh#0sE{4cniTm|_p0bU-`h6a zQCgXxv{{T-=->~MQ zKU;P!#_)!ijjt;;MbkT36(yirw|S<~`x9W>E~$HG{$7QQx1pb>Tsj}_yUWEImfojJ zi-vVoQFT*W3F?jm!gyKYA9JVNprD^G>SyQ(SlHV>uFp?Ma#D2Ayt}emM&9)1%t*l) zkg++SoSQZ~%<>S`+e9y@Q@6UccPzIFrmH*a2D-b7P7IHrsZ7V#R1H$HK2hjm+&A}| z@F1h|>B6kT(o`chX<51ybG+Ie?||b4$MM;Ni{t?xj6Tg`7E0>2zMuW5p68l8#Yx?} zP1`Zl{?yk-@VpC<6v8W_(ioH7@)c_o#~At=U#U!NAF1}13>2810S;vhD6jilr|LS# zY`riyg-1t=t-KE;<&nlr5ga@`J5o!ioBD$eunskf&b}8pvGxM1mwGu2#-GugY~Pn! zp6SK|IMc%vl+?y`3SpUr&c)$+y4r^BYWZY7-f1x#BGg$i}Fcpy!ZVGH;NApRk zp%&YyIL5Sy*Wb7gi}_DG5KsEykmjt0nkCYXG`S(aJENDVemf7o6zAsgBNb1yl;Pt;Y&0y7}dr(fl^<$eI z+D%94htXwG<*L!?PBxxhHrX~t1w!T3%owGs*jM9{N zr;e+KG()QwVdOJv9TG{_!81IPpt|0%s$yX#%Hn@c7mbaY;V0TRkm41ABzd!zrIf5g zYKG}-xU}xlEBoD~Bg#>2q&&*KSKx6#(eewY&Tmd?N4CRD!nx!}+gzOM80H2GGJN7@}s1PUpl-NIX; zR;=k4C}~A)2l)$9uzaJlxsQSY!I@hmVl>IPYz6|qUI)z8V7{h z%e(9v#|{dRD{9YNxU1(@3TtodMZXovQ2NZj9K;&)lvaBA~h^A4YjGVhZYp8+dR&>FGUS7-n;oA{NPi_trj zx4T{W8Eo`OO{<3vrIWL>SV zHI`J}^ZJx#;C6$8!qU}@C?Tej(lRu-Tx?3p*V-2<=EP}{BsPl$P}xMEy{l}m=d@-D zuJ*pr^`)J!*?#+)A2XN1{|&c$DE%BcsW=G3N>OHjF8cWQ>b%!$Q0+;*-Z4uelVr6y zP61OYfnJ-?^X`;L=%5;qr?q?0U$u!tb{37U->g)WQDAaY={5$~GbOz*P^*4Mi9T(x z*YdUG@qBRo46VeW8LfNGGy+FynQu`pAadAMxxdbec+E=J7$Yw*%yP+WB%Sr{eUSwLPEf!mM{&rA|Z#u)WH=>1rg|EV(VSm}&4tn74X< zdV7l16%tF2C?(&}&GpERcrHuym)hLGq35K$MNqG*9`hDAl5dT^OgoZ4eR@{3Yh=<} zU$S7ZCC)3*ngW;5`p^$8qZ5um4Qr(XaAsN!fTzoq}Vqwp;&aNZ%=(b-wp(9V@9-lmnuQWpF&9A8-Piy)aE#G zlR zv47sMF?^hR`y1XpbJb4gy;G2q%Z&NieNl##_cvbjWwnS*yK0+sdv5j} zbM7~>__Gr1qW6N=G={i=&Mm4kk`-BaK>`(Hdt*>zFk89=TSYA|(#@XnXg~ho>_bZ+ zuwUe=t3|}29N!;f5boXfuL~uLT8>KDM_I&IS&%Q=SsfQ0C)xqcP5Sp5+;>2?U zcJ6WtDc)yr<$UIO)8FamiF%@HkKm|td9{cG8zEz#OI=rsk6GBv9haoNW9l|!jV2a+ z!=?Gbzr%HpiOq|;FDP%iip)|}nSt98@^7#_ic8nqxjd$~;!=sxheztm{ajSYy1tXG zfZx4#!OcY4%O?6YC0#Y)*V%050W%2L!72twF8o^MQtkBh?TD}KH@=QB$JlfG?(ix`X+t5eAe7~v` zIBPI~t5A(TqLcjqy7pODwb%7PZLDqX+4&mVA3hbOeHW@PSGI;FuoEst$jONwny`BI zc|bHmSSK&9GvUXdw1)4aX)Xp4r?#BkEJlX$|WF7SudFp8o1(-YJX%WZ32nQewzyUCca>kVLk##;S zW#OPj`7x0jIM_pRO6a&(qTeC0v9=(nw1oz1%N9Nh}6`n6_9q#xQc!=XT)?Xm(8M)NgkK z@m{pQkWf}o@Zo`qNb$kPEdXr-8x`Q=D!#DSxExOw1$OdEoI0e#2wF`ILa~CenYPO7 zf(rWw&3i=gZ?=EK_&VaVI1uzULU@W*Q8`s}bv<~^8lNA$!R&o6DUv|Lpg3@wM2Mj@ zKF7}UPVZOQci}iVR*nNjf%E+1B5G3^H@L8rvlN;r*xNsFb02FB-Rp)_7x}!n>3B7| zT64khZ0E@AGhA{+6Mn5G>znk?JXoQlU7q% zOBi?;wTkNR`enyyRun|wrsMTV{j@7jgHxkaR^Y>Q3}?d$UNn>yY4=;E|mIUZ(` z&pM{yTf^8IM%su!nD)CkLMWtrPd}QtdosP{Q)O|K9dSp~AHd%2AK-<4Rccke<5Gsm ze2wD1P2y?WYAIIKW}Qaisl9$w`+&uuN5j6<@x)Ma+&hLivl;JKpQ0M~c)GnlI(#t} z3oWjDTr!Z#FOZ)~f< zjtbc7exa?9`Q^)0t2mA_)i6`kc`sm>Z$RVdmItv^-XOABw)f$s=O38&=?LhwOHsx6 zidb^O63*@S5g&^|PJ`O7Ka!b`S!^wP>6%KW96Ixq;=o3n`pL_S{dpGD*~dKgg7|e8 zDwtOfI_ap6kk2EXCq({TcB?tUs6C&il_(+@qvv~*zBm25_Vfr`@baOetRpUnar>|4 zxn6(KLB(Ko^(5PxM)Ab`7rIXu9IT*Ko8-m22&$YU{ia9BoU_X9cS~N|Q7K2k+Gm5h zXhV=Ad1tKD!zmKFE4DzLCII6uN%p0*i)4wZEjv`(iYE7|k^znbzjfYqs8cPu zzH*#iMBr`TAp_N!r_(wRELp=&)4~U~>N4~M*(kgx_v9445nDcXPV&-pgoe!s>;jiG4cbZ_;w!`v#~eb2_8>qIFh6ImqDN;63KvtGCp>jlDUQ*Xao7I|08 z#T+a7Mq2L?ck=uu)wck`Gx2XO69T<7jb?--SBI+TtBkyb$s5SG)y2R7v^x;6Ls(F| z5kD=2(R+QCq7x%CC!Y2SjAq-wb^$`R7NV^&|HWGJQF#V%WytXzoHKCF>Dsxz-j#Uz ztB<$T76#rYH)~|3VWplOapUkzsM);Sp!GUxOzOE%-KOn)N7jaX>IknDZ(_Th&E}Ua z!aQvwwf8?VuU7{=*f61-8n!jCSNGFSzWV2ss2+%F{`tj;vSC>=WSm8FdwFx)W1aSZ z5(h0~Jjl&&$5LvK(za3>#jCs~B94n*#-)j@KTdqoEuZOXe(&SsyUsN3UbGi`jd7p~8| zBcanckOj|fP6}gqBdBYDiP9%-ye6g1--}$4+a4})nx7)uVGn$i!%8SS`|Ly@<#+l9 zriSv~%H{}z#bydB7g#IDWiWo+$tAHk<6tfqBidR6Aa0@MpSf!GOeE&b^nsM@pTNJci=x_?OBK27IVTgG zz`2S_Uh{I)z9h~jq*`_&pXw7J9Gv;vmabC-{QOW`(ed%}FY#L~IN`t(-bB{O`7HEt z@1RXI)s+^kE4GYr{GtxrZF*P$6n_V`>mOYn4KH3;oUVKpK=FEHAT;cx#x(2-M!cSA za@~IgqT1eS==-^^G2kR?LQ5UyvO;pJ4AEz9)JEbW7`=dcLvgtX)oHcbO{(|rlYUXl zR#QUX8uq_=|NiMmUH??)t|a236LS{ar4Z{}O(|V_jhG@h~IWTA3;sE=*~0^0C<8pfw0H;g?v-4}3` zQrxg@uIszNpG8u@KsD>3YRiK$YJZD6QYg9OV}J@j@1IYaB(NAN;4!i}FHQG|kj>he z7rgtinFV<}Rc1eMCDbcSTSNB^J5IbTDE*{z>-#8jQ*~o(gOxgk!M4NTqct!08&Et2 z|0EtPZX{XBsXQO=2)P(YxpalO0My zgynUNGFHE_2HKxRfgHrL`Cr(k+78BjOm|jXy80I$+V#|=TXA{$9DoG7f#lWW9m|9& z{Z>YCg-b`PpmrTAiL=4ZI^t!e%9Ljy^3ahFK3Q$m#mLvr8}iyUo%-SR)M8*YZ*n@! z&_u~<#Hym}NWrE*H!tQmqTh|4wwpJPZ7LM|lXDWihH^Z3$N=iDc%5<@MjJn5Ms}fq zCRbh@FY~7iPNv!Ld=1^6AoTbQV7Pmj6mrbnU1n-YHPBF3pNu6cQVZWA2(A|!W} z>u$3phwG_>Qtx{ej{%XlvtBQ;mcXv$zL=|8XS4xq8QPl#thc==anXmt%gY{f*o9&^ ziUxX0wT44g@-<;ZfN;2R8wU&gfC`jb^`8`17)0Ry?)CRx)6GLS6~gbFyYCs(VPMdz zn)BOLO2f$HlJf-5Ngv_+nb$ETnCot%vw}A~Y;%&0VUv+8%e9CFzEoWaC^RnS2hb1# z4V4%4rD0H)Uand{T@UMoCbM7M@u<{7rf9ubNSHq}giZhCvZ>et%iSbBYrr4ZFmc`j z&W;KxT1zs3{R;o&UTMPSpf^=0jMGTdWs{xN*7h!}duIK4b+Sh|qOIv?uBhtlr?0m) z+UMRkyl$hMd8q*TV>%Q!dZS8lCNDNvpnSFZBfD#Ozx6`q7I$|R4{NKB9U4XmqxJpX za@S$UG^I1=HZFjR?cNYZdR{hMk|s5=7k<*t&tD~jRQ~7GHQF&+lJ$tKK{qvwcu+|$ zM;`263sp;*z~_sta|iGGN|CW)UTR0UR)nET-WK3G6R6a4XL`W2j(qqGZeea@!570A zCKXM5r8c_f7`OA06Mkpnw-5KjPtKIZ^{Usqx>DEqhhtpniz?=!y31d|sveF;W7mMf zNt;45!VqWh^WV>Mk-@BlJwsReNk6uq+bg$pmBjIRu4e{tGmy+M*_AX?;(o;lJt>Cv z)NNoZmpBuK!kkOUO_gsdkqkTY%SO})nNb9WvyNc(w5jEE&Ddw>fP)eYUbT;volQ5o zHLl#xakojeukE^f>T-?{)nu-QomuhOsfv7{_bn;6)Vs+pnjFv&z^wiEBHh(7JEwt; zuiU9UEg%zFlzQP$jt~VM@$~~Q49vIhJME$=6&khIwU!BSg(sg4fb30nv&i1JPlx8FB|MJ~T9OL<@7EgA+(m9( zPWz>XXk>oyt-g$2af!2QiqfVzUJsZ?dS- zlqLql)^q!l!DEI;XI`j$`4ui6C4FWXnKbd}rp$MCY?2Imomm&Mj%NoRsEvz2c?y#I zY*M6~A`?O%OB>w2Uk6%>n>Ss!qjsHq1$JfJ?0_hOIRE5q#FMb$vKT|e)K0uzY_auZi3)n>F;ad13H`bCcYX!}wB7cL zBqp`Ry-ERCB-G@>aL)aOj`qK9I{g>SBENst~k zJnX;W(uCQW%R`le_FLG{<*9s!VwR(3bnEz?T~{akym{oI|x4E%yoZ_gPi0nrGcJaOik^b{lt;cYX5Y zL0ItxgK%<>6JI3WX1rqup`5Ai*4Yv&kU5QYH?s|ykA!^5dR(E`CtX8*%^Kh@6T;@6)_fH7VsILmT`Cb>A8ZFtmHv88_aJaKo|!6o z_w>z$How2mTX6XGhX6mo*_agicD%{dHcsq;qu!*yUQWmkRz0As`(D$R7D2Na#YCO4 z8yjMaSZ2}Kv?g)3R{15kZBpVX$|^8~p7^p5qdjiN&!IO-`Hz#^s@#a+`SS`;-5Wr1 zaxC7~%s$JbJ%g(>R_K}VC4qQ0EWe#AX^nrZycR?$eeau+APqDRxt zF%Sbt9+oN?z_E4XH-!zGbr zS;>=LbXr+|wCsYs%`Mej90&1u_m2m)QY4?_Mi~89_%*@HN5Uh;B$nUae;heU(&J@GYXyPO6h& z-y53~M7MP@LRX>u#)&^pNj|>^wVDmzvkLemgeD=*^9MAKn*K{MON4DE|Evu2RXFpM zD^N@J8+yVDY?IlNWgA1C)^^Ji(l^-s4W15@Y8z!ZuWYosWx*c!J~eW6n0s1AB!r%o zC{M#=iZn9oU(7@IrreiILe;wnxU7{kt`44iUDAHq#{IUS!4G~KV-s$*gVCOOwFUX` zX-OYq%psMGNO3G<r_%8+?vW*VEOPyR(U(+STRH_4NH)pYP(ft zMkuN~(D=$7lpG%WHvIY-aOGGJwnHt;R(to1nARzKslAsaD+Xfrff-UKF1GA5>6xdM zEG6xbOb`b<^a!Ljq(aUSPMk zjS)XAU}+!^ric8rc(t66l-qL3Gv*LWIyl2{CdK2_ndpb-Z;2-t|L8#O{i>mk+j$u7 z3BdD8Pd4w&R(no{Xn}hUnxpBqa_>XW?&GannxIt5?Y)iMweYn&(0kvi!a|=G98YvB zRjqc3&CAn35uMAkWZQm>r}=5J=}YVaq2RCH_m?;?LN6JMI#8UbNHWVAGRKN9eIhi$ zYpL=!lIO9tA(x`kk7;BxsW?gf^=GK4S6DIfF!|6_ktVu)|RQI}%n&nAId3aVRuXJn5L?Sc0B(LKerRIEmnzQE}-1r=~M404SCthm~V=||u_Z#FuG(YUR z(iGQL89{iywSTVzBYmNCSSE8A%lpd(&3P|U{wXEPW3KqzDTnz&hBz}JN=-(H?38#9UbF(wp+FbB* z6GeKJGzeBYobN9Mf9CHS5IFI|Wkpx-xQom+4iIwk6gjnbpuOMAQ@RiA}#EJww@DbO$MEJNmT@E^F9QXdU zQyn?xGe4m)Wq)d;vzb2XPOI#T6(8bKy&6_K<@*XO;<45De@lo2{$zH;Sr3v@7rpr; z8-3h?{6mwP-=ygBRO}rs9)v<`TEeCI=WVP{?kg7K2x3oO=*KZ))`@%Tq$?_2exyJ0 zV&-X&HUk$olN`6wiz8C90wgunEO#3q6G{_~^pT6|LnUkg!3PD9vt+;90UsNE@GfY5 zkeIl&jmn}4&~J7`LtTsQt8daSga2~l&jp%+iHhT6$N`{FNj*7c3=*dGZdmUB#1?Tm zZcY|GZEY65@0!H;#APL{Ij+%ATXXvV>FT`Wsr>){pS|}iH;e7#j(2Y-|DB$mx_heC!jsf6Oj@5+{ zwLwjOY4eOL{3HLP$&7Nl)npvdgg?fXezUpmP#;-I^y0p@nKXO;qV`{El2MLZ!0zJA zNsGgH(+;Msl`89A=zdNjnihrGios4z^gr8p`}UzkyD0J~C2V1ryH~k&Far>buvNQ_ zyUb6EeQPJlU?OGl8P6qGHP>Q4<@d`V=-5iH9jmZwd1v-bLXOrki@oOVW4lks;4WD= zO7kvxI!^@ZYxSLPPdNlFuZeO)gBaYiy2S%@7sx8z)`dLCE?@8M=#Jt%JMV_{s{P)N zkFo#oU)mL2G0{LZy-Lm|qL(}U7u=vDqTDcqSd zTc`*@x~68Gco&r6zzx%peAGV$9gnO<6E_!L;5`O`_6w)@)}P`yz}Hou4{CW1U*I~X znk{w!K3BDBuV@Na+n?rdIqFo6Myv1TkSp=jEg&+|l<7$}YYA^YoC$d?`!U9zz@{ z!tS92u1ruL76Y_5ZUv_PMc9N2w=NGM^Y{}VZqIxqC05I{gaqIbs@~^Z4T9C;&uDNf z@vuZ)C?hI+gg6VN$A_Dd6TjZ8Y7Ot;4PD6x?+DijBJ!>_m>WWM&U%40?0ormkH-({R8-c`GNTeDLvUh{yZg+^!Uxy zY1N#7!3R$V&BT|~1Z~b@Qtm1nJt?M$uRieHPGFw4w|Q(Faw&P8@$tJGrcQ%)yg8zA zCO29nb&r{#=75`S>%{yXEfum=5BAQsz!!&J4bSXs)hUbn@SqjNB z&E*D?yXnK1UWr5}!$FUotv1`o_jKSoA_ltZzcmnaUV|l_=L8PTy(@oC zFIg}(1ydzfo_EV8&eKaMx&CZdERS6-ECE3YH@n33#htmvN1ja;lfptKiz~_4vL^f% z_7siyDKQjyld?C5U$w|wFsK(T;c=Gu2SIEPfz2NOCg~l-UD~v!7+Cby<_<@x-BUaN zCBlu1&4<0^ARSvp>&7CIBby0|Zf;N<$N{b&yE#Sc;SaaG#^wj z<*Ziss#q@_<9z*fouIYeKG&-9ri}Bq1q;p50&35<+dKiTJ}JVR-RNHp2Zv6ysZrSP z+xuH4GMF}!Sf@kkXjKoe^!*ER6Q8KaEby!AM%6L3nnP{lmoPu$2W3mEJ9~1X>_O?P zuRj9bljbA<*5t(C_wpRMsBf0mEk&2p?w7S>Q)^<5=0{1Ll21Q+Y!yi-7dKOYVj-y%{1^S_x>Do*8 zY^>d~kN%QYK9!cPeY)?Sqr*n_ZIzlbBjGY58(WZ&p_@Uhq4^Vb$->;vZsQ>Ql8@6mO242r?UGh@y%3VCI^&)j_OJ{SC|7ZVS)Xb`1aC2xv=uTd$N zH&BDFdH7nD=fF>M>&l3UQ*W{awH=*ae9UpQ{}!#&kdd{ksM*EMu)@||Dln+a?Re&F znsf*BYrl+H%Pl+Vi*$nC(r-qZBW>yVLCb~!?UWvMmu+qW@in;3xWK)=^)f$Z`|?O5 zG=7V)G&J#pAJ$!ZIXkcVF8x};o?u}h)WA~Hx9o@iU_%X=oA-IRP;ITyhVy58xk5pe z?8J-)+MUy@n5G(S4;pO_l6{A9SF#T+?_>jyuA}Jhz%%PxwavYGaMf_2!#H)^ar-E` z&``z!Fvn}-26&LEM3W`Q7ndhACgt@`5|gyUGuLql zqt50Q)pVglGjXU^U)QmpfJ{Nu)tASm_9{KHFP?@2m+00h`i+R@00ly%z>(dmcWK;|2&SXk^&qxd*d+B` zz*v0<ni-qpv^Q<`M+(VJV>{7hb~xQ}{HDPbe^E8eGDu{r4J!TEOvd#YEi0uC^5Yo30@b zx_XD4;u`Z7=(dqqHOMn~E*UpVIy{rMY5iH@@$;RpnnA51L7xJ9xx(+9B|hF$^~A3M z*a94S>!s&i**#!x2k1TKInfC^k*F~GC%;`AzQMBB{>NXXjW=3R!*W=xN{i`^>NCer zlNnZqauY+*r--VBX0Dn2>EChGO4qfCTMRKIc+Mc8 zKd!_0szN;x8>{!u8q9xT6OsGrEcE7#JoKcY$&q9b!imN(F*re3fM{&8F?V+!cNSW& z@dl)SO|{yW1&h*i5uo*|L0SlV824~}GEnGu$nhVJ1y3X<^5w^Zf*vZF0RpHV+&dF8 zU-Lwr*dnRTdB>N~!JMNHa)0{VYQXcOr^6}|YGL`!8gl42op|9w`Oy7#9yCVq3b%bb zC(Gb6GKg}7J}0{%pb4_uMmVOmE^FZky=&;}cy31B?^0Wc)8d2ZRYc(Hj%DPFvIppy zitmDdtusd&3QHfg9;4|(b`@nD=;gDF8u*E?{+%C z{V0l@e`$M+n-9(iE|a#=_e6s3v_w7Lnz=lX%>o@0}eRW>CsHDWQLxgUuEt;^1v0$+Uh z9XFz-8NtovTIVO7ulTjOCvhmX0{P`stC-UZW!v%} zt?`4lioJ;c9Ur%w$6Z!_0dOq}bzmVr0c2+8wEN4O{-%j|BPnvGh1lQy zKc}j@)EQBg7ZYa^_OFKPHKkT$3$&kmy)A-I8&l!EfmbDeoWf2r9|RUon;8<&ui|+kppBD9x{T=}E|n#mOhNPd6~6jKmlV((w!< z0-P<2E(;+jVI_*8p&yJ!L6`jt9}f=pPL>pM_h|w)(Fw>jJvOWTuZhUj0bSRU+s8Y& zD9lkAcHA?_XaWzf)NkJ|R1B&qCGNdQ1^X67_WPgHl!TbL{e53-nf4*N)z7n0D(EN? z$qkPRKx)53rg-FQmAU&|$cfPQGK#+ISWU~+gXZPNpLtO>+PN=f^~yoSL+$1t#@#It zI{1LW@$gYvi?mM=*4NvTq3EWj^Y!0PZ1UR?Er|xlE?f&q=052 zpf`8)A(I6}v{ALOOCrieS=1RXPD3t4`xZqUaFl26-+8THeVV(94GjQh5suXykBrEWvC+@adf zR^H!kJovxxh%=)!1mIXV% zuPWyR>D4X|hDc%7X@XmI>R5@pg1s%vCEGU}I_Pi#J)u((@B1l_s@}K))eaR~cT4)V zAM9#{8=hBN7WvxuD=87h6z&*Ddg!R}!jj^LpR!rhOALKb3GdsQ`KY z0fr`3)B&NMyNBX%`k}bm++4==-cuhNzS5+r@X)afTMcX@J@Dtx4&z1;zznOV96n*X z61Tc-&Z(vZ6^OFa^D;T(i1v4Y}-~>x82jQ{Z*VS7|>U)-4X@mg1^7Q(#yD_>`~}pV7Kya zQp*;@ciL*)fnXg=i+{~sUt5j`x(-JdC8)nM&??J|gNSuR_X@P`gL<@wN=&3x)X$0i zbrkKTu#%f6eI@XDr<5c-8pRU*xipX`{BlV{Ktzu@#Tx3#_T9SWZ7aE^-@43I1&g>S&r( zVm_XE&bLYETlZYDPa(dm0$+izFDa&A#N(s%dJsun>^!uZ01<4fIe!`Z!&mECJ3aS zV_*lR--2pXCJ98p<=cl*rYg;043G2EW)B9wZC(&ovIEzV{%S${o)`{oulfD6s)7TW zc^X0MGYx}lmFIZuoBq-u={$kYiTUL!Y&MH?A!*2Ka}(K$-FSz>WjA4oivqaaZ$1RS zk&H*oTOs52x}w~^1;lSl=4CA7w@AKng|a_g@Ming4> zdWmAYs*6E;wISboi?19KM)B`boPuO>vAX& z%HV#(P*HFjCp@+k-;SvZv2+Xdzp}lfkoL z>1gO{kUDpJ6Ion7Je+FF~{Q_x8Gt%yg4R#NctQKIv_Os9K@gjW~FFF0I`4*X4oLY`fQU4A8U)Ox&;&(GvYPnIs#kXu94WMvkI z*dkt;IQTg)<`k&fU8#Q@<7@E~Jk8JF{EWrEZ4zHe3jbnDK~szCPw!$hjNX$vV6hR4 zRlS5?0Af5x12i}|5ZoWrpc-ug!!bRn^-G3Gk}umV8i5xNIPYSsF~gS)Jn>ii9n(BD z9KlOsow6-ncJt{Nc*9`_1iI$DKsl1=t;R-AJ1Tq)7GJi@Upx*v7dzXIN@( z?DoN#_^}oGEz}EpSmB3HUi2{IB%aozl~GV zvTbM6O<9fqBs%DtyKk+)#;FCUms_8%KmP;Mwyd`i5E65tXSHm4XW;P7dI*-5JC#~^ zH^c;zws{(JV@}W*l52V59K*uT*w~fm@GwoKd8NH^GCj4^}+)Jk=eURkD= z-0{iofk?C}$`R2vB^Uc<6>zwbK$S`Fn%Fw&MU15dM0T$d^7#U54SG?XrXaq?&-lBa zA(+opSMycIk79zyga?AZdvlO2f_rtD@#&(7yw)?z}pa< zXyD@Sa?=(Uvgh}v;gDmg5O;x6IJa9~T!GxEPwQ|RQ5w=mqi}t;Z_MzQnH*py>Q45O>=F2J=QK`#bV}& z8I@5oTDaY=R_pNwWY9kJ`#xE0E^%MPzE;ak9!!f1Fd{%Dm~WyDo1ah&Gj)WmHZscK z>o0^@pG=(AKB{<$-9-@%t$x&DN31~4KRfRD0aXldc1&BQ@;Ecik~;6JW;V*K^m|iP z_N}*P8r9PDA6MEqj1zS!y!|pniM~WD%H%I|d*7?_tp~ zSgi1IFK{8tT~7V@mQS|8L@mRiHv_i>Ah@w(SpGH-1aNLh<{8r1Or*e|7KK}LCY9U3 zx0Sh}=>#?rV+-dOIU0{h7r93SB1c$Ny8+_5_rt#H%svvJ#_B=LpCK#aREfDLaG6lX z56)X|lbts|Bo1m4jP<*1SCG>Wm`CfeGefa8eG@4Cy?o`Yy1#oCd-XDc;!ES z+RYXhmaw2TxJ6$ZR+Am#u^V?2lK8d!#4I90ly~%p>j_7GKHT$72O;YpZy>+b$2V*aSW_DKVU4sA#y`mD>-BVcnipXDlCRB;TBSzXy8 zyc>*0|0c0$>yr0(I?SH_JRX^6Yq@0P_lJ9PX;)XGpC%*#++AJ{HYFjT5_!#yh`Z~L4EX(%Mma;jc`cbEOUOC-Izn&68%c+ z50<}JdU*27x!F;jJKC(96oRQF0)Jt{*Zl`*7JI>9-kqT4Les$0g`IiCuJaRBf4uv~ zTXm{47LaJ!f*u@C0^pQ=Z*7;M$yoxM9f(D!VUZyVYQv~B4a)@B}-rda8JoEwd|q-&!?HDke{A3YszGt!UdSI>JtIcK}YfU2v^)Af7vx>Hjj z#_&^DFrnS1V&?)UlDW7xBGu}pT{sJ4nvj@)94o{(*7)O2_n<1Ii$_MSlvO!LtzaU5 zyUjtRn+doV8E8Ig?5#gU`6bmZPSJpF^sl2gUSQuqv|g^HX4t*gPuKIEU#FbcqCH%+ zR3~&T-}Dyx29TXF&Om-ow^b=DAc_+s?|KD zZu<>uJF&B;5+o4hVMCaT2>iOzx~mI7LYw!D;F-YpCQFx7A*vv|sV4FSeY4Mdt;2fw zGY3iPvqdAomoHyb`~tNMP1d`3dMHT29JD#Vj|cC(ZEV@TIzGgC5jQIPjzGhf#M`!~ z7VQ_FRN6M*rQli2lBNIR-T|!D%xWhsU<$c+oQdbc_$lGy|#{Asz~_Zy4+efwIUy_y&BV z5>%UuYA_X)HJ6M4)ks%03SZ1u8yz2Nv%DTb(LZk8?g_QfXkvRZnlOBGUVdHuC=NlJ zX6h4$VGMg)bHK%IyQ0-8m45XB^>GG+j-N2Dd3l-B=2lwJSF4B%78h?kbv#plQ#)2W<5YQ$5yFM+k@@qd_sX!|WTY9&@EyA&3%K(04kXrw z{E3nPKA*Wco^YJx7z7&a_GfDe3vJxi-Y(AcUlM-4elF|wE#;T7J1_LAA8uM!Yq*a4 zNAWbfXx2(x?JQhp4Qdnh)?Il0G3%g1$!RE6m?h>To&H`as76g7PW(=m*phVH$=Fj5TnAo#WgyaB}pTYhq- zm)HlcyaHL4ZSAYU#1$0CLqPBR{U4)!8zC?M7V_513UB;cm=h=}dgY0;y%S^WmEXxd z4eK|b&Kfjw-^%V@7Juu4ppY_`;{@S2iCMkbqzSd%B=co3cvHF!|AK>k^)3 zLm^CXHy=iacizG-lZfGHITFlH1+sVkQ~rGybUbJ#@MfFLeK!x)UAa7ltz|gw67Iy0_i&my_jd^oI&ryjL`uT1OouW5 z%ZnVO=Ka#W6L5C+&VRD-i*Em*M{^h=o+ZiW%L!X$F!eu8W3=-nP>z5(_Z<=^poVvl z$E?}x<@6jBUlq(`9q?f~G1aw7w6y6Cf;CxTv4PpxiLz}?2@N6IK}YN33QbTeG?^Y& z#X*Jb(P$gr>zM|KF0HUUImc1P6_5@xAe_jJ8o=Va=ac`5Zkim_E_gQWs7926gDE}0 zJ~9q|bs3JA_G)2l6D-Y{v7Q)zoDZGo6#wRz^bx}Z{z7Miek_;TuRLdR%)KgkB^}^&PZ?q3kDmy2N$VHtOy!;+gXru;>oaL%A5u{S#8T9@Dr^U_sqe9hRp2r({Yd3FgU!Iw+aRyn?}5$^V{@R)o*s zjV74%%LDHIM8cZW=oLBSvC%&jF7sJrRwjgqyXyCF!Q}DNUk%2ZWF!8i-()v<3F&{M zO6&)}X3JEw(lM!jyvTgMq1i`YnzsS>G}&p5wpr#c%%ORH_ZKPU*ue~*x2{UoN zer1Hd9j+&C{}r*%6kg1eArvv-oHe+& zzuyO@k|d7@>l{{(QI*IOP+$`2+Q)+!SP~8;xZ`PUQA8)e2qRZ~blbf(_a{^QTa)QK z?9CA86^mxKn2ltbW79KvpI>^hfeTd%tPm`EIHx;$hq^$LbAgV&<5@U5=`1Wr%YHso zOR}Wu0p0Hi+#)@@c!l56Q=6AoLEda(KDKX zfH2`yF-RGShUs3&6p<_iZkS-SB|ci-#rS)2(DzL7-%U%g*&#z&-U~Yu%c#oAZE0^n z;Vkcsyo0B<>8gD-{x2qsY^gQ9iM$8`P_G9t%S`i7^@ zpFn-i7$h0E0PI|q$nR;VbYQ%8qcD__LsqQQDz6jvjtHy)A0dNBUZwImvCd2WpW4BU zz8K!n@(EqDaon zt^6A-E#t?7BOog*W2_GlCNclhZM{(l#d@>$cW|>sRe0o+Kl^yAjO>axHM{@I#q~ZR z>6c12^NCI7x7_5z3p~D3xMFYIWuyOm@1a7f0v(I|zRc$N}rw0mvcWQlGY zDFp6+$R~?j`#qY%HwLg&w9vB?Gf)6KVj z;u_`b9ZYI*I&_H6cfXu&+sra|)qr}v&Zk|3DMj$@=eKnt)xPq(X&y2<4JTAaq&(Kl zqJm?kQUeNSY|Hn=O8Jn;m=YXXnpARYGFv*R5jb&Fm-Tw}==JGGGV`HO79-=rr7eyL)_1G8+AKOf=5qQ)-?$@~qa8@X_sOpO`s!vA&U3y~D zLR~JG^RFxYT4#@4QO-dII=I!|f(^LNwN}jTZRQ=gVHCy#8GJJ(E>i1IbN}2dcO`j@;`=ZeHu7sLq80Bh)j9llLq>k2)38*t&XQ>&a%C%FwB#F7I z-RIexZX5kk_^n?og+DDD#xa+uft_(T*t_8(yp1q!{Xou`vTc?oa?(b7h2K#02eS0? zt<^WW$>4?FB$Dv4>B&*=)=z!D27Q1sjw*kqUg2H?l98c|MlY)_6J4*8fLTL0qaJJa z;)LPNv+Xh^vVD%J=_&P!@tXy4U&`-vmcPZ-rPe(pM33Vr` z67n4(t95d@^fb4Ek9HmW$Tv^2Luo;iE=c_Eo!D{fs0%`Z*v~tD;zT3;P+6Z`Xkg$e z+yvEJTdU@6xlo#h>fg>YS!M`;==6J4w<(VN`pwRT`(yzqOnZ3$cApviDdskOE}w zfSm7zE;CC0p)Kf$K?9pu#KnozdDi^J4yc~@p|2{+cI`OFb0_b1@~9--cyzw2CS+;Z z<4OEWHTlHIcGGNed@J%}d+JIVBV;h$`x2s@iB*z=nO_W0d+3TB;#lvWBQ*gR#DP($ z_XbG&FM5NG9~`DEy8Rb5VmOwNnctV77&KotOg&-8si}Hs9c*k}uZ!YMi=v`AaH(uK}4yLqc(r_bze= zVbS?)_exV%JQ=S&*=frn47NrO*zYbO-Ik)Z(X;apVK(4QE>egrwobl8WfQ z*bDu2a%{u^3mTFV{jmi}ZXdbq0lod=4R;Ut<{(F*bSUgdDUXVPTAGHqp?7s8DT3vK zIt=RINkMW+1Kre7aGgQ_i^u0dAK&}CMPAMc9NhbQ+ztns-*a3hwSR^Abl+^v_Pv@A zH#93otwFr_3T;kk7t!Pn>iXi?HY`EB!AyD?AOD?1@_9cTyMy8nt`_<)VDfW`IzG_~=wZ6rw2oyBJjN$iMAp)+|3s3GUl#C>ShDL_?w1xL|aJw8R z9RrF(F!HYvk0Q!}Wt{ML%~-he>qY|6XG%`X@7IliU5$;R%BZpCQFNHGh)m2H92}jr)x(WIro5~W8;7Y2U;^?^nt)=P6pO=8*hnqmG$MEw!Pjs*qKftzL&NA% z$fVLm`@mD|+i%#9{YULvPqzY3BADh-yqqHW(>dgvQ|vnQ{OK@CpHcyncCd9X9MFy? ze7$#8gPg#nZRU>h{w2rfRKMNAo>ehT&Mp%>Cl+ApYW%pGl9`AU%%c?W_4a-+*3mou zp&zkR56AN}-5+*VJSkgZT3Un~A^KqGM5^@%a1t92zbMv(cL3`34&d%37XO$s^8eVS ziATsEP$h7QVh7m^tvyYyFEW>XED9-Acpc$qUXJSdngDq|3dWFL$TMk_tU{a-u1?LQZQb=FIfiWEsK)g+7+Digq}Q- z=8$WOAqjOx)pf)eaZ`!CP zRuaA2?@mMl9Xu?>=KM;+?>nSiucuq|v@7WvX*_Mo<%BO%8d_GYBqnF!wJqr0&nJ%OC*{k1%7r1`QVbsp6RV)X-QZq*EahJIiLIyP>?pvP0CpJr+Y%(v90wLtl~wQPDizyQ`)Mk@h)qYwf*)q zAw#cHiLXfimti=__;)L%pw0(;Rv}~1s)1-XTJ-~8c9Pe~qdL=o=uLd=5kTEnB{Jc) zMC?gh@{{R~&a*{0ZtRP%uK_~kZakwfpD z1RM)v)|tI7ES~?a)$I?=)}sn|2fvu_W_xISwA_WA(UcwZtWm=WS&-v{>F0l8SnBaf zXpn+zZ~k~6VsvgS14H6Ncm=k3?oL^@f$=jsA0VpWo0pLiH{B{RRjRL3iCo0zWLP8* z>BQf{vs!Q{=N5IHwED+#i2BI~BBq(b@;5wvWKP1(VL(XYr|5+zw;muVJimre}tpLZTab;d<47Y z-Qk%b+NK1)6&7dyY~=W|1zZw)D-9Kd$F%_A7O~M{M9IoG)?iUM3=nJ&hkxwg?;7H_A zV2!17t6D?BsFBz3R;0OXdlgcBjFRZ@0E!xjA4}q@8bYB8X62er>Iv_X=qJ(juiUG5 zvtkvfB)JxZM;MQv43|1`l#tFvU+~Hr3x3Zx8P`ef>{a2TPX$rU;O?L01f{bl zu}-{gXY{GHHbP|ZFvXXtM`zEC*j2WWfY3;gTcUO%Q!yh?r&Bh6_k(qC!0ir_e1dW)2FHW{Rf;(d6M=P<}iH48(q+y(01fABhfAWTAg z7w^jtA$jlk=ZqU_$2$d=rTL4Ud}WeeLK1v;g&&emf&1L0gN${HbJRl-#KHDc5j;h2 zp~f0!Q6Zs&80x@nrkox?DQ=@Napc=;lXkqX_HeU@gyM73TL#Y4nz8%W#v$8;$^K>G zB;LRF=R-nW?pPV>62DqsvV${R@3^1S4A0ksQWTUe{FCk~U2MB4m{ndENyWXwy2w?-@xW=|hV;FRavc>> zM33h=ylE(qD}W3PYlY$xKs9nF2M>8lVv+vlW3Vl~q2nytT<+AfxsFUV^O%yZRz-!G zzt6~03~cx%i~kb0>g^`ioBtB-nN0l$Ea+(muHmoNoPfV{bzUbte&uu&{Vc`=#>A_p zM6tE4IsqTxAnnr;0Ot{k$aMxoo*zLcjBZgVg9ylnur`kw6?yV_H~2VNJgiQKcU^Z)G{#$(~&}ldh#p_v4Zf$!0a!sR71?W z_agBL)-nZJTIg_3UWz-Bz%W9M0-8g1M~S(mjFLAPgI9wt!wt@%jLj@3DK;0N2hIVQ zH$JC)?LJn0gwT&XLgmx!BV);rPY2GbZJdPQIv~#o?<_q5wE%>_ODE7cP27ISC#;ONhy-q^+ryNF3U&^+y)yeLy~?c~cF01lDe zE^zSxZ8rC2Sx6(IIF0xU6b7!|a*!tdU5b)oy~!cf10QAaLW+hL zIvJ-wX$-7Czx+~)A&9og(FCtr>9r=*As-8axP&NJqyB0CB<_{1vrNJ%)_Z){q$E<` z+E_kqjjP0rLZ_mVWPd`}Axo0yZh@ZRkq5JcP-CJL6k|$9KzvYP;`v#ygJk79*%xzW z!f;+xZg(HU`H4QKq=f4)QaQ3BIm`<;JAE~xn8k|~#?WQx`jbxODw6aug?kFT zZl(u3ykYc|Z`${0FI?7i$zEqMir(|gf3Yx3UNMV0pc!%q(!148F)y@=niIVi$MHg# zIv`D2E&U{wc$H*tZ_oG4ri5|dm&x&P;Jc%{gOIYaN~A7~m07tt$#(xf-k^ZNuJUE# zSYc?GgM#{es{|b)T`K9L%=Viu{bJ4ChB^T+SCg^%YT;XFNBX=5p8p8f)XA}h3m=c* z1CGk2DmUu9aZ?lTnEZ^*k6}C-a6?MY&bOCxn8%XcuhJ8=;1Ee*4 zH3e#kHzc6kwfdk}z9I|o1tOLo8?FON&b6izE$BFuj?v`5Ix%*VH&(doGf!aOzRAMr*nAnNt3iW}mb+jFN=n-2Eg$XR3<% zBn!_TpZfFn-ipIXZI0WLOD@)ly<|eac6aq$gtx^@2hfp{mUym6*#eltUsXS+8r9cKRelt}cm1N&FJ)8jv}C z6`C13H74Yk`M&uI{8KSMArV!z8<|7x3O<@}rc3h!od3$$ZD0Kfed_#xR^GpU!HH>5 zGXNRR;(L&%e|9|(Odk62gY%-sRBL77($$x*J_f%L`*f9_frq#Bik74UCq-0r;*U1p zQziydws^P8YG>9Sz3)&gj`>^AlY8Gio{deSCDGs5Sp3R5On!IOha=9DOf9{^IhIw# zD(W0H@uYZ>LXtYRC$Z4#?PG4q-3)C`i}1}qu>*W#y6FqRsdEcJGF*jFO{LpGRw@}- z_XJ;DswXB!GZ7HW3qY}~Rm{>-=TLnv*YQ$$VAqoT^N$&4{_-h(`XqSz%x_y1isR;# zP4utmBl(Le+=ekR+l^Y?OcOQlLk;*Ge$4;wVGGQfsF+lo#$p}UkCH;Jb!zILrAbZn z_3mw~ZH<4@-?l9u9d$0#qmS^z>ozVd(x4gev&g^#hfTrF@@$C+zor(Oe@TvRwiKj( z_(B=XB`jM{?5IGxKrKH~;4_1)s=o_-hIAf`(CVISxJ4)liXqn_S?Glyq1WL0B*AF| z82f1zv-q%2m#6T~eH|ROJFEm|CKV~{lZA_o#)%~M2BVAn73M2>MSN6rTa z=ahL0txo~+j4VuTGPs2tN`5z*ZQWmC_Pp;M()!~+ttcPT7aK)P#dy2De1Fz=fcH?j zz4*%gBwzm)rs|3NHed475cD7nL@s|?f`#D3I(r3vvX33M;Qy`D$r?=}T)ACpUaiYb zqAM{k1%5)$bA|QvCB%uBNM)ywQESjANDhi2B4rI00R_$Sne!*sE}vo_V-W|cqC|PJ zHrG5@%)gtfkk568xwRgYB*t7^P*qWRH8EnH^R+7P!MvKtDVl>V!#^$Mxy~?$rj+GY z)>rx;j{Yv~;q?3+mmRU#(CYn0rtcMc^fnSKhWLtiU;C!QSwsGm-W3(|;@0>!?eru$ zZ`V2Z&FgEngnjsLXGODJK4c0)T7US-u5lf>hzf;TV$sH4Z@5WhTx>i8kJPx}4aIAB zGTCGd^}!cznm@*GTWVonN;5fAH8taE1P3Q}U4)Y~G5tQ$?Daq;`5D`|IBWOWm0>;XO3u5S#ztvntPx(fG>_!gL7bXb;(Zb~$H6fq3EzYyWWFd0So0QRnpU^ABmwpi7i0p{oz{p z`HneA*5UigQgr7~Q||dEW$TOr0@Au#d$whhn_1IAb92RS1;V5 z9eqf92{-(J)n&H9{Fay#ywBxtdYy{1tc^M9Tq^glQwnFd%|8=ot?GC!_UqT1l;WTC z%yT3-%PTK9vpW;R`7z;NJj52CyUf?QpuX`wI$gUzQ9`re&z7;u=*-ceFy@#Y{3<)D zQOhUXS&Uo%;R6F)Q3o>b`X$SWMn8-rI+Fv8WgkXwzxm&^5X}pnqj7VlNdzlx#~|}v zfQ_OO`I5PRr;zOQpbJ33wg#9@!G+Gm$~1|>Bg`7q2kCqlh9Zb8JDAKx$`T={h={o+ zVOVu!wFW$n)VqEAw!8ZW2J@FMbA0VAZ7YJ*$NX*Cp3T}ndib!St{K1LFwyAaGx2p% wIJ0e@R#REn=Bm*>77RHe-Z07jR2l>!wtjS?@&pd&Pr?6846f*x>N=^^{!ABifl$2Q}CK6GQnrDB~6abT92H>AMA4Nd^e1CwW|GAXufYJV3aRDfQE~j|^ zBuu?3m1UjsC-u*2=XKE@*^NxfiKxgfFS#+!zj^eC8u+@jAHTyDr8er|&*Kr0j4(O< z$Y!TUWV=&(yEA_)@}ole{(!7b5^UjIX;_CWycAeP{CW2}U5VuaUB{q;fCREZ>vY+d z=pUH={22kcH5^d^cI=h#_k#XDdDqzeOjlu@?$0}Efsd*G^dJI)?7^R`j+edA%*x72 z007W@c=>%L=h8PZB}M9%q&-H0!^#OOcASf=`{P(v-y(c_a*++$w?Ey(1z0Dp9UU11 zL)&wrBzl9ZGhHy*hcepJGR|DL`*=?AK0HAFwsK=@t2?|rE|74@?DXldzfank;VGWv zpZ?+kkS~>Rcy#M`%2k=;=RxFFRFf@wb44D#QBdIx7Awy3cWl4jx;YMb@O$>_>}sXu zhMn)P-9NzLpIe(1tH~lBziOc#?G$`9_CvH~b@UMZ#Zbr6TGO)`4;QDaRS|^|!;6TcID zz3N8D_iX)hpJSx{q}k-9{<`sqsE=o-sy^y}#uyiHcI-#8>^s`|avqjDJkt7*$3fAx zs0V>)3SP*AHmrTWey#XcVO92OPjd1si`&lDVV=y3Z&z_~l72G3(sl)?l&)}XsG3fk z-u5XmXY+tk{I&g~51Ic=od}5Mmnh4+MF+&2ZBCOmC#_>-J6+ZiN`_p&u$*dgXisU^ zYH91_9Pa^v)BNC#HsBt-PQvq`re`TAzsOdNUR%ecu+MU>8=*DRv3J$SA~{nK-%4+qavD zXSRS=&rQsvam z{cpAdL{Y5ZSE9Gb+9P_Q`L`Lc-(XLy^+JkcF5wi8*4YUHBZa$+nG(cXs;zvCyVH=& zR+?}h7~Z2W5&(xN&|6F3GWJeL^-sfb0Xmh-x?+8EvZ7&;xR|Y@wVnU=x~BP?_|xIMk~3X` zSzJWw3^_u`+St&zvq{^&e%RpCyHs9@`@<`_nxVpPP4}u$R1(pE`uW&TwvMfqP8$%D zL;oUJ$_;6`Ve4GxVV_F#(uU)q7fFlHKIcNqC#%uAeImT~qtl3%&73}i;u=)!$sU#a(- zf&m8pxkI4EAZ|th4ne1E5x3pg2GEZkof*E=)(yr{?QjyFa>s^lHh^@1oOHOF9)1?4 zbePKJ@-L9#4=smL&+SYSQVKDL1k$qNvW+psbApka-U4mB6L{HKWQ>~m{Z|>Pmk(Q= zUK4Tqf(MJ$9>-y^&C_KI^=7}eZ!Pz0+;qk=DMySmyq?8SO4uHyy3~MTvVj)xO_UI( zmb3fRnH93ri6Kxj)aG$R z)a67AQ)DfZg(B$C!dr_D=lxS{ zmER)%XY2-{xW9EspK)0j4cmqqI-~JrN&)-u`n*Se8E-d9G@kp-6{x56su~W38nssh zo?EIL>=eX})-<#W&0n7FyC>M?RqwT#ygAIrd(b_$K)tULSB7yj zIb&~bS1z@99RIT4;!y>b3?eP*-|2@6O=GaL%UIm79yQ|LV19+nq(?f~T$A51-sZ-2 ztf&Ifj&}ZR*Lneq9I!BdtNpU?)zz&n?@P6`dUS-4>o8WL&9&`7hjN^~JTc9UEa=k{=DrG0*r=a*Kf)5@hS57QzOIYiW%Z}al@QBAUtZeH z1_xlP*NvFN3E zYA#F};Naxx2lD1)Np(r!kr1`gP`LBvhWCsh(B^mkZp~*hM1NYpkR@phc+*!p8cg`` z+mVVNrv8tq)d`UUI5b-||DN&OgN_3>-VZ&hm@WzYan)m?`*6B8Hkes!PY7oB_vYGV z->&LXXytAAEf@-LO#Bu@g?Wk^8;#c4Mk3zmtT=dDT9hXNdgRii^DhBu*%L*wajoOx zUCVuiZ)=R+8gE<@XGY$t-i*Yt=?vjAAK-f)iCA1Z%~wOkM-dq=74yb;8&s+vXYtB=$f*C3!-+wTb4(v>#1=k^*H0baL#di$c6kF`yBiZ>38@Tk z^e{lxL|tG~Ga=MD3L}Q>FnEPv zj{>ro2sU$PrU!_gtoCkyZP_v(b8i0d-D-X$gVGgfcszZ0bC8zgl4Q?!f=_E;8C>@3 zj$>uxNwa&S3}Xz1I2|YV0tfc97isbxbS2Z5ZhGH^2Kqq_!drfVFmF2|WSgUM2_p{FD|D4^hY>7Ks7hdK+zd zSPzs7e{8o6K<-0RXz6-8pX~02qHvC(S!`Fbfk|#7!?)U7(2M(+J|~1X+b2&-;>&)J zkk|dUIi=8~aIj1FNsii6~)94ga&=V+-6@_MRHw%YMJr>RRj4Cy33I*tb#rS>BKc!~cKZU%^I{oBN5nOKm6S+Ck z{O(IobWr1Urfjw#lN*Z=BPZMN?uSw>dzucz=fEy83lYBwt?l|8-x zXXIoCmblT@&sy<4$&zB1@18pzop$9Fjd*J)W``fJRTd}r_k@J2L=VJzA@+wQN*r}E2G!*LdEk+2bK=)w}!;CgZy&c|I596Rl#77%z*^0Zxn1#DKieOi{_l z{65q4T^Z?+=#;{youAQ*{UD4SLSsL-)PCr9IA}ra8(8b#?PSY5@Rjd*&vL)eiy03( zdRYAZ)Oi{Ub}BSxu=rqqbV5zwmso$B`!B)cZp+@R9j6pg3>zpXB2{~TtlSm9U2N)h zZhD?)Q%c%yTE2fGIzP*jeGN#N) zb!4L_Ei1QwxwCai7vt9ta);1cA)anZwWw+UZMThqKkr8Llt>J*}?TAny} zlD8FjzeeXawV-v_hwL$@pXLF>q+u2ro$Y;y{XIv&CJLTOPCox|S+EX8Uu z(sa13TiwWT8H>T_tzr?5RvCGkq^ymDU_R0a9-{9$^>O4Z?wch?{NNKXdfNM5L0zdT z2cMgXddQa?g*@m=cSLIzl2*eYCnolna2n9mRv&pB{pbju=(v9vL1#fc|t^8g(8 zJd$H>!KYo#X1e+LQR+D1jiCmqRTlHwhhAIhalP;@arFk zFc&;S+d%$=a3^qazLw^XM_FY04fdJM3rzYj7spTFO?y|b`A!ZpgiTby`~$DdrumQC zyi_Q1)iI;;+XWz4{u3OjCq*PeUOCLp+G^BvfRA4HX3hrcKKab)RDmrRGwPl^Th&#is@Ke+~=w zRxo&i@Ao@f0l$J2Bs=gWsBKuIwn`Aj&HOXrM4UISjhmQFq0{rTJmm$4t~};s+sv^i*zizd7TDOpc%_2Rlo5}IMCLF4yOxs ze475AKnuBLMs6}XjY|W=-Y*~|ha=oAstv@{M>=9~BT3K2@lywuvxh)9^fB&z2R7%l z$3$<55jJ)}S2l|{8Q}a=g0op-m`l+h=zlC3@EI}@X}RZh3h7sTvHK7wm=xKI6K4UuWJjnDtdG_yS~Yfa23tm@}~jdMKF^jzTBe$R0Sm2TlDn3rRgX0a;lCX zVjWa4dG57cg4}?`5H^e9OC9NteRyoBU#M&7Nq>f1MnToGy@o&)@(%Ig+6U4I8w@kM z=V3}fUopBW53^|p`ogjLVHo@OcT_NSjd_MSlTYcnI+ZDY66oYnVo|Fvkj zA1QrStcXp!@G%Fi;luYzVD{D&h`@N&t{kwMCWO}-M2?V`x0 zXh3Y>fhmw@G7OviEO?r7;bC7jQ)o$F5M~EV@I0gj@Up&w+?Qc8wVp0{1pbEaA;ZDr zVK!EempZ}&gg#~N_=tvi1^Vr(X@!bBL>*U?dDp#j8)BOaC&0yi^-|7c8=DD$KpM*v z-bDu}Nn!d_G$&mp`=Ue_XI?qcK#{=sV3t=qA|^39Dxj+?A|Rny@`X=fI_WF#$05tG z@i?#y&V?9E9pAh+G>jV1O@fdYANgfpKmYTaC=%1Ev2ON5cX?Chjq;b?x}1Dh5RU}Y zGtG;_@Pv=XH3mjLnI@(&8ehO8&&~^IBB^Alj1lsidBf*%V8RHX97v-9&;00!Q7t9) z`w-~-Ydj>O;e`!|4sbZ-JV+N>wT89e`C#uTl=ok2-G>E-@oAm@em26%_{O=4Yr5{n z#9%)T%db`Gct4BB^0T3H=nyE1R{$;xv`P^zX)k#=-<>RaxXXFCKt^a1hAtQ5+w(aU zmDlb@TSfb9fbvrB+BVo^U2=}|w>t~jQ?82ThvNr07vsb3(O7!c0l8{+?iFm@V8lC` zql)G?eFNmXcEqU@yG1Bn)a0Q%8tqiJ-g#_Ww|Ej{nIEt#LHC%Cnfub$%ukV->`TpMxNiTN}GADXyb97BcM(oY4dB^%J5&r3#Hq1M+-5t<8|w! z!*n$Ov==EWYd&eEy3GO2X>tVgSG9Sv)?I9X-kBQTH+(j4MxfTO$JHXUEJXPbscEgQ zEBAR|GhJ2D1oh3lmQAfQKA6k-Y?_qGd4@CO0Eq>yocD3>^8V|ZTEH-)fp{}9&jUgX zEQ=5cQVSiEN>Qi9hUqOey#|R2uW!(%crJk3;BC-%C@U@C&Q=Zx0|Wy^A$5VDJTMmE zHs&KmzF1D64v7NnhP)sTZ?jacXl(`Jbk@F#0^23&xtMS&Sl3?$-r(MbA;M4qCA7z)CNg_ zK%8dc=>QC>Z^Y7}oCZJ*B6ZFn^4EFR1{?T(^0kaKQAsAXL~F&|ya!@lJcX@Wbf7dm zg*CyR9?RLK3JelHIx)QF@_MoAuCJ5ZYEi6%6xS7R0;yYI>LOfgx?A*XAAHV?5C^{{ zK7UX#xa{X+<|vJiJM_NPyT*kY{FnYttqH|Lkq1G^7j57Evv(ZCmmK&KU#4=%fr%1NZ( zWVZ>@nK-dJH#rL$tW9XDm4~(ZVcaYXWBzHk?3b98^da%ofP&Yw4JlMyJv6QcVxEy; zLU~#_&57v7suJy|wojb)t*-GJhrH&6ck_ia(j2^pK)605r3T*Te2DR>t0ciqShB{| z8tpb~>E8JJ-x5Ahp+&JL`eH*Duy45d{r1!l(HIz>3dECeOuky8LI0chV{4MBK#Vtu zXvF4w7*ok-?taqrB_yU@NL-=Hvw<l`vaE)|u+DM!7usQYic*@M)kn`zQt1jY)*)J;tLfYh4boF39YWS?>%mG2Mg^q@P zZ`IL}pwd^(UNoOlNfh#4PV!({mXn=qpUYcqKQgmoK^WeN%9sOD7lup(m_oqyTjSW{ zWX@JE8o=Rmmk>&~%IK`5aOT705p=aVaZM3ol~l16X`rHQ7ZN=`b+plpU3*k?;o8M|RY8Vl?5TIPnUgn_MaD_jv^lU3v3;HSszWcG#o~aQna} zMj9^9ueM3&|5?CcvCe8qpv`jGm=3VRp-h;=j8~Re#3=)eBNfbG60(3>41Om=z@v;- zYM#w*k1rtS_wCBR+=lE{-d9*vKVW5ZQ%fX`ABnoSKjZ|u?Pp4w@9Q(w%%@BN!O)p@ zc;dkK`x%qFt?5sc7bu6R{@o_;yIE|`h-*cj^oi9A_d{=QMin!yxVG|ozW8WrFTLB= zL{)w2b~e*=!$ZI;|A~-pED;hOmzgwh+#=YQP3<30@?3$CgxkiU*}VB+d5|{4!N=4! zs5fw20!`c^+#tK%TV;J)Id%D!aVGw&Qy*iTnDw)EIChufXgJD8S1R(FB)6b5$00a^#NWQ{n^fByvG ziX)jVB#srOdec!d;Fxl@gZJ!?8b>~xn4Cm<9Uyx-w?hDP%n@+InA@5)(2K@_o*Ohc ze*v4grde1l#F|7r+L9K4olb1w^8y3b7x#OU`=NKw;?nR?ocn8LZygcxC7Sek!x%7# z%_KDfo}N^M#R5}zif#y;>i?h6N(;y;{(8$imtf^!Gr?`ik*eks#Np@TW}u`~Ui+6m z1#j2u`glk?>&^G&6mWNYSwU%oaw&m)-BWX_1w@S!@TKDBMl>n`x49=D%kc8#qG?!C zMa>l><4%QfGj=}Nmn3_4ot}Lf{3*Gn2ENG4M~7X?B|XG1U$un7XfpBzT`Ypp<=*)m zVcjq~^@fU;#nEG=x4eH2Ny;;HVKAVnHEFTkK{x=?AJAn8 z_L=qud&ZjR(1`v_@&AM$is&%)@!I_#R!o)isUW5g3t|GVQvw~_c``D~>)IC-1K9o>=9Z2qhyMKqA+AnB{08lZxlbuLDRiqw#!;8QnwF0?RLcf zOW+s(FKQwW_MiofyIziXyi(?{g4KUIGQ76J={k4xT3|77JGc&ed-n0l!Gq~eMf?Wl z*GEyl#KHBcX=w$f*^$G9e*9KZEod8;i(89W*YCfLN>1&TdPz*_*y*GGRhJ_m799V- zX8Qpi0Z0E&DN@G$t3|KVt<(L@`me_OC+n}q`}h9;%D#W@|8Et4@Bg1F{@(v5Ya8dk zwf*1Hj^w~9p1(r(-~4|?@P87LJpU*2?@Ry4(|<%fWa9bI%|_yoska?<%q0#|hL+U8 z3LSqX#t&?y(9yXO-HnEHz&EQ+pCU_Ov1*(P>k67+G`YTQ<;vPW6;xDt`t*R_kNv6c z$3r{?6m*geB4CR}CQt4`$dZM>C5U*#J`gpQ8mW#gQfQVW$yPj{h=rqLp>41xBX1=^ z&%3;qApitTjglafa0DEEo$hb5|8zX~ucl9)0o@_aIu;fC76EBTO5T6*@wkKt*v{(W>(5xzQzl2JoG7HcPKxrk+s6_Carf&%1`9>p zbjE}tOiUNiuet6Y7>bHUD!mjvuW*J!bfB7)fMaoQ`1QyF^F89u4HqEwMmuR9Nc!M#Tb+5-rx`KbLd?=M2HZ_r9{fU__<3T;58r%udw% z&D-N~rPcMXd-C&dYtJ8Z87Qlg*0|4wi5@q3EnOeZ3Cm{ZmX#eulIjsm@cxt;U(M|T zo)HK5t`aVQ~^_`d4e`rF>jZ(@5AhA@Gcs{~R#5#dq?GM<(}Mb%V}LD1NmVP0VR1dqwcB}tQgFbb(aCCA8_nXhSRbV{ z3lUdgj-SLq5n@(bstF^a^zO;ze5z^`@z~90{x>+&FMw@r$CB=A8})}eIZ-#W^@rb- z{4O+$+7M8Q`_pb52}ODbyM?yrqMP0uu?-ZRL(+$$o=U0%B-}iW+WT>*!$k)}tGRU0 zIC2vaA4NGUr=5z{_1k1v@puUV<4a;9HL9%4KV#0% z7})Z@&%UxX*G!HGujl#lAZ|Q*C$w;60r6!mR&d!PcN=P7NqLf0BDDh3a_LqCdm?P8q4IP@9<%#Yhp zm#*qOmwc^)tLPKnlpC~n9>gy7RprRrb@!=kH^=`_icwYMg>VZxXQFBUGw1QInzg%M z`rz3()AxVUrKZz5i$AcX33J=wc(}V-;hNg}u`%kmC01hl@!>v4MfwHc45k#VXysey zJMxkoh<~nPZaS3(i4)d8tGfS@Du_oCl3PU(_7X^@wZs3qI`D{=bu)hEMK>eHj57K{ zAW0o{ByxH;=Xh&;GE+h1bwR&(Lc^&7&aVO~Cku6&tmkdUtRlW@m(Cz1n@TcaR)*;W zm5hcSMe%GAN4YZX=foUwmVKeqPdHJ`F82r$B?RmyCX`Ft%u3J*zOiVs4HLPzhrN@) z1pKFW>oBpS*~Vz%(_xvG2>B6cAxp`VFp}-<n5Di>(>9~l6Y)j@EWoNfB8D(5^7*^feF9vTwu5oFDk)n$`duA_%5ZjW#3RnAeaEk zxoPM2yU|q|Iy^435mTSyRir71jlpvcCBCOT7=4L?95xWc`Qd|>Bk`MyLkVxgPMK3C zPF>wYgI|S4#Ff9|9rpWF^yAA~eTD=G44WK2`g7nnS!yfT`s@p2b)@Gz41MfVW3JY5 zT&$go32wc{p}_2-d+^=*#?RQl9rD{KGnu$Tq*<OQl)Z375p5qa+-uIHz>61apjMMu2#$v?V0)-RyM!(${ADBv}=7w1Xy23>A^N2 zIF=TwJb6pLSXdn3o+j_6(PvER@ZyuI7jK5w&DO#pw3o^`eiocjk^FJbxL7E^0^U7(0u6mcDPy-Sma$wg5#4Z;pkjo9&yx6hAwafLsJ0)Ur*PZqkS>MjhQ-+$INnZs76gF#R zVh+ytxXquVHqsl(C}(y>#5r!pvYhmNe5GMBK~5~N_sEn!CS%IM5B>9el_mr)PosbS zl12xQpPA)jWGefZ&+n6QFxusn;-_NvlJS81B9~~Y*6Yd8@SWj}Wa=Wj#o9VA#uu8w z50gI%e1?91UsL#LaKlORl>=uCoA#jiBGQ6GZVCl8yfe?Ieo;y6BwqAzxrR%})RDqu zV>Bcz<{i&n`hhqzSnKbmtSyo7GU5d}UF58&=Ye}FgC3PDd^T?fw;Pj<_2u2^v*o@I z8;Bhf<2JLzmez-R=uyl5@^kLEC(m`#2wsq7emhbBGo8kNsw?;~{?b42POzhtg-6Uv zU~DWCIvjCh`8|yptXKzqo${PYhhRSjbSi)8Zt4cTP)!zsM;yb7astez{J@uUH1AE> z&(Ag!)iTOZgahs_W}sdNm=;NXmj@SjFHVr_g5U34kR2u<`~|uH_Au$OPus(N_}BI7 z4i)@|>wV3(jP)B{%e|Nm1abj86-T?gUCiEjXjXSiI~(F^$8CTV<@m&@;~naWc$}h6 zPn{ohoysJpYCYD4QigEfu%g*phJlavD2NbS2gQDiQ7~Nof>FTe{ zGH+0pRXB6@_B(iMTs;%5%F}F@ebo!oFrfK_h35@Yo8SEoza~6z=JaMZp80>MwywOl za(A86viSm@h7C{hR8yYd35f=F(jJeNP$-e8E7D+9-c5Pg47+A6t9Bom=xzIeNGK)Eg^^oxD?6J!ZN(TmaY)jORi1rL4t%|1=alnGIZ}rr=eD!?$!y5UXG4dERxL zAHJev8-vQV%DWh@(XZTs01J5bi94fN_7i2XX;0r_XPyn$_-$&{>loS37ND zj`unXZJ`VK^8p)9j*NP@9j7#Qpo}0mX`?4HamLUOwW5!$vgzqf{)v=Tlzipq;1MAP zfcL7YYsEvr@m-OszjTjSs3~27Wk8Bk>((s}5Z>QEZkv}d;oNxfLipiAa1lJ7r!!nK zn;jX#?i2kzVo;4L*l+c%3`GK#p@L7gmX=+Se02NRS_*xTPVnnHGN}C16pRE-Wm|cI z$cq|E>R-x_)(~M)T=>!-@*3nIwI_WA5f?aTOJ#Fs`Cj#s)#uu1=m9O8;4jTPK`vxwB+9BI%47Z96@6`Y;kd*SbX3}|UwLa_ zo1p|u$?(;@hzwR%mW?1u*DWa*;q=^v6Lk^7EeQD-r3=l#&lI&c>^U%5Gx7tw)h}yv z!iYzfX_Y7Hf5D2jG!gi`KAn`u{k%}cprZBCw+EM}5`%|+5*{B(Gk}800hZyjI(aSa zt7~#XF=Ol{DkU=D9YPq9$!k5AgN@DgN+l^%qeHC-6F~4R*pB8S1RE95nhj;Q9d;${ z1eumCW-V#*J4)b7lZN7G5UpCzgAb<)&Ha&2*(y9 zddGGmmf54+-#?iArK3z&C#A)T71dZ-J;#CeNgsio?Pf6{()n^)6#!~I1vdSZRLZ&L zKm+Eq-JlbfwXeNx8j-fya<*Y`Rf%~2O-6Z_AYBzJ+lY2zii zH$x!oI1=E4Y5y;h(s_PIK9cuDZbKYbxQ&OG?UX?9L5fL$I1-^*=lGi{2h6RrO%G)1 z7|*4o@kiQzy+`N~9*-jvV{`b~rPf<5RHS+mtwQieIbV6Jx9 zH;l)t^uI5Jvqb}`f({omg4EK^BvCiQA)euBUMv1%SZfMNh%QN~V$U_Z>6CW&$<+)hFvj`E_3kgr)^3jp}OS+Hh^J6lxm=; z&y^hb^yNsXEX@DAAoWRnzISPOKs|PJFH`i|xat!#oqvP+kMxJ>fK(SDGVah#4(WKM zX1NgqcS0Lx-@`go7!Ik8c|brTmZc@}q?=sRWF|7sAF1>o67@VH(16=uxc_i|=$!Nr zeOtNojUTW-H(G+U+6msVDamC_rNNpxB{GDMU~KFQQVN|^2(-h`R0)ln^_au*p!w+6 zhXI&t_os?Uv~oXeie-F^TU%AAlfb9)+<_n$MbP=lw?fO!X%t`|!>~Ka^(QX!l$Lo( zIP()U|6p-M)a%E`n+{bKoIXDuTNhBR|K2?BV0bqu36~$UA%KdqNQLKre9;cAU!!~b z=2>a)&z%pDxVul^4}N#hWpd*JVWbK@94>m8eCJ)DtMJznq`aLOJ{&t$68@bfM7*W+ z=uI9%#sjA9Q~%CJMe|Iz`{V?ai0 zD)g&)Bs32V7dh%X=H2;5*4wJI;s{rj=20w@`MNIX5Z&SR^up0AUZ1t>ff7z(aQ+)Q zyccBR&p6|q#*tW?k=7D-*OFq#W1)8cwZ9yDlzX97BfakoA&?3P?g1iB=4sjTt7(H+ufdZfQElQ)SO-6+cQf9i!IuvaiI!W_?QXoMUY>$*Cs}y7eXeF`VLr z+gVv^^;Zgqi78`$chwrw%L#q>q^RGqzod8$oDh+ttv{hpU>~FC$XR*^4TFfqcAP1v z>N+&6uQg)0)?Ig9y*jfV&SZ$w+0EI2qwNEL-~J(8Os)7rBg0hyrT4`*J-33MTyo(2 zO?>^-L~!5B-k0{602ew=y{5%BEw#l`~wf26eXvvAo za`2vJ%I{UJ6bc}wfnl|~>?(d!HT?HxW&6Dy?V*VKR=GivO;Xq^cJSSWf8gCh>ksNi ziX~foG{8rWK3LR*1k=l`d__9Hkk=aZ2^g+o=RfHp!yxX!DnE;qWVJ-h$fId)O3{l? z)GY^Q3eW)j^S2}x{h+$1IFz=*kLq-jeH|2K8Kk6tzklJ&Gzpzk7LevkE?o0)ReY+G zYhRBF+|F=%MLUGT8el*U6uFcZSK$@*8Ws|ajRgRs^b&0Oayq%A5J}k^tLju`*Z@jd zCKXg#UKC6{Q8+qC0MB>qhVl6eC+2@aDuaNW#`le}spTp+;^%pf0T}|$#|7a+6cE6J z;k{JQf(s%_g-68t2*%Y0SCmu0W8*BL<+Pj0wMMcDg+|Zi@qV$bYQUL4jpn01M}0aW zO9reCPL29<3AlO|+PgTSE3RsFqj1EatR{`iu}*9m=_Wk`l)IPbn9lG2wIrJat#OaAW`J1?8dyeQ zV58-cOW*Jwuk~oQsMmc(^YIYCKs9u6FPv(*(S7%+G?R17E~kje1AIfRbjE>h{a2u1 zf+gk5P`Lij7{FmnQo<{0U@v{H&sx)v9=7qo=6?uKRVYg_)A2qykMZE zq7I=x4WrGpow@C@FuhRhiSF-)3h`9B>_`zA)bE{KE*#U-?#yEYK2DCy^*N0g>haIS z+@Ewq@WFe#)+(RK;;NdALda;mmZxW@Ol#e82+#m5+_to-oX=iR(eOS&#ZWI;ipnqR zD#|a3i`eE^{wyj0?&)QbYUt2*x|Inx<3-`k^FpQS|3&k*fpk6@EgRE!tAA>Abf7^4 z5~A7S@+O@|QP6i|_U`cln|T{Al35W!)C}#6dUb$Cor|J282Iw?wVK!RS^>6?rC)vL zenE(%ucHYUa*#<#Q+wTDv^x>+NvZ2q?K9-rp}iJX7Y6xhL6BeY!*TaXBoes&Mesyn zoAxrsN?!`%sim!6G~Hc_vcO4b;IqyhHo4&wzeIRTBZy1iI*Yq*{?Mg_P>TM6fTU@O zZ#-2aoqwIg3#ZsAVbqB@wZope50!fXL_J%kJMbFl9-D-H;0omME$5nnd9$ z%%p6wy=_{fgEZ(x*YorcF_dK1{CWaZ)O7YdDvf&Od{4W+76kc+`<;4-K!S(sT_SBC zb4)y>-tp7IfcNlH^a%f+1P_ibc1ZU~T}w*~F%HTxMi-I%L_`#Qz|iW8gDn9LC6VJE z6A9SK8;K(XhCKmB0e6!RfX$EOZx|l~zkW?{Wf_A1(lL=Z>F73eTDeE9^%IavpMdien#T2v zxSap4%5Z8UBBzV3*%CvBass@dIMu{7<=GZXQFrID?ABm@q;I(JD5j7fT{nu4O*W8? zG1h6($IdVKZ8`_Gs|_b;h4#SG;*%RJ_miheu-E|upAK>gX9X9%c~#W_yw%u|Nbc$6 z?d$xuwGTnvVc2THvXArW_tRddEo+~9g)w08qngKes#r=|i43AAEFOMT`Oa#Sw2O9F zT*3Sa&ySJZoJq?$Db!wo<;_^^PIWaDeVzU+y~RoZ>D17r_i{Z%B|%6DS-9MckvN%} zWC|N#DRI}=?ep?tx;8Ecj9&iajev=}QGiyurFWo=k8@$qSnQU4m9==tSm(}ynQ zZWiYR(cz>!Xc`_DcC++jz^TCch_&dzTv$}03WSTa(^;#;!?EV!uBuOoN1}@F;XRHu>q!W8nUs(EwOxH_aY+* z2Yby98`wdf%ih<@RA?>lK&5At6ua?JL@;5mh2jq2O`cW-g#fKVOQwJi76$nIW#Qdw z2xQY4U`!zq(3SpD8!oR6)jt7!{(h3+Aej(d#Wyc~0IiXeVbR8OjMw1k zlRPCcqp7uC_FF+^9MGQy+$-LP+btv6Nfu|;s#%OBsqylLC0n@xgDdPcV=*v10zwZf zATxNy{e9&*N4aIrb_cK#Nx+0XUKnpV8*LV2Kq?kpmL1dbrRP*%Ir!%~p9V!1Lv^@o zqAIwQ(Fv&(Tz*CNlNB1iTLsg&8$zMDrxH(>N{zr;xL;5LLN9AeaTi6awb<2sjV4pqA!T5}0lzD=$wyg1~N7?HyV!f-fE zP(aK0G05@a%XHZp3gbvwd~7lv4$;W^UR$Pkq%x64iWx#LZrI~Q`LfHV&aXkX-oyJK zv#8u0I?8m|o{v5lD&GzAx~~&mXj(?gCXvXs7@Q&C=hM%G67-)TIm3IGJ_XIKAq9{8M8VZ|4gd zDmUrE%ayNc0^p>3u@fncjg7_ceiC4jtmezt4t?V)3rAxFI|NTtgF%OCVz@xe%&krh z0?n3+l((sBw#+LH54Z@jn}3&+WEfPY1Nv~AV>Q4saW-G+@Ds2Hw<+mHWp8*XP~5bG zAZ~3Z*VAfcomLJ@rB2i%F@i@FpTHmLBzdGnhC?-3lU?{Vs=sqGRjrxRUZR2tOG^&9 z(a?Pj?&x0&fXf0|{u59X+*VPo(%DUamA2E*?dX9ge+E`L-cV)I;Gb}Fwex*qa%$g` z^W*947|5jmdhn5$W)JV{Cm7A+(%hpZL z8+5_p6&`xM3`|HNRj9P`yL1++&MxFIm#7IkOYwh-S7m%E1Pg9JW9Zf@z%2hRr-%)G z8VWf*whk_udqFjTq&U8Oa$nM`@yzNu)&DpADZmsCJXo@R7lB*{>hFrjefVi111wJ_ ztQl`l#)AkkrY#ET6?_SLge(IV)CJQ#k|!{UZ>n6u-B<2vsbGVG))`aX3MD=ulR=+{=)~DzM_Ya z^4m@~9a#^NYrY$mi|qr;}qKh*4_G>6bqTTx^jCaBgrYL<3-pn~lgbK>d>tlfdrcoPx5;9*nXS zc8H)8u-vN_ZqoMWe9_;-D?O(aJ5G-g@PQq3X!Gopb_V<4jm=W}!5g&_z&rb(` zg(s4W{WY`hI^t-}C*S^FQbJ|L=j_*?H!+hfS2pg5;wS?8;sE_ zjyrWu09wemCwp*6uYa&e|9-haI$g)axX$|X<$ofVt}iLF&j5itfR|Ho z#P7%-|68g5BJ+P=>Hk9R@t;5=zk@p5fRO%1c=#vy$PGa2cQ}dvD)8sa{|HrbQ~H09 zd$E+`L42>l1R6JJzAAOyZKfV6Qa|+SEr|+aM2x1Mi_7y#!Qp}k@%6QUbyuoxeHiAh zYGGnu15osF`Yyp}BzFn$LDz9lP{`7zAOq5JVy_QvwRU-E9u`N1+y`J)H>JL$?U6B^ zLC=uFIyB6k0TF<_nknBPuG|%m5Qj@!8nDQMZ%aH=0I5IZ95clRHsL9*RKnhK%W1jW z^Kb7s1k~zGy4kub9z(7HV%N;})n|pjOHP6A8+^M^1*Qt{k3wdCHQIm{75tIgci|oZ z#aj!W(70!BIXKuQBLY!riQo9MJYF^M@SlDkvWCX@WlDA3`}k-9qr%e#kLmx;U~SB!0ZP8fs%Dm%3LH`Gz$nQ_TMg`T&68mO{e0P)l^a5Q_<=~ zh!mKLO*SHH>qSPJVU&|TRN`JE52~ZlI(UeAbg6zb+kVs8scSnPp%vE)jR@{U$aA>OF)AG%vJ*>L6!9?D!D6D-k3LbN=M$q|ZXk?37@CKsA<8dTN zLN!|y0Zx^D-*go;b2_`}F+(I=rbYwNeu%gpCd9k_f-#9?WFq$sZ;*+r$2Vh)kOpdb z47BvgpVnIcyx(y>_=s!dVQUcIJT$2Luzz8HeX3odQwxh0XxG^F6?-w(@PJINqk%Tj z=*82vtM+?sFSVxy`1H(TRNp53eT|Xu@ntebunOhA9Y3nPV`2keuC&eI;x;%|a#krn zNc-fWTpaHs(#BFoC5E$toaUO_xmBM4pE`p-WaZFQ)7B;?O4ym6T3;(V<0CC9R;`Kp z{4f$PE!IocNG|~ zph1{_^p9-V#*mLwT{j!6i1T#$q3m;x8G&+2LGR}Q)zQ^vG%4dEuJ(>+khJIV3AB-f z#A;wQ@VM~rX5&lBHZ5=V+s0fLrw<*%$$0gmSr52C7_Sa?F$V?bW*g}%Fl_gR%V7F7 z&Rox*p#J=&{ozbB zhzi@ohi$7XlZ{L+;-8-F8?;=s-dTdC*m^C3m|dca%`WIsL%RuM)&Hw2q4uE^bVvH@ zI$#qCXM0$&8t?S6qMnb4N8zNQ*4dFJ*H4Gsyf_Q*xsFEUm;I@$j98mv}YER{q8k3or?Q^ZN(&VIIpSV+pwe;g~GHKvd`+WtSNJSrsV*R9BqEE4@mjHa{g6J{wh!EWVLis zDnBpSX1{=2(4wM*ce%1nUEu^%YnTufkLUy=Nb=i&jxVGZwfXFS zpYj+aPEAZ0eKsz*L2@}{I0vGh1?lx%3GAxk(J}P_O#M%`=Gl4{v7HE8<+f;q*P$~q zy&ZFBaWwkjKO_zv~?c)Y5EEGQdy?o&G)&1IL{Z$*4ZA&ul_Iiy;wJhEB?j@f3RB0y zw9!v*;op}_@CSW0-;8%d4#F*mhtbapgWTCUIM#(6!=KFUgjLAUjYv>qL{gZ~0Odh=t-G%k_@f;-b(+3X zq_<2MHymJzb~{U)$xF5Lu$S5<>58_sRGON51i9kj<`zSB$98O>cW>1lY@u#1`TJhz z=p@0$Qd0--(>atB@KJ#l~EIbzeS0jhwoo8C$?VtI;;8!Lik`H{_sR*88?d9}mPA@L3 z8r*8ptv)9t>Moo#NlNt*`*C-Vpv@Lg!6~lPVm?bu_4!Ej;Kz75S=rVMpkdN@aochC zuZenM4qJD5>)cP63~zZkc4(24b@`lsTU%~IIDUkuH-9HBEYxh-)ar$lrBJrOL+_K4 zW)dl1#i)BvppmeGSV35S$LSQ}tY;M}!;`h_bEVe%ijC5k=8zRMRHK_eacXyv&%Ind ztw&B-)^4PJf(duoJJ+Pz$V;uv%DNqa@Aq_XcXszRkvYdLK*3wDjBZZ^o8hTQXIg0( zXJ>^eX3#A}QL|uiga%Nc1+*_>=VY7PPP|?W$w_Ng2BV7Y*B5zaXLR1Dpb5J(*%F3a zsJ8Bb{2ji)OVvb3FXfL!n{19gK&{cso@lTb40meD-8UNmtHdS+Mxss*DT7V2ji1TZ zmPWbKhyio^NiI!*x9zk{q;gV&BK--=`THd?w>?zNZdOYsUMa*NvC%Z3K%nFY*>xW4 z;E{*nFBSFuGbchz-of`;<B| zB!3~K$O!9 zXws_OqN2V)V7bCjg7QIav*|tD`Q8-gHB)x_39AKKS*L1(Tovz`tOa1iu#P;S4fQNA zdp*a{7{$RR&~>QRg~^X7EXSt-hgb$pXh zJXlNf49fJpmr+h|Qfo16rfRV=Iir0?ua1D_;lpzK1-^k=;+e4a2W(s*baPHa(yFL& zQN1y-a5|z(Rg67V>>qooXLA2a)*JaJK!}Dhh~z9)Z@+ab_;p zbF!VCqY8o(%mn6S6KLnhvS1ONjPlN6^WOXE!ap3Rs=a#7+;n!|L}=NOxU%O0TJ|H! zS%UySe2RE^h+w%aj@K7n%Zi4XDGdU4CI9w37QReg!A2{_GZ^TuILNB&#!D=xv_y}8 zp=Q{4^1@`WisK8!{&+I>$ z%a!|-iI9!PF3wjk3u!^uiyD(bid0n&s6v=`kZuvSf9O3 zPWKBD5@shPJ@Qxxxr>9>?nB^OnpmlWNZ0*>5Cj%CWw!6`w_`5}mabLjFy23kU{96X z*zSd@LsF$~2`aBBhs#f0FzSYh_vxNZ-F$eI%B0W1K@ILE_uV2hAY1{z#d_`4D0$g! zHT|F<8E-#2Xf8({H{3a5y?QI?wMO%M?P0gW5wFTTLBXL~@`#Rfr+n6iI-GZ1M_G!$^&uLdtD* zV0@RJTYDxLTfEzo`mT($Soo1Qk>f0+RbxzKtlT*QtvLVok*%#*iur&>tk`{J8hNLJ zaa0a>eH>6nE8g_G6?qV2$%X@pNxMbj+-CYYsyKt{s(m8-7_wyCM95O#mM-WObjzD>JBmil@R8LsM9CLJu_9J3PrK6zUB zB5TnAPq$3uDDTY)?)RY^1;quhbO7gX_Ip6?wLjI(8Pu2hcd{1^$h|(^t$fR`n-==U zy6dn4}BGzs(T;cKC+GjZpxw`22rS zWf{fIp_=xubpbHk{IM+jv4w@geSkLo4{O^0FJ`d+7p6QnOTn}xT?ufV%LWEM27NSy z>aFm@0nH}^gIau)%v~hkclvr}f0zUT?KLTlw{XTWJp_%jgadYP{zpo?q zC8nh^3?(;|3aNIvf#S~Lp9w2WSNAchO$MBto=vKs0Z+#HbD&3`^E=Br(=m!<014|$DpGy-&qW-&CfU(d zu0Eje9jRfeMBlsoa~@s$j1H(=dYHkr0W+R&qc!^~&b1WYh|urE-z0+R#&z_1q^}b| zWZ}Qb8yCt@I0^r?Y}^d}@5Fy3Z-iw&6CH5Nym3>#HoIOYu7&G52}S!O)4zrLM!bQk zNe76XaFsV~p<`*kCOx&~@Srtmz2eu)vh}EfhNIcxu-;>{@2r5FPm*5K5uOpf0Dw|Q zBm>P|E;K!-&p*n0Fjyvxa0`|nmOAaCxx|MULo~lj|NJ)AGi)@|qiKks8WjRH7E@Eh zG`?0Pw!CDdNEYz1{26E&hr3CRe!q2y>g~ZmYR&Dun)-achT6M{n3%ds_#!94Pku~z z-T~Y>=%grJ-*;tgn4I@;H^DasD$jXCk&TRO-A6%b=G-hR1(YgDRVWX>N!SRc-{KW# zOK|6IGOgl}GTkBIQ+)8Yd?(KdJJi3RBl(-JCDsGIsmZWjd=yXf&-^uIg>yy@Ng{oH z!SAoFO62oMz6l}iqT5e4o_+mET0C`iN$SNa!>QlUboNzl z8n;;%VV>)GC5IF~{ntSg3v_i-Cj{)W+V`GCD1Fb&xN>sb*gHUHGq&;b>Wg*ny_YWR zxp@>|H8ye2Tg+v7zTA1@>axWsqQwB`Hde5H!^KX=Sg$A^RYrvqwPM9{z?#?cqjTaI zgbjvuwQ1Hnj?4>qY2fj@bOuwiM_I?A5skiHJP2gnzdUL&%r|U#b>ZT*AOYTgy3<{l zRyBEK&a9ZWqO~iu<>j+HUvn1i-DI_2{16rz0p&g9Z-Y>LRlxz&9UmrZ`#gwkX1s%b?}#X+umBnJld^ z6Wc{{_S|%)k+n#q(TfVY6`z)e7H&%;7lvLKJm>mV?n0)}qOtN^U8|GR%}0z#vXab_ zX^+`K<O2@IM&EAhQ<3^u>$f3D0J50=-;KsZ;oct0QSc(!Hb{Cgo6vT_bDob! z8DUSV?%Iw!=M`-df}6#?d0(k!_ZY(zN&3vi7`Znf8KE}6KEE>`>fN?JUa}+z$h~ke+{yF_8GD)kffa+zY#%n1 zP!W$a->!bc0%Yj@h?-mx*Td)ikpvS@jY!D^?u`RmEIh$&y_?8LGWzcu|&Hh*`2J41LwH#aG|iE z?Bx;Se7PCN^Av?k_Ld<3NzF}U#J1vBEv}i;Ohf#>aZ;FmsiQiQtrA|QEwjw2w=F@` z$XH>#R&mX>Jq_#C4vLuNc!vk^qx#MBBF|ut3HQ&)@C&`xFXT9;wm1GoLxn+GQU^HFsy&YyrW*?cNPE1*-2_+L;Tx z$+S@l#kTw6U8u#%T-K*`6h@LsC25~Bgzt>EO`!Ww6~m!3r6=cG(z@OYz!r`iZEW#u zWo0^id#&o81Y#rk1?g?G6Ij;+lV?uberVqyMtv{mR}H1oY}qji)K`knPx`Ai?_Dk4 zplb=i{=@}j*d#}%5Tl;?KvVj!ch3kPGgJt#^IzdkWC^?r5yi`2*;4t3T!Ha9;w8+<&s!2E8xaH9FDV>Ax?=k|lk*%m5Ar1pc_>ZYt; zU7sUd0QWa65adZDrC_AnCK$FhqdOloXjndCG{|1m4~r`cGB~Iw>Td^OjeR#W#K=6D zW_&hKEN+kT4d?#Pbkzo)lEB}Soe>teWn9Bj9AcwRnQomrRmM_0KsIL*W%_}nKJsUM z^T$*_d+79M9ff5K2B-y3hfbwO#ND^$ar8?MNM)UyduU$ICX3%jVu~MB$j_nng?X@~ z?+m#rHR^jljM&WLMDFa915O7t_v1e4h!VAH>a)6W6N2BW%b1oOkfQ=;W<(Oz(*hkL zYfoICsf;v&Z3#4gxLtHgK+PZt6)^5l4_QtFj;|X1eN}9DNKD*09 z_Y6X?i^egD`NU%f`%wY(O@dnJx76$nzV<&lXui%c8Bc|w}zCDF5oR8gkMQi+@!4;1hz+nh^M{X(}` z(c6Yf*4Gd2Q@VQizYI>2zQ6FoN4;b%zOJzf6&D14u-rACj^He>bZdi*86itigG~L# z>QORs0^yo5=JE~~+^mOH{T>1UH+N@@JhV*ZpyI1~ovo!5hCh#DP-7~`x7VC}T%I;w z;h=)&ao7jQLVKT@i{GF@#|>w`2d* zy3GAfg8W&gB(y1vS?)oV{3>P8n~YAK4gu)XXLMyY59LzzMF(c4u`p$ACg{9F_5ckR zcij3x&RJMjD1L|M##=8C9=$qMdwi9oO>>D%F|!CVktvL$746yWtgTy}SBGl#kcT>* zo@uCQEDl#F6j>%sqi*~`=`e3GfyyXbQE$?Q*rKqA$N;;>-D5~sKBNt3 z&ER;zRaM9JLy_z1*O(Bl{Au_{JiE!WX}B1yBqSy00s(kia(|U)KZVZ$@lohHf9$P7V*kyKSMibLrAeZjD zk#h&_u{cJ4aTiNvs^oA698uXXKzSThvmsJQ71U#30g_b2@(~Y%_kRw#%f9Vb@7|VI z(cdjAJ5AZext6udyB3xE*ek5%m$!zf_zXr|{1cXJVvMF-O6ap}=y%my4Us4OPF3he zSE~_gQA5x}BVQ)Vj#bIX?#p~*qJ-t($)Vc^##Ie1HfO3%%)E2YIAF9XYEIln-PE4V zAAdq`^;@)St$&7X6{#S(xC)=NBmS&5CZ+RHT0PENJxVe&59p+I6vO9^upIq2eiA-$N4dbz_tAy-E z9cVAD#OhF33=2zW=#gL8Ggd|lY)-=IiV0;1WMw;q|L_i3f;T>y7G@;C$TcEN6bj~kckLQ;dUYI{d zJYe>CVm@DiYPH7ggp+~QaV$Pgfr0B86R`Oy_cs5DA*fR8!E{DjRctFHbmCKg!@-U` zhDz%FtR2)oR{lt7jFA94Rm`MjWUpH>fR{rB^``V;-ws}=yIKcC-Nc&~8{u5Krd`g0t@qHgPt3okV9OUxX19;VOmMUgD3@8JHa? z4(iaY^fitk5U#kq6dcN35gN`6ds(k?pW7xoC-HFnT7jcTySpe~K z84rEgG8_$@VJ=V0u5f6;Z~N-Ckg_pPS|JG^y< zaEH@VLXnb5Bi zf~)t8Fu$gw$^>X_urAc>{NPTaCH-E6A)(!upar%ljhr|+lai-!EnFMT{jBl*Q6t!B z+4($GJVfP54^zLPd@IG~{CqjVq_K|@(~w}PV1pEJh8SSBH=T&)9ElmBl9uf-j2v&5 zj((nb$AWo6oYT?)-L6xtC`)C}iL#YK$UPdb`D)Aw8Wg2ec&at(s5D#qt~v@gd%UDC zm^?&JDnO5`EwQN)qYe2!X>FxXzijfhu~w!WGQKnKjgdTGnNPGTNyCV(_uu!+hEIHp`;UwAOkeQOc9O=hufnWR@HeDZ{LF@0b)6|=* z;Buaf3ZG3dIp7b)BFpftUa(9>V)W;+agmxbY>)0+@;0||vz*}<64mlpMbb;7FBz-+ zUgzgn=IAHlb-&KZ{8ZP8w9|+eUk1d72vv>gj!7bpG1})>Hk;K=)n7Da5!E{pROW3t zY%xln+DZqiBJ4@fhJm?u2o9=t8z0;hs_jgOHWCPzNevBxfJ}94dG0-r&j^G^k@POk z7wX)LyLuA{*L^c#B3GVG?>h@$!zv{-&>;gQXnyonK$x2opAF8=ErgY^HMK#)fn|UE zQDb#?Fnv~9n^1)ZRXA}6GGg#<-id*<8%g|Z7d5h>+OB(|mV+NBa?o5RA@QlU3-pm5 z7Az1+_OejC)Ltc%Z+a*Glt&p-7(c#|#Y1>^4%6E0$46X$Wq;9)Z!Z;pZix8PnEbTF zFx|yS-aQ&Pg7SnOO$?NN+9NUl6cR(h4{3Q6`efi@fu%q9midJiH={LMgZG&?CoOMg z^y5ikR4SWZw|1StcO}$36a&gC6I$FotVgo$_W}n^wsb{9LG?p6hjLYg+NH_eR(GtJ z(7vG}$)?BxK5g~|L|bS2*`S18uGcCKl=(2oKi2EJ)mS>Lb!Z^w5uWvH1yQNiZ%*|p z%Cg8?1Cg%6nr^z#a)sQW9JVbKlf(jrWM1oTM%c?0H7+BQ(gT8*lUZLx%0^W*W5T{K zW8ics5Z$-Y5DIr!J@imYKYMfj&i*IaE#&A!v*)@UjIfO)qO!GjO>*vI!u;u6%CERK zTpP7th&|nj5qOvmH{2V13;T$olL+kI-pL1nEh!7HXKDzTk(;vyIO&>2TurO?G`zcEM%E$0(HAYmyf!zl;^x)^+yLi~H5nH8F z?~?3TUnh52RlbjEty&}X+qzp689<^nfiC*31MxB>$r7K4Hs$M!Vp#%-N2-Hmq$&bb z!o)=m33};=0tuj2Q+#yEoY)=_^=Y&K7RgAnW>e$BKHPEL_|0QXFv%oYY+X^)s-SlO zL?}4)Xmo}bEqTMP0e9Kt;NiFN>=oR>7G0wS!Lq%!6yMcf6>SkY769CeGChKTO|=G4NVm z?VHkxE)Q(|5XK@CWUBKHpS3m6E4)qGiff9EXnkWI9yusn!TJ?B(beWz;@C!J-{(Lp{-R+j)o77I$y?Y_>!Xq@-NFMAL`m|3SixKp# z8N47XzCDvXEIF8G}4F+qw9)LbprdOlXT^M1jy(dfx~K z9`e4Q%(gM|8&hFMYQG73)+U$q8KH=Nfp`0LgWGoCYPjQY&AlwViSR^Lmg&#(&NeA> zHa{o2?hR8Ox3-N{cr{eJ|0t(WZrXt*oV`W?El|G0{x;StM3D*e_|hBI$%$8HA2IUa z^C0{}uXPQ9qs1e&C9Lfixm3Irv}xXkpkuk-d1HaZlOEv9mvkmI9V{jmwz3N@VUl60 zvpOMvi0B(@^YYbohUe`R%U1o2iASD&?$5)9MQV*HZe!2UlSEesnn$6$#$=Zz1mD@o zw$^cEfB5N9cR3L_{%j@QJWT~jcE)VQ9p|iu&Cu{oF%g*X&g1wWuTW95SrZp%t_>Tka+c%4WuN#NUb07m_}OQl?Ja*)Tb?^!$YL zWY`Nz6(WL{e~>|I_3DS>{a#@r?X@A$2I^A3P=XKD$BAZt`!^I-@}BR{)GUNKcNAGp zviAs{_gV=@Eok`HL9dsJZR}{Gs39NpT8>iKMt4*wo)lR6l!lJo3oLD`#}+~x$}GB1 zjlt$p$9@O)LMUy=LHPIK4zm1Fm#!xzOJ7(m&n--8UK^7QdPj|u$!tlw>MO2lvB=Vc zH#Ol4MVcm`!Y0&3#5Hmp`!k5Zcv#?voQZ`pgkUBZ6$MOVT;Gd#=%QifVVKbi+`F-C zE!A$UoTp>Q6?}Iun282_--cj;&|FcBg}IgHlmU<&m@yTVRQCrqb=Xk4%yUNH7k!g4 z9}jou+6;p@Yu@v3+%4<)Nfcs&9L?_DF{parR)u)SC-&aDjGe<66E&W|ohY8T#tkxu zi|du6%l^43x?=m&<``{?@i3!^nZHxZ+9+en^YiZ~qM;d>@@yM^6k2ue=N5_6fCtaw z92Ec1zvS8XkR6_8o`)x<`}xdEuDGOc-v%ux8eXt`Abz~Nm|~7Wsg|HyPYzbgE|cM# zDpwd>A$5=*;%IW4Bn0Cr{V|?Nr7Yi3d`0&=as4{Ace({p&V>+oMwG*S?8c_2;(-$Xb3o|%H&v2 zb0CS3p0u!}z_PS-_1EQwnAc8>YhSA29R2m)*Ifpe2z+S>rgrV2vZPgnP)lzm_PS@juluO*RO&ziR+Y8LuADu%qf&-s_9 zm;+fBpE`eiPs`WtJypqVdb4g_h1vBeB7PJCexKDvZAuu!u=4~)`NvWeOaqT*6YIAe zO-1s6jQwGA-lpOA^EgUu18o@#S?Y?s0EK(t2Z|4!;uWKPHnf;wipWr&x+hJvAtgpS&cCqUfH>m1t*plE zn%+wWE`CS&LxIIhg&8J&rjp9R4A)nTVMYU2o37B_H&ESBucOKT#I#?VaAwYzp6v@$KsxnjZ!t_ZIovP0rKK3W+`5gbVxdj@*amsH zU|z8<@_MYVH0=mv*Gt8R?Rqh$^HjSWOPPT$17pCCFY+25R>CM@S@fO1dT$*Vc!2c| zjwpY9w1LV3Qg!3e2-qB=$8Tem?NCX`XqT=iW_iL>1&zcdYzoY(jU&Fj&zT}G{y&oeXQL+H1;PfxO^2%q`~iQ|8l;KMnl4v5Nb-K3DE zo=D+i!njrpmgD|$z9OwGbWA)eStb_@Ri(XU)TX5T#h}$4o1GZJB|Nm`zWq^$QWGuO zP{qByvkX8H=G??l+aVw@(OZ|E5bHAN&S}^iSRPiqZQtU6XG3gKAtI7euFtjbup;&{M(A_4a=o7lS~taF)W#bnrd7urzdd|BoB4q&+3Q8mRyplpO1hs3xa z3L6bAJ@<lEx+c_;$Et3D)3vKAbMe^7gzTuX()@pj)L#9gnvNo$!$vm z0^p(DPu?h@OBlseNt%;Wu-NW$5}JBmZthmWg1mFGaUQ;}v??gmdc`-;mD52JUtwLd zSwyIaP1K#*Z8UiF;cY4D(c?%tue4qk0Iy?T)B2Y51%idT9Wtej&#tKlnSx+7E%P6` z(p>cK5R_GoBxa>=Wmyy%cwBx^hkkZJ^|S=`!-aqL!|G#gg$g8ZL*MwX6iqly|w$gB@yNsy*RDXY`TVxjPa?v6{Q-~B+0?Ov3# zR5|dlS)%0^dBpQ|01E1Qr?cr)Q79I;ZFrr6@BN1)bN2W7}_|U%13a6WNIZMpZ1cIk+`$CvhHAA-!xSQy0a@XSFW z$S;m*8utnVbs|pZf*D!TZ0s*GG(q-n1d58>lwMVreqqk3X4YvyIL z(G#@pO5n3&WSU4$jl_(Yi!whBNs&hYU} zjmAt>ZHf|{;uoiGe=zGi%pd$}-1)07_3+X{$XdS)?q~=%-b7+Bo%^Q813q1%cSYzv z_(6g-TaXnE-!Jbm0q4B81U#YKej)97xLl#vO&-e&j7=KSkj?n z8{&t07IT9Uk5l>VOMU2&OzEAdHYp-8bUiwfa|)fOMt~yh6|mYNu$gp!ye)BV%p;Cw z9-A73PyTeVAJKvOgz<=4^!3TIxQ_J5tJql`Dk1XLk09Q%*_PS2)h{UoPiA`@ku17& zyr@FAROjmQ6Vdw2KEa-~IsI&78ZSY+*ok1z$1ELW4x?y*q19mODg; zKakB3F{0nHx!UD>O#WJV?hdRHBAh@VG|Ce7Wy*2zV^@84ZRb*+p*4H8O6B@vjQ7t! zoAWoRGOyj{A4?=qpez#p$^COqo<5h%x(5Bu5?`F5J`Wpmf;(yD%Lsn#d_yEDy_wy( z7}qbqr#SiIK~rO1NMZrY>5ka8*DbhULIj4HxlUxFFfV;ghMZ1@u*^=`c^7^^!f8b1 z_AsDQmkg9c$Hq}X=8sT{EH9{De-T7tE;4pTjV*ptK^h9+pOnY_$b$~%&RMvzMR1Aj zJAaDp$x`^bnZIcKk8Sr6^bylZAG!S_Gj(+Wv%8&#eKlAt@C!dYu-v);2}A>r%2(4} zW!<6nR!WJsTj}SLXBzM*LU7K_9~100rU{u|Rd=U+&0^s#fj95mTl}Gm_P6r=^t$H@ zA9C^~Vv@(6@p)!N@!>EQb=_8k^Z+3VKfs{4A;$I?&#-yjW?Ouh=p~e7Xs@3-@v4}M z_=TfT90qWbtD-yL5rZGBk;pRagdizN+8IiC7$bBja-$vi+)_mgaziN&GQm~D*WXaBZRL@cck)rKG zIZ1jZ5>8(#tf_$q`t^~)c`lgkNjS*3{)?+a`1an8YWkkEnz@!yS_rQ9z-gE>B7JbQ zZ6W9MHkWQJ3Lf5F@Sj}(@bn0&I&y}T8WXEVuI8}&AHb|ZHF z^{o^C*@GdFg+*xMN{Y+f45yDLzJB(nTlromk8Q(d)S4Ni-C1dC8>v5ZzxcXkbDMjq zKrWqVrf8O;;d?zsD2L`J|0$UOfAs$Q201~RQ7QZoWBfC2z4z8bHIzjG;;@e6+;C|g zQBA7gC!we35=UFD6`!~x7mz5mdP-Zi745IqmF27j7*J7Z>7LSl3?#P-y00S}OUQWV zRQ;?fp>iEtM{7%n^dFNi9XqIPkS2P@mQ4fHZmOs&41NG*iBBo2-TfNDHi=Ck- ziiWQ_!6d&6%tMK;L2tGD4!Nl{ufHuUihO4Rg+dWl5&x6IfE+ust;CGPmx+6j62tym z0`5N-2c}aT%a4vS%`+tc(9{j^=^7?=jgg9CsEiu$Qnu=In9j^>U6_~~#8}GOyM_f` zC%@f(uAivi*w*Gx1)&)7#|jY<%)5V&oc(Hj>0Hpkt$31EAPKk)bC^ zCBaSJ0!Bp*76t&O@nxEbu2pc+#QW5&)Q7haywyt#wAk4mY?vd$O z4eZ>By6`ef#r5emwegSaaaz8+ug+d*dvL1he(BMy>v{<|rhe7c(Jrr!%`Ku|?;D$b zU)CZ7hdX#0+kB5Jf&?>UniMB?od1})(oSyy99CBY3%Qrl5fx2OpgtMou02EoD)qgj zt`lZrJ&Q?fOhOWeD}#$~YU}oZA80{A*?bqoXx+OSNKVN=H9f=pf8o@-8lTNpLlPo% zr+_jb&N>FPn0q3lwR~`cCPmTKpOLpeFF221--j;%oku}ofuH`yp`zsajMo!)d7LEP zz*12n>9|~85rX!4e&0#fz8aYH9~X_w=zd@L<9G>(#f_`&Kc9bbtN-=+qRqR^_1-uiE10qYu0XL z?FMcNOuHL5P~cNpCM51u1@P|;>t?(L90J#`!Gr+VPk`$A3=at9g)~#b^^Z*eHvn@B zknZcgUPBN6%>wR%^8PjwNsHP>1HP3^xc_}|L^L*j9Bk%U&UnS%IO ze6iw(x0YLZ)>Z}9Ru=_bd#Sv#%(KE2Uv8cp;MN zP_H?y0JQrJ8|3vy=(LdOlKhk^op>xRz_x1^d|x(=PBJl1UZ=8dAt`UJ(%leoTvJZJ z#xVof$EX&>MA&0boksaOtJOl(SON(6*Vc;%m=^*u=bBzsdP-j3SRW zgfo8#R0+8Br3AVY{^9u>wnK(5(cfL}zf?EupPvHQP-a$&}l* z+jGq6p1+1`X0B$xbG0Ck5OzMNn;}M5=LtybbLhDi6@EzP=iM0O3z%4QRxp?UD|R8x zZz=76nvQZ(t-Uj<8ZllAd$B((G<~$uTXH4NmGhwaVKaBLU~?l02d~zeZ9Wa(^a=jI zy~?SbEz4GGvRG=3s+qdjf@DBgQc)Z}3LB*IE2k|Jei;a2YW`E2+XY~>Zok9uY0*8g zBc~s&a>S(g2{F%u3hj!R((nA+j!TW|O7KD>BS7$RU<)fFCo3m=TvTa969n#p_jd>u zdltNY)R+Ar7j5kb=2kt;DXeX*{ZjkG0qj3DS@neh2*hy1uBY)F&T!_gxQ6AehQ*%I zs7GtlmG}u1q*Mvw#iQdqcC}*wvi@dXyrD)Y(4d$riX^Tf5fTnI?yl-vr%lX6a! zdbSrU)PNezjlt-6nXo%>8x%{1wep-X#? zc*4C`5|tk7e#xoWe_ErWXXHM`F|=$JRy#I!etyVf&K|MhHr#(q<=rDAAO@_9H$v@_ zsN>YvJ=lEi!BD5eXe(k1bJ>!3efg<~0Q7Ua@nt0d<-eH}zOTyoER`C7A+M3RAmOnk z38#cls5~;kwejLxNLqKBTgZ#X_**nz)DkjLclFl7zCs^I@|%P8Mxs#BicJhPJ(zQ* z)^#!9)^Dv#tF@)1`?a`vw_4WDk1RYZ^XFuh#p%EVr+$U_{K6-WGl(!Smu{H5XLIqI zq9<&8jQUvoJmWBm?2R;<_D^ljBN}m~6`Pf!Ny1$oms*-R**_zeXKkxeYARp0;D<=R zygGe~qkuE83gOi&%o0rlkTgplLO@>2N#-GCw$^tCq&g6X4V=_l-2V)@C{Y|D zB*V=m54cbo2j4ilY7B}Saapeu8^TTL6mp>XE(2CE(D^^OKux@gr`OKT1_Mz0=ettor$ zLf3j}RD@lJPYP;^rd)P(V}LVj;Y!GLoYR2h z`CN`*7+=n)yl5RB0zn7YuTHuCvOcaLrvB-#u>>QKiWmJI`-4n_Rj}ApCmbtYoXKHa z1`UwSSK`8x#y9mq^F4luDE#EqsbJ-I=7{u3+C_O^T;~x_(Nk6;&+;dw_GV*C#G9U7kS`jk*_q=ZM(?!6P+6VHLET1O$zXckl=T5-le!HhQK!gpZ5DS zMrt&Y=z%SfN_smS| z`R7*TE9)6;sg-9odM#Ql%JKiJJKD4Ba}x#_mWe%F zRj}w5A6pdmARCtWRxEIiNpSLeJ|Dy79rm5|Y|gkBp|7{&6XpMDr?%k?Q}xjJR~o8} zu^%FjPgWPSKk3neQtE@3S_1LgN+Aj|MSL5SpIbkXUwPdkux+-r-k=G9y;`N3f<@f; zT3)*xcjcs%&W-C2&4P+LeeSv5Qw5(24|6oVfeY`bUMgVH;dsJMs%p|cOk>`8ZnKl= zS%RGc{EGIC11|7m+MpWdhr=%#Y(Kyb+}~5vf!IPk9tD*5F-v@5jX2TA?XN8y!OH=5f%^z@jRWWf$>*aK>-yM!W zv8-(HR<{4d*faX6dmXR$Qx~7=d~ocKswZIHb{x8n1`#rnk}h}jryW!E7g7%;SN!HW zX$#~%sf(N^ob}9};4UuACn=na#P1NlI}QHrTy`A?!T?jTuYb#{yL_+Vt-4QLZ-x>? z0&lR`lmB6n#jl^8Y(ALsoTEP&ijkN-Pb`9mxAXHXCvB;5`r(TIvSo!s{?UUIT zL~!(zdMwFM(h4qawWuA6l;lj1lOWkkf!7YS!sBTPwj;~nFaL+Ew+@SP>;8vTQ0Wo{ zBnG4fM7jsbkxpquK)PFC1f_eV8>G9trC})P?v#|F`@O;AInVd~{lj(5aL>K>UVH7; z>$4$rU6W7NI}GKp$TYW!lc&qppWKn{wu>+JY;`@!eeV8&6s^O{d(;*jVncFW=e8sGOaN1sqtYIgn z7N388sS9vVdlK&LLaJ=(_!WY8&;lhI50;aauy~0vSba45f{;56Y7RD;UiBy{&cB=I z8JZFtl?XDv7aTb26=%v1V>0}8s=qFbOXZ}(P|3Rx)Kx`c-)~9dzTiEHf zjEr^FX&Xp^Cj|=MWh?omNk*Kc#7y1)#wy1LYQ95!pz`Yt3dMzI8qx8Fe=`i`Lu*Yf zbJu!L2m0(Z&7ntJ#Rik29oRk(XXQ)6Uw&q>J8g@c&Y53X~_hkw@{UvQ^pm2$FCT1Cn6}ixkNNI$KT7x!yJA7v|Ym?IuS6u%jzm!n6-84 zZ|g7 zx0$?R$QMdd>Q)Y~?>#G&LtWpsa5)gTlZN=`*{?D{AxQr33Q2HeD75y^^0MKIld-=V$zypb= zm=B)VX@k!Ew7C34>@hfn_G+LJeQUR}MVj3rNaRZ2X?Ps^#Vl(HRIo$B`{>3mVSH|b z6oq2Ou0X+FlOhh;smykD4Bnf+&0xk=KPRa7`zh^)yfMl6zwF_(nuaX63*NRN{z{mn zU8i(LsLB4K>V%;&z%`DG4sRXFSyld5%3DZ-V1>$RgI5M4;3LjIpCbdlqu>;2C#ae7_#&cnv)I8mbFhKB8=ir z@vADsVV|DQ`PJ1dgU;K{!#|6KukoLutkVsKytNH(1=*xnG;YMz^e`0wYH^orpY>KM zJQmjD*Bz)Rg+}OTLdFZGouGE>6*?dBqDTH7%BI`}{RDKqap>r%wsE zJbC{5*vUt{vtAmkhlZc^>y7ncQbFw>=#X3Vmu};_SFhw8LCgGYOX2P<93(GTOSr$m z!fM3m!26I9U%xho#mfO}zmHno0QLbcl`6BQiW_YoI)R%dKcdm{H^;QdH#gov-gW-7 z4N&~M>fh+jAwsgr_Nc3vq~Bm11)r;rX;3Ic``qTj^9cCgg5k_`be{|@o6S}zGvD+{ zds7pgm@kU`BToTLg_fu2>uxS`La(mT;zMz7{A>Zhg-c51v=Ll=KYq669I>q`geyr8 z--Pm{i(~eB(BZ=qd6O!ZY6e^^MbwH6(t=#IP;^Ici7g~8Y5$F`i~;0lALCU+SXE2^L3_EDo2N&>(P^di`2t0@Qtw^;Q_)iKLYweD@Abh1%RY^nkOun7R`Kxb5UY>zXpZhhIg z@q7uSeKzL-2lRi`9OWE)%&lyEo3>H*e9DDi8w~&F)VUNwZ(lT)Qv9hf_g|Spxw^dD z+-N(wM2cf&z3LinFZK;ao|O%kdm)WV(RMINfRnOO_Dr_W#TVe(cQUi_d$Wh4XMX=b9XrY_9`M+7W|Hti}n@ z5S6h6??1Q31Eihet+kwOTvkWmK1nfbtj_&=Ci%VqmK2Ndd^*St9kl{I#GN`3zWZ6B zKiXbkQKI$|@yJX`^>gP3y8&bU^>6D~j1*oZ0dEy4%XTkM*XL+K`xnPmO>FGEYeIis zER1JcUHtdmx2A!qkm>ft6I04*48>LcQ+u z{wlIR*ge>>S3=Ll!a2%54LJdX>-82JXu8aGbtD>2;WqGXS^8}8m9U_%kBi7Vdn8y` zYXVKbyv})BEqrlr+@4%%j~Xd5x{8HdBK8DrKfEP^(doub#zja$1~UDlWUgenRjG$^ znBn0&3(ND0+vWZRdOChAP9K+F7CjD?0mF-OGk5z=ENeBRSx5tv9A8s)j6d@;@b0*A zR-uhK;6#(jboE{p>(J(R%r#g>opdqT-M>5t4!$32+AyAW<0{7N&7f^L+xJmqa@*fd z3Z~uBbOl-G^U3@`fk};NdEWeg27V|?7nh%<18wI5X!#GDfVDg9>0~Frk_Q(t;V`Ya zCJn}zMF=;rjH{?AZe#+NOqcEV(_iI~d73@i1SL)U4uW9MZw)3hTj9U5udaZS#A$gr zn}ZU9BzvOqxO{-Ae*CGWvRr9MAsP&ecMZ!LbQ9S@w`F74o*GEIL> z2{K85H%txt9*_Hlajc#Y9G(zdA78pG-qd9(9e8C&Xpvw}${R{|)kp7WWI(06)Z|=- z6%6uUa?(iIIn3}>xSpY`2JEc(7Ib9V>PKM_heyUk-8EL0xe!i*t|Qhug=7Y-=%(Mc z9~v}ag$Lmf*ZJ|X=t^PHh9ik(#-RaxC!5AOT>4gv5u% zF@(z^Y=Ew-v)p`HvlH{ig-crT1@&NhIbBtgECqr^JU+0OsY-6+W;r&vvc;sa132r=QH#@h`cLqYLC1}g zL+iZm9%ns8KB(~K%4F6z(B(10Cc7Est6yEqe8Dd_L<|{t&=5f8-zgs=5;cB_lu}dS ztRA|bmFJ>KiZYy>zqxwhJ#I+i@QmI-ew{hGX@7-MX3P7gn#LOqU!}_58NWBO;8pxm zY-HIdeN)Sag||v%$@?Faq1&^RUtk4YU+Y9T4n)Gf7dRbe?6}JbTm^L|=AX39mJbp< zYD$^wKPn=aBb*-V%rIORelGcXK{8rF_~wP;*opkjMmcw*#p<%;_<1XChhOjD32nJa z;p^)nhOGkf7ZsE7niMPY@pjnes08|cTYcsx=+-Kfn>RZSv)z^=p+uVPTyPnh<>)L< zFriK8^ifrwVFS;x%e>Bnnx)oWmpZ*NIc3wP+gWyBp8X`gTyJtS@$kWF@Ga-;zxW5X z=r(Sl5g?`Ga^&D#M9|f_VSf;ul{6;{cEk!w3o$AgsVRJrHQl&KRDwz5UFSVs9i-l;3)~*W-02MNC2cfROmGhrm z%x9ynk2o4UNjL~`Ecy-m0$MO;vCd;Y(%J1#28xaDyoLeSj4j^joPQY6FRQEbwOFus zE9PevFbxfLK~mj@${z^~zImM=>qvS@rweO*qdDrMXov%vvfQTITC_(q zb^R-Mc$Jd1cO$6g?U2BfG1Oi6D&q~Fqbn~ePkRRDY{gD%+Azaw*jsK&i1eLmL=3X6 z+`%?BZWS?ttme*J9W!AH+Gwi|g z+5Of55G3Te^7SM4>J7#-Ke@QQ*W`nh>7A3JQT@a;U20Q+aURr{)XSK?pT2h+B)E++ z-E!~)sSM-N_pa+m$ziaI<2?{*vi0;UeO~-5bN3HaW73uDu9X@Vy?KXm!@z4B}Io~=2(@cyB zs9DXFH@M`EW|M;io+W0GA#hQP{zudZ*$|yZ-?Bc!nT^s1hC(Avo zQ{{&4noMnXSh%`Oz~B<cYMj#y9WZF~=s?!xM8I&V zJNx%+V;_O*!opUx{abszIuf4Q|HXJGgzRl9`hlik+!F^w1?8AxOXo1M;+o06$&F9=p1qc?1QMKDL5r3!W4}gBLI-+=E z(tMb1hZV&ToY=67JiD!2KzsZ&DdUa*mj)!KM;Al1|W@SbGl@B_x?26dAQwdKUNIjf7dIui(d>6;1~d zcn>y=?Xk!$S+jN$5)-kMkkK|PDtO&g?*_r9VtHmaj;&Iu=bR5IDcF7MIa~QF@g1Cu zM;v{x#vjF#<@KQY#fF5e!ss^qC1K)wa}f8`1jo!z7Q#qV>sC2xFA|hsC3bb{cbI^E z{RA&uWk9>_2|w1Yh4j$av0g3TYU>18WJ;M!E5-G%u*Md>2w{?R?kQuhP|-60-Y)$o zUDX_qo7H3XV;zE+;Jtn#DmukrXt@Sw(!pTZwc8D0XsH{+%cJ-H_}9x*F01oN$(-*ktOp%(4y zu)FJxydE}{rvx>}ml1=0TXESpLA7r7!>&7x#+s0+`<}+nyQX*h*-8vur465BuN}G9 zMH3nPHkk76LuMq5n#4)<3kS43z*G_w8a!9Bm zA8>=~mT+~XP48aSdS{CrLW$xNd(1{bTvr%(v2Q{3=?YsJgSj9ZPOeLK0XwjK@0?$Th4C zDuH8gQpF7$es20}paTA$q<&#ZnknhWdD(7T!bhK++?`Y_N?Iy8rYjZ}+VS;k80HD14RFu0 zB~DE5@P2P?h;xWp$)X0Uj-6Bvqz7{UJ}i<;e2f8Fv*eTYCQ66&koznqR0r#f+xoCN z3;LSkqs|+z)Lsqln#~$SNoC`HVmv6Vl;DfMd_q2wkb>5`Cq<%ov&IK8JGTmY9~kB= z255IE?i`wWb{YL)WlbnLPS)Y}x;> z5KfC5znhMT?*83$DqT-NiE>?wCAVmMh`oKHfxhg}PimWGDwa$hDt z->Gk4T$45aWWick{8XZlgz&VZEpeaK z0Diu`j{)D+9w$ZJJ;Z)jFP?YE`kR>Fyko<*{d7H@B#DdX!AAITt|pa4?#$Zscpi!4 zfHG(me3ewg&f;$P$<+CSp2CpDZ8D^dcm;@cacXH2Pf>3Vs%Zt|B~uqv2;;p&F97wA zH`?Q8ny0Num3$(j1nEnmrwiNaPmb03ZJB@i3|}MJdLN4uOLqe-%`%#vj~ootL31oV z>3M}6p-p5C{ft&%p32E6Rh9Ep(pn1hQ^@RzuvtKf|fEJe!h`jXJO^R@D6M z>189T6&UPCK@J!)4p?%;J#qCZX15~Z)}^n6M~#qFT2vqJ50g2hVZInC--$ed4CzYQ z9`J2}abK`&15b*i7uR zI*>opG?DhGp9Le&ypa>k(T{Ulyyx*&Sky)A8iIwL(cIGJq4ykG=9_nwu~d|*qqj4^ zJ@i1LMp<9MAUvisz~}f2A&Yz?`k}g{QjIoJU^r%bH4#l5zcAQm3lpzw^0Z@QtZpKU zu_R%ltKIxBE``;S>$)MWC58#vDDtV@T-0MxG10tJf|_kimw{mgoy_p-)iCs{ zW2Sf>xtA-JlrNiCdZ=} z+gQW_#Jlj$+GyGtNigp{zV8$-syL;yUq+$rs{}@v6U?a{^@bKy70YPG>A$fK4jy{- z4b~Oxx%*vWJ-Wx6whqVdrHO^sw~v{{r8T8BM&^b@Yq&QZhAU|^O5{KgO|?>EVKaDr zrmwT%Y)+=;x6A9(Tr6l%-%8luaF&Y)6#qc2M3+p;OykmoY{&b0RhG2yVh(vI#+=n< zqJ7&D2tYVc)8^B5JMSC+@^&N9tVvAjAu{>qlM-9ILly#qcvr%9tXRbJGlGJcS~2vP z!Z#&LP9`M~3XdR{MPIZRpN{*MKHmD^YcnpP%48Gk7m_`@1L)AwdDS0K(W8U;(PUN9LjFE2DqqDY`xy&H;kU|Lw{x5AKq7?su8a_ z^4AT8C52fV^5O8%QFvh?(3>0JtyNORo>ZI@5ln-AoFAw{MIJR+`#_OT7s^!_XoSNC zCVm)wXiLCF&yip=Bv3=omk~%C{tXL9&k8$w7V$)w-w%+t*t5iQNZy&GtM!c3aClF&+++N@AXvwbk8^S)o~xZmrN6OOsm4(HQ>E(u-X!F6Tena zRi2W4re-QSbzTtC3k>mo71=$Qi%5uO(MzK zZGV-w_r*QmY%2>+(N@My_`Jwab#K!Tn1?)>^1&Ul*x$umDs@{E-9+DfUTGW~4%s~N(=QBaQ`B{?5hQ@AxM-Y%rT zU^#v`+vj!n(x4~FH}WM;KjR?;;-5NH>FtH1f@b- z_yBnvADTj=DVU%{4+6w`{y6lrWa^D0vTgl$i^ZH*zy$6|&~}15@MF1VTlx*Qc{^v1 z2cESa`N%j8rsaRF-NEueuB8k{to%rqhJdVVHQ(drzfyMu)VHFAzi0Z&1jQ?bJjEr9 z)QXyKFvz;>LLAPLIthkS#X+svf*->uar2jppGp7KI&@)-FClPB=+xueE5zb##b{p8 zDP}->i3+13v4)zW1}~H(l^Z2w-mf9@Ji}_J3;F`WF{$&J3-e!dbC_YT>dV_^Ce-?U z5n5@lOtd75%E+r{c?lC^uH+PTG%@iGVoy=8m2u>#Out7fn2Tx>R1&kw1e`F7YlTN> zRhRl)jgT*$=5DUym0y?HC5WC8-$x~~u0WKZ2E3r9p@h?WLHSu5yv&NcaMtRNv4gKK z`&A3~Es;fn@2f_x^LBT&vjaZ(odx^o>@8JKKo-$>sj_gs;ohE}gG2m@dUedBuczwCNc6N!QiLOng~)8%Kj_qaQY4;;wd5XS z6p9NV?^58J`l1_JS&9ASkxcf>$~^nQ;asDT3G+0}t#HcyC5A)^m9I|`HXoqR01pYa zEdMF>`RLPU;n4L?L8nS5O2Ut~b4Cs6S(5x$Dgy~9dD}tnvu;d-Q1LW#hB=Ojb_`h5 zjC{ajxS?(&`6iAPq_r(h@1tE5xu{W!x@v}mLk71h?&o=vOagONITJ>aCG(FllkHBa z-RIM0QorvLW_*uejO4MyA&u42L1QMN@|EIEPH2(r>U4ue!tT<{y#A_*M`-*E*WqI?{c`o?FCzdX0jz1Tb{E6V4pak`C zbGqYQm!y_3(7kGXQuhW0NL%gFn-s;axVV2v$7VvlbNBybHK<1A`D?7vu5C>B4}X`O zB@O26hIShlbSpI`m{pS%s>O*TXBORJ4+i!G~N zB9mRBU`aNYpC?a%x~)7kw{qnXUJ-yJ^5gdB32>Sp{>$1LcaFj9Q=7Binua5Q`*V4> zS-jDW|8h*l9Zf=e=KaAMW<7=pSj zzO`iMmo|LXhU!B4Mg^_f+0PU7ragXDZC3`fj98NiY|FKv8V{k1XR2;1%8#x^L<4jA zn=t8Wem!}U7XYO3mW2R9-OB~-e4oH@Qi}?ms<_d<8JYju8}+2JC0D8`yd|N(%=Mxc zS&D$HF7nb}_35<6Gs`IpV*P9-bK;~p?7bRPwaPC0z^%>%cf5Xb-n0+DN_ql~UR7X{ zOnarIH>>a6dbs~YKyMwBNM1(mXm@~>=Mw=|=Ee99PXXgU+oS1WRkYh-ei6wU7j5nx zN#Mrht-g~7jQpFOO>6N=S?9Vz@{BN2zoAK2cHH?0p^%m*EK@h4bu;hXIWP4Jget{S zvrZB#p3KCvFBaf1vV238zzhPS_13>!0rt6d>TWk@+P@mZWFm1$?LL}xmDlhO#+=CUf7m?rB&Al^A z2-08ok5EwuWU5SK;EcYg(1qo^NvE+OS;r@ihPCYcTaN4e>Ed;p|oMeac&$Ev30dB^%Dug?<)YB0rZ zIQL)DeK6*~jCLuU`_x|out_Q@rpcS~vDqktHtyfZL5j2C?siRBJ-=$c2rqDBynb0H zJZ@KWSyGhF`fWj|r^T1W=lMVwti-vm5`SP?AjNvE0AOtWE&2y|=$Z2)D{7=oysT+z zYq+_Ub73beT0_5v)=g4h5J|G`2TTO|=okK! z%U+#P0eb4U6jx0+*6TtDmXdU*Eg@gdA>t5ycJqE*q7UY>IO=8#I6wuTS7rA0A!!ck zzN-D@Y|HYV#=td(sT>*wQB{D(N0(+M4z*|C(q!_BE_B6|%_S?FRDYXA(Sp!qOk!=z(mMRcd4;4J#50H7}Zo2c%h? z1E9UTYLRGz9er}1Vow3|37MC~Z$KGY+*ie$Lwi)II2V08;Aa6UWbuRL)%1fh;=_1~ zb>xmiNu`W!vX0~zlU$AUI}rsx#XlN$kF9k-r5vKV**IxYI@nX~=w5B*9vXDnCBP+W zcfF?7O-s!gHzYGs=@(C5I}5l=82=SVBDfN^r)g&W?khYnTL2mW+CNw4^FJx0JZF@z z>YmC|=|8OVDbSb>xJcOn$@{kaaH1h&3k+K$&ncg$T%kPoke8Y9j-0kfM_}P5R=@lF z%W1-}@vMYLWl~Pt@!Z#uOFla363?lGZMM)?>`6N%D+>Xiz=1*#ZN!G7W{WOa;y$e| z<*Oc6w@ZBG1t9SZWEUDM?t(>sGx=CPlUVK_ug%uiDxW>jA2PsPDP4dZ>B5k0nZ`!E z2y0~&F}$B^Qx`f#ue3S3r2^jT=RJc%^zX=v0XbtV!y9F#Afg*f%n#Ce@z=G?v^&1i zmB}{6I(47Uo=moo#J*3T$q@*Har-I7k$3lsT!wdb6?x!%th}{S8~s}w{;Es4ea zwi!&;c4QqyLr6zh4z*`pxDI|J#*O%{sSbXl1tp=c=-1ag?6iU727fCEOP)GN`LjIj1BLxC>_+iR=*q%WK`^KV`gL-6@X0N82xO0+c?PBO^7w+5`k78x6?@4eX&= z`VMrAb5A>jfa)*t3CiwY{AO%gV+T#FpbK#7%~1TaFv&+acC?5=CA@xf-=mp-ufz84>)^_(CAw9iR*Rr0S1N#~!N#Ed#>gljhzK(~2el_&{8y^J=$G4b;JhKWbfhHHr)D+K#T zSrP?|z-^33ADQNOKE^+X^(+0+V~2)kbV(&S`rm&}Wi#ZnKT{ni*^LsG*BJINZF?fI zm%n-59Pn*MZ7oPuSqs$BT7{RCwto6VIL6(O0jP+woV`xT0vO{yX^8{8kF}RhetvAP zv>5WhoAv?vIYx>z=T3|k7#Wkc&gC7vb2}s$LiA{iokzw0D3GhFZH|uc`6Y@V9Z%5{CV>|c`&N1qMJqKvCNgxJrNb4+Y}J}|$4y69 z5rf>uX!S<=VBIv6Q0&ArH;U zoKBEYAn}+%MRbaj@cNOj(KIRqc{wDheLhCzDSSg4=(h}lg$&u#XaG79f@S(<&-Mod z6!@0P_V+hh3hVX=LO1vVdGKQ2D_>8j>b2pV8>v^T+b#vx(q4nEH35q_mWdVtYs^;! zw|w_+2`7BhcCv_C{fhUxQBRY~D%9s5al^jE3jvCSV|g%qZWAzbDCNGeFbddcg7I#x zV2^a&Em|CObwCw8R4O8nZh8k8td)$5&$Tm_j75s4=H5GQN~Je9J32rC%jyQ( zsR=hIR$mN_oJU5{)|Aq=Y~!@9OAMgP+903{eRk)WVbezW%&(|8f)30lGMjR4`L50nm`5wsot~IY zzFVcdqmUPnu=(+|IOd~TJ&@X2rJur04#4g(5`0^9m8J-_5P*C?_(m-*{J?^&&wj;u z(jW*4?HwF~qo2?4zSjGk^ZO`y&&WslZc~AWIYwr5vLGWGC8S#iz2i9Q%OF7 z6W!!u?J{jXkc}fH;%b0azDnzi~~owL=D&_@?xc55l8fn_apHXl~9w^Sbkf5 zG|ndgW^Me=RIsL|*!`wFMTJvz?-2D9U(z=%u!j;UE_?0-vXwsv2RR>42j|!bm5i2% zimr^g3T~M;5HH;qyUjvHD3Py~)E6G5K=1j#>UF0>lw1vq!6A`AB0t419dJa^Hf6MV z<3`a{XJz=7!l^QPk!;D;o{%J`)t>{Z;I0xf0`{I6bj5C>>(9gUPzBZ1+z3Y7lIGHk;PVTS|R< zy_Ig<^ZRFEe*9YIVq8FKGO7#{IX4)pLX5m1NseC3OycqJ++0}VV1YU&6 zBLYsfos1N6uK2k>sdzTp{JNwND2YNP!Kkoko+CzApB-_uJ!)|US{0u!`VlNTeERjC z2Qq0&ic_%K5{;=)$|@>@4dN*mpp3T>usK{~D2ZV$Nc(F1Bt;Vk17O1E#9`m<@-m(RO%5h~ ziLJwqEKxih%~*H)1MkdM_RN4A=kzn@l__&@IUWXj0CKD!?v!{%0i<^*rp)h$2E9O7 zpQZuU^c(1TW+mOE29tY=wgUK3+pHO(rXu-K*(1{`FcTfm?U9;E9Vw~?HBKBD39ze&ZZ zlD|JHPbBjbr|;cV$LwQ%(@LFIT!3=7XQ|7J4d>m|OxRda8oBMrP_ue^X%9%f>=n%Mz-(0V)h0o{|VkdM-6XFc2gf;S>J}sudPzYX^0o@f6e-oVm zKTyi7qD$}*=*tEb+ZUZ4HnLyHDk=K)-iBU629EBn&#*fA_ z*}dAytn=z?=>53zL?-*YAK#7N%Uoo%k{13QKrDHi6q{L<$zT;UwVtEktRWoPo|Y8` zs0ptQmkf^?0-QxqWa*CSzwI~h&gvk3cUO&vmj_D;5@3Fbisi-6jr5yKim0aBMC#vu1UN9HdcNriCnRyEij#)Q}Lpb)< z269rQ-xEX{DdwBM-+a>-G7we#a2mK~5vS!%*OidMZayitPe-9IFAY(R*Iik~-D#{t zHhjqqezMLlZf4htS0<($>Wl8E8Q9emZ)Fz?Mee%id0xRxI@`X*en#W0t&#UmCc;Bs=a1J3p z$C=T(Fbd3JdU_K5ILii`wQU7}MU zj0lTWQ!=jtlVsHA?XLQJo>yjWOVv)iJ0`R9^7UKsmAw<2f>@9Jd}=g8?A`?()p zc^_H62nV1sCetWFDT#4IFCM%|&?ELt1q!+-tsLaFq6RGT|EtdTBA>=^qz;TP8$4gE zUo9a!6$RSTaAG2W?D5kpBcwIl&=|OlU))IkwT4Y5=Vp^2kyVBHIPw5v!vr(hkoZM` z_YnG(!WoSwFeHWVi!dx7YM^#W#F#2*<@yKR+wRZz7q?D*CuaqMH7}4Tv5`%%eA<4n zor_UDG*in}v+|8IF<&eH{Q&t_M4TTZud?tzP@&)d1ymfaegKOQY=lFs^2p;Jte>ur_w>m{?fD74gJ~k#H2T+m*>eYrvYF-4|nWeIS56xKXO}JlnL~w&VO9Vg>v_b0E zT=MKcpaDn&=0*Sv2o8wiV<(-g;wnR?G3`H4F8jDDc6ZQt28Kd1e)5T@Ue|kNykgz=my`1zm zDf_1b-w*aX7i$;#q+R0oY3EHL!7*4s(BR1*-~`~l!>NU(mCX@JH;yX10|k=y?jv78 z=pdK=v;Q7gTP}OTHx3fBVQtVTe)KOc%no~*ir*5IYLhP7y;BANAfQujASfN}NO|Ai zsj=SL>jw39Z6lK4KWjVWznySr6Q(&Y=AvyT zRPRIW!3`2X#n)8|0ZSiUZ$ju@$Zmm*C8W>l~Xn-zn_8(oGG@fY|yVOiA z-rVk#8hj*`yPL~0CbjDRE$oV$vo605Uzh61aJ$dxscV*xp_Sk@%V8%Q<-r)RJTKWP zx?PA(Sb;X17&g)^=mYd35Iz1(11021G^Z*X^?r#&ZaKly@}cAyJ}`ry62IW1z|Log zC>_4OTTD)Sfjn_p#_UPRiN#9pl74uGJ$+ker1|Kd$74-losc^^%3(?0C=(Ba^m=1+ z9dPWIblYa)EiLQienbPNy^-E-&lC`jXx3Ibq`G_WNyt$~6)^=ze}SR=Nl8ODt}0N_adUC!C&)_R+%2z~ttx6OUW>g)>EDNsWwa!pZpuX#?cPL?Dz(#sLi!85_tt0i z2?&%jeuCWbG}2`N3jTo}NtW9>fv$LlBR#Gn^IrR8eKFV~u50Xg)b^uX{r%IwQ>JXS zGfUyO+?)Hfb#O3dObqPgz1vNIaH0p}fP4*AWd>#crNN4+DzM@Nb(VGpB;ejr0Aj@E z5akLVREH9aaPxzup%dSd`u6+%RkP(B%JI+pp#@8_ez0K%qQ9#+z0`Qvi5((I&;c2< zt-t{_O)&zZ5Vj*N~cB9PUMWyMJIxeyq=&5#Bh*MLDkxHrI z{eOmYhU?ooniG*ccDJjil*J(X45fNE)uV!4Rp}JXw%Xl3;tPaZhtU3^aX}C8^koiP zEXFTkt;yOkyn+Nd-9@tY1~Q*xKxuEyfb?U^Ybs-e1zUbH?zw zAYe^7Y}f_piUaz3Q{wbYD>z?j`Wkos+UN^WnJCg^6oCe zb&lB7Q4R}L#_E~w^R@R|8u>|*4z(94JhlZcxvVdHoqbd&(t4?cNa&g=pT5u;l4||A z^P@nJdkoxdfswU*Va7Y~$nqK-8}M7J7Q~bXr)P+r##iu&h3xp5<3;+pb>(spsFB`# zu&Y}0y_eo;1>WK~EnsuNcTvQQOdImjM#HOoIpGZ?Q34YEagK{ak1 z=w6I$dj0}$@NLO-a9LPM@~&XHnL#leq-q)d4t0%PoeUWhZ-fB2Ke}O?C9U^EU@-ST zm==H|N?&a6-Gq>%nE&~*nO{T{^_fN;t^`A|?c&AFw;rO7rl=695l5YtXj-Mo+KAn( zykES`;|T4W3cP$%&BzbG`;)0tLC@tJ{pavlyd^D*ij()*8n?xBBaJ$$hm1tIo zEW++(qz*SdtfRcXPUSbeOk4eJrxZ$%Nv#*RH@EnZ*izaz2Ku-E-RF7EEWEcXicD!bNDH))of6EneNN7PZGtfkL@;X|mv@y66A1 zqSx*CPqLIr*Vug`K76gQ>)aX2R>(@}_- zgm{LorO4Zq37&E*LRjH$QG{&vI5i+r$~nq8 zM-?xXc_3Zd*wsP>PjuxM&is{rbwfXPbgpZQKVOd2=l3kRFW+!4X{GRQi-=aedH5(f z!8mDiqyXBR{d!?Wly^>>TMbcSk}7hhKj^W(Hi2~Z>1>gW_Z61JPghszCTuA>P&+?O zPiLATyc6@zEC#l#+sx9H4n+I_uQ%s_p&6=V4k@CI&yxgpsQp?bP*b0Nd7m6152lF}2!Jx?r$M3jZhg4hZF=n! zVAPxIDDk=so`S6Ku*S2?428P8^XmI5d;r@E+C~bmm|1VkLhiYIg4d?BQOH^-_!3Tu zSSrWke~v9#ywm6W^o(v6k76OB`W{Qw{;#aO+DO=F1NL?<`z&AEn?(h1X1q^{}Mb-5!3p)HLjWQ7OxxWe|#pp0#Wl{EjmKsVq}dEw+tu=;RbF!}6WQnQ4- z_d-d1sxMw6Au`@|6%DIy6(mJDQ(Jl-Wi}Z#C-a`Y^E?Z05PO1y5#H*w7lX%mTun{* z$y8Vj{3tnTLXXLNOw|bY#C^xhay8AS(o89-kmTHd)R-CYwkSvaJ}wrD7QPvL8S*z2Z9 zi~IR%;yFS)SIq6M22A^|4AV&5Qehk(KClZW&_$X*Widml+sx&47bG9!eR}|>;G8Lm zdv~t2opW{u`$U+wRg|A&y3E%@!BG#^pQul(C2<-c)M{K)G`PZ8e$afR$p{$QpI8Q! zSGBA=(zD*ib6vfkm6!KD3Ww*VozXg4J~3ZsuWmB`EPZW%Qq+Z<;_BYM|ID((2@V2aX!i1zIYjx=BX&1a^%Y!*e#lowTJpl1-b~vCdlxZ|7 z^8M2@6b||{wz#Zi&10?UevA*PQl-$gcg3W9*UgG5eaDIw<)~zjO*(jLG8*nz1+Z|J zR6Sb)y>f7Gd?^>4XP(lwF7cce4+7;YfBUMtmqYETs(1HPb*=DLUQWY1m5Lna+9#e} zPr~^G)qNE6cl|#`WQG~bM0NGBWw*3WJPR8Bb=I+_??%}kE=-ao0#`+Ufu ze()QG_?=tEuQ1pI7^dQ{7VDdLxX-G=Ae^@M=~aUMiZ?xvSzXnGCe{k=OKshRr*3Zl zA75V`7G>AOjg8VE9V^|^4U0;LgdiQ#AlD6X>ORWw`WtoofTw22r@rrm7F2QyD6%{@mGcugQvgo2zm5I ztB-FodSSR{!A{8!f0Rs$MLZQqde53VGDc4I+!|5UnCKJu;qAI6t9qu6AaIE1debDYTSWiY&Qbu#6&l<=tbncRwhpK zk;LMj(ak0*MD}?z`OnI2R(eC#O4()tBtvol=EPdU3bcHb(t03ArNN z_z%$|v^d#93?LOg2*8j1dyyM>Yel(wuVBspktI=MRbDmD>$dZW*dr6Fw`#@eudJy# z?^RPWzYd_rA76bL+iij0YT=Azp#3cC9o?jlC|t>pZNaFi$w%NIDZf=6>zuzX^W;8E zAPL&1#FX`-uNIo~+7psykm1JxkjCpD!tCGRk1ryBGb75(tO%kjsZ8|YIQoX{=j}2N z3kAiP5IEJ39)+`;^Y`=3-~{nSm$ejl`Tv$lfTBo52aB;Am^y7eYUK3$OtAU7&eeD# z*^z|B@7hW9rSGsPZFZEhjda4NZi^(UYZJJU#m_Jo?^IbE0%}<$)DYQMEcbJ1Qmkxh zy1I3rFYRvyY8}!R?8wzg2_1s-KH|!K7k^&9&AJ%{&E~=2O7F4Re$$}B$XW!lUeHEr z?6`zQbZ8EayFoNRBZ5UwPyJ^5Tm(yVJNy;%)=}m)@(74%n@|HYQ{NDOD;kTIMRN1N zl|>N`^hLkf7ayqmL)_NI@xure<+=4#L&%6w;YRlWss9sho{l=D2R$kbEvA25IIWHo z_jY9Kg-YIf&T0J{9%Pbu24%gi2&ha#OFV0Ti>>^lFs?k%Ad%KcQsSf3hjbs(r|!S4 zLtY;p_o5PLd2&~Mt_U!jc==0s*(`#mR+LNTnN`2>1C8aA0^nk97*~0^dqoUKiTv=V z>9#U+Ht`rw@=(?{u?=ydN}a~)o%cQVkPMH)r{OvB`>g{BLNLz4aIKd(@79oUU#&iW zRN^zdFUh{|H~`cGr?b@^_|6&nu3gc*xhV#U?NaVb4o%*9=SadgTWH>HJiie&ku zajpjPFan_m@%}G_qeCI>s+MFqg19hWdc|cTAw7GRy{AG3vGAN173OaSDpG}{z>5$B|7K83%@V^?Ew$H?|F*08KVRq$C`g*x;PH{VE}0$ zdoE!E(N=wyNFgN-&NfDe6}0%9iHCJk<*RVSprob%)p|H_NI!H1;y%x2drLhp?61rf z^cHN$Cn#KcDmMzPWNae05C7frLDJQlZ^#S*SFDwe#?o-ic=?@u^Pef(JX}KpoesmgpkEmBeh~p z+ylf;Jf!^#1+it$skLoC<&*gEZV&)zdOJ^9Tg0DV^-K~IhgDJss6C0%O@s%6m;w7I zKWF=|<}1aJ8%@VX#vflt1BFI7GqpZ_9)1Cej~=%Sp)O7*e9RY->z3U{2jZ|c<+Cjv zdMx$0g-)O9r!;`HKZNbwi-EFx#C#Cq`Js-$F{$oChwOfqjjWt*uRU0WvQOze?q957 zjNmcRh;VMgYVB7{Kx1)v+d}P+uhR84OsL!BKew9iw3Y>_eA(zPKap%pIOQ?++Ez*+ z0D*H~;d8W;_b3(Uo(Gt!wS2lz9{Fi6x(<+B_m@ZXf~57f;T@tH?*e6w`Vqhqu-#(@ z?TWlgSE)VBsqmH+X{8!j*RFEsXTalht^qYTEiW1;m)7%5o>zUf;JOdsJN!7P=fi*9 zL4343jytv=fQjRY*_1Lj6QCHWA|QX)n<6iMbU1YZsZ~eyNKf@A7i2K;3+Y!a(!>St zgs|t%`zK75{UwnF_fxF0t*JVxR)jb>G`;G?n+#l#)QM1h>l+aezmeu9{?o9s2}Zm@ zG~7Aq=n7p;s?%R9Do!NvySwiqwlB9r458Y%f08GovKCD|MB8(ikneDy^dMkCfP5HT z&_xac`?I`ap-E)q^=GcD6KDDh9q{t+X%2N;=bPlQy$@nzboMgix^80M8#sLSe5}AS zDK@7G?|eWB!msR=G8Y;xqRh9cd`rAH%Z&r$fUiUnnF_)!O%^U(9`dU59Gt{Lb-*4r zkxMECKgsFW#r2ZLYcDA}La<&6PJRbh=6@GTyJ8HlOVUK0?ITeso6$9Q?b#vO?Ml@l zuxkC}Mkd;PSJwlkRlzqeT1_7R7IRftYpdwScctPQX1eT8Po>)y5xM9CSEnptzFXFv z9RkUTR7gR|DRd%3pJUS(PF zjuVe;FBc7fstq;;@3;B~r?5$N8$@+~m++~8?{EC*G%8EmRc~V_CQN){`4u5DX%|sh zqNx6*^Hd6)oo6KZj>FXACv)cX!0r{;h`-PO_h_CFp|2q-R*W)B^7{to;_~gjvKqqG zM`Ez<)sYTYb=Q!@Sz3nrIL}wR#@0U1qhZeheIU*49=3ByEENWug`2%^IEvV{h=Eqk5w;K=IndjS z9Y;Tt%W_^9z#2!^*xPK(FZ{5+k`8co6#ZH^DUhVQqA+I2>6b6oe0xy}9N36WI>mWH zhNUN__PZ+bL%Q=ELm|R-Zfn@RQmV-z6u20x^_(pBJum<`r41twIs1FKH1IL<^M0H^4>`u+Jb@!Q~;PAMe^pgieo01nM&6`{XW<^p=zhqzs}(Xu+!9U2F5f`s#j zs9d#Iod_m@*Grv0fA;iQ%F87N{8HRdNY;q39;Ma8^6RcGjg-zArpmXRkfWS?@EJJ9 z2Lo1np41~1#>a%<$X`a;XuRzbBH5+z_1Pg#ADwBs%Yp(2tf>2PiM0ZY4X4boE!b&1 z6hQ0G>u<4O7iNHblH=7Fz2j2ECpK*-6XzW>uV3!bIPI67t6m>NjGoviD!>?l(*XM1 zHFKn8eSdx*+ezeQ$<1;r+~)S_kr~U8ZQX#EV*mYwDZb&FU)Qj8eB`7M*fkiSN`NhM zpJGeKLGL>yJx6)=BMMtP%4Bal2XGEFlc$|J3M2g|;rtSaAv#Xrbh&?X2;j}bGeVPU zML{Nz$!G2a!kW-9*~XP7pwFSckxK6=-})*`utb5ph8&rvE!4KAMoSX^9{<#$3SJD> z0j^CAhE6*zZrrBG1|Nx+$>T3E9LL8GO-DbF;C^1iw6-(Cf>Zau0X75-rV1AH=ZJ>h zYO6Bir2D5xb-}*naS1l^-DP-yQ>mW?S2>>m&h767VtTz-)*l2{sk@3ClIZkR$+A&M zgJt{DI-?T8JlJkk1(ctWS}w1vI+?8u>I$naGh(M>7Xini;rhmt)2`VI+9X(Am7H_+ z!BPS=d5o?vExM^pHVUE4;LxC}F8Sl0X6WTZ9QV$;msZTWmX2i4q@_kVP0(2lNVS3iG>qF*ro1#i74(g6r|AbliJ zo>Wz)il!D#3b$-(_QhRNWS~EJ(mxUYky_C4LvGg7 zoptA@_6w8d-=>7g)nlQ0SPrkERqifv+&OEX-fy4WQ>&R)&c*u1MDHjUEANiFBiT1u`f5hiJhC~(zc68@B%}qpNQ}QheeV*_B5y6 z*J97Eh4B&G-O%UJDv0mTl17zf;+S+3<@trG~W`$;rN zNu4w_gmnlM7~yu=x#^UAPyN+M{Y>0}gmqX3kAlq6o1NjQ0$FBtlK|9$HyH2E`_^*Z z#_Q8Q`E^S$rlGBce~UU5^u?Q@fb%tQDevX-xgAg!?~m=EwoXR1N4FQSFjop*(;PobxcwJvF-5u%DKJn^y2a&+`^}|F;Q}D*)+99nj*kQ5>83^;= zP(?YpthIbLj#;hNdEdQLs?-_Pnm@3+7Jxzs`D1wU1~XUlC2SYyPYHEhwe#S)Bhk*{ zZLzRYfs`LH;#{)}m!aHh*dDDU{VReyrIWD(tI@D_3WIRhwE-`WoYijodNj{rK+xQi zP8`Df%}^qCh4P=}{Ea0@^Fv7quo_PTO*XUami4<^232kWoWI4v{@xxMLc3GPlnI7; zRub7j=|?qFJ+nkUs%+*y)?)0)io*5ji%#?syZE7NpPji!c4`yN2TS&6E8YrocC4>Q zUijW`l|jW-w0rwS`jO?gn$fvGKe|!RqHtrbi;?5jYqPo5^X#sRZxK80rfa|FZ$-*G zeJWhW_0KlRK=)p4|IO6!^Os(oSFlllt;b6-`h*PUFkENPrnUD)03K-Kg5Bk4UGFe6 zIIzw5jUE}d;hVFYsa+4#y@@=POD%iHt$Qbm6&udaEgwe`-3EzF!@7?T2OiW1 zAvA<7mCrFyisOOgE6~e@{7jUjaJkRKl2ll5`7>9He*MRfA05n8^TZ(Gl%?98KXG!7 zo*7z)cftuxp#5kKFIMF1ry5lDu>pSSOVpNoU#f8bq>ZkCMh3Ao$cq^aO*}bLNF=#U z=k)nWV1${zi}fTma`lJ}Cd9XJ^kJHu|7g8QD3CnBvr_cj_R{6Xt1-Fc)O>-t9ab*z ze#zDH-=x?~%><1MqTP{=r?zG97|qaZ_J;+~{wmFl>tPR;C{oxP(sXnf?L$6F-44?X zOVAD-fA&u{NLj+s$e?kl|B_VrVsS-rCC5lXRCGS%W$jj{n`pjy$$4$;ufthN@Z*+S zMWMnWrh9)im6R^pR8mrM*bnU+mHhmIx73xNR<#u@uH8c=DiYX-R%k&<4e>fDLXW0%*zdeiN z0N*$-^s7DiG%ou$*R_`cixp2<{Uf8;8b-)GM5b4`BMksoXNa=!b# zOOKrEjeA<1-M2g-K?dZzwCo`)#ez)U?sMmYdwpRf1EPQ}9a`+fEE`n>P}e!4nSDOz z_x@Nn_Rq&HA>l6@FTQqOAEs#U+Xxe5CV!hMqZal$Yg0^fnM2pTG+9sVOVQ%3adI)a zTC8_l`(?Ki9)IuOXN4yeYlE7r=K=Abk6s|v7x;HJRJ`qXK3A}XSa2T89+nXcnxd0% z)j2tNcmJ?gDVLPDnmEE<*LmH1mb31o!n8!mi3%Jo>&l&!R zf?~}I_C7qRk%@s+7^sZ5538>2*WM1X>#M8tIrW5p{mWf27%&Qkq9qhpKSz0$8VaT4 zAK#gbrs*DGYff2aCe(FwoMjZS7?1hq)3-JY^zE<@0}9tgk5L9)fINQ;vW#ZlZvC3E z*#vQG}SL8{+Ie)_zs@y%4 z%Bu5PL~ex<1pU2zPg-6JhX6zA4$vqgtPKl%XeA3M7Er?}@f0OkjYY$T5#>`g0qBY1 z_w(gKTf=v=^~D$Eq&B^bDKqCvJ7f82M??9Uu(GYpYQjE!%0C9cz2XDz*Kw)^jDK1c z5-!UOEh@QTL?SPM?g3a}+T#vE`a8a}{4mtA8Z7kr?MzU))N$2O#>jqQ6^|zM!4pOb$aT{_W+~wl0G=t_`7N~8TFI&$HHr1YL(SN#V_5HqCDhMM^__cld3bobOZ5ROu9?47nng?2J3PeltOW7cYjs7g z&=a2Zk)6VTuy=W90h=H8`yUv-vf9fZx!cV(***A{w{y+V4lDaRk0WT(NuTMHoa4azfF9Q&}mPoCq=^vN(;2SmSxuUF7}>)CI*BN$48sEpcP84C82F4 z3Msh4$zS$df?dW zZS4RUkjr6H=smF~5lQTHrHg}QvA@c= zZoxmK$YxmYqR8oPih%XSFD0xaxpiQM1~o=kJ03p|gu|wm0Ra>BS1ZJ)<;|CapyzAB&fS!t_u61^*uqKY+n1QioCmEjY*zPxDV}RySVh$T{(DpNAVftvQ*VOOatOT4t*jP za52RCXO|DzBr{l6_pC4N;F~iG)Zo%MO#9)TL8w==C$tyZ)(Lf}D+t^o&U=6mK1>D1 zBm*~tIrkQ-Y_G2uZu959;M^V+3@oO(;h~r_9^wRhQi!#NYtw0y0b`)UdPhe`0RS@? zJMi_q=RMy7@yg2QPzhkl+h})??lE-wtS=n;>t&bQ6JY0NJt9{bDVf0D9()6kw}_f< zhw_0abJ3yB*e`lCY-w;41ggpHy@l*#iU<;PKBzyjJlJ5nbozcvB{V-}@;A`8!=6z1 z2<{mRBR+Gbl4aC6y`5!5ZfWm-m4oag3$PG$DiA*aAkj+3?n;hw-Ni9^wg%XUr)ytufc@gZAqK_nP>C7jd4Fz*D-a0& zl3F+@+^(;HMm4z_>gs2Ucmw@<_VU8rf+S#TwT_tgHFIauvqwZFSl}BcX>SRwc9`1_ z`Tq8A5iN~3*DY8*WW2odSPj%Gzjf~zeRp#SN0_o;&QQeOdRZ5i+*}owk}i}^mF2M5 zM9Bx86Om6g`Gki9%0BKPY1U6{esV&@ez5LuF1b!{X;eK9x0*O2D>)8EjirW`?t5-IBASNhxI%n50>Tuglrc5 znr6G!(5%?}3DLI;=S0^g`wF)f6I|S|gO(R7>FG}Zd%W|bU-O9mIQYN3sei;-M%xKY z|1Uynjb#cYAk(Y5XlHax=oB+`0sje8ci&Y2SQ}?z(7T`v_`vRgiPK%6UDeg*?wKfO ziIp!9UH(3UR}p|IvHeX>f5Mi&=v6JemW%BUv;TdBX)Qb>C`NKZai)f^*?qzv8U|(j zSAu4&`r7L1gfq+P3s(F$J7LTTMLmpZcoY##DMF5$DL)tysTiqSmn&D)P@sd{KLgTz zJ~E!aUR=?@FReS-+qv3o;pesL=_B2%Ws7V&8=_xgJv^+r^Qm{c^1Y=(sLbJs>-<29 z#>LDnA!lFv5�I!8dmV%s+gv zpIOnwd&G4i2pN>=q3{PQU1x5BTcQa?Gu;-KmAo5po{P;r@^OM6v0LMzlti}$s z0Dx$$W**~c-{;uk`(Ly&6x&;fDJsa2>Z#$q+4%Gk7fd1DMib?e8VDqMu@eS3A|H6f z^Ywl2jYD>Q-D{P9K#t7=$-tdjJ7h|vSD+>a%9pntFzBrh1hNO8NIgk*seO0Xm2jCF zotTTK{SJ}dL9^7u!@P+FK&-K$fQwdzJp3~C3h1~!L4734@(5*+U}Z%?hp|)Y95|x- zm+Nw%1P&2?vnHLWww_tfRhScYv977hX)qnfyIQf`r@4#GsXIi5A4$`A9s$4nZE7gM z;{**#5|mo|A2O{%6*)EK*ZD(QfOIRw3RXM$t$H?a^8i>rHfRZ|T8aKS=^|eZ_`*)* zdD7ic5unkg#{|w}j|}$J1HA?RviSmnO|*TKL)h$&Ap9Iuac4UGb|uCxyL!Q! zl5g{QfR7&fg#2NqO;`$U*LQk!67YckacW1v*%6Y3ZOCM? zQS}%litFz0z}Mn(oc`>f-uP7)Eop-(F0C%Y!*QRz4fscp{~2yq%#reIwJ$(ZL=jlIYaaOm z{04Tw3;3WvZQKBP6j*?sa$qQwCf`TtBL33@^AM*$kvkwM6skA(eS6*u5%?PAlhwb^ zEpa@43qj{7Uhw3t@%AzN#xK}n0d$fTyX%yACtXNZW4ZGW=MVK}R`wr0R@oX((E-c) ze|k^8BKZGznsifx^r8LZ{vcwIK8*kV``=U9?a0~TA%F%&|JjSm|2eNYp36XlnZTz1 zI>6?AsD3+aW_iWu?$mVW&ssbWwEpw)8hGn=Q@%|wRP!Dn#k-AfOV-r5eI8$U0=Q(% zJFNiPTA83Ph3Xgn_kdV50rrNttW8#>6rP9x-}~p74qrX7blH0?Rl<(G;#T_Qa9T*i z$m(uKRL>RI4}Wp7&EhS|-`}Y@!f#tn+seFB8_;;7IA7s$u3Wo%R*&gpq+USDI!Qk` zNL-+Jbhh2K#`Q@*3-a)W7v7>z z58=T4zudVd6b4WPkvGe@s40{5khanQ+gKq6k;W9z1y*S^vl4Lfe?}sQTz4E!)ccLH z=Bhjgu_g_=>idT$%26MS=Y)yg>!_a*|C`A#@laZzVVy0vH*{W~yzR@!S^ zqDX{t<=Q@|rR0S(8Y7dVBgxM^Wnk~2^ho_wt=_2QSO+tW|8&FGx^Luc4t<;0t~A^e zA#nM6PUpknBWjypJlCIe+^hEvQ^UQT`Yk-itT99{G=iG&s=wQfewz@y5<5>&%s8}5 zO>%P1!JIpS71~YDvAXNEYiuvJ{=!vQ751lnu5M}oLl1=m+wZfh}g z*!l@U5+yj8B42eMl};LU_q`LzY8%fIqwy_c096EmDsFC#TplHNn2_`U#s_FIsfQpV zHBo8Ytoh|&hs3}) zI*in&oT~9r;gKFGSe))wH5eek&RVl{-@hS+I_&q205GinVK22>QkAxixsMg<|*g3;`HAfi7MGO z%{8W2PZD^`$Wq3*kdsLbbe0{UTV(n+xklUv#FVJC@%EsL1Cg2Xhqx3hENQ#ru-<+I z&S}7}fKYKng(~fg;@B zA*x8X1+LREIgmJ55+vGx+(iwWMW0um;W;d34hP*%!<{|Pr>80CTAZDwbQ8seC6$rp zE1-Z=&(I#JfxF2)kB5e4(_~y=5U|`#DjxZJL9g16rR~=~?0h~$M0?K`xs|R0>uYaq zjztycEB^WREMt$$b^#fXQ2Wqp9lZ9j<6?etF?tgzH{{zE@0{)58?dQ{qa|YM*C2R> z8xH1Kc>&t=5A15O|HXa8R`tC08>)-8mEgdRfMn0xXnl|5YGLAuy z>{YaOItlHhm<}AppmVLd?lY&mt zA^?W>*j;_>Vrt2s{2Fn&EZWQ5^<0IGGSX+q%fVk8AT5U<)9rJlZK^w-7`P0#18&x0wz`s8d96e9X{^t`mB zS62z*pT4Y++6noVK@dVsJ9g8nf{DQ4nL69)uBuy?MEh9c&j+Q`1M9MYGy@!VhS-Xg zm_IIz7Q}*i(YNauw3&$G-!|_#8u63V8T%G-kOXqS#pF*Fw^;i9)GItOB<2%=&&~7v z{kk#>U9=p2&EXN_5^m({^w8XbbOj@M{DJ&EiJEWc(a*8`M_WVHLz4veqI*a7mwLbF49JK9(XQpzQEfb z7Zd$i7J`HZer}&sp!^`YHzw3t__@6O~3u3m|2;Fxb&@6T9+Wp+fJ%qk#(Tsx@9W+R*v+Om%&Mz z4?u$S1n*qrV!pv05K50l9U>cr8#7R)IM+6GZBCp~TF@Z$#+g^)%1f3z2|Fcn|eg{3W6g|~>ZA0B!qEb5Z zJT#D5d-;A{MEJv=sJDX$O1fXpxpaswv0ohpY;+ z898YS>gl0Il*(2KrWi-eVPEIdVkKx*s;*aqXB}x?T=Xe`msi|^&0#;ssNWT_VwoSb zt;5Zt8^_ls7>0CG))^!gj$g$1Eg-t3d`aKM?j<@iD(@!=wO>aQc5+U|zHzV*K>q;b zd%6~;eRHjd9DCj;9>g!&C~>kyBqBHQtZe~t&S=?RLK>71>A{`Q8!=BX`m?e&qzl~ zhg1gtYL9LCZnYQt!9IZ@Ib3MVqj>k{vKjG@d{4LZHU2YYzsmtDbL`rGFIJSO6w-?t)^+-Ryvhj1h|*kz9kQC~XoWJV#Q}Y9l36FLNv6Gwvzw3|Zb=#g&XTwz=$^Gy3`^xh2Fm=t&}kj{Z3GtD!YsEYYA z-v53Wx!Oz!PP9t8V-Bg-b1sIe^~*M#-g~2yJ)hF8n_Lh>4U z5JYs4jVlXd&}XevJ=?TC+$Vb#;ydjoE9M?YrQ!l`YIH;YP5Qp+2cUa77i&6q=1F+nsa_mlrvsf7ZF%8TGvG)Y2cz##S>LI+`cz z0Ls8YqhoY7r16zC2J}N-=KFojuay5=l-n5+wAX z2vY4afXs$Q)Q=v|97%3!z2l3Ek+7_I3Jh?`7-%IMTblyC9gZWzmf<-YkA}W#AeFJL zgkZ_!R#~>R1=tB7DC&J^8{?qaQW6n zMN1LNH;lS(&9SZOO@(@;R$4YP%9=aebuc$$xt_^k?pEZ5)hH{BA|1*pLyS&M&UKyG za8@L<(`dPEqd~c4@~ut}GiQl|bOl&?BAm^eSi@qN>y?pR%7Ms~$yd4p_8u6A?sDBy z-+Mbk2}WO^wYY7SToNOXB`iA2L)3pgKuWU;jA-Z0#g^|XBPZ|8pH+|BO#EwSal4;; zVCP1nCb^{I0P^M5m3^3-goZTN(kjI>j+Tm?vYHCNe8a|DRIdi94nG)afKAUKgD?T024l0n4J?wj^o@F~mNF8p0BeWQL_ zep?M(^}OVhHT@8W9w`OZFD=z+cHgZWRl)Uyk-K`?|8?o*RZ2)AjSDjB9KIH9{4|Ha z3i9{h6nT-pXhu92YLG7%h0q{c3s} zv_kt^3R^ex5(@~V3cxbV{<66grhO#N;JM@nMKbQFsvv`Y-tgAVi-N;qm(2RFLh zbgrzUx zt0C(BR?9FB&AvR%Q%N=;)cRFa6_HD)IQ72kmU4Up2j*u{RPg?!{uU9(@WujF58dpw z0|}!Mq&JopLW|zea6kNBr`&3*7yzfU$aUR1c?bTliISlz-p-Ipeiey@Iz{$39xHa% zkh^=}^}gqoG_LzPMCwYeld2WfTGjn1#7)s8oh>b0Sg_%FkG$&msTE)Xc5EOSCK|H{ z4l++OEiBi5If~2)r*u#So(tK1X)=5Xo=WlA5ic86?`j~9iQ%;s!o&-Ak7iKY=}lJ? zEn?qMA-il~;e)e+2zwuXrng3Zd{C`Z;wLYs>Uxz{#H&A-e)gp}#H%^$oQh6uaPe@D z-C{P=WSYT_hq_D;jdR^V*YEt`KgTI6u7YX;z6twflYv$0W6{%!nX$ozsoBtBs;{1> zX`(~)UZ8uBr1czw+Nr(X8O(6~)ov|mI!+53}k zxz~}(hl~1@*Q)U9{_21&G0?ulMRutqop+irW=a*}LuS}hvhFuQ5cWI0%sS5Yk34R7 zdHH7}mU~;LhNvXlX=~~iXVQzCfCE4`S|?6&o;z*m;_Wk{1TR+uJi0@6jrTh3S?mde4?HJ(XI~o>cAoVGDY1cqearSC;vVSdU3@7%14*5!~;%zmDtF_cy z#pVxO+&3q^hO-BTv~keI7Kcd|rsRxleXp=s2Yh%e)R1U1L2qi6 zYr7l+8T!ObAki!c6sJ4Hs%t~-Q>bE35z5UYNVLz4WH#7H6QvQ_(M{$KRcS9M+D3`6 zF)k6fQk?=907d^d3dmViKlGBHy5B?l_CLlXdWwW~{C>UsZQ*k%gvSZV3>-LVju0)s zCYqJ$kQ&OMs8y+Mneh2@HFG#xnf8JieRASWe@*|$*(sT!Cuch25a~jHZnV)fsc5QYQmKjof^UBos_E&z7YY;R|lN({bHQI5h0lx1%j*f>dX)OtDO^5i75zsbeX~V)1VtGT^Qp1$+wUOmOgS>cX{O@J}nsVwA zm?S|I8U^KaU68BPmKczYv{@bf-r8_oE5Qn|By&*ueffe@pJ7oXA^EG zSPqf1T7w8z>efNEMYG6-Y_k(CG2nIR;wo1^VFHo&8AZErXB@Wd5AOW$`-K_Y`rp#l z4&ZLH+d-~dN{0u%l%T9^jvejuANIlbd86d}bjgYN!a6~>b;%4N5x;W^G3zUgE+k$u z`8>?k6~CP%L1aMjWvGd4!K_)-NwwwO21tJL2z7xJBD=U)?rebg8KwnHtG2f)MZ7t zLu_Z=i-KFukMcL3>W!Lc9tF_2lJy$H^8?O__2-kD3E}EFa?Ch`JZIMLsUyMBW$+YLcK^fn&YO%T@uvu^Ya4X4933VZH%Iwe=-1Ow%d}J z13nz;MMQ3dgY8m49Rs&hw^NN;(+_v7GhnFu(r-+5;ik}vEhhmTtV0~XpmVnd13KP( zrWfz-5*R?@aMT)TOWyCa#}+}6+2T$nprdH<(TSz?4dmhB;lj#!k}f0o27H$lc)`?g zwI{oLy4#WaQx_3-j=H?EEmv|&hyS-2!K+unT?}&8mi?gpCau{tt^3^(5mWx;#3I&_ zejlj7dI_+?bB(_=pS!Gp{>8fBCKcH9Z@vfxMSmx*sbV%VRkQwpoXmr`51oUHi)+Tf z)Q${z=UR=muvXJD2AlDa%Bkk;=^{2OJ-M>WjT!ye-JfFiy`Bcd{5oYd$LA&?E>>Gj ze`GqfENhFc#l(v?2e-x8iv220uVASd-{*#hi?OD%vZSf9S)}+2ZVQVCSBvHWCnPb= z@_c)LYGJhLHYp`DMm-}%KXSqKnvW96aK{OzY_FjMSx~f=-o`@lW1xj9Lz6r{Yr}I= z1EM$A3t_icrAu?mqNNM&mHQhqZUmQ0iMI1FUzEesu8I9b`PCbv{8@mbl?0UKsi6># zxMEMx-N9@Nun`3k9>W;nE#K>ede+w~ugpqClNN&p^t8p_c}uhf!AD-EHCeT^cJ{xH z%qsSo1+KZxbS@r72sQrt&~UBza0R(dm=@m>`u-R!H?;XC$QB-44c9i%@u zT@7~a>pD)@Tl%)Pw-hs7J(+8*U_n0cc-JJP$a3E-*UON#=tBNb>1)jnFS@+d@#QOB zbOoD_+oXjyn~X(P7p#Sox5AT1FsjPHGQo_ zW?@oC(+gIbED?+o1HI!CW4|dfLlT*^0<`YO-BL4BhSJ35&zbP~Y{558X2zWkG0Zg- zNnNC86fiZe0%jpEypCrY zG1Epy;dZlTbooykC;|?DVM%SIQBz3g`>HPR! zrjjL>Od=#I&Z(xYgr#}ON-4MY(K(&?M- zfgu7FY9;c6rCe53FiyBLci!G8HlN*HvLkHu`p!sW?S&$6eWCLb6)95STe_ZbZV)F zv*l>dtEwmTo`hQ#1xe)Owq82_#=UB3J^an2LE~p>6*$VlxnD2rg)QMc@mf>1B>u`O z8>(cOp?f%ib2E@>Y&V4Lk%~u`hO`SeoTXT`x6qnMSxM>9v-wJ(&pz?!mP*6^KqHz* zXn68CPItthOd5g#HL*=agQxJ#N2SD8^7>+5dCA`&Igdo@ne zGX0;e0}%uIVIqcPRnC5JE%k2aQ0uf6x`sKuXIEM3lDc%i>gB8y|EZOL{wXe8T2!1W zb?Rh!H$Pas1JS8KQERb&FLT9L=_ev!jUmp;GhmnBE?jNfbp?`Re=+Qwve1TR_IscK zv;VTvQ{&B0y1n~qyZbyL;n&ImGxN3wb}%>Nw6x4&wB}mKu{-KJujJFEN075=>?$1RakALtE8yBG ziw;fo!{jHo>QY&J3B|@JxyJ3+4yskfUc)~BItpp9Ecjyg<8Qz1_bOwOrq!IdXjile zK!Lzh!%q$2gfjB8LQT#CAkxj*oW$Jw6=G#wJ(d(i1}MrK)`tCh%}dS{1@BBVvT^Yu z)cOVnTiyIPW<)la<`HYUPrUlf3fdlMpOLK*DIqDEA;zVY6n-?C-LORjjx9LUB@xD+ z9E{*_b*C|^n6VS8>OGqo7bSpTT55TuJMfYrQ4jP#F>l8BV9VBSLr)gpAe8^OHq>sI z>_ONn^&z`Wls=#O^_uDQK?;lL}7oGMP-Hs(;pxuaf?JX z4VkEW8zQ^T6fCW#h7>JsmJ|<3U$z~0Se-=;!U{nm&aE&=Air=TME-ZF1~W342iqMr zkOoPl1HSK6s--t;XGzr~m7tYV)uf4KpSL3WQSYZf`~KRbgBES7TF?s+B^mLjUmw>? zKq^OdXz7Dqy2{evXMeXUk^#A4b!-KGbGhG(J{7Hjz}b%G_|k0jlUzw>h9LTB@MpRb z;q%2Q%e6z~!=Q@z-`!~HIdhwhQ(-$&atgGxbEnr*zY~n|U;emN>~p~?mS$1-&6&A` zj)gWn*Ld6h@B;})@=~vqU#@znMUgfA-JCI5ONFL{IAiS)ICPObT~i%AYl-9pV^)kM z))?R*4V;*0_S7Yy1ZEH2W8=Dn#aEH^Lc`*k-&FoPXAK(UhT*!ednl1AP6-JVzm;fV zk|*vJ0*9Ghuik!Q=laJn+sMGg@5743w|z5;w?ChSYhaI*Gi8H*NYb!{I@3211f+>N zhRnE|{7eI6P;=Z13YLfT_MElSGo6DuJwdv!6H}2=u-DW@2pcUIi6_bMqV{ zILYQ|E6EgjVae~QEfTZEGmih7i&VFib|&_Nh9ZqmbRVuZc22QZsl^plnNsVodpUE@ z$%VXz%09sT;17TrGE;2u{x-9<^=(%QO`x^s&t>yQoAtq5M|BgG#Exqm^tSZtpzrei zl;g`+It@YNl@&9m2nC$SzJ{3twU}6zhG4Ig`46&}Pj8-5`YpadaGcKs2rUn1%KM7f zGc+nP0A+!nz5p2%4eqCSMq3l6LXM%=dM~C28M-4(IAj$*_){B@b$=43zmR&8Cbmuz zHkgv&p44uhqdYXYdArqON>FtiZpWrwBXyj%~gj9Y~Y$VWpjN`I2ZT%^_(d{yNrnO_+bx?AOv)W5akuzyfvI7NU?Hk%e z+Kekm>r1EK3}Oqloo)puq8f`r)Tnx){?_#gk}TOhYFsF$$^C*5q&e_j ze!8$NMqQnNJOArTbpD`oxFHRvk5SSSNRvU`#o*{#NtVnYpJ1=YNAPpkFzXALX;4mX zQ^$95QI3k#|Aapp5G^QcEnLhObVH!*x0r+3rRJ*D9+l%Q#FZP8VTwzL^~9+L)WEQ z#1l*DEgooCqX)Y0FlUJyyO#ng`UWAV7b0>({=HJSwuut2GwR(U);S8be@(Z)2X2Tt zJASqqOy&0lO#l6RE}NjIEoEI&#yeVc57D3(!2S1#^g(Nz?B>UlfK2AdCdc^#5g+Lv z;Yai@JxXqiYvf!{AR&UK~rE6cv(`M)}lj7>X%olR_zklQ4K-aO0~ zn$t~BMJ%Lzeb!DY((*`3D7Q%7{%+p5`{fX+^4YZuMbnsAgr)3P5zn4`0cR3U=hZ&j z$s2QSxiD<=ldOtGtD%7n;&rKO{L;C*COIuDxvq6qg0OSyyKT99f|txjQpn+aaS{=f zb7WDbb7Ws%M+vk@m{=$C#u-4!#EZ9s+%wO`XsaJJQha-=CfkRgh-&h=p;aUQ&EQLy z_!qJI-XOJGr5@=Vyi$KV8DKTo_N47SrIOU99GAqKoOY6pO*kj+RDSxFoEvvXD3YnR z;vH(mAzr_`<+L!fxaCfCtnYs1&ka%0s<+{T89dUNGev`t4ia9<9bp366DOe(%2|&p z&#ii$Gc1{KM+azqhbGbxbrH|_bzS7r4~H94kA6vsyh5nEoH4?8|1rkLTsCq2%JWxt zIb1rCRYk+qjP7H3-NTR+zLCY@7fk|auNiaoqQX$Ge{lay%^gNIx6kM5Pt%n8%jvC9 z-_FQ0dO#Jb&$j!Dw9&-}6@hqF?*8FR5)T~ILD%*ZGJu(>w%Cd?jF-PN?SJ;{aSf3! z*^L?MXInBy4*8j`QKvq{6m*#g*1xO|=Yoj3QiZ~a9;+i}Y8Ib>$YGNCzHl1)m;4!l z;C0cLO7`;Rg9i+-QxW=xzQWZsKH2coAlMkaA$f{{DC%A0z-PIO5B_k9Wuc{SM+LIN zCS%m)*XEWST$`SC%>`766^o2rJ!C$O@p)mUdKjZSS8$4pybykR&CI;dE80-Ql0WAY zF9~E~F0**1OXr#5G+6l@E>riaPH-L&hJQSq<%#>%ZTbX>j%k-Aph~cQ*89yK+^vD2 zNJC`}6lC&wzjjAkFrE$k2&=TzJ|e64Gc&z2#SBrh5UUv7Aa9?tWj~*I7m?S}yz5}O z;|sW(T;TX(r@N>!C~mlL6}`DF$$r4|yip-0;*BhbNP^+-;dYJ;-bByBPCJqnQbiB> zjEXrD?NY%wBi#bf=m+telgmukfLXrUc2zPMaUx!?%yBB{;8%NdLda3{a3vxEBJMi8 z{{_U3`A%seo_+8xsgF&0G~UFDmg`nKYaeJ%4=a*4H9!-wCQ3x;(nQ7VnpUf~7FW`Pii`tT`k#l@KgjMy4uu+Og@O0^| z?2MRZcMdpNq)8@bw%Se2kLmKiN)j$LWA0!^?5%kdxA z?w78F%)kF)YmEA;Tst5ksI{we%}|P)NLT&)I+@AS2nH?6TZ4#`rYu!i)Vnl%;w;4x zP@|jPHkcW=BGOL7r!VeBAgl@AyXA|sMMDIM9LcY=1wKE^o_?UM{0)TIjO)AcvWZ4J zAD~prUNcJ@z{=5Nhp@X0FYgXz5`IgVO0{1m!JI#JUYhL27nYL~9BdcYkkcYVk5s## zH7d`_zg^_cB$=LdYP-M$xX~@YYb7_VR7>Z;5n%dUeEBrH4w>fI=#;%K+sW4(r@mOV zq)0&$Vj}cZEIQTbJla|G?5Q84SNRUR+&stXd%xJd;g{ZT*;JpiAEj#licvUQ#K`5I z*Fr-NdFvC{M@-BkaVkhZj zF~a)Y=GmomX)~*{DXe)O7_?W)22tVTf;*{3&?x~?!fjjQHd&EiZ@`Hb*;zeaLeCa& zc|M^pr!SbDR}=(6rzuTy0qx0-Tct-aYK9OdmPiHUT!;F8?WTvW=LB0`m1*KR!oE3Z z;?t`lU1gyhSFB1ls-LpB%9=Dqd`@|-pMiC@p0DCS>4CR|0(>_XPh!JaVB$k=zKC^% ze2n#fMSdlbot==8n{Z|{Jl3bwdTCR7#^)_9#CgWKiAcfXf+n9x+42ekVL1h={|SCHIL$GH3TgvQVZD1f0T&kE8A}9Q z(uWrMIT#vK*xHXdP)kogdGU&~$0ZzuWN5{=6zo(B@g6V8CVF_D)vOGSI()o2S$b*x z;&3gmw;6zi^AdNq$&7&I?w#zavXalPPAm&(ltz3A;I_}t4#pZqk#?$Ogay)K}9Az`EfViondJ@M_8U9mPE z{hw4w|huf-~5!iMdM8`=|dzRqWMj|bcJ2nF|u!rD)R30VB%0Mf(xtB z{yXM*yb^Wv+8o|{r_9$pUn^I=CqN%0<8M`At* zYxv$uh-pp+yq3oCFK|N>wjoaCoe)SzV7MajSl2|H+Cf7sX|_E2K+NqbcYfe9x(>6Pr67=c1Q*AC%sR9zzO) zwCN#N2%pqsM5K$a#&c4b5w(C@G-J9ETr3=)XV+h`21A0;>Uk;;YK}MF9RJ zXybwrLqInMmqk1i^Qv5T-1i&TQ$(QrLTdt|Q)R!tlVMZh`Hwo9_#tD`2d|Mn?*{4oY=~|)GGuOuEa%=WJpzD4Tc}N%V z*9k%XDOh5kTq!ycEYL-GheGd3^{uOcMo3cqsL*k< z?{n9_Eg7(#_*!ro!b5O`{ueN1VX*mbOc!=JZ&aUh9#U`7BBHoTv zWYvdUc8UlIkdjXC2H&?EZe#4UnHr2;b@_?9(A!o|test2%7TN>e0TjGb)Q%LN%d1h z7xx`Pm99lGWNFRnGqw|Vdzzbd`6j$OZMJp;{UPw=dDm?1-ylrx6w#}J@%;z1DJM<@ z)uI8|>FC#NdtT+nxXqbVTypw7ZDCXnb%-gOt4y>Kr5RwNPI(D8dOmAZ)xOyc;eDg< zGahZgBfRY|1p{0PoCIZxCt=L_Y}V*n)^ zdWuHY#YTu;&JR@Bg^50JUz?94%&(bBzTk|fTApg6+LfN%e{cFZmBJL+IY5xtlI8}r z+jeS~uMzM!BwrO;U4{XiQ6SJu#g@M_`v z^xxkN_+|j#AA?lHU`wX241VgEADpnCh-nLahfVMYIELl@YCz{gj(i{%xq9g~5BF?s zx*qt1MI!uaC~^ttO1R?NBx9n;hlQG%-@t)Hl3)`C*V3*7S(&{qKn;uf%flm&PaUM2iQU#m=ZE(2o(*TA{10CNR;_0f{ zRsXA@+3OheBw(IJa8*l|0|z_7Zc2a={l+IW2sBbz(@bafAB%~B$D0rvjX zRmi1dB;Ed6koR%hvim?r8+-!P$Ts-dv;@vr9LIg{m=L^1o@@s*x3X6+>lXhIq$ zMNU#2Z?WiE^?5N{Wy8a86fDOhBbS&wS8b6czh<#op0N`@0k}pt@9>)(>RUSROm!_T zE>c`I+()@4!mm`$47{GQ#qSnjXGhK3NU>%+$W=W@6HLwL&*JI;5Z8gxINo2GgqZ~< zYL%dCnX*dE3CY=U9L8es%yac_N1y3_ix5A0psQPj-xLD#Sn^sfL}&-P-7!$3eokDs zT|HL}4`jyHBp2kbK?dzn=Z>oOe-z3aDVr~GrKS!OXn)P~?j+zl4%{E2=5(OD^OmWD zS5Hm5gdK2mvu^kus`77&u(qb%N^28E+P19f@1$E-nLcqEOf zJShOLSBT>dWnVJiy(;Z&zQH5NSd`#bzcoRr`pMYvw^ zB>nLbCvHmchb~}heSic2oYrIQ$~0S;S6hDdMMBtCQ2ej(vw;1$5zqlOx!dl8xWI-R zHeSbZA0@zq1f2kwa=Y39c}{t(F8Ls^;6xnny#FTkzfa*Sep)Dp%bG8fo)g2#$*Ee< z754J4&}9ZHYQf*};6~i={~qd36DFvh{bH!difgg&xdb?rEdb(CAo`^z?hkSdD8d9- z0}zg4Yh|ZQf}Vj9*S%S)yP)Dn-hMj(2Q zfog2lPqbA(s--)3k*a^$Q^I1y6$@p<*%VmiMg=h>4EoGmMyICscJ2W&c6xw>$)Zq@ zquDncZk!j3u$!^R?MKjE6Y#^&bq0k>^lE|NEzUVjPeFt?DWQx9n=dOsUcqF8 zIOr9RvSNmoL?1zubkRQ}nSe52zx>)I3-7qCduOVr{i=0wL-S)Y$cO+O4U^wK^_xuD z1ROW9u?!;~fr*8JAw+R{s+4cwI2;R~u$&*&KIa6u# zGOtVmq<4e%I0R@?I;*FfSuI~Fwe8FN_Z?t}ld%&=n}jIT(_^)4Q&5w*4Bs2uIgl|a zH9Ts!s)9`D?@g^#XNLX9WV~_*2G#Rt7^g;w^-<5eM1t+y_c^qG(>7Y;&ouLn0p&}o z_xu+prrkomUO)6^G`2DXeiHT^f1yV|(L?vvW7+o^1lXN#?K225Z2WP7>b=8vx6Th( zptIiYvFdp+1t3rw3V4JfR@_hKJ}H8p_uSpxMX9u3EH6KbT4Eo`n%XN>TNMoG&BJ;i zMWIqh8F!me^wLeb-gOQ#{zKph$>eQ;Of@gAd=VHb9kAMW`B@g{W#wKt`Pq5{L;)O7 z>a&1X$d5&?K~ceB++2=21DkPmru5{jEc)M*x*mtgJ;R!3=G+e@+s$`wH|d|zv> z)f2mkRE=@F{#^ML=gnx13Cz<+y1Mn=Ossmu9!dC~I5@dM(DHe)uZubK1`r2t%bJ}K z5Ne)ff08|DMR|u`7H6ilSn054F@80EP!8+%C4tYOs2QiEbW&R#a&GMO-~Fgau;Y(~ zkKWHVT=7TDZc`dwZ^bpOQs#cyP9nO7+<>^3u(=<01jX~A28F7(SKjT29gZ3ajP-Ax z!Fumo&>nKl-gesVCwqCP0%yYlKgID9-ep6bdn2LcVmR zIP+qbMDWBM>XdUOBNOvAs&a}Ab`Tr^6~RoL;|I6lXp<( zE(lc~(g7IuDUjiH1GdWQL(#riL+{* z5#LWP+BHwsL@`hbmh_qqr2j-?B{oQx59k$GkAy8wrAI7}RSG-|1kq^?kX&@*m%^b0 zG1o~A_52Y$NH@2qdhzRg>IUGnmgUEt4_s8cL}K%CdQG9&SP|vft!bbK2Vm=%Q5PV) zYwC@QtGv~R9qm>PoK2O66Me0?$qFqqm?{M8ha-7LGHK<%fZ)^2tJK$_hhB0DV2Ya| zj;j~xrpi2fno9G^4_4M91HQ#G;B?eC79XQq8(#vcwP5sQyGbSd=RJXO2;}5&L(YG? zQ;iyzRoHIsO1)q;9eyN-lfkP3_5-P4#?jkjfwWkF>eP?6{JN+omvzbXZpXP|R>oZG z{52b2#xB(?zHYA9e%_n%o6h}cj{qr{+`bUbnb|vzQ|w!~ZDQ6Pp}RRrqSdIwW(9r$ z=wGh)n|N_NmeWx*;Qdo8wkhJPjI`~)n_J|LLus==wa$RBOHKQTyat#u@dgN9@Fxq? z!ex>RiYoLCughJ)Y6+?ZJ>AA9k@6X=$b5U-V^=%awJ%#bfmL8VE1tFw9s83&UiDUK zWI}QP^SSz%?3L9~qad`hn`ZYXOeVavnbjn&>!`i&Hf$sPG9TydL)2S`NFiOTJblce z6#p^eSJ(ViM6O@&@|A+6JC|5oeYUmd$stWm&*tbh3J<0$`k z2Gqa1_;>r|hGwu3{P(vuIPU*-;;!~J$P`Yk!9s(d3EFfVPlAXW_whc(!l;!Ku=F5m zEC@>vj0*0xxZ7s+!yeO0jg2#}fpG?XJc6xKzo(NQ61+H3yOS$WVgWM;nPPi|JDr;k zt@>ZvsR+jN0U>%r4uXSM?*t3!`$=Ox;npr z|K4tvL)oapb%X)qJ|^2Ehu)5KL%Js5&xiqEZPtnNaXdFHpNs;}lewhtrZ^8Ez>}~b z3cbiuA{^;0g{sAYGH{~)_^AP`doPM~V|%`|IN=V87XZPC;8@`g^F`PYlmP614>cq` z!Ff#Z6MkJ5kym2o_P&|Psv11G=T;z!%MkSJswY5XK0o0uh5vhUl9dW5WWp&9;PSVO zP+U9FgEZG5lDdz+=nrr|8Rl2!GC)@*`3)qkU+@wyHYCm|ti{g4B#fK)lDRM1X?DKy zJ*fC{3pxWubB#ah7^g#a>dK{=|#y%RhTo*h~7X=eR)CO|4*p`*xBMi8Rz8+^M{)0JJ0kjmoc z6PXn&#Pj4>IVK8xxzjvHm&V%;kSPeR zAC_d{?dliXQbrk3xC`o9^fax~+EC{6srgLR#Pj-Et~N5sE>l3Z=V2^2r> zClk*O33vx~Ii9(!1wnDW|4gKP3h*GV_v@uVXGZ*ls+J&(CShM-IMJ*yBPPY^i zS&7*l&V;o)CQi8QZ@0$gD^cf*!*xeKk8}TRGT7R`rX4VGjET9UzP;`pbf7N(Ug>W2 zd?Q%%Z~KRvH84K>{el0c<-qad*!cWU7^^7m|IY}*t{smD3`T!EJ;z`DPw?P>>XMg% z0s%4ohs*h=7y3VWE!<+}x8M9PUJKjBs~Q$<((4db?PC{5lJp@BMuXz2RseF3ZSnMq zANei`C?Gb1r2?qq36k^=C1xw@WD}n@CpfW61GqbfXgij~Pb{$%V=w&Y5zi8Q(GcvPj?X>8QUEveSgLSZ z`o|G}8{h;^Qn3PXe2yIgw(Wm8;tVM0@ZZOOcYJ()+~L2E|E1&O3;w&~no9yKPG={XGM%V9mqOM>K(p|Vm^F*Xg@+xDeKOeyCeFrxNcz}z%z>k*LzDk zvx2Om{_eY~qVEOT=jzrZ-$##N>v)XUKLPK?#_-NPc}v;Mmn%!P{xzF&e#ioz0>a8f z%N2<4^nHr$GYcQG;ss5^E7d$So@DJJr(>& zSQ_E|Oh>ztvJ!h#1^hxu=qh=PEoWKomy?op5k11wD`b2ID&zOLA8Bf{M9awkW zq(r6K6r^}=D-?E8Q4nN1Qi-}x&m3s1ihH2f>(^F#OSN|rDTQtFvdU!>^#;cgPeDF( z@KqsUiudK5#+kTRyq=^T|A}-4(ii6&@k6HME+8Jv3SIIbOb1Hs#JZn z?`ENg@l>%Kb!FSBvYW~~B;8(EKF4Sahe~0}?%=X>v2W8Urup=@_jI8b6SwKccG|WWm%s=u&eBwVSCE{#<=r|2O1%Wt2yn>1?3;4EZH91f*7fu)a!~N8+rL8 z@vltsVf)L|#oshPRUi^-xK3V5tU4?@_r~JA{We4-4B1q&g;=~@3%iHT8&&pvY6LO< z3$>}}uveWD#qo89QxNc(>D%qglMmKDi(FC|dc*V(gBHL)_6g)WJcbgCgfhdVFiC0! zWp-|_16cY#Z&hYfg$&ItSq0^1R4`n_oPVL^$`gWE)5&=8aLz=@Q-BN7^!XLX5+&7c zs68f~Q?KYFnG_O$#2VTz+);^@e{mEDb~;zZ%oQ3e+nKYtugzdH&ab_C(H1Dp2e7(z zAV2M=M-c~vG{4gowVh%Q&uo*;`NWtXhkrmDj^~;xN+b$n^~qmHQJzVNsF0>*Q# z?T%5V0-OR4Z9095S}AgEvYWY6GEX~8xa|)1rd*#og~v2>Ow%2%#m;*D<4-9ON^XUs7(EnJIy)G)a_7HPre zIdGllN%v4HFL}Ft*1C=152i=mBEnv&J;8{%sc`9A32W-jHPhCE(;96Q)cRjAPbRp6 z?-2Q|?Q(XWre_;mSBkXsgWDmJ+x29+1D4!{QUVmqgO--2DU{Fpkj!r)Q}!Ogq*X}G z^KUk88|y+71U;k^OeaEAW`s*-AA{%Bfvn2V6Bi@bQHdAvNwI)>jE}HHm5C-<%x?Kb zg3l2-U6Go*q&y2$nfwkH=QGpTAxe+WmZue4v92pUSe7x~FRWAFSdOXjs%nyB_=WiJ zieY`Gs+n1I-?3Hp)>bS!$WL2FzuKlNAbD^UV=xyp0M%57?uQa%(C1uDYAKpSrGM3Y z>M*#&^X{eqS5bWj_SIT)qKWJb#a_K&1=jRDJUvA11SZx}ADhh)d34R#;(n#omu&xm~tZOd4P z&})huWo+pFIM0--zJosOCCx9=uj&wwgMWcY&$A^VyES7J!+Ua%+oeBKwiO1^LyXw(O=QrvY7o+Ic>YwXMC~ zCQCUPA@;7$Pe#By{Mu|@gVo1=ExyngZ#j#Zr3I39SsdHITiWFU_{Xw<6hHUd+;=UN zXz7-^k+RRM?;QqweI?a)Vass^IrYPU;el9Ml=?uh4)ldGeXR)F3`EQ3?e3`Tn7$6r zy94H2h&1$p!%O>-@sL^S7we3xW^X z{&jwZj&|sbb)~(dqgdTmr5Lx&ord*p{A{XNlfl>^{pmX59zwIG6eM)9Q`Z8HF$1CNlS+=A83cxh__DD%_#M!>4;hHoBORR zWpe*&0^lcjH6H+Tb;PA#GTgz4Ry3y7~^lVFj^vM^WXBZBl*({FhS8T!zL>Fh+saiv7)=VQx!mp)M zr$x5$$0st|Y*c_#v=3Z0kFYEAw%q`fTE@Rmg5NOjRP5y_% zB%5|eXS~qdw^-c#nEc`-OETrfG|Zoye;`Bx4hswV*>)^ zWsKho(X-dm-uKB^>W>J0{U&(CoE1dm|K6n43w~NoO|PQNAy3`-y?_idrC71-$3Ug8 zG#i4uR)U1nab1aK3`Q828Q*^B)!ZeGOwsz8vJQ5jPMNU8kepR7-u^Ts6wEtr0yjrKflfA+~tg7m@5JW@Y`Ga^5 z%zb}>&*u5#ZigGig>&xFX%rz`J|59Z-}+y(SJKT=LY))Pq|k=ZR$1StXAIxjw{q** z+-s9%Xnm>$5%b`oh0n=8(tpSd!PI5Ais|%g3+Lt}kXZdW#R&Ktqobv|<}2q;c!!QaesM+`IhB|m`CQCASTVe} z6#)-0`DS;qsUoz$uH&1?rNqE8S;@2YXSYaAL}o9A`CoZbD#T>69zqkVqfECg6^>{N zmRoka?dn4O;n`hcRe{kywv}q);or2W#3`xFa^FX6WT4c`h*XGOsj;SnT3GZyXyY2bi z&nYU37=-&L*;S$w;K(YicKPP%l$ocr%x@Xz!Ufnqpl%xRJ3ili%@dM!_smVJq3TDg zmtG2mlhUiOab{-QalGX7nx78j6_kH4U%*Gap&eVY_|vB9bl^BSnk>@tK-(dk%}&b6 zyA1v&O**^WWv!tcA`iW2F_L|?@k;k#l+}CTtf}yHc)nis!F30gJeQnx8!gRKiQG@1 zJb}xA(h|}_v;PO{YKr)iju1GKO2lR6Dv7VJ``{|{o^h>L zdcJBcxsZihmkhrOrQ_E2sh~PrWuu!RmRCsfUih~+I~mNxrJ8wM$B>1S2xk zp24G#QN&_IOy;8n;^lCpfYV;B${+K6Jq}Lq%y_wp`)WV!TL}@1H<y2%3w=G5S3Lu&++p_i`_b|UoF};g?khL`zQ+6Pz+TMy-XpsXqlfq#6d8PbgClf1&5bXpiiq$xI>vq>58=~?g0Y;i z2>i{A52oqr#-C6nH-KeqRkB~RIynA>bOP8FqqEz0!r=I@{Tkm+i diff --git a/examples-staging/basic/package.json b/examples-staging/basic/package.json index 08cc8bd250f..19b888126fa 100644 --- a/examples-staging/basic/package.json +++ b/examples-staging/basic/package.json @@ -20,7 +20,6 @@ "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", "@types/react": "^17.0.19", - "apollo-server-micro": "^2.25.2", "graphql": "^15.5.2", "graphql-tag": "^2.12.5", "next": "^11.1.0", diff --git a/examples-staging/graphql-api-endpoint/package.json b/examples-staging/graphql-api-endpoint/package.json index 687922c8585..a435251f3b0 100644 --- a/examples-staging/graphql-api-endpoint/package.json +++ b/examples-staging/graphql-api-endpoint/package.json @@ -14,8 +14,7 @@ "@babel/runtime": "^7.15.3", "@keystone-next/auth": "^32.0.0", "@keystone-next/fields-document": "^9.0.0", - "@keystone-next/keystone": "^25.0.0", - "apollo-server-micro": "^2.25.2" + "@keystone-next/keystone": "^25.0.0" }, "repository": "https://github.com/keystonejs/keystone/tree/master/examples-staging/graphql-api-endpoint" } diff --git a/examples-staging/playground/CHANGELOG.md b/examples-staging/playground/CHANGELOG.md deleted file mode 100644 index 46db53e1b83..00000000000 --- a/examples-staging/playground/CHANGELOG.md +++ /dev/null @@ -1,54 +0,0 @@ -# @keystone-next/example-playground - -## 1.0.6 - -### Patch Changes - -- [#6391](https://github.com/keystonejs/keystone/pull/6391) [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41) Thanks [@bladey](https://github.com/bladey)! - Adds support for `introspection` in the Apollo Server config. Introspection enables you to query a GraphQL server for information about the underlying schema. If the playground is enabled then introspection is automatically enabled - unless specifically disabled. - -* [#6432](https://github.com/keystonejs/keystone/pull/6432) [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9) Thanks [@renovate](https://github.com/apps/renovate)! - Updated `typescript` dependency to `^4.4.2`. - -* Updated dependencies [[`2a901a121`](https://github.com/keystonejs/keystone/commit/2a901a1210a0b3de0ccd22ca93e9cbcc8ed0f951), [`3008c5110`](https://github.com/keystonejs/keystone/commit/3008c5110a0ebc524eb3609bd8ba901f664f83d3), [`3904a9cf7`](https://github.com/keystonejs/keystone/commit/3904a9cf73e16ef192faae833f2f39ed05f2d707), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`2e3f3666b`](https://github.com/keystonejs/keystone/commit/2e3f3666b5340b8eb778104a1d4a3f4d52be6528), [`44f2ef60e`](https://github.com/keystonejs/keystone/commit/44f2ef60e29912f3c85b91fc704e09a7d5a15b22), [`9651aff8e`](https://github.com/keystonejs/keystone/commit/9651aff8eb9a51c0fbda6f51b1be0fedb07571da), [`9c5991f43`](https://github.com/keystonejs/keystone/commit/9c5991f43e8f909e576f6b51fd87aab3bbead504), [`069265b9c`](https://github.com/keystonejs/keystone/commit/069265b9cdd5898f4501535793f56debaa247c1c), [`4f36a81af`](https://github.com/keystonejs/keystone/commit/4f36a81afb03591354acc1d0141eff8fe54ff208), [`c76bfc0a2`](https://github.com/keystonejs/keystone/commit/c76bfc0a2ad5aeffb68b8d2006225f608e855a19), [`bc9088f05`](https://github.com/keystonejs/keystone/commit/bc9088f0574af27be6a068483a789a80f7a46a41), [`ee54522d5`](https://github.com/keystonejs/keystone/commit/ee54522d513a9376c1ed1e472a7ff91657e4e693), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`bd120c7c2`](https://github.com/keystonejs/keystone/commit/bd120c7c296c9adaaefe9bf93cbb384cc7528715), [`595922b48`](https://github.com/keystonejs/keystone/commit/595922b48c909053fa9d34bb1c42177ad41c72d5), [`8f2786535`](https://github.com/keystonejs/keystone/commit/8f2786535272976678427fd13758e63b2c59d955), [`b3eefc1c3`](https://github.com/keystonejs/keystone/commit/b3eefc1c336a9a366c39f7aa2cf5251baaf843fd), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`bf9b5605f`](https://github.com/keystonejs/keystone/commit/bf9b5605fc684975d9e2cad604c8e0d978eac40a), [`3957c0981`](https://github.com/keystonejs/keystone/commit/3957c098131b3b055cb94b07f1ce55ec82640908), [`af5e59bf4`](https://github.com/keystonejs/keystone/commit/af5e59bf4215aa297495ae603239b1e3510be39b), [`cbc5a68aa`](https://github.com/keystonejs/keystone/commit/cbc5a68aa7547ea55d1254ee5c3b1e543cdc78e2), [`32f024738`](https://github.com/keystonejs/keystone/commit/32f0247384ecf3bce5c3ef14ad8d367c9888459f), [`783290796`](https://github.com/keystonejs/keystone/commit/78329079606d74a2eedd63f96a985116bf0b449c), [`0a189d5d0`](https://github.com/keystonejs/keystone/commit/0a189d5d0e618ee5598e9beaccea0290d2a3f8d9), [`944bce1e8`](https://github.com/keystonejs/keystone/commit/944bce1e834be4d0f4c79f35cd53ccbabb92f555), [`e0f935eb2`](https://github.com/keystonejs/keystone/commit/e0f935eb2ef8ac311a43423c6691e56cd27b6bed), [`2324fa027`](https://github.com/keystonejs/keystone/commit/2324fa027a6c2beabef4724c69a9ad05338a0cf3), [`f2311781a`](https://github.com/keystonejs/keystone/commit/f2311781a990c0ccd3302ac8e7aa889138f70e47), [`88b03bd79`](https://github.com/keystonejs/keystone/commit/88b03bd79112c7d8f0d41c592c8bd4bb226f5f71), [`0aa02a333`](https://github.com/keystonejs/keystone/commit/0aa02a333d989c30647cd10e25325d4d2db61be6), [`5ceccd821`](https://github.com/keystonejs/keystone/commit/5ceccd821b513e2abec3eb24278e7c30bdcdf6d6), [`fd744dcaa`](https://github.com/keystonejs/keystone/commit/fd744dcaa513efb2a8ae954bb2d5d1fa7f0723d6), [`489e128fe`](https://github.com/keystonejs/keystone/commit/489e128fe0835968eda0908b199a8867c0e72a5b), [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248)]: - - @keystone-next/keystone@25.0.0 - -## 1.0.5 - -### Patch Changes - -- Updated dependencies [[`e9f3c42d5`](https://github.com/keystonejs/keystone/commit/e9f3c42d5b9d42872cecbd18fbe9bf9d7d53ed82), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`1cbcf54cb`](https://github.com/keystonejs/keystone/commit/1cbcf54cb1206461866b582865e3b1a8fc728f18), [`a92169d04`](https://github.com/keystonejs/keystone/commit/a92169d04e5a1a98deb8e757b8eae3b06fc66450), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`b696a9579`](https://github.com/keystonejs/keystone/commit/b696a9579b503db86f42776381e247c4e1a7409f), [`f3014a627`](https://github.com/keystonejs/keystone/commit/f3014a627060c7cd86440a6937da5caecfd023a0), [`092df6678`](https://github.com/keystonejs/keystone/commit/092df6678cea18d639be16ad250ec4ecc9250f5a), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`6da56b80e`](https://github.com/keystonejs/keystone/commit/6da56b80e03c748a621afcca6c1ec2887fef7271), [`4f4f0351a`](https://github.com/keystonejs/keystone/commit/4f4f0351a056dea9d1614aa2a3a4789d66bb402d), [`697efa354`](https://github.com/keystonejs/keystone/commit/697efa354b1066b3d4b6eb757ca704b458f45e93), [`c7e331d90`](https://github.com/keystonejs/keystone/commit/c7e331d90a28b2ed8236100097cb8d34a11fabe2), [`3a7a06b2c`](https://github.com/keystonejs/keystone/commit/3a7a06b2cc6b5ea157d34d925b15494b471899eb), [`272b97b3a`](https://github.com/keystonejs/keystone/commit/272b97b3a10c0dfada782171d55ef7ac6f47c98f), [`78dac764e`](https://github.com/keystonejs/keystone/commit/78dac764e1860b33f9e2bd8cee6015abeaaa5ec4), [`399561b27`](https://github.com/keystonejs/keystone/commit/399561b2769ddd8f3d3fdf29838f5784404bb053), [`9d361c1c8`](https://github.com/keystonejs/keystone/commit/9d361c1c8625e1390f837b7318b63547d686a63b), [`0dcb1c95b`](https://github.com/keystonejs/keystone/commit/0dcb1c95b5200750cc8649485425f2ae40d023a3), [`94435ffee`](https://github.com/keystonejs/keystone/commit/94435ffee765824091899242e4a2f73c7356b524), [`5cd8ffd6c`](https://github.com/keystonejs/keystone/commit/5cd8ffd6cb822dbee8555b47846a5019c4d2b1c3), [`56044e2a4`](https://github.com/keystonejs/keystone/commit/56044e2a425f4256b66475fd3b1a6342cd6c3bf9), [`f46fd32b7`](https://github.com/keystonejs/keystone/commit/f46fd32b7047dbb5ea2566859f7ecee8db5b0b15), [`874f2c405`](https://github.com/keystonejs/keystone/commit/874f2c4058c9cf006213e84b9ffcf39c5bf144e8), [`8ea4eed55`](https://github.com/keystonejs/keystone/commit/8ea4eed55367aaa213f6b4ffb7473087498e39ae), [`e3fe6498d`](https://github.com/keystonejs/keystone/commit/e3fe6498dc36203d8080dff3c2e0c25f6c98733e), [`1030296d1`](https://github.com/keystonejs/keystone/commit/1030296d1f304dc44246e895089ac1f992e80590), [`3564b342d`](https://github.com/keystonejs/keystone/commit/3564b342d6dc2127ae591d7ac055af9eae90543c), [`8b2d179b2`](https://github.com/keystonejs/keystone/commit/8b2d179b2463d78b082182ca9afa8233109e0ba3), [`e3fefafcc`](https://github.com/keystonejs/keystone/commit/e3fefafcce6f8bf836c9bf0f4d931b8200ba41c7), [`4d9f89f88`](https://github.com/keystonejs/keystone/commit/4d9f89f884e2bf984fdd74ca2cbb7874b25b9cda), [`686c0f1c4`](https://github.com/keystonejs/keystone/commit/686c0f1c4a1feb609e1584aa71738709bbbf984e), [`d214e2f72`](https://github.com/keystonejs/keystone/commit/d214e2f72bae1c798e2415a38410d6063c333e2e), [`f5e64af37`](https://github.com/keystonejs/keystone/commit/f5e64af37df2eb460c89d89fa3c8924fb34970ed)]: - - @keystone-next/fields@14.0.0 - - @keystone-next/keystone@24.0.0 - -## 1.0.4 - -### Patch Changes - -- Updated dependencies [[`3f03b8c1f`](https://github.com/keystonejs/keystone/commit/3f03b8c1fa7005b37371e1cc401c3a03334a4f7a), [`ea0712aa2`](https://github.com/keystonejs/keystone/commit/ea0712aa22487325bd898818ea4fbca543c9dcf1), [`93f1e5d30`](https://github.com/keystonejs/keystone/commit/93f1e5d302701c610b6cba74e0c5c86a3ac8aacc), [`9e2deac5f`](https://github.com/keystonejs/keystone/commit/9e2deac5f340b4baeb03b01ae065f2bec5977523), [`7716315ea`](https://github.com/keystonejs/keystone/commit/7716315ea823dd91d17d54dcbb9155b5445cd956), [`a11e54d69`](https://github.com/keystonejs/keystone/commit/a11e54d692d3cec4ec2439cbf743b590688fb7d3), [`e5f61ad50`](https://github.com/keystonejs/keystone/commit/e5f61ad50133a328fcb32299b838fd9eac574c3f), [`e4e6cf9b5`](https://github.com/keystonejs/keystone/commit/e4e6cf9b59eec461d2b53acfa3b350e4f5a06fc4), [`2ef6fe82c`](https://github.com/keystonejs/keystone/commit/2ef6fe82cee6df7796935d35d1c12cab29aecc75), [`dd7e811e7`](https://github.com/keystonejs/keystone/commit/dd7e811e7ce084c1e832acefc6ed773af371ac9e), [`587a8d0b0`](https://github.com/keystonejs/keystone/commit/587a8d0b074ccecb239d120275359f72779f306f), [`597edbdd8`](https://github.com/keystonejs/keystone/commit/597edbdd81df80982dd3df3d9d600003ef8a15e9), [`1172e1853`](https://github.com/keystonejs/keystone/commit/1172e18531064df6412c06412e74da3b85740b35), [`fbe698461`](https://github.com/keystonejs/keystone/commit/fbe6984616de7a302db7c2b0082851db89c2e314), [`32e9879db`](https://github.com/keystonejs/keystone/commit/32e9879db9cfee77f067eb8105262df65bca6c06)]: - - @keystone-next/keystone@23.0.0 - - @keystone-next/fields@13.0.0 - -## 1.0.3 - -### Patch Changes - -- Updated dependencies [[`38b78f2ae`](https://github.com/keystonejs/keystone/commit/38b78f2aeaf4c5d8176a1751ad8cb5a7acce2790), [`139d7a8de`](https://github.com/keystonejs/keystone/commit/139d7a8def263d40c0d1d5353d2744842d9a0951), [`279403cb0`](https://github.com/keystonejs/keystone/commit/279403cb0b4bffb946763c9a7ef71be57478eeb3), [`253df44c2`](https://github.com/keystonejs/keystone/commit/253df44c2f8d6535a6425b2593eaed5380433d57), [`253df44c2`](https://github.com/keystonejs/keystone/commit/253df44c2f8d6535a6425b2593eaed5380433d57), [`f482db633`](https://github.com/keystonejs/keystone/commit/f482db6332e54a1d5cd469e2805b99b544208e83), [`c536b478f`](https://github.com/keystonejs/keystone/commit/c536b478fc89f2d933cddf8533e7d88030540a63)]: - - @keystone-next/fields@12.0.0 - - @keystone-next/keystone@22.0.0 - -## 1.0.2 - -### Patch Changes - -- Updated dependencies [[`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b), [`03f535ba6`](https://github.com/keystonejs/keystone/commit/03f535ba6fa1a5e5f3027bcad761feb3fd94587b)]: - - @keystone-next/keystone@21.0.0 - - @keystone-next/fields@11.0.2 - -## 1.0.1 - -### Patch Changes - -- [#5817](https://github.com/keystonejs/keystone/pull/5817) [`10b36551a`](https://github.com/keystonejs/keystone/commit/10b36551ac3a88da2cfeba3d065d6dd36041e769) Thanks [@bladey](https://github.com/bladey)! - Added example that demonstrates how you can customise the GraphQL Playground accessed at `/api/graphql`. - -- Updated dependencies [[`10b36551a`](https://github.com/keystonejs/keystone/commit/10b36551ac3a88da2cfeba3d065d6dd36041e769), [`8afbab763`](https://github.com/keystonejs/keystone/commit/8afbab7636b4236c6604311819160d5f1420a90e), [`de0a5c19e`](https://github.com/keystonejs/keystone/commit/de0a5c19e656360ea3febc7e0240543c7817253e), [`7a25925c3`](https://github.com/keystonejs/keystone/commit/7a25925c3dc5b2af2cf1209ee949563fb71a4a8c), [`50ad1ce6b`](https://github.com/keystonejs/keystone/commit/50ad1ce6be90f5fb2481840dbd01328b6f629432), [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c), [`123042b04`](https://github.com/keystonejs/keystone/commit/123042b047f3242ac95d2c5280de8c07f18a86be), [`4e5634b86`](https://github.com/keystonejs/keystone/commit/4e5634b86a26819cecec5b10c18f9d231b5434e2), [`006afd108`](https://github.com/keystonejs/keystone/commit/006afd1082b474bac2499bed57bcaccf1e1d6138), [`543154bc0`](https://github.com/keystonejs/keystone/commit/543154bc081dde33ea29b8a2bff1d3033d538077), [`3be09ea54`](https://github.com/keystonejs/keystone/commit/3be09ea548861b490dad8b50e58980580d366434), [`eab130f30`](https://github.com/keystonejs/keystone/commit/eab130f30d79b82c18b3cce0bc054abe2c1b58fd), [`972e04514`](https://github.com/keystonejs/keystone/commit/972e045145711e39fd6fa167cb87fa05e062272c)]: - - @keystone-next/keystone@20.0.1 - - @keystone-next/fields@11.0.1 diff --git a/examples-staging/playground/README.md b/examples-staging/playground/README.md deleted file mode 100644 index dbbb99022a1..00000000000 --- a/examples-staging/playground/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# GraphQL Playground Example - -👋 This example demonstrates how you can customise the GraphQL Playground accessed at `/api/graphql`. - -See `keystone.ts` for all variations. diff --git a/examples-staging/playground/keystone.ts b/examples-staging/playground/keystone.ts deleted file mode 100644 index 9eb0eb1ed8d..00000000000 --- a/examples-staging/playground/keystone.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { config } from '@keystone-next/keystone'; -import { lists } from './schema'; - -// graphql.apolloConfig.playground === false (playground not accessible in all cases, introspection will be disabled by default) -// export default config({ -// db: { -// provider: 'sqlite', -// url: process.env.DATABASE_URL || 'file:./keystone-example.db', -// }, -// lists, -// graphql: { -// apolloConfig: { -// playground: false, -// } -// } -// }); - -// graphql.apolloConfig.playground === true (playground accessible in all cases, introspection will be enabled by default) -// export default config({ -// db: { -// provider: 'sqlite', -// url: process.env.DATABASE_URL || 'file:./keystone-example.db', -// }, -// lists, -// graphql: { -// apolloConfig: { -// playground: true, -// }, -// }, -// }); - -// graphql.apolloConfig.playground === true && graphql.apolloConfig.introspection === false (playground accessible in all cases, introspection disabled) -// export default config({ -// db: { -// provider: 'sqlite', -// url: process.env.DATABASE_URL || 'file:./keystone-example.db', -// }, -// lists, -// graphql: { -// apolloConfig: { -// playground: true, -// introspection: false, -// }, -// }, -// }); - -// graphql.apolloConfig.playground === { settings: ... } (playground accessible in all cases with further customisation - https://www.apollographql.com/docs/apollo-server/testing/graphql-playground, introspection will be enabled by default) -// export default config({ -// db: { -// provider: 'sqlite', -// url: process.env.DATABASE_URL || 'file:./keystone-example.db', -// }, -// lists, -// graphql: { -// apolloConfig: { -// playground: { -// settings: { -// 'editor.theme': 'light', -// } -// }, -// } -// } -// }); - -// process.env.NODE_ENV === 'production' (playground not accessible in production, introspection will be disabled by default) -// process.env.NODE_ENV = 'production'; -// export default config({ -// db: { -// provider: 'sqlite', -// url: process.env.DATABASE_URL || 'file:./keystone-example.db', -// }, -// lists, -// graphql: { -// apolloConfig: { -// playground: false, -// } -// } -// }); - -// not specified at all (playground and introspection uses defaults, enabled in development and disabled in production) -export default config({ - db: { - provider: 'sqlite', - url: process.env.DATABASE_URL || 'file:./keystone-example.db', - }, - lists, -}); diff --git a/examples-staging/playground/package.json b/examples-staging/playground/package.json deleted file mode 100644 index 7ea2c4206f9..00000000000 --- a/examples-staging/playground/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@keystone-next/example-playground", - "version": "1.0.6", - "private": true, - "license": "MIT", - "scripts": { - "dev": "keystone-next dev", - "start": "keystone-next start", - "build": "keystone-next build" - }, - "dependencies": { - "@keystone-next/keystone": "^25.0.0" - }, - "devDependencies": { - "typescript": "^4.4.2" - }, - "engines": { - "node": ">=v12.13.1" - }, - "repository": "https://github.com/keystonejs/keystone/tree/master/examples-staging/playground" -} diff --git a/examples-staging/playground/schema.graphql b/examples-staging/playground/schema.graphql deleted file mode 100644 index fe4aba7b55f..00000000000 --- a/examples-staging/playground/schema.graphql +++ /dev/null @@ -1,167 +0,0 @@ -# This file is automatically generated by Keystone, do not modify it manually. -# Modify your Keystone config when you want to change this. - -type Note { - id: ID! - label: String -} - -input NoteWhereUniqueInput { - id: ID -} - -input NoteWhereInput { - AND: [NoteWhereInput!] - OR: [NoteWhereInput!] - NOT: [NoteWhereInput!] - id: IDFilter -} - -input IDFilter { - equals: ID - in: [ID!] - notIn: [ID!] - lt: ID - lte: ID - gt: ID - gte: ID - not: IDFilter -} - -input NoteOrderByInput { - id: OrderDirection -} - -enum OrderDirection { - asc - desc -} - -input NoteUpdateInput { - label: String -} - -input NoteUpdateArgs { - where: NoteWhereUniqueInput! - data: NoteUpdateInput! -} - -input NoteCreateInput { - label: String -} - -""" -The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). -""" -scalar JSON - @specifiedBy( - url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf" - ) - -type Mutation { - createNote(data: NoteCreateInput!): Note - createNotes(data: [NoteCreateInput!]!): [Note] - updateNote(where: NoteWhereUniqueInput!, data: NoteUpdateInput!): Note - updateNotes(data: [NoteUpdateArgs!]!): [Note] - deleteNote(where: NoteWhereUniqueInput!): Note - deleteNotes(where: [NoteWhereUniqueInput!]!): [Note] -} - -type Query { - notes( - where: NoteWhereInput! = {} - orderBy: [NoteOrderByInput!]! = [] - take: Int - skip: Int! = 0 - ): [Note!] - note(where: NoteWhereUniqueInput!): Note - notesCount(where: NoteWhereInput! = {}): Int - keystone: KeystoneMeta! -} - -type KeystoneMeta { - adminMeta: KeystoneAdminMeta! -} - -type KeystoneAdminMeta { - enableSignout: Boolean! - enableSessionItem: Boolean! - lists: [KeystoneAdminUIListMeta!]! - list(key: String!): KeystoneAdminUIListMeta -} - -type KeystoneAdminUIListMeta { - key: String! - itemQueryName: String! - listQueryName: String! - hideCreate: Boolean! - hideDelete: Boolean! - path: String! - label: String! - singular: String! - plural: String! - description: String - initialColumns: [String!]! - pageSize: Int! - labelField: String! - fields: [KeystoneAdminUIFieldMeta!]! - initialSort: KeystoneAdminUISort - isHidden: Boolean! -} - -type KeystoneAdminUIFieldMeta { - path: String! - label: String! - isOrderable: Boolean! - isFilterable: Boolean! - fieldMeta: JSON - viewsIndex: Int! - customViewsIndex: Int - createView: KeystoneAdminUIFieldMetaCreateView! - listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView - search: QueryMode -} - -type KeystoneAdminUIFieldMetaCreateView { - fieldMode: KeystoneAdminUIFieldMetaCreateViewFieldMode! -} - -enum KeystoneAdminUIFieldMetaCreateViewFieldMode { - edit - hidden -} - -type KeystoneAdminUIFieldMetaListView { - fieldMode: KeystoneAdminUIFieldMetaListViewFieldMode! -} - -enum KeystoneAdminUIFieldMetaListViewFieldMode { - read - hidden -} - -type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! -} - -enum KeystoneAdminUIFieldMetaItemViewFieldMode { - edit - read - hidden -} - -enum QueryMode { - default - insensitive -} - -type KeystoneAdminUISort { - field: String! - direction: KeystoneAdminUISortDirection! -} - -enum KeystoneAdminUISortDirection { - ASC - DESC -} diff --git a/examples-staging/playground/schema.prisma b/examples-staging/playground/schema.prisma deleted file mode 100644 index 680ff9ec79d..00000000000 --- a/examples-staging/playground/schema.prisma +++ /dev/null @@ -1,17 +0,0 @@ -// This file is automatically generated by Keystone, do not modify it manually. -// Modify your Keystone config when you want to change this. - -datasource sqlite { - url = env("DATABASE_URL") - provider = "sqlite" -} - -generator client { - provider = "prisma-client-js" - output = "node_modules/.prisma/client" -} - -model Note { - id String @id @default(cuid()) - label String? -} \ No newline at end of file diff --git a/examples-staging/playground/schema.ts b/examples-staging/playground/schema.ts deleted file mode 100644 index 89ec9cfac3a..00000000000 --- a/examples-staging/playground/schema.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createSchema, list } from '@keystone-next/keystone'; -import { text } from '@keystone-next/keystone/fields'; - -export const lists = createSchema({ - Note: list({ - fields: { - label: text({ isRequired: true }), - }, - }), -}); diff --git a/examples/blog/README.md b/examples/blog/README.md index 5bc8b3be47f..6c9df3c8698 100644 --- a/examples/blog/README.md +++ b/examples/blog/README.md @@ -15,7 +15,7 @@ To run this project: This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. Congratulations, you're now up and running with Keystone! 🚀 @@ -29,6 +29,6 @@ This example includes sample data. To add it to your database: ## Next steps -Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the GraphQL Playground. +Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the Apollo Sandbox. When you’ve got the hang of this base project, try a [feature project](../) to learn Keystone’s advanced features and take your knowledge to the next level. diff --git a/examples/custom-admin-ui-logo/README.md b/examples/custom-admin-ui-logo/README.md index 1b5a0f890fd..960e4975649 100644 --- a/examples/custom-admin-ui-logo/README.md +++ b/examples/custom-admin-ui-logo/README.md @@ -14,7 +14,7 @@ This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. 🚀 Congratulations, you're now up and running with Keystone! diff --git a/examples/custom-admin-ui-navigation/README.md b/examples/custom-admin-ui-navigation/README.md index 8fc2df99a31..4c1f341e6d5 100644 --- a/examples/custom-admin-ui-navigation/README.md +++ b/examples/custom-admin-ui-navigation/README.md @@ -14,7 +14,7 @@ This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## admin/config.ts diff --git a/examples/custom-admin-ui-pages/README.md b/examples/custom-admin-ui-pages/README.md index 59b084aba29..2e1129bc6a1 100644 --- a/examples/custom-admin-ui-pages/README.md +++ b/examples/custom-admin-ui-pages/README.md @@ -15,7 +15,7 @@ This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. 🚀 Congratulations, you're now up and running with Keystone! diff --git a/examples/custom-field-view/README.md b/examples/custom-field-view/README.md index 949ff379372..8c474d71a23 100644 --- a/examples/custom-field-view/README.md +++ b/examples/custom-field-view/README.md @@ -14,7 +14,7 @@ This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Features diff --git a/examples/custom-field/README.md b/examples/custom-field/README.md index d1444fd1f89..dc8bca709a5 100644 --- a/examples/custom-field/README.md +++ b/examples/custom-field/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Stars field diff --git a/examples/default-values/README.md b/examples/default-values/README.md index 898bd5f1fac..e2bfd794b3c 100644 --- a/examples/default-values/README.md +++ b/examples/default-values/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Features diff --git a/examples/document-field/README.md b/examples/document-field/README.md index eff2df758ad..c8aae1448f2 100644 --- a/examples/document-field/README.md +++ b/examples/document-field/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. In a separate terminal, start the frontend dev server: diff --git a/examples/extend-graphql-schema/README.md b/examples/extend-graphql-schema/README.md index 5047e37b0d4..556d70b5a67 100644 --- a/examples/extend-graphql-schema/README.md +++ b/examples/extend-graphql-schema/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Features diff --git a/examples/json/README.md b/examples/json/README.md index ccf98d19621..22feef57fb2 100644 --- a/examples/json/README.md +++ b/examples/json/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. 🚀 Congratulations, you're now up and running with Keystone! diff --git a/examples/task-manager/README.md b/examples/task-manager/README.md index 87431499f2d..228dcad1989 100644 --- a/examples/task-manager/README.md +++ b/examples/task-manager/README.md @@ -14,7 +14,7 @@ To run this project: This will start Keystone’s Admin UI at [localhost:3000](http://localhost:3000), where you can add items to an empty database. -You can also access Keystone’s GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql) to explore the GraphQL API, and run [queries](https://keystonejs.com/docs/guides/filters) and [mutations](https://keystonejs.com/docs/apis/graphql#mutations) on your data. +You can also access Keystone’s Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql) to explore the GraphQL API, and run [queries](https://keystonejs.com/docs/guides/filters) and [mutations](https://keystonejs.com/docs/apis/graphql#mutations) on your data. Congratulations, you’re now up and running with Keystone! 🚀 @@ -28,6 +28,6 @@ This example includes sample data. To add it to your database: ## Next steps -Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the GraphQL Playground. +Experiment with the code in this example to see how Keystone works, familiarise yourself with the Admin UI, and learn about the Apollo Sandbox. When you’ve got the hang of this base project, try a [feature project](../) to learn Keystone’s advanced features and take your knowledge to the next level. diff --git a/examples/testing/README.md b/examples/testing/README.md index 3550968aa0e..74680023591 100644 --- a/examples/testing/README.md +++ b/examples/testing/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Features diff --git a/examples/virtual-field/README.md b/examples/virtual-field/README.md index 713748da176..c195ac2888f 100644 --- a/examples/virtual-field/README.md +++ b/examples/virtual-field/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Features diff --git a/examples/with-auth/README.md b/examples/with-auth/README.md index 8e922b9e6fa..b396f528bd1 100644 --- a/examples/with-auth/README.md +++ b/examples/with-auth/README.md @@ -14,7 +14,7 @@ yarn dev This will start the Admin UI at [localhost:3000](http://localhost:3000). You can use the Admin UI to create items in your database. -You can also access a GraphQL Playground at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. +You can also access a Apollo Sandbox at [localhost:3000/api/graphql](http://localhost:3000/api/graphql), which allows you to directly run GraphQL queries and mutations. ## Features diff --git a/packages/keystone/package.json b/packages/keystone/package.json index dfd693dd1d6..8f24f933273 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -71,10 +71,10 @@ "@types/supertest": "^2.0.11", "@types/uid-safe": "^2.1.2", "@types/uuid": "^8.3.1", - "apollo-server-errors": "^2.5.0", - "apollo-server-express": "^2.25.2", - "apollo-server-micro": "^2.25.2", - "apollo-server-types": "^0.9.0", + "apollo-server-errors": "^3.1.0", + "apollo-server-express": "^3.3.0", + "apollo-server-micro": "^3.3.0", + "apollo-server-types": "^3.2.0", "apollo-upload-client": "^16.0.0", "bcryptjs": "^2.4.3", "bytes": "^3.1.0", @@ -103,6 +103,7 @@ "intersection-observer": "^0.12.0", "memoize-one": "^5.2.1", "meow": "^9.0.0", + "micro": "^9.3.2", "next": "^11.1.0", "node-fetch": "^2.6.1", "object-hash": "^2.2.0", diff --git a/packages/keystone/src/lib/core/queries/output-field.ts b/packages/keystone/src/lib/core/queries/output-field.ts index abf80ee1a2d..e692aaac007 100644 --- a/packages/keystone/src/lib/core/queries/output-field.ts +++ b/packages/keystone/src/lib/core/queries/output-field.ts @@ -1,7 +1,7 @@ +import { CacheHint } from 'apollo-server-types'; import { GraphQLResolveInfo } from 'graphql'; import { NextFieldType, - CacheHint, IndividualFieldAccessControl, BaseGeneratedListTypes, ItemRootValue, @@ -128,7 +128,7 @@ export function outputTypeField( // Only static cache hints are supported at the field level until a use-case makes it clear what parameters a dynamic hint would take if (cacheHint && info && info.cacheControl) { - info.cacheControl.setCacheHint(cacheHint as any); + info.cacheControl.setCacheHint(cacheHint); } const value = getValueForDBField(rootVal, dbField, id, fieldKey, context, lists, info); diff --git a/packages/keystone/src/lib/core/types-for-lists.ts b/packages/keystone/src/lib/core/types-for-lists.ts index b8f84decaa5..fcaeb986be2 100644 --- a/packages/keystone/src/lib/core/types-for-lists.ts +++ b/packages/keystone/src/lib/core/types-for-lists.ts @@ -1,10 +1,10 @@ +import { CacheHint } from 'apollo-server-types'; import { graphql, ItemRootValue, TypesForList, getGqlNames, NextFieldType, - CacheHint, BaseGeneratedListTypes, ListInfo, ListHooks, diff --git a/packages/keystone/src/lib/server/createApolloServer.ts b/packages/keystone/src/lib/server/createApolloServer.ts index 0948635c80d..c4852c42cff 100644 --- a/packages/keystone/src/lib/server/createApolloServer.ts +++ b/packages/keystone/src/lib/server/createApolloServer.ts @@ -2,7 +2,6 @@ import type { IncomingMessage, ServerResponse } from 'http'; import { GraphQLError, GraphQLSchema } from 'graphql'; import { ApolloServer as ApolloServerMicro } from 'apollo-server-micro'; import { ApolloServer as ApolloServerExpress } from 'apollo-server-express'; -import type { Config } from 'apollo-server-express'; import type { CreateContext, GraphQLConfig, SessionStrategy } from '../../types'; import { createSessionContext } from '../../session'; @@ -61,71 +60,13 @@ const _createApolloServerConfig = ({ graphQLSchema: GraphQLSchema; graphqlConfig?: GraphQLConfig; }) => { - // Playground config const apolloConfig = graphqlConfig?.apolloConfig; - const apolloConfigPlayground = apolloConfig?.playground; - let playground: Config['playground']; - const settings = { 'request.credentials': 'same-origin' }; - - if (typeof apolloConfigPlayground === 'boolean' && !apolloConfigPlayground) { - // graphql.apolloConfig.playground === false (playground not accessible in all cases) - playground = false; - } else if (typeof apolloConfigPlayground === 'boolean') { - // graphql.apolloConfig.playground === true (playground accessible in all cases) - playground = { settings }; - } else if (apolloConfigPlayground) { - // graphql.apolloConfig.playground === { settings: ... } (playground accessible in all cases with further customisation - https://www.apollographql.com/docs/apollo-server/testing/graphql-playground) - playground = { - ...apolloConfigPlayground, - settings: { ...settings, ...apolloConfigPlayground.settings }, - }; - } else if (process.env.NODE_ENV === 'production') { - // process.env.NODE_ENV === 'production' (playground not accessible in production) - playground = undefined; - } else { - // not specified at all (playground uses defaults) - playground = { settings }; - } - - const apolloConfigIntrospection = apolloConfig?.introspection; - let introspection: Config['introspection']; - - if (typeof apolloConfigIntrospection === 'boolean' && !apolloConfigIntrospection) { - // graphql.apolloConfig.introspection === false (introspection not accessible in all cases) - introspection = false; - } else if (typeof apolloConfigIntrospection === 'boolean') { - // graphql.apolloConfig.introspection === true (introspection accessible in all cases) - introspection = true; - } else if (process.env.NODE_ENV === 'production') { - // process.env.NODE_ENV === 'production' (introspection not accessible in production) - introspection = undefined; - } else if ((typeof playground === 'boolean' && playground) || typeof playground === 'object') { - // not specified at all (introspection enabled if playground is enabled or defined) - introspection = true; - } return { - uploads: false, schema: graphQLSchema, debug: graphqlConfig?.debug, // If undefined, use Apollo default of NODE_ENV !== 'production' - // FIXME: support for apollo studio tracing - // ...(process.env.ENGINE_API_KEY || process.env.APOLLO_KEY - // ? { tracing: true } - // : { - // engine: false, - // // Only enable tracing in dev mode so we can get local debug info, but - // // don't bother returning that info on prod when the `engine` is - // // disabled. - // tracing: dev, - // }), ...apolloConfig, formatError: formatError(graphqlConfig), - // Carefully inject the playground and introspection variables - playground, - introspection, - // FIXME: Support for file handling configuration - // maxFileSize: 200 * 1024 * 1024, - // maxFiles: 5, }; }; diff --git a/packages/keystone/src/lib/server/createExpressServer.ts b/packages/keystone/src/lib/server/createExpressServer.ts index dc4e6e6de83..fdbe55606a3 100644 --- a/packages/keystone/src/lib/server/createExpressServer.ts +++ b/packages/keystone/src/lib/server/createExpressServer.ts @@ -16,7 +16,7 @@ so the CLI can bring up the dev server early to handle GraphQL requests. const DEFAULT_MAX_FILE_SIZE = 200 * 1024 * 1024; // 200 MiB -const addApolloServer = ({ +const addApolloServer = async ({ server, config, graphQLSchema, @@ -40,10 +40,15 @@ const addApolloServer = ({ const maxFileSize = config.server?.maxFileSize || DEFAULT_MAX_FILE_SIZE; server.use(graphqlUploadExpress({ maxFileSize })); + await apolloServer.start(); apolloServer.applyMiddleware({ app: server, path: config.graphql?.path || '/api/graphql', - cors: false, + cors: + config.graphql?.cors || + (process.env.NODE_ENV !== 'production' + ? { origin: 'https://studio.apollographql.com', credentials: true } + : undefined), }); }; @@ -70,7 +75,7 @@ export const createExpressServer = async ( config.server?.extendExpressApp(server); } - addApolloServer({ + await addApolloServer({ server, config, graphQLSchema, diff --git a/packages/keystone/src/types/config/fields.ts b/packages/keystone/src/types/config/fields.ts index 27235b0afb2..154e1fdf1b7 100644 --- a/packages/keystone/src/types/config/fields.ts +++ b/packages/keystone/src/types/config/fields.ts @@ -1,4 +1,4 @@ -import type { CacheHint } from '../next-fields'; +import { CacheHint } from 'apollo-server-types'; import { FieldTypeFunc } from '../next-fields'; import type { BaseGeneratedListTypes } from '../utils'; import { MaybeItemFunction, MaybeSessionFunction } from './lists'; diff --git a/packages/keystone/src/types/config/index.ts b/packages/keystone/src/types/config/index.ts index 653a4c34db3..3607521cbbb 100644 --- a/packages/keystone/src/types/config/index.ts +++ b/packages/keystone/src/types/config/index.ts @@ -47,14 +47,7 @@ export type KeystoneConfig = { // config.lists -export type { - ListSchemaConfig, - ListConfig, - BaseFields, - MaybeSessionFunction, - MaybeItemFunction, - // CacheHint, -}; +export type { ListSchemaConfig, ListConfig, BaseFields, MaybeSessionFunction, MaybeItemFunction }; // config.db @@ -141,6 +134,9 @@ export type ServerConfig = { export type GraphQLConfig = { // The path of the GraphQL API endpoint. Default: '/api/graphql'. path?: string; + // The CORS configuration to use on the GraphQL API endpoint. + // Default: { origin: 'https://studio.apollographql.com', credentials: true } + cors?: CorsOptions; queryLimits?: { maxTotalResults?: number; }; diff --git a/packages/keystone/src/types/config/lists.ts b/packages/keystone/src/types/config/lists.ts index 2f008f53b7c..fc144bf6066 100644 --- a/packages/keystone/src/types/config/lists.ts +++ b/packages/keystone/src/types/config/lists.ts @@ -1,4 +1,4 @@ -import type { CacheHint } from '../next-fields'; +import type { CacheHint } from 'apollo-server-types'; import type { BaseGeneratedListTypes, MaybePromise } from '../utils'; import type { ListHooks } from './hooks'; import type { ListAccessControl } from './access-control'; diff --git a/packages/keystone/src/types/next-fields.ts b/packages/keystone/src/types/next-fields.ts index 1ac5bd3d156..74f224de6d5 100644 --- a/packages/keystone/src/types/next-fields.ts +++ b/packages/keystone/src/types/next-fields.ts @@ -7,17 +7,6 @@ import { AdminMetaRootVal, JSONValue, KeystoneContext, MaybePromise } from '.'; export { Decimal }; -// CacheScope and CacheHint are sort of duplicated from apollo-cache-control -// because they use an enum which means TS users have to import the CacheScope enum from apollo-cache-control which isn't great -// so we have a copy of it but using a union of string literals instead of an enum -// (note people importing the enum from apollo-cache-control will still be able to use it because you can use enums as their literal values but not the opposite) -export type CacheScope = 'PUBLIC' | 'PRIVATE'; - -export type CacheHint = { - maxAge?: number; - scope?: CacheScope; -}; - export type ItemRootValue = { id: { toString(): string }; [key: string]: unknown }; export type MaybeFunction = Ret | ((...params: Params) => Ret); diff --git a/prisma-utils/CHANGELOG.md b/prisma-utils/CHANGELOG.md index de36ab67f94..6f60df7bd18 100644 --- a/prisma-utils/CHANGELOG.md +++ b/prisma-utils/CHANGELOG.md @@ -1,8 +1,7 @@ # @keystone-next/prisma-utils ## 0.0.1 -### Patch Changes - +### Patch Changes - [#6433](https://github.com/keystonejs/keystone/pull/6433) [`bb0c6c626`](https://github.com/keystonejs/keystone/commit/bb0c6c62610eda20ae93a6b67185276bdbba3248) Thanks [@renovate](https://github.com/apps/renovate)! - Updated Prisma dependencies to `2.30.2`. diff --git a/tests/api-tests/package.json b/tests/api-tests/package.json index aa8d721b7c6..996368f5c04 100644 --- a/tests/api-tests/package.json +++ b/tests/api-tests/package.json @@ -15,6 +15,7 @@ "@keystone-next/auth": "*", "@keystone-next/fields-document": "*", "@keystone-next/keystone": "*", + "apollo-server-types": "^3.2.0", "cookie-signature": "^1.1.0", "cuid": "^2.1.8", "globby": "^11.0.4", @@ -26,7 +27,6 @@ "uuid": "^8.3.2" }, "dependencies": { - "apollo-cache-control": "^0.14.0", "express": "^4.17.1" } } diff --git a/tests/api-tests/queries/cache-hints.test.ts b/tests/api-tests/queries/cache-hints.test.ts index f9256868995..23ebd2ba93c 100644 --- a/tests/api-tests/queries/cache-hints.test.ts +++ b/tests/api-tests/queries/cache-hints.test.ts @@ -1,4 +1,4 @@ -import { CacheScope } from 'apollo-cache-control'; +import { CacheScope } from 'apollo-server-types'; import { text, relationship, integer } from '@keystone-next/keystone/fields'; import { list, createSchema, graphQLSchemaExtension } from '@keystone-next/keystone'; import { KeystoneContext } from '@keystone-next/keystone/types'; diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index ebbe6bd6007..8f2657ed107 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -136,7 +136,7 @@ export const expectExtensionError = ( extensions: { code: 'INTERNAL_SERVER_ERROR', ...(expectException - ? { exception: { debug, stacktrace: expect.arrayContaining(stacktrace) } } + ? { exception: { stacktrace: expect.arrayContaining(stacktrace) } } : {}), ...(expectDebug ? { debug } : {}), }, @@ -156,7 +156,6 @@ export const expectPrismaError = ( args.map(({ path, message, code, target }) => ({ extensions: { code: 'INTERNAL_SERVER_ERROR', - exception: { prisma: { clientVersion: '2.30.2', code, meta: { target } } }, prisma: { clientVersion: '2.30.2', code, meta: { target } }, }, path, diff --git a/yarn.lock b/yarn.lock index ce366e04a22..fcbd929178d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,31 +39,18 @@ "@types/node" "^10.1.0" long "^4.0.0" -"@apollographql/apollo-tools@^0.5.0": +"@apollographql/apollo-tools@^0.5.1": version "0.5.1" resolved "https://registry.yarnpkg.com/@apollographql/apollo-tools/-/apollo-tools-0.5.1.tgz#f0baef739ff7e2fafcb8b98ad29f6ac817e53e32" integrity sha512-ZII+/xUFfb9ezDU2gad114+zScxVFMVlZ91f8fGApMzlS1kkqoyLnC4AJaQ1Ya/X+b63I20B4Gd+eCL8QuB4sA== -"@apollographql/graphql-playground-html@1.6.27": - version "1.6.27" - resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.27.tgz#bc9ab60e9445aa2a8813b4e94f152fa72b756335" - integrity sha512-tea2LweZvn6y6xFV11K0KC8ETjmm52mQrW+ezgB2O/aTQf8JGyFmMcRPFgUaQZeHbWdm8iisDC6EjOKsXu0nfw== +"@apollographql/graphql-playground-html@1.6.29": + version "1.6.29" + resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.29.tgz#a7a646614a255f62e10dcf64a7f68ead41dec453" + integrity sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA== dependencies: xss "^1.0.8" -"@apollographql/graphql-upload-8-fork@^8.1.3": - version "8.1.3" - resolved "https://registry.yarnpkg.com/@apollographql/graphql-upload-8-fork/-/graphql-upload-8-fork-8.1.3.tgz#a0d4e0d5cec8e126d78bd915c264d6b90f5784bc" - integrity sha512-ssOPUT7euLqDXcdVv3Qs4LoL4BPtfermW1IOouaqEmj36TpHYDmYDIbKoSQxikd9vtMumFnP87OybH7sC9fJ6g== - dependencies: - "@types/express" "*" - "@types/fs-capacitor" "*" - "@types/koa" "*" - busboy "^0.3.1" - fs-capacitor "^2.0.4" - http-errors "^1.7.3" - object-path "^0.11.4" - "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -1516,7 +1503,17 @@ "@graphql-tools/utils" "^8.2.2" tslib "~2.3.0" -"@graphql-tools/schema@^8.2.0": +"@graphql-tools/mock@^8.1.2": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.3.0.tgz#779780af477914fa872ed9163b6bf55a57e19edf" + integrity sha512-+at9bTfuP60bTFpcMRJ9/KWwJ1E3A+NUVM+15NEp2uHQk4E2l2OO3hnZ4P3JKtMoQY15a/xUVLByC7RqMb7PnA== + dependencies: + "@graphql-tools/schema" "^8.2.0" + "@graphql-tools/utils" "^8.2.0" + fast-json-stable-stringify "^2.1.0" + tslib "~2.3.0" + +"@graphql-tools/schema@^8.0.0", "@graphql-tools/schema@^8.2.0": version "8.2.0" resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.2.0.tgz#ae75cbb2df6cee9ed6d89fce56be467ab23758dc" integrity sha512-ufmI5mJQa8NJczzfkh0pUttKvspqDcT5LLakA3jUmOrrE4d4NVj6onZlazdTzF5sAepSNqanFnwhrxZpCAJMKg== @@ -1526,7 +1523,7 @@ tslib "~2.3.0" value-or-promise "1.0.10" -"@graphql-tools/utils@^8.2.0", "@graphql-tools/utils@^8.2.2": +"@graphql-tools/utils@^8.0.0", "@graphql-tools/utils@^8.2.0", "@graphql-tools/utils@^8.2.2": version "8.2.2" resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.2.2.tgz#d29420bf1003d2876cb30f373145be432c7f7c4b" integrity sha512-29FFY5U4lpXuBiW9dRvuWnBVwGhWbGLa2leZcAMU/Pz47Cr/QLZGVgpLBV9rt+Gbs7wyIJM7t7EuksPs0RDm3g== @@ -1545,7 +1542,7 @@ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.0.tgz#0eee6373e11418bfe0b5638f654df7a4ca6a3950" integrity sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg== -"@hapi/accept@5.0.2": +"@hapi/accept@5.0.2", "@hapi/accept@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@hapi/accept/-/accept-5.0.2.tgz#ab7043b037e68b722f93f376afb05e85c0699523" integrity sha512-CmzBx/bXUR8451fnZRuZAJRlzgm0Jgu5dltTX/bszmR2lheb9BpyN47Q1RbaGTsvFzn0PXAEs+lXDKfshccYZw== @@ -2594,7 +2591,7 @@ resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ== -"@types/body-parser@*": +"@types/body-parser@*", "@types/body-parser@1.19.1": version "1.19.1" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg== @@ -2602,14 +2599,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/body-parser@1.19.0": - version "1.19.0" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" - integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== - dependencies: - "@types/connect" "*" - "@types/node" "*" - "@types/bytes@^3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@types/bytes/-/bytes-3.1.1.tgz#67a876422e660dc4c10a27f3e5bcfbd5455f01d0" @@ -2647,10 +2636,10 @@ "@types/keygrip" "*" "@types/node" "*" -"@types/cors@2.8.10": - version "2.8.10" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.10.tgz#61cc8469849e5bcdd0c7044122265c39cec10cf4" - integrity sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ== +"@types/cors@2.8.12": + version "2.8.12" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" + integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== "@types/cross-spawn@6.0.2": version "6.0.2" @@ -2681,7 +2670,7 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.21": +"@types/express-serve-static-core@4.17.24", "@types/express-serve-static-core@^4.17.18": version "4.17.24" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA== @@ -2690,7 +2679,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*", "@types/express@^4.17.12", "@types/express@^4.17.13": +"@types/express@*", "@types/express@4.17.13", "@types/express@^4.17.13": version "4.17.13" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== @@ -3127,13 +3116,6 @@ "@types/unist" "*" "@types/vfile-message" "*" -"@types/ws@^7.0.0": - version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - "@types/yargs-parser@*": version "20.2.1" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" @@ -3280,13 +3262,6 @@ dependencies: tslib "^2.3.0" -"@wry/equality@^0.1.2": - version "0.1.11" - resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" - integrity sha512-mwEVBDUVODlsQQ5dfuLUS5/Tf7jqUKyhKYHmVi4fPB6bDMOfWvUPJmKgS1Z7Za/sOI3vzWt4+O7yCiL/70MogA== - dependencies: - tslib "^1.9.3" - "@wry/equality@^0.5.0": version "0.5.2" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" @@ -3306,14 +3281,6 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== -accept@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/accept/-/accept-3.1.3.tgz#29c3e2b3a8f4eedbc2b690e472b9ebbdc7385e87" - integrity sha512-OgOEAidVEOKPup+Gv2+2wdH2AgVKI9LxsJ4hicdJ6cY0faUuZdZoi56kkXWlHp9qicN1nWQLmW5ZRGk+SBS5xg== - dependencies: - boom "7.x.x" - hoek "6.x.x" - accepts@^1.3.5, accepts@~1.3.7: version "1.3.7" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" @@ -3481,21 +3448,13 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -apollo-cache-control@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.14.0.tgz#95f20c3e03e7994e0d1bd48c59aeaeb575ed0ce7" - integrity sha512-qN4BCq90egQrgNnTRMUHikLZZAprf3gbm8rC5Vwmc6ZdLolQ7bFsa769Hqi6Tq/lS31KLsXBLTOsRbfPHph12w== - dependencies: - apollo-server-env "^3.1.0" - apollo-server-plugin-base "^0.13.0" - -apollo-datasource@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-0.9.0.tgz#b0b2913257a6103a5f4c03cb56d78a30e9d850db" - integrity sha512-y8H99NExU1Sk4TvcaUxTdzfq2SZo6uSj5dyh75XSQvbpH6gdAXIW9MaBcvlNC7n0cVPsidHmOcHOWxJ/pTXGjA== +apollo-datasource@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/apollo-datasource/-/apollo-datasource-3.1.0.tgz#44153cb99c7602f4524397ebc8f13e486a010c09" + integrity sha512-ywcVjuWNo84eMB9uBOYygQI+00+Ne4ShyPIxJzT//sn1j1Fu3J+KStMNd6s1jyERWgjGZzxkiLn6nLmwsGymBg== dependencies: - apollo-server-caching "^0.7.0" - apollo-server-env "^3.1.0" + apollo-server-caching "^3.1.0" + apollo-server-env "^4.0.3" apollo-graphql@^0.9.0: version "0.9.3" @@ -3506,131 +3465,101 @@ apollo-graphql@^0.9.0: lodash.sortby "^4.7.0" sha.js "^2.4.11" -apollo-link@^1.2.14: - version "1.2.14" - resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.14.tgz#3feda4b47f9ebba7f4160bef8b977ba725b684d9" - integrity sha512-p67CMEFP7kOG1JZ0ZkYZwRDa369w5PIjtMjvrQd/HnIV8FRsHRqLqK+oAZQnFa1DDdZtOtHTi+aMIW6EatC2jg== - dependencies: - apollo-utilities "^1.3.0" - ts-invariant "^0.4.0" - tslib "^1.9.3" - zen-observable-ts "^0.8.21" - -apollo-reporting-protobuf@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-0.8.0.tgz#ae9d967934d3d8ed816fc85a0d8068ef45c371b9" - integrity sha512-B3XmnkH6Y458iV6OsA7AhfwvTgeZnFq9nPVjbxmLKnvfkEl8hYADtz724uPa0WeBiD7DSFcnLtqg9yGmCkBohg== +apollo-reporting-protobuf@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/apollo-reporting-protobuf/-/apollo-reporting-protobuf-3.0.0.tgz#a53966b76a3f373d9336bc953f0bc6dede487270" + integrity sha512-jmCD+6gECt8KS7PxP460hztT/5URTbv2Kg0zgnR6iWPGce88IBmSUjcqf1Z6wJJq7Teb8Hu7WbyyMhn0vN5TxQ== dependencies: "@apollo/protobufjs" "1.2.2" -apollo-server-caching@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-0.7.0.tgz#e6d1e68e3bb571cba63a61f60b434fb771c6ff39" - integrity sha512-MsVCuf/2FxuTFVhGLK13B+TZH9tBd2qkyoXKKILIiGcZ5CDUEBO14vIV63aNkMkS1xxvK2U4wBcuuNj/VH2Mkw== +apollo-server-caching@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/apollo-server-caching/-/apollo-server-caching-3.1.0.tgz#c68f2159ad8a25a0bdbb18ad6bdbbde59cd4647d" + integrity sha512-bZ4bo0kSAsax9LbMQPlpuMTkQ657idF2ehOYe4Iw+8vj7vfAYa39Ii9IlaVAFMC1FxCYzLNFz+leZBm/Stn/NA== dependencies: lru-cache "^6.0.0" -apollo-server-core@^2.25.2: - version "2.25.2" - resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-2.25.2.tgz#ff65da5e512d9b5ca54c8e5e8c78ee28b5987247" - integrity sha512-lrohEjde2TmmDTO7FlOs8x5QQbAS0Sd3/t0TaK2TWaodfzi92QAvIsq321Mol6p6oEqmjm8POIDHW1EuJd7XMA== - dependencies: - "@apollographql/apollo-tools" "^0.5.0" - "@apollographql/graphql-playground-html" "1.6.27" - "@apollographql/graphql-upload-8-fork" "^8.1.3" +apollo-server-core@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-3.3.0.tgz#f973c6f755884f8e17452cb9022672ae6f0ed9e7" + integrity sha512-KmkzKVG3yjybouDyUX6Melv39u1EOFipvAKP17IlPis/TjVbubJmb6hkE0am/g2RipyhRvlpxAjHqPaCTXR1dQ== + dependencies: + "@apollographql/apollo-tools" "^0.5.1" + "@apollographql/graphql-playground-html" "1.6.29" + "@graphql-tools/mock" "^8.1.2" + "@graphql-tools/schema" "^8.0.0" + "@graphql-tools/utils" "^8.0.0" "@josephg/resolvable" "^1.0.0" - "@types/ws" "^7.0.0" - apollo-cache-control "^0.14.0" - apollo-datasource "^0.9.0" + apollo-datasource "^3.1.0" apollo-graphql "^0.9.0" - apollo-reporting-protobuf "^0.8.0" - apollo-server-caching "^0.7.0" - apollo-server-env "^3.1.0" - apollo-server-errors "^2.5.0" - apollo-server-plugin-base "^0.13.0" - apollo-server-types "^0.9.0" - apollo-tracing "^0.15.0" + apollo-reporting-protobuf "^3.0.0" + apollo-server-caching "^3.1.0" + apollo-server-env "^4.0.3" + apollo-server-errors "^3.1.0" + apollo-server-plugin-base "^3.2.0" + apollo-server-types "^3.2.0" async-retry "^1.2.1" - fast-json-stable-stringify "^2.0.0" - graphql-extensions "^0.15.0" + fast-json-stable-stringify "^2.1.0" graphql-tag "^2.11.0" - graphql-tools "^4.0.8" - loglevel "^1.6.7" + loglevel "^1.6.8" lru-cache "^6.0.0" sha.js "^2.4.11" - subscriptions-transport-ws "^0.9.19" uuid "^8.0.0" -apollo-server-env@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-3.1.0.tgz#0733c2ef50aea596cc90cf40a53f6ea2ad402cd0" - integrity sha512-iGdZgEOAuVop3vb0F2J3+kaBVi4caMoxefHosxmgzAbbSpvWehB8Y1QiSyyMeouYC38XNVk5wnZl+jdGSsWsIQ== +apollo-server-env@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/apollo-server-env/-/apollo-server-env-4.0.3.tgz#082a5c1dd4dfb3b34de5e1fa7dc170dd15a5062f" + integrity sha512-B32+RUOM4GUJAwnQqQE1mT1BG7+VfW3a0A87Bp3gv/q8iNnhY2BIWe74Qn03pX8n27g3EGVCt0kcBuHhjG5ltA== dependencies: node-fetch "^2.6.1" - util.promisify "^1.0.0" -apollo-server-errors@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-2.5.0.tgz#5d1024117c7496a2979e3e34908b5685fe112b68" - integrity sha512-lO5oTjgiC3vlVg2RKr3RiXIIQ5pGXBFxYGGUkKDhTud3jMIhs+gel8L8zsEjKaKxkjHhCQAA/bcEfYiKkGQIvA== +apollo-server-errors@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/apollo-server-errors/-/apollo-server-errors-3.1.0.tgz#0b890dc7ae36a1f0ca4841d353e8d1c3c6524ee2" + integrity sha512-bUmobPEvtcBFt+OVHYqD390gacX/Cm5s5OI5gNZho8mYKAA6OjgnRlkm/Lti6NzniXVxEQyD5vjkC6Ox30mGFg== -apollo-server-express@^2.25.2: - version "2.25.2" - resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-2.25.2.tgz#58cd819694ff4c2dec6945a95c5dff6aa2719ef6" - integrity sha512-A2gF2e85vvDugPlajbhr0A14cDFDIGX0mteNOJ8P3Z3cIM0D4hwrWxJidI+SzobefDIyIHu1dynFedJVhV0euQ== +apollo-server-express@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-3.3.0.tgz#23ec8b102a4758548c1416fb4770334e814ffb12" + integrity sha512-qJedh77IxbfT+HpYsDraC2CGdy08wiWTwoKYXjRK4S/DHbe94A4957/1blw4boYO4n44xRKQd1k6zxiixCp+XQ== dependencies: - "@apollographql/graphql-playground-html" "1.6.27" "@types/accepts" "^1.3.5" - "@types/body-parser" "1.19.0" - "@types/cors" "2.8.10" - "@types/express" "^4.17.12" - "@types/express-serve-static-core" "^4.17.21" + "@types/body-parser" "1.19.1" + "@types/cors" "2.8.12" + "@types/express" "4.17.13" + "@types/express-serve-static-core" "4.17.24" accepts "^1.3.5" - apollo-server-core "^2.25.2" - apollo-server-types "^0.9.0" - body-parser "^1.18.3" + apollo-server-core "^3.3.0" + apollo-server-types "^3.2.0" + body-parser "^1.19.0" cors "^2.8.5" - express "^4.17.1" - graphql-subscriptions "^1.0.0" - graphql-tools "^4.0.8" - parseurl "^1.3.2" - subscriptions-transport-ws "^0.9.19" - type-is "^1.6.16" - -apollo-server-micro@^2.25.2: - version "2.25.2" - resolved "https://registry.yarnpkg.com/apollo-server-micro/-/apollo-server-micro-2.25.2.tgz#4882a886417ba260abb28aa18a44e9f0490df9e7" - integrity sha512-TaYHe82Nki4dOxpIEbWi1cNkTvm2JBQX7biluXOTjSyKXrT8/URec4rJrbwOyF56KQ7Td96gkUDJZHBYZ49Vzg== - dependencies: - "@apollographql/graphql-playground-html" "1.6.27" - accept "^3.0.2" - apollo-server-core "^2.25.2" - apollo-server-types "^0.9.0" - micro "^9.3.2" - -apollo-server-plugin-base@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-0.13.0.tgz#3f85751a420d3c4625355b6cb3fbdd2acbe71f13" - integrity sha512-L3TMmq2YE6BU6I4Tmgygmd0W55L+6XfD9137k+cWEBFu50vRY4Re+d+fL5WuPkk5xSPKd/PIaqzidu5V/zz8Kg== - dependencies: - apollo-server-types "^0.9.0" - -apollo-server-types@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-0.9.0.tgz#ccf550b33b07c48c72f104fbe2876232b404848b" - integrity sha512-qk9tg4Imwpk732JJHBkhW0jzfG0nFsLqK2DY6UhvJf7jLnRePYsPxWfPiNkxni27pLE2tiNlCwoDFSeWqpZyBg== - dependencies: - apollo-reporting-protobuf "^0.8.0" - apollo-server-caching "^0.7.0" - apollo-server-env "^3.1.0" - -apollo-tracing@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.15.0.tgz#237fbbbf669aee4370b7e9081b685eabaa8ce84a" - integrity sha512-UP0fztFvaZPHDhIB/J+qGuy6hWO4If069MGC98qVs0I8FICIGu4/8ykpX3X3K6RtaQ56EDAWKykCxFv4ScxMeA== - dependencies: - apollo-server-env "^3.1.0" - apollo-server-plugin-base "^0.13.0" + parseurl "^1.3.3" + +apollo-server-micro@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/apollo-server-micro/-/apollo-server-micro-3.3.0.tgz#02aeed4e130f418d896371bb120c51c399c1e27d" + integrity sha512-PTyTgre87Yh89fwml9pCdac60vlmByLYaUqdGtZMG8Z6GQ4tGMo7cUYPMK+FbNFr8/27oOxK8CvEAF3ogAYlCw== + dependencies: + "@hapi/accept" "^5.0.2" + apollo-server-core "^3.3.0" + apollo-server-types "^3.2.0" + type-is "^1.6.18" + +apollo-server-plugin-base@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/apollo-server-plugin-base/-/apollo-server-plugin-base-3.2.0.tgz#415337a0b1b88fc1d5f5620130a51e2935dd8dbf" + integrity sha512-anjyiw79wxU4Cj2bYZFWQqZPjuaZ4mVJvxCoyvkFrNvjPua9dovCOfpng43C5NwdsqJpz78Vqs236eFM2QoeaA== + dependencies: + apollo-server-types "^3.2.0" + +apollo-server-types@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/apollo-server-types/-/apollo-server-types-3.2.0.tgz#6243b34d35fbb09ded2cc84bf7e5f59968ccfa21" + integrity sha512-Fh7QP84ufDZHbLzoLyyxyzznlW8cpgEZYYkGsS1i36zY4VaAt5OUOp1f+FxWdLGehq0Arwb6D1W7y712IoZ/JQ== + dependencies: + apollo-reporting-protobuf "^3.0.0" + apollo-server-caching "^3.1.0" + apollo-server-env "^4.0.3" apollo-upload-client@^16.0.0: version "16.0.0" @@ -3639,16 +3568,6 @@ apollo-upload-client@^16.0.0: dependencies: extract-files "^11.0.0" -apollo-utilities@^1.0.1, apollo-utilities@^1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.3.4.tgz#6129e438e8be201b6c55b0f13ce49d2c7175c9cf" - integrity sha512-pk2hiWrCXMAy2fRPwEyhvka+mqwzeP60Jr1tRYi5xru+3ko94HI9o6lK0CT33/w4RDlxWchmdhDCrvdr+pHCig== - dependencies: - "@wry/equality" "^0.1.2" - fast-json-stable-stringify "^2.0.0" - ts-invariant "^0.4.0" - tslib "^1.10.0" - apply-ref@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/apply-ref/-/apply-ref-1.0.0.tgz#036947786ec24f64c92e905b56d6ffec2fa81951" @@ -4036,11 +3955,6 @@ babel-preset-jest@^27.0.6: babel-plugin-jest-hoist "^27.0.6" babel-preset-current-node-syntax "^1.0.0" -backo2@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" - integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= - bail@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" @@ -4139,7 +4053,7 @@ bn.js@^5.0.0, bn.js@^5.1.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== -body-parser@1.19.0, body-parser@^1.18.3: +body-parser@1.19.0, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== @@ -4160,13 +4074,6 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -boom@7.x.x: - version "7.3.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-7.3.0.tgz#733a6d956d33b0b1999da3fe6c12996950d017b9" - integrity sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A== - dependencies: - hoek "6.x.x" - boxen@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" @@ -5546,11 +5453,6 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -deprecated-decorator@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" - integrity sha1-AJZjF7ehL+kvPMgx91g68ym4bDc= - des.js@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" @@ -6152,11 +6054,6 @@ eventemitter2@^6.4.2: resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.4.tgz#aa96e8275c4dbeb017a5d0e03780c65612a1202b" integrity sha512-HLU3NDY6wARrLCEwyGKRBvuWYyvW6mHYv72SJJAH3iJN3a6eVUvkjFkcxah1bcTgGVBBrFdIopBJPhCQFMLyXw== -eventemitter3@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - events@^3.0.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -6413,7 +6310,7 @@ fast-glob@^3.1.1, fast-glob@^3.2.4, fast-glob@^3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -6653,13 +6550,6 @@ follow-redirects@^1.14.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.3.tgz#6ada78118d8d24caee595595accdc0ac6abd022e" integrity sha512-3MkHxknWMUtb23apkgz/83fDoe+y+qr0TdgacGIA7bew+QLBo3vdgEN2xEsuXNivpFy4CyDhBBZnNZOtalmenw== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -6739,11 +6629,6 @@ from@~0: resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= -fs-capacitor@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-2.0.4.tgz#5a22e72d40ae5078b4fe64fe4d08c0d3fc88ad3c" - integrity sha512-8S4f4WsCryNw2mJJchi46YgB6CR5Ze+4L1h8ewl9tEpL4SJ3ZO+c/bS4BWhB8bK+O3TMqhuZarTitd0S0eh2pA== - fs-capacitor@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-6.2.0.tgz#fa79ac6576629163cb84561995602d8999afb7f5" @@ -7077,22 +6962,6 @@ grapheme-splitter@^1.0.4: resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== -graphql-extensions@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.15.0.tgz#3f291f9274876b0c289fa4061909a12678bd9817" - integrity sha512-bVddVO8YFJPwuACn+3pgmrEg6I8iBuYLuwvxiE+lcQQ7POotVZxm2rgGw0PvVYmWWf3DT7nTVDZ5ROh/ALp8mA== - dependencies: - "@apollographql/apollo-tools" "^0.5.0" - apollo-server-env "^3.1.0" - apollo-server-types "^0.9.0" - -graphql-subscriptions@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-1.2.1.tgz#2142b2d729661ddf967b7388f7cf1dd4cf2e061d" - integrity sha512-95yD/tKi24q8xYa7Q9rhQN16AYj5wPbrb8tmHGM3WRc9EBmWrG/0kkMl+tQG8wcEuE9ibR4zyOM31p5Sdr2v4g== - dependencies: - iterall "^1.3.0" - graphql-tag@^2.11.0, graphql-tag@^2.12.3, graphql-tag@^2.12.5: version "2.12.5" resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f" @@ -7100,17 +6969,6 @@ graphql-tag@^2.11.0, graphql-tag@^2.12.3, graphql-tag@^2.12.5: dependencies: tslib "^2.1.0" -graphql-tools@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.8.tgz#e7fb9f0d43408fb0878ba66b522ce871bafe9d30" - integrity sha512-MW+ioleBrwhRjalKjYaLQbr+920pHBgy9vM/n47sswtns8+96sRn5M/G+J1eu7IMeKWiN/9p6tmwCHU7552VJg== - dependencies: - apollo-link "^1.2.14" - apollo-utilities "^1.0.1" - deprecated-decorator "^0.1.6" - iterall "^1.1.3" - uuid "^3.1.0" - graphql-type-json@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/graphql-type-json/-/graphql-type-json-0.3.2.tgz#f53a851dbfe07bd1c8157d24150064baab41e115" @@ -7298,11 +7156,6 @@ hmac-drbg@^1.0.1: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoek@6.x.x: - version "6.1.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-6.1.3.tgz#73b7d33952e01fe27a38b0457294b79dd8da242c" - integrity sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ== - hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" @@ -7382,7 +7235,7 @@ http-errors@1.7.3, http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -http-errors@^1.7.3, http-errors@^1.8.0: +http-errors@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.0.tgz#75d1bbe497e1044f51e4ee9e704a62f28d336507" integrity sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A== @@ -7705,7 +7558,7 @@ is-buffer@^2.0.0: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.3: +is-callable@^1.1.4, is-callable@^1.2.3: version "1.2.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== @@ -8153,11 +8006,6 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -iterall@^1.1.3, iterall@^1.2.1, iterall@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - jest-changed-files@^27.1.0: version "27.1.0" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.1.0.tgz#42da6ea00f06274172745729d55f42b60a9dffe0" @@ -9050,7 +8898,7 @@ log-update@^2.3.0: cli-cursor "^2.0.0" wrap-ansi "^3.0.1" -loglevel@^1.6.7: +loglevel@^1.6.8: version "1.7.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== @@ -10112,7 +9960,7 @@ object-keys@~0.4.0: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= -object-path@^0.11.4, object-path@^0.11.5: +object-path@^0.11.5: version "0.11.7" resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.7.tgz#5f211161f34bb395e4b13a5f565b79d933b6f65d" integrity sha512-T4evaK9VfGGQskXBDILcn6F90ZD+WO3OwRFFQ2rmZdUH4vQeDBpiolTpVlPY2yj5xSepyILTjDyM6UvbbdHMZw== @@ -10153,7 +10001,7 @@ object.fromentries@^2.0.4: es-abstract "^1.18.0-next.2" has "^1.0.3" -object.getownpropertydescriptors@^2.1.0, object.getownpropertydescriptors@^2.1.1: +object.getownpropertydescriptors@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== @@ -10477,7 +10325,7 @@ parse5@6.0.1: resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parseurl@^1.3.2, parseurl@~1.3.3: +parseurl@^1.3.3, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== @@ -12478,17 +12326,6 @@ stylis@^4.0.3: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.10.tgz#446512d1097197ab3f02fb3c258358c3f7a14240" integrity sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg== -subscriptions-transport-ws@^0.9.19: - version "0.9.19" - resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.19.tgz#10ca32f7e291d5ee8eb728b9c02e43c52606cdcf" - integrity sha512-dxdemxFFB0ppCLg10FTtRqH/31FNRL1y1BQv8209MK5I4CwALb7iihQg+7p65lFcIl8MHatINWBLOqpgU4Kyyw== - dependencies: - backo2 "^1.0.2" - eventemitter3 "^3.1.0" - iterall "^1.2.1" - symbol-observable "^1.0.4" - ws "^5.2.0 || ^6.0.0 || ^7.0.0" - superagent@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/superagent/-/superagent-6.1.0.tgz#09f08807bc41108ef164cfb4be293cebd480f4a6" @@ -12572,7 +12409,7 @@ svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" -symbol-observable@^1.0.4, symbol-observable@^1.1.0: +symbol-observable@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== @@ -12947,13 +12784,6 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -ts-invariant@^0.4.0: - version "0.4.4" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86" - integrity sha512-uEtWkFM/sdZvRNNDL3Ehu4WVpwaulhwQszV8mrtcdeE8nN00BV9mAmQ88RkrBhFgl9gMgvjJLAQcZbnPXI9mlA== - dependencies: - tslib "^1.9.3" - ts-invariant@^0.9.0: version "0.9.1" resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.1.tgz#87dfde9894a4ce3c7711b02b1b449e7fd7384b13" @@ -12976,7 +12806,7 @@ tsconfig-paths@^3.11.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.0.0, tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: +tslib@^1.0.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -13096,7 +12926,7 @@ type-fest@^1.0.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== -type-is@^1.6.16, type-is@~1.6.17, type-is@~1.6.18: +type-is@^1.6.18, type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== @@ -13473,17 +13303,6 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util.promisify@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b" - integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - for-each "^0.3.3" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.1" - util.promisify@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" @@ -13542,7 +13361,7 @@ uuid@8.3.2, uuid@^8.0.0, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -uuid@^3.1.0, uuid@^3.3.2: +uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -13872,7 +13691,7 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -"ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.4.6: +ws@^7.4.6: version "7.5.4" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.4.tgz#56bfa20b167427e138a7795de68d134fe92e21f9" integrity sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg== @@ -14007,14 +13826,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zen-observable-ts@^0.8.21: - version "0.8.21" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d" - integrity sha512-Yj3yXweRc8LdRMrCC8nIc4kkjWecPAUVh0TI0OUrWXx6aX790vLcDlWca6I4vsyCGH3LpWxq0dJRcMOFoVqmeg== - dependencies: - tslib "^1.9.3" - zen-observable "^0.8.0" - zen-observable-ts@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" @@ -14023,7 +13834,7 @@ zen-observable-ts@^1.1.0: "@types/zen-observable" "0.8.3" zen-observable "0.8.15" -zen-observable@0.8.15, zen-observable@^0.8.0: +zen-observable@0.8.15: version "0.8.15" resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From 110e5a770bffd9ad83cf2f9879dadc56dc845666 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 7 Sep 2021 04:50:59 +0000 Subject: [PATCH 008/135] Update patch dependencies (patch) (#6478) --- design-system/packages/button/package.json | 4 +- design-system/packages/core/package.json | 4 +- design-system/packages/fields/package.json | 4 +- design-system/packages/icons/package.json | 4 +- design-system/packages/loading/package.json | 4 +- design-system/packages/modals/package.json | 4 +- design-system/packages/notice/package.json | 4 +- design-system/packages/options/package.json | 2 +- design-system/packages/pill/package.json | 2 +- design-system/packages/popover/package.json | 4 +- .../packages/segmented-control/package.json | 4 +- design-system/packages/toast/package.json | 4 +- design-system/packages/tooltip/package.json | 2 +- design-system/website/package.json | 4 +- docs/package.json | 6 +-- examples-staging/basic/package.json | 6 +-- examples-staging/ecommerce/package.json | 6 +-- .../graphql-api-endpoint/package.json | 2 +- examples/testing/package.json | 4 +- package.json | 4 +- packages/auth/package.json | 4 +- packages/cloudinary/package.json | 4 +- packages/fields-document/package.json | 6 +-- packages/keystone/package.json | 16 ++++---- packages/session-store-redis/package.json | 2 +- tests/admin-ui-tests/package.json | 2 +- tests/api-tests/package.json | 2 +- tests/examples-smoke-tests/package.json | 2 +- yarn.lock | 41 +++++++++++-------- 29 files changed, 81 insertions(+), 76 deletions(-) diff --git a/design-system/packages/button/package.json b/design-system/packages/button/package.json index 03921b70508..38d5c775623 100644 --- a/design-system/packages/button/package.json +++ b/design-system/packages/button/package.json @@ -5,10 +5,10 @@ "main": "dist/button.cjs.js", "module": "dist/button.esm.js", "devDependencies": { - "@types/react": "^17.0.19" + "@types/react": "^17.0.20" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "@keystone-ui/icons": "^4.0.1", "@keystone-ui/loading": "^4.0.1", diff --git a/design-system/packages/core/package.json b/design-system/packages/core/package.json index dfae6a79f39..367b7199f9e 100644 --- a/design-system/packages/core/package.json +++ b/design-system/packages/core/package.json @@ -5,7 +5,7 @@ "main": "dist/core.cjs.js", "module": "dist/core.esm.js", "devDependencies": { - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "react": "^17.0.2", "react-dom": "^17.0.2" }, @@ -14,7 +14,7 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@emotion/react": "^11.4.1", "@types/facepaint": "^1.2.2", "facepaint": "^1.2.1" diff --git a/design-system/packages/fields/package.json b/design-system/packages/fields/package.json index e352f8837b5..515a9254123 100644 --- a/design-system/packages/fields/package.json +++ b/design-system/packages/fields/package.json @@ -5,10 +5,10 @@ "main": "dist/fields.cjs.js", "module": "dist/fields.esm.js", "devDependencies": { - "@types/react": "^17.0.19" + "@types/react": "^17.0.20" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "@keystone-ui/icons": "^4.0.1", "@keystone-ui/popover": "^4.0.3", diff --git a/design-system/packages/icons/package.json b/design-system/packages/icons/package.json index bff4e912da2..cba5085783b 100644 --- a/design-system/packages/icons/package.json +++ b/design-system/packages/icons/package.json @@ -12,7 +12,7 @@ "@svgr/plugin-jsx": "^5.5.0", "@svgr/plugin-prettier": "^5.5.0", "@svgr/plugin-svgo": "^5.5.0", - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "chalk": "^4.1.2", "feather-icons": "^4.28.0", "fs-extra": "^10.0.0", @@ -21,7 +21,7 @@ "to-pascal-case": "^1.0.0" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0" }, "peerDependencies": { diff --git a/design-system/packages/loading/package.json b/design-system/packages/loading/package.json index 612e6a53a9b..0beb4c08f3f 100644 --- a/design-system/packages/loading/package.json +++ b/design-system/packages/loading/package.json @@ -5,10 +5,10 @@ "main": "dist/loading.cjs.js", "module": "dist/loading.esm.js", "devDependencies": { - "@types/react": "^17.0.19" + "@types/react": "^17.0.20" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "react": "^17.0.2" }, diff --git a/design-system/packages/modals/package.json b/design-system/packages/modals/package.json index 27c6927dd15..171e8469a9d 100644 --- a/design-system/packages/modals/package.json +++ b/design-system/packages/modals/package.json @@ -5,10 +5,10 @@ "main": "dist/modals.cjs.js", "module": "dist/modals.esm.js", "devDependencies": { - "@types/react": "^17.0.19" + "@types/react": "^17.0.20" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", "react": "^17.0.2", diff --git a/design-system/packages/notice/package.json b/design-system/packages/notice/package.json index 59dd9d1e6fc..17334882e84 100644 --- a/design-system/packages/notice/package.json +++ b/design-system/packages/notice/package.json @@ -5,10 +5,10 @@ "main": "dist/notice.cjs.js", "module": "dist/notice.esm.js", "devDependencies": { - "@types/react": "^17.0.19" + "@types/react": "^17.0.20" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", "@keystone-ui/icons": "^4.0.1", diff --git a/design-system/packages/options/package.json b/design-system/packages/options/package.json index bda29369afb..b661bb54cc1 100644 --- a/design-system/packages/options/package.json +++ b/design-system/packages/options/package.json @@ -11,7 +11,7 @@ "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "@keystone-ui/fields": "^4.1.3", "@keystone-ui/icons": "^4.0.1", diff --git a/design-system/packages/pill/package.json b/design-system/packages/pill/package.json index e2d6f24cf83..e4001d8f693 100644 --- a/design-system/packages/pill/package.json +++ b/design-system/packages/pill/package.json @@ -11,7 +11,7 @@ "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "@keystone-ui/icons": "^4.0.1" }, diff --git a/design-system/packages/popover/package.json b/design-system/packages/popover/package.json index f10bdae1bbe..497d3d1f809 100644 --- a/design-system/packages/popover/package.json +++ b/design-system/packages/popover/package.json @@ -13,9 +13,9 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", - "@popperjs/core": "^2.9.3", + "@popperjs/core": "^2.10.1", "focus-trap": "^6.6.1", "react-popper": "^2.2.5" }, diff --git a/design-system/packages/segmented-control/package.json b/design-system/packages/segmented-control/package.json index 5d8dd288add..39d92a82572 100644 --- a/design-system/packages/segmented-control/package.json +++ b/design-system/packages/segmented-control/package.json @@ -5,11 +5,11 @@ "main": "dist/segmented-control.cjs.js", "module": "dist/segmented-control.esm.js", "devDependencies": { - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0" }, "peerDependencies": { diff --git a/design-system/packages/toast/package.json b/design-system/packages/toast/package.json index 1471e5d9796..4a9b516c4ab 100644 --- a/design-system/packages/toast/package.json +++ b/design-system/packages/toast/package.json @@ -5,11 +5,11 @@ "main": "dist/toast.cjs.js", "module": "dist/toast.esm.js", "devDependencies": { - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "react": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "@keystone-ui/icons": "^4.0.1" }, diff --git a/design-system/packages/tooltip/package.json b/design-system/packages/tooltip/package.json index a4ab43adcc3..a05cafcc807 100644 --- a/design-system/packages/tooltip/package.json +++ b/design-system/packages/tooltip/package.json @@ -13,7 +13,7 @@ "react-dom": "^17.0.2" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/core": "^3.2.0", "@keystone-ui/popover": "^4.0.3", "apply-ref": "^1.0.0" diff --git a/design-system/website/package.json b/design-system/website/package.json index 24fa82c6de3..952d4f3ce11 100644 --- a/design-system/website/package.json +++ b/design-system/website/package.json @@ -7,7 +7,7 @@ "dev": "next -p 8080" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", "@keystone-ui/fields": "^4.1.3", @@ -21,7 +21,7 @@ "@keystone-ui/toast": "^4.0.3", "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "@types/react-dom": "^17.0.9", "@types/tinycolor2": "^1.4.3", "next": "^11.1.0", diff --git a/docs/package.json b/docs/package.json index 77ee923757a..92e720f1b58 100644 --- a/docs/package.json +++ b/docs/package.json @@ -13,7 +13,7 @@ "cypress:run:ci": "yarn build && start-server-and-test start http://localhost:8000 cy:run" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@emotion/cache": "11.4.0", "@emotion/react": "^11.4.1", "@emotion/server": "11.4.0", @@ -26,7 +26,7 @@ "@sindresorhus/slugify": "^1.1.2", "@types/gtag.js": "^0.0.7", "@types/mdx-js__react": "^1.5.4", - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "@types/react-dom": "^17.0.9", "classnames": "^2.3.1", "copy-to-clipboard": "^3.3.1", @@ -47,7 +47,7 @@ "devDependencies": { "@types/lodash.debounce": "^4.0.6", "next-sitemap": "^1.6.164", - "start-server-and-test": "^1.13.1", + "start-server-and-test": "^1.14.0", "typescript": "^4.4.2" }, "engines": { diff --git a/examples-staging/basic/package.json b/examples-staging/basic/package.json index 19b888126fa..606566a16e6 100644 --- a/examples-staging/basic/package.json +++ b/examples-staging/basic/package.json @@ -9,7 +9,7 @@ "build": "keystone-next build" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-next/auth": "^32.0.0", "@keystone-next/document-renderer": "^4.0.0", "@keystone-next/fields-document": "^9.0.0", @@ -19,8 +19,8 @@ "@keystone-ui/icons": "^4.0.1", "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.19", - "graphql": "^15.5.2", + "@types/react": "^17.0.20", + "graphql": "^15.5.3", "graphql-tag": "^2.12.5", "next": "^11.1.0", "react": "^17.0.2", diff --git a/examples-staging/ecommerce/package.json b/examples-staging/ecommerce/package.json index aba0fb440dc..660f19fcfde 100644 --- a/examples-staging/ecommerce/package.json +++ b/examples-staging/ecommerce/package.json @@ -12,10 +12,10 @@ }, "dependencies": { "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.0", + "@babel/preset-env": "^7.15.4", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-next/auth": "^32.0.0", "@keystone-next/cloudinary": "^7.0.0", "@keystone-next/keystone": "^25.0.0", @@ -25,7 +25,7 @@ "nodemailer": "^6.6.3", "react": "^17.0.2", "react-dom": "^17.0.2", - "stripe": "^8.171.0" + "stripe": "^8.174.0" }, "devDependencies": { "typescript": "^4.4.2" diff --git a/examples-staging/graphql-api-endpoint/package.json b/examples-staging/graphql-api-endpoint/package.json index a435251f3b0..b9c4f03086b 100644 --- a/examples-staging/graphql-api-endpoint/package.json +++ b/examples-staging/graphql-api-endpoint/package.json @@ -11,7 +11,7 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-next/auth": "^32.0.0", "@keystone-next/fields-document": "^9.0.0", "@keystone-next/keystone": "^25.0.0" diff --git a/examples/testing/package.json b/examples/testing/package.json index 561a158816c..725b050942c 100644 --- a/examples/testing/package.json +++ b/examples/testing/package.json @@ -10,8 +10,8 @@ "test": "jest --runInBand --testTimeout=60000" }, "dependencies": { - "@babel/core": "^7.15.0", - "@babel/preset-env": "^7.15.0", + "@babel/core": "^7.15.5", + "@babel/preset-env": "^7.15.4", "@babel/preset-typescript": "^7.15.0", "@keystone-next/auth": "^32.0.0", "@keystone-next/keystone": "^25.0.0" diff --git a/package.json b/package.json index 111a2160661..c4587f058e6 100644 --- a/package.json +++ b/package.json @@ -40,12 +40,12 @@ "lint:filters": "cd prisma-utils && yarn verify" }, "dependencies": { - "@babel/core": "^7.15.0", + "@babel/core": "^7.15.5", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.0", + "@babel/preset-env": "^7.15.4", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@changesets/changelog-github": "^0.4.1", diff --git a/packages/auth/package.json b/packages/auth/package.json index 602a0a33fc8..0bc9f6182b8 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -8,7 +8,7 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@graphql-tools/schema": "^8.2.0", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", @@ -16,7 +16,7 @@ "@keystone-ui/notice": "^4.0.2", "cross-fetch": "^3.1.4", "fast-deep-equal": "^3.1.3", - "graphql": "^15.5.2" + "graphql": "^15.5.3" }, "devDependencies": { "@keystone-next/keystone": "^25.0.0", diff --git a/packages/cloudinary/package.json b/packages/cloudinary/package.json index 88a44042203..2efc8cb2f6a 100644 --- a/packages/cloudinary/package.json +++ b/packages/cloudinary/package.json @@ -5,12 +5,12 @@ "main": "dist/cloudinary.cjs.js", "module": "dist/cloudinary.esm.js", "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", "@keystone-ui/fields": "^4.1.3", "@keystone-ui/pill": "^5.0.1", - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "cloudinary": "^1.26.3", "cuid": "^2.1.8", "graphql-upload": "^12.0.0", diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index 48725c5658b..f0bafdf01a1 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -19,7 +19,7 @@ ] }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@braintree/sanitize-url": "^5.0.2", "@emotion/weak-memoize": "^0.2.5", "@keystone-next/keystone": "^25.0.0", @@ -29,10 +29,10 @@ "@keystone-ui/icons": "^4.0.1", "@keystone-ui/popover": "^4.0.3", "@keystone-ui/tooltip": "^4.0.2", - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "apply-ref": "^1.0.0", "fp-ts": "^2.11.1", - "graphql": "^15.5.2", + "graphql": "^15.5.3", "io-ts": "^2.2.16", "io-ts-excess": "^1.0.1", "is-hotkey": "^0.2.0", diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 8f24f933273..3eec1ddd296 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -27,9 +27,9 @@ }, "dependencies": { "@apollo/client": "^3.4.10", - "@babel/core": "^7.15.0", - "@babel/plugin-transform-modules-commonjs": "^7.15.0", - "@babel/runtime": "^7.15.3", + "@babel/core": "^7.15.5", + "@babel/plugin-transform-modules-commonjs": "^7.15.4", + "@babel/runtime": "^7.15.4", "@emotion/hash": "^0.8.0", "@emotion/weak-memoize": "^0.2.5", "@graphql-tools/schema": "^8.2.0", @@ -54,7 +54,7 @@ "@prisma/sdk": "2.30.2", "@sindresorhus/slugify": "^1.1.2", "@types/apollo-upload-client": "14.1.0", - "@types/babel__core": "^7.1.15", + "@types/babel__core": "^7.1.16", "@types/bcryptjs": "^2.4.2", "@types/cookie": "^0.4.1", "@types/express": "^4.17.13", @@ -66,7 +66,7 @@ "@types/pluralize": "^0.0.29", "@types/prettier": "^2.3.2", "@types/prompts": "^2.0.14", - "@types/react": "^17.0.19", + "@types/react": "^17.0.20", "@types/source-map-support": "^0.5.4", "@types/supertest": "^2.0.11", "@types/uid-safe": "^2.1.2", @@ -94,7 +94,7 @@ "filenamify": "^4.3.0", "form-data": "4.0.0", "fs-extra": "^10.0.0", - "graphql": "^15.5.2", + "graphql": "^15.5.3", "graphql-type-json": "^0.3.2", "graphql-upload": "^12.0.0", "image-size": "^1.0.0", @@ -103,9 +103,9 @@ "intersection-observer": "^0.12.0", "memoize-one": "^5.2.1", "meow": "^9.0.0", - "micro": "^9.3.2", + "micro": "^9.3.4", "next": "^11.1.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.2", "object-hash": "^2.2.0", "p-limit": "^2.3.0", "pirates": "^4.0.1", diff --git a/packages/session-store-redis/package.json b/packages/session-store-redis/package.json index 998d7e9a5b5..87280511352 100644 --- a/packages/session-store-redis/package.json +++ b/packages/session-store-redis/package.json @@ -8,7 +8,7 @@ "node": "^12.20 || >= 14.13" }, "dependencies": { - "@babel/runtime": "^7.15.3", + "@babel/runtime": "^7.15.4", "@types/redis": "^2.8.31" }, "peerDependencies": { diff --git a/tests/admin-ui-tests/package.json b/tests/admin-ui-tests/package.json index ce117edc9b6..bbd5e42805a 100644 --- a/tests/admin-ui-tests/package.json +++ b/tests/admin-ui-tests/package.json @@ -26,7 +26,7 @@ "dependencies": { "@manypkg/find-root": "^1.1.0", "dotenv": "^10.0.0", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.2", "tree-kill": "^1.2.2" } } diff --git a/tests/api-tests/package.json b/tests/api-tests/package.json index 996368f5c04..dd7ea068b4b 100644 --- a/tests/api-tests/package.json +++ b/tests/api-tests/package.json @@ -19,7 +19,7 @@ "cookie-signature": "^1.1.0", "cuid": "^2.1.8", "globby": "^11.0.4", - "graphql": "^15.5.2", + "graphql": "^15.5.3", "memoize-one": "^5.2.1", "superagent": "^6.1.0", "supertest": "^6.1.6", diff --git a/tests/examples-smoke-tests/package.json b/tests/examples-smoke-tests/package.json index d9c1285b6e9..e6a3d517c02 100644 --- a/tests/examples-smoke-tests/package.json +++ b/tests/examples-smoke-tests/package.json @@ -13,7 +13,7 @@ "dependencies": { "@types/tough-cookie": "^4.0.1", "execa": "^5.1.1", - "node-fetch": "^2.6.1", + "node-fetch": "^2.6.2", "playwright": "^1.14.1", "tree-kill": "^1.2.2" } diff --git a/yarn.lock b/yarn.lock index fcbd929178d..65bff7f8708 100644 --- a/yarn.lock +++ b/yarn.lock @@ -70,7 +70,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.15.0", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.7.7": +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.15.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.7.7": version "7.15.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== @@ -693,7 +693,7 @@ "@babel/helper-plugin-utils" "^7.14.5" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.15.0", "@babel/plugin-transform-modules-commonjs@^7.15.4", "@babel/plugin-transform-modules-commonjs@^7.7.5": +"@babel/plugin-transform-modules-commonjs@^7.15.4", "@babel/plugin-transform-modules-commonjs@^7.7.5": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz#8201101240eabb5a76c08ef61b2954f767b6b4c1" integrity sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA== @@ -877,7 +877,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@^7.15.0": +"@babel/preset-env@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.4.tgz#197e7f99a755c488f0af411af179cbd10de6e815" integrity sha512-4f2nLw+q6ht8gl3sHCmNhmA5W6b1ItLzbH3UrKuJxACHr2eCpk96jwjrAfCAaXaaVwTQGnyUYHY2EWXJGt7TUQ== @@ -1003,7 +1003,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.4", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== @@ -1971,7 +1971,7 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@popperjs/core@^2.9.3": +"@popperjs/core@^2.10.1": version "2.10.1" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.1.tgz#728ecd95ab207aab8a9a4e421f0422db329232be" integrity sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw== @@ -2553,10 +2553,10 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc" integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.15": - version "7.1.15" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.15.tgz#2ccfb1ad55a02c83f8e0ad327cbc332f55eb1024" - integrity sha512-bxlMKPDbY8x5h6HBwVzEOk2C8fb6SLfYQ5Jw3uBYuYF1lfWk/kbLd81la82vrIkBb0l+JdmrZaDikPrNxpS/Ew== +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.16": + version "7.1.16" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" + integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -2985,7 +2985,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17.0.19": +"@types/react@*", "@types/react@^17.0.20": version "17.0.20" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.20.tgz#a4284b184d47975c71658cd69e759b6bd37c3b8c" integrity sha512-wWZrPlihslrPpcKyCSlmIlruakxr57/buQN1RjlIeaaTWDLtJkTtRW429MoQJergvVKc4IWBpRhWw7YNh/7GVA== @@ -6985,10 +6985,10 @@ graphql-upload@^12.0.0: isobject "^4.0.0" object-path "^0.11.5" -graphql@^15.3.0, graphql@^15.5.2: - version "15.5.2" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.2.tgz#efa19f8f2bf1a48eb7d5c85bf17e144ba8bb0480" - integrity sha512-dZjLPWNQqYv0dqV2RNbiFed0LtSp6yd4jchsDGnuhDKa9OQHJYCfovaOEvY91w9gqbYO7Se9LKDTl3xxYva/3w== +graphql@^15.3.0, graphql@^15.5.3: + version "15.5.3" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.3.tgz#c72349017d5c9f5446a897fe6908b3186db1da00" + integrity sha512-sM+jXaO5KinTui6lbK/7b7H/Knj9BpjGxZ+Ki35v7YbUJxxdBCUqNM0h3CRVU1ZF9t5lNiBzvBCSYPvIwxPOQA== har-schema@^2.0.0: version "2.0.0" @@ -9332,7 +9332,7 @@ methods@^1.1.2, methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micro@^9.3.2: +micro@^9.3.4: version "9.3.4" resolved "https://registry.yarnpkg.com/micro/-/micro-9.3.4.tgz#745a494e53c8916f64fb6a729f8cbf2a506b35ad" integrity sha512-smz9naZwTG7qaFnEZ2vn248YZq9XR+XoOH3auieZbkhDL4xLOxiE+KqG8qqnBeKfXA9c1uEFGCxPN1D+nT6N7w== @@ -9758,11 +9758,16 @@ next@^11.1.0: vm-browserify "1.1.2" watchpack "2.1.1" -node-fetch@2.6.1, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1: +node-fetch@2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.2.tgz#986996818b73785e47b1965cc34eb093a1d464d0" + integrity sha512-aLoxToI6RfZ+0NOjmWAgn9+LEd30YCkJKFSyWacNZdEKTit/ZMcKjGkTRo8uWEsnIb/hfKecNPEbln02PdWbcA== + node-html-parser@1.4.9: version "1.4.9" resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-1.4.9.tgz#3c8f6cac46479fae5800725edb532e9ae8fd816c" @@ -12006,7 +12011,7 @@ stacktrace-parser@0.1.10: dependencies: type-fest "^0.7.1" -start-server-and-test@^1.13.1: +start-server-and-test@^1.14.0: version "1.14.0" resolved "https://registry.yarnpkg.com/start-server-and-test/-/start-server-and-test-1.14.0.tgz#c57f04f73eac15dd51733b551d775b40837fdde3" integrity sha512-on5ELuxO2K0t8EmNj9MtVlFqwBMxfWOhu4U7uZD1xccVpFlOQKR93CSe0u98iQzfNxRyaNTb/CdadbNllplTsw== @@ -12282,7 +12287,7 @@ strip-outer@^1.0.1: dependencies: escape-string-regexp "^1.0.2" -stripe@^8.171.0: +stripe@^8.174.0: version "8.174.0" resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.174.0.tgz#91d2e61b0217b1ee9fde2842582e0f1cf1dddc94" integrity sha512-UFU5TuYH7XwUmSllUIcIKhhsvvhhjw9D6ZwVdfB74wU4VOOaWBiQqszkw6chaEFpdulUmbcAH5eZltV3HwOi7g== From 144f7f8e4e13ec547865927cb224fea7165b98b7 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Tue, 7 Sep 2021 15:25:23 +1000 Subject: [PATCH 009/135] Fix types of (#6487) --- .changeset/loud-meals-switch.md | 5 +++++ packages/keystone/src/types/config/hooks.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/loud-meals-switch.md diff --git a/.changeset/loud-meals-switch.md b/.changeset/loud-meals-switch.md new file mode 100644 index 00000000000..4a66cb51bfb --- /dev/null +++ b/.changeset/loud-meals-switch.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed type definition of `ValidationArgs['addValidationError']`. diff --git a/packages/keystone/src/types/config/hooks.ts b/packages/keystone/src/types/config/hooks.ts index 26c24fcd899..196f30013c8 100644 --- a/packages/keystone/src/types/config/hooks.ts +++ b/packages/keystone/src/types/config/hooks.ts @@ -83,7 +83,7 @@ type ArgsForCreateOrUpdateOperation void; + addValidationError: (error: string) => void; }; type ResolveInputHook = ( From bf331141edd107e4f58e640b36b587499209c36f Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Tue, 7 Sep 2021 16:51:23 +1000 Subject: [PATCH 010/135] Remove unnecessary try/catch block (#6488) --- .changeset/hot-cameras-work.md | 5 +++ .../fields-document/src/relationship-data.tsx | 39 ++++++++----------- 2 files changed, 21 insertions(+), 23 deletions(-) create mode 100644 .changeset/hot-cameras-work.md diff --git a/.changeset/hot-cameras-work.md b/.changeset/hot-cameras-work.md new file mode 100644 index 00000000000..ff4fce2d32d --- /dev/null +++ b/.changeset/hot-cameras-work.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/fields-document': patch +--- + +Removed unnecessary try/catch block in relationship data resolver. diff --git a/packages/fields-document/src/relationship-data.tsx b/packages/fields-document/src/relationship-data.tsx index 2c870dc97fd..41e704818bf 100644 --- a/packages/fields-document/src/relationship-data.tsx +++ b/packages/fields-document/src/relationship-data.tsx @@ -49,30 +49,23 @@ export function addRelationshipData( const id = data?.id; if (id != null) { const labelField = getLabelFieldsForLists(graphQLAPI.schema)[relationship.listKey]; - let val; - try { - val = await graphQLAPI.run({ - query: `query($id: ID!) {item:${ - gqlNames(relationship.listKey).itemQueryName - }(where: {id:$id}) {${labelFieldAlias}:${labelField}\n${ - relationship.selection || '' - }}}`, - variables: { id }, - }); - if (val.item === null) { - if (!process.env.TEST_ADAPTER) { - // If we're unable to find the item (e.g. we have a dangling reference), or access was denied - // then simply return { id } and leave `label` and `data` undefined. - const r = JSON.stringify(relationship); - console.error(`Unable to fetch relationship data: relationship: ${r}, id: ${id} `); - } - return { id }; + // An exception here indicates something wrong with either the system or the + // configuration (e.g. a bad selection field). These will surface as system + // errors from the GraphQL field resolver. + const val = await graphQLAPI.run({ + query: `query($id: ID!) {item:${ + gqlNames(relationship.listKey).itemQueryName + }(where: {id:$id}) {${labelFieldAlias}:${labelField}\n${relationship.selection || ''}}}`, + variables: { id }, + }); + if (val.item === null) { + if (!process.env.TEST_ADAPTER) { + // If we're unable to find the item (e.g. we have a dangling reference), or access was denied + // then simply return { id } and leave `label` and `data` undefined. + const r = JSON.stringify(relationship); + console.error(`Unable to fetch relationship data: relationship: ${r}, id: ${id} `); } - } catch (err) { - // Errors indicate something wrong with either the system or the - // configuration (e.g. a bad selection field) and they should be surfaced as a - // GraphQL error. - throw err; + return { id }; } return { id, From c1401d48002f03f49c2a09b96a3d6a89aeb8e3db Mon Sep 17 00:00:00 2001 From: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Date: Wed, 8 Sep 2021 05:20:49 +0530 Subject: [PATCH 011/135] fix windows issues in view resolver (#6477) --- .changeset/orange-rice-return.md | 5 +++++ .../keystone/src/admin-ui/utils/serializePathForImport.ts | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .changeset/orange-rice-return.md diff --git a/.changeset/orange-rice-return.md b/.changeset/orange-rice-return.md new file mode 100644 index 00000000000..f696c59f08c --- /dev/null +++ b/.changeset/orange-rice-return.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed windows issues with new view resolver from #6414. diff --git a/packages/keystone/src/admin-ui/utils/serializePathForImport.ts b/packages/keystone/src/admin-ui/utils/serializePathForImport.ts index 741c321161a..8d890fbc766 100644 --- a/packages/keystone/src/admin-ui/utils/serializePathForImport.ts +++ b/packages/keystone/src/admin-ui/utils/serializePathForImport.ts @@ -1,8 +1,10 @@ +import Path from 'path'; export function serializePathForImport(path: string) { - // JSON.stringify is important here because it will escape windows style paths(and any thing else that might potentionally be in there) + // JSON.stringify is important here because it will escape windows style paths(and any thing else that might potentially be in there) return JSON.stringify( path - // Next is unhappy about imports that include .ts/tsx in them because TypeScript is unhappy with them becasue when doing a TypeScript compilation with tsc, the imports won't be written so they would be wrong there + // Next is unhappy about imports that include .ts/tsx in them because TypeScript is unhappy with them because when doing a TypeScript compilation with tsc, the imports won't be written so they would be wrong there .replace(/\.tsx?$/, '') + .replace(new RegExp(`\\${Path.sep}`, 'g'), '/') ); } From 8ab7d0655be3cbdbadf6c843bdc118291f91e5ea Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 8 Sep 2021 09:58:41 +1000 Subject: [PATCH 012/135] Remove unnecessary calls to context.exitSudo() from tests (#6496) --- tests/api-tests/access-control/mutations-field.test.ts | 4 ---- .../access-control/mutations-list-filter.test.ts | 4 ---- .../access-control/mutations-list-item.test.ts | 6 ------ .../nested-mutations/connect-singular.test.ts | 6 +++--- .../nested-mutations/create-and-connect-many.test.ts | 4 ++-- .../relationships/nested-mutations/create-many.test.ts | 10 +++++----- 6 files changed, 10 insertions(+), 24 deletions(-) diff --git a/tests/api-tests/access-control/mutations-field.test.ts b/tests/api-tests/access-control/mutations-field.test.ts index bc79527f9a4..1b475d4a0aa 100644 --- a/tests/api-tests/access-control/mutations-field.test.ts +++ b/tests/api-tests/access-control/mutations-field.test.ts @@ -40,7 +40,6 @@ describe('Access control', () => { test( 'createOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid name should pass await context.lists.User.createOne({ data: { name: 'good', other: 'a' } }); @@ -64,7 +63,6 @@ describe('Access control', () => { test( 'updateOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid name should pass const user = await context.lists.User.createOne({ data: { name: 'good', other: 'a' } }); await context.lists.User.updateOne({ @@ -92,7 +90,6 @@ describe('Access control', () => { test( 'createMany', runner(async ({ context }) => { - context = context.exitSudo(); // Mix of good and bad names const { data, errors } = await context.graphql.raw({ query: `mutation ($data: [UserCreateInput!]!) { createUsers(data: $data) { id name } }`, @@ -139,7 +136,6 @@ describe('Access control', () => { test( 'updateMany', runner(async ({ context }) => { - context = context.exitSudo(); // Start with some users const users = await context.lists.User.createMany({ data: [ diff --git a/tests/api-tests/access-control/mutations-list-filter.test.ts b/tests/api-tests/access-control/mutations-list-filter.test.ts index 01ee67d9525..89301875592 100644 --- a/tests/api-tests/access-control/mutations-list-filter.test.ts +++ b/tests/api-tests/access-control/mutations-list-filter.test.ts @@ -25,7 +25,6 @@ describe('Access control - Filter', () => { test( 'updateOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid name should pass const user = await context.lists.User.createOne({ data: { name: 'good' } }); await context.lists.User.updateOne({ where: { id: user.id }, data: { name: 'better' } }); @@ -52,7 +51,6 @@ describe('Access control - Filter', () => { test( 'deleteOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid names should pass const user1 = await context.lists.User.createOne({ data: { name: 'good' } }); const user2 = await context.lists.User.createOne({ data: { name: 'no delete' } }); @@ -77,7 +75,6 @@ describe('Access control - Filter', () => { test( 'updateMany', runner(async ({ context }) => { - context = context.exitSudo(); // Start with some users const users = await context.lists.User.createMany({ data: [ @@ -144,7 +141,6 @@ describe('Access control - Filter', () => { test( 'deleteMany', runner(async ({ context }) => { - context = context.exitSudo(); // Start with some users const users = await context.lists.User.createMany({ data: [ diff --git a/tests/api-tests/access-control/mutations-list-item.test.ts b/tests/api-tests/access-control/mutations-list-item.test.ts index aad75046ae2..3e02535746f 100644 --- a/tests/api-tests/access-control/mutations-list-item.test.ts +++ b/tests/api-tests/access-control/mutations-list-item.test.ts @@ -31,7 +31,6 @@ describe('Access control - Item', () => { test( 'createOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid name should pass await context.lists.User.createOne({ data: { name: 'good' } }); @@ -54,7 +53,6 @@ describe('Access control - Item', () => { test( 'updateOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid name should pass const user = await context.lists.User.createOne({ data: { name: 'good' } }); await context.lists.User.updateOne({ where: { id: user.id }, data: { name: 'better' } }); @@ -78,7 +76,6 @@ describe('Access control - Item', () => { test( 'deleteOne', runner(async ({ context }) => { - context = context.exitSudo(); // Valid names should pass const user1 = await context.lists.User.createOne({ data: { name: 'good' } }); const user2 = await context.lists.User.createOne({ data: { name: 'no delete' } }); @@ -103,7 +100,6 @@ describe('Access control - Item', () => { test( 'createMany', runner(async ({ context }) => { - context = context.exitSudo(); // Mix of good and bad names const { data, errors } = await context.graphql.raw({ query: `mutation ($data: [UserCreateInput!]!) { createUsers(data: $data) { id name } }`, @@ -147,7 +143,6 @@ describe('Access control - Item', () => { test( 'updateMany', runner(async ({ context }) => { - context = context.exitSudo(); // Start with some users const users = await context.lists.User.createMany({ data: [ @@ -205,7 +200,6 @@ describe('Access control - Item', () => { test( 'deleteMany', runner(async ({ context }) => { - context = context.exitSudo(); // Start with some users const users = await context.lists.User.createMany({ data: [ diff --git a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts index d2de495fc23..4409e871132 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts @@ -217,7 +217,7 @@ describe('with access control', () => { expect(id).toBeTruthy(); // Create an item that does the linking - const data = await context.exitSudo().lists[`EventTo${group.name}`].createOne({ + const data = await context.lists[`EventTo${group.name}`].createOne({ data: { title: 'A thing', group: { connect: { id } } }, query: 'id group { id }', }); @@ -283,7 +283,7 @@ describe('with access control', () => { expect(eventModel.id).toBeTruthy(); // Update the item and link the relationship field - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { updateEventTo${group.name}( @@ -319,7 +319,7 @@ describe('with access control', () => { expect(id).toBeTruthy(); // Create an item that does the linking - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { createEventTo${group.name}(data: { diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts index 3def7fd179d..1d48ccd24da 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts @@ -174,7 +174,7 @@ describe('with access control', () => { }); // Create an item that does the linking - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { createUserToNotesNoRead(data: { @@ -216,7 +216,7 @@ describe('with access control', () => { }); // Update the item and link the relationship field - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { updateUserToNotesNoRead( diff --git a/tests/api-tests/relationships/nested-mutations/create-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-many.test.ts index 0c29a662eb6..913c957bf02 100644 --- a/tests/api-tests/relationships/nested-mutations/create-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-many.test.ts @@ -202,7 +202,7 @@ describe('with access control', () => { const noteContent = sampleOne(alphanumGenerator); // Create an item that does the nested create - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { createUserToNotesNoRead(data: { @@ -228,7 +228,7 @@ describe('with access control', () => { const noteContent = sampleOne(alphanumGenerator); // Create an item that does the nested create - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { createUserToNotesNoRead(data: { @@ -256,7 +256,7 @@ describe('with access control', () => { }); // Update an item that does the nested create - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { updateUserToNotesNoRead( @@ -284,7 +284,7 @@ describe('with access control', () => { const noteContent = sampleOne(alphanumGenerator); // Create an item that does the nested create - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { createUserToNotesNoCreate(data: { @@ -328,7 +328,7 @@ describe('with access control', () => { }); // Update an item that does the nested create - const { data, errors } = await context.exitSudo().graphql.raw({ + const { data, errors } = await context.graphql.raw({ query: ` mutation { updateUserToNotesNoCreate( From 0ee688e50997aebd534dca5b59545b0b5dc9a18e Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 8 Sep 2021 11:11:41 +1000 Subject: [PATCH 013/135] Add tests for more ID field error code paths (#6497) --- tests/api-tests/id-field.test.ts | 58 ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/tests/api-tests/id-field.test.ts b/tests/api-tests/id-field.test.ts index d647554501e..fcc03d0002b 100644 --- a/tests/api-tests/id-field.test.ts +++ b/tests/api-tests/id-field.test.ts @@ -44,6 +44,64 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { ]); }) ); + test( + 'Fetching an item uniquely with a null id throws an error', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ query: `{ user(where: { id: null}) { id } }` }); + expect(body.data).toEqual({ user: null }); + expectBadUserInput(body.errors, [ + { + path: ['user'], + message: `The unique value provided in a unique where input must not be null`, + }, + ]); + }) + ); + test( + 'Filtering an item with a null id throws an error', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ query: `{ users(where: { id: null }) { id } }` }); + expect(body.data).toEqual({ users: null }); + expectBadUserInput(body.errors, [{ path: ['users'], message: `id filter cannot be null` }]); + }) + ); + test( + 'Filtering an item with { equals: null } throws an error', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: `{ users(where: { id: { equals: null } }) { id } }`, + }); + expect(body.data).toEqual({ users: null }); + const s = kind === 'autoincrement' ? 'an integer' : `a ${kind}`; + expectBadUserInput(body.errors, [ + { path: ['users'], message: `Only ${s} can be passed to id filters` }, + ]); + }) + ); + test( + 'Filtering an item with a in: null throws an error', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: `{ users(where: { id: { in: null } }) { id } }`, + }); + expect(body.data).toEqual({ users: null }); + expectBadUserInput(body.errors, [ + { path: ['users'], message: `in id filter cannot be null` }, + ]); + }) + ); + test( + 'Filtering an item with a notIn: null throws an error', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: `{ users(where: { id: { notIn: null } }) { id } }`, + }); + expect(body.data).toEqual({ users: null }); + expectBadUserInput(body.errors, [ + { path: ['users'], message: `notIn id filter cannot be null` }, + ]); + }) + ); test( 'Creating an item', runner(async ({ context }) => { From ce0428b93c2a87fb5b706b8bc44edf16e4cd021e Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 8 Sep 2021 11:27:02 +1000 Subject: [PATCH 014/135] Fix operation argument to field access control (#6498) --- .changeset/curly-drinks-rush.md | 5 + .../keystone/src/lib/core/access-control.ts | 2 +- .../src/lib/core/queries/output-field.ts | 2 +- .../src/types/config/access-control.ts | 2 +- .../access-control/mutations-field.test.ts | 94 +++++++++++- .../mutations-list-item.test.ts | 97 ++++++++++++- .../mutations-list-operation.test.ts | 135 ++++++++++++++++++ 7 files changed, 332 insertions(+), 5 deletions(-) create mode 100644 .changeset/curly-drinks-rush.md create mode 100644 tests/api-tests/access-control/mutations-list-operation.test.ts diff --git a/.changeset/curly-drinks-rush.md b/.changeset/curly-drinks-rush.md new file mode 100644 index 00000000000..ec5aba43497 --- /dev/null +++ b/.changeset/curly-drinks-rush.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed an issue where the incorrect value for the `operation` argument was passed into field-level access control functions. Keystone now correctly passes in `'read'` rather than the incorrect `'query'`. diff --git a/packages/keystone/src/lib/core/access-control.ts b/packages/keystone/src/lib/core/access-control.ts index 603146ba232..11b05bbdc68 100644 --- a/packages/keystone/src/lib/core/access-control.ts +++ b/packages/keystone/src/lib/core/access-control.ts @@ -53,7 +53,7 @@ export async function getAccessFilters( } export async function validateFieldAccessControl< - Args extends { listKey: string; fieldKey: string; operation: 'query' | 'create' | 'update' } + Args extends { listKey: string; fieldKey: string; operation: 'read' | 'create' | 'update' } >({ access, args, diff --git a/packages/keystone/src/lib/core/queries/output-field.ts b/packages/keystone/src/lib/core/queries/output-field.ts index e692aaac007..1e0b79b135d 100644 --- a/packages/keystone/src/lib/core/queries/output-field.ts +++ b/packages/keystone/src/lib/core/queries/output-field.ts @@ -118,7 +118,7 @@ export function outputTypeField( fieldKey, item: rootVal, listKey, - operation: 'query', + operation: 'read', session: context.session, }, }); diff --git a/packages/keystone/src/types/config/access-control.ts b/packages/keystone/src/types/config/access-control.ts index 6af3db3014c..5393ccbb522 100644 --- a/packages/keystone/src/types/config/access-control.ts +++ b/packages/keystone/src/types/config/access-control.ts @@ -121,7 +121,7 @@ export type FieldCreateItemAccessArgs & { fieldKey: string }; export type FieldReadItemAccessArgs = - BaseAccessArgs & { fieldKey: string; item: GeneratedListTypes['backing'] }; + BaseAccessArgs & { operation: 'read'; fieldKey: string; item: GeneratedListTypes['backing'] }; export type FieldUpdateItemAccessArgs = UpdateItemAccessArgs & { fieldKey: string }; diff --git a/tests/api-tests/access-control/mutations-field.test.ts b/tests/api-tests/access-control/mutations-field.test.ts index 1b475d4a0aa..83a432140bf 100644 --- a/tests/api-tests/access-control/mutations-field.test.ts +++ b/tests/api-tests/access-control/mutations-field.test.ts @@ -1,7 +1,7 @@ import { text } from '@keystone-next/keystone/fields'; import { createSchema, list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectAccessDenied } from '../utils'; +import { apiTestConfig, expectAccessDenied, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -30,6 +30,17 @@ const runner = setupTestRunner({ }, isOrderable: true, }), + badAccess: text({ + access: { + // @ts-ignore Intentionally return a string for testing purposes + read: () => 'non boolean value', + // @ts-ignore Intentionally return a string for testing purposes + create: () => 'non boolean value', + // @ts-ignore Intentionally return a string for testing purposes + update: () => 'non boolean value', + }, + isOrderable: true, + }), }, }), }), @@ -37,6 +48,27 @@ const runner = setupTestRunner({ }); describe('Access control', () => { + test( + 'findMany - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + const item = await context + .sudo() + .lists.User.createOne({ data: { name: 'foo', badAccess: 'bar' } }); + + const { body } = await graphQLRequest({ + query: `query { users { id name badAccess } }`, + }); + + // Returns the item, with null for the bad field, and an error message + expect(body.data).toEqual({ users: [{ id: item.id, name: 'foo', badAccess: null }] }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from User.fields.badAccess.access.read(). Got string', + path: ['users', 0, 'badAccess'], + }, + ]); + }) + ); test( 'createOne', runner(async ({ context }) => { @@ -60,6 +92,34 @@ describe('Access control', () => { }) ); + test( + 'createOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + // Valid name should pass + await context.lists.User.createOne({ data: { name: 'good', other: 'a' } }); + + // Invalid name + const { body } = await graphQLRequest({ + query: `mutation ($data: UserCreateInput!) { createUser(data: $data) { id } }`, + variables: { data: { name: 'fine', other: 'b', badAccess: 'bar' } }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ createUser: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from User.fields.badAccess.access.create(). Got string', + path: ['createUser'], + }, + ]); + + // Only the original user should exist + const _users = await context.lists.User.findMany({ query: 'id name other' }); + expect(_users.map(({ name }) => name)).toEqual(['good']); + expect(_users.map(({ other }) => other)).toEqual(['a']); + }) + ); + test( 'updateOne', runner(async ({ context }) => { @@ -87,6 +147,38 @@ describe('Access control', () => { }) ); + test( + 'updateOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + // Valid name should pass + const user = await context.lists.User.createOne({ data: { name: 'good', other: 'a' } }); + await context.lists.User.updateOne({ + where: { id: user.id }, + data: { name: 'better', other: 'b' }, + }); + + // Invalid name + const { body } = await graphQLRequest({ + query: `mutation ($id: ID! $data: UserUpdateInput!) { updateUser(where: { id: $id }, data: $data) { id } }`, + variables: { id: user.id, data: { name: 'bad', other: 'c', badAccess: 'bar' } }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ updateUser: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from User.fields.badAccess.access.update(). Got string', + path: ['updateUser'], + }, + ]); + + // User should have its original name + const _users = await context.lists.User.findMany({ query: 'id name other' }); + expect(_users.map(({ name }) => name)).toEqual(['better']); + expect(_users.map(({ other }) => other)).toEqual(['b']); + }) + ); + test( 'createMany', runner(async ({ context }) => { diff --git a/tests/api-tests/access-control/mutations-list-item.test.ts b/tests/api-tests/access-control/mutations-list-item.test.ts index 3e02535746f..3501912d343 100644 --- a/tests/api-tests/access-control/mutations-list-item.test.ts +++ b/tests/api-tests/access-control/mutations-list-item.test.ts @@ -1,7 +1,7 @@ import { text } from '@keystone-next/keystone/fields'; import { createSchema, list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectAccessDenied } from '../utils'; +import { apiTestConfig, expectAccessDenied, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -23,6 +23,25 @@ const runner = setupTestRunner({ }, }, }), + BadAccess: list({ + fields: { name: text({ isFilterable: true, isOrderable: true }) }, + access: { + item: { + // @ts-ignore Intentionally return a filter for testing purposes + create: () => { + return { name: { not: { equals: 'bad' } } }; + }, + // @ts-ignore Intentionally return a filter for testing purposes + update: () => { + return { name: { not: { equals: 'bad' } } }; + }, + // @ts-ignore Intentionally return a filter for testing purposes + delete: async () => { + return { name: { not: { startsWtih: 'no delete' } } }; + }, + }, + }, + }), }), }), }); @@ -50,6 +69,30 @@ describe('Access control - Item', () => { }) ); + test( + 'createOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + // Valid name + const { body } = await graphQLRequest({ + query: `mutation ($data: BadAccessCreateInput!) { createBadAccess(data: $data) { id } }`, + variables: { data: { name: 'better' } }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ createBadAccess: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.item.create(). Got object', + path: ['createBadAccess'], + }, + ]); + + // No items should exist + const _users = await context.lists.BadAccess.findMany({ query: 'id name' }); + expect(_users.map(({ name }) => name)).toEqual([]); + }) + ); + test( 'updateOne', runner(async ({ context }) => { @@ -73,6 +116,32 @@ describe('Access control - Item', () => { }) ); + test( + 'updateOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + const item = await context.sudo().lists.BadAccess.createOne({ data: { name: 'good' } }); + + // Valid name + const { body } = await graphQLRequest({ + query: `mutation ($id: ID! $data: BadAccessUpdateInput!) { updateBadAccess(where: { id: $id }, data: $data) { id } }`, + variables: { id: item.id, data: { name: 'better' } }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ updateBadAccess: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.item.update(). Got object', + path: ['updateBadAccess'], + }, + ]); + + // Item should have its original name + const _items = await context.lists.BadAccess.findMany({ query: 'id name' }); + expect(_items.map(({ name }) => name)).toEqual(['good']); + }) + ); + test( 'deleteOne', runner(async ({ context }) => { @@ -97,6 +166,32 @@ describe('Access control - Item', () => { }) ); + test( + 'deleteOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + const item = await context.sudo().lists.BadAccess.createOne({ data: { name: 'good' } }); + + // Valid name + const { body } = await graphQLRequest({ + query: `mutation ($id: ID!) { deleteBadAccess(where: { id: $id }) { id } }`, + variables: { id: item.id }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ deleteBadAccess: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.item.delete(). Got object', + path: ['deleteBadAccess'], + }, + ]); + + // Item should have its original name + const _items = await context.lists.BadAccess.findMany({ query: 'id name' }); + expect(_items.map(({ name }) => name)).toEqual(['good']); + }) + ); + test( 'createMany', runner(async ({ context }) => { diff --git a/tests/api-tests/access-control/mutations-list-operation.test.ts b/tests/api-tests/access-control/mutations-list-operation.test.ts new file mode 100644 index 00000000000..362c74e77e9 --- /dev/null +++ b/tests/api-tests/access-control/mutations-list-operation.test.ts @@ -0,0 +1,135 @@ +import { text } from '@keystone-next/keystone/fields'; +import { createSchema, list } from '@keystone-next/keystone'; +import { setupTestRunner } from '@keystone-next/keystone/testing'; +import { apiTestConfig, expectInternalServerError } from '../utils'; + +const runner = setupTestRunner({ + config: apiTestConfig({ + lists: createSchema({ + BadAccess: list({ + fields: { name: text({ isFilterable: true, isOrderable: true }) }, + access: { + operation: { + // @ts-ignore Intentionally return a filter for testing purposes + query: () => { + return { name: { not: { equals: 'bad' } } }; + }, + // @ts-ignore Intentionally return a filter for testing purposes + create: () => { + return { name: { not: { equals: 'bad' } } }; + }, + // @ts-ignore Intentionally return a filter for testing purposes + update: () => { + return { name: { not: { equals: 'bad' } } }; + }, + // @ts-ignore Intentionally return a filter for testing purposes + delete: async () => { + return { name: { not: { startsWtih: 'no delete' } } }; + }, + }, + }, + }), + }), + }), +}); + +describe('Access control - Item', () => { + test( + 'findMany - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + // Valid name + const { body } = await graphQLRequest({ + query: `query { badAccesses { id } }`, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ badAccesses: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.operation.query(). Got object', + path: ['badAccesses'], + }, + ]); + + // No items should exist + const _items = await context.sudo().lists.BadAccess.findMany({ query: 'id name' }); + expect(_items.map(({ name }) => name)).toEqual([]); + }) + ); + + test( + 'createOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + // Valid name + const { body } = await graphQLRequest({ + query: `mutation ($data: BadAccessCreateInput!) { createBadAccess(data: $data) { id } }`, + variables: { data: { name: 'better' } }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ createBadAccess: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.operation.create(). Got object', + path: ['createBadAccess'], + }, + ]); + + // No items should exist + const _users = await context.sudo().lists.BadAccess.findMany({ query: 'id name' }); + expect(_users.map(({ name }) => name)).toEqual([]); + }) + ); + + test( + 'updateOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + const item = await context.sudo().lists.BadAccess.createOne({ data: { name: 'good' } }); + + // Valid name + const { body } = await graphQLRequest({ + query: `mutation ($id: ID! $data: BadAccessUpdateInput!) { updateBadAccess(where: { id: $id }, data: $data) { id } }`, + variables: { id: item.id, data: { name: 'better' } }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ updateBadAccess: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.operation.update(). Got object', + path: ['updateBadAccess'], + }, + ]); + + // Item should have its original name + const _items = await context.sudo().lists.BadAccess.findMany({ query: 'id name' }); + expect(_items.map(({ name }) => name)).toEqual(['good']); + }) + ); + + test( + 'deleteOne - Bad function return value', + runner(async ({ context, graphQLRequest }) => { + const item = await context.sudo().lists.BadAccess.createOne({ data: { name: 'good' } }); + + // Valid name + const { body } = await graphQLRequest({ + query: `mutation ($id: ID!) { deleteBadAccess(where: { id: $id }) { id } }`, + variables: { id: item.id }, + }); + + // Returns null and throws an error + expect(body.data).toEqual({ deleteBadAccess: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Must return a Boolean from BadAccess.access.operation.delete(). Got object', + path: ['deleteBadAccess'], + }, + ]); + + // Item should have its original name + const _items = await context.sudo().lists.BadAccess.findMany({ query: 'id name' }); + expect(_items.map(({ name }) => name)).toEqual(['good']); + }) + ); +}); From 48be78d95e0f4c86faef4cc5ca12454e8f5c2f83 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 8 Sep 2021 16:08:12 +1000 Subject: [PATCH 015/135] Add tests for incomplete relationship data in update operations (#6499) --- .../nested-mutations/connect-many.test.ts | 30 +++++++++++++++++++ .../nested-mutations/connect-singular.test.ts | 28 +++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts index 7c4610410a4..2a9465a5b6e 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts @@ -297,6 +297,36 @@ describe('non-matching filter', () => { ]); }) ); + + test( + 'errors on incomplete data', + runner(async ({ context }) => { + // Create an item to link against + const createUser = await context.lists.User.createOne({ data: {} }); + + // Create an item that does the linking + const { data, errors } = await context.graphql.raw({ + query: ` + mutation { + updateUser( + where: { id: "${createUser.id}" }, + data: { notes: {} } + ) { + id + } + }`, + }); + + expect(data).toEqual({ updateUser: null }); + expectRelationshipError(errors, [ + { + path: ['updateUser'], + message: + 'You must provide at least one field in to-many relationship inputs but none were provided at User.notes', + }, + ]); + }) + ); }); describe('with access control', () => { diff --git a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts index 4409e871132..fb981c6e193 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts @@ -191,6 +191,34 @@ describe('non-matching filter', () => { ]); }) ); + + test( + 'errors on incomplete data', + runner(async ({ context }) => { + // Create an item to link against + const createEvent = await context.lists.Event.createOne({ data: {} }); + + // Create an item that does the linking + const { data, errors } = await context.graphql.raw({ + query: ` + mutation { + updateEvent( + where: { id: "${createEvent.id}" }, + data: { group: {} } + ) { + id + } + }`, + }); + expect(data).toEqual({ updateEvent: null }); + expectRelationshipError(errors, [ + { + path: ['updateEvent'], + message: `Nested to-one mutations must provide exactly one field if they're provided but Event.group did not`, + }, + ]); + }) + ); }); describe('with access control', () => { From 10c61bd44176ffa7d0e446c28fd9f12ed54790f0 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Thu, 9 Sep 2021 09:16:14 +1000 Subject: [PATCH 016/135] Fix bug in DB API with null values (#6500) --- .changeset/popular-goats-juggle.md | 5 +++++ .../keystone/src/lib/context/executeGraphQLFieldToRootVal.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/popular-goats-juggle.md diff --git a/.changeset/popular-goats-juggle.md b/.changeset/popular-goats-juggle.md new file mode 100644 index 00000000000..71215b9ee05 --- /dev/null +++ b/.changeset/popular-goats-juggle.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed a bug in `context.db.lists` API when finding items that don't exist. diff --git a/packages/keystone/src/lib/context/executeGraphQLFieldToRootVal.ts b/packages/keystone/src/lib/context/executeGraphQLFieldToRootVal.ts index 5c35e6ac33f..9e392c62e02 100644 --- a/packages/keystone/src/lib/context/executeGraphQLFieldToRootVal.ts +++ b/packages/keystone/src/lib/context/executeGraphQLFieldToRootVal.ts @@ -134,8 +134,8 @@ function getRootValGivenOutputType(originalType: OutputType, value: any): any { if (originalType instanceof GraphQLNonNull) { return getRootValGivenOutputType(originalType.ofType, value); } + if (value === null) return null; if (originalType instanceof GraphQLList) { - if (value === null) return null; return value.map((x: any) => getRootValGivenOutputType(originalType.ofType, x)); } return value[rawField]; From 398c085295d992658a9e7e22aae037f55528c258 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Thu, 9 Sep 2021 09:57:36 +1000 Subject: [PATCH 017/135] Add more tests for error cases when ordering/filtering (#6505) --- .changeset/twenty-buttons-teach.md | 6 + .../src/lib/core/queries/resolvers.ts | 2 + .../keystone/src/lib/core/where-inputs.ts | 6 +- tests/api-tests/queries/filters.test.ts | 124 +++++++++++++++++- tests/api-tests/queries/orderBy.test.ts | 32 ++++- 5 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 .changeset/twenty-buttons-teach.md diff --git a/.changeset/twenty-buttons-teach.md b/.changeset/twenty-buttons-teach.md new file mode 100644 index 00000000000..808e255e93c --- /dev/null +++ b/.changeset/twenty-buttons-teach.md @@ -0,0 +1,6 @@ +--- +'@keystone-next/keystone': patch +'@keystone-next/api-tests-legacy': patch +--- + +Improved error message for bad relationship filter inputs. diff --git a/packages/keystone/src/lib/core/queries/resolvers.ts b/packages/keystone/src/lib/core/queries/resolvers.ts index 2f9876761a2..9b23220a3de 100644 --- a/packages/keystone/src/lib/core/queries/resolvers.ts +++ b/packages/keystone/src/lib/core/queries/resolvers.ts @@ -147,6 +147,8 @@ async function resolveOrderBy( const resolve = field.input!.orderBy!.resolve; const resolvedValue = resolve ? await resolve(value, context) : value; if (field.dbField.kind === 'multi') { + // Note: no built-in field types support multi valued database fields *and* orderBy. + // This code path is only relevent to custom fields which fit that criteria. const keys = Object.keys(resolvedValue); if (keys.length !== 1) { throw new Error( diff --git a/packages/keystone/src/lib/core/where-inputs.ts b/packages/keystone/src/lib/core/where-inputs.ts index 5f36b42901c..77436b9bf10 100644 --- a/packages/keystone/src/lib/core/where-inputs.ts +++ b/packages/keystone/src/lib/core/where-inputs.ts @@ -86,10 +86,10 @@ export async function resolveWhereInput( Object.entries(value).map(async ([key, val]) => { if (val === null) { throw new Error( - `The key ${key} in a many relation filter cannot be set to null` + `The key "${key}" in a many relation filter cannot be set to null` ); } - return [key, await whereResolver(val as any)]; + return [key, await whereResolver(val)]; }) ) ); @@ -106,6 +106,8 @@ export async function resolveWhereInput( : value; if (ret === null) { if (field.dbField.kind === 'multi') { + // Note: no built-in field types support multi valued database fields *and* filtering. + // This code path is only relevent to custom fields which fit that criteria. throw new Error('multi db fields cannot return null from where input resolvers'); } return { [fieldKey]: null }; diff --git a/tests/api-tests/queries/filters.test.ts b/tests/api-tests/queries/filters.test.ts index 82023a1dee4..6efb773192f 100644 --- a/tests/api-tests/queries/filters.test.ts +++ b/tests/api-tests/queries/filters.test.ts @@ -1,22 +1,24 @@ import { text, relationship } from '@keystone-next/keystone/fields'; import { createSchema, list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig } from '../utils'; +import { apiTestConfig, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ lists: createSchema({ User: list({ fields: { - noDash: text({ isFilterable: true }), + noDash: text({ isFilterable: true, isOrderable: true }), single_dash: text({ isFilterable: true }), many_many_many_dashes: text({ isFilterable: true }), multi____dash: text({ isFilterable: true }), + email: text({ isIndexed: 'unique', isFilterable: true }), }, }), SecondaryList: list({ fields: { someUser: relationship({ ref: 'User', isFilterable: true }), + otherUsers: relationship({ ref: 'User', isFilterable: true, many: true }), }, }), }), @@ -68,3 +70,121 @@ describe('filtering on field name', () => { }) ); }); + +describe('filtering on relationships', () => { + test( + 'findMany throws error with null relationship query', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ secondaryLists(where: { otherUsers: null }) { id } }', + }); + // Returns null and throws an error + expect(body.data).toEqual({ secondaryLists: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'A many relation filter cannot be set to null', + path: ['secondaryLists'], + }, + ]); + }) + ); + + test( + 'findMany throws error with null relationship query value', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ secondaryLists(where: { otherUsers: { some: null } }) { id } }', + }); + // Returns null and throws an error + expect(body.data).toEqual({ secondaryLists: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'The key "some" in a many relation filter cannot be set to null', + path: ['secondaryLists'], + }, + ]); + }) + ); + + test( + 'findMany returns all items with empty relationship query value', + runner(async ({ context, graphQLRequest }) => { + await context.lists.SecondaryList.createOne({ + data: { otherUsers: { create: [{ noDash: 'a' }, { noDash: 'b' }] } }, + }); + const { body } = await graphQLRequest({ + query: + '{ secondaryLists(where: { otherUsers: {} }) { otherUsers(orderBy: { noDash: asc }) { noDash } } }', + }); + // Returns all the data + expect(body.errors).toBe(undefined); + expect(body.data).toEqual({ + secondaryLists: [{ otherUsers: [{ noDash: 'a' }, { noDash: 'b' }] }], + }); + }) + ); +}); + +describe('searching by unique fields', () => { + test( + 'findOne works on a unique text field', + runner(async ({ context }) => { + const item = await context.lists.User.createOne({ data: { email: 'test@example.com' } }); + const { data, errors } = await context.graphql.raw({ + query: '{ user(where: { email: "test@example.com" }) { id email } }', + }); + expect(errors).toBe(undefined); + expect(data).toEqual({ user: { id: item.id, email: 'test@example.com' } }); + }) + ); + + test( + 'findOne throws error with zero where values', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ query: '{ user(where: {}) { id email } }' }); + // Returns null and throws an error + expect(body.data).toEqual({ user: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Exactly one key must be passed in a unique where input but 0 keys were passed', + path: ['user'], + }, + ]); + }) + ); + + test( + 'findOne throws error with more than one where values', + runner(async ({ context, graphQLRequest }) => { + const item = await context.lists.User.createOne({ data: { email: 'test@example.com' } }); + const { body } = await graphQLRequest({ + query: `{ user(where: { id: "${item.id}" email: "test@example.com" }) { id email } }`, + }); + // Returns null and throws an error + expect(body.data).toEqual({ user: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'Exactly one key must be passed in a unique where input but 2 keys were passed', + path: ['user'], + }, + ]); + }) + ); + + test( + 'findOne throws error with null where values', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ user(where: { email: null }) { id email } }', + }); + // Returns null and throws an error + expect(body.data).toEqual({ user: null }); + expectInternalServerError(body.errors, false, [ + { + message: 'The unique value provided in a unique where input must not be null', + path: ['user'], + }, + ]); + }) + ); +}); diff --git a/tests/api-tests/queries/orderBy.test.ts b/tests/api-tests/queries/orderBy.test.ts index a2fbdd89626..972a71c5bcf 100644 --- a/tests/api-tests/queries/orderBy.test.ts +++ b/tests/api-tests/queries/orderBy.test.ts @@ -250,7 +250,7 @@ describe('Ordering by a single field', () => { ); test( - 'Multi filter, bad format throws error ', + 'Multi filter, multiple keys throws error ', runner(async ({ context, graphQLRequest }) => { await initialiseData({ context }); @@ -263,4 +263,34 @@ describe('Ordering by a single field', () => { ]); }) ); + + test( + 'Multi filter, zero keys throws error ', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + + const { body } = await graphQLRequest({ + query: 'query { users(orderBy: [{}]) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectBadUserInput(body.errors, [ + { path: ['users'], message: 'Only a single key must be passed to UserOrderByInput' }, + ]); + }) + ); + + test( + 'Multi filter, null values throws error ', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + + const { body } = await graphQLRequest({ + query: 'query { users(orderBy: [{ a: null }]) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectBadUserInput(body.errors, [ + { path: ['users'], message: 'null cannot be passed as an order direction' }, + ]); + }) + ); }); From 85d360a643a281c3c5041286ec50e02484853255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ol=C3=BAw=C3=A1set=C3=A8mi?= Date: Thu, 9 Sep 2021 02:27:30 +0100 Subject: [PATCH 018/135] fix: the error tabbable error when you click the popover (#6501) Co-authored-by: Thomas Walker --- design-system/website/pages/components/popover.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/design-system/website/pages/components/popover.tsx b/design-system/website/pages/components/popover.tsx index e45e8da6127..cc0baaaf1cb 100644 --- a/design-system/website/pages/components/popover.tsx +++ b/design-system/website/pages/components/popover.tsx @@ -1,8 +1,8 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx, Box } from '@keystone-ui/core'; import { Button } from '@keystone-ui/button'; +import { Box, jsx } from '@keystone-ui/core'; import { Popover } from '@keystone-ui/popover'; import { Page } from '../../components/Page'; @@ -20,7 +20,7 @@ export default function PopoverPage() { styles for height and width.

}> - + I'm in a popover! From 6a589bc4a1b3163e474b7bcaa031bf8f289edc29 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Thu, 9 Sep 2021 12:24:42 +1000 Subject: [PATCH 019/135] Fix item form submitting an invalid request after saving returns errors (#6509) --- .changeset/cool-chicken-taste.md | 5 +++++ .../admin-ui/pages/ItemPage/index.tsx | 19 +++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) create mode 100644 .changeset/cool-chicken-taste.md diff --git a/.changeset/cool-chicken-taste.md b/.changeset/cool-chicken-taste.md new file mode 100644 index 00000000000..5e83b0ad856 --- /dev/null +++ b/.changeset/cool-chicken-taste.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed item form submitting an invalid request after saving returns errors diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx index 8bc7a717d79..19e9f5ec6f9 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx @@ -92,20 +92,20 @@ function ItemForm({ const [state, setValue] = useState(() => { const value = deserializeValue(list.fields, itemGetter); - return { value, item: itemGetter.data }; + return { value, item: itemGetter }; }); if ( !loading && - state.item !== itemGetter.data && + state.item.data !== itemGetter.data && (itemGetter.errors || []).every(x => x.path?.length !== 1) ) { const value = deserializeValue(list.fields, itemGetter); - setValue({ value, item: itemGetter.data }); + setValue({ value, item: itemGetter }); } const { changedFields, dataForUpdate } = useChangedFieldsAndDataForUpdate( list.fields, - itemGetter, + state.item, state.value ); @@ -118,7 +118,7 @@ function ItemForm({ setForceValidation(newForceValidation); if (newForceValidation) return; - update({ variables: { data: dataForUpdate, id: itemGetter.get('id').data } }) + update({ variables: { data: dataForUpdate, id: state.item.get('id').data } }) // TODO -- Experimenting with less detail in the toasts, so the data lines are commented // out below. If we're happy with this, clean up the unused lines. .then(({ /* data, */ errors }) => { @@ -145,8 +145,8 @@ function ItemForm({ toasts.addToast({ title: 'Failed to update item', tone: 'negative', message: err.message }); }); }); - const labelFieldValue = itemGetter.data?.[list.labelField]; - const itemId = itemGetter.data?.id!; + const labelFieldValue = state.item.data?.[list.labelField]; + const itemId = state.item.data?.id!; return ( { - setValue({ item: itemGetter.data, value: deserializeValue(list.fields, itemGetter) }); + setValue(state => ({ + item: state.item, + value: deserializeValue(list.fields, state.item), + })); })} loading={loading} deleteButton={useMemo( From 3cfc2a3839142dd3ccdbf1dd86768257e9acc0dc Mon Sep 17 00:00:00 2001 From: Jed Watson Date: Thu, 9 Sep 2021 12:33:21 +1000 Subject: [PATCH 020/135] Add Margin to error messages in the Admin UI Item Form (#6508) * Add Margin to error messages in the Admin UI Item Form --- .changeset/early-snakes-arrive.md | 6 ++++++ design-system/packages/notice/src/Notice.tsx | 8 ++++---- .../src/admin-ui/components/GraphQLErrorNotice.tsx | 8 ++++++-- 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 .changeset/early-snakes-arrive.md diff --git a/.changeset/early-snakes-arrive.md b/.changeset/early-snakes-arrive.md new file mode 100644 index 00000000000..03be3f45223 --- /dev/null +++ b/.changeset/early-snakes-arrive.md @@ -0,0 +1,6 @@ +--- +"@keystone-ui/notice": minor +"@keystone-next/keystone": patch +--- + +Add Margin to error messages in the Admin UI Item Form diff --git a/design-system/packages/notice/src/Notice.tsx b/design-system/packages/notice/src/Notice.tsx index e9ddfa27121..a0c32451b2a 100644 --- a/design-system/packages/notice/src/Notice.tsx +++ b/design-system/packages/notice/src/Notice.tsx @@ -2,7 +2,7 @@ /** @jsx jsx */ import { ReactNode, useMemo } from 'react'; -import { jsx, makeId, useId, Stack } from '@keystone-ui/core'; +import { jsx, makeId, useId, Stack, MarginProps, Box } from '@keystone-ui/core'; import { AlertOctagonIcon } from '@keystone-ui/icons/icons/AlertOctagonIcon'; import { AlertCircleIcon } from '@keystone-ui/icons/icons/AlertCircleIcon'; import { AlertTriangleIcon } from '@keystone-ui/icons/icons/AlertTriangleIcon'; @@ -36,7 +36,7 @@ type NoticeProps = { tone?: ToneKey; title?: string; className?: string; -} /* TODO: & MarginProps */; +} & MarginProps; export const Notice = ({ actions, @@ -60,7 +60,7 @@ export const Notice = ({ return ( -
)}
- +
); }; diff --git a/packages/keystone/src/admin-ui/components/GraphQLErrorNotice.tsx b/packages/keystone/src/admin-ui/components/GraphQLErrorNotice.tsx index bc81cb8abc1..330f33ad8bc 100644 --- a/packages/keystone/src/admin-ui/components/GraphQLErrorNotice.tsx +++ b/packages/keystone/src/admin-ui/components/GraphQLErrorNotice.tsx @@ -10,11 +10,15 @@ type GraphQLErrorNoticeProps = { export function GraphQLErrorNotice({ errors, networkError }: GraphQLErrorNoticeProps) { if (networkError) { - return {networkError.message}; + return ( + + {networkError.message} + + ); } if (errors?.length) { return ( - + {errors.map(err => ( {err.message} ))} From 919eaa98439daa22db1bf01c8ad04e6f4ecf0d8c Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Thu, 9 Sep 2021 15:03:06 +1000 Subject: [PATCH 021/135] Remove changesets which were released in the hot-fix (#6511) --- .changeset/cool-chicken-taste.md | 5 ----- .changeset/curly-drinks-rush.md | 5 ----- .changeset/orange-rice-return.md | 5 ----- 3 files changed, 15 deletions(-) delete mode 100644 .changeset/cool-chicken-taste.md delete mode 100644 .changeset/curly-drinks-rush.md delete mode 100644 .changeset/orange-rice-return.md diff --git a/.changeset/cool-chicken-taste.md b/.changeset/cool-chicken-taste.md deleted file mode 100644 index 5e83b0ad856..00000000000 --- a/.changeset/cool-chicken-taste.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Fixed item form submitting an invalid request after saving returns errors diff --git a/.changeset/curly-drinks-rush.md b/.changeset/curly-drinks-rush.md deleted file mode 100644 index ec5aba43497..00000000000 --- a/.changeset/curly-drinks-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Fixed an issue where the incorrect value for the `operation` argument was passed into field-level access control functions. Keystone now correctly passes in `'read'` rather than the incorrect `'query'`. diff --git a/.changeset/orange-rice-return.md b/.changeset/orange-rice-return.md deleted file mode 100644 index f696c59f08c..00000000000 --- a/.changeset/orange-rice-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@keystone-next/keystone': patch ---- - -Fixed windows issues with new view resolver from #6414. From bf58744118320493325b3b48aadd007e12d5c680 Mon Sep 17 00:00:00 2001 From: Charles Date: Thu, 9 Sep 2021 15:22:59 +1000 Subject: [PATCH 022/135] Remove unqueryable lists from admin meta (#6512) * update createAdminMeta to not include lists with graphql querying disabled. also appy this to relationships to those omitted lists * chnageset * Update .changeset/twelve-apples-happen.md Co-authored-by: Tim Leslie Co-authored-by: Tim Leslie --- .changeset/twelve-apples-happen.md | 5 +++++ .../src/admin-ui/system/createAdminMeta.ts | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 .changeset/twelve-apples-happen.md diff --git a/.changeset/twelve-apples-happen.md b/.changeset/twelve-apples-happen.md new file mode 100644 index 00000000000..7dfc70943cd --- /dev/null +++ b/.changeset/twelve-apples-happen.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed lists with `graphql.omit: ['query']` causing issues in the Admin UI. diff --git a/packages/keystone/src/admin-ui/system/createAdminMeta.ts b/packages/keystone/src/admin-ui/system/createAdminMeta.ts index 299e2861095..2236abc9f56 100644 --- a/packages/keystone/src/admin-ui/system/createAdminMeta.ts +++ b/packages/keystone/src/admin-ui/system/createAdminMeta.ts @@ -16,8 +16,17 @@ export function createAdminMeta( views: [], }; + const omittedLists: string[] = []; + for (const [key, list] of Object.entries(initialisedLists)) { const listConfig = lists[key]; + if (list.graphql.isEnabled.query === false) { + // If graphql querying is disabled on the list, + // push the key into the ommittedLists array for use further down in the procedure and skip. + omittedLists.push(key); + + continue; + } // Default the labelField to `name`, `label`, or `title` if they exist; otherwise fall back to `id` const labelField = (listConfig.ui?.labelField as string | undefined) ?? @@ -80,6 +89,7 @@ export function createAdminMeta( } // Populate .fields array for (const [key, list] of Object.entries(initialisedLists)) { + if (omittedLists.includes(key)) continue; const searchFields = new Set(config.lists[key].ui?.searchFields ?? []); if (searchFields.has('id')) { throw new Error( @@ -98,6 +108,8 @@ export function createAdminMeta( } for (const [fieldKey, field] of Object.entries(list.fields)) { + // If the field is a relationship field and is related to an omitted list, skip. + if (field.dbField.kind === 'relation' && omittedLists.includes(field.dbField.list)) continue; // FIXME: Disabling this entirely for now until the Admin UI can properly // handle `omit: ['read']` correctly. if (field.graphql.isEnabled.read === false) continue; @@ -130,7 +142,13 @@ export function createAdminMeta( // we do this seperately to the above so that fields can check other fields to validate their config or etc. // (ofc they won't necessarily be able to see other field's fieldMeta) for (const [key, list] of Object.entries(initialisedLists)) { + if (list.graphql.isEnabled.query === false) continue; for (const fieldMetaRootVal of adminMetaRoot.listsByKey[key].fields) { + const dbField = list.fields[fieldMetaRootVal.path].dbField; + // If the field is a relationship field and is related to an omitted list, skip. + if (dbField.kind === 'relation' && omittedLists.includes(dbField.list)) { + continue; + } fieldMetaRootVal.fieldMeta = list.fields[fieldMetaRootVal.path].getAdminMeta?.(adminMetaRoot) ?? null; } From 4048991ba7db234a694287000beaf2ea052cd24e Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Thu, 9 Sep 2021 15:33:56 +1000 Subject: [PATCH 023/135] Remove isRequired and defaultValue from some fields (#6513) --- .changeset/forty-jobs-grow.md | 5 +++++ .changeset/real-jars-buy.md | 5 +++++ docs/pages/docs/apis/fields.mdx | 18 ++---------------- packages/cloudinary/src/index.ts | 6 ------ packages/cloudinary/src/test-fixtures.skip.ts | 1 + .../keystone/src/fields/types/file/index.ts | 18 ++++-------------- .../fields/types/file/tests/test-fixtures.ts | 1 + .../keystone/src/fields/types/image/index.ts | 18 ++++-------------- .../fields/types/image/tests/test-fixtures.ts | 1 + 9 files changed, 23 insertions(+), 50 deletions(-) create mode 100644 .changeset/forty-jobs-grow.md create mode 100644 .changeset/real-jars-buy.md diff --git a/.changeset/forty-jobs-grow.md b/.changeset/forty-jobs-grow.md new file mode 100644 index 00000000000..805deffff7b --- /dev/null +++ b/.changeset/forty-jobs-grow.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/cloudinary': major +--- + +Removed `isRequired` and `defaultValue` from the `cloudinaryImage` field. If you were using these options, the same behaviour can be re-created with the `validateInput` and `resolveInput` hooks respectively. diff --git a/.changeset/real-jars-buy.md b/.changeset/real-jars-buy.md new file mode 100644 index 00000000000..588974c8516 --- /dev/null +++ b/.changeset/real-jars-buy.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +Removed `isRequired` and `defaultValue` from the `image` and `file` fields. If you were using these options, the same behaviour can be re-created with the `validateInput` and `resolveInput` hooks respectively. diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index b8dff67d9a4..4ffbb2f6632 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -621,10 +621,6 @@ A `file` field represents a file of any type. See [`config.files`](./config#files) for details on how to configure your Keystone system with support for the `file` field type. -Options: - -- `isRequired` (default: `false`): If `true` then this field can never be set to `null`. - ```typescript import { config, createSchema, list } from '@keystone-next/keystone'; import { file } from '@keystone-next/keystone/fields'; @@ -633,9 +629,7 @@ export default config({ lists: createSchema({ ListName: list({ fields: { - repo: file({ - isRequired: true, - }), + repo: file(), /* ... */ }, }), @@ -651,10 +645,6 @@ An `image` field represents an image file, i.e. `.jpg`, `.png`, `.webp`, or `.gi See [`config.images`](./config#images) for details on how to configure your Keystone system with support for the `image` field type. -Options: - -- `isRequired` (default: `false`): If `true` then this field can never be set to `null`. - ```typescript import { config, createSchema, list } from '@keystone-next/keystone'; import { image } from '@keystone-next/keystone/fields'; @@ -663,9 +653,7 @@ export default config({ lists: createSchema({ ListName: list({ fields: { - avatar: image({ - isRequired: true, - }), + avatar: image(), /* ... */ }, }), @@ -722,7 +710,6 @@ export default config({ (coming soon) -- `isRequired` (default: `false`): If `true` then this field can never be set to `null`. - `cloudinary`: Configuration for the connected Cloudinary account. - `cloudName` - `apiKey` @@ -738,7 +725,6 @@ export default config({ ListName: list({ fields: { fieldName: cloudinaryImage({ - isRequired: true, cloudinary: { cloudName: process.env.CLOUDINARY_CLOUD_NAME, apiKey: process.env.CLOUDINARY_API_KEY, diff --git a/packages/cloudinary/src/index.ts b/packages/cloudinary/src/index.ts index cd29d08786e..38db4e66cf2 100644 --- a/packages/cloudinary/src/index.ts +++ b/packages/cloudinary/src/index.ts @@ -5,7 +5,6 @@ import { FieldTypeFunc, jsonFieldTypePolyfilledForSQLite, graphql, - FieldDefaultValue, } from '@keystone-next/keystone/types'; import { FileUpload } from 'graphql-upload'; import cuid from 'cuid'; @@ -23,8 +22,6 @@ type StoredFile = { type CloudinaryImageFieldConfig = CommonFieldConfig & { - isRequired?: boolean; - defaultValue?: FieldDefaultValue; cloudinary: { cloudName: string; apiKey: string; @@ -111,8 +108,6 @@ const outputType = graphql.object()({ export const cloudinaryImage = ({ cloudinary, - isRequired, - defaultValue, ...config }: CloudinaryImageFieldConfig): FieldTypeFunc => meta => { @@ -170,6 +165,5 @@ export const cloudinaryImage = }, }), views: path.join(path.dirname(__dirname), 'views'), - __legacy: { isRequired, defaultValue }, }); }; diff --git a/packages/cloudinary/src/test-fixtures.skip.ts b/packages/cloudinary/src/test-fixtures.skip.ts index a7aac8c2dbe..8d7477accbf 100644 --- a/packages/cloudinary/src/test-fixtures.skip.ts +++ b/packages/cloudinary/src/test-fixtures.skip.ts @@ -30,6 +30,7 @@ const prepareFile = (_filePath: string) => { export const name = 'CloudinaryImage'; export const typeFunction = cloudinaryImage; export const supportsUnique = false; +export const skipRequiredTest = true; export const fieldName = 'image'; export const subfieldName = 'originalFilename'; diff --git a/packages/keystone/src/fields/types/file/index.ts b/packages/keystone/src/fields/types/file/index.ts index 734b51818d3..7288cce8db4 100644 --- a/packages/keystone/src/fields/types/file/index.ts +++ b/packages/keystone/src/fields/types/file/index.ts @@ -7,16 +7,12 @@ import { BaseGeneratedListTypes, KeystoneContext, FileData, - FieldDefaultValue, } from '../../../types'; import { resolveView } from '../../resolve-view'; import { getFileRef } from './utils'; export type FileFieldConfig = - CommonFieldConfig & { - isRequired?: boolean; - defaultValue?: FieldDefaultValue; - }; + CommonFieldConfig; const FileFieldInput = graphql.inputObject({ name: 'FileFieldInput', @@ -84,11 +80,9 @@ async function inputResolver(data: FileFieldInputType, context: KeystoneContext) } export const file = - ({ - isRequired, - defaultValue, - ...config - }: FileFieldConfig = {}): FieldTypeFunc => + ( + config: FileFieldConfig = {} + ): FieldTypeFunc => () => { if ((config as any).isIndexed === 'unique') { throw Error("isIndexed: 'unique' is not a supported option for field type file"); @@ -123,9 +117,5 @@ export const file = }), unreferencedConcreteInterfaceImplementations: [LocalFileFieldOutput], views: resolveView('file/views'), - __legacy: { - isRequired, - defaultValue, - }, }); }; diff --git a/packages/keystone/src/fields/types/file/tests/test-fixtures.ts b/packages/keystone/src/fields/types/file/tests/test-fixtures.ts index 4a6b898d317..5e8d11f22c5 100644 --- a/packages/keystone/src/fields/types/file/tests/test-fixtures.ts +++ b/packages/keystone/src/fields/types/file/tests/test-fixtures.ts @@ -26,6 +26,7 @@ export const createReturnedValue = 3250; export const updateReturnedValue = 5562; export const supportsUnique = false; +export const skipRequiredTest = true; export const fieldName = 'secretFile'; export const subfieldName = 'filesize'; diff --git a/packages/keystone/src/fields/types/image/index.ts b/packages/keystone/src/fields/types/image/index.ts index fe601665885..f2ecd8559cc 100644 --- a/packages/keystone/src/fields/types/image/index.ts +++ b/packages/keystone/src/fields/types/image/index.ts @@ -1,7 +1,6 @@ import { FileUpload } from 'graphql-upload'; import { BaseGeneratedListTypes, - FieldDefaultValue, fieldType, FieldTypeFunc, CommonFieldConfig, @@ -14,10 +13,7 @@ import { resolveView } from '../../resolve-view'; import { getImageRef, SUPPORTED_IMAGE_EXTENSIONS } from './utils'; export type ImageFieldConfig = - CommonFieldConfig & { - defaultValue?: FieldDefaultValue; - isRequired?: boolean; - }; + CommonFieldConfig; const ImageExtensionEnum = graphql.enum({ name: 'ImageExtension', @@ -96,11 +92,9 @@ function isValidImageExtension(extension: string): extension is ImageExtension { } export const image = - ({ - isRequired, - defaultValue, - ...config - }: ImageFieldConfig = {}): FieldTypeFunc => + ( + config: ImageFieldConfig = {} + ): FieldTypeFunc => () => { if ((config as any).isIndexed === 'unique') { throw Error("isIndexed: 'unique' is not a supported option for field type image"); @@ -142,9 +136,5 @@ export const image = }), unreferencedConcreteInterfaceImplementations: [LocalImageFieldOutput], views: resolveView('image/views'), - __legacy: { - isRequired, - defaultValue, - }, }); }; diff --git a/packages/keystone/src/fields/types/image/tests/test-fixtures.ts b/packages/keystone/src/fields/types/image/tests/test-fixtures.ts index 04d89b592dc..dac21afee35 100644 --- a/packages/keystone/src/fields/types/image/tests/test-fixtures.ts +++ b/packages/keystone/src/fields/types/image/tests/test-fixtures.ts @@ -27,6 +27,7 @@ export const createReturnedValue = 'jpg'; export const updateReturnedValue = createReturnedValue; export const supportsUnique = false; +export const skipRequiredTest = true; export const fieldName = 'avatar'; export const subfieldName = 'extension'; From 79e2cc3aa79a90358a6ce1281a8ad5f5632ac185 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Thu, 9 Sep 2021 15:52:22 +1000 Subject: [PATCH 024/135] Relationship field updates (#6514) --- .changeset/rich-terms-love.md | 5 +++ examples-staging/ecommerce/schemas/Product.ts | 11 +++++- examples-staging/roles/schema.ts | 13 +++++-- examples/default-values/schema.ts | 24 +++++++----- .../src/fields/types/relationship/index.ts | 37 ++++++------------- .../relationship/tests/implementation.test.ts | 11 ------ 6 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 .changeset/rich-terms-love.md diff --git a/.changeset/rich-terms-love.md b/.changeset/rich-terms-love.md new file mode 100644 index 00000000000..79105b9524f --- /dev/null +++ b/.changeset/rich-terms-love.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +Removed `defaultValue` and the undocumented `withMeta` option from the `relationship` field. To re-create `defaultValue`, you can use `resolveInput` though note that if you're using autoincrement ids, you need to return the id as number, not a string like you would provide to GraphQL, e.g. `{ connect: { id: 1 } }` rather than `{ connect: { id: "1" } }`. If you were using `withMeta: false`, please open an issue with your use case. diff --git a/examples-staging/ecommerce/schemas/Product.ts b/examples-staging/ecommerce/schemas/Product.ts index fa0fce7b43f..0ce607c0206 100644 --- a/examples-staging/ecommerce/schemas/Product.ts +++ b/examples-staging/ecommerce/schemas/Product.ts @@ -44,8 +44,15 @@ export const Product = list({ price: integer(), user: relationship({ ref: 'User.products', - defaultValue: ({ context }) => - context.session?.itemId ? { connect: { id: context.session?.itemId } } : null, + hooks: { + resolveInput({ operation, resolvedData, context }) { + // Default to the currently logged in user on create. + if (operation === 'create' && !resolvedData.user && context.session?.itemId) { + return { connect: { id: context.session?.itemId } }; + } + return resolvedData.user; + }, + }, }), }, }); diff --git a/examples-staging/roles/schema.ts b/examples-staging/roles/schema.ts index fcf330ea0f0..cafa0c91367 100644 --- a/examples-staging/roles/schema.ts +++ b/examples-staging/roles/schema.ts @@ -64,9 +64,16 @@ export const lists = createSchema({ fieldMode: args => (permissions.canManageAllTodos(args) ? 'edit' : 'read'), }, }, - // Always default new todo items to the current user; this is important because users - // without canManageAllTodos don't see this field when creating new items - defaultValue: ({ context: { session } }) => ({ connect: { id: session.itemId } }), + hooks: { + resolveInput({ operation, resolvedData, context }) { + if (operation === 'create' && !resolvedData.assignedTo) { + // Always default new todo items to the current user; this is important because users + // without canManageAllTodos don't see this field when creating new items + return { connect: { id: context.session.itemId } }; + } + return resolvedData.assignedTo; + }, + }, }), }, }), diff --git a/examples/default-values/schema.ts b/examples/default-values/schema.ts index bb1e533e634..f588c36b1c0 100644 --- a/examples/default-values/schema.ts +++ b/examples/default-values/schema.ts @@ -27,15 +27,21 @@ export const lists = createSchema({ assignedTo: relationship({ ref: 'Person.tasks', many: false, - // Dynamic default: Find an anonymous user and assign the task to them - defaultValue: async ({ context }) => { - const anonymous = await context.lists.Person.findMany({ - where: { name: { equals: 'Anonymous' } }, - }); - if (anonymous.length > 0) { - return { connect: { id: anonymous[0].id } }; - } - // If we don't have an anonymous user return undefined so as not to apply any default + hooks: { + // Dynamic default: Find an anonymous user and assign the task to them + async resolveInput({ context, operation, resolvedData }) { + if (operation === 'create' && !resolvedData.assignedTo) { + const anonymous = await context.db.lists.Person.findMany({ + where: { name: { equals: 'Anonymous' } }, + }); + if (anonymous.length > 0) { + return { connect: { id: anonymous[0].id } }; + } + } + // If we don't have an anonymous user we return the value + // that was passed in(which might be nothing) so as not to apply any default + return resolvedData.assignedTo; + }, }, }), // Dynamic default: We set the due date to be 7 days in the future diff --git a/packages/keystone/src/fields/types/relationship/index.ts b/packages/keystone/src/fields/types/relationship/index.ts index ab74ff7ca5d..1eee79bf015 100644 --- a/packages/keystone/src/fields/types/relationship/index.ts +++ b/packages/keystone/src/fields/types/relationship/index.ts @@ -5,7 +5,6 @@ import { fieldType, graphql, AdminMetaRootVal, - FieldDefaultValue, } from '../../../types'; import { resolveView } from '../../resolve-view'; @@ -56,16 +55,12 @@ export type RelationshipFieldConfig, TGeneratedListTypes>; - withMeta?: boolean; } & (SelectDisplayConfig | CardsDisplayConfig | CountDisplayConfig); export const relationship = ({ many = false, ref, - defaultValue, - withMeta = true, ...config }: RelationshipFieldConfig): FieldTypeFunc => meta => { @@ -173,23 +168,18 @@ export const relationship = return value.findMany(args); }, }), - extraOutputFields: withMeta - ? { - [`${meta.fieldKey}Count`]: graphql.field({ - type: graphql.Int, - args: { - where: graphql.arg({ type: graphql.nonNull(listTypes.where), defaultValue: {} }), - }, - resolve({ value }, args) { - return value.count({ - where: args.where, - }); - }, - }), - } - : {}, - __legacy: { - defaultValue, + extraOutputFields: { + [`${meta.fieldKey}Count`]: graphql.field({ + type: graphql.Int, + args: { + where: graphql.arg({ type: graphql.nonNull(listTypes.where), defaultValue: {} }), + }, + resolve({ value }, args) { + return value.count({ + where: args.where, + }); + }, + }), }, }); } @@ -227,8 +217,5 @@ export const relationship = return value(); }, }), - __legacy: { - defaultValue, - }, }); }; diff --git a/packages/keystone/src/fields/types/relationship/tests/implementation.test.ts b/packages/keystone/src/fields/types/relationship/tests/implementation.test.ts index ce9228f1ed5..beff46967a3 100644 --- a/packages/keystone/src/fields/types/relationship/tests/implementation.test.ts +++ b/packages/keystone/src/fields/types/relationship/tests/implementation.test.ts @@ -126,17 +126,6 @@ describe('Type Generation', () => { foo(where: ZipWhereInput! = {}, orderBy: [ZipOrderByInput!]! = [], take: Int, skip: Int! = 0): [Zip!] fooCount(where: ZipWhereInput! = {}): Int }" -`); - }); - - test('to-many relationships can have meta disabled', () => { - const schema = getSchema(relationship({ many: true, ref: 'Zip', withMeta: false })); - - expect(printType(schema.getType('Test')!)).toMatchInlineSnapshot(` -"type Test { - id: ID! - foo(where: ZipWhereInput! = {}, orderBy: [ZipOrderByInput!]! = [], take: Int, skip: Int! = 0): [Zip!] -}" `); }); }); From 0218a421576fb3ceb38eb5f38223a9ef0af4c4d2 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Fri, 10 Sep 2021 09:16:31 +1000 Subject: [PATCH 025/135] Remove deprecated config.db.adapter option (#6518) --- .changeset/gold-pillows-look.md | 5 ++++ packages/keystone/src/artifacts.ts | 2 +- packages/keystone/src/lib/createSystem.ts | 4 +-- packages/keystone/src/types/config/index.ts | 28 ++------------------- tests/api-tests/utils.ts | 2 +- 5 files changed, 11 insertions(+), 30 deletions(-) create mode 100644 .changeset/gold-pillows-look.md diff --git a/.changeset/gold-pillows-look.md b/.changeset/gold-pillows-look.md new file mode 100644 index 00000000000..9c4fa7233b5 --- /dev/null +++ b/.changeset/gold-pillows-look.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +Removed the deprecated `config.db.adapter` option. Please use `config.db.provider` to indicate the database provider for your system. diff --git a/packages/keystone/src/artifacts.ts b/packages/keystone/src/artifacts.ts index 0cafb47c102..f30740c5805 100644 --- a/packages/keystone/src/artifacts.ts +++ b/packages/keystone/src/artifacts.ts @@ -139,7 +139,7 @@ const makeVercelIncludeTheSQLiteDB = ( directoryOfFileToBeWritten: string, config: KeystoneConfig ) => { - if (config.db.adapter === 'prisma_sqlite' || config.db.provider === 'sqlite') { + if (config.db.provider === 'sqlite') { const sqliteDbAbsolutePath = path.resolve(cwd, config.db.url.replace('file:', '')); return `import path from 'path'; diff --git a/packages/keystone/src/lib/createSystem.ts b/packages/keystone/src/lib/createSystem.ts index 7c3da9899ba..bca53cf3b2b 100644 --- a/packages/keystone/src/lib/createSystem.ts +++ b/packages/keystone/src/lib/createSystem.ts @@ -6,9 +6,9 @@ import { makeCreateContext } from './context/createContext'; import { initialiseLists } from './core/types-for-lists'; export function getDBProvider(db: KeystoneConfig['db']): DatabaseProvider { - if (db.adapter === 'prisma_postgresql' || db.provider === 'postgresql') { + if (db.provider === 'postgresql') { return 'postgresql'; - } else if (db.adapter === 'prisma_sqlite' || db.provider === 'sqlite') { + } else if (db.provider === 'sqlite') { return 'sqlite'; } else { throw new Error( diff --git a/packages/keystone/src/types/config/index.ts b/packages/keystone/src/types/config/index.ts index 3607521cbbb..7334e5ae2a6 100644 --- a/packages/keystone/src/types/config/index.ts +++ b/packages/keystone/src/types/config/index.ts @@ -57,32 +57,8 @@ export type DatabaseConfig = { useMigrations?: boolean; enableLogging?: boolean; idField?: IdFieldConfig; -} & ( - | ( - | { - /** @deprecated The `adapter` option is deprecated. Please use `{ provider: 'postgresql' }` */ - adapter: 'prisma_postgresql'; - provider?: undefined; - } - | { - /** @deprecated The `adapter` option is deprecated. Please use `{ provider: 'postgresql' }` */ - adapter?: undefined; - provider: 'postgresql'; - } - ) - | ( - | { - /** @deprecated The `adapter` option is deprecated. Please use `{ provider: 'sqlite' }` */ - adapter: 'prisma_sqlite'; - provider?: undefined; - } - | { - /** @deprecated The `adapter` option is deprecated. Please use `{ provider: 'sqlite' }` */ - adapter?: undefined; - provider: 'sqlite'; - } - ) -); + provider: 'postgresql' | 'sqlite'; +}; // config.ui diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 8f2657ed107..49f80b807db 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -5,7 +5,7 @@ import { KeystoneConfig, DatabaseProvider } from '@keystone-next/keystone/types' // export it from `@keystone-next/keystone/testing`. export const apiTestConfig = ( config: Omit & { - db?: Omit; + db?: Omit; } ): KeystoneConfig => ({ ...config, From e84f8f6550cff4fbca69982e0371d787e67c8915 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Fri, 10 Sep 2021 11:25:56 +1000 Subject: [PATCH 026/135] Remove unused BaseKeystone type (#6521) --- .changeset/silver-boats-draw.md | 5 +++++ packages/keystone/src/types/base.ts | 8 -------- packages/keystone/src/types/index.ts | 1 - 3 files changed, 5 insertions(+), 9 deletions(-) create mode 100644 .changeset/silver-boats-draw.md delete mode 100644 packages/keystone/src/types/base.ts diff --git a/.changeset/silver-boats-draw.md b/.changeset/silver-boats-draw.md new file mode 100644 index 00000000000..9bd4e7e5247 --- /dev/null +++ b/.changeset/silver-boats-draw.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Removed unused `BaseKeystone` type. diff --git a/packages/keystone/src/types/base.ts b/packages/keystone/src/types/base.ts deleted file mode 100644 index bd0b54ffcde..00000000000 --- a/packages/keystone/src/types/base.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { CreateContext } from './core'; - -// TODO: don't call this thing BaseKeystone -export type BaseKeystone = { - connect: () => Promise; - disconnect: () => Promise; - createContext: CreateContext; -}; diff --git a/packages/keystone/src/types/index.ts b/packages/keystone/src/types/index.ts index 94b4e12f993..10f47ab9a30 100644 --- a/packages/keystone/src/types/index.ts +++ b/packages/keystone/src/types/index.ts @@ -3,7 +3,6 @@ export * from './config'; export * from './utils'; export * from './session'; export * from './admin-meta'; -export * from './base'; export * from './context'; export * from './next-fields'; export * as filters from './filters'; From 1b0a2f516d7d9ffce2e470dcd9ea870a3274500b Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Fri, 10 Sep 2021 11:50:48 +1000 Subject: [PATCH 027/135] Consolidate concept of sudo internally (#6520) --- .changeset/nine-coins-yawn.md | 5 ++++ .changeset/short-jokes-hug.md | 6 +++++ docs/pages/docs/apis/context.mdx | 3 --- packages/auth/src/index.ts | 2 +- .../node-api.ts | 2 +- .../keystone/src/lib/context/createContext.ts | 26 ++++++++----------- packages/keystone/src/lib/createSystem.ts | 26 ++++++++++++------- packages/keystone/src/types/context.ts | 1 - packages/keystone/src/types/core.ts | 2 +- 9 files changed, 42 insertions(+), 31 deletions(-) create mode 100644 .changeset/nine-coins-yawn.md create mode 100644 .changeset/short-jokes-hug.md diff --git a/.changeset/nine-coins-yawn.md b/.changeset/nine-coins-yawn.md new file mode 100644 index 00000000000..8e2863e6c54 --- /dev/null +++ b/.changeset/nine-coins-yawn.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +Removed `context.schemaName` from the `context` object. This value was an internal API which is no longer required. diff --git a/.changeset/short-jokes-hug.md b/.changeset/short-jokes-hug.md new file mode 100644 index 00000000000..ec35083ed2c --- /dev/null +++ b/.changeset/short-jokes-hug.md @@ -0,0 +1,6 @@ +--- +'@keystone-next/auth': major +'@keystone-next/keystone': major +--- + +Renamed the `skipAccessControl` argument to `createContext` to `sudo` for consistency with `context.sudo()`. diff --git a/docs/pages/docs/apis/context.mdx b/docs/pages/docs/apis/context.mdx index a413b2a6362..ba21a94ad39 100644 --- a/docs/pages/docs/apis/context.mdx +++ b/docs/pages/docs/apis/context.mdx @@ -57,7 +57,6 @@ context = { // Internal state totalResults, maxTotalResults, - schemaName, // Deprecated gqlNames, @@ -155,8 +154,6 @@ These properties are used internally by Keystone and generally do not need to be `maxTotalResults`: The maximum number of results which can be returned before a query limit error is triggered. See [`config.graphql.queryLimits`](./apis/config#graphql). -`schemaName`: The internal name used by Keystone to refer to the GraphQL schema. - ### Deprecated The following properties are deprecated and should not be used. diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index 89dd87a936b..b9c1d1dffce 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -227,7 +227,7 @@ export function createAuth({ ...sessionStrategy, get: async ({ req, createContext }) => { const session = await get({ req, createContext }); - const sudoContext = createContext({}).sudo(); + const sudoContext = createContext({ sudo: true }); if ( !session || !session.listKey || diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts index 4d8357a2dc4..cd16bff03d1 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/node-api.ts @@ -6,5 +6,5 @@ export function createListsAPI(config: KeystoneConfig, prismaClient: any) { const { getKeystone } = createSystem(initConfig(config)); const keystone = getKeystone(prismaClient); keystone.connect(); - return keystone.createContext().sudo().lists; + return keystone.createContext({ sudo: true }).lists; } diff --git a/packages/keystone/src/lib/context/createContext.ts b/packages/keystone/src/lib/context/createContext.ts index 3f625fe4b33..9220e111692 100644 --- a/packages/keystone/src/lib/context/createContext.ts +++ b/packages/keystone/src/lib/context/createContext.ts @@ -16,14 +16,14 @@ import { createFilesContext } from './createFilesContext'; export function makeCreateContext({ graphQLSchema, - internalSchema, + sudoGraphQLSchema, prismaClient, gqlNamesByList, config, lists, }: { graphQLSchema: GraphQLSchema; - internalSchema: GraphQLSchema; + sudoGraphQLSchema: GraphQLSchema; config: KeystoneConfig; prismaClient: PrismaClient; gqlNamesByList: Record; @@ -44,23 +44,21 @@ export function makeCreateContext({ publicDbApiFactories[listKey] = getDbAPIFactory(gqlNames, graphQLSchema); } - const internalDbApiFactories: Record> = {}; + const sudoDbApiFactories: Record> = {}; for (const [listKey, gqlNames] of Object.entries(gqlNamesByList)) { - internalDbApiFactories[listKey] = getDbAPIFactory(gqlNames, internalSchema); + sudoDbApiFactories[listKey] = getDbAPIFactory(gqlNames, sudoGraphQLSchema); } const createContext = ({ sessionContext, - skipAccessControl = false, + sudo = false, req, - schemaName = 'public', }: { sessionContext?: SessionContext; - skipAccessControl?: boolean; + sudo?: Boolean; req?: IncomingMessage; - schemaName?: 'public' | 'internal'; } = {}): KeystoneContext => { - const schema = schemaName === 'public' ? graphQLSchema : internalSchema; + const schema = sudo ? sudoGraphQLSchema : graphQLSchema; const rawGraphQL: KeystoneGraphQLAPI['raw'] = ({ query, variables }) => { const source = typeof query === 'string' ? query : print(query); @@ -78,20 +76,18 @@ export function makeCreateContext({ const dbAPI: KeystoneContext['db']['lists'] = {}; const itemAPI: KeystoneContext['lists'] = {}; const contextToReturn: KeystoneContext = { - schemaName, db: { lists: dbAPI }, lists: itemAPI, totalResults: 0, prisma: prismaClient, graphql: { raw: rawGraphQL, run: runGraphQL, schema }, maxTotalResults: config.graphql?.queryLimits?.maxTotalResults ?? Infinity, - sudo: () => - createContext({ sessionContext, skipAccessControl: true, req, schemaName: 'internal' }), - exitSudo: () => createContext({ sessionContext, skipAccessControl: false, req }), + sudo: () => createContext({ sessionContext, sudo: true, req }), + exitSudo: () => createContext({ sessionContext, sudo: false, req }), withSession: session => createContext({ sessionContext: { ...sessionContext, session } as SessionContext, - skipAccessControl, + sudo, req, }), req, @@ -106,7 +102,7 @@ export function makeCreateContext({ contextToReturn.experimental = { initialisedLists: lists }; } - const dbAPIFactories = schemaName === 'public' ? publicDbApiFactories : internalDbApiFactories; + const dbAPIFactories = sudo ? sudoDbApiFactories : publicDbApiFactories; for (const listKey of Object.keys(gqlNamesByList)) { dbAPI[listKey] = dbAPIFactories[listKey](contextToReturn); itemAPI[listKey] = itemAPIForList(listKey, contextToReturn, dbAPI[listKey]); diff --git a/packages/keystone/src/lib/createSystem.ts b/packages/keystone/src/lib/createSystem.ts index bca53cf3b2b..456d5a4b60c 100644 --- a/packages/keystone/src/lib/createSystem.ts +++ b/packages/keystone/src/lib/createSystem.ts @@ -6,18 +6,26 @@ import { makeCreateContext } from './context/createContext'; import { initialiseLists } from './core/types-for-lists'; export function getDBProvider(db: KeystoneConfig['db']): DatabaseProvider { - if (db.provider === 'postgresql') { - return 'postgresql'; - } else if (db.provider === 'sqlite') { - return 'sqlite'; - } else { + if (!['postgresql', 'sqlite'].includes(db.provider)) { throw new Error( 'Invalid db configuration. Please specify db.provider as either "sqlite" or "postgresql"' ); } + return db.provider; } -function getInternalGraphQLSchema(config: KeystoneConfig, provider: DatabaseProvider) { +function getSudoGraphQLSchema(config: KeystoneConfig, provider: DatabaseProvider) { + // This function creates a GraphQLSchema based on a modified version of the provided config. + // The modifications are: + // * All list level access control is disabled + // * All field level access control is disabled + // * All graphql.omit configuration is disabled + // * All fields are explicitly made filterable and orderable + // + // These changes result in a schema without any restrictions on the CRUD + // operations that can be run. + // + // The resulting schema is used as the GraphQL schema when calling `context.sudo()`. const transformedConfig: KeystoneConfig = { ...config, lists: Object.fromEntries( @@ -63,7 +71,7 @@ export function createSystem(config: KeystoneConfig) { const graphQLSchema = createGraphQLSchema(config, lists, adminMeta); - const internalGraphQLSchema = getInternalGraphQLSchema(config, provider); + const sudoGraphQLSchema = getSudoGraphQLSchema(config, provider); return { graphQLSchema, @@ -83,7 +91,7 @@ export function createSystem(config: KeystoneConfig) { const createContext = makeCreateContext({ graphQLSchema, - internalSchema: internalGraphQLSchema, + sudoGraphQLSchema, config, prismaClient, gqlNamesByList: Object.fromEntries( @@ -95,7 +103,7 @@ export function createSystem(config: KeystoneConfig) { return { async connect() { await prismaClient.$connect(); - const context = createContext({ skipAccessControl: true, schemaName: 'internal' }); + const context = createContext({ sudo: true }); await config.db.onConnect?.(context); }, async disconnect() { diff --git a/packages/keystone/src/types/context.ts b/packages/keystone/src/types/context.ts index 606b4a90f21..22dc92c66fe 100644 --- a/packages/keystone/src/types/context.ts +++ b/packages/keystone/src/types/context.ts @@ -18,7 +18,6 @@ export type KeystoneContext = { images: ImagesContext | undefined; totalResults: number; maxTotalResults: number; - schemaName: 'public' | 'internal'; /** @deprecated */ gqlNames: (listKey: string) => GqlNames; experimental?: { diff --git a/packages/keystone/src/types/core.ts b/packages/keystone/src/types/core.ts index c62f91b0f79..4dc9d53e012 100644 --- a/packages/keystone/src/types/core.ts +++ b/packages/keystone/src/types/core.ts @@ -17,7 +17,7 @@ export type FieldDefaultValue; - skipAccessControl?: boolean; + sudo?: boolean; req?: IncomingMessage; }) => KeystoneContext; From 9f0a4cc1f6d5133e92a0d326e285152d18689173 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Fri, 10 Sep 2021 12:05:34 +1000 Subject: [PATCH 028/135] Optimise item view field mode item fetching (#6523) --- .changeset/violet-lions-attend.md | 5 +++ .../src/admin-ui/system/getAdminMetaSchema.ts | 38 +++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 .changeset/violet-lions-attend.md diff --git a/.changeset/violet-lions-attend.md b/.changeset/violet-lions-attend.md new file mode 100644 index 00000000000..b729176ffdb --- /dev/null +++ b/.changeset/violet-lions-attend.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +The item view page will only fetch the item once to determine the field modes rather than once per field. diff --git a/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts b/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts index e9163e1d7c5..711c9b5f9ae 100644 --- a/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts +++ b/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts @@ -8,6 +8,7 @@ import { AdminMetaRootVal, ListMetaRootVal, FieldMetaRootVal, + ItemRootValue, } from '../../types'; import { InitialisedList } from '../../lib/core/types-for-lists'; @@ -154,9 +155,10 @@ export function getAdminMetaSchema({ ) { return 'read'; } - const item = await context - .sudo() - .db.lists[rootVal.listKey].findOne({ where: { id: rootVal.itemId } }); + const item = await fetchItemForItemViewFieldMode(context)( + rootVal.listKey, + rootVal.itemId + ); const listConfig = config.lists[rootVal.listKey]; const sessionFunction = lists[rootVal.listKey].fields[rootVal.fieldPath].ui?.itemView?.fieldMode ?? @@ -340,3 +342,33 @@ function runMaybeFunction( } return sessionFunction; } + +const fetchItemForItemViewFieldMode = extendContext(context => { + type ListKey = string; + type ItemId = string; + const lists = new Map>>(); + return (listKey: ListKey, id: ItemId) => { + if (!lists.has(listKey)) { + lists.set(listKey, new Map()); + } + const items = lists.get(listKey)!; + if (items.has(id)) { + return items.get(id)!; + } + let promise = context.db.lists[listKey].findOne({ where: { id } }); + items.set(id, promise); + return promise; + }; +}); + +function extendContext(cb: (context: KeystoneContext) => T) { + const cache = new WeakMap(); + return (context: KeystoneContext) => { + if (cache.has(context)) { + return cache.get(context)!; + } + const result = cb(context); + cache.set(context, result); + return result; + }; +} From d9e18613a4136f1c1201a197e47d9d4bde292cd2 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Fri, 10 Sep 2021 12:23:40 +1000 Subject: [PATCH 029/135] Only check for a valid db.provider once (#6524) --- .changeset/dirty-apricots-swim.md | 5 +++++ packages/keystone/src/artifacts.ts | 11 +++-------- packages/keystone/src/lib/config/initConfig.ts | 6 ++++++ packages/keystone/src/lib/createGraphQLSchema.ts | 4 +--- packages/keystone/src/lib/createSystem.ts | 16 +++------------- 5 files changed, 18 insertions(+), 24 deletions(-) create mode 100644 .changeset/dirty-apricots-swim.md diff --git a/.changeset/dirty-apricots-swim.md b/.changeset/dirty-apricots-swim.md new file mode 100644 index 00000000000..787ad81e07d --- /dev/null +++ b/.changeset/dirty-apricots-swim.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Updated system setup to only check for a valid `config.db.provider` once during `initConfig`. diff --git a/packages/keystone/src/artifacts.ts b/packages/keystone/src/artifacts.ts index f30740c5805..caf2895c52d 100644 --- a/packages/keystone/src/artifacts.ts +++ b/packages/keystone/src/artifacts.ts @@ -9,7 +9,6 @@ import { printGeneratedTypes } from './lib/schema-type-printer'; import { ExitError } from './scripts/utils'; import { initialiseLists } from './lib/core/types-for-lists'; import { printPrismaSchema } from './lib/core/prisma-schema'; -import { getDBProvider } from './lib/createSystem'; export function getSchemaPaths(cwd: string) { return { @@ -27,12 +26,8 @@ export async function getCommittedArtifacts( graphQLSchema: GraphQLSchema, config: KeystoneConfig ): Promise { - const lists = initialiseLists(config.lists, getDBProvider(config.db)); - const prismaSchema = printPrismaSchema( - lists, - getDBProvider(config.db), - 'node_modules/.prisma/client' - ); + const lists = initialiseLists(config.lists, config.db.provider); + const prismaSchema = printPrismaSchema(lists, config.db.provider, 'node_modules/.prisma/client'); return { graphql: format( '# This file is automatically generated by Keystone, do not modify it manually.\n' + @@ -180,7 +175,7 @@ export async function generateNodeModulesArtifacts( config: KeystoneConfig, cwd: string ) { - const lists = initialiseLists(config.lists, getDBProvider(config.db)); + const lists = initialiseLists(config.lists, config.db.provider); const printedSchema = printSchema(graphQLSchema); const dotKeystoneDir = path.join(cwd, 'node_modules/.keystone'); diff --git a/packages/keystone/src/lib/config/initConfig.ts b/packages/keystone/src/lib/config/initConfig.ts index 71d5e7542a0..d22725854ca 100644 --- a/packages/keystone/src/lib/config/initConfig.ts +++ b/packages/keystone/src/lib/config/initConfig.ts @@ -8,5 +8,11 @@ import { applyIdFieldDefaults } from './applyIdFieldDefaults'; */ export function initConfig(config: KeystoneConfig) { + if (!['postgresql', 'sqlite'].includes(config.db.provider)) { + throw new Error( + 'Invalid db configuration. Please specify db.provider as either "sqlite" or "postgresql"' + ); + } + return { ...config, lists: applyIdFieldDefaults(config) }; } diff --git a/packages/keystone/src/lib/createGraphQLSchema.ts b/packages/keystone/src/lib/createGraphQLSchema.ts index 18b590c6bab..f56b3bc1e73 100644 --- a/packages/keystone/src/lib/createGraphQLSchema.ts +++ b/packages/keystone/src/lib/createGraphQLSchema.ts @@ -3,15 +3,13 @@ import { getAdminMetaSchema } from '../admin-ui/system'; import { sessionSchema } from '../session'; import { InitialisedList } from './core/types-for-lists'; import { getGraphQLSchema } from './core/graphql-schema'; -import { getDBProvider } from './createSystem'; - export function createGraphQLSchema( config: KeystoneConfig, lists: Record, adminMeta: AdminMetaRootVal ) { // Start with the core keystone graphQL schema - let graphQLSchema = getGraphQLSchema(lists, getDBProvider(config.db)); + let graphQLSchema = getGraphQLSchema(lists, config.db.provider); // Merge in the user defined graphQL API if (config.extendGraphqlSchema) { diff --git a/packages/keystone/src/lib/createSystem.ts b/packages/keystone/src/lib/createSystem.ts index 456d5a4b60c..7be2c85f392 100644 --- a/packages/keystone/src/lib/createSystem.ts +++ b/packages/keystone/src/lib/createSystem.ts @@ -5,15 +5,6 @@ import { createGraphQLSchema } from './createGraphQLSchema'; import { makeCreateContext } from './context/createContext'; import { initialiseLists } from './core/types-for-lists'; -export function getDBProvider(db: KeystoneConfig['db']): DatabaseProvider { - if (!['postgresql', 'sqlite'].includes(db.provider)) { - throw new Error( - 'Invalid db configuration. Please specify db.provider as either "sqlite" or "postgresql"' - ); - } - return db.provider; -} - function getSudoGraphQLSchema(config: KeystoneConfig, provider: DatabaseProvider) { // This function creates a GraphQLSchema based on a modified version of the provided config. // The modifications are: @@ -64,14 +55,13 @@ function getSudoGraphQLSchema(config: KeystoneConfig, provider: DatabaseProvider } export function createSystem(config: KeystoneConfig) { - const provider = getDBProvider(config.db); - const lists = initialiseLists(config.lists, provider); + const lists = initialiseLists(config.lists, config.db.provider); const adminMeta = createAdminMeta(config, lists); const graphQLSchema = createGraphQLSchema(config, lists, adminMeta); - const sudoGraphQLSchema = getSudoGraphQLSchema(config, provider); + const sudoGraphQLSchema = getSudoGraphQLSchema(config, config.db.provider); return { graphQLSchema, @@ -79,7 +69,7 @@ export function createSystem(config: KeystoneConfig) { getKeystone: (PrismaClient: any) => { const prismaClient = new PrismaClient({ log: config.db.enableLogging && ['query'], - datasources: { [provider]: { url: config.db.url } }, + datasources: { [config.db.provider]: { url: config.db.url } }, }); prismaClient.$on('beforeExit', async () => { // Prisma is failing to properly clean up its child processes From a645861a9562748cf3e9786e37acea67c4a0cc17 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Fri, 10 Sep 2021 12:34:57 +1000 Subject: [PATCH 030/135] Fixes Relationship field inline connect fields throwing 400 errors (#6526) * Update index.tsx * Create large-actors-worry.md --- .changeset/large-actors-worry.md | 5 +++++ .../src/fields/types/relationship/views/cards/index.tsx | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/large-actors-worry.md diff --git a/.changeset/large-actors-worry.md b/.changeset/large-actors-worry.md new file mode 100644 index 00000000000..8a632af6836 --- /dev/null +++ b/.changeset/large-actors-worry.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed Relationship field inline connect throwing 400 errors when selecting a value. diff --git a/packages/keystone/src/fields/types/relationship/views/cards/index.tsx b/packages/keystone/src/fields/types/relationship/views/cards/index.tsx index 209cd486dfa..5922fbe380f 100644 --- a/packages/keystone/src/fields/types/relationship/views/cards/index.tsx +++ b/packages/keystone/src/fields/types/relationship/views/cards/index.tsx @@ -310,7 +310,7 @@ export function Cards({ try { const { data, errors } = await client.query({ query: gql`query ($ids: [ID!]!) { - items: ${foreignList.gqlNames.listQueryName}(where: {id_in:$ids}) { + items: ${foreignList.gqlNames.listQueryName}(where: { id: { in: $ids }}) { ${selectedFields} } }`, From 8388452982277b10c65ff89be442464761a680a7 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Fri, 10 Sep 2021 13:02:26 +1000 Subject: [PATCH 031/135] Skip fetching fields with static fieldMode: 'hidden' on the item view (#6519) --- .changeset/wise-garlics-swim.md | 5 + examples-staging/assets-cloud/schema.graphql | 4 +- examples-staging/assets-local/schema.graphql | 4 +- examples-staging/auth/schema.graphql | 4 +- examples-staging/basic/schema.graphql | 4 +- examples-staging/ecommerce/schema.graphql | 4 +- .../embedded-nextjs/schema.graphql | 4 +- .../graphql-api-endpoint/schema.graphql | 4 +- examples-staging/roles/schema.graphql | 4 +- examples-staging/sandbox/schema.graphql | 4 +- examples/blog/schema.graphql | 4 +- examples/custom-admin-ui-logo/schema.graphql | 4 +- .../custom-admin-ui-navigation/schema.graphql | 4 +- examples/custom-admin-ui-pages/schema.graphql | 4 +- examples/custom-field-view/schema.graphql | 4 +- examples/custom-field/schema.graphql | 4 +- examples/default-values/schema.graphql | 4 +- examples/document-field/schema.graphql | 4 +- examples/extend-graphql-schema/schema.graphql | 4 +- examples/json/schema.graphql | 4 +- examples/task-manager/schema.graphql | 4 +- examples/testing/schema.graphql | 4 +- examples/virtual-field/schema.graphql | 4 +- examples/virtual-field/schema.ts | 5 +- examples/with-auth/schema.graphql | 4 +- .../admin-ui/pages/ItemPage/index.tsx | 12 +- .../src/admin-ui/admin-meta-graphql.ts | 172 +++++------------- .../src/admin-ui/system/getAdminMetaSchema.ts | 59 ++++-- .../src/admin-ui/utils/useAdminMeta.tsx | 3 + .../fixtures/basic-project/schema.graphql | 4 +- packages/keystone/src/types/admin-meta.ts | 6 + tests/test-projects/basic/schema.graphql | 4 +- .../crud-notifications/schema.graphql | 4 +- 33 files changed, 164 insertions(+), 202 deletions(-) create mode 100644 .changeset/wise-garlics-swim.md diff --git a/.changeset/wise-garlics-swim.md b/.changeset/wise-garlics-swim.md new file mode 100644 index 00000000000..8ed2035f960 --- /dev/null +++ b/.changeset/wise-garlics-swim.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +The Admin UI will skip fetching fields that have a statically set `itemView.fieldMode: 'hidden'` on the item view. The `id` argument to the `KeystoneAdminUIFieldMeta.itemView` GraphQL field can now be omitted which will make `KeystoneAdminUIFieldMetaItemView.fieldMode` return null when there isn't a static field mode. The `itemView` also no longer uses a sudo context when fetching the item in the `KeystoneAdminUIFieldMetaItemView.fieldMode`. Previously, if someone had access to the Admin UI(`ui.isAccessAllowed`) and a field had a `itemView.fieldMode` function that used the `item` argument, someone could bypass access control to determine whether or not an item with a given id exists. diff --git a/examples-staging/assets-cloud/schema.graphql b/examples-staging/assets-cloud/schema.graphql index 6e73618ef22..a155c4714bc 100644 --- a/examples-staging/assets-cloud/schema.graphql +++ b/examples-staging/assets-cloud/schema.graphql @@ -280,7 +280,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -303,7 +303,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/assets-local/schema.graphql b/examples-staging/assets-local/schema.graphql index c6be74a2179..f4a920adbad 100644 --- a/examples-staging/assets-local/schema.graphql +++ b/examples-staging/assets-local/schema.graphql @@ -258,7 +258,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -281,7 +281,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/auth/schema.graphql b/examples-staging/auth/schema.graphql index b271487175a..e4209f80ced 100644 --- a/examples-staging/auth/schema.graphql +++ b/examples-staging/auth/schema.graphql @@ -201,7 +201,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -224,7 +224,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/basic/schema.graphql b/examples-staging/basic/schema.graphql index 2f3587b414c..abe52a2da33 100644 --- a/examples-staging/basic/schema.graphql +++ b/examples-staging/basic/schema.graphql @@ -447,7 +447,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -470,7 +470,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/ecommerce/schema.graphql b/examples-staging/ecommerce/schema.graphql index ede25549b39..c806c19c1fc 100644 --- a/examples-staging/ecommerce/schema.graphql +++ b/examples-staging/ecommerce/schema.graphql @@ -830,7 +830,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -853,7 +853,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/embedded-nextjs/schema.graphql b/examples-staging/embedded-nextjs/schema.graphql index b00789c9cf7..3c4564ce5d6 100644 --- a/examples-staging/embedded-nextjs/schema.graphql +++ b/examples-staging/embedded-nextjs/schema.graphql @@ -125,7 +125,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -148,7 +148,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/graphql-api-endpoint/schema.graphql b/examples-staging/graphql-api-endpoint/schema.graphql index 3caa70617f4..b2e7f5517c7 100644 --- a/examples-staging/graphql-api-endpoint/schema.graphql +++ b/examples-staging/graphql-api-endpoint/schema.graphql @@ -376,7 +376,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -399,7 +399,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/roles/schema.graphql b/examples-staging/roles/schema.graphql index d3d71b849e7..b7657519c3b 100644 --- a/examples-staging/roles/schema.graphql +++ b/examples-staging/roles/schema.graphql @@ -386,7 +386,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -409,7 +409,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples-staging/sandbox/schema.graphql b/examples-staging/sandbox/schema.graphql index 1b415c31622..a3e94e46964 100644 --- a/examples-staging/sandbox/schema.graphql +++ b/examples-staging/sandbox/schema.graphql @@ -229,7 +229,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -252,7 +252,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/blog/schema.graphql b/examples/blog/schema.graphql index d0edfca215f..8cb5cbfc0a5 100644 --- a/examples/blog/schema.graphql +++ b/examples/blog/schema.graphql @@ -247,7 +247,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -270,7 +270,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/custom-admin-ui-logo/schema.graphql b/examples/custom-admin-ui-logo/schema.graphql index 24200845cd6..986be342995 100644 --- a/examples/custom-admin-ui-logo/schema.graphql +++ b/examples/custom-admin-ui-logo/schema.graphql @@ -285,7 +285,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -308,7 +308,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/custom-admin-ui-navigation/schema.graphql b/examples/custom-admin-ui-navigation/schema.graphql index 24200845cd6..986be342995 100644 --- a/examples/custom-admin-ui-navigation/schema.graphql +++ b/examples/custom-admin-ui-navigation/schema.graphql @@ -285,7 +285,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -308,7 +308,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/custom-admin-ui-pages/schema.graphql b/examples/custom-admin-ui-pages/schema.graphql index 24200845cd6..986be342995 100644 --- a/examples/custom-admin-ui-pages/schema.graphql +++ b/examples/custom-admin-ui-pages/schema.graphql @@ -285,7 +285,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -308,7 +308,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/custom-field-view/schema.graphql b/examples/custom-field-view/schema.graphql index 124e26dd9dc..01a3d665af2 100644 --- a/examples/custom-field-view/schema.graphql +++ b/examples/custom-field-view/schema.graphql @@ -288,7 +288,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -311,7 +311,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/custom-field/schema.graphql b/examples/custom-field/schema.graphql index f165d6d76c5..b93005bffb1 100644 --- a/examples/custom-field/schema.graphql +++ b/examples/custom-field/schema.graphql @@ -221,7 +221,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -244,7 +244,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/default-values/schema.graphql b/examples/default-values/schema.graphql index 24200845cd6..986be342995 100644 --- a/examples/default-values/schema.graphql +++ b/examples/default-values/schema.graphql @@ -285,7 +285,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -308,7 +308,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/document-field/schema.graphql b/examples/document-field/schema.graphql index 6d7e7f7dc62..b06ab9f0370 100644 --- a/examples/document-field/schema.graphql +++ b/examples/document-field/schema.graphql @@ -232,7 +232,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -255,7 +255,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/extend-graphql-schema/schema.graphql b/examples/extend-graphql-schema/schema.graphql index 75d76e389ba..3ce7e09c0bd 100644 --- a/examples/extend-graphql-schema/schema.graphql +++ b/examples/extend-graphql-schema/schema.graphql @@ -240,7 +240,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -263,7 +263,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/json/schema.graphql b/examples/json/schema.graphql index 45b03572944..656d1e341a7 100644 --- a/examples/json/schema.graphql +++ b/examples/json/schema.graphql @@ -210,7 +210,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -233,7 +233,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/task-manager/schema.graphql b/examples/task-manager/schema.graphql index 24200845cd6..986be342995 100644 --- a/examples/task-manager/schema.graphql +++ b/examples/task-manager/schema.graphql @@ -285,7 +285,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -308,7 +308,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/testing/schema.graphql b/examples/testing/schema.graphql index c37b0c90fde..b7b89b882cb 100644 --- a/examples/testing/schema.graphql +++ b/examples/testing/schema.graphql @@ -342,7 +342,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -365,7 +365,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/virtual-field/schema.graphql b/examples/virtual-field/schema.graphql index 1ad3971c405..1f5c84cb071 100644 --- a/examples/virtual-field/schema.graphql +++ b/examples/virtual-field/schema.graphql @@ -229,7 +229,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -252,7 +252,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/examples/virtual-field/schema.ts b/examples/virtual-field/schema.ts index 4de75620aa1..d6e26dcc0e7 100644 --- a/examples/virtual-field/schema.ts +++ b/examples/virtual-field/schema.ts @@ -25,6 +25,10 @@ export const lists = createSchema({ content: text({ ui: { displayMode: 'textarea' } }), // A virtual field returning a custom GraphQL object type. counts: virtual({ + ui: { + itemView: { fieldMode: 'hidden' }, + listView: { fieldMode: 'hidden' }, + }, field: graphql.field({ type: graphql.object<{ words: number; @@ -47,7 +51,6 @@ export const lists = createSchema({ }; }, }), - graphQLReturnFragment: '{ words sentences paragraphs }', }), // A virtual field which accepts GraphQL arguments. excerpt: virtual({ diff --git a/examples/with-auth/schema.graphql b/examples/with-auth/schema.graphql index c37b0c90fde..b7b89b882cb 100644 --- a/examples/with-auth/schema.graphql +++ b/examples/with-auth/schema.graphql @@ -342,7 +342,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -365,7 +365,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx index 19e9f5ec6f9..b9073597d5c 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ItemPage/index.tsx @@ -275,9 +275,15 @@ const ItemPage = ({ listKey }: ItemPageProps) => { const { palette, spacing, typography } = useTheme(); const { query, selectedFields } = useMemo(() => { - let selectedFields = Object.keys(list.fields) - .map(fieldPath => { - return list.fields[fieldPath].controller.graphqlSelection; + let selectedFields = Object.entries(list.fields) + .filter( + ([fieldKey, field]) => + field.itemView.fieldMode !== 'hidden' || + // the id field is hidden but we still need to fetch it + fieldKey === 'id' + ) + .map(([fieldKey]) => { + return list.fields[fieldKey].controller.graphqlSelection; }) .join('\n'); return { diff --git a/packages/keystone/src/admin-ui/admin-meta-graphql.ts b/packages/keystone/src/admin-ui/admin-meta-graphql.ts index 3f687820a08..6bab76927fd 100644 --- a/packages/keystone/src/admin-ui/admin-meta-graphql.ts +++ b/packages/keystone/src/admin-ui/admin-meta-graphql.ts @@ -37,6 +37,9 @@ export const staticAdminMetaQuery = gql` viewsIndex customViewsIndex search + itemView { + fieldMode + } } } } @@ -61,136 +64,53 @@ export const staticAdminMetaQuery = gql` type Maybe = T | null; -export type StaticAdminMetaQuery = { __typename?: 'Query' } & { - keystone: { __typename: 'KeystoneMeta' } & { - adminMeta: { __typename: 'KeystoneAdminMeta' } & Pick< - KeystoneAdminMeta, - 'enableSignout' | 'enableSessionItem' - > & { - lists: Array< - { __typename: 'KeystoneAdminUIListMeta' } & Pick< - KeystoneAdminUIListMeta, - | 'key' - | 'itemQueryName' - | 'listQueryName' - | 'path' - | 'label' - | 'singular' - | 'plural' - | 'description' - | 'initialColumns' - | 'pageSize' - | 'labelField' - | 'initialSort' - > & { - fields: Array< - { __typename: 'KeystoneAdminUIFieldMeta' } & Pick< - KeystoneAdminUIFieldMeta, - | 'path' - | 'label' - | 'isOrderable' - | 'isFilterable' - | 'fieldMeta' - | 'viewsIndex' - | 'customViewsIndex' - | 'search' - > - >; - } - >; - }; +export type StaticAdminMetaQuery = { + keystone: { + __typename: 'KeystoneMeta'; + adminMeta: { + __typename: 'KeystoneAdminMeta'; + enableSignout: boolean; + enableSessionItem: boolean; + lists: Array<{ + __typename: 'KeystoneAdminUIListMeta'; + key: string; + itemQueryName: string; + listQueryName: string; + path: string; + label: string; + singular: string; + plural: string; + description: Maybe; + initialColumns: Array; + pageSize: number; + labelField: string; + initialSort: Maybe<{ + __typename: 'KeystoneAdminUISort'; + field: string; + direction: KeystoneAdminUISortDirection; + }>; + fields: Array<{ + __typename: 'KeystoneAdminUIFieldMeta'; + path: string; + label: string; + isOrderable: boolean; + isFilterable: boolean; + fieldMeta: Maybe; + viewsIndex: number; + customViewsIndex: Maybe; + search: Maybe; + itemView: Maybe<{ + __typename: 'KeystoneAdminUIFieldMetaItemView'; + fieldMode: Maybe; + }>; + }>; + }>; + }; }; }; -/** All built-in and custom scalars, mapped to their actual values */ -type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; - JSON: JSONValue; -}; - -export type Query = { - __typename: 'Query'; - keystone: KeystoneMeta; -}; - -type KeystoneMeta = { - __typename: 'KeystoneMeta'; - adminMeta: KeystoneAdminMeta; -}; - -type KeystoneAdminMeta = { - __typename: 'KeystoneAdminMeta'; - enableSignout: Scalars['Boolean']; - enableSessionItem: Scalars['Boolean']; - lists: Array; - list: Maybe; -}; - -type KeystoneAdminUIListMeta = { - __typename: 'KeystoneAdminUIListMeta'; - key: Scalars['String']; - itemQueryName: Scalars['String']; - listQueryName: Scalars['String']; - hideCreate: Scalars['Boolean']; - hideDelete: Scalars['Boolean']; - path: Scalars['String']; - label: Scalars['String']; - singular: Scalars['String']; - plural: Scalars['String']; - description: Maybe; - initialColumns: Array; - pageSize: Scalars['Int']; - labelField: Scalars['String']; - fields: Array; - initialSort: Maybe; -}; - -type KeystoneAdminUISort = { - __typename: 'KeystoneAdminUISort'; - field: Scalars['String']; - direction: KeystoneAdminUISortDirection; -}; - -type KeystoneAdminUIFieldMeta = { - __typename: 'KeystoneAdminUIFieldMeta'; - path: Scalars['String']; - label: Scalars['String']; - isOrderable: Scalars['Boolean']; - isFilterable: Scalars['Boolean']; - fieldMeta: Maybe; - viewsIndex: Scalars['Int']; - customViewsIndex: Maybe; - createView: KeystoneAdminUIFieldMetaCreateView; - itemView: Maybe; - listView: KeystoneAdminUIFieldMetaListView; - search: Maybe; -}; - -type KeystoneAdminUIFieldMetaCreateView = { - __typename: 'KeystoneAdminUIFieldMetaCreateView'; - fieldMode: KeystoneAdminUIFieldMetaCreateViewFieldMode; -}; - -type KeystoneAdminUIFieldMetaItemView = { - __typename: 'KeystoneAdminUIFieldMetaItemView'; - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode; -}; - -type KeystoneAdminUIFieldMetaListView = { - __typename: 'KeystoneAdminUIFieldMetaListView'; - fieldMode: KeystoneAdminUIFieldMetaListViewFieldMode; -}; - -type KeystoneAdminUIFieldMetaCreateViewFieldMode = 'edit' | 'hidden'; +type QueryMode = 'default' | 'insensitive'; type KeystoneAdminUIFieldMetaItemViewFieldMode = 'edit' | 'read' | 'hidden'; -type KeystoneAdminUIFieldMetaListViewFieldMode = 'read' | 'hidden'; - type KeystoneAdminUISortDirection = 'ASC' | 'DESC'; - -type QueryMode = 'default' | 'insensitive'; diff --git a/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts b/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts index 711c9b5f9ae..74352f75789 100644 --- a/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts +++ b/packages/keystone/src/admin-ui/system/getAdminMetaSchema.ts @@ -126,26 +126,24 @@ export function getAdminMetaSchema({ itemView: graphql.field({ args: { id: graphql.arg({ - type: graphql.nonNull(graphql.ID), + type: graphql.ID, }), }, resolve(rootVal, args) { - return { fieldPath: rootVal.path, listKey: rootVal.listKey, itemId: args.id }; + return { fieldPath: rootVal.path, listKey: rootVal.listKey, itemId: args.id ?? null }; }, - type: graphql.object()({ + type: graphql.object()({ name: 'KeystoneAdminUIFieldMetaItemView', fields: { fieldMode: graphql.field({ - type: graphql.nonNull( - graphql.enum({ - name: 'KeystoneAdminUIFieldMetaItemViewFieldMode', - values: graphql.enumValues(['edit', 'read', 'hidden']), - }) - ), - async resolve(rootVal, args, context) { - if ('isAdminUIBuildProcess' in context) { + type: graphql.enum({ + name: 'KeystoneAdminUIFieldMetaItemViewFieldMode', + values: graphql.enumValues(['edit', 'read', 'hidden']), + }), + resolve(rootVal, args, context) { + if ('isAdminUIBuildProcess' in context && rootVal.itemId !== null) { throw new Error( - 'KeystoneAdminUIFieldMetaItemView.fieldMode cannot be resolved during the build process' + 'KeystoneAdminUIFieldMetaItemView.fieldMode cannot be resolved during the build process if an id is provided' ); } if (!lists[rootVal.listKey].fields[rootVal.fieldPath].graphql.isEnabled.read) { @@ -155,18 +153,37 @@ export function getAdminMetaSchema({ ) { return 'read'; } - const item = await fetchItemForItemViewFieldMode(context)( - rootVal.listKey, - rootVal.itemId - ); const listConfig = config.lists[rootVal.listKey]; + const sessionFunction = lists[rootVal.listKey].fields[rootVal.fieldPath].ui?.itemView?.fieldMode ?? - listConfig.ui?.itemView?.defaultFieldMode; - return runMaybeFunction(sessionFunction, 'edit', { - session: context.session, - item, + listConfig.ui?.itemView?.defaultFieldMode ?? + 'edit'; + if (typeof sessionFunction === 'string') { + return sessionFunction; + } + + if (rootVal.itemId === null) { + return null; + } + + fakeAssert(context); + + // uhhh, for some reason TypeScript only understands this if it's assigned + // to a variable and then returned + let ret = fetchItemForItemViewFieldMode(context)( + rootVal.listKey, + rootVal.itemId + ).then(item => { + if (item === null) { + return 'hidden' as const; + } + return runMaybeFunction(sessionFunction, 'edit', { + session: context.session, + item, + }); }); + return ret; }, }), }, @@ -343,6 +360,8 @@ function runMaybeFunction( return sessionFunction; } +function fakeAssert(val: any): asserts val is T {} + const fetchItemForItemViewFieldMode = extendContext(context => { type ListKey = string; type ItemId = string; diff --git a/packages/keystone/src/admin-ui/utils/useAdminMeta.tsx b/packages/keystone/src/admin-ui/utils/useAdminMeta.tsx index 168680b6a5e..f21ca3b13f9 100644 --- a/packages/keystone/src/admin-ui/utils/useAdminMeta.tsx +++ b/packages/keystone/src/admin-ui/utils/useAdminMeta.tsx @@ -109,6 +109,9 @@ export function useAdminMeta(adminMetaHash: string, fieldViews: FieldViews) { } runtimeAdminMeta.lists[list.key].fields[field.path] = { ...field, + itemView: { + fieldMode: field.itemView?.fieldMode ?? null, + }, views, controller: fieldViews[field.viewsIndex].controller({ listKey: list.key, diff --git a/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql b/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql index 1163e538bc7..ccd07e54b42 100644 --- a/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql +++ b/packages/keystone/src/scripts/tests/fixtures/basic-project/schema.graphql @@ -119,7 +119,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -142,7 +142,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/packages/keystone/src/types/admin-meta.ts b/packages/keystone/src/types/admin-meta.ts index b4772340af8..32b206f4fca 100644 --- a/packages/keystone/src/types/admin-meta.ts +++ b/packages/keystone/src/types/admin-meta.ts @@ -82,6 +82,12 @@ export type FieldMeta = { views: FieldViews[number]; controller: FieldController; search: 'default' | 'insensitive' | null; + itemView: { + /** + * `null` indicates that the value is dynamic and must be fetched for any given item + */ + fieldMode: 'edit' | 'read' | 'hidden' | null; + }; }; export type ListMeta = { diff --git a/tests/test-projects/basic/schema.graphql b/tests/test-projects/basic/schema.graphql index 4c33e8d5145..7cb29237157 100644 --- a/tests/test-projects/basic/schema.graphql +++ b/tests/test-projects/basic/schema.graphql @@ -338,7 +338,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -361,7 +361,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { diff --git a/tests/test-projects/crud-notifications/schema.graphql b/tests/test-projects/crud-notifications/schema.graphql index 24200845cd6..986be342995 100644 --- a/tests/test-projects/crud-notifications/schema.graphql +++ b/tests/test-projects/crud-notifications/schema.graphql @@ -285,7 +285,7 @@ type KeystoneAdminUIFieldMeta { customViewsIndex: Int createView: KeystoneAdminUIFieldMetaCreateView! listView: KeystoneAdminUIFieldMetaListView! - itemView(id: ID!): KeystoneAdminUIFieldMetaItemView + itemView(id: ID): KeystoneAdminUIFieldMetaItemView search: QueryMode } @@ -308,7 +308,7 @@ enum KeystoneAdminUIFieldMetaListViewFieldMode { } type KeystoneAdminUIFieldMetaItemView { - fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode! + fieldMode: KeystoneAdminUIFieldMetaItemViewFieldMode } enum KeystoneAdminUIFieldMetaItemViewFieldMode { From c2b124f8e4b283022ec473d9e5f32f37de639cf0 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Fri, 10 Sep 2021 13:21:21 +1000 Subject: [PATCH 032/135] Checkbox updates (#6448) --- .changeset/rare-baboons-repeat.md | 46 ++++++++ docs/pages/docs/apis/fields.mdx | 23 +++- examples-staging/auth/schema.prisma | 6 +- examples-staging/basic/schema.prisma | 2 +- examples-staging/ecommerce/schema.prisma | 16 +-- examples-staging/roles/schema.prisma | 22 ++-- examples-staging/sandbox/schema.prisma | 2 +- examples/custom-admin-ui-logo/schema.graphql | 6 +- examples/custom-admin-ui-logo/schema.prisma | 2 +- .../custom-admin-ui-navigation/schema.graphql | 6 +- .../custom-admin-ui-navigation/schema.prisma | 2 +- examples/custom-admin-ui-pages/schema.graphql | 6 +- examples/custom-admin-ui-pages/schema.prisma | 2 +- examples/custom-field-view/schema.graphql | 6 +- examples/custom-field-view/schema.prisma | 2 +- examples/default-values/schema.graphql | 6 +- examples/default-values/schema.prisma | 2 +- examples/json/schema.prisma | 8 +- examples/task-manager/schema.graphql | 6 +- examples/task-manager/schema.prisma | 2 +- examples/testing/schema.graphql | 6 +- examples/testing/schema.prisma | 2 +- examples/with-auth/schema.graphql | 6 +- examples/with-auth/schema.prisma | 2 +- .../keystone/src/fields/non-null-graphql.ts | 49 ++++++++ .../src/fields/types/checkbox/index.ts | 56 ++++++--- .../types/checkbox/tests/test-fixtures.ts | 12 +- .../src/fields/types/checkbox/views/index.tsx | 6 +- .../src/scripts/tests/migrations.test.ts | 32 ++++- packages/keystone/src/types/next-fields.ts | 2 +- tests/api-tests/fields/non-null.test.ts | 109 ++++++++++++++++++ tests/test-projects/basic/schema.graphql | 6 +- tests/test-projects/basic/schema.prisma | 2 +- .../crud-notifications/schema.graphql | 6 +- .../crud-notifications/schema.prisma | 2 +- 35 files changed, 370 insertions(+), 101 deletions(-) create mode 100644 .changeset/rare-baboons-repeat.md create mode 100644 packages/keystone/src/fields/non-null-graphql.ts create mode 100644 tests/api-tests/fields/non-null.test.ts diff --git a/.changeset/rare-baboons-repeat.md b/.changeset/rare-baboons-repeat.md new file mode 100644 index 00000000000..77221ac1697 --- /dev/null +++ b/.changeset/rare-baboons-repeat.md @@ -0,0 +1,46 @@ +--- +'@keystone-next/keystone': major +--- + +The `checkbox` field is now non-nullable in the database, if you need three states, you should use `select()`. The field no longer accepts dynamic default values and it will default to `false` unless a different `defaultValue` is specified. `graphql.isNonNull` can also be set if you have no read access control and you don't intend to add any in the future, it will make the GraphQL output field non-nullable. + +If you're using SQLite, Prisma will generate a migration that makes the column non-nullable and sets any rows that have + +If you're using PostgreSQL, Prisma will generate a migration but you'll need to modify it if you have nulls in a checkbox field. Keystone will say that the migration cannot be executed: + +``` +✨ Starting Keystone +⭐️ Dev Server Ready on http://localhost:3000 +✨ Generating GraphQL and Prisma schemas +✨ There has been a change to your Keystone schema that requires a migration + +⚠️ We found changes that cannot be executed: + + • Made the column `isAdmin` on table `User` required, but there are 1 existing NULL values. + +✔ Name of migration … make-is-admin-non-null +✨ A migration has been created at migrations/20210906053141_make_is_admin_non_null +Please edit the migration and run keystone-next dev again to apply the migration +``` + +The generated migration will look like this: + +```sql +/* + Warnings: + + - Made the column `isAdmin` on table `User` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE "User" ALTER COLUMN "isAdmin" SET NOT NULL, +ALTER COLUMN "isAdmin" SET DEFAULT false; +``` + +To make it set any null values to false in your database, you need to modify it so that it looks like this but with the table and column names replaced. + +```sql +ALTER TABLE "User" ALTER COLUMN "isAdmin" SET DEFAULT false; +UPDATE "User" SET "isAdmin" = DEFAULT WHERE "isAdmin" IS NULL; +ALTER TABLE "User" ALTER COLUMN "isAdmin" SET NOT NULL; +``` \ No newline at end of file diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index 4ffbb2f6632..9a64029b5f7 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -137,11 +137,15 @@ A `checkbox` field represents a boolean (`true`/`false`) value. Options: -- `defaultValue` (default: `undefined`): Can be either a boolean value or an async function which takes an argument `({ context, originalInput })` and returns a boolean value. - This value will be used for the field when creating items if no explicit value is set. - `context` is a [`KeystoneContext`](./context) object. - `originalInput` is an object containing the data passed in to the `create` mutation. -- `isRequired` (default: `false`): If `true` then this field can never be set to `null`. +- `defaultValue` (default: `false`): This value will be used for the field when creating items if no explicit value is set. +- `graphql.read.isNonNull` (default: `false`): If you have no read access control and you don't intend to add any in the future, + you can set this to true and the output field will be non-nullable. This is only allowed when you have no read access control because otherwise, + when access is denied, `null` will be returned which will cause an error since the field is non-nullable and the error + will propagate up until a nullable field is found which means the entire item will be unreadable and when doing an `items` query, all the items will be unreadable. +- `graphql.create.isNonNull` (default: `false`): If you have no create access control and you want to explicitly show that this is field is non-nullable in the create input + you can set this to true and the create field will be non-nullable and have a default value at the GraphQL level. + This is only allowed when you have no create access control because otherwise, the item will always fail access control + if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. ```typescript import { config, createSchema, list } from '@keystone-next/keystone'; @@ -153,7 +157,14 @@ export default config({ fields: { fieldName: checkbox({ defaultValue: true, - isRequired: true, + graphql: { + read: { + isNonNull: true + }, + create: { + isNonNull: true + }, + } }), /* ... */ }, diff --git a/examples-staging/auth/schema.prisma b/examples-staging/auth/schema.prisma index 7e8ccdd031e..9e95f502180 100644 --- a/examples-staging/auth/schema.prisma +++ b/examples-staging/auth/schema.prisma @@ -12,9 +12,9 @@ generator client { } model User { - id String @id @default(cuid()) + id String @id @default(cuid()) name String? - email String? @unique + email String? @unique password String? - isAdmin Boolean? + isAdmin Boolean @default(false) } \ No newline at end of file diff --git a/examples-staging/basic/schema.prisma b/examples-staging/basic/schema.prisma index d02d00119c1..7dec910681c 100644 --- a/examples-staging/basic/schema.prisma +++ b/examples-staging/basic/schema.prisma @@ -25,7 +25,7 @@ model User { attachment_mode String? attachment_filename String? password String? - isAdmin Boolean? + isAdmin Boolean @default(false) roles String? phoneNumbers PhoneNumber[] @relation("PhoneNumber_user") posts Post[] @relation("Post_author") diff --git a/examples-staging/ecommerce/schema.prisma b/examples-staging/ecommerce/schema.prisma index b2d19d2f554..64c9f1f7c91 100644 --- a/examples-staging/ecommerce/schema.prisma +++ b/examples-staging/ecommerce/schema.prisma @@ -90,13 +90,13 @@ model Order { } model Role { - id String @id @default(cuid()) + id String @id @default(cuid()) name String? - canManageProducts Boolean? - canSeeOtherUsers Boolean? - canManageUsers Boolean? - canManageRoles Boolean? - canManageCart Boolean? - canManageOrders Boolean? - assignedTo User[] @relation("User_role") + canManageProducts Boolean @default(false) + canSeeOtherUsers Boolean @default(false) + canManageUsers Boolean @default(false) + canManageRoles Boolean @default(false) + canManageCart Boolean @default(false) + canManageOrders Boolean @default(false) + assignedTo User[] @relation("User_role") } \ No newline at end of file diff --git a/examples-staging/roles/schema.prisma b/examples-staging/roles/schema.prisma index e23b4b60055..6dfad7f9120 100644 --- a/examples-staging/roles/schema.prisma +++ b/examples-staging/roles/schema.prisma @@ -12,12 +12,12 @@ generator client { } model Todo { - id String @id @default(cuid()) + id String @id @default(cuid()) label String? - isComplete Boolean? - isPrivate Boolean? - assignedTo Person? @relation("Todo_assignedTo", fields: [assignedToId], references: [id]) - assignedToId String? @map("assignedTo") + isComplete Boolean @default(false) + isPrivate Boolean @default(false) + assignedTo Person? @relation("Todo_assignedTo", fields: [assignedToId], references: [id]) + assignedToId String? @map("assignedTo") @@index([assignedToId]) } @@ -37,11 +37,11 @@ model Person { model Role { id String @id @default(cuid()) name String? - canCreateTodos Boolean? - canManageAllTodos Boolean? - canSeeOtherPeople Boolean? - canEditOtherPeople Boolean? - canManagePeople Boolean? - canManageRoles Boolean? + canCreateTodos Boolean @default(false) + canManageAllTodos Boolean @default(false) + canSeeOtherPeople Boolean @default(false) + canEditOtherPeople Boolean @default(false) + canManagePeople Boolean @default(false) + canManageRoles Boolean @default(false) assignedTo Person[] @relation("Person_role") } \ No newline at end of file diff --git a/examples-staging/sandbox/schema.prisma b/examples-staging/sandbox/schema.prisma index 8d49455e864..3905a7c87dd 100644 --- a/examples-staging/sandbox/schema.prisma +++ b/examples-staging/sandbox/schema.prisma @@ -14,7 +14,7 @@ generator client { model Todo { id String @id @default(cuid()) label String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo User? @relation("Todo_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/custom-admin-ui-logo/schema.graphql b/examples/custom-admin-ui-logo/schema.graphql index 986be342995..546de8db159 100644 --- a/examples/custom-admin-ui-logo/schema.graphql +++ b/examples/custom-admin-ui-logo/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/custom-admin-ui-logo/schema.prisma b/examples/custom-admin-ui-logo/schema.prisma index 78461ee962d..872f311ea90 100644 --- a/examples/custom-admin-ui-logo/schema.prisma +++ b/examples/custom-admin-ui-logo/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/custom-admin-ui-navigation/schema.graphql b/examples/custom-admin-ui-navigation/schema.graphql index 986be342995..546de8db159 100644 --- a/examples/custom-admin-ui-navigation/schema.graphql +++ b/examples/custom-admin-ui-navigation/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/custom-admin-ui-navigation/schema.prisma b/examples/custom-admin-ui-navigation/schema.prisma index 78461ee962d..872f311ea90 100644 --- a/examples/custom-admin-ui-navigation/schema.prisma +++ b/examples/custom-admin-ui-navigation/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/custom-admin-ui-pages/schema.graphql b/examples/custom-admin-ui-pages/schema.graphql index 986be342995..546de8db159 100644 --- a/examples/custom-admin-ui-pages/schema.graphql +++ b/examples/custom-admin-ui-pages/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/custom-admin-ui-pages/schema.prisma b/examples/custom-admin-ui-pages/schema.prisma index 78461ee962d..872f311ea90 100644 --- a/examples/custom-admin-ui-pages/schema.prisma +++ b/examples/custom-admin-ui-pages/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/custom-field-view/schema.graphql b/examples/custom-field-view/schema.graphql index 01a3d665af2..32721af1668 100644 --- a/examples/custom-field-view/schema.graphql +++ b/examples/custom-field-view/schema.graphql @@ -28,7 +28,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -79,9 +79,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/custom-field-view/schema.prisma b/examples/custom-field-view/schema.prisma index f9d9dc0a7e6..cf008f69e07 100644 --- a/examples/custom-field-view/schema.prisma +++ b/examples/custom-field-view/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/default-values/schema.graphql b/examples/default-values/schema.graphql index 986be342995..546de8db159 100644 --- a/examples/default-values/schema.graphql +++ b/examples/default-values/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/default-values/schema.prisma b/examples/default-values/schema.prisma index 78461ee962d..872f311ea90 100644 --- a/examples/default-values/schema.prisma +++ b/examples/default-values/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/json/schema.prisma b/examples/json/schema.prisma index 7e77ac3aea3..b4dd5312b55 100644 --- a/examples/json/schema.prisma +++ b/examples/json/schema.prisma @@ -12,12 +12,12 @@ generator client { } model Package { - id String @id @default(cuid()) + id String @id @default(cuid()) label String? pkgjson String? - isPrivate Boolean? - ownedBy Person? @relation("Package_ownedBy", fields: [ownedById], references: [id]) - ownedById String? @map("ownedBy") + isPrivate Boolean @default(false) + ownedBy Person? @relation("Package_ownedBy", fields: [ownedById], references: [id]) + ownedById String? @map("ownedBy") @@index([ownedById]) } diff --git a/examples/task-manager/schema.graphql b/examples/task-manager/schema.graphql index 986be342995..546de8db159 100644 --- a/examples/task-manager/schema.graphql +++ b/examples/task-manager/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/task-manager/schema.prisma b/examples/task-manager/schema.prisma index 78461ee962d..872f311ea90 100644 --- a/examples/task-manager/schema.prisma +++ b/examples/task-manager/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/testing/schema.graphql b/examples/testing/schema.graphql index b7b89b882cb..9fdc40a47ea 100644 --- a/examples/testing/schema.graphql +++ b/examples/testing/schema.graphql @@ -80,7 +80,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -131,9 +131,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/testing/schema.prisma b/examples/testing/schema.prisma index 56ac89a216f..e2931cd5089 100644 --- a/examples/testing/schema.prisma +++ b/examples/testing/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/examples/with-auth/schema.graphql b/examples/with-auth/schema.graphql index b7b89b882cb..9fdc40a47ea 100644 --- a/examples/with-auth/schema.graphql +++ b/examples/with-auth/schema.graphql @@ -80,7 +80,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -131,9 +131,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/examples/with-auth/schema.prisma b/examples/with-auth/schema.prisma index 56ac89a216f..e2931cd5089 100644 --- a/examples/with-auth/schema.prisma +++ b/examples/with-auth/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/packages/keystone/src/fields/non-null-graphql.ts b/packages/keystone/src/fields/non-null-graphql.ts new file mode 100644 index 00000000000..0b54e7766db --- /dev/null +++ b/packages/keystone/src/fields/non-null-graphql.ts @@ -0,0 +1,49 @@ +import { BaseGeneratedListTypes, FieldAccessControl, FieldData } from '../types'; + +export function hasReadAccessControl( + access: FieldAccessControl | undefined +) { + if (access === undefined) { + return false; + } + return typeof access === 'function' || typeof access.read === 'function'; +} + +export function hasCreateAccessControl( + access: FieldAccessControl | undefined +) { + if (access === undefined) { + return false; + } + return typeof access === 'function' || typeof access.create === 'function'; +} + +export function assertReadIsNonNullAllowed( + meta: FieldData, + config: { + access?: FieldAccessControl | undefined; + graphql?: { read?: { isNonNull?: boolean } }; + } +) { + if (config.graphql?.read?.isNonNull && hasReadAccessControl(config.access)) { + throw new Error( + `The field at ${meta.listKey}.${meta.fieldKey} sets graphql.read.isNonNull: true and has read access control, this is not allowed.\n` + + 'Either disable graphql.read.isNonNull or read access control.' + ); + } +} + +export function assertCreateIsNonNullAllowed( + meta: FieldData, + config: { + access?: FieldAccessControl | undefined; + graphql?: { create?: { isNonNull?: boolean } }; + } +) { + if (config.graphql?.create?.isNonNull && hasCreateAccessControl(config.access)) { + throw new Error( + `The field at ${meta.listKey}.${meta.fieldKey} sets graphql.create.isNonNull: true and has create access control, this is not allowed.\n` + + 'Either disable graphql.create.isNonNull or create access control.' + ); + } +} diff --git a/packages/keystone/src/fields/types/checkbox/index.ts b/packages/keystone/src/fields/types/checkbox/index.ts index a163c8c632a..f835f258db1 100644 --- a/packages/keystone/src/fields/types/checkbox/index.ts +++ b/packages/keystone/src/fields/types/checkbox/index.ts @@ -1,6 +1,5 @@ import { BaseGeneratedListTypes, - FieldDefaultValue, CommonFieldConfig, fieldType, FieldTypeFunc, @@ -8,18 +7,21 @@ import { graphql, filters, } from '../../../types'; +import { assertCreateIsNonNullAllowed, assertReadIsNonNullAllowed } from '../../non-null-graphql'; import { resolveView } from '../../resolve-view'; export type CheckboxFieldConfig = CommonFieldConfig & { - defaultValue?: FieldDefaultValue; - isRequired?: boolean; + defaultValue?: boolean; + graphql?: { + read?: { isNonNull?: boolean }; + create?: { isNonNull?: boolean }; + }; }; export const checkbox = ({ - isRequired, - defaultValue, + defaultValue = false, ...config }: CheckboxFieldConfig = {}): FieldTypeFunc => meta => { @@ -27,19 +29,47 @@ export const checkbox = throw Error("isIndexed: 'unique' is not a supported option for field type checkbox"); } - return fieldType({ kind: 'scalar', mode: 'optional', scalar: 'Boolean' })({ + assertReadIsNonNullAllowed(meta, config); + assertCreateIsNonNullAllowed(meta, config); + + return fieldType({ + kind: 'scalar', + mode: 'required', + scalar: 'Boolean', + default: { kind: 'literal', value: defaultValue }, + })({ ...config, input: { - where: { - arg: graphql.arg({ type: filters[meta.provider].Boolean.optional }), - resolve: filters.resolveCommon, + where: { arg: graphql.arg({ type: filters[meta.provider].Boolean.required }) }, + create: { + arg: graphql.arg({ + type: config.graphql?.create?.isNonNull + ? graphql.nonNull(graphql.Boolean) + : graphql.Boolean, + defaultValue: config.graphql?.create?.isNonNull ? defaultValue : undefined, + }), + resolve(val) { + if (val === null) { + throw new Error('checkbox fields cannot be set to null'); + } + return val ?? defaultValue; + }, + }, + update: { + arg: graphql.arg({ type: graphql.Boolean }), + resolve(val) { + if (val === null) { + throw new Error('checkbox fields cannot be set to null'); + } + return val; + }, }, - create: { arg: graphql.arg({ type: graphql.Boolean }) }, - update: { arg: graphql.arg({ type: graphql.Boolean }) }, orderBy: { arg: graphql.arg({ type: orderDirectionEnum }) }, }, - output: graphql.field({ type: graphql.Boolean }), + output: graphql.field({ + type: config.graphql?.read?.isNonNull ? graphql.nonNull(graphql.Boolean) : graphql.Boolean, + }), views: resolveView('checkbox/views'), - __legacy: { isRequired, defaultValue }, + getAdminMeta: () => ({ defaultValue }), }); }; diff --git a/packages/keystone/src/fields/types/checkbox/tests/test-fixtures.ts b/packages/keystone/src/fields/types/checkbox/tests/test-fixtures.ts index d58aaeeb2cb..f94083b90b6 100644 --- a/packages/keystone/src/fields/types/checkbox/tests/test-fixtures.ts +++ b/packages/keystone/src/fields/types/checkbox/tests/test-fixtures.ts @@ -6,6 +6,8 @@ export const exampleValue = () => true; export const exampleValue2 = () => false; export const supportsUnique = false; export const fieldName = 'enabled'; +export const skipRequiredTest = true; +export const supportsGraphQLIsNonNull = true; export const getTestFields = () => ({ enabled: checkbox({ isFilterable: true }), @@ -18,8 +20,8 @@ export const initItems = () => { { name: 'person3', enabled: false }, { name: 'person4', enabled: true }, { name: 'person5', enabled: false }, - { name: 'person6', enabled: null }, - { name: 'person7', enabled: null }, + { name: 'person6', enabled: false }, + { name: 'person7', enabled: false }, ]; }; @@ -29,8 +31,8 @@ export const storedValues = () => [ { name: 'person3', enabled: false }, { name: 'person4', enabled: true }, { name: 'person5', enabled: false }, - { name: 'person6', enabled: null }, - { name: 'person7', enabled: null }, + { name: 'person6', enabled: false }, + { name: 'person7', enabled: false }, ]; -export const supportedFilters = () => ['null_equality', 'equality']; +export const supportedFilters = () => ['equality']; diff --git a/packages/keystone/src/fields/types/checkbox/views/index.tsx b/packages/keystone/src/fields/types/checkbox/views/index.tsx index 9caa3a8edd4..90ea2fb26d9 100644 --- a/packages/keystone/src/fields/types/checkbox/views/index.tsx +++ b/packages/keystone/src/fields/types/checkbox/views/index.tsx @@ -54,12 +54,14 @@ export const CardValue: CardValueComponent = ({ item, field }) => { type CheckboxController = FieldController; -export const controller = (config: FieldControllerConfig): CheckboxController => { +export const controller = ( + config: FieldControllerConfig<{ defaultValue: boolean }> +): CheckboxController => { return { path: config.path, label: config.label, graphqlSelection: config.path, - defaultValue: false, + defaultValue: config.fieldMeta.defaultValue, deserialize(item) { const value = item[config.path]; return typeof value === 'boolean' ? value : false; diff --git a/packages/keystone/src/scripts/tests/migrations.test.ts b/packages/keystone/src/scripts/tests/migrations.test.ts index 61e4d79cb21..07ae5861d3d 100644 --- a/packages/keystone/src/scripts/tests/migrations.test.ts +++ b/packages/keystone/src/scripts/tests/migrations.test.ts @@ -320,9 +320,9 @@ describe('useMigrations: true', () => { } model Todo { - id String @id + id String @id title String? - isComplete Boolean? + isComplete Boolean @default(false) } " `); @@ -330,8 +330,18 @@ describe('useMigrations: true', () => { const { migration, migrationName } = await getGeneratedMigration(tmp, 2, 'add_is_complete'); expect(migration).toMatchInlineSnapshot(` - "-- AlterTable - ALTER TABLE \\"Todo\\" ADD COLUMN \\"isComplete\\" BOOLEAN; + "-- RedefineTables + PRAGMA foreign_keys=OFF; + CREATE TABLE \\"new_Todo\\" ( + \\"id\\" TEXT NOT NULL PRIMARY KEY, + \\"title\\" TEXT, + \\"isComplete\\" BOOLEAN NOT NULL DEFAULT false + ); + INSERT INTO \\"new_Todo\\" (\\"id\\", \\"title\\") SELECT \\"id\\", \\"title\\" FROM \\"Todo\\"; + DROP TABLE \\"Todo\\"; + ALTER TABLE \\"new_Todo\\" RENAME TO \\"Todo\\"; + PRAGMA foreign_key_check; + PRAGMA foreign_keys=ON; " `); @@ -580,8 +590,18 @@ describe('useMigrations: true', () => { ); expect(await fs.readFile(`${tmp}/migrations/${migrationName}/migration.sql`, 'utf8')) .toMatchInlineSnapshot(` - "-- AlterTable - ALTER TABLE \\"Todo\\" ADD COLUMN \\"isComplete\\" BOOLEAN; + "-- RedefineTables + PRAGMA foreign_keys=OFF; + CREATE TABLE \\"new_Todo\\" ( + \\"id\\" TEXT NOT NULL PRIMARY KEY, + \\"title\\" TEXT, + \\"isComplete\\" BOOLEAN NOT NULL DEFAULT false + ); + INSERT INTO \\"new_Todo\\" (\\"id\\", \\"title\\") SELECT \\"id\\", \\"title\\" FROM \\"Todo\\"; + DROP TABLE \\"Todo\\"; + ALTER TABLE \\"new_Todo\\" RENAME TO \\"Todo\\"; + PRAGMA foreign_key_check; + PRAGMA foreign_keys=ON; " `); diff --git a/packages/keystone/src/types/next-fields.ts b/packages/keystone/src/types/next-fields.ts index 74f224de6d5..1891296c93c 100644 --- a/packages/keystone/src/types/next-fields.ts +++ b/packages/keystone/src/types/next-fields.ts @@ -292,7 +292,7 @@ export type CreateFieldInputArg< > = { arg: TArg; } & (TArg extends graphql.Arg - ? DBFieldToInputValue extends graphql.InferValueFromArg + ? graphql.InferValueFromArg extends DBFieldToInputValue ? { resolve?: CreateFieldInputResolver, TDBField>; } diff --git a/tests/api-tests/fields/non-null.test.ts b/tests/api-tests/fields/non-null.test.ts new file mode 100644 index 00000000000..01abe2fc236 --- /dev/null +++ b/tests/api-tests/fields/non-null.test.ts @@ -0,0 +1,109 @@ +import globby from 'globby'; +import { createSchema, list } from '@keystone-next/keystone'; +import { text } from '@keystone-next/keystone/fields'; +import { setupTestEnv } from '@keystone-next/keystone/testing'; +import { assertInputObjectType, assertObjectType, GraphQLNonNull } from 'graphql'; +import { apiTestConfig } from '../utils'; + +const testModules = globby.sync(`packages/**/src/**/test-fixtures.{js,ts}`, { + absolute: true, +}); +testModules + .map(require) + .filter( + ({ unSupportedAdapterList = [], name }) => + name !== 'ID' && !unSupportedAdapterList.includes(process.env.TEST_ADAPTER) + ) + .forEach(mod => { + (mod.testMatrix || ['default']).forEach((matrixValue: string) => { + describe(`${mod.name} - ${matrixValue} - graphql.isNonNull`, () => { + beforeEach(() => { + if (mod.beforeEach) { + mod.beforeEach(); + } + }); + afterEach(async () => { + if (mod.afterEach) { + await mod.afterEach(); + } + }); + beforeAll(() => { + if (mod.beforeAll) { + mod.beforeAll(); + } + }); + afterAll(async () => { + if (mod.afterAll) { + await mod.afterAll(); + } + }); + + const getSchema = async (fieldConfig: any) => { + const { testArgs } = await setupTestEnv({ + config: apiTestConfig({ + lists: createSchema({ + Test: list({ + fields: { + name: text(), + testField: mod.typeFunction({ + ...(mod.fieldConfig ? mod.fieldConfig(matrixValue) : {}), + ...fieldConfig, + }), + }, + }), + }), + images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, + files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, + }), + }); + return testArgs.context.graphql.schema; + }; + + if (mod.supportsGraphQLIsNonNull) { + test('Sets the output field as non-null when graphql.read.isNonNull is set', async () => { + const schema = await getSchema({ graphql: { read: { isNonNull: true } } }); + const outputType = assertObjectType(schema.getType('Test')); + expect(outputType.getFields().testField.type).toBeInstanceOf(GraphQLNonNull); + }); + test('Throws when graphql.read.isNonNull and read access control is set', async () => { + const error = await getSchema({ + graphql: { read: { isNonNull: true } }, + access: { read: () => false }, + }).catch(x => x); + expect(error).toBeInstanceOf(Error); + expect(error.message).toEqual( + `The field at Test.testField sets graphql.read.isNonNull: true and has read access control, this is not allowed.\n` + + `Either disable graphql.read.isNonNull or read access control.` + ); + }); + test('Sets the create field as non-null when graphql.create.isNonNull is set', async () => { + const schema = await getSchema({ graphql: { create: { isNonNull: true } } }); + const createType = assertInputObjectType(schema.getType('TestCreateInput')); + expect(createType.getFields().testField.type).toBeInstanceOf(GraphQLNonNull); + }); + test('Throws when graphql.create.isNonNull and create access control is set', async () => { + const error = await getSchema({ + graphql: { create: { isNonNull: true } }, + access: { create: () => false }, + }).catch(x => x); + expect(error).toBeInstanceOf(Error); + expect(error.message).toEqual( + `The field at Test.testField sets graphql.create.isNonNull: true and has create access control, this is not allowed.\n` + + `Either disable graphql.create.isNonNull or create access control.` + ); + }); + } + + test("Output field is nullable when graphql.read.isNonNull isn't set", async () => { + const schema = await getSchema({}); + const outputType = assertObjectType(schema.getType('Test')); + expect(outputType.getFields().testField.type).not.toBeInstanceOf(GraphQLNonNull); + }); + test("Create field is nullable when graphql.create.isNonNull isn't set", async () => { + const schema = await getSchema({}); + const createType = assertInputObjectType(schema.getType('TestCreateInput')); + expect(createType.getFields().testField.type).not.toBeInstanceOf(GraphQLNonNull); + }); + }); + }); + }); diff --git a/tests/test-projects/basic/schema.graphql b/tests/test-projects/basic/schema.graphql index 7cb29237157..0ebede15c7f 100644 --- a/tests/test-projects/basic/schema.graphql +++ b/tests/test-projects/basic/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/tests/test-projects/basic/schema.prisma b/tests/test-projects/basic/schema.prisma index 981c3d6d1fb..9d04fa76402 100644 --- a/tests/test-projects/basic/schema.prisma +++ b/tests/test-projects/basic/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? diff --git a/tests/test-projects/crud-notifications/schema.graphql b/tests/test-projects/crud-notifications/schema.graphql index 986be342995..546de8db159 100644 --- a/tests/test-projects/crud-notifications/schema.graphql +++ b/tests/test-projects/crud-notifications/schema.graphql @@ -27,7 +27,7 @@ input TaskWhereInput { id: IDFilter label: StringNullableFilter priority: TaskPriorityTypeNullableFilter - isComplete: BooleanNullableFilter + isComplete: BooleanFilter assignedTo: PersonWhereInput finishBy: DateTimeNullableFilter } @@ -78,9 +78,9 @@ input TaskPriorityTypeNullableFilter { not: TaskPriorityTypeNullableFilter } -input BooleanNullableFilter { +input BooleanFilter { equals: Boolean - not: BooleanNullableFilter + not: BooleanFilter } input DateTimeNullableFilter { diff --git a/tests/test-projects/crud-notifications/schema.prisma b/tests/test-projects/crud-notifications/schema.prisma index 78461ee962d..872f311ea90 100644 --- a/tests/test-projects/crud-notifications/schema.prisma +++ b/tests/test-projects/crud-notifications/schema.prisma @@ -15,7 +15,7 @@ model Task { id String @id @default(cuid()) label String? priority String? - isComplete Boolean? + isComplete Boolean @default(false) assignedTo Person? @relation("Task_assignedTo", fields: [assignedToId], references: [id]) assignedToId String? @map("assignedTo") finishBy DateTime? From 1da120a388a80585e897a06b81b027b7d8011902 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Mon, 13 Sep 2021 08:22:36 +1000 Subject: [PATCH 033/135] Update schema export message to reflect required update (#6532) * Update index.ts * Create eight-buckets-breathe.md --- .changeset/eight-buckets-breathe.md | 5 +++++ packages/keystone/src/schema/index.ts | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changeset/eight-buckets-breathe.md diff --git a/.changeset/eight-buckets-breathe.md b/.changeset/eight-buckets-breathe.md new file mode 100644 index 00000000000..7487e90767d --- /dev/null +++ b/.changeset/eight-buckets-breathe.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Updated schema export message to accurately reflect required import changes. diff --git a/packages/keystone/src/schema/index.ts b/packages/keystone/src/schema/index.ts index e9f21ca865f..76e5e1115c5 100644 --- a/packages/keystone/src/schema/index.ts +++ b/packages/keystone/src/schema/index.ts @@ -5,7 +5,7 @@ // this will not so we should keep this for probably a couple months at least throw new Error( - 'The exports of `@keystone-next/keystone` have been moved to `@keystone-next/keystone`, please import from there instead.' + 'The exports of `@keystone-next/keystone/schema` have been moved to `@keystone-next/keystone`, please import from there instead.' ); export {}; From db8205f5d26a8f41a3dccb6dd80b9a364c6de0bc Mon Sep 17 00:00:00 2001 From: Dominik Wilkowski Date: Mon, 13 Sep 2021 13:38:23 +1000 Subject: [PATCH 034/135] text sizing and color fixes (#6536) * text sizing and color fixes * Update index.tsx Co-authored-by: Matt Barron --- docs/components/Header.tsx | 1 + docs/lib/prose-lite.ts | 1 + docs/pages/index.tsx | 56 +++++++++++++------------------------- 3 files changed, 21 insertions(+), 37 deletions(-) diff --git a/docs/components/Header.tsx b/docs/components/Header.tsx index 32c893a6aa7..5de6256cbda 100644 --- a/docs/components/Header.tsx +++ b/docs/components/Header.tsx @@ -242,6 +242,7 @@ export function Header() { '& a:hover': { color: 'var(--link)', }, + marginBottom: '2rem', })} > diff --git a/docs/lib/prose-lite.ts b/docs/lib/prose-lite.ts index fbf5edd053d..2098862d73c 100644 --- a/docs/lib/prose-lite.ts +++ b/docs/lib/prose-lite.ts @@ -1,4 +1,5 @@ export const proseStyles = { + color: 'var(--text)', 'img, video': { maxWidth: '100%', height: 'auto', diff --git a/docs/pages/index.tsx b/docs/pages/index.tsx index e0ed250039b..691b5dfecff 100644 --- a/docs/pages/index.tsx +++ b/docs/pages/index.tsx @@ -105,7 +105,7 @@ export default function IndexPage() { gap: '1rem', }} > - + We're an Australian design + development consultancy with a long history working on big products at scale for names you know.
@@ -139,7 +139,7 @@ export default function IndexPage() { 1m+ - + npm Installs @@ -147,7 +147,7 @@ export default function IndexPage() { 160+ - + Contributors @@ -155,7 +155,7 @@ export default function IndexPage() { 2013 - + First Commit @@ -374,10 +374,10 @@ export default function IndexPage() { Design your schema - + Rapidly spec your backend with all the primitive and advanced field types you need. - + Add logic, access control, and custom queries & mutations to create an API that's unique to your app. @@ -398,21 +398,15 @@ export default function IndexPage() { >
  • - - 100% TypeScript (or JavaScript) - + 100% TypeScript (or JavaScript)
  • - - Fits your git-based workflow & CI - + Fits your git-based workflow & CI
  • - - Automatic db migrations with Prisma - + Automatic db migrations with Prisma
  • @@ -458,7 +452,7 @@ export const lists = createSchema({ Customise your content story - + A flexible and intuitive editing environment that does what your schema says: Keystone’s Admin UI understands your access control, so you can shape it to your unique needs. @@ -480,21 +474,15 @@ export const lists = createSchema({ >
  • - - Powerful access control - + Powerful access control
  • - - Next-gen rich text WYSIWYG - + Next-gen rich text WYSIWYG
  • - - BYO custom React components{' '} - + BYO custom React components
  • @@ -519,7 +507,7 @@ export const lists = createSchema({ Query your data - + Get what you need, fast. Keystone's GraphQL API gives you session management, access control, pagination, sorting, and filtering out of the box. Customise it without losing the bits that work for you. @@ -541,21 +529,15 @@ export const lists = createSchema({ >
  • - - Powerful CRUD scaffolding - + Powerful CRUD scaffolding
  • - - Evolve with bespoke logic for your app - + Evolve with bespoke logic for your app
  • - - Integrate microservices & external APIs - + Integrate microservices & external APIs
  • @@ -630,11 +612,11 @@ export const lists = createSchema({ Deploy anywhere - + Keystone is open source. Deploy it to managed services like Digital Ocean, Heroku, and Render, or your own custom infrastructure. - + The source of truth is your codebase, so Keystone fits naturally into your git-based development workflow, and you can use all the CI & Automation tooling you already know. From 271e5d97bc2e4548ce039a568278f9f7569aa41a Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Mon, 13 Sep 2021 13:58:00 +1000 Subject: [PATCH 035/135] Rename checkOperationAccess to getOperationAccess (#6537) --- .changeset/gold-lizards-sip.md | 5 +++++ packages/keystone/src/lib/core/access-control.ts | 2 +- .../keystone/src/lib/core/mutations/create-update.ts | 12 ++++++------ packages/keystone/src/lib/core/mutations/delete.ts | 6 +++--- .../keystone/src/lib/core/queries/output-field.ts | 4 ++-- packages/keystone/src/lib/core/queries/resolvers.ts | 8 ++++---- 6 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 .changeset/gold-lizards-sip.md diff --git a/.changeset/gold-lizards-sip.md b/.changeset/gold-lizards-sip.md new file mode 100644 index 00000000000..2ed6d888872 --- /dev/null +++ b/.changeset/gold-lizards-sip.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Renamed internal function `checkOperationAccess` to `getOperationAccess`. diff --git a/packages/keystone/src/lib/core/access-control.ts b/packages/keystone/src/lib/core/access-control.ts index 11b05bbdc68..7d822be8d46 100644 --- a/packages/keystone/src/lib/core/access-control.ts +++ b/packages/keystone/src/lib/core/access-control.ts @@ -16,7 +16,7 @@ import { import { InitialisedList } from './types-for-lists'; import { InputFilter } from './where-inputs'; -export async function checkOperationAccess( +export async function getOperationAccess( list: InitialisedList, context: KeystoneContext, operation: 'delete' | 'create' | 'update' | 'query' diff --git a/packages/keystone/src/lib/core/mutations/create-update.ts b/packages/keystone/src/lib/core/mutations/create-update.ts index 340c8137142..2804b302bd1 100644 --- a/packages/keystone/src/lib/core/mutations/create-update.ts +++ b/packages/keystone/src/lib/core/mutations/create-update.ts @@ -10,7 +10,7 @@ import { } from '../utils'; import { InputFilter, resolveUniqueWhereInput, UniqueInputFilter } from '../where-inputs'; import { accessDeniedError, extensionError } from '../graphql-errors'; -import { checkOperationAccess, getAccessFilters } from '../access-control'; +import { getOperationAccess, getAccessFilters } from '../access-control'; import { resolveRelateToManyForCreateInput, resolveRelateToManyForUpdateInput, @@ -63,7 +63,7 @@ export class NestedMutationState { const writeLimit = pLimit(1); // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'create'); + const operationAccess = await getOperationAccess(list, context, 'create'); const { item, afterChange } = await createSingle( { data }, @@ -90,7 +90,7 @@ export async function createOne( const writeLimit = pLimit(1); // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'create'); + const operationAccess = await getOperationAccess(list, context, 'create'); const { item, afterChange } = await createSingle( createInput, @@ -114,7 +114,7 @@ export async function createMany( const writeLimit = pLimit(provider === 'sqlite' ? 1 : Infinity); // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'create'); + const operationAccess = await getOperationAccess(list, context, 'create'); return createInputs.data.map(async data => { const { item, afterChange } = await createSingle( @@ -181,7 +181,7 @@ export async function updateOne( const writeLimit = pLimit(1); // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'update'); + const operationAccess = await getOperationAccess(list, context, 'update'); // Get list-level access control filters const accessFilters = await getAccessFilters(list, context, 'update'); @@ -198,7 +198,7 @@ export async function updateMany( const writeLimit = pLimit(provider === 'sqlite' ? 1 : Infinity); // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'update'); + const operationAccess = await getOperationAccess(list, context, 'update'); // Get list-level access control filters const accessFilters = await getAccessFilters(list, context, 'update'); diff --git a/packages/keystone/src/lib/core/mutations/delete.ts b/packages/keystone/src/lib/core/mutations/delete.ts index 5d7e36a3c1e..57a0fb9ac1d 100644 --- a/packages/keystone/src/lib/core/mutations/delete.ts +++ b/packages/keystone/src/lib/core/mutations/delete.ts @@ -1,6 +1,6 @@ import pLimit, { Limit } from 'p-limit'; import { DatabaseProvider, KeystoneContext } from '../../../types'; -import { checkOperationAccess, getAccessFilters } from '../access-control'; +import { getOperationAccess, getAccessFilters } from '../access-control'; import { accessDeniedError } from '../graphql-errors'; import { InitialisedList } from '../types-for-lists'; import { runWithPrisma } from '../utils'; @@ -59,7 +59,7 @@ export async function deleteMany( const writeLimit = pLimit(provider === 'sqlite' ? 1 : Infinity); // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'delete'); + const operationAccess = await getOperationAccess(list, context, 'delete'); // Check filter permission to pass into single operation const accessFilters = await getAccessFilters(list, context, 'delete'); @@ -75,7 +75,7 @@ export async function deleteOne( context: KeystoneContext ) { // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'delete'); + const operationAccess = await getOperationAccess(list, context, 'delete'); // Check filter permission to pass into single operation const accessFilters = await getAccessFilters(list, context, 'delete'); diff --git a/packages/keystone/src/lib/core/queries/output-field.ts b/packages/keystone/src/lib/core/queries/output-field.ts index 1e0b79b135d..e4e661b539a 100644 --- a/packages/keystone/src/lib/core/queries/output-field.ts +++ b/packages/keystone/src/lib/core/queries/output-field.ts @@ -12,7 +12,7 @@ import { FieldReadItemAccessArgs, } from '../../../types'; import { - checkOperationAccess, + getOperationAccess, getAccessFilters, validateFieldAccessControl, } from '../access-control'; @@ -44,7 +44,7 @@ function getRelationVal( } else { return async () => { // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(foreignList, context, 'query'); + const operationAccess = await getOperationAccess(foreignList, context, 'query'); if (!operationAccess) { return null; } diff --git a/packages/keystone/src/lib/core/queries/resolvers.ts b/packages/keystone/src/lib/core/queries/resolvers.ts index 9b23220a3de..13cb1b922ed 100644 --- a/packages/keystone/src/lib/core/queries/resolvers.ts +++ b/packages/keystone/src/lib/core/queries/resolvers.ts @@ -1,6 +1,6 @@ import { GraphQLResolveInfo } from 'graphql'; import { FindManyArgsValue, ItemRootValue, KeystoneContext, OrderDirection } from '../../../types'; -import { checkOperationAccess, getAccessFilters } from '../access-control'; +import { getOperationAccess, getAccessFilters } from '../access-control'; import { PrismaFilter, UniquePrismaFilter, @@ -59,7 +59,7 @@ export async function findOne( context: KeystoneContext ) { // Check operation permission to pass into single operation - const operationAccess = await checkOperationAccess(list, context, 'query'); + const operationAccess = await getOperationAccess(list, context, 'query'); if (!operationAccess) { return null; } @@ -89,7 +89,7 @@ export async function findMany( const orderBy = await resolveOrderBy(rawOrderBy, list, context); // Check operation permission, throw access denied if not allowed - const operationAccess = await checkOperationAccess(list, context, 'query'); + const operationAccess = await getOperationAccess(list, context, 'query'); if (!operationAccess) { return []; } @@ -174,7 +174,7 @@ export async function count( extraFilter?: PrismaFilter ) { // Check operation permission, throw access denied if not allowed - const operationAccess = await checkOperationAccess(list, context, 'query'); + const operationAccess = await getOperationAccess(list, context, 'query'); if (!operationAccess) { return 0; } From 47c8b53ce44b7ad34ba40501a257a2b679cdee05 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Mon, 13 Sep 2021 16:49:20 +1000 Subject: [PATCH 036/135] Remove `createSchema` (#6542) --- .changeset/nervous-geese-pump.md | 5 + docs/components/docs/DocumentEditorDemo.tsx | 6 +- docs/pages/docs/apis/access-control.mdx | 30 ++--- docs/pages/docs/apis/auth.mdx | 6 +- docs/pages/docs/apis/config.mdx | 5 +- docs/pages/docs/apis/fields.mdx | 106 +++++++++--------- docs/pages/docs/apis/graphql.mdx | 6 +- docs/pages/docs/apis/hooks.mdx | 48 ++++---- docs/pages/docs/apis/schema.mdx | 31 +++-- docs/pages/docs/guides/document-fields.mdx | 24 ++-- docs/pages/docs/guides/hooks.mdx | 30 ++--- docs/pages/docs/guides/relationships.mdx | 46 ++++---- docs/pages/docs/guides/virtual-fields.mdx | 22 ++-- docs/pages/index.tsx | 6 +- docs/pages/updates/new-access-control.mdx | 36 +++--- docs/pages/updates/new-graphql-api.mdx | 6 +- examples-staging/assets-cloud/schema.ts | 6 +- examples-staging/assets-local/schema.ts | 6 +- examples-staging/auth/schema.ts | 6 +- examples-staging/basic/schema.ts | 6 +- examples-staging/ecommerce/keystone.ts | 6 +- .../graphql-api-endpoint/schema.ts | 6 +- examples-staging/roles/schema.ts | 6 +- examples-staging/sandbox/schema.ts | 6 +- examples/blog/schema.ts | 6 +- examples/custom-admin-ui-logo/schema.ts | 6 +- examples/custom-admin-ui-navigation/schema.ts | 6 +- examples/custom-admin-ui-pages/schema.ts | 6 +- examples/custom-field-view/schema.ts | 6 +- examples/custom-field/schema.ts | 6 +- examples/default-values/schema.ts | 6 +- examples/document-field/schema.ts | 6 +- examples/extend-graphql-schema/schema.ts | 6 +- examples/json/schema.ts | 6 +- examples/task-manager/schema.ts | 6 +- examples/testing/schema.ts | 6 +- examples/virtual-field/schema.ts | 6 +- examples/with-auth/schema.ts | 6 +- packages/keystone/src/index.ts | 2 +- packages/keystone/src/schema/schema.ts | 5 - .../access-control/mutations-field.test.ts | 6 +- .../mutations-list-filter.test.ts | 6 +- .../mutations-list-item.test.ts | 6 +- .../mutations-list-operation.test.ts | 6 +- .../api-tests/access-control/schema-utils.ts | 4 +- tests/api-tests/access-control/utils.ts | 6 +- tests/api-tests/auth-header.test.ts | 10 +- .../api-tests/default-value/defaults.test.ts | 4 +- tests/api-tests/extend-express-app.test.ts | 4 +- .../extend-graphql-schema.test.ts | 6 +- tests/api-tests/fields/crud.test.ts | 6 +- tests/api-tests/fields/filter.test.ts | 10 +- tests/api-tests/fields/non-null.test.ts | 6 +- tests/api-tests/fields/required.test.ts | 6 +- tests/api-tests/fields/types/Virtual.test.ts | 10 +- tests/api-tests/fields/types/document.test.ts | 6 +- tests/api-tests/fields/unique.test.ts | 10 +- tests/api-tests/fields/unsupported.test.ts | 6 +- tests/api-tests/healthcheck.test.ts | 4 +- tests/api-tests/hooks/auth-hooks.test.skip.ts | 6 +- tests/api-tests/hooks/hook-errors.test.ts | 6 +- tests/api-tests/hooks/list-hooks.test.ts | 6 +- tests/api-tests/hooks/validation.test.ts | 6 +- tests/api-tests/id-field.test.ts | 14 +-- tests/api-tests/new-interfaces.test.ts | 6 +- tests/api-tests/queries/cache-hints.test.ts | 6 +- tests/api-tests/queries/filters.test.ts | 6 +- tests/api-tests/queries/limits.test.ts | 6 +- tests/api-tests/queries/orderBy.test.ts | 6 +- tests/api-tests/queries/relationships.test.ts | 6 +- .../many-to-many-one-sided.test.ts | 6 +- .../crud-self-ref/many-to-many.test.ts | 6 +- .../one-to-many-one-sided.test.ts | 6 +- .../crud-self-ref/one-to-many.test.ts | 6 +- .../crud-self-ref/one-to-one.test.ts | 6 +- .../crud/many-to-many-one-sided.test.ts | 6 +- .../relationships/crud/many-to-many.test.ts | 6 +- .../crud/one-to-many-one-sided.test.ts | 6 +- .../relationships/crud/one-to-many.test.ts | 6 +- .../relationships/crud/one-to-one.test.ts | 6 +- .../filtering/access-control.test.ts | 6 +- .../relationships/filtering/filtering.test.ts | 6 +- .../relationships/filtering/nested.test.ts | 6 +- .../relationships/many-to-one-to-one.test.ts | 6 +- .../nested-mutations/connect-many.test.ts | 6 +- .../nested-mutations/connect-singular.test.ts | 6 +- .../create-and-connect-many.test.ts | 6 +- .../create-and-connect-singular.test.ts | 6 +- .../nested-mutations/create-many.test.ts | 10 +- .../nested-mutations/create-singular.test.ts | 6 +- .../nested-mutations/disconnect-many.test.ts | 6 +- .../disconnect-singular.test.ts | 6 +- .../reconnect-many-to-one.test.ts | 6 +- .../nested-mutations/set-many.test.ts | 6 +- .../two-way-backreference/to-many.test.ts | 6 +- .../to-one-required.test.ts | 6 +- .../relationships/shared-names.test.ts | 6 +- tests/benchmarks/fixtures/create-related.js | 6 +- tests/benchmarks/fixtures/create.js | 6 +- tests/benchmarks/fixtures/query.js | 6 +- tests/test-projects/basic/schema.ts | 6 +- .../crud-notifications/schema.ts | 6 +- 102 files changed, 471 insertions(+), 473 deletions(-) create mode 100644 .changeset/nervous-geese-pump.md diff --git a/.changeset/nervous-geese-pump.md b/.changeset/nervous-geese-pump.md new file mode 100644 index 00000000000..c36e6313f58 --- /dev/null +++ b/.changeset/nervous-geese-pump.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +Removed `createSchema` function, you can remove the call to `createSchema` and pass the lists directly to the `lists` property diff --git a/docs/components/docs/DocumentEditorDemo.tsx b/docs/components/docs/DocumentEditorDemo.tsx index e35fe09879f..badc2f18505 100644 --- a/docs/components/docs/DocumentEditorDemo.tsx +++ b/docs/components/docs/DocumentEditorDemo.tsx @@ -91,11 +91,11 @@ const componentBlocks = { type DocumentFieldConfig = Parameters[0]; function documentFeaturesCodeExample(config: DocumentFieldConfig | DocumentFeatures) { - return `import { config, createSchema, list } from '@keystone-next/keystone'; + return `import { config, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: document({ @@ -128,7 +128,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); `; diff --git a/docs/pages/docs/apis/access-control.mdx b/docs/pages/docs/apis/access-control.mdx index a1d4a6659b0..3485d68acb5 100644 --- a/docs/pages/docs/apis/access-control.mdx +++ b/docs/pages/docs/apis/access-control.mdx @@ -6,18 +6,18 @@ The `access` property of the [list configuration](./schema) object configures wh The `access` property of the [field configuration](./fields) object configures who can read, create, and update specific field values of an item. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ fields: { fieldName: text({ access: { /* ... */ }, }), }, access: { /* ... */ }, }), - }), + }, }); ``` @@ -59,10 +59,10 @@ Individual functions can be provided for each of the operations. !> These functions must return `true` if the operation is allowed, or `false` if it is not allowed. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { operation: { @@ -73,7 +73,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -92,11 +92,11 @@ In general, the filter access control functions will return GraphQL filters. They can also return boolean values `true` or `false` to match or exclude all items. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { checkbox } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ fields: { isReadable: checkbox(), @@ -117,7 +117,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -135,11 +135,11 @@ It’s available to `create`, `update`, and `delete` mutations, and lets you wri !> These functions must return `true` if the operation is allowed, or `false` if it is not allowed. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { checkbox } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { item: { @@ -149,7 +149,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -192,11 +192,11 @@ No errors will be returned for `read` access denied. !> The `read` access control is applied to fields returned from both **queries** and **mutations**. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ fields: { fieldName: text({ @@ -208,7 +208,7 @@ export default config({ }), }, }), - }), + }, }); ``` diff --git a/docs/pages/docs/apis/auth.mdx b/docs/pages/docs/apis/auth.mdx index 6b63dd5b3ad..e34d530d116 100644 --- a/docs/pages/docs/apis/auth.mdx +++ b/docs/pages/docs/apis/auth.mdx @@ -10,7 +10,7 @@ Additional options to this function provide support for creating an initial item For examples of how to use authentication in your system please see the [authentication guide](../guides/auth). ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text, password, checkbox } from '@keystone-next/keystone/fields'; import { createAuth } from '@keystone-next/auth'; @@ -39,7 +39,7 @@ const { withAuth } = createAuth({ export default withAuth( config({ - lists: createSchema({ + lists: { User: list({ fields: { email: text({ isIndexed: 'unique', isFilterable: true }), @@ -48,7 +48,7 @@ export default withAuth( }, }), session: { /* ... */ }, - }), + }, }) ); ``` diff --git a/docs/pages/docs/apis/config.mdx b/docs/pages/docs/apis/config.mdx index 97e0364c790..12324932d2c 100644 --- a/docs/pages/docs/apis/config.mdx +++ b/docs/pages/docs/apis/config.mdx @@ -39,15 +39,14 @@ This type definition should be considered the source of truth for the available The `lists` config option is where you define the data model, or schema, of the Keystone system. It has a TypeScript type of `ListSchemaConfig`. This is where you define and configure the `lists` and their `fields` of the data model. -In general you will use the `createSchema()` function to create this configuration option. See the [Schema API](./schema) docs for details on how to use this function. ```typescript import type { ListSchemaConfig } from '@keystone-next/keystone/types'; -import { config, createSchema } from '@keystone-next/keystone'; +import { config } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ /* ... */ }), + lists: { /* ... */ }, /* ... */ }); ``` diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index 9a64029b5f7..d46d0db5f22 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -12,7 +12,7 @@ This document covers the different field types which are available and the confi To see how to access fields in the GraphQL API please see the [GraphQL API](./graphql) docs. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { // Scalar types checkbox, @@ -43,7 +43,7 @@ import { document } from '@keystone-next/fields-document'; import { cloudinaryImage } from '@keystone-next/cloudinary'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: text({ /* ... */ }), @@ -51,7 +51,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -94,7 +94,7 @@ Options: ```typescript export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: text({ @@ -124,7 +124,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -148,11 +148,11 @@ Options: if a user doesn't have access to create the particular field regardless of whether or not they specify the field in the create. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { checkbox } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: checkbox({ @@ -170,7 +170,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -191,11 +191,11 @@ Options: - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { integer } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: integer({ @@ -207,7 +207,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -220,11 +220,11 @@ Currently the `json` field is non-orderable and non-filterable. - `isRequired` (default: `false`): If `true` then this field can never be set to `null`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { json } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: json({ @@ -234,7 +234,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -255,11 +255,11 @@ Options: - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { float } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: float({ @@ -271,7 +271,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -294,11 +294,11 @@ Options: - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { decimal } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: decimal({ @@ -312,7 +312,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -330,11 +330,11 @@ Options: This module will be used for all encryption routines in the `password` field. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { password } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: password({ @@ -347,7 +347,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -378,11 +378,11 @@ Options: Can be one of `['select', 'segmented-control']`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { select } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: select({ @@ -400,7 +400,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -423,11 +423,11 @@ Options: Can be one of `['input', 'textarea']`. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: text({ @@ -440,7 +440,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -462,11 +462,11 @@ Options: - If `'unique'` then all values of this field must be unique. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { timestamp } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: timestamp({ @@ -478,7 +478,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -512,11 +512,11 @@ Read our [relationships guide](../guides/relationships) for details on Keystone - `ui.displayMode === 'count'` only supports `many` relationships ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { relationship } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: relationship({ @@ -545,7 +545,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -563,11 +563,11 @@ Options: - `isIndexed` ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { autoIncrement } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: autoIncrement({ @@ -579,7 +579,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -597,11 +597,11 @@ Options: - `graphQLReturnFragment` (default: `''` ): The sub-fields that should be fetched by the Admin UI when displaying this field. ```typescript -import { config, createSchema, list, graphql } from '@keystone-next/keystone'; +import { config, list, graphql } from '@keystone-next/keystone'; import { virtual } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: virtual({ @@ -617,7 +617,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -633,11 +633,11 @@ A `file` field represents a file of any type. See [`config.files`](./config#files) for details on how to configure your Keystone system with support for the `file` field type. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { file } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { repo: file(), @@ -645,7 +645,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -657,11 +657,11 @@ An `image` field represents an image file, i.e. `.jpg`, `.png`, `.webp`, or `.gi See [`config.images`](./config#images) for details on how to configure your Keystone system with support for the `image` field type. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { image } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { avatar: image(), @@ -669,7 +669,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -690,11 +690,11 @@ Options: - `layouts` ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: document({ @@ -712,7 +712,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -728,11 +728,11 @@ export default config({ - `folder` ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { cloudinaryImage } from '@keystone-next/cloudinary'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: cloudinaryImage({ @@ -747,7 +747,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` diff --git a/docs/pages/docs/apis/graphql.mdx b/docs/pages/docs/apis/graphql.mdx index 7c656647d72..093c1d6bd07 100644 --- a/docs/pages/docs/apis/graphql.mdx +++ b/docs/pages/docs/apis/graphql.mdx @@ -12,13 +12,13 @@ Keystone generates a CRUD (create, read, update, delete) GraphQL API based on th Consider the following system definition: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isOrderable: true }) } }), - }), + }, /* ... */ }); ``` diff --git a/docs/pages/docs/apis/hooks.mdx b/docs/pages/docs/apis/hooks.mdx index c53f12b5bdd..0f9c616170c 100644 --- a/docs/pages/docs/apis/hooks.mdx +++ b/docs/pages/docs/apis/hooks.mdx @@ -15,11 +15,11 @@ All hook functions are async and, with the exception of `resolveInput`, do not r For examples of how to use hooks in your system please see the [hooks guide](../guides/hooks). ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { // Hooks for create and update operations @@ -50,7 +50,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -80,11 +80,11 @@ The result of `resolveInput` will be passed as `resolvedData` into the next stag | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { resolveInput: async ({ @@ -118,7 +118,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -143,11 +143,11 @@ These error messages will be returned as a `ValidationFailureError` from the Gra | `addValidationError(msg)` | Used to set a validation error. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { validateInput: async ({ @@ -177,7 +177,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -198,11 +198,11 @@ It is invoked after all `validateInput` hooks have been run, but before the data | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { beforeChange: async ({ @@ -230,7 +230,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -249,11 +249,11 @@ The `afterChange` function is used to perform side effects after the data for a | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { afterChange: async ({ @@ -281,7 +281,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -309,11 +309,11 @@ These error messages will be returned as a `ValidationFailureError` from the Gra | `addValidationError(msg)` | Used to set a validation error. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { validateDelete: async ({ @@ -339,7 +339,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -358,11 +358,11 @@ It is invoked after all `validateDelete` hooks have been run. | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { beforeDelete: async ({ listKey, operation, existingItem, context }) => { @@ -379,7 +379,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -396,11 +396,11 @@ The `afterDelete` function is used to perform side effects after the data for a | `context` | The [`KeystoneContext`](./context) object of the originating GraphQL operation. | ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ hooks: { afterDelete: async ({ listKey, operation, existingItem, context }) => { @@ -417,7 +417,7 @@ export default config({ }), }, }), - }), + }, }); ``` diff --git a/docs/pages/docs/apis/schema.mdx b/docs/pages/docs/apis/schema.mdx index 590deca6433..7eb5b3b4fc7 100644 --- a/docs/pages/docs/apis/schema.mdx +++ b/docs/pages/docs/apis/schema.mdx @@ -5,14 +5,13 @@ import { RelatedContent } from '../../../components/RelatedContent'; # Schema API The `lists` property of the [system configuration](./config) object is where you define the data model, or schema, of your Keystone system. -To setup the `lists` property of the system configuration you need to use the `createSchema()` function. -This function accepts an object with list names as keys, and `list()` configurations as values. +It accepts an object with list names as keys, and `list()` configurations as values. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: ({ ListName: list({ fields: { /* ... */ }, access: { /* ... */ }, @@ -43,11 +42,11 @@ The `fields` option defines the names, types, and configuration of the fields in This configuration option takes an object with field names as keys, and configured field types as values. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: text({ /* ... */ }), @@ -55,7 +54,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -109,11 +108,11 @@ Options: - `pageSize` (default: `50`): Sets the number of items to show per page in the list view. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields`; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { name: text({ /* ... */ }) }, ui: { @@ -138,7 +137,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` @@ -169,10 +168,10 @@ Options: ```typescript import { CacheScope } from 'apollo-cache-control'; -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListName: list({ graphql: { description: '...', @@ -185,7 +184,7 @@ export default config({ /* ... */ }), /* ... */ - }), + }, /* ... */ }); ``` @@ -200,10 +199,10 @@ Options: The default across all lists can be changed at the root-level `db.idField` config. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListName: list({ db: { idField: { kind: 'uuid' }, @@ -211,7 +210,7 @@ export default config({ /* ... */ }), /* ... */ - }), + }, /* ... */ }); ``` diff --git a/docs/pages/docs/guides/document-fields.mdx b/docs/pages/docs/guides/document-fields.mdx index e5de0fcd824..42437938816 100644 --- a/docs/pages/docs/guides/document-fields.mdx +++ b/docs/pages/docs/guides/document-fields.mdx @@ -22,10 +22,10 @@ The document field provides a number of different formatting options, all of whi To get started with a fully featured editor experience, you can turn on all of the built-in options. ```typescript -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { content: document({ @@ -39,7 +39,7 @@ export const lists = createSchema({ }), }, }), -}); +}; ``` This has enabled all of the **formatting** options, enabled inline **links**, section **dividers**, and both 2 and 3 column **layouts**. @@ -161,12 +161,12 @@ For example, you might want to include twitter-style mentions of other users in We can achieve this with the `relationships` option to the document field. ```tsx -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { Post: list({ fields: { content: document({ @@ -186,7 +186,7 @@ export default config({ name: text(), } }), - }), + }, }); ``` @@ -352,12 +352,12 @@ You need to import the `componentBlocks` and pass it to the document field along `keystone.ts` ```ts -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; import { componentBlocks } from './component-blocks'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: document({ @@ -368,7 +368,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -571,11 +571,11 @@ fields.object({ To use relationship fields on component blocks, you need to add a relationship to the document field config. ```tsx -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { document } from '@keystone-next/fields-document'; export default config({ - lists: createSchema({ + lists: { ListName: list({ fields: { fieldName: document({ @@ -593,7 +593,7 @@ export default config({ }, }), /* ... */ - }), + }, /* ... */ }); ``` diff --git a/docs/pages/docs/guides/hooks.mdx b/docs/pages/docs/guides/hooks.mdx index 67eab162ac9..4e7a078d36c 100644 --- a/docs/pages/docs/guides/hooks.mdx +++ b/docs/pages/docs/guides/hooks.mdx @@ -16,11 +16,11 @@ A hook is a function you define as part of your [schema configuration](../apis/s Let's look at a basic example to log a message to the console whenever a new user is created. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -34,7 +34,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -54,11 +54,11 @@ The `resolveInput` hook lets us take the data which has been provided to the Gra Let's write a hook which takes the data for a blog post and converts the first letter to upper-case. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { Post: list({ fields: { title: text({ isRequired: true }), @@ -76,7 +76,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -101,11 +101,11 @@ An empty string, `""`, is a perfectly valid `String` value to pass into GraphQL. Let's use a validation hook to ensure that this value doesn't make it into our database. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { Post: list({ fields: { title: text({ isRequired: true }), @@ -121,7 +121,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -145,13 +145,13 @@ We can use the `beforeChange` and `afterChange` hooks to do this. Let's send an email after a user is created. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; // Keystone leaves it up to you to decide how best to implement email in your system import { sendWelcomeEmail } from './lib/welcomeEmail'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -165,7 +165,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -198,11 +198,11 @@ For example, you might have an email validation function which want to use in yo You could always write this as a list hook, but it will make your code more clear if you write this as a field hook. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -218,7 +218,7 @@ export default config({ }), }, }), - }), + }, }); ``` diff --git a/docs/pages/docs/guides/relationships.mdx b/docs/pages/docs/guides/relationships.mdx index 09ce5b98126..ffdc10da787 100644 --- a/docs/pages/docs/guides/relationships.mdx +++ b/docs/pages/docs/guides/relationships.mdx @@ -28,11 +28,11 @@ These topics are easier to understand by example. We’ll explore them, as well Relationships are made using the [`relationship`](../apis/fields#relationship) field type within a [`list()`](../apis/schema). In our blog example we can connect a blog `post` to some `users` using the relationship field’s `ref` configuration option like so: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text() } }), Post: list({ fields: { @@ -41,7 +41,7 @@ export default config({ authors: relationship({ ref: 'User', many: true, }), }, }), - }), + }, }); ``` @@ -72,11 +72,11 @@ query { If we can find all the `authors` of a post, we can also find all the posts written by a particular user. To do this we need to configure a two-sided relationship in our schema: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -92,7 +92,7 @@ export default config({ authors: relationship({ ref: 'User.posts', many: true }), }, }), - }), + }, }); ``` @@ -121,29 +121,29 @@ query { Keystone also lets you define one, and two-sided **relationships that refer to the same list**. To make a _one-sided_ Twitter style following relationship we do the following: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), follows: relationship({ ref: 'User', many: true }), }, }), - }), + }, }); ``` Or change this into a _two-sided_ relationship to also access the followers of every user: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -151,7 +151,7 @@ export default config({ followers: relationship({ ref: 'User.follows', many: true }), }, }), - }), + }, }); ``` @@ -184,11 +184,11 @@ Let’s explore how to set up each type of cardinality in the context of our blo - Users can have multiple posts ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; import { text, relationship } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -201,7 +201,7 @@ export default config({ author: relationship({ ref: 'User', many: false }), }, }), - }), + }, }); ``` @@ -212,7 +212,7 @@ export default config({ ```typescript export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -225,7 +225,7 @@ export default config({ authors: relationship({ ref: 'User', many: true }), }, }), - }), + }, }); ``` @@ -240,7 +240,7 @@ export default config({ ```typescript export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -254,7 +254,7 @@ export default config({ author: relationship({ ref: 'User.post', many: false }), }, }), - }), + }, }); ``` @@ -265,7 +265,7 @@ export default config({ ```typescript export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -279,7 +279,7 @@ export default config({ author: relationship({ ref: 'User.posts', many: false }), }, }), - }), + }, }); ``` @@ -292,7 +292,7 @@ export default config({ ```typescript export default config({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -306,7 +306,7 @@ export default config({ authors: relationship({ ref: 'User.posts', many: true }), }, }), - }), + }, }); ``` diff --git a/docs/pages/docs/guides/virtual-fields.mdx b/docs/pages/docs/guides/virtual-fields.mdx index 7d7f14f6f61..8743a40428c 100644 --- a/docs/pages/docs/guides/virtual-fields.mdx +++ b/docs/pages/docs/guides/virtual-fields.mdx @@ -18,11 +18,11 @@ In this guide we'll introduce the syntax for adding virtual fields, and show how We'll start with a list called `Example` and create a virtual field called `hello`. ```typescript -import { config, createSchema, list, graphql } from '@keystone-next/keystone'; +import { config, list, graphql } from '@keystone-next/keystone'; import { virtual } from '@keystone-next/keystone/fields'; export default config({ - lists: createSchema({ + lists: { Example: list({ fields: { hello: virtual({ @@ -35,7 +35,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -87,7 +87,7 @@ We can do this with a `virtual` field which queries for the related `author` and ```typescript export default config({ - lists: createSchema({ + lists: { Post: list({ fields: { content: text(), @@ -111,7 +111,7 @@ export default config({ name: text({ isRequired: true }), }, }), - }), + }, }); ``` @@ -126,7 +126,7 @@ We use the `args` option to define the GraphQL field arguments we want to suppor ```typescript export default config({ - lists: createSchema({ + lists: { Post: list({ fields: { content: text(), @@ -155,7 +155,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -193,7 +193,7 @@ We can set up a GraphQL type called `PostCounts` to represent this data using th ```typescript export default config({ - lists: createSchema({ + lists: { Post: list({ fields: { content: text(), @@ -224,7 +224,7 @@ export default config({ }), }, }), - }), + }, }); ``` @@ -262,7 +262,7 @@ The argument `lists` contains the type information for all of the Keystone lists In our case, we want the output type of the `Post` list, so we specify `type: lists.Post.types.output`. ```ts -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text(), @@ -299,7 +299,7 @@ export const lists = createSchema({ }), }, }), -}); +}; ``` Once again we need to specify `graphQLReturnFragment` on this virtual field to specify which fields of the `Post` to display in the Admin UI. diff --git a/docs/pages/index.tsx b/docs/pages/index.tsx index 691b5dfecff..d0531c1ec4d 100644 --- a/docs/pages/index.tsx +++ b/docs/pages/index.tsx @@ -414,10 +414,10 @@ export default function IndexPage() { - {`import { createSchema, list } from '@keystone-next/keystone'; + {`import { list } from '@keystone-next/keystone'; import { document, text, timestamp, password, relationship } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -434,7 +434,7 @@ export const lists = createSchema({ posts: relationship({ ref: 'Post.author', many: true }), }, }), -});`} +};`} diff --git a/docs/pages/updates/new-access-control.mdx b/docs/pages/updates/new-access-control.mdx index a76359bf146..01aa8ed82ea 100644 --- a/docs/pages/updates/new-access-control.mdx +++ b/docs/pages/updates/new-access-control.mdx @@ -13,16 +13,16 @@ Previous versions of Keystone allowed you to control which operations were inclu For example, the following access control definition would omit all delete operations for the list from the GraphQL API. ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { delete: false, }, }), - }), + }, }); ``` @@ -32,16 +32,16 @@ If you would like to exclude an operation from the GraphQL API, you can use the To exclude all `delete` operations, you would write: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ graphql: { omit: ['delete'], } }), - }), + }, }); ``` @@ -75,10 +75,10 @@ If you are using **static** access control, you will generally want to update th If you previously had the following: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { create: false, @@ -87,17 +87,17 @@ export default config({ delete: false, }, }), - }), + }, }); ``` you will need to change it to: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { operation: { @@ -108,7 +108,7 @@ export default config({ } }, }), - }), + }, }); ``` @@ -120,10 +120,10 @@ If you are using **declarative** access control, you will neeed to update this t If you previously had the following: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { read: { isAdmin: { equals: true } }, @@ -131,17 +131,17 @@ export default config({ delete: { isAdmin: { equals: true } }, }, }), - }), + }, }); ``` you will need to change it to: ```typescript -import { config, createSchema, list } from '@keystone-next/keystone'; +import { config, list } from '@keystone-next/keystone'; export default config({ - lists: createSchema({ + lists: { ListKey: list({ access: { filter: { @@ -151,7 +151,7 @@ export default config({ } }, }), - }), + }, }); ``` diff --git a/docs/pages/updates/new-graphql-api.mdx b/docs/pages/updates/new-graphql-api.mdx index aac4440fd5c..7930850bf41 100644 --- a/docs/pages/updates/new-graphql-api.mdx +++ b/docs/pages/updates/new-graphql-api.mdx @@ -13,8 +13,8 @@ This guide describes the improvements we've made, and walks you through the step To illustrate the changes, we’ll refer to the `Task` list in the following schema, from our [Task Manager](https://github.com/keystonejs/keystone/tree/master/examples/task-manager) example project. -``` -export const lists = createSchema({ +```ts +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -43,7 +43,7 @@ export const lists = createSchema({ name: text(), }, }), -}); +}; ``` ## Query diff --git a/examples-staging/assets-cloud/schema.ts b/examples-staging/assets-cloud/schema.ts index 478a0fd5de2..a812e4cf49b 100644 --- a/examples-staging/assets-cloud/schema.ts +++ b/examples-staging/assets-cloud/schema.ts @@ -1,7 +1,7 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp, image, file } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -26,4 +26,4 @@ export const lists = createSchema({ posts: relationship({ ref: 'Post.author', many: true }), }, }), -}); +}; diff --git a/examples-staging/assets-local/schema.ts b/examples-staging/assets-local/schema.ts index 942a94bb07f..41cd681b398 100644 --- a/examples-staging/assets-local/schema.ts +++ b/examples-staging/assets-local/schema.ts @@ -1,7 +1,7 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp, image } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -25,4 +25,4 @@ export const lists = createSchema({ posts: relationship({ ref: 'Post.author', many: true }), }, }), -}); +}; diff --git a/examples-staging/auth/schema.ts b/examples-staging/auth/schema.ts index 53fbc34f957..0e9c2321417 100644 --- a/examples-staging/auth/schema.ts +++ b/examples-staging/auth/schema.ts @@ -1,7 +1,7 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text, checkbox, password } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { User: list({ access: { operation: { @@ -80,4 +80,4 @@ export const lists = createSchema({ */ }, }), -}); +}; diff --git a/examples-staging/basic/schema.ts b/examples-staging/basic/schema.ts index 9cf3fe8eef4..d3c0039db76 100644 --- a/examples-staging/basic/schema.ts +++ b/examples-staging/basic/schema.ts @@ -1,4 +1,4 @@ -import { createSchema, list, graphQLSchemaExtension, gql } from '@keystone-next/keystone'; +import { list, graphQLSchemaExtension, gql } from '@keystone-next/keystone'; import { text, relationship, @@ -34,7 +34,7 @@ export const access = { const randomNumber = () => Math.round(Math.random() * 10); -export const lists = createSchema({ +export const lists = { User: list({ ui: { listView: { @@ -186,7 +186,7 @@ export const lists = createSchema({ }), }, }), -}); +}; export const extendGraphqlSchema = graphQLSchemaExtension({ typeDefs: gql` diff --git a/examples-staging/ecommerce/keystone.ts b/examples-staging/ecommerce/keystone.ts index 303ee2712eb..cc82aec7b2e 100644 --- a/examples-staging/ecommerce/keystone.ts +++ b/examples-staging/ecommerce/keystone.ts @@ -1,5 +1,5 @@ import { createAuth } from '@keystone-next/auth'; -import { config, createSchema } from '@keystone-next/keystone'; +import { config } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { permissionsList } from './schemas/fields'; import { Role } from './schemas/Role'; @@ -59,7 +59,7 @@ export default withAuth( } }, }, - lists: createSchema({ + lists: { // Schema items go in here User, Product, @@ -68,7 +68,7 @@ export default withAuth( OrderItem, Order, Role, - }), + }, extendGraphqlSchema, ui: { // Show the UI only for poeple who pass this test diff --git a/examples-staging/graphql-api-endpoint/schema.ts b/examples-staging/graphql-api-endpoint/schema.ts index 6a5e5e3f765..448103f25de 100644 --- a/examples-staging/graphql-api-endpoint/schema.ts +++ b/examples-staging/graphql-api-endpoint/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text, relationship, password, timestamp, select } from '@keystone-next/keystone/fields'; import { document } from '@keystone-next/fields-document'; -export const lists = createSchema({ +export const lists = { User: list({ ui: { listView: { @@ -77,4 +77,4 @@ export const lists = createSchema({ }), }, }), -}); +}; diff --git a/examples-staging/roles/schema.ts b/examples-staging/roles/schema.ts index cafa0c91367..cd8f557abff 100644 --- a/examples-staging/roles/schema.ts +++ b/examples-staging/roles/schema.ts @@ -1,4 +1,4 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, password, relationship, text } from '@keystone-next/keystone/fields'; import { isSignedIn, permissions, rules } from './access'; @@ -12,7 +12,7 @@ import { isSignedIn, permissions, rules } from './access'; - All users can see and manage todo items assigned to themselves */ -export const lists = createSchema({ +export const lists = { Todo: list({ /* SPEC @@ -228,4 +228,4 @@ export const lists = createSchema({ }), }, }), -}); +}; diff --git a/examples-staging/sandbox/schema.ts b/examples-staging/sandbox/schema.ts index 9951884f46d..18db3479f60 100644 --- a/examples-staging/sandbox/schema.ts +++ b/examples-staging/sandbox/schema.ts @@ -1,4 +1,4 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, password, relationship, text, timestamp } from '@keystone-next/keystone/fields'; // this implementation for createdBy and updatedBy is currently wrong so they're disabled for now @@ -44,7 +44,7 @@ const trackingFields = { // }), }; -export const lists = createSchema({ +export const lists = { Todo: list({ ui: { listView: { @@ -79,4 +79,4 @@ export const lists = createSchema({ ...trackingFields, }, }), -}); +}; diff --git a/examples/blog/schema.ts b/examples/blog/schema.ts index 62895796062..f17487891b5 100644 --- a/examples/blog/schema.ts +++ b/examples/blog/schema.ts @@ -1,7 +1,7 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true, isFilterable: true }), @@ -24,4 +24,4 @@ export const lists = createSchema({ posts: relationship({ ref: 'Post.author', many: true }), }, }), -}); +}; diff --git a/examples/custom-admin-ui-logo/schema.ts b/examples/custom-admin-ui-logo/schema.ts index d76a4cb034d..4f58914a068 100644 --- a/examples/custom-admin-ui-logo/schema.ts +++ b/examples/custom-admin-ui-logo/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -29,4 +29,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/custom-admin-ui-navigation/schema.ts b/examples/custom-admin-ui-navigation/schema.ts index d76a4cb034d..4f58914a068 100644 --- a/examples/custom-admin-ui-navigation/schema.ts +++ b/examples/custom-admin-ui-navigation/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -29,4 +29,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/custom-admin-ui-pages/schema.ts b/examples/custom-admin-ui-pages/schema.ts index d76a4cb034d..4f58914a068 100644 --- a/examples/custom-admin-ui-pages/schema.ts +++ b/examples/custom-admin-ui-pages/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -29,4 +29,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/custom-field-view/schema.ts b/examples/custom-field-view/schema.ts index 241c9f22f28..fd8dc227ba4 100644 --- a/examples/custom-field-view/schema.ts +++ b/examples/custom-field-view/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { json, select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -38,4 +38,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/custom-field/schema.ts b/examples/custom-field/schema.ts index 594a821aa73..c8d35f59045 100644 --- a/examples/custom-field/schema.ts +++ b/examples/custom-field/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { stars } from './stars-field'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -26,4 +26,4 @@ export const lists = createSchema({ posts: relationship({ ref: 'Post.author', many: true }), }, }), -}); +}; diff --git a/examples/default-values/schema.ts b/examples/default-values/schema.ts index f588c36b1c0..eb67be4ae12 100644 --- a/examples/default-values/schema.ts +++ b/examples/default-values/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -61,4 +61,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/document-field/schema.ts b/examples/document-field/schema.ts index c28a69b16a4..bf7810e03fa 100644 --- a/examples/document-field/schema.ts +++ b/examples/document-field/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { document } from '@keystone-next/fields-document'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -60,4 +60,4 @@ export const lists = createSchema({ }), }, }), -}); +}; diff --git a/examples/extend-graphql-schema/schema.ts b/examples/extend-graphql-schema/schema.ts index 03a0990402f..bfd97c00f04 100644 --- a/examples/extend-graphql-schema/schema.ts +++ b/examples/extend-graphql-schema/schema.ts @@ -1,7 +1,7 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -24,4 +24,4 @@ export const lists = createSchema({ posts: relationship({ ref: 'Post.author', many: true }), }, }), -}); +}; diff --git a/examples/json/schema.ts b/examples/json/schema.ts index 2eaf23d0815..4febb3863af 100644 --- a/examples/json/schema.ts +++ b/examples/json/schema.ts @@ -1,7 +1,7 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, json, relationship, text } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Package: list({ fields: { label: text({ isRequired: true }), @@ -16,4 +16,4 @@ export const lists = createSchema({ packages: relationship({ ref: 'Package.ownedBy', many: true }), }, }), -}); +}; diff --git a/examples/task-manager/schema.ts b/examples/task-manager/schema.ts index d76a4cb034d..4f58914a068 100644 --- a/examples/task-manager/schema.ts +++ b/examples/task-manager/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -29,4 +29,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/testing/schema.ts b/examples/testing/schema.ts index 6d2e24930c6..6e60ed3665a 100644 --- a/examples/testing/schema.ts +++ b/examples/testing/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, password, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -44,4 +44,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/examples/virtual-field/schema.ts b/examples/virtual-field/schema.ts index d6e26dcc0e7..fea52fcc586 100644 --- a/examples/virtual-field/schema.ts +++ b/examples/virtual-field/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { select, relationship, text, timestamp, virtual } from '@keystone-next/keystone/fields'; import { graphql } from '@keystone-next/keystone/types'; -export const lists = createSchema({ +export const lists = { Post: list({ fields: { title: text({ isRequired: true }), @@ -117,4 +117,4 @@ export const lists = createSchema({ }), }, }), -}); +}; diff --git a/examples/with-auth/schema.ts b/examples/with-auth/schema.ts index bb286a09ad8..4580895bc8c 100644 --- a/examples/with-auth/schema.ts +++ b/examples/with-auth/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, password, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -37,4 +37,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; diff --git a/packages/keystone/src/index.ts b/packages/keystone/src/index.ts index 1d0caedc1bb..743379e5cab 100644 --- a/packages/keystone/src/index.ts +++ b/packages/keystone/src/index.ts @@ -1,2 +1,2 @@ -export { createSchema, list, gql, graphQLSchemaExtension, config } from './schema/schema'; +export { list, gql, graphQLSchemaExtension, config } from './schema/schema'; export type { ListSchemaConfig, ListConfig, ExtendGraphqlSchema, BaseFields } from './types'; diff --git a/packages/keystone/src/schema/schema.ts b/packages/keystone/src/schema/schema.ts index 7b1ced29d33..7452fc92f1d 100644 --- a/packages/keystone/src/schema/schema.ts +++ b/packages/keystone/src/schema/schema.ts @@ -8,13 +8,8 @@ import type { GraphQLSchemaExtension, KeystoneConfig, ListConfig, - ListSchemaConfig, } from '../types'; -export function createSchema(config: ListSchemaConfig) { - return config; -} - export function config(config: KeystoneConfig) { return config; } diff --git a/tests/api-tests/access-control/mutations-field.test.ts b/tests/api-tests/access-control/mutations-field.test.ts index 83a432140bf..e19f24c348b 100644 --- a/tests/api-tests/access-control/mutations-field.test.ts +++ b/tests/api-tests/access-control/mutations-field.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectAccessDenied, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { // Imperative -> Static access control User: list({ fields: { @@ -43,7 +43,7 @@ const runner = setupTestRunner({ }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/access-control/mutations-list-filter.test.ts b/tests/api-tests/access-control/mutations-list-filter.test.ts index 89301875592..3c50df09187 100644 --- a/tests/api-tests/access-control/mutations-list-filter.test.ts +++ b/tests/api-tests/access-control/mutations-list-filter.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectAccessDenied } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { // Filter access control User: list({ fields: { name: text({ isOrderable: true }) }, @@ -17,7 +17,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, }), }); diff --git a/tests/api-tests/access-control/mutations-list-item.test.ts b/tests/api-tests/access-control/mutations-list-item.test.ts index 3501912d343..21acf7c35b6 100644 --- a/tests/api-tests/access-control/mutations-list-item.test.ts +++ b/tests/api-tests/access-control/mutations-list-item.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectAccessDenied, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { // Item access control User: list({ fields: { name: text({ isFilterable: true, isOrderable: true }) }, @@ -42,7 +42,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, }), }); diff --git a/tests/api-tests/access-control/mutations-list-operation.test.ts b/tests/api-tests/access-control/mutations-list-operation.test.ts index 362c74e77e9..e38b4787b4d 100644 --- a/tests/api-tests/access-control/mutations-list-operation.test.ts +++ b/tests/api-tests/access-control/mutations-list-operation.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { BadAccess: list({ fields: { name: text({ isFilterable: true, isOrderable: true }) }, access: { @@ -29,7 +29,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, }), }); diff --git a/tests/api-tests/access-control/schema-utils.ts b/tests/api-tests/access-control/schema-utils.ts index dd327509ac4..e5b262ef9ef 100644 --- a/tests/api-tests/access-control/schema-utils.ts +++ b/tests/api-tests/access-control/schema-utils.ts @@ -1,5 +1,5 @@ import { relationship, text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list, ListSchemaConfig } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { apiTestConfig } from '../utils'; @@ -100,7 +100,7 @@ const createRelatedFields = (config: ListConfig) => ({ [`${getListPrefix(config)}many`]: relationship({ ref: getListName(config), many: true }), }); -const lists = createSchema({}); +const lists: ListSchemaConfig = {}; listConfigVariables.forEach(config => { lists[getListName(config)] = list({ diff --git a/tests/api-tests/access-control/utils.ts b/tests/api-tests/access-control/utils.ts index 0b01e6b2c82..77db5080a3e 100644 --- a/tests/api-tests/access-control/utils.ts +++ b/tests/api-tests/access-control/utils.ts @@ -1,5 +1,5 @@ import { text, password } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list, ListSchemaConfig } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import { apiTestConfig } from '../utils'; @@ -103,7 +103,7 @@ const createFieldImperative = (fieldAccess: BooleanAccess) => ({ }), }); -const lists = createSchema({ +const lists: ListSchemaConfig = { User: list({ fields: { name: text(), @@ -113,7 +113,7 @@ const lists = createSchema({ yesRead: text({ access: { read: () => true } }), }, }), -}); +}; listAccessVariations.forEach(access => { lists[getOperationListName(access)] = list({ diff --git a/tests/api-tests/auth-header.test.ts b/tests/api-tests/auth-header.test.ts index aef52148738..46634f7ded6 100644 --- a/tests/api-tests/auth-header.test.ts +++ b/tests/api-tests/auth-header.test.ts @@ -1,5 +1,5 @@ import { text, timestamp, password } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import type { KeystoneContext } from '@keystone-next/keystone/types'; @@ -26,7 +26,7 @@ const auth = createAuth({ const runner = setupTestRunner({ config: auth.withAuth( apiTestConfig({ - lists: createSchema({ + lists: { Post: list({ fields: { title: text(), @@ -48,7 +48,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, session: statelessSessions({ secret: COOKIE_SECRET }), }) ), @@ -106,7 +106,7 @@ describe('Auth testing', () => { setupTestEnv({ config: auth.withAuth( apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -114,7 +114,7 @@ describe('Auth testing', () => { password: password(), }, }), - }), + }, session: statelessSessions({ secret: COOKIE_SECRET }), }) diff --git a/tests/api-tests/default-value/defaults.test.ts b/tests/api-tests/default-value/defaults.test.ts index f49abb82580..e4e2a7facac 100644 --- a/tests/api-tests/default-value/defaults.test.ts +++ b/tests/api-tests/default-value/defaults.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { BaseFields } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../utils'; const setupList = (fields: BaseFields) => - setupTestRunner({ config: apiTestConfig({ lists: createSchema({ User: list({ fields }) }) }) }); + setupTestRunner({ config: apiTestConfig({ lists: { User: list({ fields }) } }) }); describe('defaultValue field config', () => { test( diff --git a/tests/api-tests/extend-express-app.test.ts b/tests/api-tests/extend-express-app.test.ts index 0018cc2c53a..78f90c99200 100644 --- a/tests/api-tests/extend-express-app.test.ts +++ b/tests/api-tests/extend-express-app.test.ts @@ -1,4 +1,4 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import supertest from 'supertest'; @@ -6,7 +6,7 @@ import { apiTestConfig } from './utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ User: list({ fields: { name: text() } }) }), + lists: { User: list({ fields: { name: text() } }) }, server: { extendExpressApp: app => { app.get('/magic', (req, res) => { diff --git a/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts b/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts index 97a4acc3d37..44c77b6ae63 100644 --- a/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts +++ b/tests/api-tests/extend-graphql-schema/extend-graphql-schema.test.ts @@ -1,4 +1,4 @@ -import { createSchema, list, graphQLSchemaExtension, gql } from '@keystone-next/keystone'; +import { list, graphQLSchemaExtension, gql } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectInternalServerError } from '../utils'; @@ -23,11 +23,11 @@ const withAccessCheck = ( const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text() }, }), - }), + }, extendGraphqlSchema: graphQLSchemaExtension({ typeDefs: gql` type Query { diff --git a/tests/api-tests/fields/crud.test.ts b/tests/api-tests/fields/crud.test.ts index b212f296e7b..1993b38d1bf 100644 --- a/tests/api-tests/fields/crud.test.ts +++ b/tests/api-tests/fields/crud.test.ts @@ -1,5 +1,5 @@ import globby from 'globby'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { setupTestRunner } from '@keystone-next/keystone/testing'; @@ -21,14 +21,14 @@ testModules const listKey = 'Test'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { [listKey]: list({ fields: { name: text({ isOrderable: true }), ...mod.getTestFields(matrixValue), }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), diff --git a/tests/api-tests/fields/filter.test.ts b/tests/api-tests/fields/filter.test.ts index 309012a9d73..177111be5e9 100644 --- a/tests/api-tests/fields/filter.test.ts +++ b/tests/api-tests/fields/filter.test.ts @@ -1,5 +1,5 @@ import globby from 'globby'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { setupTestRunner } from '@keystone-next/keystone/testing'; @@ -19,11 +19,11 @@ testModules const listKey = 'Test'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { [listKey]: list({ fields: { name: text({ isOrderable: true }), ...mod.getTestFields(matrixValue) }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), @@ -410,13 +410,13 @@ testModules 'Unique equality', setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { [listKey]: list({ fields: { field: mod.typeFunction({ isIndexed: 'unique', isFilterable: true }), }, }), - }), + }, }), })(async ({ context }) => { // Populate the database before running the tests diff --git a/tests/api-tests/fields/non-null.test.ts b/tests/api-tests/fields/non-null.test.ts index 01abe2fc236..ab709af60f4 100644 --- a/tests/api-tests/fields/non-null.test.ts +++ b/tests/api-tests/fields/non-null.test.ts @@ -1,5 +1,5 @@ import globby from 'globby'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestEnv } from '@keystone-next/keystone/testing'; import { assertInputObjectType, assertObjectType, GraphQLNonNull } from 'graphql'; @@ -41,7 +41,7 @@ testModules const getSchema = async (fieldConfig: any) => { const { testArgs } = await setupTestEnv({ config: apiTestConfig({ - lists: createSchema({ + lists: { Test: list({ fields: { name: text(), @@ -51,7 +51,7 @@ testModules }), }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), diff --git a/tests/api-tests/fields/required.test.ts b/tests/api-tests/fields/required.test.ts index 164d04c54a7..7b74e7481a9 100644 --- a/tests/api-tests/fields/required.test.ts +++ b/tests/api-tests/fields/required.test.ts @@ -1,5 +1,5 @@ import globby from 'globby'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectValidationError } from '../utils'; @@ -39,7 +39,7 @@ testModules const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Test: list({ fields: { name: text(), @@ -49,7 +49,7 @@ testModules }), }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), diff --git a/tests/api-tests/fields/types/Virtual.test.ts b/tests/api-tests/fields/types/Virtual.test.ts index 23c69fd4a85..6eb5c92f285 100644 --- a/tests/api-tests/fields/types/Virtual.test.ts +++ b/tests/api-tests/fields/types/Virtual.test.ts @@ -1,5 +1,5 @@ import { integer, relationship, text, virtual } from '@keystone-next/keystone/fields'; -import { BaseFields, createSchema, list } from '@keystone-next/keystone'; +import { BaseFields, list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { graphql } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -7,14 +7,14 @@ import { apiTestConfig } from '../../utils'; function makeRunner(fields: BaseFields) { return setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Post: list({ fields: { value: integer(), ...fields, }, }), - }), + }, }), }); } @@ -91,7 +91,7 @@ describe('Virtual field type', () => { 'referencing other list type', setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Organisation: list({ fields: { name: text(), @@ -147,7 +147,7 @@ describe('Virtual field type', () => { }), }, }), - }), + }, }), })(async ({ context }) => { const data = await context.lists.Post.createOne({ diff --git a/tests/api-tests/fields/types/document.test.ts b/tests/api-tests/fields/types/document.test.ts index 2abfe69616f..a45aa63f55d 100644 --- a/tests/api-tests/fields/types/document.test.ts +++ b/tests/api-tests/fields/types/document.test.ts @@ -1,13 +1,13 @@ import { text } from '@keystone-next/keystone/fields'; import { document } from '@keystone-next/fields-document'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig, expectInternalServerError } from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Post: list({ fields: { content: document({ @@ -48,7 +48,7 @@ const runner = setupTestRunner({ }, access: { filter: { query: () => ({ name: { not: { equals: 'Charlie' } } }) } }, }), - }), + }, }), }); diff --git a/tests/api-tests/fields/unique.test.ts b/tests/api-tests/fields/unique.test.ts index 4ec24060d6a..c93c1ecc098 100644 --- a/tests/api-tests/fields/unique.test.ts +++ b/tests/api-tests/fields/unique.test.ts @@ -1,5 +1,5 @@ import globby from 'globby'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestEnv, setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectPrismaError } from '../utils'; @@ -39,7 +39,7 @@ testModules }); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Test: list({ fields: { name: text(), @@ -49,7 +49,7 @@ testModules }), }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), @@ -147,7 +147,7 @@ testModules try { await setupTestEnv({ config: apiTestConfig({ - lists: createSchema({ + lists: { Test: list({ fields: { name: text(), @@ -157,7 +157,7 @@ testModules }), }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), diff --git a/tests/api-tests/fields/unsupported.test.ts b/tests/api-tests/fields/unsupported.test.ts index 23c628d680b..8491d7967ef 100644 --- a/tests/api-tests/fields/unsupported.test.ts +++ b/tests/api-tests/fields/unsupported.test.ts @@ -1,5 +1,5 @@ import globby from 'globby'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestEnv } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../utils'; @@ -45,11 +45,11 @@ if (unsupportedModules.length > 0) { async () => await setupTestEnv({ config: apiTestConfig({ - lists: createSchema({ + lists: { [listKey]: list({ fields: { name: text(), ...mod.getTestFields(matrixValue) }, }), - }), + }, images: { upload: 'local', local: { storagePath: 'tmp_test_images' } }, files: { upload: 'local', local: { storagePath: 'tmp_test_files' } }, }), diff --git a/tests/api-tests/healthcheck.test.ts b/tests/api-tests/healthcheck.test.ts index 62495f92811..8b15cb72d02 100644 --- a/tests/api-tests/healthcheck.test.ts +++ b/tests/api-tests/healthcheck.test.ts @@ -1,4 +1,4 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import supertest from 'supertest'; @@ -7,7 +7,7 @@ import { apiTestConfig } from './utils'; const makeRunner = (healthCheck: any) => setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ User: list({ fields: { name: text() } }) }), + lists: { User: list({ fields: { name: text() } }) }, server: { healthCheck }, }), }); diff --git a/tests/api-tests/hooks/auth-hooks.test.skip.ts b/tests/api-tests/hooks/auth-hooks.test.skip.ts index f2b2964c7fe..ff4f3d34747 100644 --- a/tests/api-tests/hooks/auth-hooks.test.skip.ts +++ b/tests/api-tests/hooks/auth-hooks.test.skip.ts @@ -2,14 +2,14 @@ import { AddressInfo } from 'net'; // @ts-ignore import superagent from 'superagent'; import express from 'express'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text, password } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -17,7 +17,7 @@ const runner = setupTestRunner({ password: password(), }, }), - }), + }, }), }); diff --git a/tests/api-tests/hooks/hook-errors.test.ts b/tests/api-tests/hooks/hook-errors.test.ts index c70c7cb39da..d019ee58baf 100644 --- a/tests/api-tests/hooks/hook-errors.test.ts +++ b/tests/api-tests/hooks/hook-errors.test.ts @@ -1,5 +1,5 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { GraphQLRequest, setupTestRunner } from '@keystone-next/keystone/testing'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig, expectExtensionError } from '../utils'; @@ -7,7 +7,7 @@ import { apiTestConfig, expectExtensionError } from '../utils'; const runner = (debug: boolean | undefined) => setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isFilterable: true, isOrderable: true }) }, hooks: { @@ -85,7 +85,7 @@ const runner = (debug: boolean | undefined) => }), }, }), - }), + }, graphql: { debug }, }), }); diff --git a/tests/api-tests/hooks/list-hooks.test.ts b/tests/api-tests/hooks/list-hooks.test.ts index 42ef12e4b68..f4a778288bb 100644 --- a/tests/api-tests/hooks/list-hooks.test.ts +++ b/tests/api-tests/hooks/list-hooks.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectExtensionError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ @@ -31,7 +31,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, }), }); diff --git a/tests/api-tests/hooks/validation.test.ts b/tests/api-tests/hooks/validation.test.ts index 5b6e6d7c095..7e4c8db8a35 100644 --- a/tests/api-tests/hooks/validation.test.ts +++ b/tests/api-tests/hooks/validation.test.ts @@ -1,11 +1,11 @@ import { text } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectValidationError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isOrderable: true }) }, hooks: { @@ -60,7 +60,7 @@ const runner = setupTestRunner({ }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/id-field.test.ts b/tests/api-tests/id-field.test.ts index fcc03d0002b..1281bf57560 100644 --- a/tests/api-tests/id-field.test.ts +++ b/tests/api-tests/id-field.test.ts @@ -1,4 +1,4 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { isCuid } from 'cuid'; @@ -13,9 +13,9 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { const runner = setupTestRunner({ config: apiTestConfig({ db: { idField: { kind } }, - lists: createSchema({ + lists: { User: list({ fields: { name: text() } }), - }), + }, }), }); test( @@ -131,9 +131,9 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { const runner = setupTestRunner({ config: apiTestConfig({ db: { idField: { kind: 'uuid' } }, - lists: createSchema({ + lists: { User: list({ fields: { name: text() } }), - }), + }, }), }); test( @@ -155,9 +155,9 @@ describe.each(['autoincrement', 'cuid', 'uuid'] as const)('%s', kind => { const runner = setupTestRunner({ config: apiTestConfig({ db: { idField: { kind: 'cuid' } }, - lists: createSchema({ + lists: { User: list({ fields: { name: text() } }), - }), + }, }), }); test( diff --git a/tests/api-tests/new-interfaces.test.ts b/tests/api-tests/new-interfaces.test.ts index 3c488566285..f4a1b3bea00 100644 --- a/tests/api-tests/new-interfaces.test.ts +++ b/tests/api-tests/new-interfaces.test.ts @@ -1,13 +1,13 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { text } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from './utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text() } }), - }), + }, }), }); diff --git a/tests/api-tests/queries/cache-hints.test.ts b/tests/api-tests/queries/cache-hints.test.ts index 23ebd2ba93c..c97f9c3b84c 100644 --- a/tests/api-tests/queries/cache-hints.test.ts +++ b/tests/api-tests/queries/cache-hints.test.ts @@ -1,13 +1,13 @@ import { CacheScope } from 'apollo-server-types'; import { text, relationship, integer } from '@keystone-next/keystone/fields'; -import { list, createSchema, graphQLSchemaExtension } from '@keystone-next/keystone'; +import { list, graphQLSchemaExtension } from '@keystone-next/keystone'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Post: list({ fields: { title: text(), @@ -40,7 +40,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, extendGraphqlSchema: graphQLSchemaExtension({ typeDefs: ` type MyType { diff --git a/tests/api-tests/queries/filters.test.ts b/tests/api-tests/queries/filters.test.ts index 6efb773192f..d7f0b56bed2 100644 --- a/tests/api-tests/queries/filters.test.ts +++ b/tests/api-tests/queries/filters.test.ts @@ -1,11 +1,11 @@ import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectInternalServerError } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { noDash: text({ isFilterable: true, isOrderable: true }), @@ -21,7 +21,7 @@ const runner = setupTestRunner({ otherUsers: relationship({ ref: 'User', isFilterable: true, many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/queries/limits.test.ts b/tests/api-tests/queries/limits.test.ts index c94ea3caac8..61d194a18b9 100644 --- a/tests/api-tests/queries/limits.test.ts +++ b/tests/api-tests/queries/limits.test.ts @@ -1,12 +1,12 @@ import { text, integer, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectGraphQLValidationError, expectLimitsExceededError } from '../utils'; import { depthLimit, definitionLimit, fieldLimit } from './validation'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Post: list({ fields: { title: text({ isFilterable: true, isOrderable: true }), @@ -25,7 +25,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, graphql: { queryLimits: { maxTotalResults: 6 }, apolloConfig: { diff --git a/tests/api-tests/queries/orderBy.test.ts b/tests/api-tests/queries/orderBy.test.ts index 972a71c5bcf..349cf29358e 100644 --- a/tests/api-tests/queries/orderBy.test.ts +++ b/tests/api-tests/queries/orderBy.test.ts @@ -1,19 +1,19 @@ import { integer } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig, expectBadUserInput } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { a: integer({ isOrderable: true }), b: integer({ isOrderable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/queries/relationships.test.ts b/tests/api-tests/queries/relationships.test.ts index 7cdaa582dfd..7b2bf4d537d 100644 --- a/tests/api-tests/queries/relationships.test.ts +++ b/tests/api-tests/queries/relationships.test.ts @@ -1,7 +1,7 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../utils'; @@ -9,7 +9,7 @@ const alphanumGenerator = gen.alphaNumString.notEmpty(); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Post: list({ fields: { title: text({ isFilterable: true, isOrderable: true }), @@ -22,7 +22,7 @@ const runner = setupTestRunner({ feed: relationship({ ref: 'Post', many: true, isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts index c975aab4dfe..c45be843afd 100644 --- a/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/many-to-many-one-sided.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -79,14 +79,14 @@ const createReadData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isFilterable: true }), friends: relationship({ ref: 'User', many: true, isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts b/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts index f0c8d3b123c..a795bdd816a 100644 --- a/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/many-to-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -84,7 +84,7 @@ const createReadData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isFilterable: true }), @@ -92,7 +92,7 @@ const runner = setupTestRunner({ friends: relationship({ ref: 'User.friendOf', many: true, isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts index af9d01ca965..9dc67841fa3 100644 --- a/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/one-to-many-one-sided.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -78,14 +78,14 @@ const getUserAndFriend = async (context: KeystoneContext, userId: IdType, friend const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isFilterable: true, isOrderable: true }), friend: relationship({ ref: 'User', isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts b/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts index 10934b820cf..ab550a4ebda 100644 --- a/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/one-to-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -79,7 +79,7 @@ const createReadData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isFilterable: true, isOrderable: true }), @@ -91,7 +91,7 @@ const runner = setupTestRunner({ }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts b/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts index 592c6ec029c..1ac9117fba3 100644 --- a/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts +++ b/tests/api-tests/relationships/crud-self-ref/one-to-one.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -59,7 +59,7 @@ const getUserAndFriend = async (context: KeystoneContext, userId: IdType, friend const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text({ isFilterable: true }), @@ -67,7 +67,7 @@ const runner = setupTestRunner({ friend: relationship({ ref: 'User.friendOf', isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts index 11b0dd67944..8d5efe114c1 100644 --- a/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud/many-to-many-one-sided.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -88,7 +88,7 @@ const createReadData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Company: list({ fields: { name: text(), @@ -96,7 +96,7 @@ const runner = setupTestRunner({ }, }), Location: list({ fields: { name: text({ isFilterable: true }) } }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud/many-to-many.test.ts b/tests/api-tests/relationships/crud/many-to-many.test.ts index 20c9f7b3f07..f16747082dc 100644 --- a/tests/api-tests/relationships/crud/many-to-many.test.ts +++ b/tests/api-tests/relationships/crud/many-to-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -94,7 +94,7 @@ const createReadData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Company: list({ fields: { name: text(), @@ -107,7 +107,7 @@ const runner = setupTestRunner({ companies: relationship({ ref: 'Company.locations', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts b/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts index 5df8438a05c..e2675abf189 100644 --- a/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts +++ b/tests/api-tests/relationships/crud/one-to-many-one-sided.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -100,7 +100,7 @@ const getCompanyAndLocation = async ( const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Company: list({ fields: { name: text({ isOrderable: true }), @@ -112,7 +112,7 @@ const runner = setupTestRunner({ name: text({ isFilterable: true, isOrderable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud/one-to-many.test.ts b/tests/api-tests/relationships/crud/one-to-many.test.ts index 4f9de0c30d4..7c3acd2127d 100644 --- a/tests/api-tests/relationships/crud/one-to-many.test.ts +++ b/tests/api-tests/relationships/crud/one-to-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -87,7 +87,7 @@ const createReadData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Company: list({ fields: { name: text({ isFilterable: true, isOrderable: true }), @@ -100,7 +100,7 @@ const runner = setupTestRunner({ company: relationship({ ref: 'Company.locations', isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/crud/one-to-one.test.ts b/tests/api-tests/relationships/crud/one-to-one.test.ts index 2a6a8ba1cb7..8a632740b79 100644 --- a/tests/api-tests/relationships/crud/one-to-one.test.ts +++ b/tests/api-tests/relationships/crud/one-to-one.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import type { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -93,7 +93,7 @@ const getCompanyAndLocation = async ( const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Company: list({ fields: { name: text({ isFilterable: true }), @@ -106,7 +106,7 @@ const runner = setupTestRunner({ company: relationship({ ref: 'Company.location', isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/filtering/access-control.test.ts b/tests/api-tests/relationships/filtering/access-control.test.ts index 690ddd794bf..3e89f7fc464 100644 --- a/tests/api-tests/relationships/filtering/access-control.test.ts +++ b/tests/api-tests/relationships/filtering/access-control.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../../utils'; @@ -10,7 +10,7 @@ const postNames = ['Post 1', 'Post 2', 'Post 3']; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { UserToPostLimitedRead: list({ fields: { username: text(), @@ -29,7 +29,7 @@ const runner = setupTestRunner({ }, }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/filtering/filtering.test.ts b/tests/api-tests/relationships/filtering/filtering.test.ts index 887588264d7..401841cb009 100644 --- a/tests/api-tests/relationships/filtering/filtering.test.ts +++ b/tests/api-tests/relationships/filtering/filtering.test.ts @@ -1,5 +1,5 @@ import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../../utils'; @@ -7,7 +7,7 @@ type IdType = any; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { company: relationship({ ref: 'Company', isFilterable: true }), @@ -16,7 +16,7 @@ const runner = setupTestRunner({ }), Company: list({ fields: { name: text({ isFilterable: true }) } }), Post: list({ fields: { content: text({ isFilterable: true }) } }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/filtering/nested.test.ts b/tests/api-tests/relationships/filtering/nested.test.ts index 6caa58ee9a5..0daf09f8042 100644 --- a/tests/api-tests/relationships/filtering/nested.test.ts +++ b/tests/api-tests/relationships/filtering/nested.test.ts @@ -1,13 +1,13 @@ import { text, relationship } from '@keystone-next/keystone/fields'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { apiTestConfig } from '../../utils'; type IdType = any; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { company: relationship({ ref: 'Company', isFilterable: true }), @@ -16,7 +16,7 @@ const runner = setupTestRunner({ }), Company: list({ fields: { name: text() } }), Post: list({ fields: { content: text({ isFilterable: true }) } }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/many-to-one-to-one.test.ts b/tests/api-tests/relationships/many-to-one-to-one.test.ts index 0109b04a789..91f855a23c0 100644 --- a/tests/api-tests/relationships/many-to-one-to-one.test.ts +++ b/tests/api-tests/relationships/many-to-one-to-one.test.ts @@ -1,7 +1,7 @@ import { KeystoneContext } from '@keystone-next/keystone/types'; import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../utils'; @@ -83,7 +83,7 @@ const createCompanyAndLocation = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Owner: list({ fields: { name: text({ isFilterable: true }), @@ -110,7 +110,7 @@ const runner = setupTestRunner({ locations: relationship({ ref: 'Location.custodians', many: true, isFilterable: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts index 2a9465a5b6e..defe799ac40 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectRelationshipError } from '../../utils'; @@ -8,7 +8,7 @@ const alphanumGenerator = gen.alphaNumString.notEmpty(); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { content: text(), @@ -48,7 +48,7 @@ const runner = setupTestRunner({ notes: relationship({ ref: 'NoteNoCreate', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts index fb981c6e193..6c27e85928c 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts @@ -1,12 +1,12 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectRelationshipError } from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Group: list({ fields: { name: text(), @@ -86,7 +86,7 @@ const runner = setupTestRunner({ group: relationship({ ref: 'GroupNoUpdateHard' }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts index 1d48ccd24da..6fea881bb2a 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectRelationshipError } from '../../utils'; @@ -10,7 +10,7 @@ type IdType = any; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { content: text(), @@ -50,7 +50,7 @@ const runner = setupTestRunner({ notes: relationship({ ref: 'NoteNoCreate', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts index ee01dd5a07d..bbdc1c17c9f 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts @@ -1,11 +1,11 @@ import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectRelationshipError } from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Group: list({ fields: { name: text(), @@ -17,7 +17,7 @@ const runner = setupTestRunner({ group: relationship({ ref: 'Group' }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/create-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-many.test.ts index 913c957bf02..f525677d477 100644 --- a/tests/api-tests/relationships/nested-mutations/create-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectRelationshipError } from '../../utils'; @@ -10,7 +10,7 @@ type IdType = any; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { content: text({ isOrderable: true }), @@ -50,7 +50,7 @@ const runner = setupTestRunner({ notes: relationship({ ref: 'NoteNoCreate', many: true }), }, }), - }), + }, }), }); @@ -58,7 +58,7 @@ let afterChangeWasCalled = false; const runner2 = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { content: text({ isOrderable: true }), @@ -75,7 +75,7 @@ const runner2 = setupTestRunner({ notes: relationship({ ref: 'Note', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/create-singular.test.ts b/tests/api-tests/relationships/nested-mutations/create-singular.test.ts index 10645539a6f..3301010a8a8 100644 --- a/tests/api-tests/relationships/nested-mutations/create-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-singular.test.ts @@ -1,12 +1,12 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectGraphQLValidationError, expectRelationshipError } from '../../utils'; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Group: list({ fields: { name: text(), @@ -103,7 +103,7 @@ const runner = setupTestRunner({ group: relationship({ ref: 'GroupNoUpdateHard' }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts b/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts index 7a89ba2d84b..beef5228d7c 100644 --- a/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/disconnect-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectGraphQLValidationError, expectRelationshipError } from '../../utils'; @@ -8,7 +8,7 @@ const alphanumGenerator = gen.alphaNumString.notEmpty(); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { content: text(), @@ -48,7 +48,7 @@ const runner = setupTestRunner({ notes: relationship({ ref: 'NoteNoCreate', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/disconnect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/disconnect-singular.test.ts index a457826c343..628899e2422 100644 --- a/tests/api-tests/relationships/nested-mutations/disconnect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/disconnect-singular.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectGraphQLValidationError } from '../../utils'; @@ -8,7 +8,7 @@ const alphanumGenerator = gen.alphaNumString.notEmpty(); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Group: list({ fields: { name: text(), @@ -34,7 +34,7 @@ const runner = setupTestRunner({ group: relationship({ ref: 'GroupNoRead' }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/reconnect-many-to-one.test.ts b/tests/api-tests/relationships/nested-mutations/reconnect-many-to-one.test.ts index 11c7f7af2d9..d15878d968e 100644 --- a/tests/api-tests/relationships/nested-mutations/reconnect-many-to-one.test.ts +++ b/tests/api-tests/relationships/nested-mutations/reconnect-many-to-one.test.ts @@ -1,5 +1,5 @@ import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../../utils'; @@ -7,7 +7,7 @@ type IdType = any; const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { title: text({ isOrderable: true }), @@ -20,7 +20,7 @@ const runner = setupTestRunner({ notes: relationship({ ref: 'Note.author', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/set-many.test.ts b/tests/api-tests/relationships/nested-mutations/set-many.test.ts index c51837aa417..53988022def 100644 --- a/tests/api-tests/relationships/nested-mutations/set-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/set-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig, expectGraphQLValidationError, expectRelationshipError } from '../../utils'; @@ -8,7 +8,7 @@ const alphanumGenerator = gen.alphaNumString.notEmpty(); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Note: list({ fields: { content: text(), @@ -48,7 +48,7 @@ const runner = setupTestRunner({ notes: relationship({ ref: 'NoteNoCreate', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-many.test.ts b/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-many.test.ts index 606af6d572c..8349b46486d 100644 --- a/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-many.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../../../utils'; @@ -13,7 +13,7 @@ const toStr = (items: any[]) => items.map(item => item.toString()); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Student: list({ fields: { name: text(), @@ -26,7 +26,7 @@ const runner = setupTestRunner({ students: relationship({ ref: 'Student.teachers', many: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-one-required.test.ts b/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-one-required.test.ts index 51dff679ed1..9fc7f025e2e 100644 --- a/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-one-required.test.ts +++ b/tests/api-tests/relationships/nested-mutations/two-way-backreference/to-one-required.test.ts @@ -1,6 +1,6 @@ import { gen, sampleOne } from 'testcheck'; import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { apiTestConfig } from '../../../utils'; @@ -8,7 +8,7 @@ const alphanumGenerator = gen.alphaNumString.notEmpty(); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Company: list({ fields: { name: text(), @@ -23,7 +23,7 @@ const runner = setupTestRunner({ company: relationship({ ref: 'Company.location', isRequired: true }), }, }), - }), + }, }), }); diff --git a/tests/api-tests/relationships/shared-names.test.ts b/tests/api-tests/relationships/shared-names.test.ts index ddc3c6cb0f8..683f4a5ec96 100644 --- a/tests/api-tests/relationships/shared-names.test.ts +++ b/tests/api-tests/relationships/shared-names.test.ts @@ -1,5 +1,5 @@ import { text, relationship } from '@keystone-next/keystone/fields'; -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { KeystoneContext } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../utils'; @@ -93,7 +93,7 @@ const createInitialData = async (context: KeystoneContext) => { const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { Employee: list({ fields: { name: text(), @@ -120,7 +120,7 @@ const runner = setupTestRunner({ employees: relationship({ ref: 'Employee', many: true }), }, }), - }), + }, }), }); diff --git a/tests/benchmarks/fixtures/create-related.js b/tests/benchmarks/fixtures/create-related.js index 3c6bd7b6528..8cd7e936439 100644 --- a/tests/benchmarks/fixtures/create-related.js +++ b/tests/benchmarks/fixtures/create-related.js @@ -1,12 +1,12 @@ const { text, relationship } = require('@keystone-next/keystone/fields'); -const { list, createSchema } = require('@keystone-next/keystone'); +const { list } = require('@keystone-next/keystone'); const { setupTestRunner } = require('@keystone-next/keystone/testing'); const { apiTestConfig } = require('../../utils.ts'); const { FixtureGroup, timeQuery, populate, range } = require('../lib/utils'); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -18,7 +18,7 @@ const runner = setupTestRunner({ title: text(), }, }), - }), + }, }), }); diff --git a/tests/benchmarks/fixtures/create.js b/tests/benchmarks/fixtures/create.js index 589ebae5d9a..1e0ca45c8d5 100644 --- a/tests/benchmarks/fixtures/create.js +++ b/tests/benchmarks/fixtures/create.js @@ -1,18 +1,18 @@ const { text } = require('@keystone-next/keystone/fields'); -const { list, createSchema } = require('@keystone-next/keystone'); +const { list } = require('@keystone-next/keystone'); const { setupTestRunner } = require('@keystone-next/keystone/testing'); const { apiTestConfig } = require('../../utils.ts'); const { FixtureGroup, timeQuery, populate, range } = require('../lib/utils'); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), }, }), - }), + }, }), }); diff --git a/tests/benchmarks/fixtures/query.js b/tests/benchmarks/fixtures/query.js index c3160339174..10a4817dfc8 100644 --- a/tests/benchmarks/fixtures/query.js +++ b/tests/benchmarks/fixtures/query.js @@ -1,12 +1,12 @@ const { text, relationship } = require('@keystone-next/keystone/fields'); -const { createSchema, list } = require('@keystone-next/keystone'); +const { list } = require('@keystone-next/keystone'); const { setupTestRunner } = require('@keystone-next/keystone/testing'); const { apiTestConfig } = require('../../utils.ts'); const { FixtureGroup, timeQuery, populate, range } = require('../lib/utils'); const runner = setupTestRunner({ config: apiTestConfig({ - lists: createSchema({ + lists: { User: list({ fields: { name: text(), @@ -18,7 +18,7 @@ const runner = setupTestRunner({ title: text(), }, }), - }), + }, }), }); diff --git a/tests/test-projects/basic/schema.ts b/tests/test-projects/basic/schema.ts index 13e09ba4ffc..1afb7a088ba 100644 --- a/tests/test-projects/basic/schema.ts +++ b/tests/test-projects/basic/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ fields: { label: text({ isRequired: true }), @@ -38,4 +38,4 @@ export const lists = createSchema({ isHidden: true, }, }), -}); +}; diff --git a/tests/test-projects/crud-notifications/schema.ts b/tests/test-projects/crud-notifications/schema.ts index 1c2d69ac188..7174a396e5a 100644 --- a/tests/test-projects/crud-notifications/schema.ts +++ b/tests/test-projects/crud-notifications/schema.ts @@ -1,8 +1,8 @@ -import { createSchema, list } from '@keystone-next/keystone'; +import { list } from '@keystone-next/keystone'; import { checkbox, relationship, text, timestamp } from '@keystone-next/keystone/fields'; import { select } from '@keystone-next/keystone/fields'; -export const lists = createSchema({ +export const lists = { Task: list({ access: { item: { @@ -37,4 +37,4 @@ export const lists = createSchema({ defaultIsFilterable: true, defaultIsOrderable: true, }), -}); +}; From ad247c82495e41753dcade9613e0a67cc253928f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Sep 2021 08:44:28 +1000 Subject: [PATCH 037/135] Update jest monorepo to ^27.2.0 (#6551) Co-authored-by: Renovate Bot --- examples/testing/package.json | 4 +- package.json | 4 +- packages/fields-document/package.json | 4 +- yarn.lock | 657 ++++++++++++++------------ 4 files changed, 350 insertions(+), 319 deletions(-) diff --git a/examples/testing/package.json b/examples/testing/package.json index 725b050942c..b4d352bc8ba 100644 --- a/examples/testing/package.json +++ b/examples/testing/package.json @@ -17,8 +17,8 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "babel-jest": "^27.1.0", - "jest": "^27.1.0", + "babel-jest": "^27.2.0", + "jest": "^27.2.0", "typescript": "^4.4.2" }, "engines": { diff --git a/package.json b/package.json index c4587f058e6..238a1f5c860 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@babel/preset-typescript": "^7.15.0", "@changesets/changelog-github": "^0.4.1", "@changesets/cli": "^2.17.0", - "@jest/test-sequencer": "^27.1.0", + "@jest/test-sequencer": "^27.2.0", "@manypkg/cli": "^0.18.0", "@preconstruct/cli": "2.1.1", "@preconstruct/eslint-plugin-format-js-tag": "^0.1.0", @@ -68,7 +68,7 @@ "eslint-plugin-react": "^7.25.1", "eslint-plugin-react-hooks": "^4.2.0", "is-ci": "^3.0.0", - "jest": "^27.1.0", + "jest": "^27.2.0", "prettier": "^2.3.2", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index f0bafdf01a1..c97d88be197 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -53,8 +53,8 @@ "devDependencies": { "@testing-library/react": "^12.0.0", "array.prototype.flat": "^1.2.4", - "jest-diff": "^27.1.0", - "pretty-format": "^27.1.0", + "jest-diff": "^27.2.0", + "pretty-format": "^27.2.0", "slate-hyperscript": "^0.60.8" }, "engines": { diff --git a/yarn.lock b/yarn.lock index 65bff7f8708..7be79da3e56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1629,94 +1629,94 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.1.0.tgz#de13b603cb1d389b50c0dc6296e86e112381e43c" - integrity sha512-+Vl+xmLwAXLNlqT61gmHEixeRbS4L8MUzAjtpBCOPWH+izNI/dR16IeXjkXJdRtIVWVSf9DO1gdp67B1XorZhQ== +"@jest/console@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.2.0.tgz#57f702837ec52899be58c3794dce5941c77a8b63" + integrity sha512-35z+RqsK2CCgNxn+lWyK8X4KkaDtfL4BggT7oeZ0JffIiAiEYFYPo5B67V50ZubqDS1ehBrdCR2jduFnIrZOYw== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^27.1.0" - jest-util "^27.1.0" + jest-message-util "^27.2.0" + jest-util "^27.2.0" slash "^3.0.0" -"@jest/core@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.1.0.tgz#622220f18032f5869e579cecbe744527238648bf" - integrity sha512-3l9qmoknrlCFKfGdrmiQiPne+pUR4ALhKwFTYyOeKw6egfDwJkO21RJ1xf41rN8ZNFLg5W+w6+P4fUqq4EMRWA== +"@jest/core@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.2.0.tgz#61fc27b244e9709170ed9ffe41b006add569f1b3" + integrity sha512-E/2NHhq+VMo18DpKkoty8Sjey8Kps5Cqa88A8NP757s6JjYqPdioMuyUBhDiIOGCdQByEp0ou3jskkTszMS0nw== dependencies: - "@jest/console" "^27.1.0" - "@jest/reporters" "^27.1.0" - "@jest/test-result" "^27.1.0" - "@jest/transform" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/console" "^27.2.0" + "@jest/reporters" "^27.2.0" + "@jest/test-result" "^27.2.0" + "@jest/transform" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" emittery "^0.8.1" exit "^0.1.2" graceful-fs "^4.2.4" - jest-changed-files "^27.1.0" - jest-config "^27.1.0" - jest-haste-map "^27.1.0" - jest-message-util "^27.1.0" + jest-changed-files "^27.1.1" + jest-config "^27.2.0" + jest-haste-map "^27.2.0" + jest-message-util "^27.2.0" jest-regex-util "^27.0.6" - jest-resolve "^27.1.0" - jest-resolve-dependencies "^27.1.0" - jest-runner "^27.1.0" - jest-runtime "^27.1.0" - jest-snapshot "^27.1.0" - jest-util "^27.1.0" - jest-validate "^27.1.0" - jest-watcher "^27.1.0" + jest-resolve "^27.2.0" + jest-resolve-dependencies "^27.2.0" + jest-runner "^27.2.0" + jest-runtime "^27.2.0" + jest-snapshot "^27.2.0" + jest-util "^27.2.0" + jest-validate "^27.2.0" + jest-watcher "^27.2.0" micromatch "^4.0.4" p-each-series "^2.1.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.1.0.tgz#c7224a67004759ec203d8fa44e8bc0db93f66c44" - integrity sha512-wRp50aAMY2w1U2jP1G32d6FUVBNYqmk8WaGkiIEisU48qyDV0WPtw3IBLnl7orBeggveommAkuijY+RzVnNDOQ== +"@jest/environment@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.2.0.tgz#48d1dbfa65f8e4a5a5c6cbeb9c59d1a5c2776f6b" + integrity sha512-iPWmQI0wRIYSZX3wKu4FXHK4eIqkfq6n1DCDJS+v3uby7SOXrHvX4eiTBuEdSvtDRMTIH2kjrSkjHf/F9JIYyQ== dependencies: - "@jest/fake-timers" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/fake-timers" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" - jest-mock "^27.1.0" + jest-mock "^27.1.1" -"@jest/fake-timers@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.1.0.tgz#c0b343d8a16af17eab2cb6862e319947c0ea2abe" - integrity sha512-22Zyn8il8DzpS+30jJNVbTlm7vAtnfy1aYvNeOEHloMlGy1PCYLHa4PWlSws0hvNsMM5bON6GISjkLoQUV3oMA== +"@jest/fake-timers@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.2.0.tgz#560841bc21ae7fbeff0cbff8de8f5cf43ad3561d" + integrity sha512-gSu3YHvQOoVaTWYGgHFB7IYFtcF2HBzX4l7s47VcjvkUgL4/FBnE20x7TNLa3W6ABERtGd5gStSwsA8bcn+c4w== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" "@sinonjs/fake-timers" "^7.0.2" "@types/node" "*" - jest-message-util "^27.1.0" - jest-mock "^27.1.0" - jest-util "^27.1.0" + jest-message-util "^27.2.0" + jest-mock "^27.1.1" + jest-util "^27.2.0" -"@jest/globals@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.1.0.tgz#e093a49c718dd678a782c197757775534c88d3f2" - integrity sha512-73vLV4aNHAlAgjk0/QcSIzzCZSqVIPbmFROJJv9D3QUR7BI4f517gVdJpSrCHxuRH3VZFhe0yGG/tmttlMll9g== +"@jest/globals@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.2.0.tgz#4d7085f51df5ac70c8240eb3501289676503933d" + integrity sha512-raqk9Gf9WC3hlBa57rmRmJfRl9hom2b+qEE/ifheMtwn5USH5VZxzrHHOZg0Zsd/qC2WJ8UtyTwHKQAnNlDMdg== dependencies: - "@jest/environment" "^27.1.0" - "@jest/types" "^27.1.0" - expect "^27.1.0" + "@jest/environment" "^27.2.0" + "@jest/types" "^27.1.1" + expect "^27.2.0" -"@jest/reporters@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.1.0.tgz#02ed1e6601552c2f6447378533f77aad002781d4" - integrity sha512-5T/zlPkN2HnK3Sboeg64L5eC8iiaZueLpttdktWTJsvALEtP2YMkC5BQxwjRWQACG9SwDmz+XjjkoxXUDMDgdw== +"@jest/reporters@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.2.0.tgz#629886d9a42218e504a424889a293abb27919e25" + integrity sha512-7wfkE3iRTLaT0F51h1mnxH3nQVwDCdbfgXiLuCcNkF1FnxXLH9utHqkSLIiwOTV1AtmiE0YagHbOvx4rnMP/GA== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.1.0" - "@jest/test-result" "^27.1.0" - "@jest/transform" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/console" "^27.2.0" + "@jest/test-result" "^27.2.0" + "@jest/transform" "^27.2.0" + "@jest/types" "^27.1.1" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" @@ -1727,10 +1727,10 @@ istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^27.1.0" - jest-resolve "^27.1.0" - jest-util "^27.1.0" - jest-worker "^27.1.0" + jest-haste-map "^27.2.0" + jest-resolve "^27.2.0" + jest-util "^27.2.0" + jest-worker "^27.2.0" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" @@ -1746,41 +1746,41 @@ graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.1.0.tgz#9345ae5f97f6a5287af9ebd54716cd84331d42e8" - integrity sha512-Aoz00gpDL528ODLghat3QSy6UBTD5EmmpjrhZZMK/v1Q2/rRRqTGnFxHuEkrD4z/Py96ZdOHxIWkkCKRpmnE1A== +"@jest/test-result@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.2.0.tgz#377b46a41a6415dd4839fd0bed67b89fecea6b20" + integrity sha512-JPPqn8h0RGr4HyeY1Km+FivDIjTFzDROU46iAvzVjD42ooGwYoqYO/MQTilhfajdz6jpVnnphFrKZI5OYrBONA== dependencies: - "@jest/console" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/console" "^27.2.0" + "@jest/types" "^27.1.1" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.1.0.tgz#04e8b3bd735570d3d48865e74977a14dc99bff2d" - integrity sha512-lnCWawDr6Z1DAAK9l25o3AjmKGgcutq1iIbp+hC10s/HxnB8ZkUsYq1FzjOoxxZ5hW+1+AthBtvS4x9yno3V1A== +"@jest/test-sequencer@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.2.0.tgz#b02b507687825af2fdc84e90c539d36fd8cf7bc9" + integrity sha512-PrqarcpzOU1KSAK7aPwfL8nnpaqTMwPe7JBPnaOYRDSe/C6AoJiL5Kbnonqf1+DregxZIRAoDg69R9/DXMGqXA== dependencies: - "@jest/test-result" "^27.1.0" + "@jest/test-result" "^27.2.0" graceful-fs "^4.2.4" - jest-haste-map "^27.1.0" - jest-runtime "^27.1.0" + jest-haste-map "^27.2.0" + jest-runtime "^27.2.0" -"@jest/transform@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.1.0.tgz#962e385517e3d1f62827fa39c305edcc3ca8544b" - integrity sha512-ZRGCA2ZEVJ00ubrhkTG87kyLbN6n55g1Ilq0X9nJb5bX3MhMp3O6M7KG+LvYu+nZRqG5cXsQnJEdZbdpTAV8pQ== +"@jest/transform@^27.2.0": + version "27.2.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.2.0.tgz#e7e6e49d2591792db2385c33cdbb4379d407068d" + integrity sha512-Q8Q/8xXIZYllk1AF7Ou5sV3egOZsdY/Wlv09CSbcexBRcC1Qt6lVZ7jRFAZtbHsEEzvOCyFEC4PcrwKwyjXtCg== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" babel-plugin-istanbul "^6.0.0" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" - jest-haste-map "^27.1.0" + jest-haste-map "^27.2.0" jest-regex-util "^27.0.6" - jest-util "^27.1.0" + jest-util "^27.2.0" micromatch "^4.0.4" pirates "^4.0.1" slash "^3.0.0" @@ -1798,6 +1798,17 @@ "@types/yargs" "^16.0.0" chalk "^4.0.0" +"@jest/types@^27.1.1": + version "27.1.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.1.tgz#77a3fc014f906c65752d12123a0134359707c0ad" + integrity sha512-yqJPDDseb0mXgKqmNqypCsb85C22K1aY5+LUxh7syIM9n/b0AsaltxNy+o6tt29VcfGDpYEve175bm3uOhcehA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@josephg/resolvable@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@josephg/resolvable/-/resolvable-1.0.1.tgz#69bc4db754d79e1a2f17a650d3466e038d94a5eb" @@ -3828,16 +3839,16 @@ axios@^0.21.1: dependencies: follow-redirects "^1.14.0" -babel-jest@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.1.0.tgz#e96ca04554fd32274439869e2b6d24de9d91bc4e" - integrity sha512-6NrdqzaYemALGCuR97QkC/FkFIEBWP5pw5TMJoUHZTVXyOgocujp6A0JE2V6gE0HtqAAv6VKU/nI+OCR1Z4gHA== +babel-jest@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.2.0.tgz#c0f129a81f1197028aeb4447acbc04564c8bfc52" + integrity sha512-bS2p+KGGVVmWXBa8+i6SO/xzpiz2Q/2LnqLbQknPKefWXVZ67YIjA4iXup/jMOEZplga9PpWn+wrdb3UdDwRaA== dependencies: - "@jest/transform" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/transform" "^27.2.0" + "@jest/types" "^27.1.1" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^27.0.6" + babel-preset-jest "^27.2.0" chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" @@ -3876,10 +3887,10 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.0.6.tgz#f7c6b3d764af21cb4a2a1ab6870117dbde15b456" - integrity sha512-CewFeM9Vv2gM7Yr9n5eyyLVPRSiBnk6lKZRjgwYnGKSl9M14TMn2vkN02wTF04OGuSDLEzlWiMzvjXuW9mB6Gw== +babel-plugin-jest-hoist@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz#79f37d43f7e5c4fdc4b2ca3e10cc6cf545626277" + integrity sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" @@ -3947,12 +3958,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^27.0.6: - version "27.0.6" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.0.6.tgz#909ef08e9f24a4679768be2f60a3df0856843f9d" - integrity sha512-WObA0/Biw2LrVVwZkF/2GqbOdzhKD6Fkdwhoy9ASIrOWr/zodcSpQh72JOkEn6NWyjmnPDjNSqaGN4KnpKzhXw== +babel-preset-jest@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz#556bbbf340608fed5670ab0ea0c8ef2449fba885" + integrity sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg== dependencies: - babel-plugin-jest-hoist "^27.0.6" + babel-plugin-jest-hoist "^27.2.0" babel-preset-current-node-syntax "^1.0.0" bail@^1.0.0: @@ -6140,16 +6151,16 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.1.0.tgz#380de0abb3a8f2299c4c6c66bbe930483b5dba9b" - integrity sha512-9kJngV5hOJgkFil4F/uXm3hVBubUK2nERVfvqNNwxxuW8ZOUwSTTSysgfzckYtv/LBzj/LJXbiAF7okHCXgdug== +expect@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.0.tgz#40eb89a492afb726a3929ccf3611ee0799ab976f" + integrity sha512-oOTbawMQv7AK1FZURbPTgGSzmhxkjFzoARSvDjOMnOpeWuYQx1tP6rXu9MIX5mrACmyCAM7fSNP8IJO2f1p0CQ== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" ansi-styles "^5.0.0" jest-get-type "^27.0.6" - jest-matcher-utils "^27.1.0" - jest-message-util "^27.1.0" + jest-matcher-utils "^27.2.0" + jest-message-util "^27.2.0" jest-regex-util "^27.0.6" express@^4.17.1: @@ -8006,86 +8017,86 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.1.0.tgz#42da6ea00f06274172745729d55f42b60a9dffe0" - integrity sha512-eRcb13TfQw0xiV2E98EmiEgs9a5uaBIqJChyl0G7jR9fCIvGjXovnDS6Zbku3joij4tXYcSK4SE1AXqOlUxjWg== +jest-changed-files@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.1.1.tgz#9b3f67a34cc58e3e811e2e1e21529837653e4200" + integrity sha512-5TV9+fYlC2A6hu3qtoyGHprBwCAn0AuGA77bZdUgYvVlRMjHXo063VcWTEAyx6XAZ85DYHqp0+aHKbPlfRDRvA== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" execa "^5.0.0" throat "^6.0.1" -jest-circus@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.1.0.tgz#24c280c90a625ea57da20ee231d25b1621979a57" - integrity sha512-6FWtHs3nZyZlMBhRf1wvAC5CirnflbGJAY1xssSAnERLiiXQRH+wY2ptBVtXjX4gz4AA2EwRV57b038LmifRbA== +jest-circus@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.2.0.tgz#ad0d6d75514050f539d422bae41344224d2328f9" + integrity sha512-WwENhaZwOARB1nmcboYPSv/PwHBUGRpA4MEgszjr9DLCl97MYw0qZprBwLb7rNzvMwfIvNGG7pefQ5rxyBlzIA== dependencies: - "@jest/environment" "^27.1.0" - "@jest/test-result" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/environment" "^27.2.0" + "@jest/test-result" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" - expect "^27.1.0" + expect "^27.2.0" is-generator-fn "^2.0.0" - jest-each "^27.1.0" - jest-matcher-utils "^27.1.0" - jest-message-util "^27.1.0" - jest-runtime "^27.1.0" - jest-snapshot "^27.1.0" - jest-util "^27.1.0" - pretty-format "^27.1.0" + jest-each "^27.2.0" + jest-matcher-utils "^27.2.0" + jest-message-util "^27.2.0" + jest-runtime "^27.2.0" + jest-snapshot "^27.2.0" + jest-util "^27.2.0" + pretty-format "^27.2.0" slash "^3.0.0" stack-utils "^2.0.3" throat "^6.0.1" -jest-cli@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.1.0.tgz#118438e4d11cf6fb66cb2b2eb5778817eab3daeb" - integrity sha512-h6zPUOUu+6oLDrXz0yOWY2YXvBLk8gQinx4HbZ7SF4V3HzasQf+ncoIbKENUMwXyf54/6dBkYXvXJos+gOHYZw== +jest-cli@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.2.0.tgz#6da5ecca5bd757e20449f5ec1f1cad5b0303d16b" + integrity sha512-bq1X/B/b1kT9y1zIFMEW3GFRX1HEhFybiqKdbxM+j11XMMYSbU9WezfyWIhrSOmPT+iODLATVjfsCnbQs7cfIA== dependencies: - "@jest/core" "^27.1.0" - "@jest/test-result" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/core" "^27.2.0" + "@jest/test-result" "^27.2.0" + "@jest/types" "^27.1.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" - jest-config "^27.1.0" - jest-util "^27.1.0" - jest-validate "^27.1.0" + jest-config "^27.2.0" + jest-util "^27.2.0" + jest-validate "^27.2.0" prompts "^2.0.1" yargs "^16.0.3" -jest-config@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.1.0.tgz#e6826e2baaa34c07c3839af86466870e339d9ada" - integrity sha512-GMo7f76vMYUA3b3xOdlcKeKQhKcBIgurjERO2hojo0eLkKPGcw7fyIoanH+m6KOP2bLad+fGnF8aWOJYxzNPeg== +jest-config@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.2.0.tgz#d1c359253927005c53d11ab3e50d3b2f402a673a" + integrity sha512-Z1romHpxeNwLxQtouQ4xt07bY6HSFGKTo0xJcvOK3u6uJHveA4LB2P+ty9ArBLpTh3AqqPxsyw9l9GMnWBYS9A== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^27.1.0" - "@jest/types" "^27.1.0" - babel-jest "^27.1.0" + "@jest/test-sequencer" "^27.2.0" + "@jest/types" "^27.1.1" + babel-jest "^27.2.0" chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" is-ci "^3.0.0" - jest-circus "^27.1.0" - jest-environment-jsdom "^27.1.0" - jest-environment-node "^27.1.0" + jest-circus "^27.2.0" + jest-environment-jsdom "^27.2.0" + jest-environment-node "^27.2.0" jest-get-type "^27.0.6" - jest-jasmine2 "^27.1.0" + jest-jasmine2 "^27.2.0" jest-regex-util "^27.0.6" - jest-resolve "^27.1.0" - jest-runner "^27.1.0" - jest-util "^27.1.0" - jest-validate "^27.1.0" + jest-resolve "^27.2.0" + jest-runner "^27.2.0" + jest-util "^27.2.0" + jest-validate "^27.2.0" micromatch "^4.0.4" - pretty-format "^27.1.0" + pretty-format "^27.2.0" -jest-diff@^27.0.0, jest-diff@^27.1.0: +jest-diff@^27.0.0: version "27.1.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.1.0.tgz#c7033f25add95e2218f3c7f4c3d7b634ab6b3cd2" integrity sha512-rjfopEYl58g/SZTsQFmspBODvMSytL16I+cirnScWTLkQVXYVZfxm78DFfdIIXc05RCYuGjxJqrdyG4PIFzcJg== @@ -8095,6 +8106,16 @@ jest-diff@^27.0.0, jest-diff@^27.1.0: jest-get-type "^27.0.6" pretty-format "^27.1.0" +jest-diff@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.2.0.tgz#bda761c360f751bab1e7a2fe2fc2b0a35ce8518c" + integrity sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.0.6" + jest-get-type "^27.0.6" + pretty-format "^27.2.0" + jest-docblock@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.0.6.tgz#cc78266acf7fe693ca462cbbda0ea4e639e4e5f3" @@ -8102,53 +8123,53 @@ jest-docblock@^27.0.6: dependencies: detect-newline "^3.0.0" -jest-each@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.1.0.tgz#36ac75f7aeecb3b8da2a8e617ccb30a446df408c" - integrity sha512-K/cNvQlmDqQMRHF8CaQ0XPzCfjP5HMJc2bIJglrIqI9fjwpNqITle63IWE+wq4p+3v+iBgh7Wq0IdGpLx5xjDg== +jest-each@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.2.0.tgz#4c531c7223de289429fc7b2473a86e653c86d61f" + integrity sha512-biDmmUQjg+HZOB7MfY2RHSFL3j418nMoC3TK3pGAj880fQQSxvQe1y2Wy23JJJNUlk6YXiGU0yWy86Le1HBPmA== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" chalk "^4.0.0" jest-get-type "^27.0.6" - jest-util "^27.1.0" - pretty-format "^27.1.0" + jest-util "^27.2.0" + pretty-format "^27.2.0" -jest-environment-jsdom@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.1.0.tgz#5fb3eb8a67e02e6cc623640388d5f90e33075f18" - integrity sha512-JbwOcOxh/HOtsj56ljeXQCUJr3ivnaIlM45F5NBezFLVYdT91N5UofB1ux2B1CATsQiudcHdgTaeuqGXJqjJYQ== +jest-environment-jsdom@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.2.0.tgz#c654dfae50ca2272c2a2e2bb95ff0af298283a3c" + integrity sha512-wNQJi6Rd/AkUWqTc4gWhuTIFPo7tlMK0RPZXeM6AqRHZA3D3vwvTa9ktAktyVyWYmUoXdYstOfyYMG3w4jt7eA== dependencies: - "@jest/environment" "^27.1.0" - "@jest/fake-timers" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/environment" "^27.2.0" + "@jest/fake-timers" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" - jest-mock "^27.1.0" - jest-util "^27.1.0" + jest-mock "^27.1.1" + jest-util "^27.2.0" jsdom "^16.6.0" -jest-environment-node@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.1.0.tgz#feea6b765f1fd4582284d4f1007df2b0a8d15b7f" - integrity sha512-JIyJ8H3wVyM4YCXp7njbjs0dIT87yhGlrXCXhDKNIg1OjurXr6X38yocnnbXvvNyqVTqSI4M9l+YfPKueqL1lw== +jest-environment-node@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.2.0.tgz#73ef2151cb62206669becb94cd84f33276252de5" + integrity sha512-WbW+vdM4u88iy6Q3ftUEQOSgMPtSgjm3qixYYK2AKEuqmFO2zmACTw1vFUB0qI/QN88X6hA6ZkVKIdIWWzz+yg== dependencies: - "@jest/environment" "^27.1.0" - "@jest/fake-timers" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/environment" "^27.2.0" + "@jest/fake-timers" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" - jest-mock "^27.1.0" - jest-util "^27.1.0" + jest-mock "^27.1.1" + jest-util "^27.2.0" jest-get-type@^27.0.6: version "27.0.6" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.0.6.tgz#0eb5c7f755854279ce9b68a9f1a4122f69047cfe" integrity sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg== -jest-haste-map@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.1.0.tgz#a39f456823bd6a74e3c86ad25f6fa870428326bf" - integrity sha512-7mz6LopSe+eA6cTFMf10OfLLqRoIPvmMyz5/OnSXnHO7hB0aDP1iIeLWCXzAcYU5eIJVpHr12Bk9yyq2fTW9vg== +jest-haste-map@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.2.0.tgz#703b3a473e3f2e27d75ab07864ffd7bbaad0d75e" + integrity sha512-laFet7QkNlWjwZtMGHCucLvF8o9PAh2cgePRck1+uadSM4E4XH9J4gnx4do+a6do8ZV5XHNEAXEkIoNg5XUH2Q== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" "@types/graceful-fs" "^4.1.2" "@types/node" "*" anymatch "^3.0.3" @@ -8156,76 +8177,76 @@ jest-haste-map@^27.1.0: graceful-fs "^4.2.4" jest-regex-util "^27.0.6" jest-serializer "^27.0.6" - jest-util "^27.1.0" - jest-worker "^27.1.0" + jest-util "^27.2.0" + jest-worker "^27.2.0" micromatch "^4.0.4" walker "^1.0.7" optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.1.0.tgz#324a3de0b2ee20d238b2b5b844acc4571331a206" - integrity sha512-Z/NIt0wBDg3przOW2FCWtYjMn3Ip68t0SL60agD/e67jlhTyV3PIF8IzT9ecwqFbeuUSO2OT8WeJgHcalDGFzQ== +jest-jasmine2@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.2.0.tgz#1ece0ee37c348b59ed3dfcfe509fc24e3377b12d" + integrity sha512-NcPzZBk6IkDW3Z2V8orGueheGJJYfT5P0zI/vTO/Jp+R9KluUdgFrgwfvZ0A34Kw6HKgiWFILZmh3oQ/eS+UxA== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^27.1.0" + "@jest/environment" "^27.2.0" "@jest/source-map" "^27.0.6" - "@jest/test-result" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/test-result" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^27.1.0" + expect "^27.2.0" is-generator-fn "^2.0.0" - jest-each "^27.1.0" - jest-matcher-utils "^27.1.0" - jest-message-util "^27.1.0" - jest-runtime "^27.1.0" - jest-snapshot "^27.1.0" - jest-util "^27.1.0" - pretty-format "^27.1.0" + jest-each "^27.2.0" + jest-matcher-utils "^27.2.0" + jest-message-util "^27.2.0" + jest-runtime "^27.2.0" + jest-snapshot "^27.2.0" + jest-util "^27.2.0" + pretty-format "^27.2.0" throat "^6.0.1" -jest-leak-detector@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.1.0.tgz#fe7eb633c851e06280ec4dd248067fe232c00a79" - integrity sha512-oHvSkz1E80VyeTKBvZNnw576qU+cVqRXUD3/wKXh1zpaki47Qty2xeHg2HKie9Hqcd2l4XwircgNOWb/NiGqdA== +jest-leak-detector@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.2.0.tgz#9a7ca2dad1a21c4e49ad2a8ad7f1214ffdb86a28" + integrity sha512-e91BIEmbZw5+MHkB4Hnrq7S86coTxUMCkz4n7DLmQYvl9pEKmRx9H/JFH87bBqbIU5B2Ju1soKxRWX6/eGFGpA== dependencies: jest-get-type "^27.0.6" - pretty-format "^27.1.0" + pretty-format "^27.2.0" -jest-matcher-utils@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.1.0.tgz#68afda0885db1f0b9472ce98dc4c535080785301" - integrity sha512-VmAudus2P6Yt/JVBRdTPFhUzlIN8DYJd+et5Rd9QDsO/Z82Z4iwGjo43U8Z+PTiz8CBvKvlb6Fh3oKy39hykkQ== +jest-matcher-utils@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.0.tgz#b4d224ab88655d5fab64b96b989ac349e2f5da43" + integrity sha512-F+LG3iTwJ0gPjxBX6HCyrARFXq6jjiqhwBQeskkJQgSLeF1j6ui1RTV08SR7O51XTUhtc8zqpDj8iCG4RGmdKw== dependencies: chalk "^4.0.0" - jest-diff "^27.1.0" + jest-diff "^27.2.0" jest-get-type "^27.0.6" - pretty-format "^27.1.0" + pretty-format "^27.2.0" -jest-message-util@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.1.0.tgz#e77692c84945d1d10ef00afdfd3d2c20bd8fb468" - integrity sha512-Eck8NFnJ5Sg36R9XguD65cf2D5+McC+NF5GIdEninoabcuoOfWrID5qJhufq5FB0DRKoiyxB61hS7MKoMD0trQ== +jest-message-util@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.2.0.tgz#2f65c71df55267208686b1d7514e18106c91ceaf" + integrity sha512-y+sfT/94CiP8rKXgwCOzO1mUazIEdEhrLjuiu+RKmCP+8O/TJTSne9dqQRbFIHBtlR2+q7cddJlWGir8UATu5w== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.4" micromatch "^4.0.4" - pretty-format "^27.1.0" + pretty-format "^27.2.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.1.0.tgz#7ca6e4d09375c071661642d1c14c4711f3ab4b4f" - integrity sha512-iT3/Yhu7DwAg/0HvvLCqLvrTKTRMyJlrrfJYWzuLSf9RCAxBoIXN3HoymZxMnYsC3eD8ewGbUa9jUknwBenx2w== +jest-mock@^27.1.1: + version "27.1.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.1.1.tgz#c7a2e81301fdcf3dab114931d23d89ec9d0c3a82" + integrity sha512-SClsFKuYBf+6SSi8jtAYOuPw8DDMsTElUWEae3zq7vDhH01ayVSIHUSIa8UgbDOUalCFp6gNsaikN0rbxN4dbw== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" "@types/node" "*" jest-pnp-resolver@^1.2.2: @@ -8238,72 +8259,72 @@ jest-regex-util@^27.0.6: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.0.6.tgz#02e112082935ae949ce5d13b2675db3d8c87d9c5" integrity sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ== -jest-resolve-dependencies@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.1.0.tgz#d32ea4a2c82f76410f6157d0ec6cde24fbff2317" - integrity sha512-Kq5XuDAELuBnrERrjFYEzu/A+i2W7l9HnPWqZEeKGEQ7m1R+6ndMbdXCVCx29Se1qwLZLgvoXwinB3SPIaitMQ== +jest-resolve-dependencies@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.2.0.tgz#b56a1aab95b0fd21e0a69a15fda985c05f902b8a" + integrity sha512-EY5jc/Y0oxn+oVEEldTidmmdVoZaknKPyDORA012JUdqPyqPL+lNdRyI3pGti0RCydds6coaw6xt4JQY54dKsg== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" jest-regex-util "^27.0.6" - jest-snapshot "^27.1.0" + jest-snapshot "^27.2.0" -jest-resolve@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.1.0.tgz#bb22303c9e240cccdda28562e3c6fbcc6a23ac86" - integrity sha512-TXvzrLyPg0vLOwcWX38ZGYeEztSEmW+cQQKqc4HKDUwun31wsBXwotRlUz4/AYU/Fq4GhbMd/ileIWZEtcdmIA== +jest-resolve@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.2.0.tgz#f5d053693ab3806ec2f778e6df8b0aa4cfaef95f" + integrity sha512-v09p9Ib/VtpHM6Cz+i9lEAv1Z/M5NVxsyghRHRMEUOqwPQs3zwTdwp1xS3O/k5LocjKiGS0OTaJoBSpjbM2Jlw== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" chalk "^4.0.0" escalade "^3.1.1" graceful-fs "^4.2.4" - jest-haste-map "^27.1.0" + jest-haste-map "^27.2.0" jest-pnp-resolver "^1.2.2" - jest-util "^27.1.0" - jest-validate "^27.1.0" + jest-util "^27.2.0" + jest-validate "^27.2.0" resolve "^1.20.0" slash "^3.0.0" -jest-runner@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.1.0.tgz#1b28d114fb3b67407b8354c9385d47395e8ff83f" - integrity sha512-ZWPKr9M5w5gDplz1KsJ6iRmQaDT/yyAFLf18fKbb/+BLWsR1sCNC2wMT0H7pP3gDcBz0qZ6aJraSYUNAGSJGaw== +jest-runner@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.2.0.tgz#281b255d88a473aebc0b5cb46e58a83a1251cab3" + integrity sha512-Cl+BHpduIc0cIVTjwoyx0pQk4Br8gn+wkr35PmKCmzEdOUnQ2wN7QVXA8vXnMQXSlFkN/+KWnk20TAVBmhgrww== dependencies: - "@jest/console" "^27.1.0" - "@jest/environment" "^27.1.0" - "@jest/test-result" "^27.1.0" - "@jest/transform" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/console" "^27.2.0" + "@jest/environment" "^27.2.0" + "@jest/test-result" "^27.2.0" + "@jest/transform" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" chalk "^4.0.0" emittery "^0.8.1" exit "^0.1.2" graceful-fs "^4.2.4" jest-docblock "^27.0.6" - jest-environment-jsdom "^27.1.0" - jest-environment-node "^27.1.0" - jest-haste-map "^27.1.0" - jest-leak-detector "^27.1.0" - jest-message-util "^27.1.0" - jest-resolve "^27.1.0" - jest-runtime "^27.1.0" - jest-util "^27.1.0" - jest-worker "^27.1.0" + jest-environment-jsdom "^27.2.0" + jest-environment-node "^27.2.0" + jest-haste-map "^27.2.0" + jest-leak-detector "^27.2.0" + jest-message-util "^27.2.0" + jest-resolve "^27.2.0" + jest-runtime "^27.2.0" + jest-util "^27.2.0" + jest-worker "^27.2.0" source-map-support "^0.5.6" throat "^6.0.1" -jest-runtime@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.1.0.tgz#1a98d984ffebc16a0b4f9eaad8ab47c00a750cf5" - integrity sha512-okiR2cpGjY0RkWmUGGado6ETpFOi9oG3yV0CioYdoktkVxy5Hv0WRLWnJFuArSYS8cHMCNcceUUMGiIfgxCO9A== +jest-runtime@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.2.0.tgz#998295ccd80008b3031eeb5cc60e801e8551024b" + integrity sha512-6gRE9AVVX49hgBbWQ9PcNDeM4upMUXzTpBs0kmbrjyotyUyIJixLPsYjpeTFwAA07PVLDei1iAm2chmWycdGdQ== dependencies: - "@jest/console" "^27.1.0" - "@jest/environment" "^27.1.0" - "@jest/fake-timers" "^27.1.0" - "@jest/globals" "^27.1.0" + "@jest/console" "^27.2.0" + "@jest/environment" "^27.2.0" + "@jest/fake-timers" "^27.2.0" + "@jest/globals" "^27.2.0" "@jest/source-map" "^27.0.6" - "@jest/test-result" "^27.1.0" - "@jest/transform" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/test-result" "^27.2.0" + "@jest/transform" "^27.2.0" + "@jest/types" "^27.1.1" "@types/yargs" "^16.0.0" chalk "^4.0.0" cjs-module-lexer "^1.0.0" @@ -8312,14 +8333,14 @@ jest-runtime@^27.1.0: exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-haste-map "^27.1.0" - jest-message-util "^27.1.0" - jest-mock "^27.1.0" + jest-haste-map "^27.2.0" + jest-message-util "^27.2.0" + jest-mock "^27.1.1" jest-regex-util "^27.0.6" - jest-resolve "^27.1.0" - jest-snapshot "^27.1.0" - jest-util "^27.1.0" - jest-validate "^27.1.0" + jest-resolve "^27.2.0" + jest-snapshot "^27.2.0" + jest-util "^27.2.0" + jest-validate "^27.2.0" slash "^3.0.0" strip-bom "^4.0.0" yargs "^16.0.3" @@ -8332,10 +8353,10 @@ jest-serializer@^27.0.6: "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.1.0.tgz#2a063ab90064017a7e9302528be7eaea6da12d17" - integrity sha512-eaeUBoEjuuRwmiRI51oTldUsKOohB1F6fPqWKKILuDi/CStxzp2IWekVUXbuHHoz5ik33ioJhshiHpgPFbYgcA== +jest-snapshot@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.2.0.tgz#7961e7107ac666a46fbb23e7bb48ce0b8c6a9285" + integrity sha512-MukJvy3KEqemCT2FoT3Gum37CQqso/62PKTfIzWmZVTsLsuyxQmJd2PI5KPcBYFqLlA8LgZLHM8ZlazkVt8LsQ== dependencies: "@babel/core" "^7.7.2" "@babel/generator" "^7.7.2" @@ -8343,60 +8364,60 @@ jest-snapshot@^27.1.0: "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" "@babel/types" "^7.0.0" - "@jest/transform" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/transform" "^27.2.0" + "@jest/types" "^27.1.1" "@types/babel__traverse" "^7.0.4" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^27.1.0" + expect "^27.2.0" graceful-fs "^4.2.4" - jest-diff "^27.1.0" + jest-diff "^27.2.0" jest-get-type "^27.0.6" - jest-haste-map "^27.1.0" - jest-matcher-utils "^27.1.0" - jest-message-util "^27.1.0" - jest-resolve "^27.1.0" - jest-util "^27.1.0" + jest-haste-map "^27.2.0" + jest-matcher-utils "^27.2.0" + jest-message-util "^27.2.0" + jest-resolve "^27.2.0" + jest-util "^27.2.0" natural-compare "^1.4.0" - pretty-format "^27.1.0" + pretty-format "^27.2.0" semver "^7.3.2" -jest-util@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.1.0.tgz#06a53777a8cb7e4940ca8e20bf9c67dd65d9bd68" - integrity sha512-edSLD2OneYDKC6gZM1yc+wY/877s/fuJNoM1k3sOEpzFyeptSmke3SLnk1dDHk9CgTA+58mnfx3ew3J11Kes/w== +jest-util@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.2.0.tgz#bfccb85cfafae752257319e825a5b8d4ada470dc" + integrity sha512-T5ZJCNeFpqcLBpx+Hl9r9KoxBCUqeWlJ1Htli+vryigZVJ1vuLB9j35grEBASp4R13KFkV7jM52bBGnArpJN6A== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" "@types/node" "*" chalk "^4.0.0" graceful-fs "^4.2.4" is-ci "^3.0.0" picomatch "^2.2.3" -jest-validate@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.1.0.tgz#d9e82024c5e3f5cef52a600cfc456793a84c0998" - integrity sha512-QiJ+4XuSuMsfPi9zvdO//IrSRSlG6ybJhOpuqYSsuuaABaNT84h0IoD6vvQhThBOKT+DIKvl5sTM0l6is9+SRA== +jest-validate@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.2.0.tgz#b7535f12d95dd3b4382831f4047384ca098642ab" + integrity sha512-uIEZGkFKk3+4liA81Xu0maG5aGDyPLdp+4ed244c+Ql0k3aLWQYcMbaMLXOIFcb83LPHzYzqQ8hwNnIxTqfAGQ== dependencies: - "@jest/types" "^27.1.0" + "@jest/types" "^27.1.1" camelcase "^6.2.0" chalk "^4.0.0" jest-get-type "^27.0.6" leven "^3.1.0" - pretty-format "^27.1.0" + pretty-format "^27.2.0" -jest-watcher@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.1.0.tgz#2511fcddb0e969a400f3d1daa74265f93f13ce93" - integrity sha512-ivaWTrA46aHWdgPDgPypSHiNQjyKnLBpUIHeBaGg11U+pDzZpkffGlcB1l1a014phmG0mHgkOHtOgiqJQM6yKQ== +jest-watcher@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.2.0.tgz#dc2eef4c13c6d41cebf3f1fc5f900a54b51c2ea0" + integrity sha512-SjRWhnr+qO8aBsrcnYIyF+qRxNZk6MZH8TIDgvi+VlsyrvOyqg0d+Rm/v9KHiTtC9mGGeFi9BFqgavyWib6xLg== dependencies: - "@jest/test-result" "^27.1.0" - "@jest/types" "^27.1.0" + "@jest/test-result" "^27.2.0" + "@jest/types" "^27.1.1" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^27.1.0" + jest-util "^27.2.0" string-length "^4.0.1" jest-worker@27.0.0-next.5: @@ -8417,23 +8438,23 @@ jest-worker@^26.3.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.1.0.tgz#65f4a88e37148ed984ba8ca8492d6b376938c0aa" - integrity sha512-mO4PHb2QWLn9yRXGp7rkvXLAYuxwhq1ZYUo0LoDhg8wqvv4QizP1ZWEJOeolgbEgAWZLIEU0wsku8J+lGWfBhg== +jest-worker@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.2.0.tgz#11eef39f1c88f41384ca235c2f48fe50bc229bc0" + integrity sha512-laB0ZVIBz+voh/QQy9dmUuuDsadixeerrKqyVpgPz+CCWiOYjOBabUXHIXZhsdvkWbLqSHbgkAHWl5cg24Q6RA== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.1.0.tgz#eaab62dfdc02d8b7c814cd27b8d2d92bc46d3d69" - integrity sha512-pSQDVwRSwb109Ss13lcMtdfS9r8/w2Zz8+mTUA9VORD66GflCdl8nUFCqM96geOD2EBwWCNURrNAfQsLIDNBdg== +jest@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.2.0.tgz#3bc329287d699d26361e2094919630eefdf1ac0d" + integrity sha512-oUqVXyvh5YwEWl263KWdPUAqEzBFzGHdFLQ05hUnITr1tH+9SscEI9A/GH9eBClA+Nw1ct+KNuuOV6wlnmBPcg== dependencies: - "@jest/core" "^27.1.0" + "@jest/core" "^27.2.0" import-local "^3.0.2" - jest-cli "^27.1.0" + jest-cli "^27.2.0" joi@^17.4.0: version "17.4.2" @@ -10599,6 +10620,16 @@ pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.1.0: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^27.2.0: + version "27.2.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.2.0.tgz#ee37a94ce2a79765791a8649ae374d468c18ef19" + integrity sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA== + dependencies: + "@jest/types" "^27.1.1" + ansi-regex "^5.0.0" + ansi-styles "^5.0.0" + react-is "^17.0.1" + prettysize@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prettysize/-/prettysize-2.0.0.tgz#902c02480d865d9cc0813011c9feb4fa02ce6996" From 593d0bb655595553d21383b948e1f87f55abf4a3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 23:12:56 +0000 Subject: [PATCH 038/135] Update dependency @testing-library/react to ^12.1.0 (#6547) Co-authored-by: Renovate Bot --- packages/fields-document/package.json | 2 +- packages/keystone/package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index c97d88be197..b455cd50282 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -51,7 +51,7 @@ }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/fields-document", "devDependencies": { - "@testing-library/react": "^12.0.0", + "@testing-library/react": "^12.1.0", "array.prototype.flat": "^1.2.4", "jest-diff": "^27.2.0", "pretty-format": "^27.2.0", diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 3eec1ddd296..885d3abf6ff 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -124,7 +124,7 @@ }, "devDependencies": { "@testing-library/dom": "^8.2.0", - "@testing-library/react": "^12.0.0", + "@testing-library/react": "^12.1.0", "@testing-library/user-event": "^13.2.1", "@types/bytes": "^3.1.1", "fixturez": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 7be79da3e56..4c076a791ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2508,10 +2508,10 @@ lodash "^4.17.15" redent "^3.0.0" -"@testing-library/react@^12.0.0": - version "12.0.0" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.0.0.tgz#9aeb2264521522ab9b68f519eaf15136148f164a" - integrity sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA== +"@testing-library/react@^12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-12.1.0.tgz#3e9a4002b0b8f986a738a2f88fc458b5af319f35" + integrity sha512-Ge3Ht3qXE82Yv9lyPpQ7ZWgzo/HgOcHu569Y4ZGWcZME38iOFiOg87qnu6hTEa8jTJVL7zYovnvD3GE2nsNIoQ== dependencies: "@babel/runtime" "^7.12.5" "@testing-library/dom" "^8.0.0" From e7d4508fee77d877288b80ed9b1c6c45344d746d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 23:24:45 +0000 Subject: [PATCH 039/135] Update dependency @types/inflection to ^1.13.0 (#6549) Co-authored-by: Renovate Bot --- packages/keystone/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 885d3abf6ff..9305081e376 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -61,7 +61,7 @@ "@types/form-data": "2.5.0", "@types/fs-extra": "^9.0.12", "@types/graphql-upload": "^8.0.7", - "@types/inflection": "^1.5.28", + "@types/inflection": "^1.13.0", "@types/node-fetch": "^2.5.12", "@types/pluralize": "^0.0.29", "@types/prettier": "^2.3.2", diff --git a/yarn.lock b/yarn.lock index 4c076a791ed..f1eeb239fb3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2771,10 +2771,10 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-1.8.1.tgz#e81ad28a60bee0328c6d2384e029aec626f1ae67" integrity sha512-e+2rjEwK6KDaNOm5Aa9wNGgyS9oSZU/4pfSMMPYNOfjvFI0WVXm29+ITRFr6aKDvvKo7uU1jV68MW4ScsfDi7Q== -"@types/inflection@^1.5.28": - version "1.5.28" - resolved "https://registry.yarnpkg.com/@types/inflection/-/inflection-1.5.28.tgz#43d55e0d72cf333a2dffd9c4ec0407455a1b0931" - integrity sha1-Q9VeDXLPMzot/9nE7AQHRVobCTE= +"@types/inflection@^1.13.0": + version "1.13.0" + resolved "https://registry.yarnpkg.com/@types/inflection/-/inflection-1.13.0.tgz#d641b773317f2e71e5c7c80809057e3101c4b2bf" + integrity sha512-kZSETqAVS74XC/K3mPX/tbMEi/Zy1KP0Wc59dB1i5P72AHz4eSW+UIpzWxmQnDxipoKSX5eRgUXy+wUr+bY73g== "@types/is-hotkey@^0.1.1": version "0.1.5" From 1fd042da9a2bbb1eb2de9270f4c4d1a157cb303b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 23:35:09 +0000 Subject: [PATCH 040/135] Update dependency @testing-library/dom to ^8.5.0 (#6546) Co-authored-by: Renovate Bot --- packages/keystone/package.json | 2 +- yarn.lock | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 9305081e376..4392550ab5b 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -123,7 +123,7 @@ "uuid": "^8.3.2" }, "devDependencies": { - "@testing-library/dom": "^8.2.0", + "@testing-library/dom": "^8.5.0", "@testing-library/react": "^12.1.0", "@testing-library/user-event": "^13.2.1", "@types/bytes": "^3.1.1", diff --git a/yarn.lock b/yarn.lock index f1eeb239fb3..1e04ed57c44 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2479,7 +2479,7 @@ dependencies: defer-to-connect "^1.0.1" -"@testing-library/dom@^8.0.0", "@testing-library/dom@^8.2.0": +"@testing-library/dom@^8.0.0": version "8.2.0" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.2.0.tgz#ac46a1b9d7c81f0d341ae38fb5424b64c27d151e" integrity sha512-U8cTWENQPHO3QHvxBdfltJ+wC78ytMdg69ASvIdkGdQ/XRg4M9H2vvM3mHddxl+w/fM6NNqzGMwpQoh82v9VIA== @@ -2493,6 +2493,20 @@ lz-string "^1.4.4" pretty-format "^27.0.2" +"@testing-library/dom@^8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.5.0.tgz#56e31331015f943a68c6ec27e259fdf16c69ab7d" + integrity sha512-O0fmHFaPlqaYCpa/cBL0cvroMridb9vZsMLacgIqrlxj+fd+bGF8UfAgwsLCHRF84KLBafWlm9CuOvxeNTlodw== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/runtime" "^7.12.5" + "@types/aria-query" "^4.2.0" + aria-query "^4.2.2" + chalk "^4.1.0" + dom-accessibility-api "^0.5.6" + lz-string "^1.4.4" + pretty-format "^27.0.2" + "@testing-library/jest-dom@^5.14.1": version "5.14.1" resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz#8501e16f1e55a55d675fe73eecee32cdaddb9766" From 4eacef0793a84b460049d5157825fcb32900dd7a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 23:43:44 +0000 Subject: [PATCH 041/135] Update dependency cloudinary to ^1.27.0 (#6548) Co-authored-by: Renovate Bot --- packages/cloudinary/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/cloudinary/package.json b/packages/cloudinary/package.json index 2efc8cb2f6a..f2e26005a8f 100644 --- a/packages/cloudinary/package.json +++ b/packages/cloudinary/package.json @@ -11,7 +11,7 @@ "@keystone-ui/fields": "^4.1.3", "@keystone-ui/pill": "^5.0.1", "@types/react": "^17.0.20", - "cloudinary": "^1.26.3", + "cloudinary": "^1.27.0", "cuid": "^2.1.8", "graphql-upload": "^12.0.0", "react": "^17.0.2" diff --git a/yarn.lock b/yarn.lock index 1e04ed57c44..1bf7b985eee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4713,10 +4713,10 @@ cloudinary-core@^2.10.2: resolved "https://registry.yarnpkg.com/cloudinary-core/-/cloudinary-core-2.11.4.tgz#1d191935bcdcd412d499a91b928a94b266fee49d" integrity sha512-F1BZczD6f5mB73D0c8gl/iuacVQQO+UhckNZxeeS9ZIVeIHbsfqwWiAZMQmIvEb7Wti/9MLU0xVwaWOak2THHA== -cloudinary@^1.26.3: - version "1.26.3" - resolved "https://registry.yarnpkg.com/cloudinary/-/cloudinary-1.26.3.tgz#dd79a1e50395abcf7abec970f5973200c77430cb" - integrity sha512-80ItEXYLbhOGPM42ksOsqG6320jbsU6kqszjVjl5QwDwzbjouktRlw/NdGva1beSu8sp/0lj1mtSGPymGsNiQA== +cloudinary@^1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/cloudinary/-/cloudinary-1.27.0.tgz#1939f4767c32d596c8cd74ea3db66094bf25fa96" + integrity sha512-3Slh8gTmEfaut+ZBIMByOXaD60QP5uw46zn3lyYYEA0mhTQ82FIrwfj98s0eZ6PciQJIJ+Ea4QPBl7Ji21TQEA== dependencies: cloudinary-core "^2.10.2" core-js "3.6.5" From af4af5bf792fbf8c8b872104ff08ae033fb6a9e9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Sep 2021 23:56:06 +0000 Subject: [PATCH 042/135] Update dependency @babel/plugin-proposal-object-rest-spread to ^7.15.6 (#6545) Co-authored-by: Renovate Bot --- package.json | 2 +- yarn.lock | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 238a1f5c860..483cc956f74 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "dependencies": { "@babel/core": "^7.15.5", "@babel/plugin-proposal-class-properties": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.14.7", + "@babel/plugin-proposal-object-rest-spread": "^7.15.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.15.0", "@babel/preset-env": "^7.15.4", diff --git a/yarn.lock b/yarn.lock index 1bf7b985eee..92fd977198a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -406,6 +406,17 @@ "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-transform-parameters" "^7.14.5" +"@babel/plugin-proposal-object-rest-spread@^7.15.6": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz#ef68050c8703d07b25af402cb96cf7f34a68ed11" + integrity sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.15.4" + "@babel/plugin-proposal-optional-catch-binding@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" From ca0e789c522d83b61a08ec306aa28a4c78e6fcb5 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Sep 2021 00:10:30 +0000 Subject: [PATCH 043/135] Update dependency prettier to ^2.4.0 (#6550) --- package.json | 2 +- .../src/DocumentEditor/component-blocks/api.tsx | 8 +++----- packages/keystone/package.json | 2 +- prisma-utils/package.json | 2 +- yarn.lock | 7 ++++++- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 483cc956f74..dc11e22bf94 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "eslint-plugin-react-hooks": "^4.2.0", "is-ci": "^3.0.0", "jest": "^27.2.0", - "prettier": "^2.3.2", + "prettier": "^2.4.0", "react": "^17.0.2", "react-dom": "^17.0.2", "remark-cli": "^6.0.1", diff --git a/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx b/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx index 21517516f5c..ec6477829e5 100644 --- a/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx +++ b/packages/fields-document/src/DocumentEditor/component-blocks/api.tsx @@ -519,11 +519,9 @@ export function component< >( options: { /** The preview component shown in the editor */ - component: ( - props: { - [Key in keyof PropsOption]: ExtractPropFromComponentPropFieldForPreview; - } - ) => ReactElement | null; + component: (props: { + [Key in keyof PropsOption]: ExtractPropFromComponentPropFieldForPreview; + }) => ReactElement | null; /** The props that the preview component, toolbar and rendered component will receive */ props: PropsOption; /** The label to show in the insert menu and chrome around the block if chromeless is false */ diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 4392550ab5b..f11eb0ebadb 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -110,7 +110,7 @@ "p-limit": "^2.3.0", "pirates": "^4.0.1", "pluralize": "^8.0.0", - "prettier": "^2.3.2", + "prettier": "^2.4.0", "prisma": "2.30.2", "prompts": "^2.4.1", "react": "^17.0.2", diff --git a/prisma-utils/package.json b/prisma-utils/package.json index 5907387baba..fa1877b968e 100644 --- a/prisma-utils/package.json +++ b/prisma-utils/package.json @@ -7,7 +7,7 @@ "@prisma/generator-helper": "2.30.2", "@prisma/sdk": "2.30.2", "fs-extra": "^10.0.0", - "prettier": "^2.3.2" + "prettier": "^2.4.0" }, "scripts": { "generate": "node .", diff --git a/yarn.lock b/yarn.lock index 92fd977198a..0930f01f47f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10625,11 +10625,16 @@ prettier@^1.19.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.1.2, prettier@^2.3.2: +prettier@^2.1.2: version "2.3.2" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== +prettier@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.0.tgz#85bdfe0f70c3e777cf13a4ffff39713ca6f64cba" + integrity sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ== + pretty-bytes@^5.4.1: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" From 4e485a914cfbc6c4b5ef9eeca9157bf654469b2d Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Tue, 14 Sep 2021 10:44:55 +1000 Subject: [PATCH 044/135] Virtual field updates (#6538) --- .changeset/shy-bananas-explode.md | 5 ++ docs/pages/docs/apis/fields.mdx | 12 ++- docs/pages/docs/guides/virtual-fields.mdx | 14 ++-- examples/virtual-field/README.md | 4 +- examples/virtual-field/schema.ts | 4 +- .../src/fields/types/virtual/index.ts | 49 ++++++++++-- .../src/fields/types/virtual/views/index.tsx | 4 +- tests/api-tests/fields/types/Virtual.test.ts | 79 ++++++++----------- 8 files changed, 104 insertions(+), 67 deletions(-) create mode 100644 .changeset/shy-bananas-explode.md diff --git a/.changeset/shy-bananas-explode.md b/.changeset/shy-bananas-explode.md new file mode 100644 index 00000000000..1958ab4fd43 --- /dev/null +++ b/.changeset/shy-bananas-explode.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +Renamed `graphQLReturnFragment` to `ui.query` in the virtual field options. The virtual field now checks if `ui.query` is required for the GraphQL output type, and throws an error if it is missing. If you don't want want the Admin UI to fetch the field, you can set `ui.itemView.fieldMode` and `ui.listView.fieldMode` to `'hidden'` instead of providing `ui.query`. diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index d46d0db5f22..7b9100ebaef 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -594,7 +594,17 @@ See the [virtual fields guide](../guides/virtual-fields) for details on how to u Options: - `field` (required): The GraphQL field that defines the type, resolver and arguments. -- `graphQLReturnFragment` (default: `''` ): The sub-fields that should be fetched by the Admin UI when displaying this field. +- `ui.query` (default: `''` ): + Defines what the Admin UI should fetch from this field, it's interpolated into a query like this: + ```graphql + query { + item(where: { id: "..." }) { + field${ui.query} + } + } + ``` + This is only needed when you your field returns a GraphQL type other than a scalar(String and etc.) + or an enum or you need to provide arguments to the field. ```typescript import { config, list, graphql } from '@keystone-next/keystone'; diff --git a/docs/pages/docs/guides/virtual-fields.mdx b/docs/pages/docs/guides/virtual-fields.mdx index 8743a40428c..4502fd109f2 100644 --- a/docs/pages/docs/guides/virtual-fields.mdx +++ b/docs/pages/docs/guides/virtual-fields.mdx @@ -151,7 +151,7 @@ export default config({ } }, }), - graphQLReturnFragment: '(length: 500)', + ui: { query: '(length: 500)' }, }), }, }), @@ -180,9 +180,9 @@ We can now perform the following query to get all the excerpts without over-fetc } ``` -As well as passing in the `field` definition, we have also passed in `graphQLReturnFragment: '(length: 500)'`. +As well as passing in the `field` definition, we have also passed in `ui: { query: '(length: 500)' }`. This is the value used when displaying the field in the Admin UI, where we want to have a different length the default of `200`. -Had we not specified `defaultValue` in our field, the `graphQLReturnFragment` argument would be **required**, as the Admin UI would not be able to query this field without it. +Had we not specified `defaultValue` in our field, the `ui.query` argument would be **required**, as the Admin UI would not be able to query this field without it. ## GraphQL objects @@ -220,7 +220,7 @@ export default config({ }; }, }), - graphQLReturnFragment: '{ words sentences paragraphs }', + ui: { query: '{ words sentences paragraphs }' }, }), }, }), @@ -231,7 +231,7 @@ export default config({ This example is written in TypeScript, so we need to specify the type of the root value expected by the `PostCounts` type. This type must correspond to the return type of the `resolve` function. -Because our `virtual` field has an object type, we also need to provide a value for the option `graphQLReturnFragment`. +Because our `virtual` field has an object type, we also need to provide a value for the option `ui.query`. This fragment tells the Keystone Admin UI which values to show in the item page for this field. #### Self-referencing objects @@ -295,14 +295,14 @@ export const lists = { } }, }), - graphQLReturnFragment: '{ title publishDate }', + ui: { query: '{ title publishDate }' }, }), }, }), }; ``` -Once again we need to specify `graphQLReturnFragment` on this virtual field to specify which fields of the `Post` to display in the Admin UI. +Once again we need to specify `ui.query` on this virtual field to specify which fields of the `Post` to display in the Admin UI. ## Working with virtual fields diff --git a/examples/virtual-field/README.md b/examples/virtual-field/README.md index c195ac2888f..086cc1607e1 100644 --- a/examples/virtual-field/README.md +++ b/examples/virtual-field/README.md @@ -70,7 +70,7 @@ counts: virtual({ return { content: item.content || '' }; }, }), - graphQLReturnFragment: '{ words sentences paragraphs }', + ui: { query: '{ words sentences paragraphs }' }, }), ``` @@ -114,6 +114,6 @@ relatedPosts: virtual({ }); }, }), - graphQLReturnFragment: '{ title }', + ui: { query: '{ title }' }, }), ``` diff --git a/examples/virtual-field/schema.ts b/examples/virtual-field/schema.ts index fea52fcc586..ff95d0e7901 100644 --- a/examples/virtual-field/schema.ts +++ b/examples/virtual-field/schema.ts @@ -71,7 +71,7 @@ export const lists = { } }, }), - graphQLReturnFragment: '(length: 10)', + ui: { query: '(length: 10)' }, }), publishDate: timestamp(), author: relationship({ ref: 'Author.posts', many: false }), @@ -113,7 +113,7 @@ export const lists = { } }, }), - graphQLReturnFragment: '{ title publishDate }', + ui: { query: '{ title publishDate }' }, }), }, }), diff --git a/packages/keystone/src/fields/types/virtual/index.ts b/packages/keystone/src/fields/types/virtual/index.ts index 28333e8f404..6e267710ce3 100644 --- a/packages/keystone/src/fields/types/virtual/index.ts +++ b/packages/keystone/src/fields/types/virtual/index.ts @@ -1,3 +1,4 @@ +import { getNamedType, isLeafType } from 'graphql'; import { BaseGeneratedListTypes, graphql, @@ -6,10 +7,11 @@ import { FieldTypeFunc, fieldType, ListInfo, + getGqlNames, } from '../../../types'; import { resolveView } from '../../resolve-view'; -type VirtualFieldGraphQLField = graphql.Field; +type VirtualFieldGraphQLField = graphql.Field; export type VirtualFieldConfig = CommonFieldConfig & { @@ -17,18 +19,55 @@ export type VirtualFieldConfig) => VirtualFieldGraphQLField); unreferencedConcreteInterfaceImplementations?: graphql.ObjectType[]; - graphQLReturnFragment?: string; + ui?: { + /** + * Defines what the Admin UI should fetch from this field, it's interpolated into a query like this: + * ```graphql + * query { + * item(where: { id: "..." }) { + * field${ui.query} + * } + * } + * ``` + * + * This is only needed when you your field returns a GraphQL type other than a scalar(String and etc.) + * or an enum or you need to provide arguments to the field. + */ + query?: string; + }; }; export const virtual = ({ - graphQLReturnFragment = '', field, ...config }: VirtualFieldConfig): FieldTypeFunc => meta => { const usableField = typeof field === 'function' ? field(meta.lists) : field; - + const namedType = getNamedType(usableField.type.graphQLType); + const hasRequiredArgs = + usableField.args && + Object.values( + usableField.args as Record> + ).some(x => x.type.kind === 'non-null' && x.defaultValue === undefined); + if ( + (!isLeafType(namedType) || hasRequiredArgs) && + !config.ui?.query && + (config.ui?.itemView?.fieldMode !== 'hidden' || config.ui?.listView?.fieldMode !== 'hidden') + ) { + throw new Error( + `The virtual field at ${meta.listKey}.${meta.fieldKey} requires a selection for the Admin UI but ui.query is unspecified and ui.listView.fieldMode and ui.itemView.fieldMode are not both set to 'hidden'.\n` + + `Either set ui.query with what the Admin UI should fetch or hide the field from the Admin UI by setting ui.listView.fieldMode and ui.itemView.fieldMode to 'hidden'.\n` + + `When setting ui.query, it is interpolated into a GraphQL query like this:\n` + + `query {\n` + + ` ${ + getGqlNames({ listKey: meta.listKey, pluralGraphQLName: '' }).itemQueryName + }(where: { id: "..." }) {\n` + + ` ${meta.fieldKey}\${ui.query}\n` + + ` }\n` + + `}` + ); + } return fieldType({ kind: 'none', })({ @@ -40,6 +79,6 @@ export const virtual = }, }), views: resolveView('virtual/views'), - getAdminMeta: () => ({ graphQLReturnFragment }), + getAdminMeta: () => ({ query: config.ui?.query || '' }), }); }; diff --git a/packages/keystone/src/fields/types/virtual/views/index.tsx b/packages/keystone/src/fields/types/virtual/views/index.tsx index e7094bee26e..1140bc69db4 100644 --- a/packages/keystone/src/fields/types/virtual/views/index.tsx +++ b/packages/keystone/src/fields/types/virtual/views/index.tsx @@ -37,12 +37,12 @@ export const CardValue: CardValueComponent = ({ item, field }) => { const createViewValue = Symbol('create view virtual field value'); export const controller = ( - config: FieldControllerConfig<{ graphQLReturnFragment: string }> + config: FieldControllerConfig<{ query: string }> ): FieldController => { return { path: config.path, label: config.label, - graphqlSelection: `${config.path}${config.fieldMeta.graphQLReturnFragment}`, + graphqlSelection: `${config.path}${config.fieldMeta.query}`, defaultValue: createViewValue, deserialize: data => { return data[config.path]; diff --git a/tests/api-tests/fields/types/Virtual.test.ts b/tests/api-tests/fields/types/Virtual.test.ts index 6eb5c92f285..8e6fb348006 100644 --- a/tests/api-tests/fields/types/Virtual.test.ts +++ b/tests/api-tests/fields/types/Virtual.test.ts @@ -1,6 +1,6 @@ import { integer, relationship, text, virtual } from '@keystone-next/keystone/fields'; import { BaseFields, list } from '@keystone-next/keystone'; -import { setupTestRunner } from '@keystone-next/keystone/testing'; +import { setupTestEnv, setupTestRunner } from '@keystone-next/keystone/testing'; import { graphql } from '@keystone-next/keystone/types'; import { apiTestConfig } from '../../utils'; @@ -64,29 +64,6 @@ describe('Virtual field type', () => { }) ); - test( - 'args - use defaults', - makeRunner({ - foo: virtual({ - field: graphql.field({ - type: graphql.Int, - args: { - x: graphql.arg({ type: graphql.Int }), - y: graphql.arg({ type: graphql.Int }), - }, - resolve: (item, { x = 5, y = 6 }) => x! * y!, - }), - }), - })(async ({ context }) => { - const data = await context.lists.Post.createOne({ - data: { value: 1 }, - query: 'value foo', - }); - expect(data.value).toEqual(1); - expect(data.foo).toEqual(30); - }) - ); - test( 'referencing other list type', setupTestRunner({ @@ -117,6 +94,7 @@ describe('Virtual field type', () => { organisationAuthor: relationship({ ref: 'Organisation.authoredPosts' }), personAuthor: relationship({ ref: 'Person.authoredPosts' }), author: virtual({ + ui: { listView: { fieldMode: 'hidden' }, itemView: { fieldMode: 'hidden' } }, field: lists => graphql.field({ type: graphql.union({ @@ -185,32 +163,37 @@ describe('Virtual field type', () => { }) ); - test( - 'graphQLReturnFragment', - makeRunner({ - foo: virtual({ - field: graphql.field({ - type: graphql.list( - graphql.object<{ title: string; rating: number }>()({ - name: 'Movie', + test("errors when a non leaf type is used but the field isn't hidden in the Admin UI and ui.query isn't provided", async () => { + await expect( + setupTestEnv({ + config: apiTestConfig({ + lists: { + Post: list({ fields: { - title: graphql.field({ type: graphql.String }), - rating: graphql.field({ type: graphql.Int }), + virtual: virtual({ + field: graphql.field({ + type: graphql.object()({ + name: 'Something', + fields: { + something: graphql.field({ type: graphql.String }), + }, + }), + }), + }), }, - }) - ), - resolve() { - return [{ title: 'CATS!', rating: 100 }]; + }), }, }), - }), - })(async ({ context }) => { - const data = await context.lists.Post.createOne({ - data: { value: 1 }, - query: 'value foo { title rating }', - }); - expect(data.value).toEqual(1); - expect(data.foo).toEqual([{ title: 'CATS!', rating: 100 }]); - }) - ); + }) + ).rejects.toMatchInlineSnapshot(` + [Error: The virtual field at Post.virtual requires a selection for the Admin UI but ui.query is unspecified and ui.listView.fieldMode and ui.itemView.fieldMode are not both set to 'hidden'. + Either set ui.query with what the Admin UI should fetch or hide the field from the Admin UI by setting ui.listView.fieldMode and ui.itemView.fieldMode to 'hidden'. + When setting ui.query, it is interpolated into a GraphQL query like this: + query { + post(where: { id: "..." }) { + virtual\${ui.query} + } + }] + `); + }); }); From 7621d0db75033b68a510d5f6c9b03d9418980e73 Mon Sep 17 00:00:00 2001 From: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Date: Tue, 14 Sep 2021 06:31:02 +0530 Subject: [PATCH 045/135] export field types (#6481) --- .changeset/old-houses-yawn.md | 5 +++++ packages/keystone/src/fields/index.ts | 14 ++++++++++++++ .../keystone/src/fields/types/password/index.ts | 2 +- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .changeset/old-houses-yawn.md diff --git a/.changeset/old-houses-yawn.md b/.changeset/old-houses-yawn.md new file mode 100644 index 00000000000..324e9160685 --- /dev/null +++ b/.changeset/old-houses-yawn.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Exported Field types to help in updating contrib packages diff --git a/packages/keystone/src/fields/index.ts b/packages/keystone/src/fields/index.ts index 70ac5f483ed..8b72264efd4 100644 --- a/packages/keystone/src/fields/index.ts +++ b/packages/keystone/src/fields/index.ts @@ -1,14 +1,28 @@ export { autoIncrement } from './types/autoIncrement'; +export type { AutoIncrementFieldConfig } from './types/autoIncrement'; export { checkbox } from './types/checkbox'; +export type { CheckboxFieldConfig } from './types/checkbox'; export { decimal } from './types/decimal'; +export type { DecimalFieldConfig } from './types/decimal'; export { file } from './types/file'; +export type { FileFieldConfig } from './types/file'; export { float } from './types/float'; +export type { FloatFieldConfig } from './types/float'; export { integer } from './types/integer'; +export type { IntegerFieldConfig } from './types/integer'; export { image } from './types/image'; +export type { ImageFieldConfig } from './types/image'; export { json } from './types/json'; +export type { JsonFieldConfig } from './types/json'; export { password } from './types/password'; +export type { PasswordFieldConfig } from './types/password'; export { relationship } from './types/relationship'; +export type { RelationshipFieldConfig } from './types/relationship'; export { select } from './types/select'; +export type { SelectFieldConfig } from './types/select'; export { text } from './types/text'; +export type { TextFieldConfig } from './types/text'; export { timestamp } from './types/timestamp'; +export type { TimestampFieldConfig } from './types/timestamp'; export { virtual } from './types/virtual'; +export type { VirtualFieldConfig } from './types/virtual'; diff --git a/packages/keystone/src/fields/types/password/index.ts b/packages/keystone/src/fields/types/password/index.ts index 3984d94a265..e8d4b6c16ab 100644 --- a/packages/keystone/src/fields/types/password/index.ts +++ b/packages/keystone/src/fields/types/password/index.ts @@ -11,7 +11,7 @@ import { } from '../../../types'; import { resolveView } from '../../resolve-view'; -type PasswordFieldConfig = +export type PasswordFieldConfig = CommonFieldConfig & { /** * @default 8 From df6005c43de736fc21a2558ab38435832e5109c2 Mon Sep 17 00:00:00 2001 From: Thomas Walker Date: Tue, 14 Sep 2021 11:09:18 +1000 Subject: [PATCH 046/135] Update RELEASE.md with branch syncing instructions (#6471) * Update RELEASE.md * Update RELEASE.md * Update RELEASE.md * Update RELEASE.md --- RELEASE.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index 152a15646b6..12332a57ffb 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -160,3 +160,41 @@ Add release to release page index under `/docs/pages/releases/index.mdx` with a Commit website update and open PR to add to `master`. Have PR reviewed and merged into `master`. + +## GitHub branch sync + +When we do a release we need to make sure `master` and `website_live` are both in sync with each other, this is done by: + +Creating a branch off `master` such as `bring-in-latest-website-changes` and merging in `website_live` changes, opening a PR and getting it merged, example - https://github.com/keystonejs/keystone/pull/6470 + +Then the other way around, create a branch off `website_live` such as `bring-in-latest-master-changes`, and merging in `master` changes, opening a PR and getting it merged, example - https://github.com/keystonejs/keystone/pull/6472 + +Once this is done, the histories will be out of sync, GitHub will state that `website_live` is still x commits behind, if you look at the branches page - https://github.com/keystonejs/keystone/branches + +To resolve this in the CLI: + +Go to the `website_live` branch + +`git checkout website_live` + +Check that we're identical to master + +`git diff master` + +Do a merge that should just update the parents of the new commit + +`git merge master` + +This should be empty + +`git diff origin/website_live` + +This should be empty + +`git diff master` + +Force push `website_live` (after turning off branch protection in github) + +`git push --force` + +Branches should now be nicely aligned. From 914aef532e471348bd5e63381f95dc74f27b3f30 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Sep 2021 01:28:24 +0000 Subject: [PATCH 047/135] Lock file maintenance (#6531) --- RELEASE.md | 6 +- yarn.lock | 424 ++++++++++++++++++++--------------------------------- 2 files changed, 166 insertions(+), 264 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 12332a57ffb..40b41b05618 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -165,11 +165,11 @@ Have PR reviewed and merged into `master`. When we do a release we need to make sure `master` and `website_live` are both in sync with each other, this is done by: -Creating a branch off `master` such as `bring-in-latest-website-changes` and merging in `website_live` changes, opening a PR and getting it merged, example - https://github.com/keystonejs/keystone/pull/6470 +Creating a branch off `master` such as `bring-in-latest-website-changes` and merging in `website_live` changes, opening a PR and getting it merged, example - -Then the other way around, create a branch off `website_live` such as `bring-in-latest-master-changes`, and merging in `master` changes, opening a PR and getting it merged, example - https://github.com/keystonejs/keystone/pull/6472 +Then the other way around, create a branch off `website_live` such as `bring-in-latest-master-changes`, and merging in `master` changes, opening a PR and getting it merged, example - -Once this is done, the histories will be out of sync, GitHub will state that `website_live` is still x commits behind, if you look at the branches page - https://github.com/keystonejs/keystone/branches +Once this is done, the histories will be out of sync, GitHub will state that `website_live` is still x commits behind, if you look at the branches page - To resolve this in the CLI: diff --git a/yarn.lock b/yarn.lock index 0930f01f47f..bee611ccf28 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,9 +3,9 @@ "@apollo/client@^3.1.3", "@apollo/client@^3.4.10": - version "3.4.10" - resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.4.10.tgz#cee9ed75b1bb7f391c55d79300ecf87096e59792" - integrity sha512-b+8TT3jBM2BtEJi+V2FuLpvoYDZCY3baNYrgAgEyw4fjnuBCSRPY7qVjqriZAwMaGiTLtyVifGhmdeICQs4Eow== + version "3.4.11" + resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.4.11.tgz#19cc27abe59d0cdcc1d357b30a89ebec8bb2b072" + integrity sha512-+A0z/Vy7sDg1uyijv3t9w1U0ybxn0bSpMUZHpsb2cLg/zM8fEHQ217226buzJ+cPUA1GVfJ8n6JsiN26RchvNA== dependencies: "@graphql-typed-document-node/core" "^3.0.0" "@wry/context" "^0.6.0" @@ -18,7 +18,7 @@ symbol-observable "^4.0.0" ts-invariant "^0.9.0" tslib "^2.3.0" - zen-observable-ts "^1.1.0" + zen-observable-ts "~1.1.0" "@apollo/protobufjs@1.2.2": version "1.2.2" @@ -65,7 +65,7 @@ dependencies: "@babel/highlight" "^7.14.5" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.15.0": version "7.15.0" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== @@ -115,7 +115,7 @@ "@babel/helper-explode-assignable-expression" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.4": +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== @@ -308,9 +308,9 @@ js-tokens "^4.0.0" "@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.15.5", "@babel/parser@^7.7.2": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.5.tgz#d33a58ca69facc05b26adfe4abebfed56c1c2dac" - integrity sha512-2hQstc6I7T6tQsWzlboMh3SgMRPaS4H6H7cPQsJkdzTzEGqQrpLDsE2BGASU5sBPoEQyHzeqU6C8uKbFeEk6sg== + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.6.tgz#043b9aa3c303c0722e5377fef9197f4cf1796549" + integrity sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": version "7.15.4" @@ -395,17 +395,6 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-proposal-object-rest-spread@^7.14.7": - version "7.14.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363" - integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g== - dependencies: - "@babel/compat-data" "^7.14.7" - "@babel/helper-compilation-targets" "^7.14.5" - "@babel/helper-plugin-utils" "^7.14.5" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.14.5" - "@babel/plugin-proposal-object-rest-spread@^7.15.6": version "7.15.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz#ef68050c8703d07b25af402cb96cf7f34a68ed11" @@ -755,7 +744,7 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-replace-supers" "^7.14.5" -"@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.15.4": +"@babel/plugin-transform-parameters@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz#5f2285cc3160bf48c8502432716b48504d29ed62" integrity sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ== @@ -889,9 +878,9 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/preset-env@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.4.tgz#197e7f99a755c488f0af411af179cbd10de6e815" - integrity sha512-4f2nLw+q6ht8gl3sHCmNhmA5W6b1ItLzbH3UrKuJxACHr2eCpk96jwjrAfCAaXaaVwTQGnyUYHY2EWXJGt7TUQ== + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" + integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== dependencies: "@babel/compat-data" "^7.15.0" "@babel/helper-compilation-targets" "^7.15.4" @@ -907,7 +896,7 @@ "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" "@babel/plugin-proposal-numeric-separator" "^7.14.5" - "@babel/plugin-proposal-object-rest-spread" "^7.14.7" + "@babel/plugin-proposal-object-rest-spread" "^7.15.6" "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" "@babel/plugin-proposal-optional-chaining" "^7.14.5" "@babel/plugin-proposal-private-methods" "^7.14.5" @@ -960,7 +949,7 @@ "@babel/plugin-transform-unicode-escapes" "^7.14.5" "@babel/plugin-transform-unicode-regex" "^7.14.5" "@babel/preset-modules" "^0.1.4" - "@babel/types" "^7.15.4" + "@babel/types" "^7.15.6" babel-plugin-polyfill-corejs2 "^0.2.2" babel-plugin-polyfill-corejs3 "^0.2.2" babel-plugin-polyfill-regenerator "^0.2.2" @@ -1053,10 +1042,10 @@ "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.14.9", "@babel/types@^7.15.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.4.tgz#74eeb86dbd6748d2741396557b9860e57fce0a0d" - integrity sha512-0f1HJFuGmmbrKTCZtbm3cU+b/AqdEYk5toj5iQur58xkVMlS0JWaKxTBSmCXd47uiN7vbcozAupm6Mvs80GNhw== +"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.14.9", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.15.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" + integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== dependencies: "@babel/helper-validator-identifier" "^7.14.9" to-fast-properties "^2.0.0" @@ -1507,17 +1496,17 @@ strip-json-comments "^3.1.1" "@graphql-tools/merge@^8.1.0": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.1.1.tgz#692ff0de5e6b025a1166e25d7cda4e20ec0c2df3" - integrity sha512-zyeUbFG5zasSQC6LnBxzhmPTLYeeT3c0ijYfmFlIlOLiTAdRgCjIba03l6kKHcCiMDJYr+P+Nz5kKYLGqPSSjQ== + version "8.1.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.1.2.tgz#50f5763927c51de764d09c5bfd20261671976e24" + integrity sha512-kFLd4kKNJXYXnKIhM8q9zgGAtbLmsy3WmGdDxYq3YHBJUogucAxnivQYyRIseUq37KGmSAIWu3pBQ23TKGsGOw== dependencies: "@graphql-tools/utils" "^8.2.2" tslib "~2.3.0" "@graphql-tools/mock@^8.1.2": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.3.0.tgz#779780af477914fa872ed9163b6bf55a57e19edf" - integrity sha512-+at9bTfuP60bTFpcMRJ9/KWwJ1E3A+NUVM+15NEp2uHQk4E2l2OO3hnZ4P3JKtMoQY15a/xUVLByC7RqMb7PnA== + version "8.3.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/mock/-/mock-8.3.1.tgz#da89829e91d7492d6559efdfe1c5426a20e033ed" + integrity sha512-iJ3GeQ10Vqa0Tg4QJHiulxUUI4r84RAvltM3Sc+XPj07QlrLzMHOHO/goO7FC4TN2/HVncj7pWHwrmLPT9du/Q== dependencies: "@graphql-tools/schema" "^8.2.0" "@graphql-tools/utils" "^8.2.0" @@ -1798,17 +1787,6 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" -"@jest/types@^27.1.0": - version "27.1.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.0.tgz#674a40325eab23c857ebc0689e7e191a3c5b10cc" - integrity sha512-pRP5cLIzN7I7Vp6mHKRSaZD7YpBTK7hawx5si8trMKqk4+WOdK8NEKOTO2G8PKWD1HbKMVckVB6/XHh/olhf2g== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - "@jest/types@^27.1.1": version "27.1.1" resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.1.1.tgz#77a3fc014f906c65752d12123a0134359707c0ad" @@ -2490,21 +2468,7 @@ dependencies: defer-to-connect "^1.0.1" -"@testing-library/dom@^8.0.0": - version "8.2.0" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.2.0.tgz#ac46a1b9d7c81f0d341ae38fb5424b64c27d151e" - integrity sha512-U8cTWENQPHO3QHvxBdfltJ+wC78ytMdg69ASvIdkGdQ/XRg4M9H2vvM3mHddxl+w/fM6NNqzGMwpQoh82v9VIA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/runtime" "^7.12.5" - "@types/aria-query" "^4.2.0" - aria-query "^4.2.2" - chalk "^4.1.0" - dom-accessibility-api "^0.5.6" - lz-string "^1.4.4" - pretty-format "^27.0.2" - -"@testing-library/dom@^8.5.0": +"@testing-library/dom@^8.0.0", "@testing-library/dom@^8.5.0": version "8.5.0" resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.5.0.tgz#56e31331015f943a68c6ec27e259fdf16c69ab7d" integrity sha512-O0fmHFaPlqaYCpa/cBL0cvroMridb9vZsMLacgIqrlxj+fd+bGF8UfAgwsLCHRF84KLBafWlm9CuOvxeNTlodw== @@ -2929,9 +2893,9 @@ form-data "^3.0.0" "@types/node@*", "@types/node@>=8.1.0": - version "16.7.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.10.tgz#7aa732cc47341c12a16b7d562f519c2383b6d4fc" - integrity sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA== + version "16.9.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.1.tgz#0611b37db4246c937feef529ddcc018cf8e35708" + integrity sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g== "@types/node@^10.1.0": version "10.17.60" @@ -2939,9 +2903,9 @@ integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== "@types/node@^12.7.1": - version "12.20.23" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.23.tgz#d0d5885bb885ee9b1ed114a04ea586540a1b2e2a" - integrity sha512-FW0q7NI8UnjbKrJK8NGr6QXY69ATw9IFe6ItIo5yozPwA9DU/xkhiPddctUVyrmFXvyFYerYgQak/qu200UBDw== + version "12.20.24" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.24.tgz#c37ac69cb2948afb4cef95f424fa0037971a9a5c" + integrity sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ== "@types/nodemailer@^6.4.4": version "6.4.4" @@ -3031,9 +2995,9 @@ csstype "^3.0.2" "@types/redis@^2.8.31": - version "2.8.31" - resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.31.tgz#c11c1b269fec132ac2ec9eb891edf72fc549149e" - integrity sha512-daWrrTDYaa5iSDFbgzZ9gOOzyp2AJmYK59OlG/2KGBgYWF3lfs8GDKm1c//tik5Uc93hDD36O+qLPvzDolChbA== + version "2.8.32" + resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.32.tgz#1d3430219afbee10f8cfa389dad2571a05ecfb11" + integrity sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w== dependencies: "@types/node" "*" @@ -3177,118 +3141,72 @@ integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== "@typescript-eslint/eslint-plugin@^4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.0.tgz#9c3fa6f44bad789a962426ad951b54695bd3af6b" - integrity sha512-iPKZTZNavAlOhfF4gymiSuUkgLne/nh5Oz2/mdiUmuZVD42m9PapnCnzjxuDsnpnbH3wT5s2D8bw6S39TC6GNw== + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" + integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== dependencies: - "@typescript-eslint/experimental-utils" "4.31.0" - "@typescript-eslint/scope-manager" "4.31.0" + "@typescript-eslint/experimental-utils" "4.31.1" + "@typescript-eslint/scope-manager" "4.31.1" debug "^4.3.1" functional-red-black-tree "^1.0.1" regexpp "^3.1.0" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.0.tgz#0ef1d5d86c334f983a00f310e43c1ce4c14e054d" - integrity sha512-Hld+EQiKLMppgKKkdUsLeVIeEOrwKc2G983NmznY/r5/ZtZCDvIOXnXtwqJIgYz/ymsy7n7RGvMyrzf1WaSQrw== +"@typescript-eslint/experimental-utils@4.31.1", "@typescript-eslint/experimental-utils@^4.0.1", "@typescript-eslint/experimental-utils@^4.2.0": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.31.1.tgz#0c900f832f270b88e13e51753647b02d08371ce5" + integrity sha512-NtoPsqmcSsWty0mcL5nTZXMf7Ei0Xr2MT8jWjXMVgRK0/1qeQ2jZzLFUh4QtyJ4+/lPUyMw5cSfeeME+Zrtp9Q== dependencies: "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.31.0" - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/typescript-estree" "4.31.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/experimental-utils@^4.0.1", "@typescript-eslint/experimental-utils@^4.2.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz#9e49704fef568432ae16fc0d6685c13d67db0fd5" - integrity sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.30.0" - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/typescript-estree" "4.30.0" + "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/typescript-estree" "4.31.1" eslint-scope "^5.1.1" eslint-utils "^3.0.0" "@typescript-eslint/parser@^4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.0.tgz#87b7cd16b24b9170c77595d8b1363f8047121e05" - integrity sha512-oWbzvPh5amMuTmKaf1wp0ySxPt2ZXHnFQBN2Szu1O//7LmOvgaKTCIDNLK2NvzpmVd5A2M/1j/rujBqO37hj3w== + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" + integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== dependencies: - "@typescript-eslint/scope-manager" "4.31.0" - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/typescript-estree" "4.31.0" + "@typescript-eslint/scope-manager" "4.31.1" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/typescript-estree" "4.31.1" debug "^4.3.1" -"@typescript-eslint/scope-manager@4.30.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.30.0.tgz#1a3ffbb385b1a06be85cd5165a22324f069a85ee" - integrity sha512-VJ/jAXovxNh7rIXCQbYhkyV2Y3Ac/0cVHP/FruTJSAUUm4Oacmn/nkN5zfWmWFEanN4ggP0vJSHOeajtHq3f8A== - dependencies: - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/visitor-keys" "4.30.0" - -"@typescript-eslint/scope-manager@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.0.tgz#9be33aed4e9901db753803ba233b70d79a87fc3e" - integrity sha512-LJ+xtl34W76JMRLjbaQorhR0hfRAlp3Lscdiz9NeI/8i+q0hdBZ7BsiYieLoYWqy+AnRigaD3hUwPFugSzdocg== +"@typescript-eslint/scope-manager@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.31.1.tgz#0c21e8501f608d6a25c842fcf59541ef4f1ab561" + integrity sha512-N1Uhn6SqNtU2XpFSkD4oA+F0PfKdWHyr4bTX0xTj8NRx1314gBDRL1LUuZd5+L3oP+wo6hCbZpaa1in6SwMcVQ== dependencies: - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/visitor-keys" "4.31.0" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/visitor-keys" "4.31.1" -"@typescript-eslint/types@4.30.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.30.0.tgz#fb9d9b0358426f18687fba82eb0b0f869780204f" - integrity sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw== +"@typescript-eslint/types@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.1.tgz#5f255b695627a13401d2fdba5f7138bc79450d66" + integrity sha512-kixltt51ZJGKENNW88IY5MYqTBA8FR0Md8QdGbJD2pKZ+D5IvxjTYDNtJPDxFBiXmka2aJsITdB1BtO1fsgmsQ== -"@typescript-eslint/types@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.31.0.tgz#9a7c86fcc1620189567dc4e46cad7efa07ee8dce" - integrity sha512-9XR5q9mk7DCXgXLS7REIVs+BaAswfdHhx91XqlJklmqWpTALGjygWVIb/UnLh4NWhfwhR5wNe1yTyCInxVhLqQ== - -"@typescript-eslint/typescript-estree@4.30.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz#ae57833da72a753f4846cd3053758c771670c2ac" - integrity sha512-6WN7UFYvykr/U0Qgy4kz48iGPWILvYL34xXJxvDQeiRE018B7POspNRVtAZscWntEPZpFCx4hcz/XBT+erenfg== - dependencies: - "@typescript-eslint/types" "4.30.0" - "@typescript-eslint/visitor-keys" "4.30.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/typescript-estree@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.0.tgz#4da4cb6274a7ef3b21d53f9e7147cc76f278a078" - integrity sha512-QHl2014t3ptg+xpmOSSPn5hm4mY8D4s97ftzyk9BZ8RxYQ3j73XcwuijnJ9cMa6DO4aLXeo8XS3z1omT9LA/Eg== +"@typescript-eslint/typescript-estree@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.31.1.tgz#4a04d5232cf1031232b7124a9c0310b577a62d17" + integrity sha512-EGHkbsUvjFrvRnusk6yFGqrqMBTue5E5ROnS5puj3laGQPasVUgwhrxfcgkdHNFECHAewpvELE1Gjv0XO3mdWg== dependencies: - "@typescript-eslint/types" "4.31.0" - "@typescript-eslint/visitor-keys" "4.31.0" + "@typescript-eslint/types" "4.31.1" + "@typescript-eslint/visitor-keys" "4.31.1" debug "^4.3.1" globby "^11.0.3" is-glob "^4.0.1" semver "^7.3.5" tsutils "^3.21.0" -"@typescript-eslint/visitor-keys@4.30.0": - version "4.30.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz#a47c6272fc71b0c627d1691f68eaecf4ad71445e" - integrity sha512-pNaaxDt/Ol/+JZwzP7MqWc8PJQTUhZwoee/PVlQ+iYoYhagccvoHnC9e4l+C/krQYYkENxznhVSDwClIbZVxRw== - dependencies: - "@typescript-eslint/types" "4.30.0" - eslint-visitor-keys "^2.0.0" - -"@typescript-eslint/visitor-keys@4.31.0": - version "4.31.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.0.tgz#4e87b7761cb4e0e627dc2047021aa693fc76ea2b" - integrity sha512-HUcRp2a9I+P21+O21yu3ezv3GEPGjyGiXoEUQwZXjR8UxRApGeLyWH4ZIIUSalE28aG4YsV6GjtaAVB3QKOu0w== +"@typescript-eslint/visitor-keys@4.31.1": + version "4.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.31.1.tgz#f2e7a14c7f20c4ae07d7fc3c5878c4441a1da9cc" + integrity sha512-PCncP8hEqKw6SOJY+3St4LVtoZpPPn+Zlpm7KW5xnviMhdqcsBty4Lsg4J/VECpJjw1CkROaZhH4B8M1OfnXTQ== dependencies: - "@typescript-eslint/types" "4.31.0" + "@typescript-eslint/types" "4.31.1" eslint-visitor-keys "^2.0.0" "@wry/context@^0.6.0": @@ -3349,9 +3267,9 @@ acorn@^7.1.1, acorn@^7.4.0: integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== acorn@^8.0.0, acorn@^8.2.4: - version "8.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c" - integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA== + version "8.5.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== agent-base@6: version "6.0.2" @@ -3379,9 +3297,9 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571" - integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w== + version "8.6.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.3.tgz#11a66527761dc3e9a3845ea775d2d3c0414e8764" + integrity sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -3858,9 +3776,9 @@ aws4@^1.8.0: integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== axios@^0.21.1: - version "0.21.3" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.3.tgz#f85d9b747f9b66d59ca463605cedf1844872b82e" - integrity sha512-JtoZ3Ndke/+Iwt5n+BgSli/3idTvpt5OjKyoCmz4LX5+lPiY5l7C1colYezhlxThjNa/NhngCUWZSZFypIFuaA== + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== dependencies: follow-redirects "^1.14.0" @@ -4243,7 +4161,7 @@ browserslist@4.16.6: escalade "^3.1.1" node-releases "^1.1.71" -browserslist@^4.16.6, browserslist@^4.16.8: +browserslist@^4.16.6, browserslist@^4.17.0: version "4.17.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.0.tgz#1fcd81ec75b41d6d4994fb0831b92ac18c01649c" integrity sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g== @@ -4423,9 +4341,9 @@ camelcase@^6.2.0: integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== caniuse-lite@^1.0.30001202, caniuse-lite@^1.0.30001219, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001254: - version "1.0.30001254" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001254.tgz#974d45e8b7f6e3b63d4b1435e97752717612d4b9" - integrity sha512-GxeHOvR0LFMYPmFGA+NiTOt9uwYDxB3h154tW2yBYwfz2EMX3i1IBgr6gmJGfU0K8KQsqPa5XqLD8zVdP5lUzA== + version "1.0.30001257" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz#150aaf649a48bee531104cfeda57f92ce587f6e5" + integrity sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA== caseless@~0.12.0: version "0.12.0" @@ -4796,9 +4714,9 @@ color-name@~1.1.4: integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colorette@^1.2.2, colorette@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af" - integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w== + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colors@^1.1.2: version "1.4.0" @@ -4951,17 +4869,17 @@ copy-to-clipboard@^3.3.1: toggle-selection "^1.0.6" core-js-compat@^3.14.0, core-js-compat@^3.16.0: - version "3.17.2" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.17.2.tgz#f461ab950c0a0ffedfc327debf28b7e518950936" - integrity sha512-lHnt7A1Oqplebl5i0MrQyFv/yyEzr9p29OjlkcsFRDDgHwwQyVckfRGJ790qzXhkwM8ba4SFHHa2sO+T5f1zGg== + version "3.17.3" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.17.3.tgz#b39c8e4dec71ecdc735c653ce5233466e561324e" + integrity sha512-+in61CKYs4hQERiADCJsdgewpdl/X0GhEX77pjKgbeibXviIt2oxEjTc8O2fqHX8mDdBrDvX8MYD/RYsBv4OiA== dependencies: - browserslist "^4.16.8" + browserslist "^4.17.0" semver "7.0.0" core-js-pure@^3.10.2, core-js-pure@^3.16.0: - version "3.17.2" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.17.2.tgz#ba6311b6aa1e2f2adeba4ac6ec51a9ff40bdc1af" - integrity sha512-2VV7DlIbooyTI7Bh+yzOOWL9tGwLnQKHno7qATE+fqZzDKYr6llVjVQOzpD/QLZFgXDPb8T71pJokHEZHEYJhQ== + version "3.17.3" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.17.3.tgz#98ea3587188ab7ef4695db6518eeb71aec42604a" + integrity sha512-YusrqwiOTTn8058JDa0cv9unbXdIiIgcgI9gXso0ey4WgkFLd3lYlV9rp9n7nDCsYxXsMDTjA4m1h3T348mdlQ== core-js@3.6.5: version "3.6.5" @@ -4969,9 +4887,9 @@ core-js@3.6.5: integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== core-js@^3.1.3: - version "3.17.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.17.2.tgz#f960eae710dc62c29cca93d5332e3660e289db10" - integrity sha512-XkbXqhcXeMHPRk2ItS+zQYliAMilea2euoMsnpRRdDad6b2VY6CQQcwz1K8AnWesfw4p165RzY0bTnr3UrbYiA== + version "3.17.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.17.3.tgz#8e8bd20e91df9951e903cabe91f9af4a0895bc1e" + integrity sha512-lyvajs+wd8N1hXfzob1LdOCCHFU4bGMbqqmLn1Q4QlCpDqWPpGf+p0nj+LNrvDDG33j0hZXw2nsvvVpHysxyNw== core-util-is@1.0.2: version "1.0.2" @@ -5212,14 +5130,14 @@ cssstyle@^2.3.0: cssom "~0.3.6" csstype@^2.5.7: - version "2.6.17" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e" - integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A== + version "2.6.18" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.18.tgz#980a8b53085f34af313410af064f2bd241784218" + integrity sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ== csstype@^3.0.2: - version "3.0.8" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.8.tgz#d2266a792729fb227cd216fb572f43728e1ad340" - integrity sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw== + version "3.0.9" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.9.tgz#6410af31b26bd0520933d02cbc64fce9ce3fbf0b" + integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw== csv-generate@^3.4.3: version "3.4.3" @@ -5687,9 +5605,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.723, electron-to-chromium@^1.3.830: - version "1.3.830" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.830.tgz#40e3144204f8ca11b2cebec83cf14c20d3499236" - integrity sha512-gBN7wNAxV5vl1430dG+XRcQhD4pIeYeak6p6rjdCtlz5wWNwDad8jwvphe5oi1chL5MV6RNRikfffBBiFuj+rQ== + version "1.3.837" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.837.tgz#3a807540df47b85fb819481539b8ed9083b0a3b5" + integrity sha512-AWDQiLSmSXg7/cDwMtkl7v3od7yLGQmvP2uydZYx4L2GEWUUFbCEfR72aCIB8ig3zI+vqYwvPScKfma3LD5xNw== elegant-spinner@^1.0.1: version "1.0.1" @@ -5773,21 +5691,22 @@ error-ex@^1.3.1: is-arrayish "^0.2.1" es-abstract@^1.17.2, es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2, es-abstract@^1.18.5: - version "1.18.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19" - integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA== + version "1.18.6" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.6.tgz#2c44e3ea7a6255039164d26559777a6d978cb456" + integrity sha512-kAeIT4cku5eNLNuUKhlmtuk1/TRZvQoYccn6TO0cSVdf1kzB0T7+dYuVK9MWM7l+/53W2Q8M7N2c6MQvhXFcUQ== dependencies: call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" has "^1.0.3" has-symbols "^1.0.2" internal-slot "^1.0.3" - is-callable "^1.2.3" + is-callable "^1.2.4" is-negative-zero "^2.0.1" - is-regex "^1.1.3" - is-string "^1.0.6" + is-regex "^1.1.4" + is-string "^1.0.7" object-inspect "^1.11.0" object-keys "^1.1.1" object.assign "^4.1.2" @@ -6357,9 +6276,9 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fast-safe-stringify@^2.0.7: - version "2.0.8" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f" - integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag== + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== fast-write-atomic@0.2.1: version "0.2.1" @@ -6367,9 +6286,9 @@ fast-write-atomic@0.2.1: integrity sha512-WvJe06IfNYlr+6cO3uQkdKdy3Cb1LlCJSF8zRs2eT8yuhdbSlR9nIt+TgQ92RUxiRrQm+/S7RARnMfCs5iuAjw== fastq@^1.6.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.12.0.tgz#ed7b6ab5d62393fb2cc591c853652a5c318bf794" - integrity sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg== + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== dependencies: reusify "^1.0.4" @@ -6644,9 +6563,9 @@ forwarded@0.2.0: integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== fp-ts@^2.11.1: - version "2.11.1" - resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.11.1.tgz#b1eeb2540728b6328542664888442f8f805d2443" - integrity sha512-CJOfs+Heq/erkE5mqH2mhpsxCKABGmcLyeEwPxtbTlkLkItGUs6bmk2WqjB2SgoVwNwzTE5iKjPQJiq06CPs5g== + version "2.11.2" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.11.2.tgz#a3f5f74ac56f16c412044470a5fe3b51b94816dc" + integrity sha512-G1rD89nmbbgTNRBKohjB3Qv4IxOHQ5KV3ZvYfpaQZyrGt+ZQUFrcnCqE567bcEdvwoAUKDQM7isOcv7xcM/qAQ== fragment-cache@^0.2.1: version "0.2.1" @@ -6821,6 +6740,14 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -7594,7 +7521,7 @@ is-buffer@^2.0.0: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== -is-callable@^1.1.4, is-callable@^1.2.3: +is-callable@^1.1.4, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== @@ -7882,7 +7809,7 @@ is-reference@^1.1.4, is-reference@^1.2.1: dependencies: "@types/estree" "*" -is-regex@^1.1.3: +is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== @@ -7900,7 +7827,7 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5, is-string@^1.0.6: +is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== @@ -8121,17 +8048,7 @@ jest-config@^27.2.0: micromatch "^4.0.4" pretty-format "^27.2.0" -jest-diff@^27.0.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.1.0.tgz#c7033f25add95e2218f3c7f4c3d7b634ab6b3cd2" - integrity sha512-rjfopEYl58g/SZTsQFmspBODvMSytL16I+cirnScWTLkQVXYVZfxm78DFfdIIXc05RCYuGjxJqrdyG4PIFzcJg== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.0.6" - jest-get-type "^27.0.6" - pretty-format "^27.1.0" - -jest-diff@^27.2.0: +jest-diff@^27.0.0, jest-diff@^27.2.0: version "27.2.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.2.0.tgz#bda761c360f751bab1e7a2fe2fc2b0a35ce8518c" integrity sha512-QSO9WC6btFYWtRJ3Hac0sRrkspf7B01mGrrQEiCW6TobtViJ9RWL0EmOs/WnBsZDsI/Y2IoSHZA2x6offu0sYw== @@ -9740,9 +9657,9 @@ next-compose-plugins@^2.2.1: integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg== next-sitemap@^1.6.164: - version "1.6.164" - resolved "https://registry.yarnpkg.com/next-sitemap/-/next-sitemap-1.6.164.tgz#8e633c5a5687aad292284ef3f5eeddeb8df42e31" - integrity sha512-7kfuZYEuuKNzAiJ5cLH+wCS5A/J57Hb4ZyIAf8JIbX6dLJjVQdRCrt4zp/AfC/w5+faOds3zvwqg5fyEykZvPw== + version "1.6.168" + resolved "https://registry.yarnpkg.com/next-sitemap/-/next-sitemap-1.6.168.tgz#5d184b7713edf03c16e6d9064c9a00b2339ec78c" + integrity sha512-zzveI/1tjyvdTHd9qoxzH1JyK+wNqW3L+AxHf7Ppa7FbmcLb9Gj30b2pBLTK9wSiRVuSYAjOGxsPliL+daxspQ== dependencies: "@corex/deepmerge" "^2.6.34" matcher "^4.0.0" @@ -10625,12 +10542,7 @@ prettier@^1.19.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.1.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d" - integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== - -prettier@^2.4.0: +prettier@^2.1.2, prettier@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.0.tgz#85bdfe0f70c3e777cf13a4ffff39713ca6f64cba" integrity sha512-DsEPLY1dE5HF3BxCRBmD4uYZ+5DCbvatnolqTqcxEgKVZnL2kUfyu7b8pPQ5+hTBkdhU9SLUmK0/pHb07RE4WQ== @@ -10640,17 +10552,7 @@ pretty-bytes@^5.4.1: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== -pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.1.0: - version "27.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.1.0.tgz#022f3fdb19121e0a2612f3cff8d724431461b9ca" - integrity sha512-4aGaud3w3rxAO6OXmK3fwBFQ0bctIOG3/if+jYEFGNGIs0EvuidQm3bZ9mlP2/t9epLNC/12czabfy7TZNSwVA== - dependencies: - "@jest/types" "^27.1.0" - ansi-regex "^5.0.0" - ansi-styles "^5.0.0" - react-is "^17.0.1" - -pretty-format@^27.2.0: +pretty-format@^27.0.0, pretty-format@^27.0.2, pretty-format@^27.2.0: version "27.2.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.2.0.tgz#ee37a94ce2a79765791a8649ae374d468c18ef19" integrity sha512-KyJdmgBkMscLqo8A7K77omgLx5PWPiXJswtTtFV7XgVZv2+qPk6UivpXXO+5k6ZEbWIbLoKdx1pZ6ldINzbwTA== @@ -11940,10 +11842,10 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" -source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.19: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== +source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: + version "0.5.20" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -12607,13 +12509,13 @@ terminal-link@^3.0.0: supports-hyperlinks "^2.2.0" terser@^5.2.1: - version "5.7.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.2.tgz#d4d95ed4f8bf735cb933e802f2a1829abf545e3f" - integrity sha512-0Omye+RD4X7X69O0eql3lC4Heh/5iLj3ggxR/B5ketZLOtLiOqukUgjw3q4PDnNQbsrkKr3UMypqStQG3XKRvw== + version "5.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.8.0.tgz#c6d352f91aed85cc6171ccb5e84655b77521d947" + integrity sha512-f0JH+6yMpneYcRJN314lZrSwu9eKkUFEHLN/kNy8ceh8gaRiLgFPJqrB9HsXjhEGdv4e/ekjTOFxIlL6xlma8A== dependencies: commander "^2.20.0" source-map "~0.7.2" - source-map-support "~0.5.19" + source-map-support "~0.5.20" test-exclude@^6.0.0: version "6.0.0" @@ -12689,9 +12591,9 @@ tmp@^0.0.33: os-tmpdir "~1.0.2" tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-arraybuffer@^1.0.0: version "1.0.1" @@ -12851,9 +12753,9 @@ trough@^1.0.0: integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== ts-invariant@^0.9.0: - version "0.9.1" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.1.tgz#87dfde9894a4ce3c7711b02b1b449e7fd7384b13" - integrity sha512-hSeYibh29ULlHkuEfukcoiyTct+s2RzczMLTv4x3NWC/YrBy7x7ps5eYq/b4Y3Sb9/uAlf54+/5CAEMVxPhuQw== + version "0.9.3" + resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.3.tgz#4b41e0a80c2530a56ce4b8fd4e14183aaac0efa8" + integrity sha512-HinBlTbFslQI0OHP07JLsSXPibSegec6r9ai5xxq/qHYCsIQbzpymLpDhAUsnXcSrDEcd0L62L8vsOEdzM0qlA== dependencies: tslib "^2.1.0" @@ -13013,9 +12915,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.2.tgz#6d618640d430e3569a1dfb44f7d7e600ced3ee86" - integrity sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ== + version "4.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" + integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== uid-safe@^2.1.5: version "2.1.5" @@ -13758,9 +13660,9 @@ write-file-atomic@^3.0.0: typedarray-to-buffer "^3.1.5" ws@^7.4.6: - version "7.5.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.4.tgz#56bfa20b167427e138a7795de68d134fe92e21f9" - integrity sha512-zP9z6GXm6zC27YtspwH99T3qTG7bBFv2VIkeHstMLrLlDJuzA7tQ5ls3OJ1hOGGCzTQPniNJoHXIAOS0Jljohg== + version "7.5.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" + integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== x-is-string@^0.1.0: version "0.1.0" @@ -13892,7 +13794,7 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zen-observable-ts@^1.1.0: +zen-observable-ts@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== From e0d9626383b39671f4b9e9470b38c94c6e6bde1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Sep 2021 01:55:40 +0000 Subject: [PATCH 048/135] Update patch dependencies (patch) (#6489) --- design-system/website/package.json | 2 +- docs/package.json | 4 +-- examples-staging/assets-cloud/package.json | 2 +- examples-staging/assets-local/package.json | 2 +- examples-staging/auth/package.json | 2 +- examples-staging/basic/package.json | 2 +- examples-staging/ecommerce/package.json | 4 +-- examples-staging/embedded-nextjs/package.json | 2 +- examples-staging/roles/package.json | 2 +- examples/blog/package.json | 2 +- examples/custom-admin-ui-logo/package.json | 2 +- .../custom-admin-ui-navigation/package.json | 2 +- examples/custom-admin-ui-pages/package.json | 2 +- examples/custom-field-view/package.json | 2 +- examples/custom-field/package.json | 2 +- examples/default-values/package.json | 2 +- examples/document-field/package.json | 2 +- examples/extend-graphql-schema/package.json | 2 +- examples/json/package.json | 2 +- examples/task-manager/package.json | 2 +- examples/testing/package.json | 4 +-- examples/virtual-field/package.json | 2 +- examples/with-auth/package.json | 2 +- package.json | 10 +++--- packages/fields-document/package.json | 2 +- packages/keystone/package.json | 8 ++--- packages/session-store-redis/package.json | 2 +- tests/test-projects/basic/package.json | 2 +- .../crud-notifications/package.json | 2 +- yarn.lock | 34 +++++++++---------- 30 files changed, 56 insertions(+), 56 deletions(-) diff --git a/design-system/website/package.json b/design-system/website/package.json index 952d4f3ce11..d69c7d77984 100644 --- a/design-system/website/package.json +++ b/design-system/website/package.json @@ -30,7 +30,7 @@ "tinycolor2": "^1.4.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/docs/package.json b/docs/package.json index 92e720f1b58..390effaa4db 100644 --- a/docs/package.json +++ b/docs/package.json @@ -46,9 +46,9 @@ }, "devDependencies": { "@types/lodash.debounce": "^4.0.6", - "next-sitemap": "^1.6.164", + "next-sitemap": "^1.6.168", "start-server-and-test": "^1.14.0", - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/assets-cloud/package.json b/examples-staging/assets-cloud/package.json index c939653f3cb..cad7866ec20 100644 --- a/examples-staging/assets-cloud/package.json +++ b/examples-staging/assets-cloud/package.json @@ -13,7 +13,7 @@ "dotenv": "^10.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/assets-local/package.json b/examples-staging/assets-local/package.json index c6a7b6132e5..bbc4383d52c 100644 --- a/examples-staging/assets-local/package.json +++ b/examples-staging/assets-local/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/auth/package.json b/examples-staging/auth/package.json index a2e9793f942..b15792fa2d7 100644 --- a/examples-staging/auth/package.json +++ b/examples-staging/auth/package.json @@ -16,7 +16,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/basic/package.json b/examples-staging/basic/package.json index 606566a16e6..d7a71df6ead 100644 --- a/examples-staging/basic/package.json +++ b/examples-staging/basic/package.json @@ -27,7 +27,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/ecommerce/package.json b/examples-staging/ecommerce/package.json index 660f19fcfde..0eba70d3bc7 100644 --- a/examples-staging/ecommerce/package.json +++ b/examples-staging/ecommerce/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.4", + "@babel/preset-env": "^7.15.6", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@babel/runtime": "^7.15.4", @@ -28,7 +28,7 @@ "stripe": "^8.174.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/embedded-nextjs/package.json b/examples-staging/embedded-nextjs/package.json index 709adba8534..8e95bdb5d99 100644 --- a/examples-staging/embedded-nextjs/package.json +++ b/examples-staging/embedded-nextjs/package.json @@ -16,7 +16,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples-staging/roles/package.json b/examples-staging/roles/package.json index ecd8c71c289..3361f7f878d 100644 --- a/examples-staging/roles/package.json +++ b/examples-staging/roles/package.json @@ -16,7 +16,7 @@ "react-dom": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/blog/package.json b/examples/blog/package.json index 14b39a0db65..e146cf0eb59 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -13,7 +13,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-admin-ui-logo/package.json b/examples/custom-admin-ui-logo/package.json index 563c72c024b..5d856f532b1 100644 --- a/examples/custom-admin-ui-logo/package.json +++ b/examples/custom-admin-ui-logo/package.json @@ -15,7 +15,7 @@ "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-admin-ui-navigation/package.json b/examples/custom-admin-ui-navigation/package.json index 86c3496dd8e..a29f7b74db3 100644 --- a/examples/custom-admin-ui-navigation/package.json +++ b/examples/custom-admin-ui-navigation/package.json @@ -13,7 +13,7 @@ "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-admin-ui-pages/package.json b/examples/custom-admin-ui-pages/package.json index 5dc75970641..b24c8d8eb97 100644 --- a/examples/custom-admin-ui-pages/package.json +++ b/examples/custom-admin-ui-pages/package.json @@ -14,7 +14,7 @@ "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-field-view/package.json b/examples/custom-field-view/package.json index 1a28687a4fd..8f159f65738 100644 --- a/examples/custom-field-view/package.json +++ b/examples/custom-field-view/package.json @@ -18,7 +18,7 @@ "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/custom-field/package.json b/examples/custom-field/package.json index 874ece11724..22a8c4c2584 100644 --- a/examples/custom-field/package.json +++ b/examples/custom-field/package.json @@ -14,7 +14,7 @@ "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/default-values/package.json b/examples/default-values/package.json index 6e9eadc8e3b..3f924cb9021 100644 --- a/examples/default-values/package.json +++ b/examples/default-values/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/document-field/package.json b/examples/document-field/package.json index 9dc76bd34d7..cc0f4a2df5f 100644 --- a/examples/document-field/package.json +++ b/examples/document-field/package.json @@ -18,7 +18,7 @@ "react": "^17.0.2" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/extend-graphql-schema/package.json b/examples/extend-graphql-schema/package.json index ad02a179778..97afb90417e 100644 --- a/examples/extend-graphql-schema/package.json +++ b/examples/extend-graphql-schema/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/json/package.json b/examples/json/package.json index 72fdf6d4875..e6c62a1b1f3 100644 --- a/examples/json/package.json +++ b/examples/json/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/task-manager/package.json b/examples/task-manager/package.json index b383afca1c8..2395c798579 100644 --- a/examples/task-manager/package.json +++ b/examples/task-manager/package.json @@ -13,7 +13,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/testing/package.json b/examples/testing/package.json index b4d352bc8ba..519db7a8f17 100644 --- a/examples/testing/package.json +++ b/examples/testing/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@babel/core": "^7.15.5", - "@babel/preset-env": "^7.15.4", + "@babel/preset-env": "^7.15.6", "@babel/preset-typescript": "^7.15.0", "@keystone-next/auth": "^32.0.0", "@keystone-next/keystone": "^25.0.0" @@ -19,7 +19,7 @@ "devDependencies": { "babel-jest": "^27.2.0", "jest": "^27.2.0", - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/virtual-field/package.json b/examples/virtual-field/package.json index cd9ddc93dd8..f8a8743d0cc 100644 --- a/examples/virtual-field/package.json +++ b/examples/virtual-field/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/examples/with-auth/package.json b/examples/with-auth/package.json index f06c93de849..05ef8849942 100644 --- a/examples/with-auth/package.json +++ b/examples/with-auth/package.json @@ -13,7 +13,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/package.json b/package.json index dc11e22bf94..3f4571d26f0 100644 --- a/package.json +++ b/package.json @@ -45,20 +45,20 @@ "@babel/plugin-proposal-object-rest-spread": "^7.15.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.4", + "@babel/preset-env": "^7.15.6", "@babel/preset-react": "^7.14.5", "@babel/preset-typescript": "^7.15.0", "@changesets/changelog-github": "^0.4.1", "@changesets/cli": "^2.17.0", "@jest/test-sequencer": "^27.2.0", "@manypkg/cli": "^0.18.0", - "@preconstruct/cli": "2.1.1", + "@preconstruct/cli": "2.1.3", "@preconstruct/eslint-plugin-format-js-tag": "^0.1.0", "@testing-library/jest-dom": "^5.14.1", "@types/jest": "^27.0.1", "@types/node-fetch": "^2.5.12", - "@typescript-eslint/eslint-plugin": "^4.31.0", - "@typescript-eslint/parser": "^4.31.0", + "@typescript-eslint/eslint-plugin": "^4.31.1", + "@typescript-eslint/parser": "^4.31.1", "chalk-cli": "^4.1.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", @@ -77,7 +77,7 @@ "remark-toc": "^5.1.1", "rimraf": "^3.0.2", "terminal-link-cli": "^3.0.0", - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "prettier": { "proseWrap": "preserve", diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index b455cd50282..60e826ebaec 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -31,7 +31,7 @@ "@keystone-ui/tooltip": "^4.0.2", "@types/react": "^17.0.20", "apply-ref": "^1.0.0", - "fp-ts": "^2.11.1", + "fp-ts": "^2.11.2", "graphql": "^15.5.3", "io-ts": "^2.2.16", "io-ts-excess": "^1.0.1", diff --git a/packages/keystone/package.json b/packages/keystone/package.json index f11eb0ebadb..783210bebf5 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -26,14 +26,14 @@ "keystone-next": "bin/cli.js" }, "dependencies": { - "@apollo/client": "^3.4.10", + "@apollo/client": "^3.4.11", "@babel/core": "^7.15.5", "@babel/plugin-transform-modules-commonjs": "^7.15.4", "@babel/runtime": "^7.15.4", "@emotion/hash": "^0.8.0", "@emotion/weak-memoize": "^0.2.5", "@graphql-tools/schema": "^8.2.0", - "@graphql-ts/schema": "0.3.0", + "@graphql-ts/schema": "0.3.1", "@hapi/iron": "^6.0.0", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", @@ -116,9 +116,9 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "resolve": "^1.20.0", - "source-map-support": "^0.5.19", + "source-map-support": "^0.5.20", "supertest": "^6.1.6", - "typescript": "^4.4.2", + "typescript": "^4.4.3", "uid-safe": "^2.1.5", "uuid": "^8.3.2" }, diff --git a/packages/session-store-redis/package.json b/packages/session-store-redis/package.json index 87280511352..75a26454e1f 100644 --- a/packages/session-store-redis/package.json +++ b/packages/session-store-redis/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@babel/runtime": "^7.15.4", - "@types/redis": "^2.8.31" + "@types/redis": "^2.8.32" }, "peerDependencies": { "@keystone-next/keystone": "^25.0.0" diff --git a/tests/test-projects/basic/package.json b/tests/test-projects/basic/package.json index f5d2f6d137a..52006d99bf4 100644 --- a/tests/test-projects/basic/package.json +++ b/tests/test-projects/basic/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/tests/test-projects/crud-notifications/package.json b/tests/test-projects/crud-notifications/package.json index 933682bd82b..cbbc5ca6d6e 100644 --- a/tests/test-projects/crud-notifications/package.json +++ b/tests/test-projects/crud-notifications/package.json @@ -12,7 +12,7 @@ "@keystone-next/keystone": "^25.0.0" }, "devDependencies": { - "typescript": "^4.4.2" + "typescript": "^4.4.3" }, "engines": { "node": "^12.20 || >= 14.13" diff --git a/yarn.lock b/yarn.lock index bee611ccf28..eb5f11ad7a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@apollo/client@^3.1.3", "@apollo/client@^3.4.10": +"@apollo/client@^3.1.3", "@apollo/client@^3.4.11": version "3.4.11" resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.4.11.tgz#19cc27abe59d0cdcc1d357b30a89ebec8bb2b072" integrity sha512-+A0z/Vy7sDg1uyijv3t9w1U0ybxn0bSpMUZHpsb2cLg/zM8fEHQ217226buzJ+cPUA1GVfJ8n6JsiN26RchvNA== @@ -877,7 +877,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/preset-env@^7.15.4": +"@babel/preset-env@^7.15.6": version "7.15.6" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.6.tgz#0f3898db9d63d320f21b17380d8462779de57659" integrity sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw== @@ -1530,10 +1530,10 @@ dependencies: tslib "~2.3.0" -"@graphql-ts/schema@0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@graphql-ts/schema/-/schema-0.3.0.tgz#c01ce625c2a5c2f150348bdd50edbfc69b81d747" - integrity sha512-lwhxm6bmD7gTSgg3u+OzMVD0RoBeDf3G8/iTxI9EK0eIUHXdJNhaYiJcvsJDpbuSY6naficziBk8pgQU5X1Egg== +"@graphql-ts/schema@0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@graphql-ts/schema/-/schema-0.3.1.tgz#d98eefce24212c20808a43338ce014ebae1ca6d7" + integrity sha512-sPK1dXo0HEk4+DkMm9eE1MeylcDxtjK/sAKJJ4FJbYKK5F0gew7ohszVfgidVwk1nrjcT2/SWncdwM3plBX28g== dependencies: "@babel/runtime" "^7.9.2" @@ -1976,10 +1976,10 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.1.tgz#728ecd95ab207aab8a9a4e421f0422db329232be" integrity sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw== -"@preconstruct/cli@2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@preconstruct/cli/-/cli-2.1.1.tgz#3c43c5e730b58010b0a15b280b385395145e8090" - integrity sha512-RTKDx/fmRGt8G2OlbFN/J37Bq49LXbEDCdMTypUWrRC3uj/fcrKaDjKSjXl/oos0youkZoB31M+t5ZjJsZhY1w== +"@preconstruct/cli@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@preconstruct/cli/-/cli-2.1.3.tgz#5e10f012e6962b22ea972ef136211680b9cdd67b" + integrity sha512-uKA/XEs156fyZhCz+FCjBU7nFHFIybLV7SMmtKrHioqs+Eac8TPFNetWAeGRB96dRTvIpqezE/UPr916X85ufw== dependencies: "@babel/code-frame" "^7.5.5" "@babel/core" "^7.7.7" @@ -2994,7 +2994,7 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/redis@^2.8.31": +"@types/redis@^2.8.32": version "2.8.32" resolved "https://registry.yarnpkg.com/@types/redis/-/redis-2.8.32.tgz#1d3430219afbee10f8cfa389dad2571a05ecfb11" integrity sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w== @@ -3140,7 +3140,7 @@ resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== -"@typescript-eslint/eslint-plugin@^4.31.0": +"@typescript-eslint/eslint-plugin@^4.31.1": version "4.31.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.31.1.tgz#e938603a136f01dcabeece069da5fb2e331d4498" integrity sha512-UDqhWmd5i0TvPLmbK5xY3UZB0zEGseF+DHPghZ37Sb83Qd3p8ujhvAtkU4OF46Ka5Pm5kWvFIx0cCTBFKo0alA== @@ -3165,7 +3165,7 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/parser@^4.31.0": +"@typescript-eslint/parser@^4.31.1": version "4.31.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.31.1.tgz#8f9a2672033e6f6d33b1c0260eebdc0ddf539064" integrity sha512-dnVZDB6FhpIby6yVbHkwTKkn2ypjVIfAR9nh+kYsA/ZL0JlTsd22BiDjouotisY3Irmd3OW1qlk9EI5R8GrvRQ== @@ -6562,7 +6562,7 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fp-ts@^2.11.1: +fp-ts@^2.11.2: version "2.11.2" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.11.2.tgz#a3f5f74ac56f16c412044470a5fe3b51b94816dc" integrity sha512-G1rD89nmbbgTNRBKohjB3Qv4IxOHQ5KV3ZvYfpaQZyrGt+ZQUFrcnCqE567bcEdvwoAUKDQM7isOcv7xcM/qAQ== @@ -9656,7 +9656,7 @@ next-compose-plugins@^2.2.1: resolved "https://registry.yarnpkg.com/next-compose-plugins/-/next-compose-plugins-2.2.1.tgz#020fc53f275a7e719d62521bef4300fbb6fde5ab" integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg== -next-sitemap@^1.6.164: +next-sitemap@^1.6.168: version "1.6.168" resolved "https://registry.yarnpkg.com/next-sitemap/-/next-sitemap-1.6.168.tgz#5d184b7713edf03c16e6d9064c9a00b2339ec78c" integrity sha512-zzveI/1tjyvdTHd9qoxzH1JyK+wNqW3L+AxHf7Ppa7FbmcLb9Gj30b2pBLTK9wSiRVuSYAjOGxsPliL+daxspQ== @@ -11842,7 +11842,7 @@ source-map-resolve@^0.6.0: atob "^2.1.2" decode-uri-component "^0.2.0" -source-map-support@^0.5.16, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@^0.5.16, source-map-support@^0.5.20, source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.20" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== @@ -12914,7 +12914,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.4.2: +typescript@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== From 80cd313033b339d90b5e640b252a357a4d60fbcd Mon Sep 17 00:00:00 2001 From: Gautam Singh <5769869+gautamsi@users.noreply.github.com> Date: Wed, 15 Sep 2021 04:10:15 +0530 Subject: [PATCH 049/135] fix windows build issue (#6530) --- .changeset/strange-pianos-raise.md | 5 +++++ packages/keystone/src/scripts/build/build.ts | 17 ++--------------- 2 files changed, 7 insertions(+), 15 deletions(-) create mode 100644 .changeset/strange-pianos-raise.md diff --git a/.changeset/strange-pianos-raise.md b/.changeset/strange-pianos-raise.md new file mode 100644 index 00000000000..67cd194f3a3 --- /dev/null +++ b/.changeset/strange-pianos-raise.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed remaining windows issue where it creates invalid import path. This removes some duplicate code which caused this. diff --git a/packages/keystone/src/scripts/build/build.ts b/packages/keystone/src/scripts/build/build.ts index e570ea8b8de..80dc03e7141 100644 --- a/packages/keystone/src/scripts/build/build.ts +++ b/packages/keystone/src/scripts/build/build.ts @@ -1,5 +1,4 @@ import Path from 'path'; -import prettier from 'prettier'; import fs from 'fs-extra'; import { AdminFileToWrite } from '../../types'; import { buildAdminUI, generateAdminUI } from '../../admin-ui/system'; @@ -8,6 +7,8 @@ import { initConfig } from '../../lib/config/initConfig'; import { requireSource } from '../../lib/config/requireSource'; import { generateNodeModulesArtifacts, validateCommittedArtifacts } from '../../artifacts'; import { getAdminPath, getConfigPath } from '../utils'; +import { serializePathForImport } from '../../admin-ui/utils/serializePathForImport'; +import { formatSource } from '../../admin-ui/system/generateAdminUI'; // FIXME: Duplicated from admin-ui package. Need to decide on a common home. async function writeAdminFile(file: AdminFileToWrite, projectAdminPath: string) { @@ -27,20 +28,6 @@ async function writeAdminFile(file: AdminFileToWrite, projectAdminPath: string) } } -// FIXME: Duplicated from admin-ui package. Need to decide on a common home. -export function serializePathForImport(path: string) { - // JSON.stringify is important here because it will escape windows style paths(and any thing else that might potentionally be in there) - return JSON.stringify( - path - // Next is unhappy about imports that include .ts/tsx in them because TypeScript is unhappy with them becasue when doing a TypeScript compilation with tsc, the imports won't be written so they would be wrong there - .replace(/\.tsx?$/, '') - ); -} - -// FIXME: Duplicated from admin-ui package. Need to decide on a common home. -export const formatSource = (src: string, parser: 'babel' | 'babel-ts' = 'babel') => - prettier.format(src, { parser, trailingComma: 'es5', singleQuote: true }); - const reexportKeystoneConfig = async (cwd: string, isDisabled?: boolean) => { const projectAdminPath = getAdminPath(cwd); const configPath = getConfigPath(cwd); From a76d33d845e6f1abd84aec4458c21960917fddfa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Sep 2021 23:18:25 +0000 Subject: [PATCH 050/135] Update dependency chalk-cli to v5 (#6558) Co-authored-by: Renovate Bot --- package.json | 2 +- yarn.lock | 231 +++++++++++++++++++++++++-------------------------- 2 files changed, 114 insertions(+), 119 deletions(-) diff --git a/package.json b/package.json index 3f4571d26f0..0b81ad10df7 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "@types/node-fetch": "^2.5.12", "@typescript-eslint/eslint-plugin": "^4.31.1", "@typescript-eslint/parser": "^4.31.1", - "chalk-cli": "^4.1.0", + "chalk-cli": "^5.0.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", "eslint-plugin-cypress": "^2.11.3", diff --git a/yarn.lock b/yarn.lock index eb5f11ad7a0..76c5aa83632 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2874,7 +2874,7 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== -"@types/minimist@^1.2.0": +"@types/minimist@^1.2.0", "@types/minimist@^1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== @@ -3362,7 +3362,7 @@ ansi-styles@^2.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= -ansi-styles@^3.1.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -3381,6 +3381,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" + integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== + any-observable@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/any-observable/-/any-observable-0.3.0.tgz#af933475e5806a67d0d7df090dd5e8bef65d119b" @@ -3601,11 +3606,6 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/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.yarnpkg.com/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.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -4307,15 +4307,6 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -4325,7 +4316,17 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^4.0.0, camelcase@^4.1.0: +camelcase-keys@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-7.0.0.tgz#40fcbe171f7432888369d0c871df7cfa5ce4f788" + integrity sha512-qlQlECgDl5Ev+gkvONaiD4X4TF2gyZKuLBvzx0zLo2UwAxmz3hJP/841aaMHTeH1T7v5HRwoRq91daulXoYWvg== + dependencies: + camelcase "^6.2.0" + map-obj "^4.1.0" + quick-lru "^5.1.1" + type-fest "^1.2.1" + +camelcase@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= @@ -4355,16 +4356,16 @@ ccount@^1.0.0: resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== -chalk-cli@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk-cli/-/chalk-cli-4.1.0.tgz#c4ddf4f1dcd2d80bf1b501d785cdc3ede57922a2" - integrity sha512-Nsi7JmzX6R8NnUHJGgbLw53je9PpMG3OHYPlyYTY4KcZNFCyOOXXCjd0EH99mwH8ZCnyAU573uWaOiPTT3gJpg== +chalk-cli@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/chalk-cli/-/chalk-cli-5.0.0.tgz#5cf12a63cf44f81910d720f5a8259bd6c372c8a5" + integrity sha512-b0TQHOxLsDYV1u00VLsQU+LHxvn7zHpF3YBdbDq6sCfMFEckE0dySV6i8V4U8m2X+aKRX+olpUv424Cq1WcCRQ== dependencies: - ansi-styles "^3.1.0" - chalk "^2.0.0" - dot-prop "^3.0.0" - get-stdin "^6.0.0" - meow "^5.0.0" + ansi-styles "^6.1.0" + chalk "^4.1.2" + dot-prop "^6.0.1" + get-stdin "^9.0.0" + meow "^10.1.1" chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" @@ -5169,13 +5170,6 @@ cuid@^2.1.8: resolved "https://registry.yarnpkg.com/cuid/-/cuid-2.1.8.tgz#cbb88f954171e0d5747606c0139fb65c5101eac0" integrity sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg== -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - cypress@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/cypress/-/cypress-5.6.0.tgz#6781755c3ddfd644ce3179fcd7389176c0c82280" @@ -5282,7 +5276,7 @@ debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: +decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= @@ -5295,6 +5289,11 @@ decamelize@^1.1.0, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decamelize@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.0.tgz#88358157b010ef133febfd27c18994bd80c6215b" + integrity sha512-U75DcT5hrio3KNtvdULAWnLiAPbFUC4191ldxMmj4FA/mRuBnmDwU0boNfPyFRhnan+Jm+haLeSn3P0afcBn4w== + decimal.js@10.3.1, decimal.js@^10.2.1: version "10.3.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" @@ -5552,12 +5551,12 @@ domutils@^1.7.0: dom-serializer "0" domelementtype "1" -dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" - integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc= +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== dependencies: - is-obj "^1.0.0" + is-obj "^2.0.0" dotenv@10.0.0, dotenv@^10.0.0: version "10.0.0" @@ -6711,10 +6710,10 @@ get-package-type@^0.1.0: resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== +get-stdin@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" + integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== get-stream@6.0.1, get-stream@^6.0.0: version "6.0.1" @@ -7351,6 +7350,11 @@ indent-string@^3.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== + inflection@^1.13.1: version "1.13.1" resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.13.1.tgz#c5cadd80888a90cf84c2e96e340d7edc85d5f0cb" @@ -7743,10 +7747,10 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== is-object@^1.0.1: version "1.0.2" @@ -8883,14 +8887,6 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/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, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -8952,12 +8948,7 @@ map-obj@^1.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - -map-obj@^4.0.0: +map-obj@^4.0.0, map-obj@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== @@ -9208,20 +9199,23 @@ memoize-one@^5.0.0, memoize-one@^5.2.1: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -meow@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" +meow@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-10.1.1.tgz#87fa665f18e727024116d456e725f69033ca6d8f" + integrity sha512-uzOAEBTGujHAD6bVzIQQk5kDTgatxmpVmr1pj9QhwsHLEG2AiB+9F08/wmjrZIk4h5pWxERd7+jqGZywYx3ZFw== + dependencies: + "@types/minimist" "^1.2.2" + camelcase-keys "^7.0.0" + decamelize "^5.0.0" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.2" + read-pkg-up "^8.0.0" + redent "^4.0.0" + trim-newlines "^4.0.2" + type-fest "^1.2.2" + yargs-parser "^20.2.9" meow@^6.0.0: version "6.1.1" @@ -9485,7 +9479,7 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -min-indent@^1.0.0: +min-indent@^1.0.0, min-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== @@ -9516,14 +9510,6 @@ minimist-options@4.1.0, minimist-options@^4.0.2: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - minimist@^1.2.0, minimist@^1.2.5, minimist@~1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" @@ -9787,7 +9773,7 @@ nodemailer@^6.6.3: resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.3.tgz#31fb53dd4d8ae16fc088a65cb9ffa8d928a69b48" integrity sha512-faZFufgTMrphYoDjvyVpbpJcYzwyFnbAMmQtj1lVBYAUSm3SOy2fIdd9+Mr4UxPosBa0JRw9bJoIwQn+nswiew== -normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: +normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -9797,7 +9783,7 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0: +normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== @@ -10278,7 +10264,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0, parse-json@^5.1.0: +parse-json@^5.0.0, parse-json@^5.1.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -10741,11 +10727,6 @@ queue@6.0.2: dependencies: inherits "~2.0.3" -quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - quick-lru@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" @@ -10980,6 +10961,15 @@ read-pkg-up@^3.0.0: find-up "^2.0.0" read-pkg "^3.0.0" +read-pkg-up@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-8.0.0.tgz#72f595b65e66110f43b052dd9af4de6b10534670" + integrity sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ== + dependencies: + find-up "^5.0.0" + read-pkg "^6.0.0" + type-fest "^1.0.1" + read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -10999,6 +10989,16 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" +read-pkg@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-6.0.0.tgz#a67a7d6a1c2b0c3cd6aa2ea521f40c458a4a504c" + integrity sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^3.0.2" + parse-json "^5.2.0" + type-fest "^1.0.1" + read-yaml-file@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-yaml-file/-/read-yaml-file-1.1.0.tgz#9362bbcbdc77007cc8ea4519fe1c0b821a7ce0d8" @@ -11057,14 +11057,6 @@ readdirp@~3.5.0: dependencies: picomatch "^2.2.1" -redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -11073,6 +11065,14 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" +redent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-4.0.0.tgz#0c0ba7caabb24257ab3bb7a4fd95dd1d5c5681f9" + integrity sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag== + dependencies: + indent-string "^5.0.0" + strip-indent "^4.0.0" + redis-commands@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" @@ -12228,10 +12228,12 @@ strip-indent@3.0.0, strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= +strip-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-4.0.0.tgz#b41379433dd06f5eae805e21d631e07ee670d853" + integrity sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA== + dependencies: + min-indent "^1.0.1" strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" @@ -12720,16 +12722,16 @@ treekill@^1.0.0: resolved "https://registry.yarnpkg.com/treekill/-/treekill-1.0.0.tgz#c81539410e8589944614f1641cdd65dc57551517" integrity sha1-yBU5QQ6FiZRGFPFkHN1l3FdVFRc= -trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== +trim-newlines@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-4.0.2.tgz#d6aaaf6a0df1b4b536d183879a6b939489808c7c" + integrity sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew== + trim-repeated@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" @@ -12889,7 +12891,7 @@ type-fest@^0.8.0, type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^1.0.2: +type-fest@^1.0.1, type-fest@^1.0.2, type-fest@^1.2.1, type-fest@^1.2.2: version "1.4.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA== @@ -13724,13 +13726,6 @@ yaml@^1.10.0, yaml@^1.7.2: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - yargs-parser@^18.1.2, yargs-parser@^18.1.3: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -13739,7 +13734,7 @@ yargs-parser@^18.1.2, yargs-parser@^18.1.3: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2, yargs-parser@^20.2.3: +yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== From a316eb3b5898edd9250fc88ac15ad91d41ff767d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 14 Sep 2021 23:26:47 +0000 Subject: [PATCH 051/135] Update dependency eslint-plugin-cypress to ^2.12.1 (#6557) Co-authored-by: Renovate Bot --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0b81ad10df7..7e3fcb43c3d 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "chalk-cli": "^5.0.0", "cross-env": "^7.0.3", "eslint": "^7.32.0", - "eslint-plugin-cypress": "^2.11.3", + "eslint-plugin-cypress": "^2.12.1", "eslint-plugin-import": "^2.24.2", "eslint-plugin-jest": "^24.4.0", "eslint-plugin-react": "^7.25.1", diff --git a/yarn.lock b/yarn.lock index 76c5aa83632..5f19790763b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5780,10 +5780,10 @@ eslint-module-utils@^2.6.2: debug "^3.2.7" pkg-dir "^2.0.0" -eslint-plugin-cypress@^2.11.3: - version "2.11.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.11.3.tgz#54ee4067aa8192aa62810cd35080eb577e191ab7" - integrity sha512-hOoAid+XNFtpvOzZSNWP5LDrQBEJwbZwjib4XJ1KcRYKjeVj0mAmPmucG4Egli4j/aruv+Ow/acacoloWWCl9Q== +eslint-plugin-cypress@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz#9aeee700708ca8c058e00cdafe215199918c2632" + integrity sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA== dependencies: globals "^11.12.0" From 499c00b44b4b378285ed21a385da799b4af0af82 Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Wed, 15 Sep 2021 11:51:04 +1000 Subject: [PATCH 052/135] Remove dependency on `typescript` (#6559) --- .changeset/eighty-llamas-scream.md | 5 +++++ packages/keystone/package.json | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .changeset/eighty-llamas-scream.md diff --git a/.changeset/eighty-llamas-scream.md b/.changeset/eighty-llamas-scream.md new file mode 100644 index 00000000000..1aa2ae655b6 --- /dev/null +++ b/.changeset/eighty-llamas-scream.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Removed unnecessary dependency on `typescript` diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 783210bebf5..717eebaa6f8 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -118,7 +118,6 @@ "resolve": "^1.20.0", "source-map-support": "^0.5.20", "supertest": "^6.1.6", - "typescript": "^4.4.3", "uid-safe": "^2.1.5", "uuid": "^8.3.2" }, From 543b5e24a156c234cbc1a9202a6f0ded9e27d747 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 15 Sep 2021 12:20:33 +1000 Subject: [PATCH 053/135] Update patch dependencies (patch) (#6555) --- design-system/packages/button/package.json | 2 +- design-system/packages/core/package.json | 2 +- design-system/packages/fields/package.json | 2 +- design-system/packages/icons/package.json | 2 +- design-system/packages/loading/package.json | 2 +- design-system/packages/modals/package.json | 2 +- design-system/packages/notice/package.json | 2 +- .../packages/segmented-control/package.json | 2 +- design-system/packages/toast/package.json | 2 +- design-system/website/package.json | 2 +- docs/package.json | 2 +- examples-staging/basic/package.json | 2 +- package.json | 2 +- packages/cloudinary/package.json | 2 +- packages/fields-document/package.json | 2 +- packages/keystone/package.json | 10 +-- prisma-utils/package.json | 4 +- tests/api-tests/utils.ts | 2 +- yarn.lock | 86 +++++++++---------- 19 files changed, 66 insertions(+), 66 deletions(-) diff --git a/design-system/packages/button/package.json b/design-system/packages/button/package.json index 38d5c775623..fd2e8cc0e88 100644 --- a/design-system/packages/button/package.json +++ b/design-system/packages/button/package.json @@ -5,7 +5,7 @@ "main": "dist/button.cjs.js", "module": "dist/button.esm.js", "devDependencies": { - "@types/react": "^17.0.20" + "@types/react": "^17.0.21" }, "dependencies": { "@babel/runtime": "^7.15.4", diff --git a/design-system/packages/core/package.json b/design-system/packages/core/package.json index 367b7199f9e..637f7365737 100644 --- a/design-system/packages/core/package.json +++ b/design-system/packages/core/package.json @@ -5,7 +5,7 @@ "main": "dist/core.cjs.js", "module": "dist/core.esm.js", "devDependencies": { - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/design-system/packages/fields/package.json b/design-system/packages/fields/package.json index 515a9254123..e70db7eb169 100644 --- a/design-system/packages/fields/package.json +++ b/design-system/packages/fields/package.json @@ -5,7 +5,7 @@ "main": "dist/fields.cjs.js", "module": "dist/fields.esm.js", "devDependencies": { - "@types/react": "^17.0.20" + "@types/react": "^17.0.21" }, "dependencies": { "@babel/runtime": "^7.15.4", diff --git a/design-system/packages/icons/package.json b/design-system/packages/icons/package.json index cba5085783b..dc013a2c5c0 100644 --- a/design-system/packages/icons/package.json +++ b/design-system/packages/icons/package.json @@ -12,7 +12,7 @@ "@svgr/plugin-jsx": "^5.5.0", "@svgr/plugin-prettier": "^5.5.0", "@svgr/plugin-svgo": "^5.5.0", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "chalk": "^4.1.2", "feather-icons": "^4.28.0", "fs-extra": "^10.0.0", diff --git a/design-system/packages/loading/package.json b/design-system/packages/loading/package.json index 0beb4c08f3f..9073c864718 100644 --- a/design-system/packages/loading/package.json +++ b/design-system/packages/loading/package.json @@ -5,7 +5,7 @@ "main": "dist/loading.cjs.js", "module": "dist/loading.esm.js", "devDependencies": { - "@types/react": "^17.0.20" + "@types/react": "^17.0.21" }, "dependencies": { "@babel/runtime": "^7.15.4", diff --git a/design-system/packages/modals/package.json b/design-system/packages/modals/package.json index 171e8469a9d..bfb1a72ffcd 100644 --- a/design-system/packages/modals/package.json +++ b/design-system/packages/modals/package.json @@ -5,7 +5,7 @@ "main": "dist/modals.cjs.js", "module": "dist/modals.esm.js", "devDependencies": { - "@types/react": "^17.0.20" + "@types/react": "^17.0.21" }, "dependencies": { "@babel/runtime": "^7.15.4", diff --git a/design-system/packages/notice/package.json b/design-system/packages/notice/package.json index 17334882e84..961fc0ae86e 100644 --- a/design-system/packages/notice/package.json +++ b/design-system/packages/notice/package.json @@ -5,7 +5,7 @@ "main": "dist/notice.cjs.js", "module": "dist/notice.esm.js", "devDependencies": { - "@types/react": "^17.0.20" + "@types/react": "^17.0.21" }, "dependencies": { "@babel/runtime": "^7.15.4", diff --git a/design-system/packages/segmented-control/package.json b/design-system/packages/segmented-control/package.json index 39d92a82572..fdcfe5b5600 100644 --- a/design-system/packages/segmented-control/package.json +++ b/design-system/packages/segmented-control/package.json @@ -5,7 +5,7 @@ "main": "dist/segmented-control.cjs.js", "module": "dist/segmented-control.esm.js", "devDependencies": { - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "react": "^17.0.2" }, "dependencies": { diff --git a/design-system/packages/toast/package.json b/design-system/packages/toast/package.json index 4a9b516c4ab..6b39d193859 100644 --- a/design-system/packages/toast/package.json +++ b/design-system/packages/toast/package.json @@ -5,7 +5,7 @@ "main": "dist/toast.cjs.js", "module": "dist/toast.esm.js", "devDependencies": { - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "react": "^17.0.2" }, "dependencies": { diff --git a/design-system/website/package.json b/design-system/website/package.json index d69c7d77984..284ba0136ca 100644 --- a/design-system/website/package.json +++ b/design-system/website/package.json @@ -21,7 +21,7 @@ "@keystone-ui/toast": "^4.0.3", "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "@types/react-dom": "^17.0.9", "@types/tinycolor2": "^1.4.3", "next": "^11.1.0", diff --git a/docs/package.json b/docs/package.json index 390effaa4db..3224f634652 100644 --- a/docs/package.json +++ b/docs/package.json @@ -26,7 +26,7 @@ "@sindresorhus/slugify": "^1.1.2", "@types/gtag.js": "^0.0.7", "@types/mdx-js__react": "^1.5.4", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "@types/react-dom": "^17.0.9", "classnames": "^2.3.1", "copy-to-clipboard": "^3.3.1", diff --git a/examples-staging/basic/package.json b/examples-staging/basic/package.json index d7a71df6ead..7a5ff545b25 100644 --- a/examples-staging/basic/package.json +++ b/examples-staging/basic/package.json @@ -19,7 +19,7 @@ "@keystone-ui/icons": "^4.0.1", "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "graphql": "^15.5.3", "graphql-tag": "^2.12.5", "next": "^11.1.0", diff --git a/package.json b/package.json index 7e3fcb43c3d..7d2e2b74ebc 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@changesets/cli": "^2.17.0", "@jest/test-sequencer": "^27.2.0", "@manypkg/cli": "^0.18.0", - "@preconstruct/cli": "2.1.3", + "@preconstruct/cli": "2.1.4", "@preconstruct/eslint-plugin-format-js-tag": "^0.1.0", "@testing-library/jest-dom": "^5.14.1", "@types/jest": "^27.0.1", diff --git a/packages/cloudinary/package.json b/packages/cloudinary/package.json index f2e26005a8f..ef70b7ffa42 100644 --- a/packages/cloudinary/package.json +++ b/packages/cloudinary/package.json @@ -10,7 +10,7 @@ "@keystone-ui/core": "^3.2.0", "@keystone-ui/fields": "^4.1.3", "@keystone-ui/pill": "^5.0.1", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "cloudinary": "^1.27.0", "cuid": "^2.1.8", "graphql-upload": "^12.0.0", diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index 60e826ebaec..bf26a4dbd65 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -29,7 +29,7 @@ "@keystone-ui/icons": "^4.0.1", "@keystone-ui/popover": "^4.0.3", "@keystone-ui/tooltip": "^4.0.2", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "apply-ref": "^1.0.0", "fp-ts": "^2.11.2", "graphql": "^15.5.3", diff --git a/packages/keystone/package.json b/packages/keystone/package.json index 717eebaa6f8..1ae4ba7e3c1 100644 --- a/packages/keystone/package.json +++ b/packages/keystone/package.json @@ -49,9 +49,9 @@ "@keystone-ui/toast": "^4.0.3", "@keystone-ui/tooltip": "^4.0.2", "@preconstruct/next": "^3.0.0", - "@prisma/client": "2.30.2", - "@prisma/migrate": "2.30.2", - "@prisma/sdk": "2.30.2", + "@prisma/client": "2.30.3", + "@prisma/migrate": "2.30.3", + "@prisma/sdk": "2.30.3", "@sindresorhus/slugify": "^1.1.2", "@types/apollo-upload-client": "14.1.0", "@types/babel__core": "^7.1.16", @@ -66,7 +66,7 @@ "@types/pluralize": "^0.0.29", "@types/prettier": "^2.3.2", "@types/prompts": "^2.0.14", - "@types/react": "^17.0.20", + "@types/react": "^17.0.21", "@types/source-map-support": "^0.5.4", "@types/supertest": "^2.0.11", "@types/uid-safe": "^2.1.2", @@ -111,7 +111,7 @@ "pirates": "^4.0.1", "pluralize": "^8.0.0", "prettier": "^2.4.0", - "prisma": "2.30.2", + "prisma": "2.30.3", "prompts": "^2.4.1", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/prisma-utils/package.json b/prisma-utils/package.json index fa1877b968e..51b6a65cce6 100644 --- a/prisma-utils/package.json +++ b/prisma-utils/package.json @@ -4,8 +4,8 @@ "private": true, "main": "dist/prisma-utils.cjs.js", "dependencies": { - "@prisma/generator-helper": "2.30.2", - "@prisma/sdk": "2.30.2", + "@prisma/generator-helper": "2.30.3", + "@prisma/sdk": "2.30.3", "fs-extra": "^10.0.0", "prettier": "^2.4.0" }, diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 49f80b807db..4e1741983db 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -156,7 +156,7 @@ export const expectPrismaError = ( args.map(({ path, message, code, target }) => ({ extensions: { code: 'INTERNAL_SERVER_ERROR', - prisma: { clientVersion: '2.30.2', code, meta: { target } }, + prisma: { clientVersion: '2.30.3', code, meta: { target } }, }, path, message, diff --git a/yarn.lock b/yarn.lock index 5f19790763b..1c71700e978 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1976,10 +1976,10 @@ resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.1.tgz#728ecd95ab207aab8a9a4e421f0422db329232be" integrity sha512-HnUhk1Sy9IuKrxEMdIRCxpIqPw6BFsbYSEUO9p/hNw5sMld/+3OLMWQP80F8/db9qsv3qUjs7ZR5bS/R+iinXw== -"@preconstruct/cli@2.1.3": - version "2.1.3" - resolved "https://registry.yarnpkg.com/@preconstruct/cli/-/cli-2.1.3.tgz#5e10f012e6962b22ea972ef136211680b9cdd67b" - integrity sha512-uKA/XEs156fyZhCz+FCjBU7nFHFIybLV7SMmtKrHioqs+Eac8TPFNetWAeGRB96dRTvIpqezE/UPr916X85ufw== +"@preconstruct/cli@2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@preconstruct/cli/-/cli-2.1.4.tgz#246bfe307490f29a537dd4b0092286787884a879" + integrity sha512-7sJ2O6qYiEqXtl3s7ik9Tw1iYNTapnfbLlmsy/stF8temoMZWsezU3tpVvGWeGfDo1OA2HT1QSl5AneRx2wq4Q== dependencies: "@babel/code-frame" "^7.5.5" "@babel/core" "^7.7.7" @@ -2041,10 +2041,10 @@ resolved "https://registry.yarnpkg.com/@preconstruct/next/-/next-3.0.0.tgz#71781cbaecd011f43e456a149817094a43e4755f" integrity sha512-G90cyJX9w4Zr3Bt/j2fURgDhsJb5+agqf4YUgrvDe3Dyvbbssy9a6d0tzLH0ehfa2Osxw/EEhQb+W4X+v/x06A== -"@prisma/client@2.30.2": - version "2.30.2" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.30.2.tgz#4e7f90f27a176d95769609e65932a4b95aa8da3f" - integrity sha512-cfS/1UWBRE4sq0z7spGLYqOE0oN2YJJvKtm+63o7h/BI6ji10VWla79aXBTXj3AImtfykNtC6OHtFVawEl/49w== +"@prisma/client@2.30.3": + version "2.30.3" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-2.30.3.tgz#49c1015e2cec26a44b20c62eb2fd738cb0bb043b" + integrity sha512-Ey2miZ+Hne12We3rA8XrlPoAF0iuKEhw5IK2nropaelSt0Ju3b2qSz9Qt50a/1Mx3+7yRSu/iSXt8y9TUMl/Yw== dependencies: "@prisma/engines-version" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" @@ -2057,23 +2057,23 @@ debug "4.3.2" ms "2.1.3" -"@prisma/debug@2.30.2": - version "2.30.2" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-2.30.2.tgz#603b9ec41d04fa82f683e60264e277adbfac54ed" - integrity sha512-QFUTRPfFhZ6oryH5KsEaBeBMpFsx16zBWwlBBPkGhfiLRL8eo9vxm4+EVKzKob5PAmrfJCJ7DQvb/k6rdSXdxg== +"@prisma/debug@2.30.3": + version "2.30.3" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-2.30.3.tgz#2c10a4aa4c99728d0f13d64036eca9521352b0d4" + integrity sha512-hMsCl6ZA718vgKuTRd1+qeetzGSVkZEIEUTfeT5rPtklgqDytQ01nRNN74gLeoSI64tyGg/pvSX1wgAioMuyiQ== dependencies: "@types/debug" "4.1.7" debug "4.3.2" ms "2.1.3" -"@prisma/engine-core@2.30.2": - version "2.30.2" - resolved "https://registry.yarnpkg.com/@prisma/engine-core/-/engine-core-2.30.2.tgz#ad991c2dc9532e50550eba3314d7ba858a50ca19" - integrity sha512-oDMVIvv5hz/kepNypr6X8yIcOxK0XgJhA8X7grO5hSznPZA+yj64xuYnIPLD0xN9+6u777k8tv4/fMCBSjsjag== +"@prisma/engine-core@2.30.3": + version "2.30.3" + resolved "https://registry.yarnpkg.com/@prisma/engine-core/-/engine-core-2.30.3.tgz#ec0675cdb0ee25e27fd771fd90b998616ac2dc1f" + integrity sha512-5wVfwRiEgCHgd6/V7ZaegsBT5lJ/RuF/vRgFKKEqVfeGvSQAkm3GtuvhDdIcjovJPazfQciJM8zaG8Pu3bdgWw== dependencies: - "@prisma/debug" "2.30.2" + "@prisma/debug" "2.30.3" "@prisma/engines" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" - "@prisma/generator-helper" "2.30.2" + "@prisma/generator-helper" "2.30.3" "@prisma/get-platform" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" chalk "4.1.2" execa "5.1.1" @@ -2117,12 +2117,12 @@ temp-dir "^2.0.0" tempy "^1.0.0" -"@prisma/generator-helper@2.30.2": - version "2.30.2" - resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-2.30.2.tgz#0b0a5480a481dd300e93d6dfec62450ed67b4107" - integrity sha512-9iCBIlG+XwagakXV9MU+TTbTB+72iCFcoQwqx4kuhvnZnrPiFppuM6XXDW2EteBIY2G4oCkasMFOC68NQPbfbg== +"@prisma/generator-helper@2.30.3": + version "2.30.3" + resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-2.30.3.tgz#bf0405d1ff9a4d34776c0b76c1565638f4a4c55e" + integrity sha512-HM43m9RHlDzC8yZJaPIDDfPChiXGC4l3oH85Esxn2F/bVvP60VSpXC+EHHzBRhexDpNgpRNQBHqQJoxbo+O/1Q== dependencies: - "@prisma/debug" "2.30.2" + "@prisma/debug" "2.30.3" "@types/cross-spawn" "6.0.2" chalk "4.1.2" cross-spawn "7.0.3" @@ -2134,12 +2134,12 @@ dependencies: "@prisma/debug" "2.30.0" -"@prisma/migrate@2.30.2": - version "2.30.2" - resolved "https://registry.yarnpkg.com/@prisma/migrate/-/migrate-2.30.2.tgz#8b1b519ba906060d3ef7fa26388b91159c4d45e1" - integrity sha512-nutHBQtnxyJgej84cSgzkNpaG5hwGw4IG3Z2ugLm0d2pIjPyoYggLGOd+IA+CkGZpaekqfwccFtPZFgKN5vuyg== +"@prisma/migrate@2.30.3": + version "2.30.3" + resolved "https://registry.yarnpkg.com/@prisma/migrate/-/migrate-2.30.3.tgz#8a3c29834234d4582916ac353e556dc6b6d82013" + integrity sha512-Sooj6kgtor+4nrCBkmvIgHDoFZ625rnD0Tk97EwCjfDubOD36ZHMVQ2xktuW8mmhCvhnmmz9hpHy87WsIANVLA== dependencies: - "@prisma/debug" "2.30.2" + "@prisma/debug" "2.30.3" "@prisma/get-platform" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" "@sindresorhus/slugify" "1.1.2" execa "5.1.1" @@ -2155,16 +2155,16 @@ strip-ansi "6.0.0" strip-indent "3.0.0" -"@prisma/sdk@2.30.2": - version "2.30.2" - resolved "https://registry.yarnpkg.com/@prisma/sdk/-/sdk-2.30.2.tgz#dc76f419628d5eeba902249f2e12e7370b78d221" - integrity sha512-FVVAh5bYCyRK9CLpGQ6XOY3wGp0wgjtNj6zaQ96En9kIrSW9CLMW/nQTG7f4OnXAwX1z7fE7LlvLsipnJKssXA== +"@prisma/sdk@2.30.3": + version "2.30.3" + resolved "https://registry.yarnpkg.com/@prisma/sdk/-/sdk-2.30.3.tgz#85d7f8d6b911fb93d239ce825f84d66445bf3ad3" + integrity sha512-+6pIH78gqk1N4ZNn0oP5tXx3hpfySv8kMrKxsu3Cc9l3g/Zw4tk/HauTzWYW2r+fdNwNBzQS/aMoCvrPU+RKXg== dependencies: - "@prisma/debug" "2.30.2" - "@prisma/engine-core" "2.30.2" + "@prisma/debug" "2.30.3" + "@prisma/engine-core" "2.30.3" "@prisma/engines" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" "@prisma/fetch-engine" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" - "@prisma/generator-helper" "2.30.2" + "@prisma/generator-helper" "2.30.3" "@prisma/get-platform" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" "@timsuchanek/copy" "1.4.5" archiver "4.0.2" @@ -2985,10 +2985,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17.0.20": - version "17.0.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.20.tgz#a4284b184d47975c71658cd69e759b6bd37c3b8c" - integrity sha512-wWZrPlihslrPpcKyCSlmIlruakxr57/buQN1RjlIeaaTWDLtJkTtRW429MoQJergvVKc4IWBpRhWw7YNh/7GVA== +"@types/react@*", "@types/react@^17.0.21": + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.21.tgz#069c43177cd419afaab5ce26bb4e9056549f7ea6" + integrity sha512-GzzXCpOthOjXvrAUFQwU/svyxu658cwu00Q9ugujS4qc1zXgLFaO0kS2SLOaMWLt2Jik781yuHCWB7UcYdGAeQ== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -10558,10 +10558,10 @@ prism-react-renderer@^1.2.1: resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.2.1.tgz#392460acf63540960e5e3caa699d851264e99b89" integrity sha512-w23ch4f75V1Tnz8DajsYKvY5lF7H1+WvzvLUcF0paFxkTHSp42RS0H5CttdN2Q8RR3DRGZ9v5xD/h3n8C8kGmg== -prisma@2.30.2: - version "2.30.2" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.30.2.tgz#f65ea0a04ff642e1e393d5b42c804bdcb099a465" - integrity sha512-AoLz3CfD7XM+vfE7IWzxQq1O2+ZZ31+6yfabWeMr32wxdLLxSsGagW80LFgKIsZgWW6Ypwleu5ujyKNvO91WHA== +prisma@2.30.3: + version "2.30.3" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-2.30.3.tgz#e4a770e1f52151e72c1c5be0aa2e75222a0135c4" + integrity sha512-48qYba2BIyUmXuosBZs0g3kYGrxKvo4VkSHYOuLlDdDirmKyvoY2hCYMUYHSx3f++8ovfgs+MX5KmNlP+iAZrQ== dependencies: "@prisma/engines" "2.30.1-2.b8c35d44de987a9691890b3ddf3e2e7effb9bf20" From 53aaf4f4dcf1b8b82f017bee6f9a7dcafef95c5c Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 15 Sep 2021 12:53:09 +1000 Subject: [PATCH 054/135] Simplify fake IDs in tests (#6562) --- .../api-tests/access-control/list-access.test.ts | 15 +++++++-------- tests/api-tests/access-control/utils.ts | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/api-tests/access-control/list-access.test.ts b/tests/api-tests/access-control/list-access.test.ts index a44a383cc8d..5c48f173de1 100644 --- a/tests/api-tests/access-control/list-access.test.ts +++ b/tests/api-tests/access-control/list-access.test.ts @@ -1,5 +1,5 @@ import { GraphQLError } from 'graphql'; -import { DatabaseProvider, KeystoneContext } from '@keystone-next/keystone/types'; +import { KeystoneContext } from '@keystone-next/keystone/types'; import { setupTestEnv, TestEnv } from '@keystone-next/keystone/testing'; import { expectAccessDenied } from '../utils'; import { @@ -37,12 +37,11 @@ const expectNoAccessMany = ( type IdType = any; describe(`List access`, () => { - let testEnv: TestEnv, context: KeystoneContext, provider: DatabaseProvider; + let testEnv: TestEnv, context: KeystoneContext; let items: Record; beforeAll(async () => { testEnv = await setupTestEnv({ config }); context = testEnv.testArgs.context; - provider = config.db.provider!; await testEnv.connect(); @@ -114,14 +113,14 @@ describe(`List access`, () => { listAccessVariations.forEach(access => { test(`single not existing: ${JSON.stringify(access)}`, async () => { const { itemQueryName } = context.gqlNames(nameFn[mode](access)); - const query = `query { ${itemQueryName}(where: { id: "${FAKE_ID[provider]}" }) { id } }`; + const query = `query { ${itemQueryName}(where: { id: "${FAKE_ID}" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); expect(errors).toBe(undefined); expect(data![itemQueryName]).toBe(null); }); test(`multiple not existing: ${JSON.stringify(access)}`, async () => { const _items = await context.lists[nameFn[mode](access)].findMany({ - where: { id: { in: [FAKE_ID[provider], FAKE_ID_2[provider]] } }, + where: { id: { in: [FAKE_ID, FAKE_ID_2] } }, }); expect(_items).toHaveLength(0); }); @@ -247,7 +246,7 @@ describe(`List access`, () => { listAccessVariations.forEach(access => { test(`denies missing: ${JSON.stringify(access)}`, async () => { const updateMutationName = `update${nameFn[mode](access)}`; - const query = `mutation { ${updateMutationName}(where: { id: "${FAKE_ID[provider]}" }, data: { name: "bar" }) { id } }`; + const query = `mutation { ${updateMutationName}(where: { id: "${FAKE_ID}" }, data: { name: "bar" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); expectNoAccess(data, errors, updateMutationName, false); }); @@ -362,13 +361,13 @@ describe(`List access`, () => { listAccessVariations.forEach(access => { test(`single denies missing: ${JSON.stringify(access)}`, async () => { const deleteMutationName = `delete${nameFn[mode](access)}`; - const query = `mutation { ${deleteMutationName}(where: { id: "${FAKE_ID[provider]}" }) { id } }`; + const query = `mutation { ${deleteMutationName}(where: { id: "${FAKE_ID}" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); expectNoAccess(data, errors, deleteMutationName, false); }); test(`multi denies missing: ${JSON.stringify(access)}`, async () => { const multiDeleteMutationName = `delete${nameFn[mode](access)}s`; - const query = `mutation { ${multiDeleteMutationName}(where: [{ id: "${FAKE_ID[provider]}" }, { id: "${FAKE_ID_2[provider]}" }]) { id } }`; + const query = `mutation { ${multiDeleteMutationName}(where: [{ id: "${FAKE_ID}" }, { id: "${FAKE_ID_2}" }]) { id } }`; const { data, errors } = await context.graphql.raw({ query }); expectAccessDenied('dev', false, undefined, errors, [ { path: [multiDeleteMutationName, 0] }, diff --git a/tests/api-tests/access-control/utils.ts b/tests/api-tests/access-control/utils.ts index 77db5080a3e..816a656675b 100644 --- a/tests/api-tests/access-control/utils.ts +++ b/tests/api-tests/access-control/utils.ts @@ -4,8 +4,8 @@ import { statelessSessions } from '@keystone-next/keystone/session'; import { createAuth } from '@keystone-next/auth'; import { apiTestConfig } from '../utils'; -const FAKE_ID = { postgresql: 'cdsfasfafafadfasdf', sqlite: 'cdsfasfafafadfasdf' } as const; -const FAKE_ID_2 = { postgresql: 'csdfbstrsbaf', sqlite: 'csdfbstrsbaf' } as const; +const FAKE_ID = 'cdsfasfafafadfasdf'; +const FAKE_ID_2 = 'csdfbstrsbaf'; const COOKIE_SECRET = 'qwertyuiopasdfghjlkzxcvbmnm1234567890'; const yesNo = (truthy: boolean | undefined) => (truthy ? 'Yes' : 'No'); From 1faddea9d285c70d2d867958bc5ab2bbfb44dbd6 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Wed, 15 Sep 2021 16:02:15 +1000 Subject: [PATCH 055/135] Add userInputError error function (#6565) --- .changeset/gentle-wolves-join.md | 5 +++++ examples-staging/ecommerce/tests/mutations.test.ts | 2 +- .../keystone/src/fields/types/checkbox/index.ts | 5 +++-- packages/keystone/src/fields/types/file/index.ts | 5 +++-- packages/keystone/src/fields/types/image/index.ts | 5 +++-- .../keystone/src/fields/types/password/index.ts | 3 ++- packages/keystone/src/lib/core/graphql-errors.ts | 2 ++ .../nested-mutation-many-input-resolvers.ts | 7 ++++--- .../nested-mutation-one-input-resolvers.ts | 5 +++-- packages/keystone/src/lib/core/queries/resolvers.ts | 6 +++--- packages/keystone/src/lib/core/where-inputs.ts | 9 +++++---- packages/keystone/src/lib/id-field.ts | 13 +++++++------ tests/api-tests/queries/filters.test.ts | 12 ++++++------ .../nested-mutations/connect-many.test.ts | 2 +- .../nested-mutations/connect-singular.test.ts | 2 +- .../create-and-connect-many.test.ts | 2 +- .../create-and-connect-singular.test.ts | 4 ++-- .../relationships/nested-mutations/set-many.test.ts | 2 +- tests/api-tests/utils.ts | 2 +- 19 files changed, 54 insertions(+), 39 deletions(-) create mode 100644 .changeset/gentle-wolves-join.md diff --git a/.changeset/gentle-wolves-join.md b/.changeset/gentle-wolves-join.md new file mode 100644 index 00000000000..9654607ed1b --- /dev/null +++ b/.changeset/gentle-wolves-join.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Updated error messages to indicate user input errors. diff --git a/examples-staging/ecommerce/tests/mutations.test.ts b/examples-staging/ecommerce/tests/mutations.test.ts index f3f425b175d..81579ab3eb4 100644 --- a/examples-staging/ecommerce/tests/mutations.test.ts +++ b/examples-staging/ecommerce/tests/mutations.test.ts @@ -171,7 +171,7 @@ describe(`Custom mutations`, () => { }); expect(data).toEqual({ addToCart: null }); expect(errors).toHaveLength(1); - expect(errors![0].message).toEqual('Only a cuid can be passed to id filters'); + expect(errors![0].message).toEqual('Input error: Only a cuid can be passed to id filters'); }) ); diff --git a/packages/keystone/src/fields/types/checkbox/index.ts b/packages/keystone/src/fields/types/checkbox/index.ts index f835f258db1..15e6528e2b0 100644 --- a/packages/keystone/src/fields/types/checkbox/index.ts +++ b/packages/keystone/src/fields/types/checkbox/index.ts @@ -1,3 +1,4 @@ +import { userInputError } from '../../../lib/core/graphql-errors'; import { BaseGeneratedListTypes, CommonFieldConfig, @@ -50,7 +51,7 @@ export const checkbox = }), resolve(val) { if (val === null) { - throw new Error('checkbox fields cannot be set to null'); + throw userInputError('checkbox fields cannot be set to null'); } return val ?? defaultValue; }, @@ -59,7 +60,7 @@ export const checkbox = arg: graphql.arg({ type: graphql.Boolean }), resolve(val) { if (val === null) { - throw new Error('checkbox fields cannot be set to null'); + throw userInputError('checkbox fields cannot be set to null'); } return val; }, diff --git a/packages/keystone/src/fields/types/file/index.ts b/packages/keystone/src/fields/types/file/index.ts index 7288cce8db4..cfe1f5daba5 100644 --- a/packages/keystone/src/fields/types/file/index.ts +++ b/packages/keystone/src/fields/types/file/index.ts @@ -1,4 +1,5 @@ import { FileUpload } from 'graphql-upload'; +import { userInputError } from '../../../lib/core/graphql-errors'; import { fieldType, graphql, @@ -68,12 +69,12 @@ async function inputResolver(data: FileFieldInputType, context: KeystoneContext) if (data.ref) { if (data.upload) { - throw new Error('Only one of ref and upload can be passed to FileFieldInput'); + throw userInputError('Only one of ref and upload can be passed to FileFieldInput'); } return context.files!.getDataFromRef(data.ref); } if (!data.upload) { - throw new Error('Either ref or upload must be passed to FileFieldInput'); + throw userInputError('Either ref or upload must be passed to FileFieldInput'); } const upload = await data.upload; return context.files!.getDataFromStream(upload.createReadStream(), upload.filename); diff --git a/packages/keystone/src/fields/types/image/index.ts b/packages/keystone/src/fields/types/image/index.ts index f2ecd8559cc..7df02bb1687 100644 --- a/packages/keystone/src/fields/types/image/index.ts +++ b/packages/keystone/src/fields/types/image/index.ts @@ -1,4 +1,5 @@ import { FileUpload } from 'graphql-upload'; +import { userInputError } from '../../../lib/core/graphql-errors'; import { BaseGeneratedListTypes, fieldType, @@ -75,12 +76,12 @@ async function inputResolver(data: ImageFieldInputType, context: KeystoneContext if (data.ref) { if (data.upload) { - throw new Error('Only one of ref and upload can be passed to ImageFieldInput'); + throw userInputError('Only one of ref and upload can be passed to ImageFieldInput'); } return context.images!.getDataFromRef(data.ref); } if (!data.upload) { - throw new Error('Either ref or upload must be passed to ImageFieldInput'); + throw userInputError('Either ref or upload must be passed to ImageFieldInput'); } return context.images!.getDataFromStream((await data.upload).createReadStream()); } diff --git a/packages/keystone/src/fields/types/password/index.ts b/packages/keystone/src/fields/types/password/index.ts index e8d4b6c16ab..501e0326e41 100644 --- a/packages/keystone/src/fields/types/password/index.ts +++ b/packages/keystone/src/fields/types/password/index.ts @@ -1,6 +1,7 @@ import bcryptjs from 'bcryptjs'; // @ts-ignore import dumbPasswords from 'dumb-passwords'; +import { userInputError } from '../../../lib/core/graphql-errors'; import { BaseGeneratedListTypes, FieldDefaultValue, @@ -100,7 +101,7 @@ export const password = arg: graphql.arg({ type: PasswordFilter }), resolve(val) { if (val === null) { - throw new Error('Password filters cannot be set to null'); + throw userInputError('Password filters cannot be set to null'); } if (val.isSet) { return { diff --git a/packages/keystone/src/lib/core/graphql-errors.ts b/packages/keystone/src/lib/core/graphql-errors.ts index 1feaa70ed55..9f4bfa09692 100644 --- a/packages/keystone/src/lib/core/graphql-errors.ts +++ b/packages/keystone/src/lib/core/graphql-errors.ts @@ -1,5 +1,7 @@ import { ApolloError } from 'apollo-server-errors'; +export const userInputError = (msg: string) => new ApolloError(`Input error: ${msg}`); + export const accessDeniedError = () => new ApolloError('You do not have access to this resource'); export const prismaError = (err: Error) => { diff --git a/packages/keystone/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts b/packages/keystone/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts index 11bf9535ef4..8ef6541b040 100644 --- a/packages/keystone/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts +++ b/packages/keystone/src/lib/core/mutations/nested-mutation-many-input-resolvers.ts @@ -2,6 +2,7 @@ import { KeystoneContext, TypesForList, graphql } from '../../../types'; import { resolveUniqueWhereInput, UniqueInputFilter, UniquePrismaFilter } from '../where-inputs'; import { InitialisedList } from '../types-for-lists'; import { isRejected, isFulfilled } from '../utils'; +import { userInputError } from '../graphql-errors'; import { NestedMutationState } from './create-update'; type _CreateValueType = Exclude< @@ -43,7 +44,7 @@ export function resolveRelateToManyForCreateInput( ) { return async (value: _CreateValueType) => { if (!Array.isArray(value.connect) && !Array.isArray(value.create)) { - throw new Error( + throw userInputError( `You must provide at least one field in to-many relationship inputs but none were provided at ${target}` ); } @@ -90,12 +91,12 @@ export function resolveRelateToManyForUpdateInput( !Array.isArray(value.disconnect) && !Array.isArray(value.set) ) { - throw new Error( + throw userInputError( `You must provide at least one field in to-many relationship inputs but none were provided at ${target}` ); } if (value.set && value.disconnect) { - throw new Error( + throw userInputError( `The set and disconnect fields cannot both be provided to to-many relationship inputs but both were provided at ${target}` ); } diff --git a/packages/keystone/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts b/packages/keystone/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts index aad464a354d..aa50410d87f 100644 --- a/packages/keystone/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts +++ b/packages/keystone/src/lib/core/mutations/nested-mutation-one-input-resolvers.ts @@ -1,6 +1,7 @@ import { KeystoneContext, TypesForList, graphql } from '../../../types'; import { resolveUniqueWhereInput } from '../where-inputs'; import { InitialisedList } from '../types-for-lists'; +import { userInputError } from '../graphql-errors'; import { NestedMutationState } from './create-update'; type _CreateValueType = Exclude< @@ -60,7 +61,7 @@ export function resolveRelateToOneForCreateInput( return async (value: _CreateValueType) => { const numOfKeys = Object.keys(value).length; if (numOfKeys !== 1) { - throw new Error( + throw userInputError( `Nested to-one mutations must provide exactly one field if they're provided but ${target} did not` ); } @@ -76,7 +77,7 @@ export function resolveRelateToOneForUpdateInput( ) { return async (value: _UpdateValueType) => { if (Object.keys(value).length !== 1) { - throw new Error( + throw userInputError( `Nested to-one mutations must provide exactly one field if they're provided but ${target} did not` ); } diff --git a/packages/keystone/src/lib/core/queries/resolvers.ts b/packages/keystone/src/lib/core/queries/resolvers.ts index 13cb1b922ed..e40e49205dc 100644 --- a/packages/keystone/src/lib/core/queries/resolvers.ts +++ b/packages/keystone/src/lib/core/queries/resolvers.ts @@ -9,7 +9,7 @@ import { UniqueInputFilter, InputFilter, } from '../where-inputs'; -import { limitsExceededError } from '../graphql-errors'; +import { limitsExceededError, userInputError } from '../graphql-errors'; import { InitialisedList } from '../types-for-lists'; import { getDBFieldKeyForFieldOnMultiField, runWithPrisma } from '../utils'; @@ -132,7 +132,7 @@ async function resolveOrderBy( orderBy.map(async orderBySelection => { const keys = Object.keys(orderBySelection); if (keys.length !== 1) { - throw new Error( + throw userInputError( `Only a single key must be passed to ${list.types.orderBy.graphQLType.name}` ); } @@ -140,7 +140,7 @@ async function resolveOrderBy( const fieldKey = keys[0]; const value = orderBySelection[fieldKey]; if (value === null) { - throw new Error('null cannot be passed as an order direction'); + throw userInputError('null cannot be passed as an order direction'); } const field = list.fields[fieldKey]; diff --git a/packages/keystone/src/lib/core/where-inputs.ts b/packages/keystone/src/lib/core/where-inputs.ts index 77436b9bf10..2f23516559f 100644 --- a/packages/keystone/src/lib/core/where-inputs.ts +++ b/packages/keystone/src/lib/core/where-inputs.ts @@ -1,4 +1,5 @@ import { DBField, KeystoneContext } from '../../types'; +import { userInputError } from './graphql-errors'; import { InitialisedList } from './types-for-lists'; import { getDBFieldKeyForFieldOnMultiField } from './utils'; @@ -33,14 +34,14 @@ export async function resolveUniqueWhereInput( ): Promise { const inputKeys = Object.keys(input); if (inputKeys.length !== 1) { - throw new Error( + throw userInputError( `Exactly one key must be passed in a unique where input but ${inputKeys.length} keys were passed` ); } const key = inputKeys[0]; const val = input[key]; if (val === null) { - throw new Error(`The unique value provided in a unique where input must not be null`); + throw userInputError(`The unique value provided in a unique where input must not be null`); } const resolver = fields[key].input!.uniqueWhere!.resolve; return { [key]: resolver ? await resolver(val, context) : val }; @@ -79,13 +80,13 @@ export async function resolveWhereInput( if (field.dbField.mode === 'many') { return async () => { if (value === null) { - throw new Error('A many relation filter cannot be set to null'); + throw userInputError('A many relation filter cannot be set to null'); } return Object.fromEntries( await Promise.all( Object.entries(value).map(async ([key, val]) => { if (val === null) { - throw new Error( + throw userInputError( `The key "${key}" in a many relation filter cannot be set to null` ); } diff --git a/packages/keystone/src/lib/id-field.ts b/packages/keystone/src/lib/id-field.ts index ba8948c7789..5cefbe0ef70 100644 --- a/packages/keystone/src/lib/id-field.ts +++ b/packages/keystone/src/lib/id-field.ts @@ -10,6 +10,7 @@ import { graphql, } from '../types'; import { packagePath } from '../package-path'; +import { userInputError } from './core/graphql-errors'; const views = path.join( packagePath, @@ -19,13 +20,13 @@ const views = path.join( const idParsers = { autoincrement(val: string | null) { if (val === null) { - throw new Error('Only an integer can be passed to id filters'); + throw userInputError('Only an integer can be passed to id filters'); } const parsed = parseInt(val); if (Number.isInteger(parsed)) { return parsed; } - throw new Error('Only an integer can be passed to id filters'); + throw userInputError('Only an integer can be passed to id filters'); }, cuid(val: string | null) { // isCuid is just "it's a string and it starts with c" @@ -33,13 +34,13 @@ const idParsers = { if (typeof val === 'string' && isCuid(val)) { return val; } - throw new Error('Only a cuid can be passed to id filters'); + throw userInputError('Only a cuid can be passed to id filters'); }, uuid(val: string | null) { if (typeof val === 'string' && validate(val)) { return val.toLowerCase(); } - throw new Error('Only a uuid can be passed to id filters'); + throw userInputError('Only a uuid can be passed to id filters'); }, }; @@ -74,7 +75,7 @@ function resolveVal( kind: IdFieldConfig['kind'] ): any { if (input === null) { - throw new Error('id filter cannot be null'); + throw userInputError('id filter cannot be null'); } const idParser = idParsers[kind]; const obj: any = {}; @@ -89,7 +90,7 @@ function resolveVal( const val = input[key]; if (val !== undefined) { if (val === null) { - throw new Error(`${key} id filter cannot be null`); + throw userInputError(`${key} id filter cannot be null`); } obj[key] = val.map(x => idParser(x)); } diff --git a/tests/api-tests/queries/filters.test.ts b/tests/api-tests/queries/filters.test.ts index d7f0b56bed2..044565eab60 100644 --- a/tests/api-tests/queries/filters.test.ts +++ b/tests/api-tests/queries/filters.test.ts @@ -1,7 +1,7 @@ import { text, relationship } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectInternalServerError } from '../utils'; +import { apiTestConfig, expectBadUserInput } from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -80,7 +80,7 @@ describe('filtering on relationships', () => { }); // Returns null and throws an error expect(body.data).toEqual({ secondaryLists: null }); - expectInternalServerError(body.errors, false, [ + expectBadUserInput(body.errors, [ { message: 'A many relation filter cannot be set to null', path: ['secondaryLists'], @@ -97,7 +97,7 @@ describe('filtering on relationships', () => { }); // Returns null and throws an error expect(body.data).toEqual({ secondaryLists: null }); - expectInternalServerError(body.errors, false, [ + expectBadUserInput(body.errors, [ { message: 'The key "some" in a many relation filter cannot be set to null', path: ['secondaryLists'], @@ -144,7 +144,7 @@ describe('searching by unique fields', () => { const { body } = await graphQLRequest({ query: '{ user(where: {}) { id email } }' }); // Returns null and throws an error expect(body.data).toEqual({ user: null }); - expectInternalServerError(body.errors, false, [ + expectBadUserInput(body.errors, [ { message: 'Exactly one key must be passed in a unique where input but 0 keys were passed', path: ['user'], @@ -162,7 +162,7 @@ describe('searching by unique fields', () => { }); // Returns null and throws an error expect(body.data).toEqual({ user: null }); - expectInternalServerError(body.errors, false, [ + expectBadUserInput(body.errors, [ { message: 'Exactly one key must be passed in a unique where input but 2 keys were passed', path: ['user'], @@ -179,7 +179,7 @@ describe('searching by unique fields', () => { }); // Returns null and throws an error expect(body.data).toEqual({ user: null }); - expectInternalServerError(body.errors, false, [ + expectBadUserInput(body.errors, [ { message: 'The unique value provided in a unique where input must not be null', path: ['user'], diff --git a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts index defe799ac40..e431432f6be 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-many.test.ts @@ -322,7 +322,7 @@ describe('non-matching filter', () => { { path: ['updateUser'], message: - 'You must provide at least one field in to-many relationship inputs but none were provided at User.notes', + 'Input error: You must provide at least one field in to-many relationship inputs but none were provided at User.notes', }, ]); }) diff --git a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts index 6c27e85928c..e78b1972820 100644 --- a/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/connect-singular.test.ts @@ -214,7 +214,7 @@ describe('non-matching filter', () => { expectRelationshipError(errors, [ { path: ['updateEvent'], - message: `Nested to-one mutations must provide exactly one field if they're provided but Event.group did not`, + message: `Input error: Nested to-one mutations must provide exactly one field if they're provided but Event.group did not`, }, ]); }) diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts index 6fea881bb2a..0d03cabb7d4 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-many.test.ts @@ -153,7 +153,7 @@ describe('errors on incomplete data', () => { { path: ['createUser'], message: - 'You must provide at least one field in to-many relationship inputs but none were provided at User.notes', + 'Input error: You must provide at least one field in to-many relationship inputs but none were provided at User.notes', }, ]); }) diff --git a/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts b/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts index bbdc1c17c9f..72a35fcc0e4 100644 --- a/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts +++ b/tests/api-tests/relationships/nested-mutations/create-and-connect-singular.test.ts @@ -40,7 +40,7 @@ describe('errors on incomplete data', () => { { path: ['createEvent'], message: - "Nested to-one mutations must provide exactly one field if they're provided but Event.group did not", + "Input error: Nested to-one mutations must provide exactly one field if they're provided but Event.group did not", }, ]); }) @@ -67,7 +67,7 @@ describe('errors on incomplete data', () => { { path: ['createEvent'], message: - "Nested to-one mutations must provide exactly one field if they're provided but Event.group did not", + "Input error: Nested to-one mutations must provide exactly one field if they're provided but Event.group did not", }, ]); }) diff --git a/tests/api-tests/relationships/nested-mutations/set-many.test.ts b/tests/api-tests/relationships/nested-mutations/set-many.test.ts index 53988022def..9817f6b0f36 100644 --- a/tests/api-tests/relationships/nested-mutations/set-many.test.ts +++ b/tests/api-tests/relationships/nested-mutations/set-many.test.ts @@ -147,7 +147,7 @@ describe('no access control', () => { { path: ['updateUser'], message: - 'The set and disconnect fields cannot both be provided to to-many relationship inputs but both were provided at User.notes', + 'Input error: The set and disconnect fields cannot both be provided to to-many relationship inputs but both were provided at User.notes', }, ]); }) diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 4e1741983db..9a279e95d82 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -189,7 +189,7 @@ export const expectBadUserInput = ( args.map(({ path, message }) => ({ extensions: { code: 'INTERNAL_SERVER_ERROR' }, path, - message, + message: `Input error: ${message}`, })) ); }; From b6c8c3bff9d3d98f743c47c015ae27e63db0271e Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Thu, 16 Sep 2021 09:13:30 +1000 Subject: [PATCH 056/135] Document field updates (#6564) --- .changeset/rare-baboons-repeat.md | 2 +- .changeset/short-moles-hug.md | 46 +++++++ .changeset/tiny-mice-tell.md | 5 + examples-staging/basic/schema.graphql | 4 +- examples-staging/basic/schema.prisma | 2 +- .../graphql-api-endpoint/schema.graphql | 4 +- .../graphql-api-endpoint/schema.prisma | 2 +- examples/document-field/schema.graphql | 8 +- examples/document-field/schema.prisma | 4 +- packages/fields-document/package.json | 5 +- packages/fields-document/src/index.ts | 117 ++++++++++-------- .../src/tests/test-fixtures.ts | 9 +- .../json-field-type-polyfill-for-sqlite.ts | 20 ++- 13 files changed, 156 insertions(+), 72 deletions(-) create mode 100644 .changeset/short-moles-hug.md create mode 100644 .changeset/tiny-mice-tell.md diff --git a/.changeset/rare-baboons-repeat.md b/.changeset/rare-baboons-repeat.md index 77221ac1697..1588e1ee1c1 100644 --- a/.changeset/rare-baboons-repeat.md +++ b/.changeset/rare-baboons-repeat.md @@ -4,7 +4,7 @@ The `checkbox` field is now non-nullable in the database, if you need three states, you should use `select()`. The field no longer accepts dynamic default values and it will default to `false` unless a different `defaultValue` is specified. `graphql.isNonNull` can also be set if you have no read access control and you don't intend to add any in the future, it will make the GraphQL output field non-nullable. -If you're using SQLite, Prisma will generate a migration that makes the column non-nullable and sets any rows that have +If you're using SQLite, Prisma will generate a migration that makes the column non-nullable and sets any rows that have null values to the `defaultValue`. If you're using PostgreSQL, Prisma will generate a migration but you'll need to modify it if you have nulls in a checkbox field. Keystone will say that the migration cannot be executed: diff --git a/.changeset/short-moles-hug.md b/.changeset/short-moles-hug.md new file mode 100644 index 00000000000..aa26bcf9bce --- /dev/null +++ b/.changeset/short-moles-hug.md @@ -0,0 +1,46 @@ +--- +'@keystone-next/fields-document': major +--- + +The `document` field is now non-nullable in the database. The field no longer has `defaultValue` or `isRequired` options. The same behaviour can be re-created with the `validateInput` and `resolveInput` hooks respectively. The field will default to `[{ "type": "paragraph", "children": [{ "text": "" }] }]`. The output type has also been renamed to `ListKey_fieldKey_Document` + +If you're using SQLite, Prisma will generate a migration that makes the column non-nullable and sets any rows that have null values to an empty paragraph. + +If you're using PostgreSQL, Prisma will generate a migration but you'll need to modify it if you have nulls in a `document` field. Keystone will say that the migration cannot be executed: + +``` +✨ Starting Keystone +⭐️ Dev Server Ready on http://localhost:3000 +✨ Generating GraphQL and Prisma schemas +✨ There has been a change to your Keystone schema that requires a migration + +⚠️ We found changes that cannot be executed: + + • Made the column `content` on table `Post` required, but there are 1 existing NULL values. + +✔ Name of migration … make_document_field_non_null +✨ A migration has been created at migrations/20210915050920_make_document_field_non_null +Please edit the migration and run keystone-next dev again to apply the migration +``` + +The generated migration will look like this: + +```sql +/* + Warnings: + + - Made the column `content` on table `Post` required. This step will fail if there are existing NULL values in that column. + +*/ +-- AlterTable +ALTER TABLE "Post" ALTER COLUMN "content" SET NOT NULL, +ALTER COLUMN "content" SET DEFAULT E'[{"type":"paragraph","children":[{"text":""}]}]'; +``` + +To make it set any null values to an empty paragraph in your database, you need to modify it so that it looks like this but with the table and column names replaced. + +```sql +ALTER TABLE "Post" ALTER COLUMN "content" SET DEFAULT E'[{"type":"paragraph","children":[{"text":""}]}]'; +UPDATE "Post" SET "content" = DEFAULT WHERE "content" IS NULL; +ALTER TABLE "Post" ALTER COLUMN "content" SET NOT NULL; +``` diff --git a/.changeset/tiny-mice-tell.md b/.changeset/tiny-mice-tell.md new file mode 100644 index 00000000000..12f708203f1 --- /dev/null +++ b/.changeset/tiny-mice-tell.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': minor +--- + +Added `dbFieldConfig` parameter to `jsonFieldTypePolyfilledForSQLite` diff --git a/examples-staging/basic/schema.graphql b/examples-staging/basic/schema.graphql index abe52a2da33..022c968d590 100644 --- a/examples-staging/basic/schema.graphql +++ b/examples-staging/basic/schema.graphql @@ -324,12 +324,12 @@ type Post { id: ID! title: String status: String - content: Post_content_DocumentField + content: Post_content_Document publishDate: String author: User } -type Post_content_DocumentField { +type Post_content_Document { document(hydrateRelationships: Boolean! = false): JSON! } diff --git a/examples-staging/basic/schema.prisma b/examples-staging/basic/schema.prisma index 7dec910681c..a5c1243f00d 100644 --- a/examples-staging/basic/schema.prisma +++ b/examples-staging/basic/schema.prisma @@ -45,7 +45,7 @@ model Post { id String @id @default(cuid()) title String? status String? - content String? + content String @default("[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]") publishDate DateTime? author User? @relation("Post_author", fields: [authorId], references: [id]) authorId String? @map("author") diff --git a/examples-staging/graphql-api-endpoint/schema.graphql b/examples-staging/graphql-api-endpoint/schema.graphql index b2e7f5517c7..96e88d47305 100644 --- a/examples-staging/graphql-api-endpoint/schema.graphql +++ b/examples-staging/graphql-api-endpoint/schema.graphql @@ -180,7 +180,7 @@ type Post { id: ID! title: String status: String - content: Post_content_DocumentField + content: Post_content_Document publishDate: String author: User tags( @@ -192,7 +192,7 @@ type Post { tagsCount(where: TagWhereInput! = {}): Int } -type Post_content_DocumentField { +type Post_content_Document { document(hydrateRelationships: Boolean! = false): JSON! } diff --git a/examples-staging/graphql-api-endpoint/schema.prisma b/examples-staging/graphql-api-endpoint/schema.prisma index 24735e8e91b..80d70265a71 100644 --- a/examples-staging/graphql-api-endpoint/schema.prisma +++ b/examples-staging/graphql-api-endpoint/schema.prisma @@ -23,7 +23,7 @@ model Post { id String @id @default(cuid()) title String? status String? - content Json? + content Json @default("[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]") publishDate DateTime? author User? @relation("Post_author", fields: [authorId], references: [id]) authorId String? @map("author") diff --git a/examples/document-field/schema.graphql b/examples/document-field/schema.graphql index b06ab9f0370..0fa348553ce 100644 --- a/examples/document-field/schema.graphql +++ b/examples/document-field/schema.graphql @@ -6,7 +6,7 @@ type Post { title: String slug: String status: PostStatusType - content: Post_content_DocumentField + content: Post_content_Document publishDate: String author: Author } @@ -16,7 +16,7 @@ enum PostStatusType { published } -type Post_content_DocumentField { +type Post_content_Document { document(hydrateRelationships: Boolean! = false): JSON! } @@ -96,10 +96,10 @@ type Author { skip: Int! = 0 ): [Post!] postsCount(where: PostWhereInput! = {}): Int - bio: Author_bio_DocumentField + bio: Author_bio_Document } -type Author_bio_DocumentField { +type Author_bio_Document { document(hydrateRelationships: Boolean! = false): JSON! } diff --git a/examples/document-field/schema.prisma b/examples/document-field/schema.prisma index 384462f9123..13365fb4cd5 100644 --- a/examples/document-field/schema.prisma +++ b/examples/document-field/schema.prisma @@ -16,7 +16,7 @@ model Post { title String? slug String? @unique status String? - content String? + content String @default("[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]") publishDate DateTime? author Author? @relation("Post_author", fields: [authorId], references: [id]) authorId String? @map("author") @@ -29,5 +29,5 @@ model Author { name String? email String? @unique posts Post[] @relation("Post_author") - bio String? + bio String @default("[{\"type\":\"paragraph\",\"children\":[{\"text\":\"\"}]}]") } \ No newline at end of file diff --git a/packages/fields-document/package.json b/packages/fields-document/package.json index bf26a4dbd65..4639f087735 100644 --- a/packages/fields-document/package.json +++ b/packages/fields-document/package.json @@ -18,11 +18,13 @@ "views.tsx" ] }, + "peerDependencies": { + "@keystone-next/keystone": "^25.0.0" + }, "dependencies": { "@babel/runtime": "^7.15.4", "@braintree/sanitize-url": "^5.0.2", "@emotion/weak-memoize": "^0.2.5", - "@keystone-next/keystone": "^25.0.0", "@keystone-ui/button": "^5.0.1", "@keystone-ui/core": "^3.2.0", "@keystone-ui/fields": "^4.1.3", @@ -51,6 +53,7 @@ }, "repository": "https://github.com/keystonejs/keystone/tree/master/packages/fields-document", "devDependencies": { + "@keystone-next/keystone": "*", "@testing-library/react": "^12.1.0", "array.prototype.flat": "^1.2.4", "jest-diff": "^27.2.0", diff --git a/packages/fields-document/src/index.ts b/packages/fields-document/src/index.ts index 0f79732dbf8..be2e895b437 100644 --- a/packages/fields-document/src/index.ts +++ b/packages/fields-document/src/index.ts @@ -6,7 +6,6 @@ import { jsonFieldTypePolyfilledForSQLite, graphql, JSONValue, - FieldDefaultValue, } from '@keystone-next/keystone/types'; import { Relationships } from './DocumentEditor/relationship'; import { ComponentBlock } from './component-blocks'; @@ -75,8 +74,6 @@ export type DocumentFieldConfig[], TGeneratedListTypes>; }; const views = path.join(path.dirname(__dirname), 'views'); @@ -89,8 +86,6 @@ export const document = layouts, relationships: configRelationships, links, - isRequired, - defaultValue, ...config }: DocumentFieldConfig = {}): FieldTypeFunc => meta => { @@ -103,7 +98,10 @@ export const document = const relationships = normaliseRelationships(configRelationships); const inputResolver = (data: JSONValue | null | undefined): any => { - if (data === null || data === undefined) { + if (data === null) { + throw new Error(`Document fields cannot be set to null`); + } + if (data === undefined) { return data; } return validateAndNormalizeDocument(data, documentFeatures, componentBlocks, relationships); @@ -113,55 +111,72 @@ export const document = throw Error("isIndexed: 'unique' is not a supported option for field type document"); } - return jsonFieldTypePolyfilledForSQLite(meta.provider, { - ...config, - input: { - create: { arg: graphql.arg({ type: graphql.JSON }), resolve: inputResolver }, - update: { arg: graphql.arg({ type: graphql.JSON }), resolve: inputResolver }, - }, - output: graphql.field({ - type: graphql.object<{ document: JSONValue }>()({ - name: `${meta.listKey}_${meta.fieldKey}_DocumentField`, - fields: { - document: graphql.field({ - args: { - hydrateRelationships: graphql.arg({ - type: graphql.nonNull(graphql.Boolean), - defaultValue: false, - }), - }, - type: graphql.nonNull(graphql.JSON), - resolve({ document }, { hydrateRelationships }, context) { - return hydrateRelationships - ? addRelationshipData( - document as any, - context.graphql, - relationships, - componentBlocks, - context.gqlNames as any - ) - : (document as any); - }, - }), + return jsonFieldTypePolyfilledForSQLite( + meta.provider, + { + ...config, + input: { + create: { + arg: graphql.arg({ type: graphql.JSON }), + resolve(val) { + if (val === undefined) { + val = [{ type: 'paragraph', children: [{ text: '' }] }]; + } + return inputResolver(val); + }, + }, + update: { arg: graphql.arg({ type: graphql.JSON }), resolve: inputResolver }, + }, + output: graphql.field({ + type: graphql.object<{ document: JSONValue }>()({ + name: `${meta.listKey}_${meta.fieldKey}_Document`, + fields: { + document: graphql.field({ + args: { + hydrateRelationships: graphql.arg({ + type: graphql.nonNull(graphql.Boolean), + defaultValue: false, + }), + }, + type: graphql.nonNull(graphql.JSON), + resolve({ document }, { hydrateRelationships }, context) { + return hydrateRelationships + ? addRelationshipData( + document as any, + context.graphql, + relationships, + componentBlocks, + context.gqlNames + ) + : (document as any); + }, + }), + }, + }), + resolve({ value }) { + if (value === null) { + return null; + } + return { document: value }; }, }), - resolve({ value }) { - if (value === null) { - return null; - } - return { document: value }; + views, + getAdminMeta(): Parameters[0]['fieldMeta'] { + return { + relationships, + documentFeatures, + componentBlocksPassedOnServer: Object.keys(componentBlocks), + }; }, - }), - views, - getAdminMeta(): Parameters[0]['fieldMeta'] { - return { - relationships, - documentFeatures, - componentBlocksPassedOnServer: Object.keys(componentBlocks), - }; }, - __legacy: { isRequired, defaultValue }, - }); + { + mode: 'required', + default: { + kind: 'literal', + value: JSON.stringify([{ type: 'paragraph', children: [{ text: '' }] }]), + }, + } + ); }; function normaliseRelationships( diff --git a/packages/fields-document/src/tests/test-fixtures.ts b/packages/fields-document/src/tests/test-fixtures.ts index 3b96abd92b1..6733ed1d05a 100644 --- a/packages/fields-document/src/tests/test-fixtures.ts +++ b/packages/fields-document/src/tests/test-fixtures.ts @@ -13,6 +13,7 @@ export const updateReturnedValue = [ ]; export const supportsUnique = false; +export const skipRequiredTest = true; export const fieldName = 'content'; export const subfieldName = 'document'; @@ -39,7 +40,7 @@ export const initItems = () => { name: 'd', content: [{ type: 'paragraph', children: [{ text: 'text' }] }], }, - { name: 'e', content: null }, + { name: 'e', content: [{ type: 'paragraph', children: [{ text: '' }] }] }, { name: 'f' }, { name: 'g' }, ]; @@ -69,9 +70,9 @@ export const storedValues = () => [ name: 'd', content: { document: [{ type: 'paragraph', children: [{ text: 'text' }] }] }, }, - { name: 'e', content: null }, - { name: 'f', content: null }, - { name: 'g', content: null }, + { name: 'e', content: { document: [{ type: 'paragraph', children: [{ text: '' }] }] } }, + { name: 'f', content: { document: [{ type: 'paragraph', children: [{ text: '' }] }] } }, + { name: 'g', content: { document: [{ type: 'paragraph', children: [{ text: '' }] }] } }, ]; export const supportedFilters = () => []; diff --git a/packages/keystone/src/types/json-field-type-polyfill-for-sqlite.ts b/packages/keystone/src/types/json-field-type-polyfill-for-sqlite.ts index 6f9a1091a3e..62d5e2f02ec 100644 --- a/packages/keystone/src/types/json-field-type-polyfill-for-sqlite.ts +++ b/packages/keystone/src/types/json-field-type-polyfill-for-sqlite.ts @@ -105,13 +105,22 @@ export function jsonFieldTypePolyfilledForSQLite< uniqueWhere?: undefined; orderBy?: undefined; }; + }, + dbFieldConfig?: { + mode?: 'required' | 'optional'; + default?: ScalarDBField<'Json', 'optional'>['default']; } ) { if (provider === 'sqlite') { - return fieldType({ kind: 'scalar', mode: 'optional', scalar: 'String' })({ + return fieldType({ + kind: 'scalar', + mode: dbFieldConfig?.mode ?? 'optional', + scalar: 'String', + default: dbFieldConfig?.default, + })({ ...config, input: { - create: mapCreateInputArgToSQLite(config.input?.create), + create: mapCreateInputArgToSQLite(config.input?.create) as any, update: mapUpdateInputArgToSQLite(config.input?.update), }, output: mapOutputFieldToSQLite(config.output), @@ -123,5 +132,10 @@ export function jsonFieldTypePolyfilledForSQLite< ), }); } - return fieldType({ kind: 'scalar', mode: 'optional', scalar: 'Json' })(config); + return fieldType({ + kind: 'scalar', + mode: (dbFieldConfig?.mode ?? 'optional') as 'optional', + scalar: 'Json', + default: dbFieldConfig?.default, + })(config); } From 7de13bce32630ee2478a9894e801020c520c64a9 Mon Sep 17 00:00:00 2001 From: Charles Date: Fri, 17 Sep 2021 10:02:18 +1000 Subject: [PATCH 057/135] 6306/fix deletion pagination bug (#6571) * add effect to reroute when all items on a page have been deleted * add comments to clarify why we add the effect * add pagination bug tests * move effect to Pagination component * remove effect from ListPage page * remove unused router property assignments * update utils * Update packages/keystone/src/admin-ui/components/Pagination.tsx Co-authored-by: Mitchell Hamilton * chnageset Co-authored-by: Mitchell Hamilton --- .changeset/gold-jars-provide.md | 5 ++ .../admin-ui/pages/ListPage/index.tsx | 1 + .../src/admin-ui/components/Pagination.tsx | 16 ++++++ tests/admin-ui-tests/init.test.ts | 51 ++++++++++++++++++- tests/admin-ui-tests/utils.ts | 6 +++ 5 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 .changeset/gold-jars-provide.md diff --git a/.changeset/gold-jars-provide.md b/.changeset/gold-jars-provide.md new file mode 100644 index 00000000000..7751f159d28 --- /dev/null +++ b/.changeset/gold-jars-provide.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed pagination bug on deletion of items. diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx index 549a629679e..589cbcc958c 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx @@ -221,6 +221,7 @@ const ListPage = ({ listKey }: ListPageProps) => { const theme = useTheme(); const showCreate = !(metaQuery.data?.keystone.adminMeta.list?.hideCreate ?? true) || null; + return ( }> {metaQuery.error ? ( diff --git a/packages/keystone/src/admin-ui/components/Pagination.tsx b/packages/keystone/src/admin-ui/components/Pagination.tsx index 368ed8a152b..fd8da82c1e8 100644 --- a/packages/keystone/src/admin-ui/components/Pagination.tsx +++ b/packages/keystone/src/admin-ui/components/Pagination.tsx @@ -1,5 +1,6 @@ /** @jsxRuntime classic */ /** @jsx jsx */ +import { useEffect } from 'react'; import { jsx, Stack, useTheme } from '@keystone-ui/core'; import { Select } from '@keystone-ui/fields'; import { ChevronRightIcon, ChevronLeftIcon } from '@keystone-ui/icons'; @@ -43,6 +44,21 @@ export function Pagination({ currentPage, total, pageSize, list }: PaginationPro const limit = Math.ceil(total / pageSize); const pages = []; + useEffect(() => { + // Check if the current page is larger than + // the maximal page given the total and associated page size value. + // (This could happen due to a deletion event, in which case we want to reroute the user to a previous page). + if (currentPage > Math.ceil(total / pageSize)) { + push({ + pathname, + query: { + ...query, + page: Math.ceil(total / pageSize), + }, + }); + } + }, [total, pageSize, currentPage, pathname, query, push]); + // Don't render the pagiantion component if the pageSize is greater than the total number of items in the list. if (total <= pageSize) return null; diff --git a/tests/admin-ui-tests/init.test.ts b/tests/admin-ui-tests/init.test.ts index de48a86a2fb..3774d43a4d1 100644 --- a/tests/admin-ui-tests/init.test.ts +++ b/tests/admin-ui-tests/init.test.ts @@ -1,5 +1,5 @@ import { Browser, Page } from 'playwright'; -import { adminUITests } from './utils'; +import { adminUITests, deleteAllData, generateDataArray, makeGqlRequest } from './utils'; adminUITests('./tests/test-projects/basic', browserType => { let browser: Browser = undefined as any; @@ -28,6 +28,55 @@ adminUITests('./tests/test-projects/basic', browserType => { const content = await page.textContent('body h1'); expect(content).toBe('404'); }); + describe('List View', () => { + beforeEach(async () => { + const gql = String.raw; + const query = gql` + mutation Create_Tasks_Mutation($data: [TaskCreateInput!]!) { + createTasks(data: $data) { + id + } + } + `; + const variables = { + data: generateDataArray( + (key: number) => ({ label: `Test Task: ${key}`, isComplete: false }), + 52 + ), + }; + await makeGqlRequest(query, variables); + await page.goto('http://localhost:3000/tasks?page=6&pageSize=10'); + }); + afterEach(async () => { + await deleteAllData('./tests/test-projects/basic'); + }); + test('If all items are deleted from the last page, users should be redirected to the previous page if one exists', async () => { + await page.waitForSelector('thead th:first-of-type label'); + await page.click('thead th:first-of-type label'); + await page.click('button:has-text("Delete")'); + await Promise.all([ + page.waitForNavigation({ + url: /localhost:3000\/tasks\?.*(page=5)/, + }), + page.click('div[role="dialog"] button:has-text("Delete")'), + ]); + }); + test('The page users are redirected to on complete deleletion of the last page, should have items', async () => { + await page.waitForSelector('thead th:first-of-type label'); + await page.click('thead th:first-of-type label'); + await page.click('button:has-text("Delete")'); + await Promise.all([ + page.waitForNavigation({ + url: /localhost:3000\/tasks\?.*(page=5)/, + }), + page.click('div[role="dialog"] button:has-text("Delete")'), + ]); + await page.waitForSelector('table tbody'); + const elements = page.locator('table tbody tr'); + await expect(elements.evaluateAll((tr, min) => tr.length > min, 0)).resolves.toBe(true); + }); + }); + afterAll(async () => { await browser.close(); }); diff --git a/tests/admin-ui-tests/utils.ts b/tests/admin-ui-tests/utils.ts index fceac1cfdbf..53812dcd026 100644 --- a/tests/admin-ui-tests/utils.ts +++ b/tests/admin-ui-tests/utils.ts @@ -22,6 +22,7 @@ const promiseSignal = (): Promise & { resolve: () => void } => { }; const projectRoot = findRootSync(process.cwd()); +// Light wrapper around node-fetch for making graphql requests to the graphql api of the test instance. export const makeGqlRequest = async (query: string, variables?: Record) => { const { data, errors } = await fetch('http://localhost:3000/api/graphql', { method: 'POST', @@ -41,6 +42,11 @@ export const makeGqlRequest = async (query: string, variables?: Record any, range: number) { + return Array.from(Array(range).keys()).map(map); +} + export const deleteAllData: (projectDir: string) => Promise = async (projectDir: string) => { const { PrismaClient } = require(path.resolve( projectRoot, From a95da1d812574fd17d1fa8bc324415da558a9d9d Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Fri, 17 Sep 2021 11:18:49 +1000 Subject: [PATCH 058/135] Add support for dynamic isFilterable and isOrderable (#6560) --- .changeset/nine-avocados-promise.md | 5 + docs/pages/docs/apis/fields.mdx | 16 +- docs/pages/docs/apis/schema.mdx | 4 +- .../src/admin-ui/system/createAdminMeta.ts | 4 +- .../src/lib/core/filter-order-access.ts | 46 +++ .../keystone/src/lib/core/graphql-errors.ts | 13 + .../src/lib/core/mutations/create-update.ts | 5 + .../keystone/src/lib/core/mutations/delete.ts | 5 + .../src/lib/core/queries/output-field.ts | 5 + .../src/lib/core/queries/resolvers.ts | 86 ++++- .../keystone/src/lib/core/types-for-lists.ts | 48 ++- packages/keystone/src/types/config/fields.ts | 11 +- packages/keystone/src/types/config/lists.ts | 6 +- tests/api-tests/queries/filters.test.ts | 290 ++++++++++++++++- tests/api-tests/queries/orderBy.test.ts | 301 +++++++++++++++++- 15 files changed, 796 insertions(+), 49 deletions(-) create mode 100644 .changeset/nine-avocados-promise.md create mode 100644 packages/keystone/src/lib/core/filter-order-access.ts diff --git a/.changeset/nine-avocados-promise.md b/.changeset/nine-avocados-promise.md new file mode 100644 index 00000000000..318cf4bbc6d --- /dev/null +++ b/.changeset/nine-avocados-promise.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': minor +--- + +Added support for dynamic `isFilterable` and `isOrderable` field config values. If a function is provided for these config option, it will be dynamically evaluated each time the field is used for filtering and ordering, and an error will be returned if the function returns `false`. diff --git a/docs/pages/docs/apis/fields.mdx b/docs/pages/docs/apis/fields.mdx index 7b9100ebaef..c3d46eee475 100644 --- a/docs/pages/docs/apis/fields.mdx +++ b/docs/pages/docs/apis/fields.mdx @@ -63,8 +63,14 @@ All options are optional. Options: -- `isFilterable` (default: `false`): If `true`, the GraphQL API and Admin UI will support filtering by this field. -- `isOrderable` (default: `false`): If `true`, the GraphQL API and Admin UI will support ordering by this field. +- `isFilterable` (default: `false`): If `false` (default), the GraphQL API and admin UI will not support filtering by this field. + If `true`, the GraphQL API and Admin UI will support filtering by this field. + If a function is provided, it will be evaluated dynamically each time this field is used as a filter in a GraphQL operation. + If the function returns `false`, the operation will return an error indicating that filtering on this field is not allowed. +- `isOrderable` (default: `false`): If `false` (default), the GraphQL API and admin UI will not support ordering by this field. + If `true`, the GraphQL API and Admin UI will support ordering by this field. + If a function is provided, it will be evaluated dynamically each time this field is used as an ordering field in a GraphQL operation. + If the function returns `false`, the operation will return an error indicating this ordering by this field is not allowed. - `access`: Defines the [Access Control](../guides/access-control) rules for the field. See the [Access Control API](./access-control) for full details on the available access control options. - `hooks`: The `hooks` option defines [hook](../guides/hooks) functions for the field. @@ -98,8 +104,8 @@ export default config({ ListName: list({ fields: { fieldName: text({ - isFilterable: true, - isOrderable: true, + isFilterable: ({ context, session, fieldKey, listKey }) => true, + isOrderable: ({ context, session, fieldKey, listKey }) => true, access: { /* ... */ }, hooks: { /* ... */ }, label: '...', @@ -594,7 +600,7 @@ See the [virtual fields guide](../guides/virtual-fields) for details on how to u Options: - `field` (required): The GraphQL field that defines the type, resolver and arguments. -- `ui.query` (default: `''` ): +- `ui.query` (default: `''` ): Defines what the Admin UI should fetch from this field, it's interpolated into a query like this: ```graphql query { diff --git a/docs/pages/docs/apis/schema.mdx b/docs/pages/docs/apis/schema.mdx index 7eb5b3b4fc7..f531e174f5c 100644 --- a/docs/pages/docs/apis/schema.mdx +++ b/docs/pages/docs/apis/schema.mdx @@ -33,8 +33,8 @@ This document will explain the configuration options which can be used with the Options: -- `defaultIsFilterable`: If `true`, all fields will be filterable by default. They can override this by setting the field level `isFilterable` option to `false`. -- `defaultIsOrderable`: If `true`, all fields will be orderable by default. They can override this by setting the field level `isOrderable` option to `false`. +- `defaultIsFilterable`: This value sets the default value to use for `isFilterable` for fields on this list. +- `defaultIsOrderable`: This value sets the default value to use for `isOrderable` for fields on this list. ## fields diff --git a/packages/keystone/src/admin-ui/system/createAdminMeta.ts b/packages/keystone/src/admin-ui/system/createAdminMeta.ts index 2236abc9f56..49b0e9bbdbb 100644 --- a/packages/keystone/src/admin-ui/system/createAdminMeta.ts +++ b/packages/keystone/src/admin-ui/system/createAdminMeta.ts @@ -130,8 +130,8 @@ export function createAdminMeta( viewsIndex: getViewId(field.views), customViewsIndex: field.ui?.views === undefined ? null : getViewId(field.ui.views), fieldMeta: null, - isOrderable: field.graphql.isEnabled.orderBy, - isFilterable: field.graphql.isEnabled.filter, + isOrderable: !!field.graphql.isEnabled.orderBy, + isFilterable: !!field.graphql.isEnabled.filter, path: fieldKey, listKey: key, search, diff --git a/packages/keystone/src/lib/core/filter-order-access.ts b/packages/keystone/src/lib/core/filter-order-access.ts new file mode 100644 index 00000000000..d2f705520ce --- /dev/null +++ b/packages/keystone/src/lib/core/filter-order-access.ts @@ -0,0 +1,46 @@ +import { KeystoneContext } from '../../types'; +import { filterAccessError } from './graphql-errors'; +import { InitialisedList } from './types-for-lists'; + +export async function checkFilterOrderAccess( + things: { fieldKey: string; list: InitialisedList }[], + context: KeystoneContext, + operation: 'filter' | 'orderBy' +) { + const failures: string[] = []; + for (const { fieldKey, list } of things) { + const field = list.fields[fieldKey]; + const rule = field.graphql.isEnabled[operation]; + // Check isOrderable + if (!rule) { + // If the field is explicitly false, it will excluded from the GraphQL API. + throw new Error('Assert failed'); + } else if (typeof rule === 'function') { + // Apply dynamic rules + const result = await rule({ + context, + session: context.session, + listKey: list.listKey, + fieldKey, + }); + const resultType = typeof result; + + // It's important that we don't cast objects to truthy values, as there's a strong chance that the user + // has made a mistake. + if (resultType !== 'boolean') { + throw new Error( + `Must return a Boolean from ${list.listKey}.${fieldKey}.${ + operation === 'filter' ? 'isFilterable' : 'isOrderable' + }(). Got ${resultType}` + ); + } + + if (!result) { + failures.push(`${list.listKey}.${fieldKey}`); + } + } + } + if (failures.length) { + throw filterAccessError({ operation, fieldKeys: failures }); + } +} diff --git a/packages/keystone/src/lib/core/graphql-errors.ts b/packages/keystone/src/lib/core/graphql-errors.ts index 9f4bfa09692..03d558401d5 100644 --- a/packages/keystone/src/lib/core/graphql-errors.ts +++ b/packages/keystone/src/lib/core/graphql-errors.ts @@ -32,3 +32,16 @@ export const extensionError = (extension: string, things: { error: Error; tag: s // eslint-disable-next-line @typescript-eslint/no-unused-vars export const limitsExceededError = (args: { type: string; limit: number; list: string }) => new ApolloError('Your request exceeded server limits'); + +export const filterAccessError = ({ + operation, + fieldKeys, +}: { + operation: 'filter' | 'orderBy'; + fieldKeys: string[]; +}) => + new ApolloError( + `You do not have access to perform '${operation}' operations on the fields ${JSON.stringify( + fieldKeys + )}.` + ); diff --git a/packages/keystone/src/lib/core/mutations/create-update.ts b/packages/keystone/src/lib/core/mutations/create-update.ts index 2804b302bd1..16aaa6c7631 100644 --- a/packages/keystone/src/lib/core/mutations/create-update.ts +++ b/packages/keystone/src/lib/core/mutations/create-update.ts @@ -11,6 +11,7 @@ import { import { InputFilter, resolveUniqueWhereInput, UniqueInputFilter } from '../where-inputs'; import { accessDeniedError, extensionError } from '../graphql-errors'; import { getOperationAccess, getAccessFilters } from '../access-control'; +import { checkFilterOrderAccess } from '../filter-order-access'; import { resolveRelateToManyForCreateInput, resolveRelateToManyForUpdateInput, @@ -148,6 +149,10 @@ async function updateSingle( // Validate and resolve the input filter const uniqueWhere = await resolveUniqueWhereInput(uniqueInput, list.fields, context); + // Check filter access + const fieldKey = Object.keys(uniqueWhere)[0]; + await checkFilterOrderAccess([{ fieldKey, list }], context, 'filter'); + // Filter and Item access control. Will throw an accessDeniedError if not allowed. const existingItem = await getAccessControlledItemForUpdate( list, diff --git a/packages/keystone/src/lib/core/mutations/delete.ts b/packages/keystone/src/lib/core/mutations/delete.ts index 57a0fb9ac1d..76a9f80457d 100644 --- a/packages/keystone/src/lib/core/mutations/delete.ts +++ b/packages/keystone/src/lib/core/mutations/delete.ts @@ -1,6 +1,7 @@ import pLimit, { Limit } from 'p-limit'; import { DatabaseProvider, KeystoneContext } from '../../../types'; import { getOperationAccess, getAccessFilters } from '../access-control'; +import { checkFilterOrderAccess } from '../filter-order-access'; import { accessDeniedError } from '../graphql-errors'; import { InitialisedList } from '../types-for-lists'; import { runWithPrisma } from '../utils'; @@ -25,6 +26,10 @@ async function deleteSingle( // Validate and resolve the input filter const uniqueWhere = await resolveUniqueWhereInput(uniqueInput, list.fields, context); + // Check filter access + const fieldKey = Object.keys(uniqueWhere)[0]; + await checkFilterOrderAccess([{ fieldKey, list }], context, 'filter'); + // Filter and Item access control. Will throw an accessDeniedError if not allowed. const existingItem = await getAccessControlledItemForDelete( list, diff --git a/packages/keystone/src/lib/core/queries/output-field.ts b/packages/keystone/src/lib/core/queries/output-field.ts index e4e661b539a..568904ae539 100644 --- a/packages/keystone/src/lib/core/queries/output-field.ts +++ b/packages/keystone/src/lib/core/queries/output-field.ts @@ -54,6 +54,11 @@ function getRelationVal( return null; } + // Check filter access? + // There's no need to check filter access here (c.f. `findOne()`), as + // the filter has been construct internally, not as part of user input. + + // Apply access control const resolvedWhere = await accessControlledFilter( foreignList, context, diff --git a/packages/keystone/src/lib/core/queries/resolvers.ts b/packages/keystone/src/lib/core/queries/resolvers.ts index e40e49205dc..65aca892488 100644 --- a/packages/keystone/src/lib/core/queries/resolvers.ts +++ b/packages/keystone/src/lib/core/queries/resolvers.ts @@ -12,6 +12,7 @@ import { import { limitsExceededError, userInputError } from '../graphql-errors'; import { InitialisedList } from '../types-for-lists'; import { getDBFieldKeyForFieldOnMultiField, runWithPrisma } from '../utils'; +import { checkFilterOrderAccess } from '../filter-order-access'; // doing this is a result of an optimisation to skip doing a findUnique and then a findFirst(where the second one is done with access control) // we want to do this explicit mapping because: @@ -39,6 +40,44 @@ export function mapUniqueWhereToWhere( return { [key]: val }; } +function traverseQuery( + list: InitialisedList, + context: KeystoneContext, + inputFilter: InputFilter, + filterFields: Record +) { + // Recursively traverse a where filter to find all the fields which are being + // filtered on. + Object.entries(inputFilter).forEach(([fieldKey, value]) => { + if (fieldKey === 'OR' || fieldKey === 'AND' || fieldKey === 'NOT') { + value.forEach((value: any) => { + traverseQuery(list, context, value, filterFields); + }); + } else if (fieldKey === 'some' || fieldKey === 'none' || fieldKey === 'every') { + traverseQuery(list, context, value, filterFields); + } else { + filterFields[`${list.listKey}.${fieldKey}`] = { fieldKey, list }; + // If it's a relationship, check the nested filters. + const field = list.fields[fieldKey]; + if (field.dbField.kind === 'relation' && value !== null) { + const foreignList = field.dbField.list; + traverseQuery(list.lists[foreignList], context, value, filterFields); + } + } + }); +} + +export async function checkFilterAccess( + list: InitialisedList, + context: KeystoneContext, + inputFilter: InputFilter +) { + if (!inputFilter) return; + const filterFields: Record = {}; + traverseQuery(list, context, inputFilter, filterFields); + await checkFilterOrderAccess(Object.values(filterFields), context, 'filter'); +} + export async function accessControlledFilter( list: InitialisedList, context: KeystoneContext, @@ -73,6 +112,10 @@ export async function findOne( const uniqueWhere = await resolveUniqueWhereInput(args.where, list.fields, context); const resolvedWhere = mapUniqueWhereToWhere(list, uniqueWhere); + // Check filter access + const fieldKey = Object.keys(args.where)[0]; + await checkFilterOrderAccess([{ fieldKey, list }], context, 'filter'); + // Apply access control const filter = await accessControlledFilter(list, context, resolvedWhere, accessFilters); @@ -102,6 +145,10 @@ export async function findMany( applyEarlyMaxResults(take, list); let resolvedWhere = await resolveWhereInput(where, list, context); + + // Check filter access + await checkFilterAccess(list, context, where); + resolvedWhere = await accessControlledFilter(list, context, resolvedWhere, accessFilters); const results = await runWithPrisma(context, list, model => @@ -128,21 +175,34 @@ async function resolveOrderBy( list: InitialisedList, context: KeystoneContext ): Promise[]> { + // Check input format. FIXME: Group all errors + orderBy.forEach(orderBySelection => { + const keys = Object.keys(orderBySelection); + if (keys.length !== 1) { + throw userInputError( + `Only a single key must be passed to ${list.types.orderBy.graphQLType.name}` + ); + } + + const fieldKey = keys[0]; + const value = orderBySelection[fieldKey]; + if (value === null) { + throw userInputError('null cannot be passed as an order direction'); + } + }); + + // Check orderBy access + const orderByKeys = orderBy.map(orderBySelection => ({ + fieldKey: Object.keys(orderBySelection)[0], + list, + })); + await checkFilterOrderAccess(orderByKeys, context, 'orderBy'); + return await Promise.all( orderBy.map(async orderBySelection => { const keys = Object.keys(orderBySelection); - if (keys.length !== 1) { - throw userInputError( - `Only a single key must be passed to ${list.types.orderBy.graphQLType.name}` - ); - } - const fieldKey = keys[0]; const value = orderBySelection[fieldKey]; - if (value === null) { - throw userInputError('null cannot be passed as an order direction'); - } - const field = list.fields[fieldKey]; const resolve = field.input!.orderBy!.resolve; const resolvedValue = resolve ? await resolve(value, context) : value; @@ -173,7 +233,7 @@ export async function count( info: GraphQLResolveInfo, extraFilter?: PrismaFilter ) { - // Check operation permission, throw access denied if not allowed + // Check operation permission, return zero if not allowed const operationAccess = await getOperationAccess(list, context, 'query'); if (!operationAccess) { return 0; @@ -185,6 +245,10 @@ export async function count( } let resolvedWhere = await resolveWhereInput(where, list, context); + + // Check filter access + await checkFilterAccess(list, context, where); + resolvedWhere = await accessControlledFilter(list, context, resolvedWhere, accessFilters); const count = await runWithPrisma(context, list, model => diff --git a/packages/keystone/src/lib/core/types-for-lists.ts b/packages/keystone/src/lib/core/types-for-lists.ts index fcaeb986be2..49eff14f961 100644 --- a/packages/keystone/src/lib/core/types-for-lists.ts +++ b/packages/keystone/src/lib/core/types-for-lists.ts @@ -12,8 +12,10 @@ import { DatabaseProvider, FindManyArgs, CacheHintArgs, + MaybePromise, } from '../../types'; import { FieldHooks } from '../../types/config/hooks'; +import { FilterOrderArgs } from '../../types/config/fields'; import { ResolvedFieldAccessControl, ResolvedListAccessControl, @@ -34,8 +36,8 @@ export type InitialisedField = Omit MaybePromise); + orderBy: boolean | ((args: FilterOrderArgs) => MaybePromise); }; cacheHint?: CacheHint | undefined; }; @@ -79,14 +81,29 @@ export function initialiseLists( create: boolean; update: boolean; delete: boolean; - filter: boolean; - orderBy: boolean; + filter: boolean | ((args: FilterOrderArgs) => MaybePromise); + orderBy: boolean | ((args: FilterOrderArgs) => MaybePromise); } > = {}; for (const [listKey, listConfig] of Object.entries(listsConfig)) { const omit = listConfig.graphql?.omit; const { defaultIsFilterable, defaultIsOrderable } = listConfig; + if (!omit) { + // We explicity check for boolean/function values here to ensure the dev hasn't made a mistake + // when defining these values. We avoid duck-typing here as this is security related + // and we want to make it hard to write incorrect code. + if (!['boolean', 'undefined', 'function'].includes(typeof defaultIsFilterable)) { + throw new Error( + `Configuration option '${listKey}.defaultIsFilterable' must be either a boolean value or a function. Recieved '${typeof defaultIsFilterable}'.` + ); + } + if (!['boolean', 'undefined', 'function'].includes(typeof defaultIsOrderable)) { + throw new Error( + `Configuration option '${listKey}.defaultIsOrderable' must be either a boolean value or a function. Recieved '${typeof defaultIsOrderable}'.` + ); + } + } if (omit === true) { isEnabled[listKey] = { type: false, @@ -104,8 +121,8 @@ export function initialiseLists( create: true, update: true, delete: true, - filter: !!defaultIsFilterable, - orderBy: !!defaultIsOrderable, + filter: defaultIsFilterable || false, + orderBy: defaultIsOrderable || false, }; } else { isEnabled[listKey] = { @@ -114,8 +131,8 @@ export function initialiseLists( create: !omit.includes('create'), update: !omit.includes('update'), delete: !omit.includes('delete'), - filter: !!defaultIsFilterable, - orderBy: !!defaultIsOrderable, + filter: defaultIsFilterable || false, + orderBy: defaultIsOrderable || false, }; } } @@ -355,6 +372,21 @@ export function initialiseLists( const omit = f.graphql?.omit; const read = omit !== true && !omit?.includes('read'); + + // We explicity check for boolean values here to ensure the dev hasn't made a mistake + // when defining these values. We avoid duck-typing here as this is security related + // and we want to make it hard to write incorrect code. + if (!['boolean', 'function', 'undefined'].includes(typeof f.isFilterable)) { + throw new Error( + `Configuration option '${listKey}.${fieldKey}.isFilterable' must be either a boolean value or a function. Recieved '${typeof f.isFilterable}'.` + ); + } + if (!['boolean', 'function', 'undefined'].includes(typeof f.isOrderable)) { + throw new Error( + `Configuration option '${listKey}.${fieldKey}.isOrderable' must be either a boolean value or a function. Recieved '${typeof f.isOrderable}'.` + ); + } + const _isEnabled = { read, update: omit !== true && !omit?.includes('update'), diff --git a/packages/keystone/src/types/config/fields.ts b/packages/keystone/src/types/config/fields.ts index 154e1fdf1b7..e71426729e2 100644 --- a/packages/keystone/src/types/config/fields.ts +++ b/packages/keystone/src/types/config/fields.ts @@ -1,6 +1,7 @@ import { CacheHint } from 'apollo-server-types'; import { FieldTypeFunc } from '../next-fields'; import type { BaseGeneratedListTypes } from '../utils'; +import { KeystoneContext, MaybePromise } from '..'; import { MaybeItemFunction, MaybeSessionFunction } from './lists'; import { FieldHooks } from './hooks'; import { FieldAccessControl } from './access-control'; @@ -10,6 +11,12 @@ export type BaseFields = { [key: string]: FieldTypeFunc; }; +export type FilterOrderArgs = { + context: KeystoneContext; + session: KeystoneContext['session']; + listKey: string; + fieldKey: string; +}; export type CommonFieldConfig = { access?: FieldAccessControl; hooks?: FieldHooks; @@ -35,6 +42,6 @@ export type CommonFieldConfig MaybePromise); + isOrderable?: boolean | ((args: FilterOrderArgs) => MaybePromise); }; diff --git a/packages/keystone/src/types/config/lists.ts b/packages/keystone/src/types/config/lists.ts index fc144bf6066..ee29ca3e284 100644 --- a/packages/keystone/src/types/config/lists.ts +++ b/packages/keystone/src/types/config/lists.ts @@ -2,7 +2,7 @@ import type { CacheHint } from 'apollo-server-types'; import type { BaseGeneratedListTypes, MaybePromise } from '../utils'; import type { ListHooks } from './hooks'; import type { ListAccessControl } from './access-control'; -import type { BaseFields } from './fields'; +import type { BaseFields, FilterOrderArgs } from './fields'; export type ListSchemaConfig = Record< string, @@ -51,8 +51,8 @@ export type ListConfig< description?: string; // defaults both { adminUI: { description }, graphQL: { description } } // Defaults to apply to all fields. - defaultIsFilterable?: true; // The default value to use for graphql.isEnabled.filter on all fields for this list - defaultIsOrderable?: true; // The default value to use for graphql.isEnabled.orderBy on all fields for this list + defaultIsFilterable?: true | ((args: FilterOrderArgs) => MaybePromise); // The default value to use for graphql.isEnabled.filter on all fields for this list + defaultIsOrderable?: true | ((args: FilterOrderArgs) => MaybePromise); // The default value to use for graphql.isEnabled.orderBy on all fields for this list /** * The label used for the list diff --git a/tests/api-tests/queries/filters.test.ts b/tests/api-tests/queries/filters.test.ts index 044565eab60..2ec9720b6dd 100644 --- a/tests/api-tests/queries/filters.test.ts +++ b/tests/api-tests/queries/filters.test.ts @@ -1,7 +1,13 @@ -import { text, relationship } from '@keystone-next/keystone/fields'; +import { text, relationship, integer } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; -import { apiTestConfig, expectBadUserInput } from '../utils'; +import { KeystoneContext } from '@keystone-next/keystone/types'; +import { + apiTestConfig, + expectBadUserInput, + expectGraphQLValidationError, + expectInternalServerError, +} from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -13,18 +19,79 @@ const runner = setupTestRunner({ many_many_many_dashes: text({ isFilterable: true }), multi____dash: text({ isFilterable: true }), email: text({ isIndexed: 'unique', isFilterable: true }), + + filterFalse: integer({ isFilterable: false }), + filterTrue: integer({ isFilterable: true }), + filterFunctionFalse: integer({ isFilterable: () => false }), + filterFunctionTrue: integer({ isFilterable: () => true }), + // @ts-ignore + filterFunctionOtherFalsey: integer({ isFilterable: () => null }), + // @ts-ignore + filterFunctionOtherTruthy: integer({ isFilterable: () => ({}) }), }, }), SecondaryList: list({ fields: { + filterFunctionFalse: integer({ isFilterable: () => false }), someUser: relationship({ ref: 'User', isFilterable: true }), otherUsers: relationship({ ref: 'User', isFilterable: true, many: true }), }, }), + + DefaultFilterUndefined: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + }), + DefaultFilterFalse: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + // @ts-ignore + defaultIsFilterable: false, + }), + DefaultFilterTrue: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + defaultIsFilterable: true, + }), + DefaultFilterFunctionFalse: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + defaultIsFilterable: () => false, + }), + DefaultFilterFunctionTrue: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + defaultIsFilterable: () => true, + }), + DefaultFilterFunctionFalsey: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + // @ts-ignore + defaultIsFilterable: () => null, + }), + DefaultFilterFunctionTruthy: list({ + fields: { a: integer(), b: integer({ isFilterable: true }) }, + // @ts-ignore + defaultIsFilterable: () => ({}), + }), }, }), }); +const initialiseData = async ({ context }: { context: KeystoneContext }) => { + // Use shuffled data to ensure that ordering is actually happening. + for (const listKey of Object.keys(context.lists)) { + if (listKey === 'User' || listKey === 'SecondaryList') continue; + await context.lists[listKey].createMany({ + data: [ + { a: 1, b: 10 }, + { a: 1, b: 30 }, + { a: 1, b: 20 }, + { a: 3, b: 30 }, + { a: 3, b: 10 }, + { a: 3, b: 20 }, + { a: 2, b: 30 }, + { a: 2, b: 20 }, + { a: 2, b: 10 }, + ], + }); + } +}; + describe('filtering on field name', () => { test( 'filter works when there is no dash in field name', @@ -188,3 +255,222 @@ describe('searching by unique fields', () => { }) ); }); + +describe('isFilterable', () => { + test( + 'isFilterable: false', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ users(where: { filterFalse: { equals: 10 } }) { id } }', + }); + expectGraphQLValidationError(body.errors, [ + { + message: + 'Field "filterFalse" is not defined by type "UserWhereInput". Did you mean "filterTrue"?', + }, + ]); + }) + ); + + test( + 'isFilterable: true', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ users(where: { filterTrue: { equals: 10 } }) { id } }', + }); + expect(body.data.users).toHaveLength(0); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'isFilterable: () => false', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ users(where: { filterFunctionFalse: { equals: 10 } }) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'You do not have access to perform \'filter\' operations on the fields ["User.filterFunctionFalse"].', + }, + ]); + }) + ); + + test( + 'isFilterable: () => true', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ users(where: { filterFunctionTrue: { equals: 10 } }) { id } }', + }); + expect(body.data.users).toHaveLength(0); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'isFilterable: () => null', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ users(where: { filterFunctionOtherFalsey: { equals: 10 } }) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'Must return a Boolean from User.filterFunctionOtherFalsey.isFilterable(). Got object', + }, + ]); + }) + ); + + test( + 'isFilterable: () => ({})', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ users(where: { filterFunctionOtherTruthy: { equals: 10 } }) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'Must return a Boolean from User.filterFunctionOtherTruthy.isFilterable(). Got object', + }, + ]); + }) + ); + + test( + 'isFilterable: multiple () => false', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: `{ secondaryLists(where: { + OR: [ + { filterFunctionFalse: { gt: 10 } } + { filterFunctionFalse: { lt: 20 } } + { someUser: { filterFunctionFalse: { equals: 10 } } } + ] + } ) { id } }`, + }); + expect(body.data).toEqual({ secondaryLists: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['secondaryLists'], + message: + 'You do not have access to perform \'filter\' operations on the fields ["SecondaryList.filterFunctionFalse","User.filterFunctionFalse"].', + }, + ]); + }) + ); +}); + +describe('defaultIsFilterable', () => { + test( + 'defaultIsFilterable: undefined', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ defaultFilterUndefineds(where: { a: { equals: 10 } }) { id } }', + }); + expectGraphQLValidationError(body.errors, [ + { + message: + 'Field "a" is not defined by type "DefaultFilterUndefinedWhereInput". Did you mean "b"?', + }, + ]); + }) + ); + + test( + 'defaultIsFilterable: false', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ defaultFilterFalses(where: { a: { equals: 10 } }) { id } }', + }); + expectGraphQLValidationError(body.errors, [ + { + message: + 'Field "a" is not defined by type "DefaultFilterFalseWhereInput". Did you mean "b"?', + }, + ]); + }) + ); + + test( + 'defaultIsFilterable: true', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ defaultFilterTrues(where: { a: { equals: 10 } }) { id } }', + }); + expect(body.data.defaultFilterTrues).toHaveLength(0); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'defaultIsFilterable: () => false', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ defaultFilterFunctionFalses(where: { a: { equals: 10 } }) { id } }', + }); + expect(body.data).toEqual({ defaultFilterFunctionFalses: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['defaultFilterFunctionFalses'], + message: + 'You do not have access to perform \'filter\' operations on the fields ["DefaultFilterFunctionFalse.a"].', + }, + ]); + }) + ); + + test( + 'defaultIsFilterable: () => true', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultFilterFunctionTrues(where: { a: { equals: 10 } }) { id } }', + }); + expect(body.data.defaultFilterFunctionTrues).toHaveLength(0); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'defaultIsFilterable: () => null', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ defaultFilterFunctionFalseys(where: { a: { equals: 10 } }) { id } }', + }); + expect(body.data).toEqual({ defaultFilterFunctionFalseys: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['defaultFilterFunctionFalseys'], + message: + 'Must return a Boolean from DefaultFilterFunctionFalsey.a.isFilterable(). Got object', + }, + ]); + }) + ); + + test( + 'defaultIsFilterable: () => ({})', + runner(async ({ graphQLRequest }) => { + const { body } = await graphQLRequest({ + query: '{ defaultFilterFunctionTruthies(where: { a: { equals: 10 } }) { id } }', + }); + expect(body.data).toEqual({ defaultFilterFunctionTruthies: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['defaultFilterFunctionTruthies'], + message: + 'Must return a Boolean from DefaultFilterFunctionTruthy.a.isFilterable(). Got object', + }, + ]); + }) + ); +}); diff --git a/tests/api-tests/queries/orderBy.test.ts b/tests/api-tests/queries/orderBy.test.ts index 349cf29358e..75c66a1c11b 100644 --- a/tests/api-tests/queries/orderBy.test.ts +++ b/tests/api-tests/queries/orderBy.test.ts @@ -2,7 +2,12 @@ import { integer } from '@keystone-next/keystone/fields'; import { list } from '@keystone-next/keystone'; import { setupTestRunner } from '@keystone-next/keystone/testing'; import { KeystoneContext } from '@keystone-next/keystone/types'; -import { apiTestConfig, expectBadUserInput } from '../utils'; +import { + apiTestConfig, + expectBadUserInput, + expectGraphQLValidationError, + expectInternalServerError, +} from '../utils'; const runner = setupTestRunner({ config: apiTestConfig({ @@ -11,27 +16,66 @@ const runner = setupTestRunner({ fields: { a: integer({ isOrderable: true }), b: integer({ isOrderable: true }), + orderFalse: integer({ isOrderable: false }), + orderTrue: integer({ isOrderable: true }), + orderFunctionFalse: integer({ isOrderable: () => false }), + orderFunctionTrue: integer({ isOrderable: () => true }), + // @ts-ignore + orderFunctionOtherFalsey: integer({ isOrderable: () => null }), + // @ts-ignore + orderFunctionOtherTruthy: integer({ isOrderable: () => ({}) }), + orderFunctionFalseToo: integer({ isOrderable: () => false }), }, }), + DefaultOrderUndefined: list({ fields: { a: integer(), b: integer({ isOrderable: true }) } }), + DefaultOrderFalse: list({ + fields: { a: integer(), b: integer({ isOrderable: true }) }, + // @ts-ignore + defaultIsOrderable: false, + }), + DefaultOrderTrue: list({ + fields: { a: integer(), b: integer({ isOrderable: true }) }, + defaultIsOrderable: true, + }), + DefaultOrderFunctionFalse: list({ + fields: { a: integer(), b: integer({ isOrderable: true }) }, + defaultIsOrderable: () => false, + }), + DefaultOrderFunctionTrue: list({ + fields: { a: integer(), b: integer({ isOrderable: true }) }, + defaultIsOrderable: () => true, + }), + DefaultOrderFunctionFalsey: list({ + fields: { a: integer(), b: integer({ isOrderable: true }) }, + // @ts-ignore + defaultIsOrderable: () => null, + }), + DefaultOrderFunctionTruthy: list({ + fields: { a: integer(), b: integer({ isOrderable: true }) }, + // @ts-ignore + defaultIsOrderable: () => ({}), + }), }, }), }); const initialiseData = async ({ context }: { context: KeystoneContext }) => { // Use shuffled data to ensure that ordering is actually happening. - await context.lists.User.createMany({ - data: [ - { a: 1, b: 10 }, - { a: 1, b: 30 }, - { a: 1, b: 20 }, - { a: 3, b: 30 }, - { a: 3, b: 10 }, - { a: 3, b: 20 }, - { a: 2, b: 30 }, - { a: 2, b: 20 }, - { a: 2, b: 10 }, - ], - }); + for (const listKey of Object.keys(context.lists)) { + await context.lists[listKey].createMany({ + data: [ + { a: 1, b: 10 }, + { a: 1, b: 30 }, + { a: 1, b: 20 }, + { a: 3, b: 30 }, + { a: 3, b: 10 }, + { a: 3, b: 20 }, + { a: 2, b: 30 }, + { a: 2, b: 20 }, + { a: 2, b: 10 }, + ], + }); + } }; describe('Ordering by a single field', () => { @@ -76,7 +120,9 @@ describe('Ordering by a single field', () => { expect(users.map(({ a }) => a)).toEqual([1, 1, 1, 2, 2, 2, 3, 3, 3]); }) ); +}); +describe('Ordering by Multiple', () => { test( 'Multi ascending/ascending filter - a,b ', runner(async ({ context }) => { @@ -294,3 +340,230 @@ describe('Ordering by a single field', () => { }) ); }); + +describe('isOrderable', () => { + test( + 'isOrderable: false', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ users(orderBy: [{orderFalse: asc}]) { id } }', + }); + expectGraphQLValidationError(body.errors, [ + { + message: + 'Field "orderFalse" is not defined by type "UserOrderByInput". Did you mean "orderTrue"?', + }, + ]); + }) + ); + + test( + 'isOrderable: true', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ users(orderBy: [{orderTrue: asc}]) { id } }', + }); + expect(body.data.users).toHaveLength(9); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'isOrderable: () => false', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ users(orderBy: [{orderFunctionFalse: asc}]) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'You do not have access to perform \'orderBy\' operations on the fields ["User.orderFunctionFalse"].', + }, + ]); + }) + ); + + test( + 'isOrderable: () => true', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ users(orderBy: [{orderFunctionTrue: asc}]) { id } }', + }); + expect(body.data.users).toHaveLength(9); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'isOrderable: () => null', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ users(orderBy: [{orderFunctionOtherFalsey: asc}]) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'Must return a Boolean from User.orderFunctionOtherFalsey.isOrderable(). Got object', + }, + ]); + }) + ); + + test( + 'isOrderable: () => ({})', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ users(orderBy: [{orderFunctionOtherTruthy: asc}]) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'Must return a Boolean from User.orderFunctionOtherTruthy.isOrderable(). Got object', + }, + ]); + }) + ); + + test( + 'isOrderable: multiple () => false', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: + '{ users(orderBy: [{orderFunctionTrue: asc}, {orderFunctionFalse: asc}, {orderFunctionFalseToo: asc}]) { id } }', + }); + expect(body.data).toEqual({ users: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['users'], + message: + 'You do not have access to perform \'orderBy\' operations on the fields ["User.orderFunctionFalse","User.orderFunctionFalseToo"].', + }, + ]); + }) + ); +}); + +describe('defaultIsOrderable', () => { + test( + 'defaultIsOrderable: undefined', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderUndefineds(orderBy: [{a: asc}]) { id } }', + }); + expectGraphQLValidationError(body.errors, [ + { + message: + 'Field "a" is not defined by type "DefaultOrderUndefinedOrderByInput". Did you mean "b"?', + }, + ]); + }) + ); + + test( + 'defaultIsOrderable: false', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderFalses(orderBy: [{a: asc}]) { id } }', + }); + expectGraphQLValidationError(body.errors, [ + { + message: + 'Field "a" is not defined by type "DefaultOrderFalseOrderByInput". Did you mean "b"?', + }, + ]); + }) + ); + + test( + 'defaultIsOrderable: true', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderTrues(orderBy: [{a: asc}]) { id } }', + }); + expect(body.data.defaultOrderTrues).toHaveLength(9); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'defaultIsOrderable: () => false', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderFunctionFalses(orderBy: [{a: asc}]) { id } }', + }); + expect(body.data).toEqual({ defaultOrderFunctionFalses: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['defaultOrderFunctionFalses'], + message: + 'You do not have access to perform \'orderBy\' operations on the fields ["DefaultOrderFunctionFalse.a"].', + }, + ]); + }) + ); + + test( + 'defaultIsOrderable: () => true', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderFunctionTrues(orderBy: [{a: asc}]) { id } }', + }); + expect(body.data.defaultOrderFunctionTrues).toHaveLength(9); + expect(body.errors).toBe(undefined); + }) + ); + + test( + 'defaultIsOrderable: () => null', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderFunctionFalseys(orderBy: [{a: asc}]) { id } }', + }); + expect(body.data).toEqual({ defaultOrderFunctionFalseys: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['defaultOrderFunctionFalseys'], + message: + 'Must return a Boolean from DefaultOrderFunctionFalsey.a.isOrderable(). Got object', + }, + ]); + }) + ); + + test( + 'defaultIsOrderable: () => ({})', + runner(async ({ context, graphQLRequest }) => { + await initialiseData({ context }); + const { body } = await graphQLRequest({ + query: '{ defaultOrderFunctionTruthies(orderBy: [{a: asc}]) { id } }', + }); + expect(body.data).toEqual({ defaultOrderFunctionTruthies: null }); + expectInternalServerError(body.errors, false, [ + { + path: ['defaultOrderFunctionTruthies'], + message: + 'Must return a Boolean from DefaultOrderFunctionTruthy.a.isOrderable(). Got object', + }, + ]); + }) + ); +}); From 9b7ff66d58ba3f64b06cffebe8c9f3457288eba1 Mon Sep 17 00:00:00 2001 From: Tim Leslie Date: Fri, 17 Sep 2021 13:30:02 +1000 Subject: [PATCH 059/135] Remove unused arguments to expectAccessDenied (#6590) --- .../access-control/field-access.test.ts | 4 +- .../access-control/list-access.test.ts | 52 +++++++++---------- .../access-control/mutations-field.test.ts | 14 ++--- .../mutations-list-filter.test.ts | 14 ++--- .../mutations-list-item.test.ts | 21 +++----- tests/api-tests/auth-header.test.ts | 2 +- tests/api-tests/utils.ts | 25 +-------- 7 files changed, 44 insertions(+), 88 deletions(-) diff --git a/tests/api-tests/access-control/field-access.test.ts b/tests/api-tests/access-control/field-access.test.ts index 7f310ceeefb..75274065c72 100644 --- a/tests/api-tests/access-control/field-access.test.ts +++ b/tests/api-tests/access-control/field-access.test.ts @@ -87,7 +87,7 @@ describe(`Field access`, () => { const { data, errors } = await context.graphql.raw({ query }); if (!access.create) { expect(data).toEqual({ [createMutationName]: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: [createMutationName] }]); + expectAccessDenied(errors, [{ path: [createMutationName] }]); } else { expect(errors).toBe(undefined); if (access.query) { @@ -116,7 +116,7 @@ describe(`Field access`, () => { const { data, errors } = await context.graphql.raw({ query }); if (!access.update) { expect(data).toEqual({ [updateMutationName]: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: [updateMutationName] }]); + expectAccessDenied(errors, [{ path: [updateMutationName] }]); } else { expect(errors).toBe(undefined); if (access.query) { diff --git a/tests/api-tests/access-control/list-access.test.ts b/tests/api-tests/access-control/list-access.test.ts index 5c48f173de1..0d454ff72b4 100644 --- a/tests/api-tests/access-control/list-access.test.ts +++ b/tests/api-tests/access-control/list-access.test.ts @@ -17,21 +17,19 @@ import { const expectNoAccess = ( data: Record | null | undefined, errors: readonly GraphQLError[] | undefined, - name: N, - httpQuery: boolean + name: N ) => { expect(data?.[name]).toBe(null); - expectAccessDenied('dev', httpQuery, undefined, errors, [{ path: [name] }]); + expectAccessDenied(errors, [{ path: [name] }]); }; const expectNoAccessMany = ( data: Record | null | undefined, errors: readonly GraphQLError[] | undefined, - name: N, - httpQuery: boolean + name: N ) => { expect(data?.[name]).toEqual([null]); - expectAccessDenied('dev', httpQuery, undefined, errors, [{ path: [name, 0] }]); + expectAccessDenied(errors, [{ path: [name, 0] }]); }; type IdType = any; @@ -78,7 +76,7 @@ describe(`List access`, () => { const query = `mutation { ${createMutationName}(data: { name: "bar" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.create) { - expectNoAccess(data, errors, createMutationName, false); + expectNoAccess(data, errors, createMutationName); } else { expect(errors).toBe(undefined); expect(data![createMutationName]).not.toEqual(null); @@ -93,7 +91,7 @@ describe(`List access`, () => { const query = `mutation { ${createMutationName}(data: [{ name: "bar" }]) { id } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.create) { - expectNoAccessMany(data, errors, createMutationName, false); + expectNoAccessMany(data, errors, createMutationName); } else { expect(errors).toBe(undefined); expect(data![createMutationName]).not.toEqual(null); @@ -248,7 +246,7 @@ describe(`List access`, () => { const updateMutationName = `update${nameFn[mode](access)}`; const query = `mutation { ${updateMutationName}(where: { id: "${FAKE_ID}" }, data: { name: "bar" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); - expectNoAccess(data, errors, updateMutationName, false); + expectNoAccess(data, errors, updateMutationName); }); }); }); @@ -262,7 +260,7 @@ describe(`List access`, () => { const query = `mutation { ${updateMutationName}(where: { id: "${item.id}" }, data: { name: "bar" }) { id name } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.update) { - expectNoAccess(data, errors, updateMutationName, false); + expectNoAccess(data, errors, updateMutationName); } else { expect(errors).toBe(undefined); expect(data![updateMutationName]).toEqual({ id: item.id, name: 'bar' }); @@ -276,7 +274,7 @@ describe(`List access`, () => { const query = `mutation { ${updateMutationName}(data: [{ where: { id: "${item.id}" }, data: { name: "bar" } }]) { id name } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.update) { - expectNoAccessMany(data, errors, updateMutationName, false); + expectNoAccessMany(data, errors, updateMutationName); } else { expect(errors).toBe(undefined); expect(data![updateMutationName]).toEqual([{ id: item.id, name: 'bar' }]); @@ -302,17 +300,17 @@ describe(`List access`, () => { const query = `mutation { ${updateMutationName}(where: { id: "${item1.id}" }, data: { name: "bar" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.update) { - expectNoAccess(data, errors, updateMutationName, false); + expectNoAccess(data, errors, updateMutationName); } else { // Filtered out - expectNoAccess(data, errors, updateMutationName, false); + expectNoAccess(data, errors, updateMutationName); } await context.sudo().lists[nameFn[mode](access)].deleteOne({ where: { id: item1.id } }); const _query = `mutation { ${updateMutationName}(where: { id: "${item2.id}" }, data: { name: "bar" }) { id } }`; const result = await context.graphql.raw({ query: _query }); if (!access.update) { - expectNoAccess(result.data, result.errors, updateMutationName, false); + expectNoAccess(result.data, result.errors, updateMutationName); } else { // Filtered in expect(result.errors).toBe(undefined); @@ -332,17 +330,17 @@ describe(`List access`, () => { const query = `mutation { ${updateMutationName}(data: [{ where: { id: "${item1.id}" }, data: { name: "bar" } }]) { id } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.update) { - expectNoAccessMany(data, errors, updateMutationName, false); + expectNoAccessMany(data, errors, updateMutationName); } else { // Filtered out - expectNoAccessMany(data, errors, updateMutationName, false); + expectNoAccessMany(data, errors, updateMutationName); } await context.sudo().lists[nameFn[mode](access)].deleteOne({ where: { id: item1.id } }); const _query = `mutation { ${updateMutationName}(data: [{ where: { id: "${item2.id}" }, data: { name: "bar" } }]) { id } }`; const result = await context.graphql.raw({ query: _query }); if (!access.update) { - expectNoAccessMany(result.data, result.errors, updateMutationName, false); + expectNoAccessMany(result.data, result.errors, updateMutationName); } else { // Filtered in expect(result.errors).toBe(undefined); @@ -363,13 +361,13 @@ describe(`List access`, () => { const deleteMutationName = `delete${nameFn[mode](access)}`; const query = `mutation { ${deleteMutationName}(where: { id: "${FAKE_ID}" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); - expectNoAccess(data, errors, deleteMutationName, false); + expectNoAccess(data, errors, deleteMutationName); }); test(`multi denies missing: ${JSON.stringify(access)}`, async () => { const multiDeleteMutationName = `delete${nameFn[mode](access)}s`; const query = `mutation { ${multiDeleteMutationName}(where: [{ id: "${FAKE_ID}" }, { id: "${FAKE_ID_2}" }]) { id } }`; const { data, errors } = await context.graphql.raw({ query }); - expectAccessDenied('dev', false, undefined, errors, [ + expectAccessDenied(errors, [ { path: [multiDeleteMutationName, 0] }, { path: [multiDeleteMutationName, 1] }, ]); @@ -390,7 +388,7 @@ describe(`List access`, () => { const { data, errors } = await context.graphql.raw({ query }); if (!access.delete) { - expectNoAccess(data, errors, deleteMutationName, false); + expectNoAccess(data, errors, deleteMutationName); } else { expect(errors).toBe(undefined); expect(data![deleteMutationName]).not.toEqual(null); @@ -410,7 +408,7 @@ describe(`List access`, () => { const { data, errors } = await context.graphql.raw({ query }); if (!access.delete) { - expectNoAccessMany(data, errors, multiDeleteMutationName, false); + expectNoAccessMany(data, errors, multiDeleteMutationName); } else { expect(errors).toBe(undefined); expect(data![multiDeleteMutationName]).not.toEqual(null); @@ -440,10 +438,10 @@ describe(`List access`, () => { const query = `mutation { ${deleteMutationName}(where: {id: "${item1.id}" }) { id } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.delete) { - expectNoAccess(data, errors, deleteMutationName, false); + expectNoAccess(data, errors, deleteMutationName); } else { // Filtered out - expectNoAccess(data, errors, deleteMutationName, false); + expectNoAccess(data, errors, deleteMutationName); } if (!access.delete) { @@ -455,7 +453,7 @@ describe(`List access`, () => { const _query = `mutation { ${deleteMutationName}(where: {id: "${item2.id}" }) { id } }`; const result = await context.graphql.raw({ query: _query }); if (!access.delete) { - expectNoAccess(result.data, result.errors, deleteMutationName, false); + expectNoAccess(result.data, result.errors, deleteMutationName); } else { // Filtered in expect(result.errors).toBe(undefined); @@ -481,10 +479,10 @@ describe(`List access`, () => { const query = `mutation { ${multiDeleteMutationName}(where: [{ id: "${item1.id}" }]) { id } }`; const { data, errors } = await context.graphql.raw({ query }); if (!access.delete) { - expectNoAccessMany(data, errors, multiDeleteMutationName, false); + expectNoAccessMany(data, errors, multiDeleteMutationName); } else { // Filtered out - expectNoAccessMany(data, errors, multiDeleteMutationName, false); + expectNoAccessMany(data, errors, multiDeleteMutationName); } if (!access.delete) { await context @@ -495,7 +493,7 @@ describe(`List access`, () => { const _query = `mutation { ${multiDeleteMutationName}(where: [{ id: "${item2.id}" }]) { id } }`; const result = await context.graphql.raw({ query: _query }); if (!access.delete) { - expectNoAccessMany(result.data, result.errors, multiDeleteMutationName, false); + expectNoAccessMany(result.data, result.errors, multiDeleteMutationName); } else { // Filtered in expect(result.errors).toBe(undefined); diff --git a/tests/api-tests/access-control/mutations-field.test.ts b/tests/api-tests/access-control/mutations-field.test.ts index e19f24c348b..81daabbd2db 100644 --- a/tests/api-tests/access-control/mutations-field.test.ts +++ b/tests/api-tests/access-control/mutations-field.test.ts @@ -83,7 +83,7 @@ describe('Access control', () => { // Returns null and throws an error expect(data).toEqual({ createUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['createUser'] }]); + expectAccessDenied(errors, [{ path: ['createUser'] }]); // Only the original user should exist const _users = await context.lists.User.findMany({ query: 'id name other' }); @@ -138,7 +138,7 @@ describe('Access control', () => { // Returns null and throws an error expect(data).toEqual({ updateUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['updateUser'] }]); + expectAccessDenied(errors, [{ path: ['updateUser'] }]); // User should have its original name const _users = await context.lists.User.findMany({ query: 'id name other' }); @@ -208,10 +208,7 @@ describe('Access control', () => { }); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['createUsers', 1] }, - { path: ['createUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['createUsers', 1] }, { path: ['createUsers', 3] }]); // Valid users should exist in the database const users = await context.lists.User.findMany({ @@ -264,10 +261,7 @@ describe('Access control', () => { }); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['updateUsers', 1] }, - { path: ['updateUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['updateUsers', 1] }, { path: ['updateUsers', 3] }]); // All users should still exist in the database const _users = await context.lists.User.findMany({ diff --git a/tests/api-tests/access-control/mutations-list-filter.test.ts b/tests/api-tests/access-control/mutations-list-filter.test.ts index 3c50df09187..a6d7b72a107 100644 --- a/tests/api-tests/access-control/mutations-list-filter.test.ts +++ b/tests/api-tests/access-control/mutations-list-filter.test.ts @@ -40,7 +40,7 @@ describe('Access control - Filter', () => { // Returns null and throws an error expect(data).toEqual({ updateUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['updateUser'] }]); + expectAccessDenied(errors, [{ path: ['updateUser'] }]); // User should have its original name const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -64,7 +64,7 @@ describe('Access control - Filter', () => { // Returns null and throws an error expect(data).toEqual({ deleteUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['deleteUser'] }]); + expectAccessDenied(errors, [{ path: ['deleteUser'] }]); // Bad users should still be in the database. const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -118,10 +118,7 @@ describe('Access control - Filter', () => { null, ], }); - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['updateUsers', 1] }, - { path: ['updateUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['updateUsers', 1] }, { path: ['updateUsers', 3] }]); // All users should still exist in the database const _users = await context.lists.User.findMany({ @@ -161,10 +158,7 @@ describe('Access control - Filter', () => { }, }); - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['deleteUsers', 1] }, - { path: ['deleteUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['deleteUsers', 1] }, { path: ['deleteUsers', 3] }]); // Valid users are returned, invalid come back as null // The invalid deletes should have errors which point to the nulls in their path diff --git a/tests/api-tests/access-control/mutations-list-item.test.ts b/tests/api-tests/access-control/mutations-list-item.test.ts index 21acf7c35b6..8ab8f5510b5 100644 --- a/tests/api-tests/access-control/mutations-list-item.test.ts +++ b/tests/api-tests/access-control/mutations-list-item.test.ts @@ -61,7 +61,7 @@ describe('Access control - Item', () => { // Returns null and throws an error expect(data).toEqual({ createUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['createUser'] }]); + expectAccessDenied(errors, [{ path: ['createUser'] }]); // Only the original user should exist const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -108,7 +108,7 @@ describe('Access control - Item', () => { // Returns null and throws an error expect(data).toEqual({ updateUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['updateUser'] }]); + expectAccessDenied(errors, [{ path: ['updateUser'] }]); // User should have its original name const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -158,7 +158,7 @@ describe('Access control - Item', () => { // Returns null and throws an error expect(data).toEqual({ deleteUser: null }); - expectAccessDenied('dev', false, undefined, errors, [{ path: ['deleteUser'] }]); + expectAccessDenied(errors, [{ path: ['deleteUser'] }]); // Bad users should still be in the database. const _users = await context.lists.User.findMany({ query: 'id name' }); @@ -221,10 +221,7 @@ describe('Access control - Item', () => { }); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['createUsers', 1] }, - { path: ['createUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['createUsers', 1] }, { path: ['createUsers', 3] }]); // The good users should exist in the database const users = await context.lists.User.findMany(); @@ -272,10 +269,7 @@ describe('Access control - Item', () => { ]); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['updateUsers', 1] }, - { path: ['updateUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['updateUsers', 1] }, { path: ['updateUsers', 3] }]); // All users should still exist in the database const _users = await context.lists.User.findMany({ @@ -324,10 +318,7 @@ describe('Access control - Item', () => { ]); // The invalid updates should have errors which point to the nulls in their path - expectAccessDenied('dev', false, undefined, errors, [ - { path: ['deleteUsers', 1] }, - { path: ['deleteUsers', 3] }, - ]); + expectAccessDenied(errors, [{ path: ['deleteUsers', 1] }, { path: ['deleteUsers', 3] }]); const _users = await context.lists.User.findMany({ orderBy: { name: 'asc' }, diff --git a/tests/api-tests/auth-header.test.ts b/tests/api-tests/auth-header.test.ts index 46634f7ded6..7c794ce10b7 100644 --- a/tests/api-tests/auth-header.test.ts +++ b/tests/api-tests/auth-header.test.ts @@ -91,7 +91,7 @@ describe('Auth testing', () => { query: `mutation { updateUser(where: { email: "boris@keystone.com" }, data: { password: "new_password" }) { id } }`, }); expect(result.data).toEqual({ updateUser: null }); - expectAccessDenied('dev', false, undefined, result.errors, [{ path: ['updateUser'] }]); + expectAccessDenied(result.errors, [{ path: ['updateUser'] }]); }) ); diff --git a/tests/api-tests/utils.ts b/tests/api-tests/utils.ts index 9a279e95d82..204f6c08a64 100644 --- a/tests/api-tests/utils.ts +++ b/tests/api-tests/utils.ts @@ -55,38 +55,17 @@ export const expectGraphQLValidationError = ( }; export const expectAccessDenied = ( - mode: 'dev' | 'production', - httpQuery: boolean, - _debug: boolean | undefined, errors: readonly any[] | undefined, args: { path: (string | number)[] }[] ) => { const unpackedErrors = (errors || []).map(({ locations, ...unpacked }) => ({ ...unpacked, })); - const message = 'You do not have access to this resource'; - // We expect to see debug details if: - // - httpQuery is false - // - graphql.debug is true or - // - graphql.debug is undefined and mode !== production or - // const expectDebug = - // _debug === true || (_debug === undefined && mode !== 'production') || !httpQuery; - // We expect to see the Apollo exception under the same conditions, but only if - // httpQuery is also true. - const expectException = false; - // httpQuery && expectDebug; - // console.log({ expectDebug, httpQuery, expectException }); - expect(unpackedErrors).toEqual( args.map(({ path }) => ({ - extensions: { - code: httpQuery ? 'INTERNAL_SERVER_ERROR' : undefined, - ...(expectException - ? { exception: { stacktrace: expect.arrayContaining([`Error: ${message}`]) } } - : {}), - }, + extensions: { code: undefined }, path, - message, + message: 'You do not have access to this resource', })) ); }; From 8bbba49c74fd4b7cf2560613c9cf6bcaddb11a6f Mon Sep 17 00:00:00 2001 From: Mitchell Hamilton Date: Fri, 17 Sep 2021 13:59:32 +1000 Subject: [PATCH 060/135] Fix dynamic isFilterable/isOrderable in the Admin UI (#6587) --- .changeset/cool-geese-live.md | 5 ++ .changeset/kind-socks-drop.md | 5 ++ .../admin-ui/pages/ListPage/FilterAdd.tsx | 24 +++++++-- .../admin-ui/pages/ListPage/SortSelection.tsx | 26 +++++++--- .../admin-ui/pages/ListPage/index.tsx | 50 ++++++++++++++----- .../admin-ui/pages/ListPage/useFilters.tsx | 6 +-- .../admin-ui/pages/ListPage/useSort.tsx | 13 +++-- .../src/admin-ui/admin-meta-graphql.ts | 4 -- .../src/admin-ui/system/createAdminMeta.ts | 2 - .../src/admin-ui/system/getAdminMetaSchema.ts | 42 +++++++++++++++- packages/keystone/src/testing.ts | 2 +- packages/keystone/src/types/admin-meta.ts | 4 -- .../api-tests/access-control/schema-utils.ts | 3 ++ tests/api-tests/access-control/schema.test.ts | 7 ++- 14 files changed, 145 insertions(+), 48 deletions(-) create mode 100644 .changeset/cool-geese-live.md create mode 100644 .changeset/kind-socks-drop.md diff --git a/.changeset/cool-geese-live.md b/.changeset/cool-geese-live.md new file mode 100644 index 00000000000..ee9201cb4bc --- /dev/null +++ b/.changeset/cool-geese-live.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': major +--- + +The `KeystoneAdminUIFieldMeta.isOrderable` and `KeystoneAdminUIFieldMeta.isFilterable` fields are no longer statically resolvable and will now take into account the context/session. This also means `isOrderable` and `isFilterable` are no longer accessible on `useList().fields[fieldKey].isOrderable/isFilterable`, they can be fetched through GraphQL if you need them in the Admin UI. diff --git a/.changeset/kind-socks-drop.md b/.changeset/kind-socks-drop.md new file mode 100644 index 00000000000..7489cd1d7f3 --- /dev/null +++ b/.changeset/kind-socks-drop.md @@ -0,0 +1,5 @@ +--- +'@keystone-next/keystone': patch +--- + +Fixed `@keystone-next/keystone/testing` not respecting Admin UI config diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FilterAdd.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FilterAdd.tsx index 0859f77a610..90c527f8921 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FilterAdd.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/FilterAdd.tsx @@ -41,7 +41,13 @@ const fieldSelectComponents: ComponentProps['components'] = { ); }, }; -export function FilterAdd({ listKey }: { listKey: string }) { +export function FilterAdd({ + listKey, + filterableFields, +}: { + listKey: string; + filterableFields: Set; +}) { const { isOpen, setOpen, trigger, dialog, arrow } = usePopover({ placement: 'bottom', modifiers: [{ name: 'offset', options: { offset: [0, 8] } }], @@ -74,6 +80,7 @@ export function FilterAdd({ listKey }: { listKey: string }) { setOpen(false); }} listKey={listKey} + filterableFields={filterableFields} /> )} @@ -81,7 +88,15 @@ export function FilterAdd({ listKey }: { listKey: string }) { ); } -function FilterAddPopoverContent({ onClose, listKey }: { onClose: () => void; listKey: string }) { +function FilterAddPopoverContent({ + onClose, + listKey, + filterableFields, +}: { + onClose: () => void; + listKey: string; + filterableFields: Set; +}) { const list = useList(listKey); const router = useRouter(); const fieldsWithFilters = useMemo(() => { @@ -91,13 +106,12 @@ function FilterAddPopoverContent({ onClose, listKey }: { onClose: () => void; li > = {}; Object.keys(list.fields).forEach(fieldPath => { const field = list.fields[fieldPath]; - if (field.isFilterable && field.controller.filter) { - // TODO: make all the things readonly so this works + if (filterableFields.has(fieldPath) && field.controller.filter) { fieldsWithFilters[fieldPath] = field as any; } }); return fieldsWithFilters; - }, [list.fields]); + }, [list.fields, filterableFields]); const filtersByFieldThenType = useMemo(() => { const filtersByFieldThenType: Record> = {}; Object.keys(fieldsWithFilters).forEach(fieldPath => { diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/SortSelection.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/SortSelection.tsx index 7554b98ffdf..507381e02b3 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/SortSelection.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/SortSelection.tsx @@ -11,8 +11,14 @@ import { useRouter } from '../../../../admin-ui/router'; import { fieldSelectionOptionsComponents } from './FieldSelection'; import { useSort } from './useSort'; -export function SortSelection({ list }: { list: ListMeta }) { - const sort = useSort(list); +export function SortSelection({ + list, + orderableFields, +}: { + list: ListMeta; + orderableFields: Set; +}) { + const sort = useSort(list, orderableFields); const { isOpen, setOpen, trigger, dialog, arrow } = usePopover({ placement: 'bottom', modifiers: [{ name: 'offset', options: { offset: [0, 8] } }], @@ -50,6 +56,7 @@ export function SortSelection({ list }: { list: ListMeta }) { setOpen(false); }} list={list} + orderableFields={orderableFields} /> )} @@ -62,8 +69,16 @@ const noFieldOption = { value: '___________NO_FIELD___________', }; -function SortSelectionPopoverContent({ onClose, list }: { onClose: () => void; list: ListMeta }) { - const sort = useSort(list); +function SortSelectionPopoverContent({ + onClose, + list, + orderableFields, +}: { + onClose: () => void; + list: ListMeta; + orderableFields: Set; +}) { + const sort = useSort(list, orderableFields); const router = useRouter(); return ( @@ -96,8 +111,7 @@ function SortSelectionPopoverContent({ onClose, list }: { onClose: () => void; l onClose(); }} - options={Object.keys(list.fields) - .filter(fieldPath => list.fields[fieldPath].isOrderable) + options={[...orderableFields] .map(fieldPath => ({ label: list.fields[fieldPath].label, value: fieldPath })) .concat(noFieldOption)} /> diff --git a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx index 589cbcc958c..2a99ee1240a 100644 --- a/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx +++ b/packages/keystone/src/___internal-do-not-use-will-break-in-patch/admin-ui/pages/ListPage/index.tsx @@ -35,6 +35,13 @@ import { useSort } from './useSort'; type ListPageProps = { listKey: string }; +type FetchedFieldMeta = { + path: string; + isOrderable: boolean; + isFilterable: boolean; + listView: { fieldMode: 'read' | 'hidden' }; +}; + let listMetaGraphqlQuery: TypedDocumentNode< { keystone: { @@ -42,7 +49,7 @@ let listMetaGraphqlQuery: TypedDocumentNode< list: { hideCreate: boolean; hideDelete: boolean; - fields: { path: string; listView: { fieldMode: 'read' | 'hidden' } }[]; + fields: FetchedFieldMeta[]; } | null; }; }; @@ -57,6 +64,8 @@ let listMetaGraphqlQuery: TypedDocumentNode< hideCreate fields { path + isOrderable + isFilterable listView { fieldMode } @@ -133,20 +142,29 @@ const ListPage = ({ listKey }: ListPageProps) => { ? parseInt(query.pageSize) : list.pageSize; - const sort = useSort(list); - - const filters = useFilters(list); - let metaQuery = useQuery(listMetaGraphqlQuery, { variables: { listKey } }); - let listViewFieldModesByField = useMemo(() => { - let listViewFieldModesByField: Record = {}; - metaQuery.data?.keystone.adminMeta.list?.fields.forEach(field => { + let { listViewFieldModesByField, filterableFields, orderableFields } = useMemo(() => { + const listViewFieldModesByField: Record = {}; + const orderableFields = new Set(); + const filterableFields = new Set(); + for (const field of metaQuery.data?.keystone.adminMeta.list?.fields || []) { listViewFieldModesByField[field.path] = field.listView.fieldMode; - }); - return listViewFieldModesByField; + if (field.isOrderable) { + orderableFields.add(field.path); + } + if (field.isFilterable) { + filterableFields.add(field.path); + } + } + + return { listViewFieldModesByField, orderableFields, filterableFields }; }, [metaQuery.data?.keystone.adminMeta.list?.fields]); + const sort = useSort(list, orderableFields); + + const filters = useFilters(list, filterableFields); + let selectedFields = useSelectedFields(list, listViewFieldModesByField); let { @@ -181,6 +199,7 @@ const ListPage = ({ listKey }: ListPageProps) => { { fetchPolicy: 'cache-and-network', errorPolicy: 'all', + skip: !metaQuery.data, variables: { where: filters.where, take: pageSize, @@ -231,7 +250,9 @@ const ListPage = ({ listKey }: ListPageProps) => { {showCreate && } - {data.count || filters.filters.length ? : null} + {data.count || filters.filters.length ? ( + + ) : null} {filters.filters.length ? : null} {Boolean(Object.keys(query).length) && (