From 83066ee687cffef42f9de6347f53ff727758819f Mon Sep 17 00:00:00 2001 From: J <93984341+VWSCoronaDashboard18@users.noreply.github.com> Date: Fri, 8 Jul 2022 12:02:04 +0200 Subject: [PATCH 01/12] Run the sync-after-release script (#4318) --- packages/cms/src/lokalize/key-mutations.csv | 52 --------------------- 1 file changed, 52 deletions(-) diff --git a/packages/cms/src/lokalize/key-mutations.csv b/packages/cms/src/lokalize/key-mutations.csv index 8872d8e39f..a7c6419a8a 100755 --- a/packages/cms/src/lokalize/key-mutations.csv +++ b/packages/cms/src/lokalize/key-mutations.csv @@ -1,53 +1 @@ timestamp,action,key,document_id,move_to -2022-04-22T08:09:02.839Z,add,common.g_number.bar_chart.legend_inaccurate_label,X8Z1HTDxqJ9pM59362hg1m,__ -2022-04-25T14:25:46.327Z,add,common.charts.time_controls.firstOfSeptember,A5Y41hFe5J3wNnB7O7FFlP,__ -2022-04-25T14:25:47.391Z,add,common.g_number.bar_chart.legend.negative_label,Raj9X55CxrYuKzixU46zrk,__ -2022-04-25T14:25:48.351Z,add,common.g_number.bar_chart.legend.positive_label,X8Z1HTDxqJ9pM59364bIJw,__ -2022-04-25T14:25:48.352Z,move,common.g_number.bar_chart.legend_inaccurate_label,X8Z1HTDxqJ9pM59362hg1m,common.g_number.bar_chart.legend.inaccurate_label -2022-04-26T12:03:58.578Z,move,ic_opnames_per_dag.chart_bedbezetting.description,jF33EuwumlGuwav2FD3WM8,pages.intensiveCarePage.nl.chart_bedbezetting.description -2022-05-03T07:38:37.855Z,add,common.choropleth_tooltip.gm.admissions_on_date_of_admission_per_100000.content,Hx8hkeSw0pqyYojKtfA6sV,__ -2022-05-03T07:38:38.919Z,add,common.choropleth_tooltip.gm.admissions_on_date_of_admission_per_100000.subject,xNELI4GNAeXqkWZzsGHq9R,__ -2022-05-03T07:38:39.890Z,add,common.choropleth_tooltip.vr.admissions_on_date_of_admission_per_100000.content,xNELI4GNAeXqkWZzsGHqv1,__ -2022-05-03T07:38:40.968Z,add,common.choropleth_tooltip.vr.admissions_on_date_of_admission_per_100000.subject,Hx8hkeSw0pqyYojKtfA8KD,__ -2022-05-03T07:38:41.991Z,add,common.common.value_until_value,Hx8hkeSw0pqyYojKtfA8e9,__ -2022-05-03T07:38:42.924Z,add,common.common.value_and_higher,hqivmGf8UPzCLjKFjHM91t,__ -2022-05-03T12:26:14.845Z,add,pages.vaccinationsPage.nl.vaccination_coverage.headers.fully_vaccinated,hqivmGf8UPzCLjKFjHrFoj,__ -2022-05-03T12:26:16.004Z,add,pages.vaccinationsPage.nl.vaccination_coverage.headers.difference_booster_shot_and_fully_vaccinated,xNELI4GNAeXqkWZzsHMnYw,__ -2022-05-03T12:26:17.032Z,add,pages.vaccinationsPage.nl.vaccination_coverage.headers.booster_shot,xNELI4GNAeXqkWZzsHMprg,__ -2022-05-03T12:26:18.031Z,add,pages.vaccinationsPage.nl.vaccination_coverage.toelichting_booster_shot,hqivmGf8UPzCLjKFjHrGgv,__ -2022-05-03T15:21:44.684Z,add,pages.vaccinationsPage.gm.vaccination_coverage.description_booster_and_fully_vaccinated,hqivmGf8UPzCLjKFjIAkJp,__ -2022-05-03T15:21:46.025Z,add,pages.vaccinationsPage.vr.vaccination_coverage.description_booster_and_fully_vaccinated,hqivmGf8UPzCLjKFjIAkSr,__ -2022-05-03T15:21:47.062Z,add,pages.vaccinationsPage.vr.vaccination_coverage.title,xNELI4GNAeXqkWZzsI1aAP,__ -2022-05-04T12:40:09.691Z,add,pages.vaccinationsPage.shared.vaccine_coverage_per_age_group,hqivmGf8UPzCLjKFjK6SXZ,__ -2022-05-05T11:48:10.313Z,add,pages.vaccinationsPage.nl.vaccination_coverage.no_data,hqivmGf8UPzCLjKFjLpCSD,__ -2022-05-05T11:48:10.323Z,delete,pages.vaccinationsPage.shared.vaccine_coverage_per_age_group,hqivmGf8UPzCLjKFjK6SXZ,__ -2022-05-03T14:03:24.707Z,add,common.corona_melder_app.belangrijk_bericht,xNELI4GNAeXqkWZzsHkjJM,__ -2022-05-09T09:27:22.505Z,add,common.choropleth_tooltip.vr.booster_shot_percentage.content,Hx8hkeSw0pqyYojKu0sKeK,__ -2022-05-09T09:27:23.526Z,add,common.choropleth_tooltip.vr.booster_shot_percentage.subject,Hx8hkeSw0pqyYojKu0sKtH,__ -2022-05-09T09:27:24.542Z,add,common.vaccinations.coverage_kinds.booster_shot_percentage,Hx8hkeSw0pqyYojKu0sL8E,__ -2022-05-09T09:27:24.543Z,delete,choropleth_tooltip.vr.booster_shot_percentage.content,ctWR1OtR3Bc4Z1QxETQyT3,__ -2022-05-09T09:27:24.543Z,delete,choropleth_tooltip.vr.booster_shot_percentage.subject,4C4Y1v39Co3s0ZW9zUzEm1,__ -2022-05-09T09:27:24.543Z,move,choropleth_tooltip.gm.booster_shot_percentage.content,VNAGnZtzuWCFY8gXn2zsLa,common.choropleth_tooltip.gm.booster_shot_percentage.content -2022-05-09T09:27:24.544Z,move,choropleth_tooltip.gm.booster_shot_percentage.subject,VNAGnZtzuWCFY8gXn2zsT8,common.choropleth_tooltip.gm.booster_shot_percentage.subject -2022-05-09T08:58:28.088Z,move,accessibility.charts.hospital_admissions_region_choropleth.description,G1DXw0RdifOml06twMjbPq,common.accessibility.charts.hospital_admissions_region_choropleth.description -2022-05-12T07:55:42.658Z,delete,common.charts.time_controls.firstOfSeptember,A5Y41hFe5J3wNnB7O7FFlP,__ -2022-05-17T11:30:05.964Z,delete,pages.vaccinationsPage.nl.booster_kpi.booster_shot_last_seven_days.description,W42pYebYgNKSplnOwA9UMB,__ -2022-05-23T10:24:35.671Z,add,pages.situationsPage.shared.belangrijk_bericht,RQYRq9yqc5kuEd5capEHG3,__ -2022-05-25T12:52:50.949Z,add,pages.hospitalPage.nl.chart_bedbezetting.legend_dot_label,hErpiCVzoc9qP245irsdCS,__ -2022-05-25T13:25:56.013Z,add,pages.intensiveCarePage.nl.chart_bedbezetting.legend_dot_label,l9y47X7Mn753quuWoDXzrN,__ -2022-06-08T14:31:12.676Z,add,pages.positiveTestsPage.nl.ggd.linechart_percentage_legend_label,FpB1VG3smRHDNCGaZQZZoS,__ -2022-06-08T14:31:13.689Z,add,pages.positiveTestsPage.vr.ggd.linechart_percentage_legend_label,avHj0RuKBVR3WKDFaNt28q,__ -2022-07-06T13:00:33.984Z,add,common.variants.omicron b_1_1_529.countryOfOrigin,FpB1VG3smRHDNCGaZfFnHc,__ -2022-07-06T13:00:35.005Z,add,common.variants.omicron b_1_1_529.name,FpB1VG3smRHDNCGaZfFnJP,__ -2022-07-06T13:00:36.018Z,add,common.variants.omicron ba_1.countryOfOrigin,ITiTU3jVuy3jp8GMhgLGnz,__ -2022-07-06T13:00:37.027Z,add,common.variants.omicron ba_1.name,FpB1VG3smRHDNCGaZfFnPN,__ -2022-07-06T13:00:38.028Z,add,common.variants.omicron ba_2.countryOfOrigin,avHj0RuKBVR3WKDFarkBDI,__ -2022-07-06T13:00:39.050Z,add,common.variants.omicron ba_2.name,FpB1VG3smRHDNCGaZfFnWX,__ -2022-07-06T13:00:40.061Z,add,common.variants.omicron ba_2_12_1.countryOfOrigin,ITiTU3jVuy3jp8GMhgLHhL,__ -2022-07-06T13:00:41.073Z,add,common.variants.omicron ba_2_12_1.name,FpB1VG3smRHDNCGaZfFnnF,__ -2022-07-06T13:00:42.075Z,add,common.variants.omicron ba_3.countryOfOrigin,FpB1VG3smRHDNCGaZfFnp2,__ -2022-07-06T13:00:43.098Z,add,common.variants.omicron ba_3.name,avHj0RuKBVR3WKDFarkBch,__ -2022-07-06T13:00:44.103Z,add,common.variants.omicron ba_4.countryOfOrigin,FpB1VG3smRHDNCGaZfFnuP,__ -2022-07-06T13:00:45.123Z,add,common.variants.omicron ba_4.name,FpB1VG3smRHDNCGaZfFnwC,__ -2022-07-06T13:00:46.132Z,add,common.variants.omicron ba_5.countryOfOrigin,avHj0RuKBVR3WKDFarkC5j,__ -2022-07-06T13:00:47.149Z,add,common.variants.omicron ba_5.name,ITiTU3jVuy3jp8GMhgLJBb,__ From 263df281d85c6f8c20617a43b39496f1f5e11b1a Mon Sep 17 00:00:00 2001 From: L R <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Mon, 11 Jul 2022 14:30:00 +0200 Subject: [PATCH 02/12] bugfix/COR-918-remove-variant-origin-and-description (#4320) * bugfix: updated MobileVariantRow component to not render the variant's description (containing country of origin) when country of origin is unknown or unset (using '-'); * bugfix: added showDescription prop to MobileVariantRow component to conditionally render the variant's description (including name and country of origin); * bugfix: updated MobileVariantRow component to revert changes for showDescription prop; updated MobileVariantRow to remove variant description logic and component in its entirety; updated VariantNameCell component to completely remove logic for isTooltipEnabled and simplify the component; removed useVariantNameAndDescription logic; Co-authored-by: VWSCoronaDashboard26 --- .../components/narrow-variants-table.tsx | 10 +---- .../components/variant-name-cell.tsx | 20 ++------- .../variants-table-tile/logic/index.ts | 1 - .../logic/use-variant-name-and-description.ts | 41 ------------------- 4 files changed, 5 insertions(+), 67 deletions(-) delete mode 100644 packages/app/src/domain/variants/variants-table-tile/logic/index.ts delete mode 100644 packages/app/src/domain/variants/variants-table-tile/logic/use-variant-name-and-description.ts diff --git a/packages/app/src/domain/variants/variants-table-tile/components/narrow-variants-table.tsx b/packages/app/src/domain/variants/variants-table-tile/components/narrow-variants-table.tsx index 6afae6f41e..9536bc4a83 100644 --- a/packages/app/src/domain/variants/variants-table-tile/components/narrow-variants-table.tsx +++ b/packages/app/src/domain/variants/variants-table-tile/components/narrow-variants-table.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; import styled from 'styled-components'; import { isPresent } from 'ts-is-present'; import { Box } from '~/components/base'; -import { InlineText, Text } from '~/components/typography'; +import { InlineText } from '~/components/typography'; import { VariantRow } from '~/domain/variants/static-props'; import { useIntl } from '~/intl'; import { getMaximumNumberOfDecimals } from '~/utils/get-maximum-number-of-decimals'; @@ -17,7 +17,6 @@ import { VariantDifference, VariantNameCell, } from '.'; -import { useVariantNameAndDescription } from '../logic/use-variant-name-and-description'; import { TableText } from '../types'; import { NoPercentageData } from './no-percentage-data'; @@ -76,12 +75,6 @@ function MobileVariantRow(props: MobileVariantRowProps) { const columnNames = text.kolommen; - const [, variantDescription] = useVariantNameAndDescription( - row.variant as keyof typeof text.varianten, - text.anderen_tooltip, - text - ); - return ( <> @@ -118,7 +111,6 @@ function MobileVariantRow(props: MobileVariantRowProps) { '-' )} - {variantDescription} )} diff --git a/packages/app/src/domain/variants/variants-table-tile/components/variant-name-cell.tsx b/packages/app/src/domain/variants/variants-table-tile/components/variant-name-cell.tsx index ccda515c81..f687521df6 100644 --- a/packages/app/src/domain/variants/variants-table-tile/components/variant-name-cell.tsx +++ b/packages/app/src/domain/variants/variants-table-tile/components/variant-name-cell.tsx @@ -1,7 +1,5 @@ -import { InlineTooltip } from '~/components/inline-tooltip'; import { BoldText } from '~/components/typography'; import { Cell } from '.'; -import { useVariantNameAndDescription } from '../logic'; import { TableText } from '../types'; type VariantNameCellProps = { @@ -9,27 +7,17 @@ type VariantNameCellProps = { text: TableText; mobile?: boolean; narrow?: boolean; - isTooltipEnabled?: boolean; }; export function VariantNameCell(props: VariantNameCellProps) { - const { variant, text, mobile, narrow, isTooltipEnabled } = props; + const { variant, text, mobile, narrow } = props; - const [variantName, variantDescription] = useVariantNameAndDescription( - variant as keyof typeof text.varianten, - text.anderen_tooltip, - text - ); + const { name: variantName } = + text.varianten[variant as keyof typeof text.varianten]; return ( - {!mobile && isTooltipEnabled && ( - - {variantName} - - )} - - {(mobile || !isTooltipEnabled) && {variantName}} + {variantName} ); } diff --git a/packages/app/src/domain/variants/variants-table-tile/logic/index.ts b/packages/app/src/domain/variants/variants-table-tile/logic/index.ts deleted file mode 100644 index a1e638d0a8..0000000000 --- a/packages/app/src/domain/variants/variants-table-tile/logic/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './use-variant-name-and-description'; diff --git a/packages/app/src/domain/variants/variants-table-tile/logic/use-variant-name-and-description.ts b/packages/app/src/domain/variants/variants-table-tile/logic/use-variant-name-and-description.ts deleted file mode 100644 index 15c87f103f..0000000000 --- a/packages/app/src/domain/variants/variants-table-tile/logic/use-variant-name-and-description.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { assert } from '@corona-dashboard/common'; -import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; -import { TableText } from '../types'; - -export function useVariantNameAndDescription( - variant: keyof T['varianten'], - otherDescription: string, - text: T -) { - const { name, countryOfOrigin } = - text.varianten[variant as keyof typeof text.varianten]; - const variantDescription = - variant === 'other_table' ? otherDescription : text.description; - - assert( - name, - `[${ - useVariantNameAndDescription.name - }] No translation found for variant ${String(variant)}` - ); - assert( - name, - `[${ - useVariantNameAndDescription.name - }] No tooltip found for variant ${String(variant)}` - ); - assert( - name, - `[${ - useVariantNameAndDescription.name - }] No country of origin found for variant ${String(variant)}` - ); - - return [ - name, - replaceVariablesInText(variantDescription, { - variantName: name, - countryOfOrigin, - }), - ] as const; -} From 3d312f064d0aed26cec0fbbc29237e3e882d49d8 Mon Sep 17 00:00:00 2001 From: L R <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Wed, 13 Jul 2022 17:24:32 +0200 Subject: [PATCH 03/12] bugfix/COR-869-scroll-to-anchors (#4322) * bugfix: updated CollapsibleSection component's handleHashChange to not toggle (open) the section until the selected/current section has been scrolled into view (is either at the top of the viewport or we reached the bottom of the viewport); * bugfix: simplified handleHashChange to extract creating new variables over and over again; * bugfix: added isElementAtTopOfViewport and isAtBottomOfPage utility functions; refactored handleHashChange function to use utility functions; Co-authored-by: VWSCoronaDashboard26 --- .../collapsible/collapsible-section.tsx | 23 +++++++++++++++---- .../app/src/utils/is-at-bottom-of-page.ts | 6 +++++ .../utils/is-element-at-top-of-viewport.ts | 7 ++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 packages/app/src/utils/is-at-bottom-of-page.ts create mode 100644 packages/app/src/utils/is-element-at-top-of-viewport.ts diff --git a/packages/app/src/components/collapsible/collapsible-section.tsx b/packages/app/src/components/collapsible/collapsible-section.tsx index d9ce29633d..477ae91c2b 100644 --- a/packages/app/src/components/collapsible/collapsible-section.tsx +++ b/packages/app/src/components/collapsible/collapsible-section.tsx @@ -1,7 +1,9 @@ import { css } from '@styled-system/css'; -import { ReactNode, useEffect } from 'react'; +import { ReactNode, useEffect, useRef } from 'react'; import styled from 'styled-components'; import { Box, BoxProps } from '~/components/base'; +import { isAtBottomOfPage } from '~/utils/is-at-bottom-of-page'; +import { isElementAtTopOfViewport } from '~/utils/is-element-at-top-of-viewport'; import { useCollapsible } from '~/utils/use-collapsible'; import { Anchor } from '../typography'; @@ -18,6 +20,8 @@ export const CollapsibleSection = ({ id, hideBorder, }: CollapsibleSectionProps) => { + const section = useRef(null); + const collapsible = useCollapsible(); const { toggle } = collapsible; @@ -26,11 +30,21 @@ export const CollapsibleSection = ({ * Checks the hash part of the URL to see if it matches the id. * If so, the collapsible needs to be opened. */ - function handleHashChange() { + const handleHashChange = () => { if (id && window.location.hash === `#${id}`) { - toggle(true); + const sectionElement = section?.current; + if (!sectionElement) return; + + const interval = setInterval(() => { + if (isElementAtTopOfViewport(sectionElement) || isAtBottomOfPage()) { + toggle(true); + + clearInterval(interval); + return; + } + }, 250); // This value is slightly higher than the animation duration of the collapsible section. } - } + }; handleHashChange(); @@ -44,6 +58,7 @@ export const CollapsibleSection = ({ borderTop={hideBorder ? undefined : '1px solid'} borderTopColor={hideBorder ? undefined : 'lightGray'} id={id} + ref={section} > {collapsible.button( diff --git a/packages/app/src/utils/is-at-bottom-of-page.ts b/packages/app/src/utils/is-at-bottom-of-page.ts new file mode 100644 index 0000000000..6091f45fa6 --- /dev/null +++ b/packages/app/src/utils/is-at-bottom-of-page.ts @@ -0,0 +1,6 @@ +/** + * Checks wether the current scroll position is at the bottom of the page. + * @returns boolean + */ +export const isAtBottomOfPage = (): boolean => + window.innerHeight + Math.round(window.scrollY) >= document.body.scrollHeight; diff --git a/packages/app/src/utils/is-element-at-top-of-viewport.ts b/packages/app/src/utils/is-element-at-top-of-viewport.ts new file mode 100644 index 0000000000..eefa8a44eb --- /dev/null +++ b/packages/app/src/utils/is-element-at-top-of-viewport.ts @@ -0,0 +1,7 @@ +/** + * Checks wether an element is at the top of the browser's viewport. + * @param element - the element to get the position for + * @returns boolean + */ +export const isElementAtTopOfViewport = (element: HTMLElement): boolean => + element.getBoundingClientRect().top <= 1; From 757bb3cb61b045585ddc508fd22c57f48bf37c1c Mon Sep 17 00:00:00 2001 From: HO <93981322+VWSCoronaDashboard19@users.noreply.github.com> Date: Mon, 18 Jul 2022 11:14:29 +0200 Subject: [PATCH 04/12] Remove international from codebase (#4321) * feat(international): remove international from codebase * fix: remove unused import * feat: remove more trails of data and update typ * feat: add as keyword and remove last trails --- docs/feature-flags.md | 6 +- docs/get-static-props.md | 3 +- packages/app/schema/in/__index.json | 46 - .../app/schema/in/__named_difference.json | 75 - packages/app/schema/in/tested_overall.json | 49 - packages/app/schema/in/variants.json | 78 - .../app/schema/in_collection/__index.json | 42 - .../schema/in_collection/tested_overall.json | 35 - .../choropleth/components/choropleth-map.tsx | 2 - .../app/src/components/choropleth/index.tsx | 14 +- .../components/choropleth/logic/thresholds.ts | 3 - .../src/components/choropleth/logic/types.ts | 32 +- .../logic/use-choropleth-features.ts | 52 +- .../choropleth/logic/use-feature-name.ts | 5 - .../choropleth/logic/use-feature-props.ts | 23 - .../src/components/choropleth/logic/utils.ts | 7 - .../src/components/cms/inline-choropleth.tsx | 2 +- .../app/src/components/layout/app-content.tsx | 5 +- .../international/europe-choropleth-tile.tsx | 40 - .../app/src/domain/international/flag.tsx | 23 - .../components/bar-with-number.tsx | 30 - .../components/narrow-infected-table.tsx | 176 - .../components/wide-infected-table.tsx | 199 - .../infected-table-tile/index.ts | 1 - .../infected-table-tile.tsx | 186 - .../infected-table-tile/logic/common.ts | 1 - .../infected-table-tile/logic/sort-options.ts | 57 - .../use-map-country-to-color.spec.ts | 68 - .../multi-select-countries/context.tsx | 194 - .../multi-select-countries/country-code.ts | 36 - .../multi-select-countries/index.ts | 4 - .../mult-select-countries-input.tsx | 107 - .../multi-select-countries.tsx | 153 - .../multi-select-country-results.tsx | 189 - .../multi-select-country-search.tsx | 94 - .../selected-countries.tsx | 142 - .../use-hit-selection.ts | 77 - .../use-map-country-to-color.ts | 64 - .../use-select-country-results.ts | 67 - .../international/select-country/index.ts | 1 - .../select-country/select-country-input.tsx | 180 - .../select-country/select-country.tsx | 239 - .../select-country/use-hit-selection.ts | 105 - .../in-positive-tested-people-tooltip.tsx | 85 - .../src/domain/international/tooltip/index.ts | 1 - .../international/tooltip/tooltip-content.tsx | 67 - packages/app/src/domain/layout/in-layout.tsx | 66 - packages/app/src/domain/layout/index.ts | 1 - packages/app/src/domain/layout/logic/types.ts | 14 +- .../src/domain/layout/logic/use-sidebar.tsx | 5 - .../get-international-variant-chart-data.ts | 117 - .../get-international-variant-table-data.ts | 13 - .../static-props/get-variant-table-data.ts | 36 +- .../src/domain/variants/static-props/index.ts | 2 - .../src/pages/api/choropleth/[...param].ts | 19 +- .../app/src/pages/api/choropleth/topology.ts | 6 - .../pages/api/data/choropleth/[...param].ts | 1 - .../app/src/pages/api/topo-json/[type].ts | 5 - .../app/src/pages/api/topo-json/in.topo.json | 15072 ---------------- packages/app/src/types/cms.d.ts | 8 - .../__tests__/use-reverse-router.spec.tsx | 18 +- .../app/src/utils/get-current-page-scope.ts | 4 +- .../schema/custom-validations/choropleth.ts | 4 +- packages/cli/src/schema/schema-info.ts | 18 - .../shared/area-select-input.tsx | 1 - ...ollection-metric-property-select-input.tsx | 2 +- .../shared/collection-metric-select-input.tsx | 2 +- packages/cms/src/data/data-structure.ts | 51 +- packages/cms/src/elements/NOTES.md | 1 - packages/cms/src/elements/add.ts | 1 - .../migrations/sprint35/page-identifiers.ts | 21 - packages/cms/src/migrations/sprint43/index.ts | 2 - .../documents/choropleth-configuration.ts | 1 - packages/common/src/data-sorting.ts | 7 +- packages/common/src/data/reverse-router.ts | 7 - packages/common/src/types/data-utils.ts | 5 +- packages/common/src/types/data.ts | 69 - packages/common/src/types/feature-flags.ts | 6 +- packages/common/src/types/inline-charts.ts | 3 +- 79 files changed, 93 insertions(+), 18560 deletions(-) delete mode 100644 packages/app/schema/in/__index.json delete mode 100644 packages/app/schema/in/__named_difference.json delete mode 100644 packages/app/schema/in/tested_overall.json delete mode 100644 packages/app/schema/in/variants.json delete mode 100644 packages/app/schema/in_collection/__index.json delete mode 100644 packages/app/schema/in_collection/tested_overall.json delete mode 100644 packages/app/src/domain/international/europe-choropleth-tile.tsx delete mode 100644 packages/app/src/domain/international/flag.tsx delete mode 100644 packages/app/src/domain/international/infected-table-tile/components/bar-with-number.tsx delete mode 100644 packages/app/src/domain/international/infected-table-tile/components/narrow-infected-table.tsx delete mode 100644 packages/app/src/domain/international/infected-table-tile/components/wide-infected-table.tsx delete mode 100644 packages/app/src/domain/international/infected-table-tile/index.ts delete mode 100644 packages/app/src/domain/international/infected-table-tile/infected-table-tile.tsx delete mode 100644 packages/app/src/domain/international/infected-table-tile/logic/common.ts delete mode 100644 packages/app/src/domain/international/infected-table-tile/logic/sort-options.ts delete mode 100644 packages/app/src/domain/international/multi-select-countries/__tests__/use-map-country-to-color.spec.ts delete mode 100644 packages/app/src/domain/international/multi-select-countries/context.tsx delete mode 100644 packages/app/src/domain/international/multi-select-countries/country-code.ts delete mode 100644 packages/app/src/domain/international/multi-select-countries/index.ts delete mode 100644 packages/app/src/domain/international/multi-select-countries/mult-select-countries-input.tsx delete mode 100644 packages/app/src/domain/international/multi-select-countries/multi-select-countries.tsx delete mode 100644 packages/app/src/domain/international/multi-select-countries/multi-select-country-results.tsx delete mode 100644 packages/app/src/domain/international/multi-select-countries/multi-select-country-search.tsx delete mode 100644 packages/app/src/domain/international/multi-select-countries/selected-countries.tsx delete mode 100644 packages/app/src/domain/international/multi-select-countries/use-hit-selection.ts delete mode 100644 packages/app/src/domain/international/multi-select-countries/use-map-country-to-color.ts delete mode 100644 packages/app/src/domain/international/multi-select-countries/use-select-country-results.ts delete mode 100644 packages/app/src/domain/international/select-country/index.ts delete mode 100644 packages/app/src/domain/international/select-country/select-country-input.tsx delete mode 100644 packages/app/src/domain/international/select-country/select-country.tsx delete mode 100644 packages/app/src/domain/international/select-country/use-hit-selection.ts delete mode 100644 packages/app/src/domain/international/tooltip/in-positive-tested-people-tooltip.tsx delete mode 100644 packages/app/src/domain/international/tooltip/index.ts delete mode 100644 packages/app/src/domain/international/tooltip/tooltip-content.tsx delete mode 100644 packages/app/src/domain/layout/in-layout.tsx delete mode 100644 packages/app/src/domain/variants/static-props/get-international-variant-chart-data.ts delete mode 100644 packages/app/src/domain/variants/static-props/get-international-variant-table-data.ts delete mode 100644 packages/app/src/pages/api/topo-json/in.topo.json diff --git a/docs/feature-flags.md b/docs/feature-flags.md index 6e98e5b081..c72a07e0e3 100644 --- a/docs/feature-flags.md +++ b/docs/feature-flags.md @@ -39,11 +39,7 @@ export interface Feature { metricProperties?: string[]; } -export type JsonDataScope = - | DataScopeKey - | 'in_collection' - | 'vr_collection' - | 'gm_collection'; +export type JsonDataScope = DataScopeKey | 'vr_collection' | 'gm_collection'; ``` ## Usage diff --git a/docs/get-static-props.md b/docs/get-static-props.md index ce728b6d6b..443a4a647a 100644 --- a/docs/get-static-props.md +++ b/docs/get-static-props.md @@ -92,7 +92,7 @@ This does exactly the same as `selectNl` and `selectVr` except it selects data f #### createGetChoroplethData -This selects choropleth data from **GM_COLLECTION.json**, **VR_COLLECTION.json** or **IN_COLLECTION.json**. +This selects choropleth data from **GM_COLLECTION.json** or **VR_COLLECTION.json**. The object it returns is of this shape: ```ts @@ -100,7 +100,6 @@ The object it returns is of this shape: choropleth: { vr: VrCollection; gm: GmCollection - in: InCollection; }, } ``` diff --git a/packages/app/schema/in/__index.json b/packages/app/schema/in/__index.json deleted file mode 100644 index b801b03551..0000000000 --- a/packages/app/schema/in/__index.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "in", - "required": [ - "last_generated", - "proto_name", - "name", - "code", - "named_difference", - "tested_overall" - ], - "additionalProperties": false, - "properties": { - "last_generated": { - "type": "string" - }, - "proto_name": { - "$ref": "#/$defs/in_code" - }, - "name": { - "$ref": "#/$defs/in_code" - }, - "code": { - "type": "string", - "$comment": "We might want to use an enum here with country codes. This would be the filename without the IN_ prefix, so the country ISO code", - "pattern": "^[A-Z]+$" - }, - "named_difference": { - "$ref": "__named_difference.json" - }, - "tested_overall": { - "$ref": "tested_overall.json" - }, - "variants": { - "$ref": "variants.json" - } - }, - "$defs": { - "in_code": { - "type": "string", - "$comment": "We might want to use an enum here with country codes. We need the IN_ prefix for validation because all files end up in the same folder", - "pattern": "^IN_[A-Z]+$" - } - } -} diff --git a/packages/app/schema/in/__named_difference.json b/packages/app/schema/in/__named_difference.json deleted file mode 100644 index 786098024b..0000000000 --- a/packages/app/schema/in/__named_difference.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "in_named_difference", - "type": "object", - "properties": { - "variants__percentage": { - "type": "array", - "items": { - "$ref": "#/definitions/optional_named_diff_decimal" - } - } - }, - "required": [], - "additionalProperties": false, - "definitions": { - "optional_named_diff_integer": { - "title": "optional_named_difference_integer", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "old_value": { - "type": ["integer", "null"] - }, - "difference": { - "type": ["integer", "null"] - }, - "old_date_unix": { - "type": "integer" - }, - "new_date_unix": { - "type": "integer" - } - }, - "required": [ - "name", - "old_value", - "difference", - "old_date_unix", - "new_date_unix" - ], - "additionalProperties": false - }, - "optional_named_diff_decimal": { - "title": "optional_named_difference_decimal", - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "old_value": { - "type": ["number", "null"] - }, - "difference": { - "type": ["number", "null"] - }, - "old_date_unix": { - "type": "integer" - }, - "new_date_unix": { - "type": "integer" - } - }, - "required": [ - "name", - "old_value", - "difference", - "old_date_unix", - "new_date_unix" - ], - "additionalProperties": false - } - } -} diff --git a/packages/app/schema/in/tested_overall.json b/packages/app/schema/in/tested_overall.json deleted file mode 100644 index 58a135b5a0..0000000000 --- a/packages/app/schema/in/tested_overall.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "definitions": { - "value": { - "title": "in_tested_overall_value", - "type": "object", - "additionalProperties": false, - "required": [ - "infected", - "infected_per_100k_average", - "date_start_unix", - "date_end_unix", - "date_of_insertion_unix" - ], - "properties": { - "infected": { - "type": "integer" - }, - "infected_per_100k_average": { - "type": "number" - }, - "date_start_unix": { - "type": "integer" - }, - "date_end_unix": { - "type": "integer" - }, - "date_of_insertion_unix": { - "type": "integer" - } - } - } - }, - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "in_tested_overall", - "required": ["values", "last_value"], - "additionalProperties": false, - "properties": { - "values": { - "type": "array", - "items": { - "$ref": "#/definitions/value" - } - }, - "last_value": { - "$ref": "#/definitions/value" - } - } -} diff --git a/packages/app/schema/in/variants.json b/packages/app/schema/in/variants.json deleted file mode 100644 index 938d9ee769..0000000000 --- a/packages/app/schema/in/variants.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "in_variants", - "required": [], - "additionalProperties": false, - "properties": { - "values": { - "type": "array", - "items": { - "$ref": "#/definitions/variant" - } - } - }, - "definitions": { - "variant": { - "title": "in_variants_variant", - "type": "object", - "additionalProperties": false, - "required": ["name", "values", "last_value"], - "properties": { - "name": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "$ref": "#/definitions/value" - } - }, - "last_value": { - "$ref": "#/definitions/value" - } - } - }, - "value": { - "title": "in_variants_variant_value", - "type": "object", - "additionalProperties": false, - "required": [ - "percentage", - "occurrence", - "is_variant_of_concern", - "sample_size", - "is_reliable", - "date_start_unix", - "date_end_unix", - "date_of_insertion_unix" - ], - "properties": { - "percentage": { - "type": ["number", "null"] - }, - "occurrence": { - "type": ["number", "null"] - }, - "is_variant_of_concern": { - "type": "boolean" - }, - "sample_size": { - "type": "integer" - }, - "is_reliable": { - "type": "boolean" - }, - "date_start_unix": { - "type": "integer" - }, - "date_end_unix": { - "type": "integer" - }, - "date_of_insertion_unix": { - "type": "integer" - } - } - } - } -} diff --git a/packages/app/schema/in_collection/__index.json b/packages/app/schema/in_collection/__index.json deleted file mode 100644 index 161e897426..0000000000 --- a/packages/app/schema/in_collection/__index.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "in_collection", - "additionalProperties": false, - "required": [ - "last_generated", - "proto_name", - "name", - "code", - "tested_overall" - ], - "properties": { - "last_generated": { - "type": "string" - }, - "proto_name": { - "$ref": "#/$defs/in_collection_id" - }, - "name": { - "$ref": "#/$defs/in_collection_id" - }, - "code": { - "$ref": "#/$defs/in_collection_id" - }, - "tested_overall": { - "type": "array", - "$comment": "@TODO set min/maxItems to the number of countries", - "minItems": 0, - "maxItems": 999, - "items": { - "$ref": "tested_overall.json" - } - } - }, - "$defs": { - "in_collection_id": { - "type": "string", - "enum": ["IN_COLLECTION"] - } - } -} diff --git a/packages/app/schema/in_collection/tested_overall.json b/packages/app/schema/in_collection/tested_overall.json deleted file mode 100644 index 999581e923..0000000000 --- a/packages/app/schema/in_collection/tested_overall.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "in_collection_tested_overall", - "additionalProperties": false, - "required": [ - "country_code", - "infected", - "infected_per_100k_average", - "date_start_unix", - "date_end_unix", - "date_of_insertion_unix" - ], - "properties": { - "country_code": { - "type": "string", - "pattern": "^[A-Z]+$" - }, - "infected": { - "type": "integer" - }, - "infected_per_100k_average": { - "type": "number" - }, - "date_start_unix": { - "type": "integer" - }, - "date_end_unix": { - "type": "integer" - }, - "date_of_insertion_unix": { - "type": "integer" - } - } -} diff --git a/packages/app/src/components/choropleth/components/choropleth-map.tsx b/packages/app/src/components/choropleth/components/choropleth-map.tsx index 9e9c0c043e..995f3dc232 100644 --- a/packages/app/src/components/choropleth/components/choropleth-map.tsx +++ b/packages/app/src/components/choropleth/components/choropleth-map.tsx @@ -55,8 +55,6 @@ export const ChoroplethMap: ( const dataConfig = createDataConfig(partialDataConfig); const mapProjection = isDefined(dataOptions.projection) - ? dataOptions.projection - : map === 'in' ? geoConicConformal : geoMercator; diff --git a/packages/app/src/components/choropleth/index.tsx b/packages/app/src/components/choropleth/index.tsx index b16ba866f0..398988d5ec 100644 --- a/packages/app/src/components/choropleth/index.tsx +++ b/packages/app/src/components/choropleth/index.tsx @@ -62,14 +62,18 @@ export type DataOptions = { export type OptionalDataConfig = { /** - * A top-level property name of either IN_COLLECTION.json, VR_COLLECTION.json or GM_COLLECTION.json + * A top-level property name of either VR_COLLECTION.json or GM_COLLECTION.json */ metricName: KeysOfType, T[]>; /** * A property name of the object determined by the metric name. This value is used to determine the color * of the feature. */ - metricProperty: KeysOfType; + metricProperty: KeysOfType< + T, + string | number | null | boolean | undefined, + true + >; /** * The color that is used for the feature when no data is available (a null value for example). */ @@ -278,9 +282,9 @@ export const DynamicChoropleth = withLoadingProps((getLoadingProps) => } = getLoadingProps(); return ( ); }, diff --git a/packages/app/src/components/choropleth/logic/thresholds.ts b/packages/app/src/components/choropleth/logic/thresholds.ts index 2b8baab307..144e7f9959 100644 --- a/packages/app/src/components/choropleth/logic/thresholds.ts +++ b/packages/app/src/components/choropleth/logic/thresholds.ts @@ -422,9 +422,6 @@ export const thresholds: Thresholds = { ChoroplethThresholdsValue[] >), }, - in: { - infected_per_100k_average: positiveTestedThresholds, - }, }; export type ChoroplethThresholdsValue = { diff --git a/packages/app/src/components/choropleth/logic/types.ts b/packages/app/src/components/choropleth/logic/types.ts index 69d2f8c547..854f3b5a7c 100644 --- a/packages/app/src/components/choropleth/logic/types.ts +++ b/packages/app/src/components/choropleth/logic/types.ts @@ -1,6 +1,5 @@ import type { GmCollection, - InCollection, KeysOfType, VrCollection, } from '@corona-dashboard/common'; @@ -28,55 +27,38 @@ export type FitExtent = [[[number, number], [number, number]], any]; export enum CHOROPLETH_ASPECT_RATIO { nl = 1 / 1.2, - in = 1 / 0.775, } /** - * in - International, indicates a map of Europe * gm - Municipality, indicates a map of the Netherlands that shows the different municipalities * vr - Safety region, indicates a map of the Netherlands that shows the different safety regions */ -export type MapType = 'gm' | 'vr' | 'in'; +export type MapType = 'gm' | 'vr'; export type CodeProp = - | KeysOfType | KeysOfType | KeysOfType; export const mapToCodeType: Record = { gm: 'gmcode', vr: 'vrcode', - in: 'country_code', }; -export type ChoroplethCollection = InCollection | GmCollection | VrCollection; +export type ChoroplethCollection = GmCollection | VrCollection; -export type InferedMapType = T extends InDataItem - ? 'in' - : T extends GmDataItem +export type InferedMapType = T extends GmDataItem ? 'gm' : T extends VrDataItem ? 'vr' : never; export type InferedDataCollection = - T extends InDataItem - ? InCollection - : T extends GmDataItem + T extends GmDataItem ? GmCollection : T extends VrDataItem ? VrCollection : never; -/** - * Select all the item types of all the properties from the InCollection with an array type that has a country_code property - */ -export type InDataCollection = InCollection[KeysOfType< - InCollection, - { country_code: string }[] ->]; -export type InDataItem = InDataCollection[number]; - /** * Select all the item types of all the properties from the VrCollection with an array type that has a vrcode property */ @@ -102,8 +84,6 @@ export type MappedDataCollection = T extends 'gm' ? GmCollection : T extends 'vr' ? VrCollection - : T extends 'in' - ? InCollection : never; /** @@ -113,11 +93,9 @@ export type MappedDataItem = T extends 'gm' ? GmDataItem : T extends 'vr' ? VrDataItem - : T extends 'in' - ? InDataItem : never; -export type ChoroplethDataItem = GmDataItem | VrDataItem | InDataItem; +export type ChoroplethDataItem = GmDataItem | VrDataItem; export type CodedGeoProperties = { code: string; diff --git a/packages/app/src/components/choropleth/logic/use-choropleth-features.ts b/packages/app/src/components/choropleth/logic/use-choropleth-features.ts index 5402c6d385..864f8cbdc6 100644 --- a/packages/app/src/components/choropleth/logic/use-choropleth-features.ts +++ b/packages/app/src/components/choropleth/logic/use-choropleth-features.ts @@ -10,13 +10,6 @@ import type { ChoroplethDataItem, CodedGeoJSON } from './types'; export type FeatureType = keyof ChoroplethFeatures; -/** - * These country codes represent the outer most features of the international - * map that need to be centered in on. So, roughly the top left, top right - * bottom left and bottom right features. - */ -const internationalBoundingBoxCodes = ['ISL', 'NOR', 'ESP', 'GRC', 'CYP']; - export type ChoroplethFeatures = { outline?: CodedGeoJSON; hover: CodedGeoJSON; @@ -93,40 +86,6 @@ export function getChoroplethFeatures( boundingBox: outlineGeo, }; } - case 'in': { - const inData = (data as unknown[]).filter(function ( - v: any - ): v is { country_code: string } { - return 'country_code' in v; - }); - /** - * The european map features are datadriven, only the features - * for which data exists are added to the outline, hover and boundingbox - * This way the map can be centered on only those countries with the - * surrounding countries only partially in view. - */ - return { - outline: { - ...featureGeo, - features: featureGeo.features.filter( - (x) => !inData.some((d) => d.country_code === x.properties.code) - ), - }, - hover: { - ...featureGeo, - features: featureGeo.features.filter((x) => - inData.some((d) => d.country_code === x.properties.code) - ), - }, - area: featureGeo, - boundingBox: { - ...featureGeo, - features: featureGeo.features.filter((x) => - internationalBoundingBoxCodes.includes(x.properties.code) - ), - }, - }; - } } } @@ -185,13 +144,10 @@ function filterVrBySelectedGmCode( } function createGeoJson(map: MapType, topoJson: any) { - const outlineGeo = - map === 'in' - ? undefined - : (topojsonFeature( - topoJson, - topoJson.objects.nl_features - ) as CodedGeoJSON); + const outlineGeo = topojsonFeature( + topoJson, + topoJson.objects.nl_features + ) as CodedGeoJSON; const featureGeo = topojsonFeature( topoJson, diff --git a/packages/app/src/components/choropleth/logic/use-feature-name.ts b/packages/app/src/components/choropleth/logic/use-feature-name.ts index 8a2d0701db..96f0e922a1 100644 --- a/packages/app/src/components/choropleth/logic/use-feature-name.ts +++ b/packages/app/src/components/choropleth/logic/use-feature-name.ts @@ -45,11 +45,6 @@ export function useFeatureName( return item.name; }; } - case 'in': { - throw new Error( - 'International feature names are lokalized and need to be passed in using a custom getFeatureName method' - ); - } } }, [map, customGetFeatureName]); } diff --git a/packages/app/src/components/choropleth/logic/use-feature-props.ts b/packages/app/src/components/choropleth/logic/use-feature-props.ts index 58cae4a241..b16c12ca53 100644 --- a/packages/app/src/components/choropleth/logic/use-feature-props.ts +++ b/packages/app/src/components/choropleth/logic/use-feature-props.ts @@ -138,28 +138,5 @@ export function getFeatureProps( }, }; } - case 'in': { - return { - area: { - fill: (code: string) => { - return getFillColor(code); - }, - stroke: () => colors.white, - strokeWidth: () => DEFAULT_STROKE_WIDTH, - }, - hover: { - fill: () => 'none', - stroke: (_code: string, isActivated?: boolean) => - isActivated ? colors.body : 'none', - strokeWidth: (_code: string, isActivated?: boolean) => - isActivated ? 1 : 0, - }, - outline: { - fill: () => 'none', - stroke: () => colors.silver, - strokeWidth: () => DEFAULT_STROKE_WIDTH, - }, - }; - } } } diff --git a/packages/app/src/components/choropleth/logic/utils.ts b/packages/app/src/components/choropleth/logic/utils.ts index 3331a423fc..4c81a00f31 100644 --- a/packages/app/src/components/choropleth/logic/utils.ts +++ b/packages/app/src/components/choropleth/logic/utils.ts @@ -6,7 +6,6 @@ import type { CodedGeoProperties, CodeProp, GmDataItem, - InDataItem, ParsedFeatureWithPath, VrDataItem, } from './types'; @@ -17,8 +16,6 @@ export function isCodedValueType(codeType: CodeProp) { return isGmData; case 'vrcode': return isVrData; - case 'country_code': - return isInData; } } @@ -30,10 +27,6 @@ export function isVrData(item: ChoroplethDataItem): item is VrDataItem { return 'vrcode' in item; } -export function isInData(item: ChoroplethDataItem): item is InDataItem { - return 'country_code' in item; -} - export function featureHasPath( value: ParsedFeature> ): value is ParsedFeatureWithPath { diff --git a/packages/app/src/components/cms/inline-choropleth.tsx b/packages/app/src/components/cms/inline-choropleth.tsx index eff75be27f..6016cf616f 100644 --- a/packages/app/src/components/cms/inline-choropleth.tsx +++ b/packages/app/src/components/cms/inline-choropleth.tsx @@ -58,7 +58,7 @@ export function InlineChoropleth(props: InlineChoroplethProps) { }; const dataConfig: OptionalDataConfig = { - metricName: configuration.metricName, + metricName: configuration.metricName as any, metricProperty: configuration.metricProperty as any, areaStroke: getColor(configuration.areaStroke), areaStrokeWidth: configuration.areaStrokeWidth, diff --git a/packages/app/src/components/layout/app-content.tsx b/packages/app/src/components/layout/app-content.tsx index 7daa360733..480a94738b 100644 --- a/packages/app/src/components/layout/app-content.tsx +++ b/packages/app/src/components/layout/app-content.tsx @@ -29,7 +29,6 @@ export function AppContent({ const { commonTexts } = useIntl(); const isMenuOpen = - router.pathname == '/internationaal' || router.pathname == '/landelijk' || router.pathname == '/veiligheidsregio/[code]' || router.pathname == '/gemeente/[code]' || @@ -43,13 +42,13 @@ export function AppContent({ * @TODO Open the menu purely client side without loading a new page */ const backButtonUrl = currentPageScope - ? isMenuOpen && currentPageScope !== 'in' + ? isMenuOpen ? reverseRouter.actueel[currentPageScope](currentCode) : reverseRouter[currentPageScope].index(currentCode) : undefined; const backButtonText = currentPageScope - ? isMenuOpen && currentPageScope !== 'in' + ? isMenuOpen ? commonTexts.nav.back_topical[currentPageScope] : commonTexts.nav.back_all_metrics[currentPageScope] : ''; diff --git a/packages/app/src/domain/international/europe-choropleth-tile.tsx b/packages/app/src/domain/international/europe-choropleth-tile.tsx deleted file mode 100644 index d0df99c1b2..0000000000 --- a/packages/app/src/domain/international/europe-choropleth-tile.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { ChoroplethThresholdsValue } from '@corona-dashboard/common'; -import { ReactNode } from 'react'; -import { Box } from '~/components/base'; -import { ChartTile } from '~/components/chart-tile'; -import { ChoroplethLegenda } from '~/components/choropleth-legenda'; -import { MetadataProps } from '~/components/metadata'; - -type EuropeChoroplethTileProps = { - children: ReactNode; - title: string; - description: string; - metadata?: MetadataProps; - legend?: { - title: string; - thresholds: ChoroplethThresholdsValue[]; - }; -}; - -export function EuropeChoroplethTile(props: EuropeChoroplethTileProps) { - const { children, title, description, metadata, legend } = props; - - const legendaComponent = legend && ( - - - - ); - - return ( - - - {children} - - {legendaComponent && ( - - {legendaComponent} - - )} - - ); -} diff --git a/packages/app/src/domain/international/flag.tsx b/packages/app/src/domain/international/flag.tsx deleted file mode 100644 index ab9ab36fef..0000000000 --- a/packages/app/src/domain/international/flag.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import css from '@styled-system/css'; - -interface FlagProps { - countryCode: string; - width?: number; - height?: number; -} - -export function Flag({ countryCode, width = 17, height = 13 }: FlagProps) { - return ( - - ); -} diff --git a/packages/app/src/domain/international/infected-table-tile/components/bar-with-number.tsx b/packages/app/src/domain/international/infected-table-tile/components/bar-with-number.tsx deleted file mode 100644 index 75714156d2..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/components/bar-with-number.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import { Box } from '~/components/base'; -import { PercentageBar } from '~/components/percentage-bar'; -import { BoldText } from '~/components/typography'; - -export function BarWithNumber({ - amount, - percentage, - color, - formatValue, -}: { - amount: number; - percentage: number; - color: string; - formatValue: (value: number) => string; -}) { - return ( - - - {formatValue(amount)} - - - - ); -} diff --git a/packages/app/src/domain/international/infected-table-tile/components/narrow-infected-table.tsx b/packages/app/src/domain/international/infected-table-tile/components/narrow-infected-table.tsx deleted file mode 100644 index 1cd02b370b..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/components/narrow-infected-table.tsx +++ /dev/null @@ -1,176 +0,0 @@ -import { colors, InCollectionTestedOverall } from '@corona-dashboard/common'; -import css from '@styled-system/css'; -import { maxBy } from 'lodash'; -import { ReactNode, useMemo } from 'react'; -import { Box } from '~/components/base'; -import { thresholds } from '~/components/choropleth/logic/thresholds'; -import { PercentageBar } from '~/components/percentage-bar'; -import { InlineText, BoldText } from '~/components/typography'; -import { Flag } from '~/domain/international/flag'; -import { useIntl } from '~/intl'; -import { getThresholdValue } from '~/utils/get-threshold-value'; -import { getMaximumNumberOfDecimals } from '~/utils/get-maximum-number-of-decimals'; -import { FilterArrayType } from '../infected-table-tile'; -import { MAX_COUNTRIES_START } from '../logic/common'; -import { SiteText } from '~/locale'; - -interface NarrowInfectedTableProps { - data: InCollectionTestedOverall[]; - isExpanded: boolean; - matchingCountries: FilterArrayType[]; - countryNames: Record; - inputValue: string; - text: SiteText['pages']['in_positiveTestsPage']['shared']; -} -export function NarrowInfectedTable({ - data, - isExpanded, - matchingCountries, - countryNames, - inputValue, - text, -}: NarrowInfectedTableProps) { - const { formatPercentage } = useIntl(); - const highestAverage = maxBy(data, (x) => x.infected_per_100k_average); - - const formatValue = useMemo(() => { - const numberOfDecimals = getMaximumNumberOfDecimals( - data.map((x) => x.infected_per_100k_average ?? 0) - ); - return (value: number) => - formatPercentage(value, { - minimumFractionDigits: numberOfDecimals, - maximumFractionDigits: numberOfDecimals, - }); - }, [formatPercentage, data]); - - return ( - - {data.map((item, index) => - inputValue.length === 0 ? ( - isExpanded || index < MAX_COUNTRIES_START ? ( - - ) : null - ) : ( - matchingCountries.some( - (i) => i.country_code === item.country_code - ) && ( - - ) - ) - )} - - ); -} - -interface ItemRowProps { - item: InCollectionTestedOverall; - highestAverage: number | undefined; - countryNames: Record; - formatValue: (value: number) => string; - text: SiteText['pages']['in_positiveTestsPage']['shared']; -} - -function ItemRow({ - item, - highestAverage, - countryNames, - formatValue, - text, -}: ItemRowProps) { - const filterBelow = getThresholdValue( - thresholds.in.infected_per_100k_average, - item.infected_per_100k_average - ); - - return ( - - - - - - - {countryNames[item.country_code.toLocaleLowerCase()]} - - 0 ? ( - - - - ) : undefined - } - /> - - - ); -} - -function Row({ - formatValue, - label, - value, - bar, -}: { - formatValue: (value: number) => string; - label: string; - value: number; - bar?: ReactNode; -}) { - return ( - - - {label}: - - - - - - {formatValue(value)} - - {bar} - - - - ); -} diff --git a/packages/app/src/domain/international/infected-table-tile/components/wide-infected-table.tsx b/packages/app/src/domain/international/infected-table-tile/components/wide-infected-table.tsx deleted file mode 100644 index 938b6fd036..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/components/wide-infected-table.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { colors, InCollectionTestedOverall } from '@corona-dashboard/common'; -import css from '@styled-system/css'; -import { maxBy } from 'lodash'; -import { useMemo } from 'react'; -import styled from 'styled-components'; -import { Box } from '~/components/base'; -import { thresholds } from '~/components/choropleth/logic/thresholds'; -import { InlineText } from '~/components/typography'; -import { Flag } from '~/domain/international/flag'; -import { useIntl } from '~/intl'; -import { asResponsiveArray } from '~/style/utils'; -import { getThresholdValue } from '~/utils/get-threshold-value'; -import { getMaximumNumberOfDecimals } from '~/utils/get-maximum-number-of-decimals'; -import { FilterArrayType } from '../infected-table-tile'; -import { MAX_COUNTRIES_START } from '../logic/common'; -import { BarWithNumber } from './bar-with-number'; -import { SiteText } from '~/locale'; -interface WideInfectedTableProps { - data: InCollectionTestedOverall[]; - isExpanded: boolean; - matchingCountries: FilterArrayType[]; - countryNames: Record; - inputValue: string; - text: SiteText['pages']['in_positiveTestsPage']['shared']; -} - -export function WideInfectedTable({ - data, - isExpanded, - matchingCountries, - countryNames, - inputValue, - text, -}: WideInfectedTableProps) { - const { formatPercentage } = useIntl(); - const highestAverage = maxBy(data, (x) => x.infected_per_100k_average); - - const formatValue = useMemo(() => { - const numberOfDecimals = getMaximumNumberOfDecimals( - data.map((x) => x.infected_per_100k_average ?? 0) - ); - return (value: number) => - formatPercentage(value, { - minimumFractionDigits: numberOfDecimals, - maximumFractionDigits: numberOfDecimals, - }); - }, [data, formatPercentage]); - - return ( - - - - - - {text.land_tabel.header_land} - - - {text.land_tabel.header_per_inwoners} - - - {text.land_tabel.header_totale} - - - - - - {data.map((item, index) => - inputValue.length === 0 ? ( - isExpanded || index < MAX_COUNTRIES_START ? ( - - ) : null - ) : ( - matchingCountries.some( - (i) => i.country_code === item.country_code - ) && ( - - ) - ) - )} - - - - ); -} - -interface tableRowProps { - item: InCollectionTestedOverall; - highestAverage: number | undefined; - countryNames: Record; - formatValue: (value: number) => string; -} - -function TableRow({ - item, - highestAverage, - countryNames, - formatValue, -}: tableRowProps) { - const { formatNumber } = useIntl(); - - const filterBelow = getThresholdValue( - thresholds.in.infected_per_100k_average, - item.infected_per_100k_average - ); - - return ( - - - - - - - {countryNames[item.country_code.toLocaleLowerCase()]} - - - - {highestAverage && highestAverage > 0 && ( - - )} - - - {formatNumber(item.infected)} - - - ); -} - -const StyledTable = styled.table( - css({ - borderCollapse: 'collapse', - width: '100%', - }) -); - -const HeaderCell = styled.th( - css({ - textAlign: 'left', - fontWeight: 'normal', - pb: 2, - verticalAlign: 'middle', - }) -); - -const Cell = styled.td( - css({ - borderBottom: '1px solid', - borderBottomColor: 'silver', - p: 0, - py: 2, - }) -); diff --git a/packages/app/src/domain/international/infected-table-tile/index.ts b/packages/app/src/domain/international/infected-table-tile/index.ts deleted file mode 100644 index 67f52142cc..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { InfectedTableTile } from './infected-table-tile'; diff --git a/packages/app/src/domain/international/infected-table-tile/infected-table-tile.tsx b/packages/app/src/domain/international/infected-table-tile/infected-table-tile.tsx deleted file mode 100644 index b81cfe1e63..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/infected-table-tile.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import { InCollectionTestedOverall } from '@corona-dashboard/common'; -import css from '@styled-system/css'; -import { matchSorter } from 'match-sorter'; -import { useEffect, useMemo, useState } from 'react'; -import styled from 'styled-components'; -import { Box } from '~/components/base'; -import { ChartTile } from '~/components/chart-tile'; -import { Metadata, MetadataProps } from '~/components/metadata'; -import { RichContentSelect } from '~/components/rich-content-select'; -import { SearchInput } from '~/components/search-input'; -import { SiteText } from '~/locale'; -import { useBreakpoints } from '~/utils/use-breakpoints'; -import { NarrowInfectedTable } from './components/narrow-infected-table'; -import { WideInfectedTable } from './components/wide-infected-table'; -import { - positiveTestedSortOptions, - SortIdentifier, -} from './logic/sort-options'; -interface InfectedTableTileProps { - data: InCollectionTestedOverall[]; - countryNames: Record; - metadata: MetadataProps; - text: SiteText['pages']['in_positiveTestsPage']['shared']; -} - -export type FilterArrayType = { - country_code: string; - label: string; -}; - -export function InfectedTableTile({ - data, - countryNames, - metadata, - text, -}: InfectedTableTileProps) { - const [inputValue, setInputValue] = useState(''); - const [isExpanded, setIsExpanded] = useState(false); - const [matchingCountries, setMatchingCountries] = useState( - [] as FilterArrayType[] - ); - const [sortOption, setSortOption] = useState( - 'infected_per_100k_average_high_to_low' - ); - - const breakpoints = useBreakpoints(); - - const sortOptions = useMemo(() => { - const sortIdentifiers = Object.keys( - positiveTestedSortOptions - ) as SortIdentifier[]; - - return sortIdentifiers.map((id) => { - const label = text.land_tabel.sort_option[id]; - return { - label: label, - value: id, - }; - }); - }, [text]); - - /** - * Get all the country names and their translation - */ - const filterArray = useMemo( - () => - data.map((item) => { - return { - country_code: item.country_code, - label: countryNames[item.country_code.toLocaleLowerCase()], - }; - }), - [countryNames, data] - ); - - useEffect(() => { - setMatchingCountries([ - ...matchSorter(filterArray, inputValue, { - keys: ['country_code', 'label'], - }), - - /** - * Always show the Netherlands - */ - { - country_code: 'NLD', - label: countryNames['nld'], - }, - ]); - }, [filterArray, inputValue, countryNames]); - - return ( - - - - - - - - setSortOption(option.value)} - /> - - - - {breakpoints.sm ? ( - - ) : ( - - )} - - {matchingCountries.length > data.length && ( - - setIsExpanded(!isExpanded)}> - {isExpanded - ? text.land_tabel.toon_minder - : text.land_tabel.toon_meer} - - - )} - - - - ); -} - -const ExpandButton = styled.button( - css({ - position: 'relative', - padding: 0, - margin: 0, - border: 'none', - background: 'none', - font: 'inherit', - color: 'blue', - outline: 'inherit', - cursor: 'pointer', - - '&:hover': { - textDecoration: 'underline', - }, - - '&:focus': { - textDecoration: 'underline', - outlineWidth: '1px', - outlineStyle: 'dashed', - outlineColor: 'blue', - }, - }) -); diff --git a/packages/app/src/domain/international/infected-table-tile/logic/common.ts b/packages/app/src/domain/international/infected-table-tile/logic/common.ts deleted file mode 100644 index 48df1d6a1b..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/logic/common.ts +++ /dev/null @@ -1 +0,0 @@ -export const MAX_COUNTRIES_START = 10; diff --git a/packages/app/src/domain/international/infected-table-tile/logic/sort-options.ts b/packages/app/src/domain/international/infected-table-tile/logic/sort-options.ts deleted file mode 100644 index ef0afe4975..0000000000 --- a/packages/app/src/domain/international/infected-table-tile/logic/sort-options.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { InCollectionTestedOverall } from '@corona-dashboard/common'; - -export const positiveTestedSortOptions = { - infected_per_100k_average_high_to_low: ( - a: InCollectionTestedOverall, - b: InCollectionTestedOverall - ) => { - if ( - (a.infected_per_100k_average ?? -Infinity) > - (b.infected_per_100k_average ?? -Infinity) - ) - return -1; - if ( - (b.infected_per_100k_average ?? -Infinity) > - (a.infected_per_100k_average ?? -Infinity) - ) - return 1; - return 0; - }, - - infected_per_100k_average_low_to_high: ( - a: InCollectionTestedOverall, - b: InCollectionTestedOverall - ) => { - if ( - (a.infected_per_100k_average ?? -Infinity) < - (b.infected_per_100k_average ?? -Infinity) - ) - return -1; - if ( - (b.infected_per_100k_average ?? -Infinity) < - (a.infected_per_100k_average ?? -Infinity) - ) - return 1; - return 0; - }, - - infected_high_to_low: ( - a: InCollectionTestedOverall, - b: InCollectionTestedOverall - ) => { - if ((a.infected ?? -Infinity) > (b.infected ?? -Infinity)) return -1; - if ((b.infected ?? -Infinity) > (a.infected ?? -Infinity)) return 1; - return 0; - }, - - infected_low_to_high: ( - a: InCollectionTestedOverall, - b: InCollectionTestedOverall - ) => { - if ((a.infected ?? -Infinity) < (b.infected ?? -Infinity)) return -1; - if ((b.infected ?? -Infinity) < (a.infected ?? -Infinity)) return 1; - return 0; - }, -}; - -export type SortIdentifier = keyof typeof positiveTestedSortOptions; diff --git a/packages/app/src/domain/international/multi-select-countries/__tests__/use-map-country-to-color.spec.ts b/packages/app/src/domain/international/multi-select-countries/__tests__/use-map-country-to-color.spec.ts deleted file mode 100644 index a7a0cda766..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/__tests__/use-map-country-to-color.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { CountryCode } from '../country-code'; -import { - useMapCountryToColor, - ORDERED_COLORS, -} from '../use-map-country-to-color'; - -import { act, cleanup, renderHook } from '@testing-library/react-hooks'; -import { suite } from 'uvu'; -import * as assert from 'uvu/assert'; - -const UseMapCountryToColor = suite('useMapCountryToColor'); - -UseMapCountryToColor.after.each(() => { - cleanup(); -}); - -UseMapCountryToColor('should initialize in order', () => { - const selectedCountries: CountryCode[] = ['nld', 'bel', 'deu']; - - const { result } = renderHook(() => useMapCountryToColor(selectedCountries)); - - assert.equal( - selectedCountries.map((code) => result.current.getColor(code)), - ORDERED_COLORS.slice(0, selectedCountries.length) - ); -}); - -UseMapCountryToColor('should assign a unique color to a new country', () => { - const selectedCountries: CountryCode[] = ['nld', 'bel', 'deu']; - - const { result } = renderHook(() => useMapCountryToColor(selectedCountries)); - - act(() => { - result.current.toggleColor('fra'); - }); - - const uniqueAssignedColors = [ - ...new Set( - (['nld', 'bel', 'deu', 'fra'] as CountryCode[]).map( - result.current.getColor - ) - ), - ]; - - assert.is(result.current.getColor('fra'), ORDERED_COLORS[3]); - assert.is(['nld', 'bel', 'deu', 'fra'].length, uniqueAssignedColors.length); -}); - -UseMapCountryToColor( - 'should return the same color for the same country after updates', - () => { - const selectedCountries: CountryCode[] = ['nld', 'bel', 'deu']; - - const { result } = renderHook(() => - useMapCountryToColor(selectedCountries) - ); - - const beforeChangeColor = result.current.getColor('bel'); - - act(() => { - result.current.toggleColor('nld'); - }); - - assert.is(result.current.getColor('bel'), beforeChangeColor); - } -); - -UseMapCountryToColor.run(); diff --git a/packages/app/src/domain/international/multi-select-countries/context.tsx b/packages/app/src/domain/international/multi-select-countries/context.tsx deleted file mode 100644 index 149dc55676..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/context.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import { - ChangeEvent, - createContext, - ReactNode, - RefObject, - useContext, - useEffect, - useState, -} from 'react'; -import { assert } from '~/utils/assert'; -import { useOnClickOutside } from '~/utils/use-on-click-outside'; -import { CountryCode } from './country-code'; -import { useHitSelection } from './use-hit-selection'; -import { Hit, useSearchResults } from './use-select-country-results'; - -export interface CountryOption { - code: CountryCode; - name: string; - isSelected?: boolean; - lastValue?: number; - searchTerms?: string[]; -} - -type SearchContext = ReturnType; - -interface SearchContextProviderProps { - containerRef: RefObject; - children: (context: SearchContext) => ReactNode; - initialValue?: string; - onToggleCountry: (data: CountryOption) => void; - countries: CountryOption[]; - limit?: number; -} - -const searchContext = createContext(undefined); - -export function SearchContextProvider({ - children, - containerRef, - initialValue = '', - onToggleCountry, - countries, - limit, -}: SearchContextProviderProps) { - const value = useSearchContextValue( - initialValue, - containerRef, - onToggleCountry, - countries, - limit - ); - - return ( - - {children(value)} - - ); -} - -export function useSearchContext() { - const context = useContext(searchContext); - - assert(context, `[${useSearchContext.name}] Missing search context provider`); - - return context; -} - -function useSearchContextValue( - initialValue: string, - containerRef: RefObject, - onToggleCountry: (data: CountryOption) => void, - countries: CountryOption[], - limit?: number -) { - useOnClickOutside([containerRef], () => setHasInputFocus(false)); - - const id = '__search_countries'; - - /** - * current search term - */ - const [term, setTerm] = useState(initialValue); - - /** - * when a hit is selected (e.g. hitting return-key) the input's value will be - * replaced with the value of the selected hit. - */ - const [termSubmitted] = useState(''); - - /** - * Used for showing/hiding search results - */ - const [hasInputFocus, setHasInputFocus] = useState(false); - const [hasHitFocus, setHasHitFocus] = useState(false); - - /** - * By default narrow devices will show search-results when the input field - * has a value. We don't want to show these results when the value is - * pre-set/pre-populated. - * To fix this we will listen to an initial focus event on the input element, - * if that initial event is recognized, we'll allow the results to show. - */ - const [hasHadInputFocus, setHasHadInputFocus] = useState(false); - useEffect(() => { - if (hasInputFocus) setHasHadInputFocus(true); - }, [hasInputFocus]); - - /** - * the useSearchResults-hook which will perform the actual search - */ - const { hits } = useSearchResults(countries, term); - - const showResults = hasHadInputFocus && (hasInputFocus || hasHitFocus); - - const { focusRef, focusIndex, setFocusIndex } = useHitSelection({ - numberOfHits: hits.length, - onSelectHit: (index) => { - const option = hits[index]; - - if (option) onToggleCountry(option.data); - }, - /** - * Only enable keyboard navigation when we show results - */ - isEnabled: showResults, - }); - - useEffect(() => { - /** - * On input-change we'll reset the focus index to 0. - */ - setFocusIndex(0); - }, [setFocusIndex]); - - /** - * An option id is necessary for screen readers to link the search input - * to the currently selected option. - */ - const getOptionId = (index: number) => `${id}-result-${index}`; - - useOnClickOutside([containerRef], () => setHasHitFocus(false)); - - return { - selectedCount: countries.filter((x) => x.isSelected).length, - hits, - id, - setHasHitFocus, - setTerm, - showResults, - term, - limit: limit ?? Infinity, - - onToggleCountry, - - inputProps: { - value: termSubmitted || term, - onChange: (evt: ChangeEvent) => - setTerm(evt.target.value), - onFocus: () => setHasInputFocus(true), - /** - * Usually search-results will disappear when the input loses focus, - * but this doesn't allow the user to set focus on a search-result using - * the "tab"-key. - * The following timeout will handle the blur-event after a small delay. - * This allows the browser to fire a focusEvent for one of the results, - * which in turn will keep the search-results alive. - */ - onBlur: () => setTimeout(() => setHasInputFocus(false), 60), - 'aria-autocomplete': 'list', - 'aria-controls': id, - 'aria-activedescendant': getOptionId(focusIndex), - }, - - comboboxProps: { - role: 'combobox', - 'aria-expanded': showResults ? 'true' : 'false', - 'aria-haspopup': 'grid', - 'aria-owns': id, - }, - - getOptionProps: (option: Hit) => - ({ - id: getOptionId(option.index), - ref: option.index === focusIndex ? focusRef : undefined, - hasFocus: focusIndex === option.index, - onHover: () => setFocusIndex(option.index), - onFocus: () => { - setFocusIndex(option.index); - setHasHitFocus(true); - }, - isSelected: option.data.isSelected ?? false, - } as const), - } as const; -} diff --git a/packages/app/src/domain/international/multi-select-countries/country-code.ts b/packages/app/src/domain/international/multi-select-countries/country-code.ts deleted file mode 100644 index 9053ef47cd..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/country-code.ts +++ /dev/null @@ -1,36 +0,0 @@ -export const countryCodes = [ - 'aut', - 'bel', - 'bgr', - 'che', - 'cyp', - 'cze', - 'deu', - 'dnk', - 'esp', - 'est', - 'fin', - 'fra', - 'gbr', - 'grc', - 'hrv', - 'hun', - 'irl', - 'isl', - 'ita', - 'lie', - 'ltu', - 'lux', - 'lva', - 'mlt', - 'nld', - 'nor', - 'pol', - 'prt', - 'rou', - 'svk', - 'svn', - 'swe', -] as const; - -export type CountryCode = typeof countryCodes[number]; diff --git a/packages/app/src/domain/international/multi-select-countries/index.ts b/packages/app/src/domain/international/multi-select-countries/index.ts deleted file mode 100644 index ba21ae346e..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type { CountryOption } from './context'; -export { countryCodes } from './country-code'; -export type { CountryCode } from './country-code'; -export { MultiSelectCountries } from './multi-select-countries'; diff --git a/packages/app/src/domain/international/multi-select-countries/mult-select-countries-input.tsx b/packages/app/src/domain/international/multi-select-countries/mult-select-countries-input.tsx deleted file mode 100644 index 16d6ad32b9..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/mult-select-countries-input.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import css from '@styled-system/css'; -import { MouseEvent, useRef } from 'react'; -import styled from 'styled-components'; -import { Close } from '@corona-dashboard/icons'; -import { Search } from '@corona-dashboard/icons'; -import { Box } from '~/components/base'; -import { VisuallyHidden } from '~/components/visually-hidden'; -import { useIntl } from '~/intl'; -import { useSearchContext } from './context'; - -export function MultiSelectCountriesInput() { - const { commonTexts } = useIntl(); - const { id, inputProps, setTerm } = useSearchContext(); - const inputRef = useRef(null); - - return ( - - - - - - {inputProps.value && ( - { - evt.stopPropagation(); - inputRef.current?.focus(); - setTerm(''); - }} - css={css({ - svg: { - width: 20, - height: 20, - }, - })} - > - {commonTexts.select_countries.clear} - - - )} - - - - - - - - ); -} - -const StyledSearchInput = styled.input( - css({ - display: 'inline-block', - - width: '100%', - border: `1px solid silver`, - py: 2, - pl: '36px', - - fontFamily: 'body', - fontSize: 1, - - appearance: 'none', - - '&::-webkit-search-cancel-button': { - display: 'none', - }, - - '&::-ms-clear': { - display: 'none', - }, - }) -); - -const IconContainer = styled.div<{ align: 'left' | 'right' }>((x) => - css({ - position: 'absolute', - zIndex: 1, - top: 0, - right: x.align === 'right' ? '12px' : undefined, - bottom: 0, - left: x.align === 'left' ? '10px' : undefined, - - display: 'flex', - alignItems: 'center', - - m: 0, - p: 0, - height: '100%', - - background: 'none', - - color: x.align === 'left' ? 'labelGray' : 'icon', - - border: 'none', - }) -); diff --git a/packages/app/src/domain/international/multi-select-countries/multi-select-countries.tsx b/packages/app/src/domain/international/multi-select-countries/multi-select-countries.tsx deleted file mode 100644 index d1c19ca7e4..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/multi-select-countries.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { colors } from '@corona-dashboard/common'; -import css, { SystemStyleObject } from '@styled-system/css'; -import { ReactNode, useMemo, useState } from 'react'; -import styled from 'styled-components'; -import { asResponsiveArray } from '~/style/utils'; -import { assert } from '~/utils/assert'; -import { CountryOption } from './context'; -import { CountryCode } from './country-code'; -import { MultiSelectCountrySearch } from './multi-select-country-search'; -import { SelectedCountries } from './selected-countries'; -import { - ORDERED_COLORS, - useMapCountryToColor, -} from './use-map-country-to-color'; - -interface MultiSelectCountriesProps { - countryOptions: CountryOption[]; - children: ( - selectedCountries: CountryCode[], - getColor: (countryCode: CountryCode) => string - ) => ReactNode; - limit?: number; - alwaysSelectedCodes: CountryCode[]; - defaultSelectedCodes: CountryCode[]; -} - -export function MultiSelectCountries({ - countryOptions, - children, - limit, - alwaysSelectedCodes, - defaultSelectedCodes, -}: MultiSelectCountriesProps) { - assert( - limit ? limit <= ORDERED_COLORS.length : !limit, - `[${MultiSelectCountries.name}] limit cannot be higher than the # of specified colors` - ); - - const [selectedCountries, setSelectedCountries] = useState( - defaultSelectedCodes ?? [] - ); - - const { getColor, toggleColor } = useMapCountryToColor(selectedCountries); - - function handleToggleCountry(countryData: CountryOption) { - if (selectedCountries.includes(countryData.code)) { - setSelectedCountries( - selectedCountries.filter( - (countryCode: CountryCode) => countryCode !== countryData.code - ) - ); - } else { - if (limit && selectedCountries.length >= limit) { - return; - } - setSelectedCountries([...selectedCountries, countryData.code]); - } - - toggleColor(countryData.code); - } - - const countries: CountryOption[] = useMemo(() => { - return countryOptions - .filter((x) => !alwaysSelectedCodes.includes(x.code)) - .map((countryOption) => ({ - ...countryOption, - isSelected: selectedCountries.includes(countryOption.code), - })); - }, [countryOptions, selectedCountries, alwaysSelectedCodes]); - - const selectOptions = selectedCountries.map((countryCode) => ({ - metricProperty: countryCode, - color: getColor(countryCode), - label: - countryOptions.find((x) => x.code === countryCode)?.name ?? countryCode, - shape: 'line' as const, - })); - - return ( - <> - - - - - {alwaysSelectedCodes.map((countryCode) => ( - - {countryOptions.find((x) => x.code === countryCode)?.name} - - - ))} - - handleToggleCountry({ code: countryCode } as CountryOption) - } - /> - - {children(selectedCountries, getColor)} - - ); -} - -const List = styled.ul( - css({ - listStyle: 'none', - px: 0, - m: 0, - mt: 2, - lineHeight: '2.25rem', - }) -); - -const InputItem = styled.li( - css({ - mb: 2, - mr: asResponsiveArray({ _: 2, md: 3 }), - position: 'relative', - display: 'inline-block', - height: '1.5rem', - width: '300px', - verticalAlign: 'top', - }) -); - -const AlwaysSelectedItem = styled.li( - css({ - mb: 2, - mr: asResponsiveArray({ _: 2, md: 3 }), - position: 'relative', - display: 'inline-block', - pl: '25px', // alignment with shape - fontSize: 1, - }) -); - -const Line = styled.div<{ color: string }>(({ color }) => - css({ - display: 'block', - position: 'absolute', - borderTop: '3px solid', - borderTopColor: color as SystemStyleObject, - top: '15px', - width: '15px', - height: 0, - borderRadius: '2px', - left: 0, - }) -); diff --git a/packages/app/src/domain/international/multi-select-countries/multi-select-country-results.tsx b/packages/app/src/domain/international/multi-select-countries/multi-select-country-results.tsx deleted file mode 100644 index 89bd2dded8..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/multi-select-country-results.tsx +++ /dev/null @@ -1,189 +0,0 @@ -import css from '@styled-system/css'; -import { ReactNode } from 'react'; -import styled from 'styled-components'; -import { Checked } from '@corona-dashboard/icons'; -import { Unchecked } from '@corona-dashboard/icons'; -import { Box } from '~/components/base'; -import { Text } from '~/components/typography'; -import { Flag } from '~/domain/international/flag'; -import { useIntl } from '~/intl'; -import { useHotkey } from '~/utils/hotkey/use-hotkey'; -import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; -import { useSearchContext } from './context'; - -export function MultiSelectCountriesResults() { - const { - id, - hits, - setHasHitFocus, - onToggleCountry, - getOptionProps, - limit, - selectedCount, - } = useSearchContext(); - - const { formatNumber, commonTexts } = useIntl(); - - useHotkey('esc', () => setHasHitFocus(false), { preventDefault: false }); - - const isLimitReached = selectedCount >= limit; - - return ( - setHasHitFocus(true)} - > - - {hits.length > 0 ? ( - - {hits.map((x) => ( -
  • - onToggleCountry(x.data)} - isLimitReached={isLimitReached} - > - - {x.data.isSelected ? : } - - - - - - {x.data.name} - - - {formatNumber(x.data.lastValue, 1)} - - -
  • - ))} -
    - ) : ( - - - {commonTexts.select_countries.no_countries_found} - - - {commonTexts.select_countries.no_countries_found_hint} - - - )} -
    - - {replaceVariablesInText( - commonTexts.select_countries.selection_summary, - { - selectedCount, - limit, - } - )} - -
    - ); -} - -const StyledSelectCountriesResults = styled.div(css({})); - -const StyledCountriesList = styled.div( - css({ - maxHeight: '20em', - overflow: 'auto', - }) -); - -const StyledSelectionSummary = styled.div( - css({ - p: 1, - textAlign: 'center', - borderTop: '1px solid', - borderTopColor: 'lightGray', - fontSize: 1, - }) -); - -const StyledNoHits = styled.div( - css({ - color: 'gray', - textAlign: 'center', - p: 4, - }) -); - -interface HitProps { - children: ReactNode; - hasFocus: boolean; - onHover: () => void; - onFocus: () => void; - id: string; - onClick: () => void; - isSelected: boolean; - isLimitReached: boolean; -} - -function Hit({ - children, - hasFocus, - onHover, - onFocus, - onClick, - id, - isSelected, - isLimitReached, -}: HitProps) { - return ( - - {children} - - ); -} - -const StyledHit = styled.button<{ - hasFocus: boolean; - isSelected: boolean; - isLimitReached: boolean; -}>((x) => - css({ - px: 3, - py: 2, - display: 'flex', - alignItems: 'center', - textDecoration: 'none', - color: 'annotation', - width: '100%', - bg: x.hasFocus ? 'contextualContent' : 'white', - transitionProperty: 'background', - transitionDuration: x.hasFocus ? '0ms' : '120ms', - border: 'none', - textAlign: 'left', - opacity: x.isLimitReached && !x.isSelected ? 0.5 : 1, - fontFamily: 'inherit', - fontSize: '1em', - }) -); - -const StyledHitList = styled.ol( - css({ - listStyle: 'none', - m: 0, - p: 0, - }) -); diff --git a/packages/app/src/domain/international/multi-select-countries/multi-select-country-search.tsx b/packages/app/src/domain/international/multi-select-countries/multi-select-country-search.tsx deleted file mode 100644 index 628abd4c22..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/multi-select-country-search.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import css from '@styled-system/css'; -import { forwardRef, ReactNode, useRef } from 'react'; -import styled from 'styled-components'; -import { Box } from '~/components/base'; -import { useBreakpoints } from '~/utils/use-breakpoints'; -import { useIsMounted } from '~/utils/use-is-mounted'; -import { useResizeObserver } from '~/utils/use-resize-observer'; -import { CountryOption, SearchContextProvider } from './context'; -import { MultiSelectCountriesInput } from './mult-select-countries-input'; -import { MultiSelectCountriesResults } from './multi-select-country-results'; - -export function MultiSelectCountrySearch({ - initialValue, - countries, - onToggleCountry, - limit, -}: { - onToggleCountry: (data: CountryOption) => void; - initialValue?: string; - countries: CountryOption[]; - limit?: number; -}) { - const [heightRef, { height }] = useResizeObserver(); - const containerRef = useRef(null); - - const isMounted = useIsMounted(); - const breakpoints = useBreakpoints(); - - return ( - - {(context) => ( - - - - - - - - - - - - )} - - ); -} - -interface SearchContainerProps { - children: ReactNode; - isFloating: boolean; - height?: number; -} - -const SearchForm = forwardRef( - ({ children, height, isFloating }, ref) => { - return ( -
    evt.preventDefault()} - > - - {children} - - {isFloating && } - - ); - } -); - -const StyledSearchContainer = styled.li<{ isFloating: boolean }>((x) => - css({ - position: x.isFloating ? 'absolute' : 'relative', - width: '100%', - borderRadius: 1, - zIndex: 10, - background: 'white', - minWidth: 300, - maxWidth: 300, - }) -); diff --git a/packages/app/src/domain/international/multi-select-countries/selected-countries.tsx b/packages/app/src/domain/international/multi-select-countries/selected-countries.tsx deleted file mode 100644 index 631b382a1a..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/selected-countries.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import css from '@styled-system/css'; -import styled from 'styled-components'; -import { isDefined } from 'ts-is-present'; -import { Reset } from '@corona-dashboard/icons'; -import { asResponsiveArray } from '~/style/utils'; - -interface SelectOption { - metricProperty: string; - label: string; - color: string; - shape?: 'line' | 'circle'; -} - -interface SelectedCountriesProps { - selectOptions: SelectOption[]; - selection: string[]; - onRemoveItem: (metricProperty: string) => void; -} - -export function SelectedCountries({ - selectOptions, - selection, - onRemoveItem, -}: SelectedCountriesProps) { - const hasSelection = selection.length !== 0; - - return ( - <> - {selectOptions.map((item) => { - const isSelected = selection.includes(item.metricProperty); - return ( - - onRemoveItem(item.metricProperty)} - isActive={hasSelection && isSelected} - color={item.color} - data-text={item.label} - hasRemoveIcon={isDefined(onRemoveItem)} - > - {item.label} - {item.shape === 'line' && } - {isDefined(onRemoveItem) && ( - - - - )} - - - ); - })} - - ); -} - -const RemoveIconWrapper = styled.div( - css({ - width: '0.6rem', - position: 'absolute', - right: 1, - }) -); - -const Item = styled.li( - css({ - mb: 2, - mr: asResponsiveArray({ _: 2, md: 3 }), - position: 'relative', - display: 'inline-block', - }) -); - -/** - * Styling for this button contains: - * :before to render the colored line on hover/focus - * :after to widen the button to avoid font-weight bold jumps - */ -const ItemButton = styled.button<{ - isActive: boolean; - color: string; - text?: string; - hasRemoveIcon?: boolean; -}>(({ isActive, color, hasRemoveIcon }) => - css({ - appearance: 'none', - backgroundColor: 'tileGray', - cursor: 'pointer', - pr: hasRemoveIcon ? 24 : asResponsiveArray({ _: '5px', md: 10 }), - pl: asResponsiveArray({ _: 25, md: 30 }), - py: '3px', - border: '3px solid', - borderColor: isActive && !hasRemoveIcon ? color : 'transparent', - fontWeight: 'normal', - fontFamily: 'inherit', - position: 'relative', - outline: 'none', - display: 'inline-flex', - flexDirection: 'column', - alignItems: 'center', - fontSize: 1, - justifyContent: 'space-between', - - '&:hover,&:focus': { - '&:before': { - content: '""', - background: color, - height: '3px', - position: 'absolute', - left: '-3px', - right: '-3px', - bottom: '-3px', - }, - }, - - '&:focus': { - background: 'lightGray', - }, - - '&:after': { - content: hasRemoveIcon ? 'attr(data-text)' : undefined, - height: 0, - visibility: 'hidden', - overflow: 'hidden', - userSelect: 'none', - pointerEvents: 'none', - fontWeight: 'bold', - pr: '1px', - }, - }) -); - -const Line = styled.div<{ color: string }>(({ color }) => - css({ - top: '10px', - width: '15px', - height: '3px', - borderRadius: '2px', - display: 'block', - position: 'absolute', - left: asResponsiveArray({ _: '5px', md: 10 }), - backgroundColor: color, - }) -); diff --git a/packages/app/src/domain/international/multi-select-countries/use-hit-selection.ts b/packages/app/src/domain/international/multi-select-countries/use-hit-selection.ts deleted file mode 100644 index c5078efe37..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/use-hit-selection.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { useRef, useState } from 'react'; -import scrollIntoView from 'scroll-into-view-if-needed'; -import { useHotkey } from '~/utils/hotkey/use-hotkey'; - -/** - * This hook controls the currently selected search result index. - * It allows the index to be controlled by the keyboard using arrow-navigation. - * - * Additionally: - * - it will set focus on the corresponding DOM element while navigating with - * the arrow-keys. - * - it will capture "selection"-events triggered with the return-key. These - * events can be triggered in combination with a command/control-modifier key - * which means the user would like to open the result in a new window. - */ -export function useHitSelection({ - numberOfHits, - onSelectHit, - isEnabled = false, -}: { - numberOfHits: number; - onSelectHit: (index: number, openInNewWindow: boolean) => void; - isEnabled: boolean; -}) { - const [focusIndex, setFocusIndex] = useState(0); - const focusRef = useRef(null); - - useHotkey( - 'up', - () => { - const nextIndex = focusIndex - 1 < 0 ? numberOfHits - 1 : focusIndex - 1; - setFocusIndex(nextIndex); - maybeScrollIntoView(focusRef.current); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - useHotkey( - 'down', - () => { - const nextIndex = focusIndex + 1 < numberOfHits ? focusIndex + 1 : 0; - - setFocusIndex(nextIndex); - maybeScrollIntoView(focusRef.current); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - useHotkey( - 'enter', - () => { - onSelectHit(focusIndex, false); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - useHotkey( - 'space', - () => { - onSelectHit(focusIndex, false); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - return { focusIndex, setFocusIndex, focusRef }; -} - -function maybeScrollIntoView(el: T | null | undefined) { - if (el) { - scrollIntoView(el, { - behavior: 'smooth', - scrollMode: 'if-needed', - block: 'nearest', - inline: 'nearest', - }); - } -} diff --git a/packages/app/src/domain/international/multi-select-countries/use-map-country-to-color.ts b/packages/app/src/domain/international/multi-select-countries/use-map-country-to-color.ts deleted file mode 100644 index bad2852d95..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/use-map-country-to-color.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { colors } from '@corona-dashboard/common'; -import { useCallback, useRef } from 'react'; -import { CountryCode } from './country-code'; - -const { - cyan, - turquoise, - yellow, - orange, - magenta, - cyan_dark, - turquoise_dark, - yellow_dark, - orange_dark, - magenta_dark, -} = colors.data.multiseries; - -export const ORDERED_COLORS = [ - cyan, - turquoise, - yellow, - orange, - magenta, - cyan_dark, - turquoise_dark, - yellow_dark, - orange_dark, - magenta_dark, -]; - -/** - * Persistently map country codes to colors. - */ -export function useMapCountryToColor(selectedCountries: CountryCode[]) { - // Create an instance variable to track country-color mapping. - const countryCodeToColor = useRef( - new Map( - // Set the initial value - selectedCountries.map((countryCode: CountryCode, index: number) => [ - countryCode, - ORDERED_COLORS[index], - ]) - ) - ); - - const getColor = useCallback((countryCode: CountryCode) => { - return countryCodeToColor.current.get(countryCode) as string; - }, []); - - const toggleColor = useCallback((countryCode: CountryCode) => { - if (countryCodeToColor.current.has(countryCode)) { - countryCodeToColor.current.delete(countryCode); - } else { - const currentColors = [...countryCodeToColor.current.values()]; - // find the first unused color - const color = ORDERED_COLORS.find( - (color) => !currentColors.includes(color) - ); - countryCodeToColor.current.set(countryCode, color as string); - } - }, []); - - return { getColor, toggleColor }; -} diff --git a/packages/app/src/domain/international/multi-select-countries/use-select-country-results.ts b/packages/app/src/domain/international/multi-select-countries/use-select-country-results.ts deleted file mode 100644 index 0da3879776..0000000000 --- a/packages/app/src/domain/international/multi-select-countries/use-select-country-results.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { matchSorter } from 'match-sorter'; -import { useMemo } from 'react'; -import { isPresent } from 'ts-is-present'; -import { CountryOption } from './context'; - -export interface Hit { - /** - * The `index` holds the position of a hit. - */ - index: number; - - /** - * The score is a float between 0 and 1. - * A score of 1 equals the best match. - */ - score: number; - /** - * The `id` is unique for every hit. - */ - id: string; - data: T; -} - -export function useSearchResults(countries: CountryOption[], term: string) { - const termTrimmed = term.trim(); - - const { hits } = useMemo(() => { - const hits: Hit[] = search(countries, termTrimmed); - - return { hits }; - }, [countries, termTrimmed]); - - return { hits }; -} - -function search(countries: CountryOption[], term: string) { - let options = countries - .map((x) => ({ - code: x.code, - name: x.name, - lastValue: x.lastValue, - isSelected: x.isSelected, - searchTerms: [x.name, x.code, ...(x.searchTerms || [])].filter(isPresent), - })) - .sort((a, b) => a.name.localeCompare(b.name)); - - if (term !== '') { - options = matchSorter(options, term, { - keys: ['searchTerms'], - }); - } - - const hits = options.map( - (data, index) => - ({ - id: data.code, - data, - index, - /** - * Set score based on the order of the initial hits - */ - score: 1 - options.indexOf(data) / options.length, - } as Hit) - ); - - return hits; -} diff --git a/packages/app/src/domain/international/select-country/index.ts b/packages/app/src/domain/international/select-country/index.ts deleted file mode 100644 index c99c48867e..0000000000 --- a/packages/app/src/domain/international/select-country/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { SelectCountry } from './select-country'; diff --git a/packages/app/src/domain/international/select-country/select-country-input.tsx b/packages/app/src/domain/international/select-country/select-country-input.tsx deleted file mode 100644 index 4332a83c25..0000000000 --- a/packages/app/src/domain/international/select-country/select-country-input.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import css from '@styled-system/css'; -import { Dispatch, RefObject, SetStateAction } from 'react'; -import styled from 'styled-components'; -import { Chevron } from '@corona-dashboard/icons'; -import { Close } from '@corona-dashboard/icons'; -import { Search } from '@corona-dashboard/icons'; -import { Box } from '~/components/base'; -import { VisuallyHidden } from '~/components/visually-hidden'; -import { useIntl } from '~/intl'; -import { Option } from './select-country'; - -interface SelectCountryInputType { - inputValue: string; - setInputValue: Dispatch>; - currentOption: Option; - isOpen: boolean; - prefixId: string; - inputRef: RefObject; - handleOnClose: () => void; - handleOnFocus: () => void; - isMouseDown: boolean; -} - -export function SelectCountryInput({ - inputValue, - setInputValue, - currentOption, - isOpen, - handleOnClose, - prefixId, - handleOnFocus, - inputRef, - isMouseDown, -}: SelectCountryInputType) { - const { commonTexts } = useIntl(); - - /** - * A small timeout due the fact that otherwise the onClick event fires later than the onBlur. - * Resulting that the click won't work without the timeout. - */ - const handleOnBlur = () => { - if (isMouseDown) return; - setTimeout(() => { - handleOnClose(); - }, 100); - }; - - return ( - - - {isOpen ? ( - - ) : ( - - )} - - - - {isOpen ? ( - inputValue.length > 0 && ( - - - {commonTexts.select_countries.clear} - - - - ) - ) : ( - ) => { - event.stopPropagation(); - if (inputRef.current) inputRef.current.focus(); - setInputValue(''); - }} - css={css({ - display: 'flex', - - svg: { - width: 15, - height: 15, - }, - })} - > - - - )} - - - setInputValue(event.target.value)} - ref={inputRef} - onFocus={handleOnFocus} - onBlur={handleOnBlur} - autoComplete="off" - aria-haspopup="listbox" - aria-labelledby={`${prefixId} ${prefixId}_button`} - id={prefixId + '_button'} - /> - - ); -} -const IconContainer = styled.span<{ align: 'left' | 'right' }>((x) => - css({ - position: 'absolute', - top: 0, - right: x.align === 'right' ? '10px' : undefined, - bottom: 0, - left: x.align === 'left' ? '10px' : undefined, - - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - - m: 0, - p: 0, - height: '100%', - border: 'none', - - background: 'none', - color: x.align === 'left' ? 'labelGray' : 'icon', - - cursor: x.align === 'right' ? 'default' : undefined, - pointerEvents: x.align === 'left' ? 'none' : undefined, - }) -); - -const Input = styled.input( - css({ - appearance: 'none', - boxShadow: 'none', - display: 'inline-block', - - width: '100%', - border: `1px solid silver`, - py: 2, - pl: '2.25rem', - m: 0, - - fontFamily: 'body', - fontSize: 1, - - cursor: 'default', - - '&::-webkit-search-cancel-button': { - display: 'none', - }, - - '&::-ms-clear': { - display: 'none', - }, - - '&:focus': { - borderColor: 'lightGray', - outline: '2px dotted', - outlineColor: 'body', - cursor: 'text', - }, - }) -); diff --git a/packages/app/src/domain/international/select-country/select-country.tsx b/packages/app/src/domain/international/select-country/select-country.tsx deleted file mode 100644 index b4fd88238e..0000000000 --- a/packages/app/src/domain/international/select-country/select-country.tsx +++ /dev/null @@ -1,239 +0,0 @@ -import css from '@styled-system/css'; -import { matchSorter } from 'match-sorter'; -import { useEffect, useRef, useState } from 'react'; -import styled from 'styled-components'; -import { Box } from '~/components/base'; -import { InlineText, Text } from '~/components/typography'; -import { useIntl } from '~/intl'; -import { useOnClickOutside } from '~/utils/use-on-click-outside'; -import { useUniqueId } from '~/utils/use-unique-id'; -import { SelectCountryInput } from './select-country-input'; -import { useHitSelection } from './use-hit-selection'; - -export type Option = { - value: string; - label: string; -}; - -interface SelectCountryProps { - options: Option[]; - onChange: (value: string) => void; - value: string; -} - -export function SelectCountry({ - options, - onChange, - value, -}: SelectCountryProps) { - const { commonTexts } = useIntl(); - const uniqueId = useUniqueId(); - - const containerRef = useRef(null); - const inputRef = useRef(null); - - const [inputValue, setInputValue] = useState(value); - const [matchingCountries, setMatchingCountries] = useState([]); - const [isOpen, setIsOpen] = useState(false); - - /** - * Tracking when the mouse - */ - const [isMouseDown, setIsMouseDown] = useState(false); - - /** - * The currently selected item, we need to save this so we can always fall back to this country. - */ - const currentOption = options.filter((item) => item.value === value)[0]; - - /** - * Find all the results that match the label as well as the value - */ - useEffect(() => { - setMatchingCountries( - matchSorter(options, inputValue, { - keys: ['label', 'value'], - }).map((item: Option) => item.value) as [] - ); - }, [options, inputValue]); - - const handleOnFocus = () => { - setIsOpen(true); - setInputValue(''); - }; - - const handleOnClose = () => { - setIsOpen(false); - setInputValue(currentOption.label); - }; - - const { focusIndex, focusRef, setFocusIndex } = useHitSelection({ - isEnabled: isOpen, - onSelectHit: (index) => { - setIsOpen(false); - onChange(matchingCountries[index]); - // When the user presses "enter" we toggle off the focus state for the element. - if (inputRef.current) inputRef.current.blur(); - }, - maxPossibleItems: matchingCountries.length, - handleOnClose, - }); - - const handleOnClick = (item: Option) => { - setIsOpen(false); - onChange(item.value); - }; - - useOnClickOutside([containerRef], () => handleOnClose()); - - const handleOnMouseEnter = (index: number) => { - setFocusIndex(index); - }; - - /** - * Every time the user inputs a new value reset the focus index to the beginning of the results. - */ - useEffect(() => { - if (inputValue.length > 0 && isOpen) { - setFocusIndex(0); - } - }, [inputValue, setFocusIndex, isOpen]); - - const prefixId = `select_country_${uniqueId}`; - - return ( - - - - setIsMouseDown(true)} - onMouseUp={() => setIsMouseDown(false)} - /** - * If the dropdown is open set the aria-activedescendant to the highlighted country. - * When closed reset it to the current selected country. - */ - aria-activedescendant={ - isOpen - ? `${prefixId}_${matchingCountries[focusIndex]}` - : `${prefixId}_${currentOption.value}` - } - > - {matchingCountries.length > 0 ? ( - <> - {options - .filter((item) => matchingCountries.includes(item.value)) - .map((item, index) => { - const hasFocus = index === focusIndex; - - return ( - handleOnClick(item)} - onMouseDown={() => handleOnClick(item)} - onMouseEnter={() => handleOnMouseEnter(index)} - > - - - {item.label} - - - ); - })} - - ) : ( - - - {commonTexts.select_countries.no_countries_found} - - - {commonTexts.select_countries.no_countries_found_hint} - - - )} - - - ); -} - -const OrderedList = styled.ol<{ isOpen: boolean }>((x) => - css({ - display: x.isOpen ? 'block' : 'none', - position: 'absolute', - top: '100%', - - width: '100%', - - border: `1px solid`, - borderColor: 'silver', - borderTopColor: 'transparent', - borderBottomLeftRadius: 1, - borderBottomRightRadius: 1, - - backgroundColor: 'white', - zIndex: 10, - m: 0, - p: 0, - maxHeight: '20em', - overflow: 'auto', - }) -); - -const ListItem = styled.li<{ hasFocus?: boolean }>((x) => - css({ - px: 3, - py: 2, - display: 'flex', - alignItems: 'center', - textDecoration: 'none', - color: 'body', - width: '100%', - bg: x.hasFocus ? 'contextualContent' : 'white', - transitionProperty: 'background', - transitionDuration: x.hasFocus ? '0ms' : '120ms', - border: 'none', - textAlign: 'left', - - '&:hover': { - cursor: 'pointer', - }, - }) -); - -const StyledNoHits = styled.div( - css({ - color: 'gray', - textAlign: 'center', - p: 4, - }) -); diff --git a/packages/app/src/domain/international/select-country/use-hit-selection.ts b/packages/app/src/domain/international/select-country/use-hit-selection.ts deleted file mode 100644 index 09b476f40b..0000000000 --- a/packages/app/src/domain/international/select-country/use-hit-selection.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { useRef, useState } from 'react'; -import scrollIntoView from 'scroll-into-view-if-needed'; -import { useHotkey } from '~/utils/hotkey/use-hotkey'; -import { positiveModulo } from '~/utils/positive-modulo'; -/** - * This hook controls the currently selected search result index. - * It allows the index to be controlled by the keyboard using arrow-navigation. - * - * Additionally: - * - it will set focus on the corresponding DOM element while navigating with - * the arrow-keys. - */ -export function useHitSelection({ - isEnabled = false, - maxPossibleItems = 0, - onSelectHit, - handleOnClose, -}: { - isEnabled: boolean; - maxPossibleItems: number; - onSelectHit: (index: number, openInNewWindow?: boolean) => void; - handleOnClose: () => void; -}) { - const [focusIndex, setFocusIndex] = useState(0); - const focusRef = useRef(null); - - useHotkey( - 'up', - () => { - const nextIndex = focusIndex - 1; - setFocusIndex(positiveModulo(nextIndex, maxPossibleItems)); - maybeScrollIntoView(focusRef.current); - }, - { - allowRepeat: true, - isDisabled: !isEnabled, - } - ); - - useHotkey( - 'down', - () => { - const nextIndex = focusIndex + 1; - setFocusIndex(positiveModulo(nextIndex, maxPossibleItems)); - maybeScrollIntoView(focusRef.current); - }, - { - allowRepeat: true, - isDisabled: !isEnabled, - } - ); - - useHotkey( - 'enter', - () => { - if (maxPossibleItems === 0) return; - - onSelectHit(focusIndex); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - useHotkey( - 'home', - () => { - setFocusIndex(0); - maybeScrollIntoView(focusRef.current); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - useHotkey( - 'end', - () => { - setFocusIndex(maxPossibleItems - 1); - maybeScrollIntoView(focusRef.current); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - useHotkey( - 'escape', - () => { - handleOnClose(); - }, - { allowRepeat: true, isDisabled: !isEnabled } - ); - - return { - focusIndex, - focusRef, - setFocusIndex, - }; -} - -function maybeScrollIntoView(el: T | null | undefined) { - if (el) { - scrollIntoView(el, { - behavior: 'smooth', - scrollMode: 'if-needed', - block: 'nearest', - inline: 'nearest', - }); - } -} diff --git a/packages/app/src/domain/international/tooltip/in-positive-tested-people-tooltip.tsx b/packages/app/src/domain/international/tooltip/in-positive-tested-people-tooltip.tsx deleted file mode 100644 index abf2372eed..0000000000 --- a/packages/app/src/domain/international/tooltip/in-positive-tested-people-tooltip.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { Box } from '~/components/base'; -import { thresholds } from '~/components/choropleth/logic/thresholds'; -import { TooltipSubject } from '~/components/choropleth/tooltips'; -import { InlineText } from '~/components/typography'; -import { Flag } from '~/domain/international/flag'; -import { useIntl } from '~/intl'; -import { TooltipContent } from './tooltip-content'; - -type InPositiveTestedPeopleTooltipProps = { - title: string; - countryName: string; - countryCode: string; - value: number; - comparedName: string; - comparedCode: string; - comparedValue: number; -}; - -export function InPositiveTestedPeopleTooltip( - props: InPositiveTestedPeopleTooltipProps -) { - const { - countryName, - value, - comparedName, - comparedValue, - comparedCode, - title, - countryCode, - } = props; - const { formatPercentage } = useIntl(); - - const thresholdValues = thresholds.in.infected_per_100k_average; - - const showComparison = countryName !== comparedName; - - return ( - - - - - {showComparison && ( - - - - )} - - ); -} - -function SubjectText({ - code, - name, - value, - bold, -}: { - code: string; - name: string; - value: string; - bold?: boolean; -}) { - return ( - - - - {name} - - - {value} - - - ); -} diff --git a/packages/app/src/domain/international/tooltip/index.ts b/packages/app/src/domain/international/tooltip/index.ts deleted file mode 100644 index 5738646eef..0000000000 --- a/packages/app/src/domain/international/tooltip/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './in-positive-tested-people-tooltip'; diff --git a/packages/app/src/domain/international/tooltip/tooltip-content.tsx b/packages/app/src/domain/international/tooltip/tooltip-content.tsx deleted file mode 100644 index 23eeb297c5..0000000000 --- a/packages/app/src/domain/international/tooltip/tooltip-content.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import css from '@styled-system/css'; -import { ReactNode } from 'react'; -import styled from 'styled-components'; -import { Heading } from '~/components/typography'; -import { useIsTouchDevice } from '~/utils/use-is-touch-device'; - -interface IProps { - title: string; - children?: ReactNode; -} - -export function TooltipContent(props: IProps) { - const { title, children } = props; - const isTouch = useIsTouchDevice(); - - return ( - - - - {title} - - - {children && {children}} - - ); -} - -const StyledTooltipContent = styled.div<{ isInteractive: boolean }>((x) => - css({ - color: 'body', - width: 250, - borderRadius: 1, - cursor: x.onClick ? 'pointer' : 'default', - pointerEvents: x.isInteractive ? undefined : 'none', - }) -); - -const StyledTooltipHeader = styled.div( - css({ - padding: '0.25rem 2rem 0.25rem 0.5rem', - fontSize: '1.125rem', - color: 'body', - py: 2, - px: 3, - display: 'flex', - justifyContent: 'space-between', - alignItems: 'center', - textDecoration: 'none', - }) -); - -const TooltipInfo = styled.div( - css({ - borderTop: '1px solid', - borderTopColor: 'border', - py: 2, - px: 3, - }) -); diff --git a/packages/app/src/domain/layout/in-layout.tsx b/packages/app/src/domain/layout/in-layout.tsx deleted file mode 100644 index 719be4fe1f..0000000000 --- a/packages/app/src/domain/layout/in-layout.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import Head from 'next/head'; -import { Menu, MenuRenderer } from '~/components/aside/menu'; -import { Box } from '~/components/base'; -import { ErrorBoundary } from '~/components/error-boundary'; -import { AppContent } from '~/components/layout/app-content'; -import { VisuallyHidden } from '~/components/visually-hidden'; -import { useIntl } from '~/intl'; -import { useSidebar } from './logic/use-sidebar'; - -type InLayoutProps = { - lastGenerated: string; - children?: React.ReactNode; -}; - -export function InLayout(props: InLayoutProps) { - const { children } = props; - - const { commonTexts } = useIntl(); - - const items = useSidebar({ - layout: 'in', - map: [['international_metrics', ['positive_tests', 'variants']]], - }); - - return ( - <> - - - - - - - {commonTexts.internationaal_layout.headings.sidebar} - - - - - -
    - } - > - {children} - - - ); -} diff --git a/packages/app/src/domain/layout/index.ts b/packages/app/src/domain/layout/index.ts index a73e74e48d..32b2825f8a 100644 --- a/packages/app/src/domain/layout/index.ts +++ b/packages/app/src/domain/layout/index.ts @@ -2,5 +2,4 @@ export { Layout } from './layout'; export { NlLayout } from './nl-layout'; export { VrLayout } from './vr-layout'; export { GmLayout } from './gm-layout'; -export { InLayout } from './in-layout'; export { Content } from './content'; diff --git a/packages/app/src/domain/layout/logic/types.ts b/packages/app/src/domain/layout/logic/types.ts index 40013040df..b78af8890b 100644 --- a/packages/app/src/domain/layout/logic/types.ts +++ b/packages/app/src/domain/layout/logic/types.ts @@ -1,4 +1,4 @@ -export type Layout = 'in' | 'nl' | 'vr' | 'gm'; +export type Layout = 'nl' | 'vr' | 'gm'; export type GmItemKeys = | 'hospital_admissions' @@ -64,21 +64,13 @@ export type NlCategoryKeys = | 'vaccinations' | 'vulnerable_groups'; -export type InItemKeys = 'positive_tests' | 'variants'; - -export type InCategoryKeys = 'international_metrics'; - -export type CategoryKeys = T extends 'in' - ? InCategoryKeys - : T extends 'nl' +export type CategoryKeys = T extends 'nl' ? NlCategoryKeys : T extends 'vr' ? VrCategoryKeys : GmCategoryKeys; -export type ItemKeys = T extends 'in' - ? InItemKeys - : T extends 'nl' +export type ItemKeys = T extends 'nl' ? NlItemKeys : T extends 'vr' ? VrItemKeys diff --git a/packages/app/src/domain/layout/logic/use-sidebar.tsx b/packages/app/src/domain/layout/logic/use-sidebar.tsx index 38aef9364d..0300bfd46a 100644 --- a/packages/app/src/domain/layout/logic/use-sidebar.tsx +++ b/packages/app/src/domain/layout/logic/use-sidebar.tsx @@ -91,11 +91,6 @@ export function useSidebar({ return useMemo(() => { const getHref = (key: ItemKeys) => { const route = mapKeysToReverseRouter[key]; - - if (layout === 'in') { - return reverseRouter.in[route as keyof ReverseRouter['in']](); - } - if (layout === 'nl') { return reverseRouter.nl[route](); } diff --git a/packages/app/src/domain/variants/static-props/get-international-variant-chart-data.ts b/packages/app/src/domain/variants/static-props/get-international-variant-chart-data.ts deleted file mode 100644 index 100c6b7505..0000000000 --- a/packages/app/src/domain/variants/static-props/get-international-variant-chart-data.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { In, InVariants, InVariantsVariant } from '@corona-dashboard/common'; -import { last } from 'lodash'; -import { isDefined, isPresent } from 'ts-is-present'; -import { VariantChartValue } from './get-variant-chart-data'; - -export function getInternationalVariantChartData(data: Record) { - const variantChartData = Object.fromEntries( - Object.entries(data).map(([key, value]) => [ - key, - getVariantChartData(value.variants), - ]) - ); - - return { variantChartData } as const; -} - -const EMPTY_VALUES = { - variantChart: null, -} as const; - -export type VariantChartData = ReturnType; - -function getVariantChartData(variants: InVariants | undefined) { - if (!isDefined(variants) || !isDefined(variants.values)) { - return EMPTY_VALUES; - } - - const completeDateRange = getBaseObjectsCompleteDateRange(variants.values); - - if (!completeDateRange.length) { - return EMPTY_VALUES; - } - - const variantsOfConcern = variants.values.filter( - (x) => last(x.values)?.is_variant_of_concern - ); - - if (!variantsOfConcern.length) { - return EMPTY_VALUES; - } - - /** - * Here it loops through the entire date range list (a VariantChartValue array) and per start/end date - * it looks up a variant of concern item that matches the given dates. - * - * If it exists, it adds a property called `_percentage` to - * the given VariantChartValue. - * - * While doing this it accumulates the total percentage so that after finding the variants of concern - * numbers it can add an `other_percentage` property that represents all of the other variants. - * - * If one of the percentage values is marked as unreliable, the entire VariantChartValue is marked as such. - * - */ - const values = completeDateRange.map((partialChartValue) => { - partialChartValue.is_reliable = true; - const { item, total } = variantsOfConcern.reduce( - ({ item, total }, variantOfConcern) => { - const variantItem = variantOfConcern.values.find( - (x) => - x.date_end_unix === partialChartValue.date_end_unix && - x.date_start_unix === partialChartValue.date_start_unix - ); - - if (isDefined(variantItem) && isPresent(variantItem.percentage)) { - total += variantItem.percentage; - (item as unknown as Record)[ - `${variantOfConcern.name}_percentage` - ] = variantItem.percentage; - if (!variantItem.is_reliable) { - partialChartValue.is_reliable = false; - } - } - - return { item, total }; - }, - { item: partialChartValue, total: 0 } - ); - - (item as unknown as Record)['other_percentage'] = - parseFloat((100 - total).toFixed(2)); - - return item; - }); - - return { - variantChart: values, - } as const; -} - -/** - * The different historical value lists are of different lengths, - * so here we create a start to end range based on all of them. - * - * First it creates a flatmap of all the start and end dates (plus the sample_size), - * which is then de-duped and finally re-sorted by end date. - * - */ -function getBaseObjectsCompleteDateRange(lists: InVariantsVariant[]) { - return lists - .flatMap((x) => x.values) - .map((x) => ({ - date_start_unix: x.date_start_unix, - date_end_unix: x.date_end_unix, - sample_size: x.sample_size, - is_reliable: true, - })) - .filter( - ({ date_start_unix, date_end_unix }, index, array) => - array.findIndex( - (y) => - y.date_end_unix === date_end_unix && - y.date_start_unix === date_start_unix - ) === index - ) - .sort((a, b) => a.date_end_unix - b.date_end_unix); -} diff --git a/packages/app/src/domain/variants/static-props/get-international-variant-table-data.ts b/packages/app/src/domain/variants/static-props/get-international-variant-table-data.ts deleted file mode 100644 index ed6b0ffc99..0000000000 --- a/packages/app/src/domain/variants/static-props/get-international-variant-table-data.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { In } from '@corona-dashboard/common'; -import { getVariantTableData } from './get-variant-table-data'; - -export function getInternationalVariantTableData(data: Record) { - const variantTableData = Object.fromEntries( - Object.entries(data).map(([key, value]) => [ - key, - getVariantTableData(value.variants, value.named_difference), - ]) - ); - - return { variantTableData } as const; -} diff --git a/packages/app/src/domain/variants/static-props/get-variant-table-data.ts b/packages/app/src/domain/variants/static-props/get-variant-table-data.ts index ec2767945a..12132ce183 100644 --- a/packages/app/src/domain/variants/static-props/get-variant-table-data.ts +++ b/packages/app/src/domain/variants/static-props/get-variant-table-data.ts @@ -1,14 +1,9 @@ import { colors, - InNamedDifference, - InVariants, - InVariantsVariant, - InVariantsVariantValue, NlNamedDifference, NlVariants, NlVariantsVariant, - NlVariantsVariantValue, - OptionalNamedDifferenceDecimal, + NamedDifferenceDecimal, } from '@corona-dashboard/common'; import { first } from 'lodash'; import { isDefined, isPresent } from 'ts-is-present'; @@ -16,7 +11,7 @@ import { isDefined, isPresent } from 'ts-is-present'; export type VariantRow = { variant: string; percentage: number | null; - difference?: OptionalNamedDifferenceDecimal | null; + difference?: NamedDifferenceDecimal | null; color: string; }; @@ -50,8 +45,8 @@ export const VARIANT_TABLE_MAP = [ ]; export function getVariantTableData( - variants: NlVariants | InVariants | undefined, - namedDifference: NlNamedDifference | InNamedDifference + variants: NlVariants | undefined, + namedDifference: NlNamedDifference ) { if (!isDefined(variants) || !isDefined(variants.values)) { return { @@ -75,9 +70,7 @@ export function getVariantTableData( } } - const firstLastValue = first( - variants.values - ); + const firstLastValue = first(variants.values); const dates = { date_end_unix: firstLastValue?.last_value.date_end_unix ?? 0, @@ -87,17 +80,6 @@ export function getVariantTableData( }; const sampleSize = firstLastValue?.last_value.sample_size ?? 0; - const inVariants = variants.values - .map((x) => x.last_value) - .filter(isInVariant); - /** - * Only international data has the is_reliable key, - * so for national data we assume it is reliable by default. - */ - const isReliable = inVariants.length - ? inVariants.some((x) => x.is_reliable) - : true; - const getVariantSortingRank = (variantName: string): number => { const index = VARIANT_TABLE_MAP.findIndex((variant) => variantName.includes(variant) @@ -170,11 +152,5 @@ export function getVariantTableData( return 0; }); - return { variantTable, dates, sampleSize, isReliable }; -} - -function isInVariant( - value: NlVariantsVariantValue | InVariantsVariantValue -): value is InVariantsVariantValue { - return 'is_reliable' in value; + return { variantTable, dates, sampleSize }; } diff --git a/packages/app/src/domain/variants/static-props/index.ts b/packages/app/src/domain/variants/static-props/index.ts index 1e70585020..5cc693e298 100644 --- a/packages/app/src/domain/variants/static-props/index.ts +++ b/packages/app/src/domain/variants/static-props/index.ts @@ -1,5 +1,3 @@ -export * from './get-international-variant-chart-data'; -export * from './get-international-variant-table-data'; export * from './get-variant-chart-data'; export * from './get-variant-sidebar-value'; export * from './get-variant-table-data'; diff --git a/packages/app/src/pages/api/choropleth/[...param].ts b/packages/app/src/pages/api/choropleth/[...param].ts index bfd4d6418a..53569ba2f6 100644 --- a/packages/app/src/pages/api/choropleth/[...param].ts +++ b/packages/app/src/pages/api/choropleth/[...param].ts @@ -1,5 +1,5 @@ import { assert, vrData } from '@corona-dashboard/common'; -import { geoConicConformal, geoMercator } from 'd3-geo'; +import { geoMercator } from 'd3-geo'; import fs from 'fs'; import hash from 'hash-sum'; import Konva from 'konva-node'; @@ -21,7 +21,7 @@ import { createDataConfig } from '~/components/choropleth/logic/create-data-conf import { getProjectedCoordinates } from '~/components/choropleth/logic/use-projected-coordinates'; import { dataUrltoBlob } from '~/utils/api/data-url-to-blob'; import { resolvePublicFolder } from '~/utils/api/resolve-public-folder'; -import { gmGeo, inGeo, nlGeo, vrGeo } from './topology'; +import { gmGeo, nlGeo, vrGeo } from './topology'; /** * The combination node-canvas and sharp leads to runtime crashes under Windows, this * ENV variable disables compression. By conditionally importing the sharp lib we @@ -99,18 +99,17 @@ export default async function handler( } function createGeoJson(map: MapType) { - const outlineGeo = map === 'in' ? undefined : nlGeo; assert( - map === 'in' || map === 'vr' || map === 'gm', + map === 'vr' || map === 'gm', `[${createGeoJson.name}] Unknown maptype: ${map}` ); - const featureGeo = map === 'in' ? inGeo : map === 'vr' ? vrGeo : gmGeo; + const featureGeo = map === 'vr' ? vrGeo : gmGeo; - return [featureGeo, outlineGeo] as const; + return [featureGeo, nlGeo] as const; } -const validMapTypes: MapType[] = ['gm', 'vr', 'in']; +const validMapTypes: MapType[] = ['gm', 'vr']; function loadChoroplethData(map: MapType, metric: string) { if (!validMapTypes.includes(map)) { throw new Error(`Invalid map type: ${map}`); @@ -154,10 +153,8 @@ async function generateChoroplethImage( const dataOptions: DataOptions = {}; - const aspectRatio = - map === 'in' ? CHOROPLETH_ASPECT_RATIO.in : CHOROPLETH_ASPECT_RATIO.nl; - - const mapProjection = map === 'in' ? geoConicConformal : geoMercator; + const aspectRatio = CHOROPLETH_ASPECT_RATIO.nl; + const mapProjection = geoMercator; const width = height * (1 / aspectRatio); diff --git a/packages/app/src/pages/api/choropleth/topology.ts b/packages/app/src/pages/api/choropleth/topology.ts index 501e69d7f7..6d956e462d 100644 --- a/packages/app/src/pages/api/choropleth/topology.ts +++ b/packages/app/src/pages/api/choropleth/topology.ts @@ -1,6 +1,5 @@ import type { FeatureCollection, MultiPolygon, Polygon } from 'geojson'; import * as topojson from 'topojson-client'; -import inTopology from '../topo-json/in.topo.json'; import nlTopology from '../topo-json/nl-vr-gm.topo.json'; export type CodedGeoProperties = { @@ -26,8 +25,3 @@ export const gmGeo = topojson.feature( nlTopology, nlTopology.objects.gm_features ) as CodedGeoJSON; - -export const inGeo = topojson.feature( - inTopology, - inTopology.objects.in_features -) as CodedGeoJSON; diff --git a/packages/app/src/pages/api/data/choropleth/[...param].ts b/packages/app/src/pages/api/data/choropleth/[...param].ts index 50c845ca31..f38dca7ee3 100644 --- a/packages/app/src/pages/api/data/choropleth/[...param].ts +++ b/packages/app/src/pages/api/data/choropleth/[...param].ts @@ -10,7 +10,6 @@ const publicPath = resolvePublicFolder(path.resolve(__dirname)); const publicJsonPath = path.resolve(publicPath, 'json'); const choroplethScopes = { - in: 'IN_COLLECTION', vr: 'VR_COLLECTION', gm: 'GM_COLLECTION', } as const; diff --git a/packages/app/src/pages/api/topo-json/[type].ts b/packages/app/src/pages/api/topo-json/[type].ts index c2b6a12f40..a4b153d29f 100644 --- a/packages/app/src/pages/api/topo-json/[type].ts +++ b/packages/app/src/pages/api/topo-json/[type].ts @@ -1,5 +1,4 @@ import { NextApiRequest, NextApiResponse } from 'next/dist/shared/lib/utils'; -import inTopology from './in.topo.json'; import nlTopology from './nl-vr-gm.topo.json'; export default function handler(req: NextApiRequest, res: NextApiResponse) { @@ -36,10 +35,6 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) { res.status(200).json(result); break; } - case 'in': { - res.status(200).json(inTopology); - break; - } default: { res.status(404); } diff --git a/packages/app/src/pages/api/topo-json/in.topo.json b/packages/app/src/pages/api/topo-json/in.topo.json deleted file mode 100644 index 6bbdc8d158..0000000000 --- a/packages/app/src/pages/api/topo-json/in.topo.json +++ /dev/null @@ -1,15072 +0,0 @@ -{ - "type": "Topology", - "arcs": [ - [ - [5944, 17021], - [-38, -27] - ], - [ - [5906, 16994], - [-48, -140], - [-20, -21], - [-102, -27], - [-7, -9], - [54, -37], - [-75, -42], - [-60, -57], - [4, -17], - [73, -73], - [28, -51], - [95, -43], - [84, -4], - [51, 60], - [-9, 50], - [58, 49], - [14, -8], - [54, -91], - [64, -50], - [-1, -56], - [17, -3], - [70, 32] - ], - [ - [6250, 16456], - [19, -2], - [67, -52], - [-77, -5], - [-1, -48], - [38, -41], - [14, -107], - [38, -51], - [8, -106], - [-40, -28], - [37, -64], - [27, -147], - [-4, -39], - [-57, -128], - [-7, -81], - [-49, -118], - [-44, -8], - [42, -83], - [-11, -10], - [-119, 5], - [-59, -41], - [-31, -7], - [-183, -14], - [-26, -9], - [6, -46], - [-97, -28], - [-72, -84], - [-51, -5], - [8, 41], - [-56, 5], - [14, -68], - [-12, -20], - [-105, -82], - [-30, -13], - [-133, -16], - [-86, -37], - [-19, 37], - [-17, -2], - [-102, -50], - [59, 71], - [-54, -3], - [92, 73], - [-13, 2], - [-116, -39] - ], - [ - [5048, 15008], - [-8, -2] - ], - [ - [5040, 15006], - [-75, -18], - [46, 70], - [71, 56], - [-115, -36], - [-18, 1], - [-22, 46], - [-37, -24], - [6, 67] - ], - [ - [4896, 15168], - [18, 35], - [116, 63], - [-5, 37], - [-20, 2], - [-134, -23], - [-20, 2], - [-3, 37], - [123, 68], - [64, -20], - [23, 71], - [-30, 19], - [79, 33], - [17, 51], - [17, 8], - [119, 14], - [139, 38], - [10, 12], - [-35, 51], - [-13, -3], - [-59, -69], - [-24, -9], - [-111, 5], - [-117, -25], - [108, 85], - [20, 22], - [38, 78], - [-23, 32], - [61, 97], - [20, 14], - [87, 27], - [-35, 41], - [-22, 3], - [-118, -18], - [-22, 8], - [-35, 73], - [-11, 5], - [-52, -42], - [-7, 49], - [-104, 13], - [20, 27], - [-33, 41], - [48, 6], - [47, 41], - [-2, 74], - [11, 10], - [97, 29], - [8, 50], - [-13, 6], - [-100, -9], - [-10, 13], - [27, 101], - [-7, 22], - [-79, 73], - [41, 35], - [77, -7], - [9, 23], - [124, -7], - [76, -49], - [64, 33], - [108, -18], - [55, 13], - [-47, 44], - [9, 14], - [110, 64], - [20, 18], - [27, 65], - [-17, 7], - [-149, -9], - [-25, 3], - [-29, 32], - [14, 18], - [126, 97], - [13, 20], - [-32, 46], - [48, 84], - [31, 18], - [175, 50], - [30, -7], - [44, -100], - [-13, 111], - [8, 15], - [76, 12], - [-30, 41], - [131, -78], - [9, -14], - [-71, -41], - [-37, -48] - ], - [ - [5040, 15006], - [8, 2] - ], - [ - [5048, 15008], - [-8, -2] - ], - [ - [16387, 9197], - [3, -20] - ], - [ - [16390, 9177], - [-18, -73] - ], - [ - [16372, 9104], - [0, -26] - ], - [ - [16372, 9078], - [0, -63] - ], - [ - [16372, 9015], - [-2, -78] - ], - [ - [16370, 8937], - [-50, 6] - ], - [ - [16320, 8943], - [-11, -28] - ], - [ - [16309, 8915], - [-16, -65] - ], - [ - [16293, 8850], - [-12, -19] - ], - [ - [16281, 8831], - [-80, -12] - ], - [ - [16201, 8819], - [-81, 25], - [-54, -4], - [-51, -37], - [-57, -103], - [-59, -24], - [-54, 14] - ], - [ - [15845, 8690], - [-14, -1] - ], - [ - [15831, 8689], - [-110, -25], - [-34, 3] - ], - [ - [15687, 8667], - [-11, 20] - ], - [ - [15676, 8687], - [-13, 16] - ], - [ - [15663, 8703], - [-50, 1], - [-56, 115] - ], - [ - [15557, 8819], - [-30, 111] - ], - [ - [15527, 8930], - [10, 75], - [-24, 39] - ], - [ - [15513, 9044], - [3, 16] - ], - [ - [15516, 9060], - [21, 39], - [19, 156] - ], - [ - [15556, 9255], - [55, 30], - [14, 78], - [19, 35], - [69, 39] - ], - [ - [15713, 9437], - [19, 3] - ], - [ - [15732, 9440], - [59, -37] - ], - [ - [15791, 9403], - [6, 1] - ], - [ - [15797, 9404], - [27, 57] - ], - [ - [15824, 9461], - [26, 13], - [65, 0], - [13, 12] - ], - [ - [15928, 9486], - [17, 0], - [75, 41] - ], - [ - [16020, 9527], - [17, 5] - ], - [ - [16037, 9532], - [45, -9], - [59, 27] - ], - [ - [16141, 9550], - [7, -4] - ], - [ - [16148, 9546], - [28, -36] - ], - [ - [16176, 9510], - [5, -9] - ], - [ - [16181, 9501], - [55, -84], - [89, -68], - [19, -29] - ], - [ - [16344, 9320], - [15, -71], - [28, -52] - ], - [ - [2908, 23763], - [21, 2], - [22, -52], - [67, -23], - [-5, -59], - [13, -15], - [100, -60], - [17, -2], - [36, 54], - [75, 22], - [73, 52], - [76, -11], - [-92, -36], - [-14, -13], - [-20, -68], - [-51, -31], - [21, -36], - [111, 6], - [18, -6], - [35, -50], - [-6, -20], - [-84, -101], - [31, -13], - [135, 19], - [16, -35], - [102, -55], - [75, -15], - [73, -65], - [-11, -50], - [-51, -18], - [49, -79], - [-19, -63], - [59, -36], - [-35, -42], - [-18, 1], - [-115, 39], - [-51, -19], - [88, -13], - [62, -37], - [-87, -16], - [63, -37], - [-47, -19], - [-42, -63], - [-95, -13], - [-72, -66], - [32, -23], - [-32, -77], - [-71, -3], - [-72, -56], - [-72, -23], - [-72, 33], - [-43, -48], - [-158, -62], - [-118, -81], - [-57, -55], - [-125, -29], - [-53, -42], - [-78, 9], - [-123, -32], - [-38, 14], - [-82, -51], - [37, -21], - [-41, -64], - [-35, -18], - [-207, -60], - [-48, -6], - [-138, 14], - [-37, 9], - [-123, 51], - [-35, 7], - [-121, 0], - [-82, 36], - [-66, 91], - [-18, -19], - [-178, 81], - [-34, 37], - [-57, -39], - [-45, -5], - [-272, 5], - [-50, -2], - [-87, -18], - [-10, 5], - [14, 55], - [-11, 81], - [48, -38], - [27, 0], - [151, 36], - [19, 11], - [-7, 46], - [60, -9], - [32, 40], - [-55, 21], - [51, 54], - [-72, -20], - [20, 45], - [-45, 21], - [7, 17], - [90, 109], - [-126, -89], - [-56, 12], - [-52, 101], - [27, 56], - [-41, 28], - [-51, -23], - [-32, 1], - [-207, 31], - [-72, -5], - [-73, -45], - [-86, 28], - [-18, 65], - [62, 14], - [67, -14], - [47, 25], - [72, -8], - [33, 40], - [78, -5], - [75, 41], - [52, -36], - [20, 25], - [30, 4], - [196, -5], - [31, 10], - [14, 79], - [-72, -37], - [-29, -3], - [-132, 19], - [-13, 11], - [40, 60], - [28, 17], - [167, 74], - [-51, 4], - [-16, 37], - [-98, -32], - [-40, 36], - [-92, 32], - [-22, -22], - [-86, 48], - [-62, -19], - [-32, -48], - [-43, 9], - [-144, -46], - [-25, -2], - [-83, 33], - [-126, 14], - [-10, 10], - [57, 60], - [22, 2], - [109, -50], - [-33, 55], - [62, -4], - [-77, 58], - [-3, 36], - [129, -36], - [62, -58], - [77, 31], - [-59, 26], - [81, 32], - [-145, 4], - [-25, 7], - [-33, 41], - [20, 27], - [71, -24], - [-68, 78], - [33, 34], - [80, -19], - [-56, 56], - [56, 37], - [23, -1], - [105, -41], - [84, -62], - [24, 18], - [123, -60], - [11, 2], - [-30, 69], - [-17, 14], - [-91, 32], - [-59, 46], - [68, 21], - [71, -13], - [48, 19], - [-76, 49], - [-20, 3], - [-73, -23], - [-17, 5], - [-48, 60], - [8, 7], - [131, -9], - [84, 14], - [20, -10], - [59, -82], - [17, -12], - [74, -5], - [61, -48], - [22, -52], - [60, -3], - [67, -71], - [14, -73], - [-50, -44], - [32, -14], - [-84, -49], - [72, -35], - [51, -82], - [47, -153], - [2, 118], - [6, 12], - [53, -28], - [-16, 60], - [13, 61], - [82, 59], - [11, -2], - [8, -60], - [15, -1], - [100, 50], - [14, 14], - [-3, 51], - [-53, 164], - [33, 32], - [81, 4], - [19, -13], - [56, -96], - [67, -44], - [24, -51], - [53, -12], - [18, 57], - [-26, 59], - [15, 65], - [100, 35], - [42, 38], - [79, 8], - [92, -69], - [12, -59], - [83, -46], - [18, -21], - [40, -106], - [9, 85], - [-49, 65], - [-37, 84], - [21, 57], - [92, -4], - [25, -13], - [100, -77], - [66, -27], - [25, 61], - [61, 76], - [14, 7], - [60, -16], - [14, -31], - [131, 26], - [19, 12], - [19, 75], - [-35, 87], - [16, 15], - [148, 19] - ], - [ - [16598, 15560], - [-57, -38] - ], - [ - [16541, 15522], - [-28, -27], - [-60, -113], - [26, -30], - [73, -23], - [17, -16], - [48, -92], - [2, -28] - ], - [ - [16619, 15193], - [-28, -120] - ], - [ - [16591, 15073], - [-9, -52], - [27, -32] - ], - [ - [16609, 14989], - [-2, -58] - ], - [ - [16607, 14931], - [22, -59] - ], - [ - [16629, 14872], - [-8, -62] - ], - [ - [16621, 14810], - [54, -68], - [32, -99], - [68, -79], - [2, -13], - [-45, -42], - [26, -37], - [14, -99], - [-36, -80], - [-115, -55], - [-36, -33], - [-153, -188], - [-37, -51], - [-111, -174], - [-12, -39], - [24, -106] - ], - [ - [16296, 13647], - [-9, -83], - [7, -21] - ], - [ - [16294, 13543], - [14, -24] - ], - [ - [16308, 13519], - [27, -47] - ], - [ - [16335, 13472], - [-29, 7] - ], - [ - [16306, 13479], - [-27, 8] - ], - [ - [16279, 13487], - [-52, -10] - ], - [ - [16227, 13477], - [-12, 24], - [-137, 69], - [-23, 17] - ], - [ - [16055, 13587], - [-29, 56] - ], - [ - [16026, 13643], - [-70, 41] - ], - [ - [15956, 13684], - [-43, 18] - ], - [ - [15913, 13702], - [-107, 15] - ], - [ - [15806, 13717], - [-74, -18] - ], - [ - [15732, 13699], - [-52, -58], - [-24, -2], - [-59, 45], - [-22, 6], - [-117, -10], - [-53, -50], - [-29, -60] - ], - [ - [15376, 13570], - [-15, -7] - ], - [ - [15361, 13563], - [-72, 9], - [-11, 13], - [0, 94], - [-61, 37] - ], - [ - [15217, 13716], - [-21, 33] - ], - [ - [15196, 13749], - [-37, 53], - [-59, -46] - ], - [ - [15100, 13756], - [-10, -12] - ], - [ - [15090, 13744], - [-24, -48] - ], - [ - [15066, 13696], - [-66, 0] - ], - [ - [15000, 13696], - [-1, 42], - [-41, 27] - ], - [ - [14958, 13765], - [-23, 76], - [-51, 45], - [-19, 83], - [-13, 12], - [-104, 23], - [-84, 60], - [-48, -23], - [-16, 7], - [-62, 76] - ], - [ - [14538, 14124], - [35, 50] - ], - [ - [14573, 14174], - [-8, 46], - [-84, -29] - ], - [ - [14481, 14191], - [-14, 2], - [-89, 72] - ], - [ - [14378, 14265], - [-82, 29], - [-11, -33], - [30, -82], - [-4, -14], - [-62, -21], - [-33, -36], - [-47, 31], - [-70, 109], - [-48, 35], - [63, 91], - [-17, 42] - ], - [ - [14097, 14416], - [-12, 5] - ], - [ - [14085, 14421], - [-75, 3], - [-45, -17], - [-59, 44], - [-110, 56], - [-40, 2], - [-28, 83], - [-80, 47], - [-11, -5], - [-19, -80] - ], - [ - [13618, 14554], - [-55, -18] - ], - [ - [13563, 14536], - [51, 133], - [19, 96], - [-16, 113], - [-24, 28] - ], - [ - [13593, 14906], - [-61, 52] - ], - [ - [13532, 14958], - [2, 30] - ], - [ - [13534, 14988], - [1, 30] - ], - [ - [13535, 15018], - [-37, 71], - [2, 26], - [44, 163], - [-14, 73], - [-22, 28] - ], - [ - [13508, 15379], - [-22, 25], - [-11, 55] - ], - [ - [13475, 15459], - [0, 3] - ], - [ - [13475, 15462], - [26, 47] - ], - [ - [13501, 15509], - [-2, 29] - ], - [ - [13499, 15538], - [-26, 57], - [-124, 115] - ], - [ - [13349, 15710], - [-6, 7] - ], - [ - [13343, 15717], - [0, 73], - [55, 46] - ], - [ - [13398, 15836], - [13, 21] - ], - [ - [13411, 15857], - [21, 102], - [-1, 27], - [-30, 91], - [-10, 154] - ], - [ - [13391, 16231], - [8, 12], - [65, -46], - [13, 6], - [24, 92], - [-7, 15], - [-70, 14], - [-35, -28], - [-35, 41], - [87, 21], - [188, 85], - [227, 77], - [46, 13], - [108, 14], - [31, 20], - [107, 128], - [31, 23], - [110, 32], - [70, 51], - [121, 47], - [176, 37], - [92, 5], - [77, -31], - [12, -26], - [30, -156], - [18, -28], - [103, -41], - [28, -5], - [100, 10], - [14, -6], - [0, -46], - [14, 3], - [102, 70], - [29, 9], - [181, 1] - ], - [ - [15456, 16644], - [720, -41] - ], - [ - [16176, 16603], - [113, 15] - ], - [ - [16289, 16618], - [32, -9], - [54, 9], - [23, -10], - [109, -79] - ], - [ - [16507, 16529], - [19, -19] - ], - [ - [16526, 16510], - [17, -33] - ], - [ - [16543, 16477], - [6, -10] - ], - [ - [16549, 16467], - [14, -97] - ], - [ - [16563, 16370], - [-3, -33], - [51, -216], - [66, -198], - [27, -133] - ], - [ - [16704, 15790], - [4, -94] - ], - [ - [16708, 15696], - [-3, -50], - [-16, -23], - [-91, -63] - ], - [ - [10689, 13930], - [3, -7] - ], - [ - [10692, 13923], - [0, -12] - ], - [ - [10692, 13911], - [-30, -81], - [-13, -96] - ], - [ - [10649, 13734], - [-71, 7] - ], - [ - [10578, 13741], - [-58, -16] - ], - [ - [10520, 13725], - [-20, 2], - [-46, 52] - ], - [ - [10454, 13779], - [25, 58] - ], - [ - [10479, 13837], - [-38, 73] - ], - [ - [10441, 13910], - [-8, 73] - ], - [ - [10433, 13983], - [51, 108] - ], - [ - [10484, 14091], - [11, 20] - ], - [ - [10495, 14111], - [19, 26], - [43, -13] - ], - [ - [10557, 14124], - [6, -60] - ], - [ - [10563, 14064], - [9, -20] - ], - [ - [10572, 14044], - [25, -54], - [33, -26] - ], - [ - [10630, 13964], - [8, -5] - ], - [ - [10638, 13959], - [6, -3] - ], - [ - [10644, 13956], - [45, -26] - ], - [ - [18216, 11404], - [7, -89], - [35, -35], - [108, -36], - [17, 0], - [20, 45], - [32, -19], - [45, 40], - [92, 46], - [21, 3], - [74, -38], - [22, -77], - [9, -2] - ], - [ - [18698, 11242], - [-1, -82], - [-32, -143], - [-17, -21], - [-92, -9], - [-81, -53], - [30, 50], - [-24, 39], - [14, 65], - [-27, 19], - [-44, -34], - [11, -113], - [-38, -33], - [-20, -144], - [-30, -88], - [3, -142], - [-25, -156], - [-18, -33], - [-131, 22] - ], - [ - [18176, 10386], - [-59, 46], - [-24, 64], - [-57, -8], - [-61, 45], - [-65, 0], - [-52, 52], - [-97, 23], - [-37, -7], - [-214, -71], - [-38, -23], - [-119, -139], - [-29, -22], - [-105, -27], - [-30, 2], - [-134, 47], - [-57, -5], - [-82, 30], - [-104, -22], - [-35, 5], - [-167, 55], - [-91, 11] - ], - [ - [16519, 10442], - [-138, -19] - ], - [ - [16381, 10423], - [-23, 44] - ], - [ - [16358, 10467], - [-1, 13] - ], - [ - [16357, 10480], - [16, 31] - ], - [ - [16373, 10511], - [6, 10] - ], - [ - [16379, 10521], - [3, 6] - ], - [ - [16382, 10527], - [14, 31] - ], - [ - [16396, 10558], - [-3, 12] - ], - [ - [16393, 10570], - [-10, 12] - ], - [ - [16383, 10582], - [-72, 49], - [-33, 44] - ], - [ - [16278, 10675], - [-2, 22], - [-50, 55], - [-8, 50], - [81, 52] - ], - [ - [16299, 10854], - [-2, 12] - ], - [ - [16297, 10866], - [-95, 69], - [-23, -5], - [-76, -106], - [-15, -6], - [-44, 78], - [-60, 30], - [-50, 0], - [-36, 47], - [-62, 37], - [43, 36], - [-47, 66], - [35, 59], - [-17, 40], - [-156, 96], - [-62, 69], - [-8, 27] - ], - [ - [15624, 11403], - [-2, 135] - ], - [ - [15622, 11538], - [-31, 16] - ], - [ - [15591, 11554], - [-38, 69] - ], - [ - [15553, 11623], - [-70, 57], - [-43, 50] - ], - [ - [15440, 11730], - [5, 30] - ], - [ - [15445, 11760], - [57, 27] - ], - [ - [15502, 11787], - [4, 1] - ], - [ - [15506, 11788], - [74, -13] - ], - [ - [15580, 11775], - [14, 7] - ], - [ - [15594, 11782], - [40, 55], - [79, -2] - ], - [ - [15713, 11835], - [19, 9], - [59, 83], - [19, 118], - [51, 46], - [22, 44], - [99, 271], - [19, 45], - [38, 45], - [21, 93], - [35, 27], - [48, 83], - [60, 41] - ], - [ - [16203, 12740], - [23, 1] - ], - [ - [16226, 12741], - [46, 3] - ], - [ - [16272, 12744], - [67, 82] - ], - [ - [16339, 12826], - [10, 21] - ], - [ - [16349, 12847], - [12, 0], - [67, 65], - [22, 1] - ], - [ - [16450, 12913], - [92, -50] - ], - [ - [16542, 12863], - [102, -2] - ], - [ - [16644, 12861], - [143, -46], - [26, -3] - ], - [ - [16813, 12812], - [67, 24], - [71, -29], - [92, -96], - [20, -11], - [65, 36], - [70, 69], - [41, 16], - [220, 41], - [37, 20], - [41, 101], - [22, 19], - [90, 24] - ], - [ - [17649, 13026], - [42, -5] - ], - [ - [17691, 13021], - [20, -12] - ], - [ - [17711, 13009], - [36, -30] - ], - [ - [17747, 12979], - [3, -4] - ], - [ - [17750, 12975], - [21, -17] - ], - [ - [17771, 12958], - [18, -28], - [62, -142], - [24, -99], - [21, -43], - [135, -239], - [29, -46] - ], - [ - [18060, 12361], - [68, -80] - ], - [ - [18128, 12281], - [15, -29], - [48, -151], - [7, -37], - [3, -111] - ], - [ - [18201, 11953], - [-45, -143] - ], - [ - [18156, 11810], - [-6, -119], - [21, -195], - [-24, -48], - [33, -60], - [36, 16] - ], - [ - [16981, 5470], - [87, 0], - [64, -48], - [86, -2], - [41, -19], - [73, 19], - [9, -8], - [-11, -73], - [23, -42], - [89, 54], - [72, 28], - [21, -50], - [-24, -78], - [-15, -11], - [-121, -2], - [-159, -19], - [-101, -33], - [-94, -4], - [-16, 9], - [-16, 68], - [-14, 17], - [-81, 46], - [-112, 11], - [-66, 30], - [-80, -5], - [-58, 36], - [-2, 23], - [21, 128], - [37, -18], - [23, 81], - [20, -69], - [34, -5], - [70, 36], - [16, -11], - [48, -115], - [23, -11], - [113, 37] - ], - [ - [17828, 5468], - [-27, 95], - [0, 25], - [30, 104], - [18, -5], - [-18, -78], - [19, -109], - [-22, -32] - ], - [ - [16415, 5976], - [-5, -48], - [-43, 11], - [4, 84], - [44, -47] - ], - [ - [18053, 5756], - [-33, 34], - [11, 65], - [-10, 62], - [83, 105], - [79, 45], - [15, -15], - [-43, -183], - [-9, -24], - [-30, -5], - [-63, -84] - ], - [ - [16892, 6251], - [23, -35], - [-56, -16], - [33, 51] - ], - [ - [17886, 6323], - [-50, -36], - [-52, -16], - [33, 50], - [69, 2] - ], - [ - [17140, 6462], - [40, 7], - [-13, -58], - [-38, -7], - [11, 58] - ], - [ - [17253, 6502], - [34, -51], - [-40, -88], - [-9, -3], - [-30, 65], - [45, 77] - ], - [ - [17120, 6774], - [38, -4], - [-20, -43], - [-18, 47] - ], - [ - [17542, 6796], - [-7, -27], - [-95, -58], - [16, 56], - [86, 29] - ], - [ - [16565, 6804], - [-18, 41], - [35, 1], - [-17, -42] - ], - [ - [17642, 6838], - [-2, 11], - [67, 22], - [83, -47], - [-60, -44], - [-18, 3], - [-70, 55] - ], - [ - [15584, 6861], - [12, 74], - [70, -100], - [-31, -38], - [-51, 64] - ], - [ - [17062, 6819], - [-77, 118], - [-5, 18], - [34, 20], - [21, -41], - [28, -6], - [15, -74], - [-16, -35] - ], - [ - [16575, 6970], - [-7, -42], - [-29, 10], - [36, 32] - ], - [ - [15629, 7041], - [-6, -11], - [-75, 19], - [-14, 13], - [-18, 73], - [-36, -32], - [16, 82], - [31, -6], - [31, 78], - [6, -83], - [33, -36], - [32, -97] - ], - [ - [17443, 7094], - [-50, 29], - [28, 73], - [-2, 20], - [-43, 82], - [3, 14], - [77, 16], - [25, -21], - [0, -133], - [-38, -80] - ], - [ - [15566, 7438], - [30, 33], - [6, -115], - [-48, -21], - [12, 103] - ], - [ - [16767, 7377], - [17, -12], - [32, -86], - [-11, -55], - [27, -112], - [42, -32], - [67, -21], - [-17, -79], - [-68, 2], - [-50, 71], - [-11, 75], - [-38, 82], - [-20, 12], - [-108, 5], - [-16, 10], - [-5, 64], - [-18, 28], - [-118, 133], - [-72, 40], - [-56, -14], - [80, 77], - [69, 31], - [13, -8], - [46, -84], - [37, -52], - [72, -48], - [106, -27] - ], - [ - [17492, 7589], - [-24, 34], - [56, 59], - [-29, 9], - [-35, -51], - [-72, 30], - [13, 73], - [46, 3], - [43, 46], - [80, -29], - [61, -141], - [2, -23], - [-43, -31], - [-98, 21] - ], - [ - [15242, 7998], - [-10, 21], - [28, 26], - [73, -6], - [-27, -47], - [30, -126], - [-8, 3], - [-86, 129] - ], - [ - [17546, 8884], - [3, -137], - [-12, -34], - [-83, -101] - ], - [ - [17454, 8612], - [-44, 47], - [-132, 19], - [-36, 11], - [-124, 60], - [-28, -3], - [-89, -82], - [-51, 16], - [-25, 41], - [-51, -12], - [-16, -51], - [-82, -59], - [-101, 15], - [-27, -71], - [54, -70], - [-11, -56], - [14, -15], - [124, -71], - [35, -60], - [-22, -24], - [-62, 91], - [-64, 36], - [-56, 0], - [-21, -52], - [85, -85], - [10, -20], - [-11, -75], - [-47, 35], - [-51, 101], - [-16, 17], - [-71, 23], - [-22, -37], - [52, -96], - [65, -50], - [-90, 3], - [-15, 9], - [-28, 77], - [-3, 60], - [-16, 20], - [-114, 82], - [-17, 19], - [-7, 61], - [38, 23], - [-13, 40], - [-104, -85], - [-10, -18], - [14, -70], - [-29, -112], - [22, -73], - [80, -139], - [35, -112], - [65, -74], - [42, -78], - [22, -85], - [-6, -12], - [-64, -26], - [27, 48], - [-37, 62], - [-51, 17], - [-35, -65], - [2, -17], - [49, -76], - [-8, -68], - [-65, -40], - [-51, 14], - [41, -61], - [93, -38], - [39, -57], - [53, 4], - [31, -87], - [55, -3], - [38, -65], - [85, -45], - [55, -57], - [-18, -87], - [21, -193], - [-2, -27], - [-35, 0], - [-81, 131], - [-65, 69], - [-50, -30], - [-130, -39], - [7, -40], - [52, -37], - [2, -95], - [41, -41], - [5, 36], - [56, -94], - [-1, -14], - [-68, -17], - [-25, -51], - [-40, 19], - [8, 56], - [-45, 20], - [-59, 60], - [-10, -3], - [-11, -77], - [8, -34], - [65, -161], - [45, -174], - [-14, -109], - [41, -96], - [-65, 33], - [-55, 84], - [-15, 73], - [-59, 3], - [-12, -15], - [-29, -96], - [-6, -112], - [-35, 56], - [4, 96], - [-8, 32], - [-67, 152], - [-17, 20], - [-51, -9], - [-7, -15], - [3, -96], - [-21, -45], - [-65, 61], - [-5, 65], - [-38, 87], - [-1, 30], - [29, 123], - [-6, 35], - [-83, 136], - [-30, 0], - [-18, 77], - [-48, 46], - [3, 23], - [69, 119], - [10, 59], - [83, -16], - [18, 9], - [65, 89], - [41, -9], - [67, -65], - [171, -88], - [70, -65], - [13, 54], - [94, 27], - [10, 11], - [-24, 51], - [-90, 34], - [-69, 64], - [-41, -29], - [-42, 70], - [-19, -48], - [-16, -3], - [-105, 32], - [-32, -2], - [-121, -51], - [-25, 0], - [-51, 51], - [-14, 0], - [-58, -50], - [-21, 33], - [-7, 104], - [-45, 68], - [-19, 63], - [-52, 27], - [11, 70], - [11, 8], - [70, -9], - [30, -29], - [22, 55], - [-10, 15], - [-94, 56], - [-16, 1], - [-16, -41], - [-13, 8], - [-88, 115], - [-38, 31], - [-67, 131], - [3, 35], - [68, 141] - ], - [ - [15484, 8053], - [-6, 54] - ], - [ - [15478, 8107], - [-13, 39] - ], - [ - [15465, 8146], - [30, 47], - [69, 21], - [13, 21], - [38, 139] - ], - [ - [15615, 8374], - [17, 43] - ], - [ - [15632, 8417], - [59, 50], - [19, 97] - ], - [ - [15710, 8564], - [-18, 82] - ], - [ - [15692, 8646], - [-5, 21] - ], - [ - [15831, 8689], - [14, 1] - ], - [ - [16201, 8819], - [80, 12] - ], - [ - [16281, 8831], - [12, 19] - ], - [ - [16309, 8915], - [11, 28] - ], - [ - [16370, 8937], - [70, 1], - [29, 29] - ], - [ - [16469, 8967], - [11, 9] - ], - [ - [16480, 8976], - [102, -5] - ], - [ - [16582, 8971], - [61, 23] - ], - [ - [16643, 8994], - [137, 67] - ], - [ - [16780, 9061], - [111, 17], - [19, -5] - ], - [ - [16910, 9073], - [22, -50], - [67, -60], - [39, 20], - [78, -33], - [39, -47], - [21, 1] - ], - [ - [17176, 8904], - [117, 29] - ], - [ - [17293, 8933], - [105, 5] - ], - [ - [17398, 8938], - [21, 2], - [68, 65] - ], - [ - [17487, 9005], - [-8, 69], - [-29, 77], - [52, 37] - ], - [ - [17502, 9188], - [51, -23] - ], - [ - [17553, 9165], - [72, -64] - ], - [ - [17625, 9101], - [19, -117], - [-9, -23], - [-78, -50], - [-11, -27] - ], - [ - [18052, 13117], - [99, -74] - ], - [ - [18151, 13043], - [45, -50], - [35, 14], - [54, -94], - [20, 36], - [69, -10], - [17, -13], - [46, -82] - ], - [ - [18437, 12844], - [14, -11], - [64, 6] - ], - [ - [18515, 12839], - [28, -57], - [0, -64] - ], - [ - [18543, 12718], - [-4, -20] - ], - [ - [18539, 12698], - [-27, -78], - [7, -28], - [69, -119], - [17, -15], - [42, 14], - [7, -23], - [3, -169], - [13, -33], - [89, -65], - [14, -23], - [17, -119], - [-11, -27], - [67, -67] - ], - [ - [18846, 11946], - [-4, -12], - [-89, -32] - ], - [ - [18753, 11902], - [-34, 52] - ], - [ - [18719, 11954], - [-5, 1] - ], - [ - [18714, 11955], - [-2, 1] - ], - [ - [18712, 11956], - [-33, -41] - ], - [ - [18679, 11915], - [-3, 0] - ], - [ - [18676, 11915], - [-59, 58] - ], - [ - [18617, 11973], - [-50, -12] - ], - [ - [18567, 11961], - [-27, -51], - [-19, 82], - [-10, 5], - [-60, -46], - [-11, -85], - [24, -68], - [-15, -90], - [-69, -48], - [-19, -80], - [-67, -83], - [-12, -93] - ], - [ - [18282, 11404], - [-55, 4] - ], - [ - [18227, 11408], - [-11, -4] - ], - [ - [18156, 11810], - [41, 111], - [4, 32] - ], - [ - [18128, 12281], - [-68, 80] - ], - [ - [17771, 12958], - [-21, 17] - ], - [ - [17750, 12975], - [-3, 4] - ], - [ - [17711, 13009], - [-20, 12] - ], - [ - [17649, 13026], - [42, 53], - [40, 16], - [62, 5], - [39, -17] - ], - [ - [17832, 13083], - [5, 0] - ], - [ - [17837, 13083], - [116, 59], - [23, 4], - [76, -29] - ], - [ - [14120, 12000], - [-12, 5] - ], - [ - [14108, 12005], - [-14, 2] - ], - [ - [14094, 12007], - [-13, -10] - ], - [ - [14081, 11997], - [-17, -19] - ], - [ - [14064, 11978], - [-1, -61] - ], - [ - [14063, 11917], - [-52, -3], - [-37, -46] - ], - [ - [13974, 11868], - [-114, -64] - ], - [ - [13860, 11804], - [-11, -16] - ], - [ - [13849, 11788], - [21, -84] - ], - [ - [13870, 11704], - [-3, -83], - [-16, -20], - [-110, -60], - [-12, -24], - [24, -115], - [-4, -20], - [-54, -23], - [-87, 42], - [-45, -19], - [-15, 9], - [-57, 83], - [-15, 0], - [-51, -77], - [-17, -12], - [-85, -3], - [-35, 19], - [-32, -40], - [-99, 26] - ], - [ - [13157, 11387], - [-12, 31], - [92, 50] - ], - [ - [13237, 11468], - [7, 13], - [-35, 56], - [-54, 33], - [-11, 112], - [-32, 19], - [43, 92], - [-64, 21], - [-19, 37] - ], - [ - [13072, 11851], - [99, 126] - ], - [ - [13171, 11977], - [5, 18] - ], - [ - [13176, 11995], - [36, -3], - [132, -42], - [65, 0], - [61, -31], - [15, 3], - [70, 69], - [32, 51], - [94, 30], - [102, -14], - [21, 4], - [49, 46], - [19, 4] - ], - [ - [13872, 12112], - [92, -18], - [13, 7] - ], - [ - [13977, 12101], - [-2, 30] - ], - [ - [13975, 12131], - [-1, 37] - ], - [ - [13974, 12168], - [47, 48] - ], - [ - [14021, 12216], - [2, -11] - ], - [ - [14023, 12205], - [61, -30], - [22, -100] - ], - [ - [14106, 12075], - [8, -21] - ], - [ - [14114, 12054], - [29, -43], - [-23, -11] - ], - [ - [15361, 13563], - [15, 7] - ], - [ - [15732, 13699], - [74, 18] - ], - [ - [15913, 13702], - [43, -18] - ], - [ - [16026, 13643], - [29, -56] - ], - [ - [16227, 13477], - [-32, -62], - [-32, -116] - ], - [ - [16163, 13299], - [-3, -10] - ], - [ - [16160, 13289], - [-58, -92], - [-3, -99] - ], - [ - [16099, 13098], - [-20, 2], - [-97, -24], - [-20, 6], - [-43, 60], - [-58, 44], - [-117, -21], - [-96, 28] - ], - [ - [15648, 13193], - [-35, 6], - [-46, -17] - ], - [ - [15567, 13182], - [-46, -27], - [-32, -72] - ], - [ - [15489, 13083], - [-37, -50] - ], - [ - [15452, 13033], - [-102, -74] - ], - [ - [15350, 12959], - [-18, -5], - [-76, 32] - ], - [ - [15256, 12986], - [-67, -3], - [-46, -60], - [-24, -10], - [-147, -21], - [-43, -45], - [14, -78], - [-27, -27] - ], - [ - [14916, 12742], - [-41, -4], - [-267, -5] - ], - [ - [14608, 12733], - [-51, 13], - [-38, 27], - [-71, 78], - [-56, 24] - ], - [ - [14392, 12875], - [-50, 30], - [-29, 101], - [-38, 77], - [-1, 23], - [28, 113] - ], - [ - [14302, 13219], - [9, 27] - ], - [ - [14311, 13246], - [57, 117], - [53, 8], - [84, -18] - ], - [ - [14505, 13353], - [25, 4], - [95, 64] - ], - [ - [14625, 13421], - [16, 41], - [50, 30] - ], - [ - [14691, 13492], - [25, 93] - ], - [ - [14716, 13585], - [68, 59] - ], - [ - [14784, 13644], - [62, 83] - ], - [ - [14846, 13727], - [4, 3] - ], - [ - [14850, 13730], - [92, 33] - ], - [ - [14942, 13763], - [16, 2] - ], - [ - [15000, 13696], - [66, 0] - ], - [ - [15090, 13744], - [10, 12] - ], - [ - [15196, 13749], - [21, -33] - ], - [ - [16297, 10866], - [2, -12] - ], - [ - [16278, 10675], - [-40, -130] - ], - [ - [16238, 10545], - [-57, -56], - [-11, -65], - [6, -33], - [51, -169], - [16, -31], - [59, -46], - [70, -90], - [5, -20], - [-16, -69], - [-61, -93], - [-56, -16], - [-33, -31] - ], - [ - [16211, 9826], - [-2, -2] - ], - [ - [16209, 9824], - [-11, -20], - [13, -50], - [-14, -53] - ], - [ - [16197, 9701], - [30, -62] - ], - [ - [16227, 9639], - [-18, -67] - ], - [ - [16209, 9572], - [-1, -1] - ], - [ - [16208, 9571], - [-8, -25] - ], - [ - [16200, 9546], - [-10, -19] - ], - [ - [16190, 9527], - [-49, 23] - ], - [ - [16037, 9532], - [-17, -5] - ], - [ - [15928, 9486], - [-40, 41], - [4, 27], - [61, 133] - ], - [ - [15953, 9687], - [7, 22] - ], - [ - [15960, 9709], - [-9, 25] - ], - [ - [15951, 9734], - [-117, 52] - ], - [ - [15834, 9786], - [9, 42], - [-60, 52], - [-54, 99], - [-63, 37], - [-30, 52], - [-61, -25], - [9, -61], - [-9, -27], - [-53, -60] - ], - [ - [15522, 9895], - [6, -34] - ], - [ - [15528, 9861], - [-50, -29] - ], - [ - [15478, 9832], - [-3, 37], - [-74, 47] - ], - [ - [15401, 9916], - [-13, 10] - ], - [ - [15388, 9926], - [-22, 28] - ], - [ - [15366, 9954], - [-21, 25] - ], - [ - [15345, 9979], - [-21, 18], - [-47, -3] - ], - [ - [15277, 9994], - [-58, 44], - [-16, 17], - [-55, 84] - ], - [ - [15148, 10139], - [-70, 58], - [0, 44] - ], - [ - [15078, 10241], - [46, 39] - ], - [ - [15124, 10280], - [12, 4] - ], - [ - [15136, 10284], - [36, -12], - [8, 16], - [-14, 94], - [-74, 112], - [3, 19], - [92, -8], - [25, 40], - [-57, 61], - [-22, 39] - ], - [ - [15133, 10645], - [-26, 36] - ], - [ - [15107, 10681], - [-38, 9], - [-14, 38], - [4, 50] - ], - [ - [15059, 10778], - [8, 54] - ], - [ - [15067, 10832], - [43, 79], - [24, 120], - [-5, 15] - ], - [ - [15129, 11046], - [-63, 7] - ], - [ - [15066, 11053], - [-38, -10] - ], - [ - [15028, 11043], - [14, 52], - [-11, 69], - [11, 13], - [92, 23], - [7, 40] - ], - [ - [15141, 11240], - [-9, 7] - ], - [ - [15132, 11247], - [-64, 27] - ], - [ - [15068, 11274], - [-36, 32] - ], - [ - [15032, 11306], - [-17, 21] - ], - [ - [15015, 11327], - [25, 81] - ], - [ - [15040, 11408], - [-57, 42], - [12, 50], - [-27, 65] - ], - [ - [14968, 11565], - [8, 76] - ], - [ - [14976, 11641], - [63, 52] - ], - [ - [15039, 11693], - [51, -12], - [21, 14] - ], - [ - [15111, 11695], - [80, 80] - ], - [ - [15191, 11775], - [17, 9], - [74, -16], - [101, 10] - ], - [ - [15383, 11778], - [17, -1], - [40, -47] - ], - [ - [15553, 11623], - [38, -69] - ], - [ - [15622, 11538], - [2, -135] - ], - [ - [16337, 19991], - [-34, -37], - [-79, -26], - [-11, 9], - [-3, 87], - [14, 15], - [97, 19], - [14, -5], - [2, -62] - ], - [ - [18463, 24702], - [105, -35], - [27, -17] - ], - [ - [18595, 24650], - [73, -96], - [68, -60] - ], - [ - [18736, 24494], - [58, -47], - [12, -20] - ], - [ - [18806, 24427], - [-20, -66] - ], - [ - [18786, 24361], - [-117, -120] - ], - [ - [18669, 24241], - [-156, -190], - [-16, -33], - [13, -82], - [15, -30], - [92, -123], - [31, -54], - [45, -105] - ], - [ - [18693, 23624], - [72, -95] - ], - [ - [18765, 23529], - [17, -38], - [65, -214], - [-124, -43], - [23, -44] - ], - [ - [18746, 23190], - [-15, -17] - ], - [ - [18731, 23173], - [-12, -23], - [-6, -80], - [-31, -70], - [68, -19], - [7, -40], - [-76, -58], - [-8, -14], - [20, -72] - ], - [ - [18693, 22797], - [3, -5] - ], - [ - [18696, 22792], - [44, -44], - [97, -17], - [30, -68], - [-10, -19], - [-48, -23], - [-3, -16], - [30, -91], - [22, -25], - [126, -77], - [18, -23], - [0, -82], - [-12, -26], - [-107, -114], - [-70, -39], - [6, -19], - [145, -134], - [28, -20], - [115, -55], - [104, -77], - [30, -63], - [31, -42] - ], - [ - [19272, 21718], - [64, -80], - [5, -18] - ], - [ - [19341, 21620], - [-47, -87], - [-48, -117] - ], - [ - [19246, 21416], - [-4, -7] - ], - [ - [19242, 21409], - [-7, -11] - ], - [ - [19235, 21398], - [-65, -75] - ], - [ - [19170, 21323], - [-28, -30] - ], - [ - [19142, 21293], - [-4, -4] - ], - [ - [19138, 21289], - [-124, -99], - [-24, -26] - ], - [ - [18990, 21164], - [-169, -195] - ], - [ - [18821, 20969], - [-93, -107] - ], - [ - [18728, 20862], - [-14, -15] - ], - [ - [18714, 20847], - [-89, -77] - ], - [ - [18625, 20770], - [-30, -37] - ], - [ - [18595, 20733], - [-43, -53] - ], - [ - [18552, 20680], - [-118, -85] - ], - [ - [18434, 20595], - [-130, -106], - [-203, -194], - [-48, -51] - ], - [ - [18053, 20244], - [-31, -25], - [-82, 3], - [5, -24], - [-156, 41], - [-13, -23], - [-101, -40], - [-119, -25], - [-78, 8], - [-22, -33], - [-59, 9], - [-7, -63], - [-58, 7], - [-30, 50], - [-51, -56], - [-56, 9], - [-85, -61], - [-65, 8], - [-23, -11], - [-116, -87], - [-19, -7], - [-22, 37], - [-25, -2], - [-162, -51], - [-121, -7], - [22, 58], - [-82, -71], - [-17, -47], - [-96, -20], - [93, 65], - [-41, 25], - [35, 27], - [-65, 19], - [-51, 65], - [-2, 17], - [38, 60], - [-12, 2], - [-147, -49], - [-14, 40], - [29, 60], - [-75, -3], - [-26, 9], - [-116, 69], - [-54, -6], - [9, 60], - [-61, -60], - [-17, 5], - [-76, 107], - [26, 28], - [-36, 45], - [23, 57], - [-28, 75], - [55, 24], - [22, 83], - [3, 101], - [-25, 92], - [62, -11], - [0, 12], - [-57, 101], - [-35, 103], - [-50, 53], - [0, 18], - [41, 113], - [-16, 74], - [-41, 8], - [-27, 55], - [24, 70], - [-37, 55], - [2, 18], - [57, 105], - [59, 36], - [13, 25], - [32, 132], - [16, 21], - [78, 14], - [17, -45], - [84, 25], - [75, 51], - [-39, 59], - [16, 64], - [37, -30], - [14, 11], - [73, 110], - [14, 12], - [32, -27], - [35, 27], - [17, 61], - [57, 36], - [97, 37], - [13, 12], - [-6, 51], - [58, 1], - [23, 59], - [113, 128], - [127, 110], - [27, 64], - [102, 109], - [27, 16], - [102, 27], - [72, -34], - [48, 81], - [-22, 60], - [-40, 23], - [-2, 18], - [30, 101], - [4, 93], - [-11, 17], - [-75, 55], - [-75, 29], - [-60, -8], - [-40, 62], - [39, 86], - [-100, -72], - [-56, 4], - [-59, 109] - ], - [ - [16760, 23432], - [-34, 70] - ], - [ - [16726, 23502], - [-22, 38], - [-48, 27] - ], - [ - [16656, 23567], - [-7, 12] - ], - [ - [16649, 23579], - [-25, 118], - [4, 22], - [54, 51], - [12, 26] - ], - [ - [16694, 23796], - [27, 132], - [-11, 40], - [-102, 147], - [-14, 26], - [13, 53], - [48, 36], - [1, 47] - ], - [ - [16656, 24277], - [-99, 42], - [-8, 12], - [30, 56], - [1, 23] - ], - [ - [16580, 24410], - [-19, 115], - [4, 23], - [40, 51], - [-5, 13], - [-69, 46], - [-37, 53] - ], - [ - [16494, 24711], - [-37, -4] - ], - [ - [16457, 24707], - [-9, 10] - ], - [ - [16448, 24717], - [-3, 41], - [-32, 33] - ], - [ - [16413, 24791], - [-87, 64] - ], - [ - [16326, 24855], - [-136, 45], - [-109, 15] - ], - [ - [16081, 24915], - [-48, 39], - [-97, 37], - [-111, 84], - [-137, 73], - [-20, 17], - [-6, 41], - [-77, 34] - ], - [ - [15585, 25240], - [36, 32], - [100, -29], - [29, 19], - [-23, 71], - [30, 24], - [70, 29], - [79, -8], - [40, -32], - [204, -210], - [30, -36], - [8, -41], - [27, -9], - [213, -29], - [46, -22], - [135, 37], - [89, 63], - [27, 0], - [123, -51], - [118, -32], - [76, -50], - [18, -2], - [54, 37], - [46, 110], - [74, 37], - [65, 4], - [49, 48], - [-8, 137], - [39, 84], - [19, 119], - [37, 85], - [49, 9] - ], - [ - [17484, 25634], - [127, 117] - ], - [ - [17611, 25751], - [112, 17], - [81, -19] - ], - [ - [17804, 25749], - [31, 8], - [143, 73], - [31, 10], - [81, -10] - ], - [ - [18090, 25830], - [87, -84], - [70, -46] - ], - [ - [18247, 25700], - [31, -13] - ], - [ - [18278, 25687], - [184, -61], - [32, -18] - ], - [ - [18494, 25608], - [79, -106] - ], - [ - [18573, 25502], - [-26, -42], - [-118, -114], - [-13, -27], - [24, -73] - ], - [ - [18440, 25246], - [-12, -19], - [-148, -65], - [-7, -12], - [109, -27] - ], - [ - [18382, 25123], - [0, -23] - ], - [ - [18382, 25100], - [-84, -131], - [-15, -45] - ], - [ - [18283, 24924], - [-1, -10] - ], - [ - [18282, 24914], - [57, -138], - [38, -44], - [86, -30] - ], - [ - [10305, 20231], - [5, 14], - [89, 60], - [12, -4], - [-11, -102], - [-40, -16], - [-55, 48] - ], - [ - [11596, 22017], - [-200, -63], - [-73, 11], - [27, 42], - [107, 20], - [-16, 28], - [114, 8], - [3, -21], - [55, -16], - [-17, -9] - ], - [ - [12355, 22597], - [33, -36], - [-60, 13], - [27, 23] - ], - [ - [12406, 22626], - [-30, -13], - [3, 32], - [27, -19] - ], - [ - [12363, 22635], - [-44, 21], - [47, 14], - [-3, -35] - ], - [ - [12660, 22904], - [-60, 12], - [51, 65], - [12, 1], - [37, -52], - [-40, -26] - ], - [ - [12769, 23106], - [-135, -94], - [-9, 10], - [60, 151], - [16, 12], - [68, -79] - ], - [ - [13359, 24053], - [-64, 31], - [59, 20], - [5, -51] - ], - [ - [13732, 24594], - [-95, 0], - [40, 31], - [55, -31] - ], - [ - [14046, 24931], - [48, 9], - [38, -30], - [-100, -57], - [14, 78] - ], - [ - [19102, 25535], - [-62, 0] - ], - [ - [19040, 25535], - [-75, 12], - [-50, 29] - ], - [ - [18915, 25576], - [-18, 11] - ], - [ - [18897, 25587], - [-3, 1] - ], - [ - [18894, 25588], - [-14, -15] - ], - [ - [18880, 25573], - [-27, -91] - ], - [ - [18853, 25482], - [-48, -42], - [-161, -35] - ], - [ - [18644, 25405], - [-9, -2] - ], - [ - [18635, 25403], - [-29, -17], - [-48, -85], - [-66, -59], - [-52, 4] - ], - [ - [18573, 25502], - [-79, 106] - ], - [ - [18278, 25687], - [-31, 13] - ], - [ - [18090, 25830], - [-25, 16], - [-65, -4], - [-28, -12], - [-138, -73], - [-30, -8] - ], - [ - [17611, 25751], - [-31, -16], - [-96, -101] - ], - [ - [15585, 25240], - [-166, -15], - [-9, -9], - [65, -64], - [-5, -67], - [-35, -64], - [-73, -72], - [1, -13], - [62, -31], - [0, -11], - [-72, -47], - [-74, 9] - ], - [ - [15279, 24856], - [-237, 65], - [-44, 8] - ], - [ - [14998, 24929], - [-81, -5], - [-101, 39], - [-79, -24], - [-14, -58], - [-1, -139], - [-7, -24], - [-68, -89], - [-49, 2], - [-148, 50], - [-26, 2] - ], - [ - [14424, 24683], - [-38, -36] - ], - [ - [14386, 24647], - [-127, -82], - [-24, -25], - [-47, -112], - [-66, -71], - [-80, -28], - [-9, -46], - [85, -120] - ], - [ - [14118, 24163], - [8, -26] - ], - [ - [14126, 24137], - [-19, -69], - [-117, -98], - [-99, -128], - [-94, -86], - [-9, -22], - [8, -107], - [-14, -18], - [-134, -60], - [-156, -22], - [-12, -37], - [24, -114], - [-18, -85], - [-18, -192], - [-7, -29], - [-35, -51] - ], - [ - [13426, 23019], - [-7, -17] - ], - [ - [13419, 23002], - [-19, -68], - [-47, -68], - [-140, -183], - [-32, -66], - [125, -61], - [14, -22], - [18, -112], - [-2, -27], - [-60, -101], - [-236, 32], - [-45, -4], - [-134, -55], - [-38, -29], - [-129, -151], - [-20, -34], - [-18, -112], - [-46, -87], - [1, -30], - [51, -123], - [3, -24], - [-32, -62], - [14, -83], - [-14, -68], - [5, -28], - [51, -129], - [11, -70], - [-37, -232], - [-1, -69], - [77, -74], - [71, -35], - [78, -112] - ], - [ - [12888, 20715], - [0, -32], - [-59, -128], - [-22, -20] - ], - [ - [12807, 20535], - [-94, -15], - [-11, -16], - [16, -106], - [12, -33], - [65, -128], - [5, -30], - [-30, -105], - [5, -78], - [-20, -58], - [-86, -80], - [-103, -29], - [-10, -13], - [-2, -90], - [-53, -46], - [-4, -33], - [27, -188], - [-3, -46], - [-43, -133], - [-12, -20], - [-49, -3] - ], - [ - [12417, 19285], - [-24, 76], - [-39, 31] - ], - [ - [12354, 19392], - [-1, 1] - ], - [ - [12353, 19393], - [-67, 34], - [-97, 19], - [-14, 10], - [-3, 55], - [-55, 81], - [23, 44], - [-33, 119], - [20, 69], - [29, -37], - [0, 71], - [-68, -14], - [-9, -12], - [7, -90], - [27, -46], - [-45, -48], - [-67, 4], - [59, -55], - [8, -19], - [-4, -93], - [-29, 9], - [-35, -114], - [-13, -15], - [-62, -4], - [-61, -43], - [-38, 42], - [-45, -57], - [-102, -32], - [26, -31], - [-22, -32], - [-189, -202], - [-100, -96], - [-80, -35], - [-26, -44], - [-76, -8], - [-121, -55], - [-31, -6], - [-99, 14], - [-73, -25], - [17, 48], - [-48, -19], - [-4, 53], - [-51, 19], - [-10, -55], - [-62, 29], - [1, 12], - [65, 57], - [-93, 3], - [-134, 60], - [-25, 16], - [-57, 68], - [-78, 36], - [-16, 19], - [-38, 91], - [-2, 30], - [21, 119], - [22, 6], - [135, -78], - [17, -1], - [-17, 82], - [-38, 22], - [5, 17], - [76, 97], - [7, 19], - [-23, 53], - [56, 77], - [5, 69], - [-53, -105], - [-57, -41], - [-12, 6], - [-38, 82], - [13, -82], - [-16, -15], - [-123, -23], - [-26, 9], - [-56, 87], - [3, 27], - [84, 101], - [13, 3], - [11, -81], - [16, 60], - [46, -2], - [57, 51], - [-2, 13], - [-62, 46], - [3, 13], - [84, 46], - [58, 84], - [-7, 52], - [87, 105], - [21, 15], - [77, 12], - [-28, -85], - [-3, -83], - [33, 130], - [18, 31], - [95, 105], - [-104, -78], - [-8, 33], - [-121, -60], - [-20, -15], - [-21, -50], - [-58, -21], - [-49, -69], - [3, -46], - [-40, -28], - [-16, 96], - [-32, -14], - [11, 119], - [-7, 0], - [-59, -106], - [-16, -10], - [-61, 50], - [-20, 71], - [45, 35], - [8, 55], - [71, -42], - [57, 22], - [9, 18], - [9, 114], - [-34, 23], - [-43, -60], - [-70, -40], - [-15, 7], - [-42, 73], - [0, 17], - [43, 58], - [-65, 5], - [-10, 14], - [-4, 111], - [54, 8], - [72, -23], - [23, 2], - [89, 42], - [120, 11], - [87, -52], - [20, 3], - [75, 69], - [25, 4], - [99, -41], - [39, 3], - [191, 72], - [-92, -16], - [-127, -42], - [-32, 3], - [-102, 60], - [-17, 1], - [-19, -45], - [-64, -17], - [-42, 30], - [-27, 1], - [-192, -24], - [-58, -22], - [-102, 32], - [37, 15], - [-70, 43], - [-1, 11], - [63, 44], - [-59, 27], - [59, 45], - [89, -19], - [-83, 39], - [37, 32], - [6, 45], - [-110, 5], - [-13, 7], - [15, 58], - [89, 41], - [34, 48], - [23, 0], - [182, -37], - [128, -1], - [-181, 27], - [24, 20], - [-120, 12], - [-135, -14], - [-7, 6], - [60, 55], - [1, 12], - [-54, 44], - [11, 50], - [53, -46], - [55, 40], - [61, -14], - [79, 23], - [56, 61], - [86, 22], - [20, -9], - [59, -85], - [-40, 101], - [6, 19], - [88, 32] - ], - [ - [10764, 21361], - [-93, -6], - [-49, 9], - [79, 54], - [-85, -2], - [25, 31], - [162, 36], - [87, 0], - [28, -9], - [116, -64], - [25, -5], - [65, 27], - [-78, 11], - [16, 51], - [20, 10], - [126, 23], - [31, 30], - [-180, -44], - [-26, -3], - [-47, 26], - [-131, 0], - [23, 41], - [47, 7], - [-81, 46], - [1, 12], - [83, 41], - [22, 1], - [73, -37], - [89, 26], - [2, -28], - [62, 23], - [61, -13], - [40, -75], - [11, 49], - [-73, 70], - [18, 44], - [81, -58], - [29, -65], - [99, -23], - [-65, 60], - [12, 44], - [-87, 6], - [-23, 54], - [46, 14], - [100, -15], - [12, 52], - [-42, 46], - [70, 32], - [-10, 45], - [54, -10], - [68, 32], - [53, -18], - [76, 23], - [-79, 9], - [10, 11], - [148, 73], - [30, -4], - [65, -101], - [-10, -59], - [114, 60], - [26, 7], - [75, -14], - [118, 8], - [-23, 38], - [25, 50], - [-56, -14], - [81, 66], - [143, 50], - [10, 42], - [-86, 26], - [3, 11], - [105, 69], - [-59, 9], - [-23, -8], - [-105, -69], - [-7, -14], - [56, -42], - [-51, -46], - [-78, -27], - [-95, -63], - [-131, -46], - [-29, 10], - [-35, 95], - [4, 17], - [46, 35], - [-129, -51], - [43, 40], - [-44, 17], - [73, 58], - [118, 33], - [-64, 26], - [19, 73], - [20, 22], - [124, 83], - [17, 18], - [1, 56], - [33, 23], - [76, -30], - [3, 67], - [41, -10], - [11, 57], - [66, -77], - [66, -31], - [53, 86], - [1, 20], - [-32, 60], - [8, 20], - [86, 86], - [-111, -54], - [85, 76], - [-103, -22], - [48, 35], - [99, 27], - [83, 51], - [46, -5], - [148, 36], - [29, 16], - [79, 81], - [-92, -60], - [-65, -14], - [-43, 46], - [9, 19], - [94, 87], - [12, 22], - [-11, 69], - [-28, -23], - [-40, 65], - [5, 19], - [78, 73], - [17, 68], - [50, 28], - [105, -42], - [-53, 60], - [10, 50], - [-95, 5], - [99, 47], - [159, 42], - [23, -2], - [3, -55], - [52, 55], - [62, 23], - [-107, 7], - [-157, -48], - [28, 34], - [98, 31], - [-58, 32], - [-29, -35], - [-57, 9], - [-1, 14], - [45, 92], - [26, 18], - [147, 43], - [-65, 2], - [-97, -20], - [17, 51], - [75, -9], - [-66, 35], - [125, -2], - [23, 40], - [-35, 23], - [105, -8], - [-121, 62], - [-1, 13], - [110, 36], - [53, 42], - [38, -42], - [11, 6], - [51, 82], - [20, 12], - [104, 8], - [3, 27], - [116, 0], - [120, -32], - [3, 23], - [119, -6], - [-19, 18], - [-187, 19], - [-17, 34], - [-81, -18], - [-150, -13], - [-7, 10], - [67, 77], - [17, 9], - [54, -19], - [69, 34], - [-78, 34], - [86, 36], - [16, -43], - [113, -9], - [20, -9], - [33, -55], - [13, 76], - [-12, 12], - [-94, 14], - [-26, 44], - [39, 57], - [109, 54], - [-85, -5], - [-79, -47], - [-102, -37], - [-16, 6], - [-11, 78], - [7, 16], - [71, 41], - [67, -10], - [196, 44], - [30, -19], - [56, 55], - [-21, 9], - [-200, 14], - [-14, 10], - [110, 58], - [29, -35], - [54, 14], - [36, 67], - [32, -56], - [-8, -76], - [40, -23], - [25, -54], - [3, 65], - [62, -49], - [7, 5], - [-3, 87], - [-59, 34], - [88, 23], - [-6, 10], - [-135, 63], - [62, 0], - [144, -79], - [-48, 59], - [-100, 55], - [2, 9], - [100, 18], - [72, -34], - [25, 0], - [159, 37], - [157, 2], - [-98, 27], - [9, 36], - [-135, -36], - [-20, -1], - [-38, 32], - [-67, -31], - [-65, -5], - [-9, 12], - [6, 87], - [16, 17], - [130, 37], - [78, 10], - [131, -30], - [-108, 48], - [-8, 10], - [67, 23], - [83, -23], - [-68, 38], - [-2, 11], - [53, 46], - [-62, -14], - [-3, 11], - [46, 97], - [25, 16], - [126, 18], - [14, 11], - [-27, 60], - [7, 21], - [75, 92], - [15, 7], - [39, -53], - [84, -46], - [91, 4], - [-5, 10], - [-151, 83], - [18, 28], - [102, 19], - [22, -9], - [73, -87], - [78, -27], - [5, -62], - [54, -2], - [-48, 80], - [-72, 14], - [-14, 15], - [-43, 101], - [0, 23], - [43, 60], - [68, 29], - [149, 8], - [12, -18], - [-38, -128], - [7, -55], - [54, 147], - [13, 21], - [54, 31], - [52, 81], - [37, 19], - [43, -45], - [-22, -113], - [14, -50], - [-13, -27], - [-108, -143], - [-3, -12], - [86, 60], - [61, 87], - [19, 6], - [97, -24], - [-87, 67], - [-11, 69], - [9, 12], - [82, 27], - [19, 41], - [80, 32], - [-36, -48], - [85, 20], - [40, 69], - [15, 7], - [78, -27], - [43, -55], - [92, -55], - [10, 6], - [-19, 96], - [5, 17], - [48, 23], - [-82, 9], - [57, 38], - [-121, -24], - [-64, 26], - [2, 32], - [-79, 31], - [3, 8], - [92, 37], - [24, -4], - [81, -70], - [-4, 43], - [50, 28], - [99, 2], - [12, -10], - [9, -76], - [21, 55], - [25, 5], - [150, -23], - [28, -19], - [46, -111], - [22, -11], - [107, 27], - [3, 9], - [-93, 40], - [60, 33], - [-30, 51], - [85, 33], - [1, 47], - [96, 60], - [32, 6], - [127, -14], - [-50, 45], - [0, 15], - [59, 65], - [21, 4], - [102, -25], - [-35, 52], - [-97, 32], - [-7, 9], - [59, 32], - [59, -25], - [0, 82], - [18, 5], - [126, -50], - [43, 14], - [33, -55], - [19, -1], - [102, 46], - [24, 4], - [70, -14], - [0, -10], - [-67, -60], - [-169, -113], - [-15, -21], - [35, -65], - [-5, -18], - [-82, -88], - [-13, -65], - [10, -8], - [83, 5], - [22, 13], - [80, 101], - [-24, 19], - [18, 21], - [176, 154], - [35, 55], - [159, 118], - [23, 12], - [29, -27], - [-8, -78], - [-13, -17], - [-86, -41], - [70, -22], - [6, -19], - [-35, -124], - [7, -10], - [86, 55], - [88, 9], - [-22, 56], - [38, 27], - [2, 57], - [61, 11], - [18, 48], - [46, 13], - [-68, 92], - [3, 8], - [83, -27], - [11, 4], - [-2, 60], - [12, 6], - [119, -26], - [113, 6], - [5, -42], - [88, -7], - [-39, -63], - [-87, -42], - [-119, 0], - [88, -26], - [-3, -11], - [-110, -55], - [7, -3], - [158, 32], - [21, 0], - [-30, -46], - [-105, -64], - [3, -7], - [123, 14], - [12, -8], - [-46, -92], - [6, -89], - [19, 111], - [14, 23], - [87, 65], - [-35, 38], - [52, 97], - [65, 60], - [80, 14], - [116, -42], - [13, -14], - [-6, -64], - [13, -4], - [97, 37], - [18, -2], - [27, -51], - [65, 35], - [19, -2], - [84, -50], - [5, -12], - [-52, -37], - [83, 16], - [24, -7], - [103, -64], - [54, 7], - [42, -35], - [-5, -57], - [-20, -9], - [-131, -19], - [-34, -13], - [-102, -78], - [-65, -5], - [-358, 46], - [-56, 3], - [-41, -28], - [13, -8], - [123, -27], - [45, -30], - [130, -19], - [-15, -37], - [54, 0], - [17, -47], - [-64, -59], - [17, -3], - [178, 23], - [24, 10], - [-11, 46], - [35, 17], - [57, -46], - [129, -11], - [18, -9], - [22, -60], - [0, -16], - [-18, -60], - [-7, -3] - ], - [ - [10785, 21362], - [-21, -1] - ], - [ - [10764, 21361], - [21, 1] - ], - [ - [10785, 21362], - [48, -28], - [40, -70], - [75, -13], - [11, 23], - [-96, 23], - [-33, 60], - [-45, 5] - ], - [ - [14298, 25335], - [57, 31], - [1, 13], - [-54, 60], - [11, 7], - [126, -10], - [16, 10], - [-13, 78], - [9, 6], - [78, -31], - [18, 2], - [55, 58], - [70, -47], - [22, -74], - [-46, -29], - [8, -65], - [-17, -12], - [-147, -24], - [-16, 19], - [-70, -45], - [-131, -21], - [-2, 5], - [92, 56], - [-67, 13] - ], - [ - [16219, 25979], - [-29, 25], - [92, 33], - [18, -25], - [64, -11], - [30, -38], - [-17, -3], - [-158, 19] - ], - [ - [16355, 26047], - [45, 46], - [25, 10], - [129, 23], - [36, 38], - [9, -99], - [-18, -21], - [-135, -60], - [-27, -1], - [-62, 51], - [-2, 13] - ], - [ - [13889, 24868], - [-33, -50], - [-18, -2], - [-108, 27], - [-24, -1], - [-64, -34], - [42, 60], - [59, 30], - [-43, 38], - [6, 12], - [105, 64], - [19, 52], - [-38, 37], - [60, 78], - [75, 9], - [21, -31], - [20, -82], - [-29, -68], - [94, 51], - [9, 13], - [-27, 41], - [95, 21], - [18, -7], - [40, -69], - [2, -21], - [-24, -72], - [-18, -12], - [-105, -10], - [-23, -11], - [-70, -82], - [-41, 19] - ], - [ - [14272, 25062], - [37, 60], - [46, -37], - [-83, -23] - ], - [ - [16641, 26239], - [83, -16], - [43, -52], - [-3, -13], - [-65, -46], - [-17, -1], - [-63, 56], - [11, 65], - [11, 7] - ], - [ - [17218, 26440], - [138, 42], - [74, -21], - [-22, -55], - [-124, -48], - [-22, 3], - [-54, 65], - [10, 14] - ], - [ - [20263, 14789], - [106, -18] - ], - [ - [20369, 14771], - [30, -6] - ], - [ - [20399, 14765], - [17, -24] - ], - [ - [20416, 14741], - [3, -6] - ], - [ - [20419, 14735], - [17, -2] - ], - [ - [20436, 14733], - [1, 0] - ], - [ - [20437, 14733], - [57, 5] - ], - [ - [20494, 14738], - [72, -3] - ], - [ - [20566, 14735], - [24, -65], - [21, -12] - ], - [ - [20611, 14658], - [29, -7] - ], - [ - [20640, 14651], - [42, -178] - ], - [ - [20682, 14473], - [9, -41] - ], - [ - [20691, 14432], - [-5, -98] - ], - [ - [20686, 14334], - [54, -71] - ], - [ - [20740, 14263], - [73, 20] - ], - [ - [20813, 14283], - [32, 7], - [81, -13] - ], - [ - [20926, 14277], - [54, -66] - ], - [ - [20980, 14211], - [40, 8], - [11, -5], - [33, -30] - ], - [ - [21064, 14184], - [31, -9], - [84, 56] - ], - [ - [21179, 14231], - [16, 7] - ], - [ - [21195, 14238], - [152, 46] - ], - [ - [21347, 14284], - [27, -1] - ], - [ - [21374, 14283], - [52, -65] - ], - [ - [21426, 14218], - [5, -27] - ], - [ - [21431, 14191], - [16, -53], - [94, -97] - ], - [ - [21541, 14041], - [9, -14] - ], - [ - [21550, 14027], - [30, -38] - ], - [ - [21580, 13989], - [14, 5] - ], - [ - [21594, 13994], - [35, 27], - [1, 47] - ], - [ - [21630, 14068], - [3, 5] - ], - [ - [21633, 14073], - [1, 1] - ], - [ - [21634, 14074], - [2, 0] - ], - [ - [21636, 14074], - [41, -2], - [51, -51], - [33, -4] - ], - [ - [21761, 14017], - [30, 2] - ], - [ - [21791, 14019], - [22, -30] - ], - [ - [21813, 13989], - [56, -42] - ], - [ - [21869, 13947], - [18, -13] - ], - [ - [21887, 13934], - [3, -1] - ], - [ - [21890, 13933], - [66, 30], - [15, -6] - ], - [ - [21971, 13957], - [15, -22] - ], - [ - [21986, 13935], - [38, -45], - [70, -9] - ], - [ - [22094, 13881], - [27, -41] - ], - [ - [22121, 13840], - [22, -30], - [62, -27], - [63, 30], - [31, -23] - ], - [ - [22299, 13790], - [-3, -9] - ], - [ - [22296, 13781], - [-13, -62] - ], - [ - [22283, 13719], - [28, -66] - ], - [ - [22311, 13653], - [-1, -32] - ], - [ - [22310, 13621], - [-11, -32] - ], - [ - [22299, 13589], - [-63, -90] - ], - [ - [22236, 13499], - [-15, -16] - ], - [ - [22221, 13483], - [-63, -20], - [13, -59], - [82, -25] - ], - [ - [22253, 13379], - [8, -2] - ], - [ - [22261, 13377], - [-5, -29] - ], - [ - [22256, 13348], - [-13, -12] - ], - [ - [22243, 13336], - [-46, 7], - [-55, -109], - [2, -15], - [58, -20] - ], - [ - [22202, 13199], - [6, -7] - ], - [ - [22208, 13192], - [2, -7] - ], - [ - [22210, 13185], - [4, -17] - ], - [ - [22214, 13168], - [16, -59], - [-6, -24] - ], - [ - [22224, 13085], - [-18, -27] - ], - [ - [22206, 13058], - [42, -38] - ], - [ - [22248, 13020], - [0, -9] - ], - [ - [22248, 13011], - [-42, -82] - ], - [ - [22206, 12929], - [-3, -11] - ], - [ - [22203, 12918], - [-21, -97] - ], - [ - [22182, 12821], - [-8, -35], - [-32, -15] - ], - [ - [22142, 12771], - [-6, -3], - [-248, 0], - [-40, -11], - [-35, -73], - [-20, -17], - [-105, -46], - [-28, -70] - ], - [ - [21660, 12551], - [-6, -27] - ], - [ - [21654, 12524], - [-13, -62] - ], - [ - [21641, 12462], - [-17, -142], - [-48, 16], - [-150, -19], - [-28, -13], - [-53, -82], - [-33, 15], - [-112, -56], - [-48, -63], - [-38, 24], - [-92, -29], - [-53, -59], - [-45, 29], - [-81, -19], - [-110, -86], - [-25, -30], - [-98, -150], - [40, 92], - [-1, 23], - [-48, 71], - [2, -56], - [-55, -81], - [-68, -56], - [-5, -23], - [27, -148], - [53, -124], - [73, -138], - [75, -72], - [75, 20], - [36, 61], - [59, -40], - [38, 36], - [22, 3], - [135, -19], - [12, -12], - [-52, -92], - [-10, -108], - [-60, -24], - [-71, 13], - [-49, -24], - [-62, 55], - [-62, 12], - [-55, -93], - [-27, 5], - [-77, -91], - [-27, 19], - [-164, -66], - [-23, -17], - [-27, -65], - [-123, -103], - [-27, -9], - [-87, 19], - [-21, 12], - [-71, 81], - [48, 31], - [-8, 73], - [31, 105], - [-28, 100], - [-57, 45], - [-29, -14], - [-127, 100], - [-62, 14], - [-67, -9], - [-14, 41], - [49, 63], - [166, 122], - [121, 72], - [61, 7], - [34, 36], - [-39, 26], - [-12, 97], - [-53, -41], - [-14, 4], - [-66, 79], - [-51, -37], - [-99, -5], - [-79, -26], - [-91, 22], - [-13, 46], - [-60, 17], - [-57, 46], - [44, 48], - [-5, 12], - [-101, 49], - [-25, -20], - [-27, 46], - [48, 7], - [191, -47], - [35, 5], - [75, 90], - [-86, -36], - [-62, 0], - [-16, 11], - [-51, 77], - [-5, 23], - [14, 87], - [-43, -67], - [9, -69], - [-13, -11], - [-97, -14], - [-11, 10], - [12, 80], - [-70, -96], - [-17, -12], - [-45, 14], - [-127, -40], - [-15, -15], - [-2, -69], - [-13, -32], - [-86, -160], - [-24, -37], - [-87, -101], - [-66, -16], - [-16, -50], - [-64, -65], - [-11, 5], - [-32, 78], - [-8, -110], - [36, -78], - [14, -81], - [-24, -47] - ], - [ - [18227, 11408], - [55, -4] - ], - [ - [18567, 11961], - [50, 12] - ], - [ - [18617, 11973], - [59, -58] - ], - [ - [18679, 11915], - [33, 41] - ], - [ - [18714, 11955], - [5, -1] - ], - [ - [18753, 11902], - [18, -5], - [72, 36], - [3, 13] - ], - [ - [18539, 12698], - [4, 20] - ], - [ - [18515, 12839], - [-14, 9], - [-51, -14], - [-13, 10] - ], - [ - [18151, 13043], - [-99, 74] - ], - [ - [17837, 13083], - [-5, 0] - ], - [ - [16813, 12812], - [-169, 49] - ], - [ - [16542, 12863], - [-92, 50] - ], - [ - [16349, 12847], - [-19, 65] - ], - [ - [16330, 12912], - [-16, 11] - ], - [ - [16314, 12923], - [-66, 17], - [-24, 55], - [-50, 18], - [-38, 91], - [-37, -6] - ], - [ - [16160, 13289], - [3, 10] - ], - [ - [16279, 13487], - [27, -8] - ], - [ - [16335, 13472], - [-27, 47] - ], - [ - [16294, 13543], - [2, 104] - ], - [ - [16621, 14810], - [8, 62] - ], - [ - [16629, 14872], - [-22, 59] - ], - [ - [16609, 14989], - [29, 13] - ], - [ - [16638, 15002], - [21, 3] - ], - [ - [16659, 15005], - [53, -24], - [22, 5], - [86, 68] - ], - [ - [16820, 15054], - [40, 73], - [18, 12], - [86, 9], - [172, 38], - [44, 3], - [169, -14], - [199, -39], - [76, -23] - ], - [ - [17624, 15113], - [100, -35] - ], - [ - [17724, 15078], - [94, -5], - [15, -11], - [30, -73], - [12, -8], - [78, 13], - [60, -28], - [14, -49], - [50, 71], - [62, -22], - [60, 35], - [49, -56], - [65, 14], - [61, -78], - [37, 74], - [80, 46], - [31, -25], - [43, -106], - [49, -15], - [57, 53], - [71, -20], - [113, 23], - [20, -7], - [61, -89], - [57, -34], - [32, 60], - [0, 21], - [-34, 113], - [26, 85] - ], - [ - [19017, 15060], - [60, 112] - ], - [ - [19077, 15172], - [43, 31] - ], - [ - [19120, 15203], - [18, 49] - ], - [ - [19138, 15252], - [13, 7], - [72, -13] - ], - [ - [19223, 15246], - [7, 2] - ], - [ - [19230, 15248], - [64, 37] - ], - [ - [19294, 15285], - [27, 3] - ], - [ - [19321, 15288], - [74, -5] - ], - [ - [19395, 15283], - [23, -2] - ], - [ - [19418, 15281], - [53, -39], - [115, 43], - [16, 18], - [20, 98], - [27, 7] - ], - [ - [19649, 15408], - [63, -18] - ], - [ - [19712, 15390], - [90, -19], - [27, 3] - ], - [ - [19829, 15374], - [90, 61] - ], - [ - [19919, 15435], - [78, -4] - ], - [ - [19997, 15431], - [20, -27] - ], - [ - [20017, 15404], - [74, 26], - [35, -9], - [44, -55] - ], - [ - [20170, 15366], - [28, -40], - [19, -65] - ], - [ - [20217, 15261], - [23, -82] - ], - [ - [20240, 15179], - [77, -73], - [-4, -45] - ], - [ - [20313, 15061], - [-15, -21], - [-69, -32] - ], - [ - [20229, 15008], - [32, -72], - [-6, -63] - ], - [ - [20255, 14873], - [37, -44] - ], - [ - [20292, 14829], - [-29, -40] - ], - [ - [20421, 11783], - [-22, -60], - [-55, -19], - [28, 73], - [-6, 10], - [-83, 21], - [-32, 29], - [-43, -52], - [-81, 41], - [-26, -17], - [72, -93], - [33, 9], - [38, -56], - [24, 38], - [51, -28], - [20, -51], - [60, 8], - [-29, -66], - [32, 19], - [19, -11], - [117, -118], - [24, -76], - [-6, -50], - [12, -15], - [105, -63], - [6, 16], - [-108, 154], - [-83, 161], - [-15, 39], - [-22, 119], - [-30, 38] - ], - [ - [14127, 17927], - [60, 146], - [48, 48], - [78, 187], - [40, 52], - [-15, -88], - [-54, -122], - [-74, -207], - [-36, -160], - [-47, -64], - [-6, 9], - [-8, 130], - [14, 69] - ], - [ - [14910, 18342], - [-8, -42], - [-89, -57], - [-14, -18], - [-27, -96], - [-45, -4], - [32, 77], - [-2, 22], - [-49, 91], - [16, 70], - [-14, 64], - [28, 67], - [83, 106], - [92, 72], - [34, -40], - [69, 36], - [19, -48], - [-41, -46], - [-46, -12], - [-5, -16], - [1, -137], - [26, -52], - [-60, -37] - ], - [ - [12507, 18772], - [-40, -52], - [-28, 47], - [68, 5] - ], - [ - [12406, 18841], - [70, 68], - [15, 5], - [40, -36], - [-6, -52], - [-15, -6], - [-100, 10], - [-4, 11] - ], - [ - [14705, 21542], - [3, -35], - [-30, 9], - [27, 26] - ], - [ - [16580, 24410], - [-31, -73], - [-1, -11], - [18, -23], - [90, -26] - ], - [ - [16694, 23796], - [-12, -26], - [-57, -51], - [-4, -22], - [28, -118] - ], - [ - [16656, 23567], - [70, -65] - ], - [ - [16760, 23432], - [22, -69], - [-4, -19], - [-62, -23], - [-91, 32], - [-143, -5], - [-23, -8], - [-21, -50], - [-21, 5], - [-124, 87], - [-16, 6], - [11, -46], - [-57, -17], - [-62, 30], - [-23, -69], - [26, -87], - [-16, -3], - [-143, 56], - [87, -56], - [1, -9], - [-92, -15], - [45, -40], - [-27, -23], - [-111, 3], - [-53, -31], - [69, -46], - [-47, -29], - [15, -87], - [-10, -21], - [-92, -60], - [-35, -62], - [-41, -10], - [56, -43], - [23, -47], - [-53, 11], - [60, -61], - [70, -34], - [23, -50], - [-11, -14], - [-110, -77], - [-82, -87], - [-44, -116], - [-54, -83], - [-15, -10], - [-62, 8], - [-24, -60], - [-16, -10], - [-92, -14], - [-29, -16], - [-113, -101], - [-23, -7], - [-59, 55], - [13, -70], - [-47, 22], - [-30, -70], - [-48, -34], - [-19, -55], - [-65, 38], - [-39, -51], - [-53, 4], - [-45, -83], - [11, -37], - [-38, -70], - [-85, -46], - [-76, 24], - [13, -72], - [-38, -101], - [-17, -17], - [-81, -23], - [-59, 41], - [-21, -65], - [3, -21], - [49, -82], - [0, -31], - [-49, -138], - [-4, -32], - [19, -92], - [-7, -12], - [-70, 5], - [18, -36], - [-52, -53], - [29, -22], - [-14, -78], - [41, -53], - [-40, -4], - [-1, -20], - [35, -138], - [-16, -66], - [47, -99], - [-35, -41], - [51, -36], - [69, 2], - [30, -65], - [56, 33], - [23, -8], - [116, -96], - [62, -30], - [12, -85], - [16, -16], - [108, -42], - [18, -23], - [18, -118], - [-31, -58], - [73, -2], - [-92, -50], - [-33, -56], - [-73, -50], - [-53, -13], - [13, -37], - [-82, -15], - [47, -39], - [37, 24], - [47, -9], - [-5, 46], - [58, -55], - [-27, -19], - [-78, 9], - [35, -84], - [-25, -32], - [-86, -31], - [-19, -17], - [-45, -87], - [-13, -5], - [-40, 60], - [-21, 82], - [-39, -137], - [-13, -26], - [-68, -50], - [-104, -13], - [9, -49], - [-67, -14], - [-161, 12], - [112, -27], - [24, -12], - [34, -66], - [-59, -18], - [-95, 14], - [103, -59], - [-33, -20], - [54, -83], - [-18, -28], - [-41, 23], - [26, -66], - [-22, -27], - [34, -73], - [-38, 15], - [-61, -30], - [3, -15], - [72, -88], - [-29, 4], - [16, -177], - [-34, -24], - [-24, -96], - [26, -90], - [-39, -8], - [5, -55], - [-30, -149], - [-41, -33], - [-12, -27], - [-74, -213], - [-48, -70], - [-28, 34], - [-88, 19], - [-99, -19], - [-149, 3], - [-19, -11], - [-23, -85], - [-38, 29], - [-33, -19], - [-78, -91], - [-10, -20], - [-1, -85], - [38, -82], - [0, -20], - [-41, -55], - [-26, -7], - [-145, 5], - [-30, -4], - [-67, -32], - [-25, -2], - [-105, 24], - [-68, -4], - [35, 36], - [-12, 59], - [33, 64], - [-39, 102], - [-41, 50], - [-97, 201], - [-3, 18], - [78, -38], - [30, 23], - [-58, 84], - [34, 37], - [51, 12], - [-18, 94], - [-38, 5], - [-65, 107], - [-59, 46], - [-15, 24], - [-43, 129], - [-46, 91], - [-54, 36], - [0, 113], - [-6, 19], - [-56, 52], - [17, 40], - [-36, 27], - [23, 46], - [17, 119], - [23, 65], - [-38, 60], - [-73, -28], - [35, 73], - [-29, 32], - [-10, -50], - [-96, -7], - [-9, 16], - [14, 134], - [-29, 79], - [14, 31], - [-32, 84], - [14, 72], - [42, 23] - ], - [ - [12354, 19392], - [47, -96], - [16, -11] - ], - [ - [12807, 20535], - [17, 4], - [27, 36], - [40, 111], - [-3, 29] - ], - [ - [13419, 23002], - [7, 17] - ], - [ - [14126, 24137], - [-8, 26] - ], - [ - [14386, 24647], - [38, 36] - ], - [ - [14998, 24929], - [47, -10], - [234, -63] - ], - [ - [16081, 24915], - [39, -15], - [206, -45] - ], - [ - [16413, 24791], - [35, -74] - ], - [ - [16457, 24707], - [37, 4] - ], - [ - [25431, 11895], - [-156, 110] - ], - [ - [25275, 12005], - [-59, 19] - ], - [ - [25216, 12024], - [-33, 50], - [31, 58], - [27, 6], - [33, -36], - [83, 32], - [-1, 24], - [-72, 137], - [-28, 63], - [-53, 149], - [-50, 55], - [-83, 144], - [-63, 26] - ], - [ - [25007, 12732], - [-102, 0] - ], - [ - [24905, 12732], - [-70, 31], - [-28, -64], - [-15, -10], - [-64, 57], - [-27, 126], - [33, 27], - [-21, 31], - [-5, 83], - [-18, 16], - [-170, 71], - [-13, 41], - [65, 207], - [25, 61], - [19, 15], - [67, 103], - [-12, 60], - [-61, 54], - [-6, 39], - [10, 67] - ], - [ - [24614, 13747], - [28, 171] - ], - [ - [24642, 13918], - [26, 55], - [65, 41], - [46, 59], - [4, 104] - ], - [ - [24783, 14177], - [0, 34] - ], - [ - [24783, 14211], - [7, 11] - ], - [ - [24790, 14222], - [56, 68] - ], - [ - [24846, 14290], - [39, 14] - ], - [ - [24885, 14304], - [101, -114] - ], - [ - [24986, 14190], - [43, -62] - ], - [ - [25029, 14128], - [73, -148] - ], - [ - [25102, 13980], - [17, -21], - [57, -19], - [20, 6], - [105, 71], - [20, 66], - [-27, 27], - [-32, 147], - [-6, 101], - [-31, 51], - [65, -10], - [22, 10], - [93, 82], - [92, 50], - [-7, 76], - [22, 67], - [118, 14], - [80, 69], - [105, 49], - [29, 63], - [45, 31], - [28, 94], - [56, -23], - [8, 34], - [-10, 39], - [17, 14], - [66, -36], - [93, -3], - [33, -33], - [-37, -56], - [21, -28], - [99, 26], - [23, -38], - [40, 32], - [-1, 53], - [35, 36], - [85, 9], - [55, 50], - [15, -10], - [55, -144], - [25, -24], - [42, 1], - [40, 24], - [45, -25], - [71, 14], - [11, 17], - [92, -22], - [60, -53], - [-5, -52], - [26, -40], - [100, -31], - [55, -53], - [9, -48], - [41, -53], - [68, -32], - [4, -18], - [-26, -129], - [43, -45], - [48, 36], - [5, 24], - [-17, 150], - [-39, 24], - [9, 40], - [32, 16], - [98, -69], - [48, -20], - [20, -54], - [59, -61], - [59, -12], - [65, -67], - [23, 4], - [113, 89], - [19, 25], - [30, 93], - [50, -7], - [38, 54], - [14, 50], - [47, -51], - [28, -2], - [8, 54], - [48, -9], - [94, 24], - [18, -10], - [60, -109], - [44, -17], - [34, 32], - [45, -5], - [20, 109], - [9, 11], - [52, -19], - [43, 8], - [32, -21], - [49, 51], - [36, -48], - [64, -33], - [-10, -70], - [25, -13], - [14, -46], - [23, 3], - [75, -70], - [86, -10], - [20, -22], - [54, 5], - [45, -26], - [-30, -25], - [32, -35], - [93, 54], - [27, 51], - [22, 100], - [54, 8], - [16, -54], - [40, -37], - [133, -20], - [41, 6], - [203, 71], - [21, 51], - [28, 171], - [9, 28], - [37, 29], - [-28, 17], - [-31, 71], - [-20, 12], - [-140, 33], - [-44, 73], - [-114, 3], - [-59, 24], - [-11, 18], - [39, 53], - [-19, 21], - [-99, 42], - [-21, -14], - [-26, 47], - [2, 27], - [63, 3], - [75, 72], - [85, 16], - [23, 13], - [99, 88], - [11, 16], - [-25, 41], - [-7, 40], - [-38, 23], - [-12, 64], - [-40, 23], - [6, 36], - [55, 35], - [62, 70], - [-12, 41], - [58, 19], - [57, -12], - [36, 17], - [52, -36], - [72, 11], - [61, -20], - [43, 35], - [6, 34], - [-20, 35], - [-90, 28], - [-58, 44], - [-35, -16], - [-112, 45], - [-21, 45], - [29, 73], - [70, -27], - [39, 32], - [-11, 48], - [-94, -16], - [-118, 47], - [34, 1], - [64, 85], - [-28, 52], - [-41, 13], - [5, 27], - [47, 8], - [26, -22], - [-2, 58], - [42, 28], - [81, -41], - [75, 7], - [26, -30], - [48, -9], - [5, 44], - [126, 10], - [26, -17], - [-13, -37], - [42, -33], - [19, 52], - [-1, 50], - [72, 23], - [92, -2], - [33, 49], - [97, 2], - [3277, 50] - ], - [ - [33624, 16548], - [-2804, -4628], - [-477, -1], - [-79, -14], - [-67, -47], - [-45, -74], - [-20, -91], - [6, -76], - [34, -84], - [57, -61], - [73, -32], - [45, 1], - [0, -1153], - [-122, -2], - [-318, -67], - [-77, 35], - [-233, 315], - [-38, 59], - [-34, 98], - [-42, 44], - [-264, 214], - [-36, 60], - [5, 256], - [-11, 96], - [-13, 43], - [-72, 5], - [-19, 21], - [31, 128], - [4, 42], - [29, 8], - [152, -36], - [34, 13], - [112, 131], - [29, 24], - [109, 59], - [32, 93], - [-16, 33], - [-119, 36], - [-17, 11], - [-17, 50], - [2, 50], - [-16, 31], - [-60, 11], - [46, -54], - [6, -33], - [-23, -22], - [-58, 6], - [-26, -34], - [-36, 85], - [-22, 1], - [-53, -37], - [-31, -67], - [22, -60], - [100, -4], - [72, -44], - [48, 37], - [11, -7], - [26, -87], - [-2, -21], - [-37, -62], - [-28, -5], - [-156, 23], - [-33, -1], - [-81, -26], - [-12, 11], - [-7, 106], - [-11, 17], - [-66, 19], - [-4, -10], - [39, -95], - [15, -73], - [-24, -126], - [-10, -20], - [-56, -42], - [-26, 19], - [-20, -26], - [-23, 52], - [27, 88], - [-5, 31], - [-51, -19], - [-55, 6], - [-87, -65], - [-14, -28], - [-35, -139], - [-26, -26], - [-150, -39], - [-99, -36], - [-554, -212], - [-79, -267], - [1, -1685], - [-13, -242], - [-112, -29], - [-50, 7], - [-75, 102], - [-94, 182], - [-32, 109], - [-75, 79], - [-166, 133], - [-51, 13], - [-191, -36], - [-43, -14], - [-117, -60], - [-37, -33], - [-145, -174], - [-19, -14], - [13, 93], - [-26, 105], - [17, 56], - [51, 95], - [25, 111], - [-3, 34], - [-32, 72], - [48, -76], - [-2, 68], - [-89, 64], - [-56, -13], - [-35, 42], - [-84, -15], - [-16, 10], - [-88, 171], - [-20, 18], - [-92, -15], - [-13, 17], - [10, 127], - [-26, 108], - [-45, 59], - [-44, 139], - [-34, 51], - [-20, 113], - [-54, 38], - [-134, 43], - [-13, 26], - [-2, 107], - [26, 50], - [32, 1], - [114, -25], - [55, 6], - [59, -65], - [41, -9], - [57, 33], - [64, -18], - [-37, 51], - [-38, 1], - [-22, 52], - [-97, 102], - [7, 68], - [57, 38], - [40, 1], - [-1, 78], - [46, 105], - [11, 11], - [40, -23], - [63, 55], - [14, 2], - [67, -41], - [170, 19], - [37, -4], - [128, -51], - [66, -4], - [41, 20], - [-13, 14], - [-156, 94], - [-3, 64], - [105, 191], - [26, 108], - [10, 105], - [-53, 109], - [12, 37], - [17, -6], - [12, 40], - [28, 15], - [-1, 30], - [-33, 32], - [-17, 82], - [-43, 34], - [-96, 0], - [-61, 26], - [-36, -53], - [-53, -32], - [5, -24], - [-35, 1], - [-57, 48], - [-36, 3], - [5, 18], - [-39, -1], - [-26, 27], - [-7, 41], - [-27, -29], - [-18, 31], - [-57, 24], - [-75, 7], - [-73, -41], - [-39, -9], - [-29, -59], - [0, 32], - [-57, -56], - [-45, 9], - [-69, -87], - [-131, -105], - [-80, 6], - [-18, -42], - [-39, 5], - [-44, 35], - [14, -46], - [-15, 4], - [7, -50], - [-63, -10], - [3, -29] - ], - [ - [10132, 15920], - [11, -47], - [-35, -65], - [-24, 29], - [48, 83] - ], - [ - [9777, 15038], - [-45, 0], - [0, 23], - [34, 12], - [52, -6], - [48, -47], - [-51, -18], - [-38, 36] - ], - [ - [10936, 15937], - [0, -111] - ], - [ - [10936, 15826], - [0, -5] - ], - [ - [10936, 15821], - [-3, -25], - [-41, -104] - ], - [ - [10892, 15692], - [-14, -90] - ], - [ - [10878, 15602], - [-11, -12], - [-89, 0], - [-18, -52], - [11, -42], - [93, -17], - [24, -53], - [-7, -59], - [-121, -112], - [42, -53], - [-35, -41], - [-96, -18], - [-25, -29], - [-78, 37], - [3, -25], - [-59, -12], - [-7, -47], - [55, -59], - [-3, -23], - [31, -47], - [2, -103], - [-44, -80], - [31, -29], - [-65, -71], - [-38, -6], - [7, -35], - [43, 0], - [22, -35], - [0, -29], - [-31, -42], - [7, -23] - ], - [ - [10522, 14485], - [-86, 0], - [-38, 47], - [40, 68], - [8, 61], - [24, 30], - [-13, 35] - ], - [ - [10457, 14726], - [-61, 21] - ], - [ - [10396, 14747], - [-54, 48], - [-89, -10], - [-48, 64], - [3, 36], - [-24, 23], - [-41, -47], - [-25, 12], - [0, 41], - [-20, 6], - [-58, -40] - ], - [ - [10040, 14880], - [-36, 5] - ], - [ - [10004, 14885], - [-36, 1], - [2, -37] - ], - [ - [9970, 14849], - [-48, -5] - ], - [ - [9922, 14844], - [-109, -83], - [-45, -3] - ], - [ - [9768, 14758], - [-29, 20] - ], - [ - [9739, 14778], - [-40, 22], - [-62, -19], - [-33, 61] - ], - [ - [9604, 14842], - [76, 31], - [76, -35], - [35, 0], - [34, 29], - [48, -23], - [35, 5], - [3, 30], - [-41, -6], - [-42, 23], - [-44, -29], - [-52, 29], - [-52, 6], - [-31, 47], - [45, 36], - [93, 6], - [7, -36], - [52, -17], - [31, -42], - [55, 0], - [-14, 42], - [-79, 41], - [59, 0], - [-35, 70], - [-38, 59], - [-28, 6], - [63, 18], - [-14, 23], - [-4, 53], - [38, 12], - [118, 176], - [20, 65], - [76, 329], - [52, -35], - [55, 24], - [100, 76], - [38, 88], - [59, 47], - [135, 59], - [89, -6], - [163, 36], - [41, -18], - [21, -53], - [79, -47], - [10, -24] - ], - [ - [10215, 15773], - [-3, -24], - [55, -106], - [-11, -35], - [-44, -18], - [-7, -94], - [-18, -58], - [145, -65], - [35, 12], - [100, 105], - [14, 24], - [-11, 59], - [-69, 29], - [-6, 18], - [10, 88], - [-7, 12], - [-62, 12], - [-24, 100], - [-14, 5], - [-83, -64] - ], - [ - [10419, 16084], - [79, -5], - [-72, -18], - [-7, 23] - ], - [ - [10357, 16064], - [-107, -50], - [-11, 12], - [118, 38] - ], - [ - [10170, 15973], - [42, 17], - [-63, -58], - [21, 41] - ], - [ - [10343, 15402], - [-69, 12], - [-31, 24], - [13, 17], - [132, 94], - [27, 12], - [52, -29], - [-28, -53], - [-76, -71], - [-20, -6] - ], - [ - [10577, 16096], - [59, 6], - [-65, -23], - [6, 17] - ], - [ - [17049, 2859], - [27, -119], - [1, -31], - [-19, -101], - [-67, -177], - [-2, -59], - [49, -320], - [1, -72], - [30, -137] - ], - [ - [17069, 1843], - [4, -88], - [3, -482], - [0, -1140], - [-591, -133], - [-4188, 0], - [-592, 5] - ], - [ - [11705, 5], - [-4, 48], - [35, 82] - ], - [ - [11736, 135], - [17, 24], - [92, 87], - [14, 32], - [11, 132], - [-1, 23], - [-19, 27], - [-6, 28], - [-27, 165], - [4, 60], - [53, 261], - [3, 62], - [-38, 174], - [-3, 64] - ], - [ - [11836, 1274], - [18, 332], - [-12, 171], - [-38, 215], - [-19, 63], - [-96, 230] - ], - [ - [11689, 2285], - [-14, 37], - [3, 37], - [14, 16], - [94, 78], - [20, 13], - [45, 19], - [18, 24], - [97, 194], - [33, 134], - [-11, 89], - [-40, 181] - ], - [ - [11948, 3107], - [3, 55], - [49, 102], - [74, 43], - [12, 18], - [30, 96], - [44, 35] - ], - [ - [12160, 3456], - [13, 13], - [53, 78], - [31, 29], - [161, 123], - [20, 30], - [-24, 82], - [-1, 48], - [15, 251], - [17, 29], - [132, -71], - [105, -91], - [33, -16], - [129, -23], - [32, 2], - [97, 41], - [75, 12], - [96, -60], - [111, -17], - [94, -46], - [81, -85], - [37, -19], - [202, -69], - [35, -23], - [52, -117], - [0, -92], - [49, -201], - [17, -40], - [72, -115], - [22, -23], - [78, -50], - [85, -28], - [156, -13], - [37, -9], - [135, -50], - [49, -26], - [212, -128], - [74, -54], - [118, -157], - [27, -30], - [92, -77], - [25, -12], - [89, -5], - [32, 17], - [137, 118], - [30, 37], - [87, 171], - [30, 124], - [-5, 89], - [-46, 147], - [-27, 192], - [15, 118], - [41, 102], - [102, 159], - [97, 89], - [102, 78], - [31, 15], - [119, 27], - [24, 13], - [67, 66], - [82, -14], - [81, 14], - [27, -9], - [149, -98], - [143, -65], - [21, -19], - [11, -73], - [-17, -84], - [6, -20], - [70, -80], - [14, 23], - [130, -28], - [30, -14], - [97, -73], - [27, -12], - [121, -3], - [87, 19], - [51, -24], - [14, -21], - [58, -151], - [-6, -32], - [-11, -25], - [-72, -147], - [-9, -40], - [12, -157], - [4, -17] - ], - [ - [20178, 380], - [1, 8] - ], - [ - [20179, 388], - [-1, -8] - ], - [ - [17049, 2859], - [-5, 38], - [-8, 152], - [10, 40], - [75, 138], - [17, 11], - [46, -60], - [25, -2], - [160, 52], - [100, -20], - [339, -106], - [80, -17], - [42, -78], - [56, -27], - [67, 22], - [50, -70], - [24, -10], - [135, -10], - [30, -7], - [103, -62], - [94, -72], - [69, 17], - [60, 41], - [192, 210], - [27, 18], - [30, -51], - [35, 24], - [31, 120], - [50, -2], - [131, 51], - [-108, -94], - [67, -3], - [59, 23], - [51, 56], - [-1, 43], - [156, -79], - [31, -5], - [89, 41], - [0, -46], - [-34, -85], - [2, -16], - [50, -51], - [29, 15], - [29, -88], - [10, -5], - [55, 49], - [21, 55], - [11, -3], - [57, -78], - [54, -32], - [20, 7], - [99, 69], - [16, 1], - [11, -65], - [12, -2], - [91, 50], - [62, -14], - [25, 6], - [116, 55], - [68, 8] - ], - [ - [20262, 3011], - [17, -40] - ], - [ - [20279, 2971], - [80, -325] - ], - [ - [20359, 2646], - [12, -115], - [27, -63], - [35, -137] - ], - [ - [20433, 2331], - [51, -281], - [-1, -60], - [-52, -198], - [-9, -51], - [-13, -165], - [-10, -49], - [-53, -178], - [-8, -50], - [3, -169], - [-9, -38], - [-78, -114], - [-53, 31], - [-107, 140], - [-53, 123], - [-62, 75], - [-48, 82], - [-10, 41], - [-22, 207], - [-13, 44], - [-86, 136], - [-25, 88], - [-32, 53], - [-13, 144], - [-30, 92], - [-13, -9], - [-62, -151], - [1, -39], - [67, -124], - [13, -33], - [20, -133], - [-3, -70], - [52, -112], - [18, -92], - [43, -65], - [76, -174], - [21, -40], - [92, -138], - [10, -23], - [-22, -40], - [22, -65], - [-10, -47], - [69, -174], - [35, -46], - [8, -74], - [47, -119], - [-5, -78] - ], - [ - [20179, 388], - [-1, -8] - ], - [ - [20178, 380], - [-6, -59], - [31, -59], - [70, -230], - [-343, -32], - [-2501, 0], - [-353, 147], - [0, 1241], - [-3, 382], - [-4, 73] - ], - [ - [11243, 4943], - [-91, -82], - [-13, -65], - [-76, -87], - [-11, -22], - [-13, -115], - [16, -111], - [55, -168], - [8, -88], - [16, -24], - [105, -82], - [22, -29], - [56, -157], - [16, -131], - [46, -65], - [150, -165], - [27, -39], - [35, -115], - [19, -109], - [99, -661] - ], - [ - [11709, 2628], - [15, -107], - [5, -96], - [-6, -20], - [-54, -51], - [5, -32], - [15, -37] - ], - [ - [11836, 1274], - [3, -66], - [38, -193], - [-3, -58], - [-53, -220], - [-4, -58], - [27, -188], - [7, -32], - [21, -36], - [0, -25], - [-18, -143], - [-15, -30], - [-86, -68], - [-17, -22] - ], - [ - [11705, 5], - [-612, -5], - [-4348, 0], - [-670, 58], - [-401, 408], - [-74, 85], - [-123, 198], - [-18, 98], - [0, 505], - [2, 84], - [13, 87], - [17, 30] - ], - [ - [5491, 1553], - [132, 154], - [85, 77], - [78, 101], - [23, 16], - [107, 24], - [56, 55], - [67, 13] - ], - [ - [6039, 1993], - [71, -31], - [11, 0], - [28, 35] - ], - [ - [6149, 1997], - [73, 23], - [198, 30], - [26, -3], - [38, -42], - [48, -5], - [20, 26], - [89, 188], - [24, 41], - [83, 106], - [113, 95], - [99, 136], - [46, 27], - [121, 33], - [62, 51], - [5, 69], - [29, 73], - [-46, 112], - [-47, 22], - [11, 83], - [35, 27], - [15, 130], - [28, 37], - [231, 75], - [21, 34], - [-26, 108], - [25, 30], - [89, 27], - [58, 2], - [326, -19], - [89, 3], - [-24, 53], - [13, 78], - [61, 84], - [-8, 28], - [-102, 128], - [-18, 30], - [-33, 103], - [8, 64], - [-48, 98], - [-4, 29], - [16, 129], - [-2, 29], - [-32, 78], - [-2, 34], - [16, 165], - [-2, 44], - [-33, 147], - [-1, 27], - [22, 55], - [-43, 82], - [21, 55], - [-5, 20], - [-78, 105], - [-51, 41] - ], - [ - [7703, 5222], - [-4, 48], - [96, 2], - [40, 19], - [98, 103], - [70, 51], - [14, 20], - [30, 91], - [19, 25], - [105, 82], - [21, 10], - [54, -11], - [51, 85], - [29, 9], - [35, -46], - [62, -16], - [41, 41], - [38, 99], - [63, 85], - [151, 93], - [102, 80], - [111, 37], - [159, 10], - [170, 40], - [40, -19], - [61, 13], - [87, 91], - [44, 22], - [47, -36], - [44, 36], - [78, -10], - [22, 6], - [84, 51], - [46, 7], - [242, 0], - [47, -7], - [92, -51], - [27, -53], - [65, -36], - [61, 15], - [68, 69], - [27, 15], - [123, 37], - [22, 14], - [43, 77], - [52, 24], - [43, -50], - [83, -23], - [50, -33], - [87, 38], - [11, 74], - [73, -17], - [99, -60], - [45, -55], - [19, -1], - [104, 50], - [65, -19], - [55, 13], - [8, -65] - ], - [ - [11422, 6296], - [-61, -34], - [3, -51], - [-79, -85], - [-4, -15], - [46, -37], - [3, -40], - [-24, -253], - [-1, -56], - [24, -182], - [-8, -101], - [35, -66], - [-2, -28], - [-45, -152] - ], - [ - [11309, 5196], - [-8, -36], - [-13, -126], - [-45, -91] - ], - [ - [12765, 10510], - [-5, -59], - [-23, 27], - [28, 32] - ], - [ - [24009, 8859], - [41, -23], - [-35, -19], - [15, -17], - [137, -110], - [18, -22], - [-18, -58], - [-41, -36], - [-1, -20], - [33, -101], - [20, -28], - [130, -118], - [11, -23], - [-23, -92], - [-13, -12], - [-70, -5], - [-2, -13], - [66, -102], - [48, -38], - [68, -88], - [45, 5], - [65, -41], - [3, -16], - [-35, -68], - [2, -20], - [51, -68], - [-42, -31] - ], - [ - [24482, 7695], - [-2, -23], - [24, -142], - [-3, -18], - [-43, 14], - [-64, -24], - [-15, 15], - [-61, 157] - ], - [ - [24318, 7674], - [6, 37], - [-67, 78] - ], - [ - [24257, 7789], - [-8, 20], - [2, 78], - [-13, 7], - [-94, -27], - [-20, 3], - [-45, 50], - [-34, -3], - [-38, 93], - [-14, 9], - [-76, -24], - [-19, 11], - [-81, 116], - [-48, 46], - [-18, 6] - ], - [ - [23751, 8174], - [-78, -5], - [-134, 52], - [-13, 12], - [10, 60], - [-38, 133] - ], - [ - [23498, 8426], - [-1, 27], - [36, 55], - [5, 18], - [6, 68], - [-21, 93], - [-9, 17], - [-46, 46], - [-8, 13], - [-11, 41], - [117, 15] - ], - [ - [23566, 8819], - [32, 22] - ], - [ - [23598, 8841], - [40, 8], - [251, 22], - [41, 9], - [52, 35], - [27, -56] - ], - [ - [24062, 8739], - [-9, -5] - ], - [ - [24053, 8734], - [9, 5] - ], - [ - [11948, 3107], - [40, -186], - [3, -39], - [-11, -119], - [-16, -45], - [-102, -207], - [-25, -36], - [-72, -46], - [-14, 6], - [-24, 87], - [-18, 106] - ], - [ - [11243, 4943], - [48, 61], - [11, 153], - [7, 39] - ], - [ - [11422, 6296], - [5, 55], - [58, 32], - [133, 135], - [52, 16], - [97, 47], - [76, 6], - [-10, -53], - [89, 15], - [67, -39], - [-15, -102], - [47, -79], - [18, -88], - [44, 19], - [26, 60], - [52, 23], - [43, 64], - [58, 36], - [10, -10], - [20, -105], - [-27, -41], - [-83, -194], - [-17, -27], - [-62, -36], - [-27, -95], - [11, -141], - [47, -88], - [51, -27], - [25, -55], - [48, -27], - [7, -22], - [7, -155], - [27, -55], - [-5, -26], - [-65, -133], - [-18, -87], - [-87, -144], - [-28, -31], - [-124, -96], - [-22, -26], - [-39, -111], - [25, -110], - [65, -110], - [61, -57], - [83, 20], - [-3, -75], - [23, -46], - [44, 22], - [17, 55], - [56, -51], - [4, -81], - [21, -92], - [15, -12], - [99, -21], - [3, -36], - [-13, -262], - [3, -44], - [24, -77], - [-3, -18], - [-46, -51], - [-26, -21], - [-140, -101], - [-24, -22], - [-39, -65] - ], - [ - [4420, 21], - [48, 147], - [69, 130], - [7, 30], - [-3, 114], - [14, 23], - [123, 54], - [81, 8], - [74, -28], - [84, -56], - [93, 13], - [73, -18], - [21, 10], - [78, 92], - [45, 29], - [173, 23], - [21, 25], - [3, 160] - ], - [ - [5424, 777], - [-1, 35], - [-8, 82], - [4, 12], - [32, 0], - [8, -94], - [-3, -693], - [-5, -88], - [-32, -27], - [-115, -4], - [-891, 0], - [7, 21] - ], - [ - [6608, 5728], - [47, -179], - [54, -80], - [78, -82], - [27, -18], - [110, -46], - [34, 0], - [148, 49], - [33, -23], - [32, 33], - [120, -37], - [23, 0], - [59, 37], - [57, 83], - [8, -87], - [32, -69], - [17, -12], - [89, -14], - [86, 3], - [41, -64] - ], - [ - [6149, 1997], - [-38, -35], - [-72, 31] - ], - [ - [5491, 1553], - [-17, -28], - [-13, -69], - [-2, -62], - [-1, -431], - [-5, -50], - [-5, -9], - [-30, -9], - [-3, -12], - [9, -106] - ], - [ - [4420, 21], - [-112, -21], - [-745, 0], - [-104, 6], - [24, 65], - [77, 100], - [93, 61], - [111, 129], - [38, 122], - [97, 386], - [19, 60], - [42, 55], - [19, 60], - [37, 30], - [216, 65], - [49, 22], - [164, 106], - [57, 52], - [106, 182], - [34, 42], - [153, 142], - [32, 36], - [89, 155], - [86, 204], - [62, 110], - [55, 167], - [15, 155], - [-21, 74], - [-58, 65], - [9, 96], - [-2, 336], - [6, 59], - [43, 133], - [89, 159], - [44, 118], - [16, 228], - [28, 57], - [104, 142], - [25, 40], - [70, 142], - [20, 30], - [73, 69], - [40, 27], - [210, 118], - [52, 37], - [189, 171], - [50, 94], - [91, 237], - [75, 234], - [21, 78], - [76, 321], - [35, 103], - [98, 28], - [67, 51], - [24, -31] - ], - [ - [24318, 7674], - [48, -141], - [4, -18], - [-16, -10], - [-26, 7], - [-170, 60], - [-29, 21] - ], - [ - [24129, 7593], - [-47, 100], - [-33, 5] - ], - [ - [24049, 7698], - [-77, 136], - [-24, 87], - [-7, 18], - [-21, 52], - [70, 32], - [14, -1], - [30, -47], - [86, -100], - [22, -7], - [95, 40], - [21, -26], - [-9, -73], - [8, -20] - ], - [ - [24053, 8734], - [9, 5] - ], - [ - [24510, 9268], - [22, -47] - ], - [ - [24532, 9221], - [61, 15] - ], - [ - [24593, 9236], - [59, -82] - ], - [ - [24652, 9154], - [33, -70] - ], - [ - [24685, 9084], - [49, -31] - ], - [ - [24734, 9053], - [40, -115], - [16, -22] - ], - [ - [24790, 8916], - [70, -36] - ], - [ - [24860, 8880], - [108, 0] - ], - [ - [24968, 8880], - [19, 15], - [45, 106] - ], - [ - [25032, 9001], - [18, 22], - [78, 55] - ], - [ - [25128, 9078], - [19, 24], - [59, 115] - ], - [ - [25206, 9217], - [11, 15], - [38, -37], - [113, -183], - [21, -46], - [50, -180], - [45, -87], - [62, -70], - [16, -81], - [12, -14], - [91, -35], - [59, 4], - [19, -11], - [75, -82], - [12, -23], - [5, -82], - [-36, 51], - [-112, 17], - [-24, -7], - [-96, -79], - [-42, -72], - [-7, -33], - [-6, -162], - [-5, -34], - [-36, -87], - [0, -21], - [33, -75], - [-7, -55], - [-27, 18], - [-34, -154], - [-12, -10], - [-59, 69], - [-11, -6], - [-18, -139], - [-24, -82], - [6, -174], - [-8, -27] - ], - [ - [25310, 7243], - [-62, -19], - [-18, 12], - [-74, 114], - [-21, -9] - ], - [ - [25135, 7341], - [-40, 67], - [-69, 74], - [11, 50], - [11, 12], - [76, 44], - [-19, 67] - ], - [ - [25105, 7655], - [-40, 69], - [2, 16], - [57, 46] - ], - [ - [25124, 7786], - [7, 10], - [-20, 44], - [-96, 128], - [-22, 14], - [-54, -27], - [-32, -26] - ], - [ - [24907, 7929], - [-175, -156], - [-27, -28], - [-16, -46], - [-48, -23] - ], - [ - [24641, 7676], - [-98, -142], - [-15, -16], - [-27, 19], - [-4, 11], - [3, 60], - [-18, 87] - ], - [ - [24009, 8859], - [-12, 67], - [7, 15], - [51, 55], - [18, 7], - [75, -5], - [75, -37], - [13, -14], - [35, -69], - [11, -11], - [43, -14], - [13, 0], - [51, 14], - [19, -8], - [84, -69], - [17, -4], - [35, 36], - [7, 16], - [13, 73], - [-3, 17], - [-45, 58] - ], - [ - [24516, 8986], - [-59, 41] - ], - [ - [24457, 9027], - [-15, 17], - [-43, 78], - [3, 26], - [65, 106], - [13, 14], - [30, 0] - ], - [ - [19719, 5333], - [33, -23], - [42, 1], - [13, 25], - [9, 111], - [81, -27], - [114, 1], - [84, 32], - [267, 157], - [8, -21], - [-144, -134], - [-65, -80], - [-5, -46], - [33, -76], - [-44, 10], - [-15, -15], - [-35, 19], - [-39, -49], - [13, -49], - [-37, -74], - [-81, -34], - [-86, -25], - [-33, -58], - [-12, 46], - [-29, 20], - [-62, -19], - [-70, 39], - [-14, 27], - [-48, 177], - [35, -15], - [45, 56], - [42, 24] - ], - [ - [21346, 3219], - [-63, -37], - [-30, -77], - [26, -62], - [216, -352], - [33, -59], - [19, -60], - [-8, -16], - [-69, -60], - [-18, -29], - [-62, -171], - [-27, -23], - [-182, -61], - [-55, -38] - ], - [ - [21126, 2174], - [-110, -224] - ], - [ - [21016, 1950], - [-104, -122] - ], - [ - [20912, 1828], - [-83, 3], - [-237, 55] - ], - [ - [20592, 1886], - [-38, 4], - [-36, 39], - [10, 142] - ], - [ - [20528, 2071], - [26, 167] - ], - [ - [20554, 2238], - [8, 40] - ], - [ - [20562, 2278], - [18, 60] - ], - [ - [20580, 2338], - [3, 27] - ], - [ - [20583, 2365], - [0, 133], - [11, 65] - ], - [ - [20594, 2563], - [72, 300], - [16, 95] - ], - [ - [20682, 2958], - [-1, 69], - [38, 69], - [7, 30], - [8, 152], - [-17, 178] - ], - [ - [20717, 3456], - [14, 158], - [-8, 85] - ], - [ - [20723, 3699], - [18, 147], - [43, 36] - ], - [ - [20784, 3882], - [11, 18] - ], - [ - [20795, 3900], - [17, -12] - ], - [ - [20812, 3888], - [44, -27] - ], - [ - [20856, 3861], - [26, -23] - ], - [ - [20882, 3838], - [23, -68] - ], - [ - [20905, 3770], - [29, 0] - ], - [ - [20934, 3770], - [84, -84], - [23, -14], - [92, -23] - ], - [ - [21133, 3649], - [23, 4], - [69, 51], - [68, 60], - [416, 385], - [127, 113] - ], - [ - [21836, 4262], - [22, -96], - [59, -316], - [7, -53], - [-14, -76], - [19, -62], - [51, 4], - [30, -59] - ], - [ - [22010, 3604], - [-35, -61] - ], - [ - [21975, 3543], - [-64, -75], - [-136, -65] - ], - [ - [21775, 3403], - [-429, -184] - ], - [ - [23749, 6393], - [99, 99], - [48, -5] - ], - [ - [23896, 6487], - [11, -21] - ], - [ - [23907, 6466], - [37, -62], - [-7, -127] - ], - [ - [23937, 6277], - [49, -53], - [0, -94] - ], - [ - [23986, 6130], - [28, -66] - ], - [ - [24014, 6064], - [53, -34] - ], - [ - [24067, 6030], - [35, -151], - [2, -69], - [64, -5], - [66, -89], - [20, -10], - [89, 14], - [89, -29] - ], - [ - [24432, 5691], - [-1, -4], - [-8, -14], - [-80, -60] - ], - [ - [24343, 5613], - [-13, -20] - ], - [ - [24330, 5593], - [-5, -83], - [7, -29], - [57, -147], - [-18, -49], - [-62, -14], - [-27, -85], - [-42, -35], - [-32, -87], - [13, -99], - [-49, 14], - [-37, -81], - [36, -69], - [5, -90], - [-49, -110], - [31, -49], - [65, -151], - [14, -18], - [43, 5], - [18, -28], - [80, -207], - [7, -34], - [-37, -51], - [29, -79], - [36, 5], - [97, -57], - [29, -28], - [126, -152], - [27, -24], - [77, -27], - [49, -52], - [15, -72], - [123, -251], - [-2, -68], - [-38, -183], - [-5, -47], - [-2, -171], - [11, -23], - [81, -3], - [23, -31], - [1, -219], - [7, -39], - [54, -92] - ], - [ - [25086, 2483], - [49, -39] - ], - [ - [25135, 2444], - [40, -148], - [-19, -41], - [-107, 49], - [-48, -15], - [-55, 33] - ], - [ - [24946, 2322], - [-19, 8] - ], - [ - [24927, 2330], - [-84, 9] - ], - [ - [24843, 2339], - [-38, -4], - [-53, -31] - ], - [ - [24752, 2304], - [-32, -36], - [-76, -250], - [-21, -54], - [-83, -170] - ], - [ - [24540, 1794], - [-19, -28], - [-51, -27], - [-64, 3], - [-193, 25] - ], - [ - [24213, 1767], - [-219, 31], - [-72, 25] - ], - [ - [23922, 1823], - [-115, 92], - [-96, 109], - [-554, 674], - [-97, 115], - [-129, 137], - [-67, 63] - ], - [ - [22864, 3013], - [-393, 345], - [-74, 52], - [-123, 43], - [-261, 69], - [-38, 21] - ], - [ - [21975, 3543], - [35, 61] - ], - [ - [21836, 4262], - [132, 115], - [467, 400], - [82, 61], - [59, 23], - [18, 26], - [65, 165], - [9, 52], - [6, 202], - [16, 174], - [40, 145], - [0, 65] - ], - [ - [22730, 5690], - [-34, 135], - [-4, 32] - ], - [ - [22692, 5857], - [10, 152] - ], - [ - [22702, 6009], - [24, 73], - [19, 18], - [130, 61] - ], - [ - [22875, 6161], - [30, 28], - [156, 219] - ], - [ - [23061, 6408], - [18, 49], - [52, 22], - [19, 27] - ], - [ - [23150, 6506], - [50, 92], - [73, -4] - ], - [ - [23273, 6594], - [14, 1] - ], - [ - [23287, 6595], - [57, 13] - ], - [ - [23344, 6608], - [97, -55], - [109, -33], - [23, 3], - [84, 51], - [18, 2], - [47, -50], - [-12, -77], - [24, -60] - ], - [ - [23734, 6389], - [15, 4] - ], - [ - [20831, 4019], - [0, -28] - ], - [ - [20831, 3991], - [-36, -91] - ], - [ - [20795, 3900], - [-11, -18] - ], - [ - [20723, 3699], - [-38, 0], - [-21, 47] - ], - [ - [20664, 3746], - [-53, 27] - ], - [ - [20611, 3773], - [-48, -42] - ], - [ - [20563, 3731], - [-12, -25], - [-29, -119], - [-3, -38] - ], - [ - [20519, 3549], - [14, -147], - [8, -25], - [46, -27], - [-1, -16], - [-65, -114] - ], - [ - [20521, 3220], - [-21, -106] - ], - [ - [20500, 3114], - [6, -16] - ], - [ - [20506, 3098], - [65, -14] - ], - [ - [20571, 3084], - [19, 5] - ], - [ - [20590, 3089], - [72, 50] - ], - [ - [20662, 3139], - [12, -16], - [8, -165] - ], - [ - [20682, 2958], - [-10, -69], - [-78, -326] - ], - [ - [20583, 2365], - [-3, -27] - ], - [ - [20562, 2278], - [-8, -40] - ], - [ - [20528, 2071], - [-28, -77], - [-10, 30], - [-57, 307] - ], - [ - [20359, 2646], - [-80, 325] - ], - [ - [20279, 2971], - [8, 4], - [42, 143], - [36, 57], - [-6, 31] - ], - [ - [20359, 3206], - [73, 220], - [46, 209], - [39, 274], - [8, 35], - [30, 27], - [19, 115], - [15, 12] - ], - [ - [20589, 4098], - [94, -4], - [17, 11], - [24, 92] - ], - [ - [20724, 4197], - [28, 2] - ], - [ - [20752, 4199], - [58, 68] - ], - [ - [20810, 4267], - [-9, -60] - ], - [ - [20801, 4207], - [30, -188] - ], - [ - [22609, 10153], - [125, -34], - [78, -60], - [25, -10] - ], - [ - [22837, 10049], - [125, -13] - ], - [ - [22962, 10036], - [105, 23], - [25, -3] - ], - [ - [23092, 10056], - [69, -41] - ], - [ - [23161, 10015], - [63, 10] - ], - [ - [23224, 10025], - [13, -2] - ], - [ - [23237, 10023], - [45, -27] - ], - [ - [23282, 9996], - [56, -88] - ], - [ - [23338, 9908], - [22, -17], - [110, -46] - ], - [ - [23470, 9845], - [95, -74], - [7, -14] - ], - [ - [23572, 9757], - [-17, -47], - [51, -36], - [18, 0] - ], - [ - [23624, 9674], - [78, 36] - ], - [ - [23702, 9710], - [94, 63] - ], - [ - [23796, 9773], - [66, -4] - ], - [ - [23862, 9769], - [10, -8] - ], - [ - [23872, 9761], - [36, -49] - ], - [ - [23908, 9712], - [32, 60], - [16, 3] - ], - [ - [23956, 9775], - [100, -51] - ], - [ - [24056, 9724], - [54, -70] - ], - [ - [24110, 9654], - [59, 1] - ], - [ - [24169, 9655], - [14, -4] - ], - [ - [24183, 9651], - [48, -41], - [4, -20], - [-25, -102] - ], - [ - [24210, 9488], - [8, -27] - ], - [ - [24218, 9461], - [81, -91], - [21, -15] - ], - [ - [24320, 9355], - [67, -14] - ], - [ - [24387, 9341], - [84, -60], - [4, -15], - [-32, -60], - [-9, -10], - [-33, -14], - [1, -18], - [41, -114], - [14, -23] - ], - [ - [24516, 8986], - [45, -63], - [2, -19], - [-19, -77], - [-7, -16], - [-32, -27], - [-13, 5], - [-62, 60], - [-19, 7], - [-70, -5], - [-21, 6], - [-78, 46], - [-16, 49], - [-111, 51], - [-18, 6], - [-22, -5], - [-19, -14], - [-116, -102], - [-24, -13], - [-57, 5], - [-229, -31], - [-32, -8] - ], - [ - [23566, 8819], - [-106, -3], - [-15, 5], - [-19, 36], - [-7, 4], - [-42, -5] - ], - [ - [23377, 8856], - [-38, 37], - [16, 26] - ], - [ - [23355, 8919], - [-120, 154], - [-22, 19], - [-59, -9] - ], - [ - [23154, 9083], - [-48, -65], - [-18, -4], - [-97, 31], - [-57, 0], - [-38, -37] - ], - [ - [22896, 9008], - [-93, 53], - [-4, 19], - [48, 83], - [8, 30], - [11, 128], - [-38, 117], - [-65, 284], - [-19, 46], - [-73, 36], - [-15, 17], - [-45, 95], - [-83, 57], - [-132, 32], - [-24, 17], - [-53, 103], - [-48, 22], - [-3, 15], - [36, 95] - ], - [ - [22304, 10257], - [55, 1] - ], - [ - [22359, 10258], - [81, -30] - ], - [ - [22440, 10228], - [58, 5], - [86, -68], - [25, -12] - ], - [ - [20262, 3011], - [17, 74], - [80, 121] - ], - [ - [20662, 3139], - [-72, -50] - ], - [ - [20571, 3084], - [-65, 14] - ], - [ - [20500, 3114], - [21, 106] - ], - [ - [20519, 3549], - [3, 39], - [41, 143] - ], - [ - [20611, 3773], - [53, -27] - ], - [ - [20717, 3456], - [7, -121], - [-24, -36], - [-38, -160] - ], - [ - [20884, 5030], - [140, -33] - ], - [ - [21024, 4997], - [-23, -68] - ], - [ - [21001, 4929], - [51, -37], - [10, -21] - ], - [ - [21062, 4871], - [19, -114], - [-5, -25] - ], - [ - [21076, 4732], - [-51, -60] - ], - [ - [21025, 4672], - [-12, -18] - ], - [ - [21013, 4654], - [-32, -69] - ], - [ - [20981, 4585], - [14, -50] - ], - [ - [20995, 4535], - [-62, 10], - [-16, -13] - ], - [ - [20917, 4532], - [-57, -114] - ], - [ - [20860, 4418], - [23, -27] - ], - [ - [20883, 4391], - [-1, -4] - ], - [ - [20882, 4387], - [-72, -120] - ], - [ - [20752, 4199], - [-28, -2] - ], - [ - [20589, 4098], - [-8, 24], - [50, 199], - [54, 144], - [13, 97], - [51, 76], - [7, 26], - [6, 128], - [13, 35], - [99, 137], - [10, 66] - ], - [ - [24958, 1418], - [-29, 5], - [-43, 41], - [-11, 27] - ], - [ - [24875, 1491], - [-48, 177], - [-32, 27] - ], - [ - [24795, 1695], - [-31, 9], - [-218, 40], - [-16, 23], - [10, 27] - ], - [ - [24752, 2304], - [91, 35] - ], - [ - [24843, 2339], - [84, -9] - ], - [ - [24946, 2322], - [63, -69], - [22, -104], - [43, -111], - [-1, -14], - [-48, 4], - [-87, -93], - [-5, -17], - [41, -31], - [42, 34], - [39, -41], - [23, -166], - [43, -97], - [46, -189], - [-25, -5], - [-184, -5] - ], - [ - [24129, 7593], - [42, -34], - [28, -8], - [161, -46], - [31, -3], - [53, 22], - [16, 3], - [60, -5], - [20, 17], - [101, 137] - ], - [ - [24907, 7929], - [33, 26], - [59, 27], - [22, -17], - [97, -152], - [6, -27] - ], - [ - [25105, 7655], - [9, -73], - [-67, -38], - [-9, -11], - [-9, -46], - [66, -74], - [40, -72] - ], - [ - [25310, 7243], - [9, -9], - [2, -83], - [31, -240], - [30, -91], - [38, -55], - [101, -71], - [30, -9], - [129, -9], - [82, -38], - [15, -21], - [57, -142], - [55, -63], - [156, -135], - [73, -36], - [191, -68], - [46, -6], - [129, 27], - [18, -577], - [0, -4124], - [-9, -572], - [-68, 69], - [-21, 10], - [-111, 12], - [-86, 46], - [-17, 19], - [-32, 87], - [-8, 86], - [-55, 144], - [-20, 133], - [-8, 20], - [-57, 63], - [-14, 68], - [33, 36], - [-21, 50], - [-67, 17], - [-7, 12], - [13, 94], - [-25, 94], - [-54, 73], - [-97, 183], - [-14, 37], - [-21, 110], - [-44, 15], - [-115, -83], - [-18, -3], - [-33, 55], - [-69, 13], - [-19, 14], - [-88, 112], - [30, 14], - [47, -29], - [14, 74], - [-7, 10], - [-65, 5], - [6, -36], - [-51, -65], - [17, -75], - [-11, -87], - [-10, -12], - [-65, 5], - [-25, -51], - [-38, 14], - [-11, 23], - [-46, 147] - ], - [ - [25135, 2444], - [-49, 39] - ], - [ - [24330, 5593], - [13, 20] - ], - [ - [24343, 5613], - [87, 65], - [2, 13] - ], - [ - [24067, 6030], - [-10, 22], - [-43, 12] - ], - [ - [23986, 6130], - [0, 101], - [-49, 46] - ], - [ - [23907, 6466], - [3, 101], - [-8, 23], - [-56, 64], - [-8, 27], - [6, 123], - [-8, 26] - ], - [ - [23836, 6830], - [-59, 60], - [-55, 30], - [3, 30], - [63, 202], - [3, 32], - [-41, 23], - [-6, 118], - [-15, 41], - [4, 108], - [-36, 83], - [5, 82], - [-48, 127], - [6, 19], - [89, 27] - ], - [ - [23749, 7812], - [17, 23], - [33, 138], - [10, 22], - [40, 24], - [14, -5], - [60, -55], - [17, -27], - [65, -133], - [9, -18], - [35, -83] - ], - [ - [10522, 14485], - [52, -66], - [14, -62] - ], - [ - [10588, 14357], - [43, -29] - ], - [ - [10631, 14328], - [17, -96] - ], - [ - [10648, 14232], - [-4, -8] - ], - [ - [10644, 14224], - [-58, -50], - [-29, -50] - ], - [ - [10495, 14111], - [-11, -20] - ], - [ - [10433, 13983], - [8, -73] - ], - [ - [10479, 13837], - [-25, -58] - ], - [ - [10454, 13779], - [-90, -27], - [-31, 17], - [-160, 148] - ], - [ - [10173, 13917], - [-13, 8] - ], - [ - [10160, 13925], - [-24, -4] - ], - [ - [10136, 13921], - [-7, 12] - ], - [ - [10129, 13933], - [-19, 101] - ], - [ - [10110, 14034], - [7, 89] - ], - [ - [10117, 14123], - [-3, 3] - ], - [ - [10114, 14126], - [-73, -96], - [-78, -19], - [-72, 19], - [-10, 30] - ], - [ - [9881, 14060], - [2, 114] - ], - [ - [9883, 14174], - [-6, 23], - [-44, 42], - [-65, 9], - [-33, -24], - [-28, 80], - [-15, 14], - [-90, 24], - [-14, 12], - [-26, 112], - [-30, 32] - ], - [ - [9532, 14498], - [-12, -1] - ], - [ - [9520, 14497], - [-56, -36], - [-19, 3], - [-78, 60], - [-14, 23], - [-21, 106] - ], - [ - [9332, 14653], - [16, 35], - [143, 106], - [100, 51], - [13, -3] - ], - [ - [9739, 14778], - [29, -20] - ], - [ - [9922, 14844], - [48, 5] - ], - [ - [10004, 14885], - [36, -5] - ], - [ - [10396, 14747], - [61, -21] - ], - [ - [24213, 1767], - [185, -27], - [69, -4], - [35, 9], - [257, -40], - [36, -10] - ], - [ - [24875, 1491], - [8, -26], - [18, -37], - [31, -10], - [26, 0] - ], - [ - [24958, 1418], - [218, 2], - [19, -37], - [10, -91], - [30, -66], - [-6, -23], - [21, -66], - [37, -24], - [1, -44], - [30, -50], - [-24, -76], - [27, -22], - [4, -44], - [24, 5], - [41, -42], - [56, -10], - [13, -32], - [-43, -23], - [39, -22], - [-8, -36], - [27, -12], - [3, -51], - [18, -38], - [46, -15], - [57, -90], - [84, -69], - [77, -111], - [-48, -4], - [16, -101], - [39, -51], - [20, -57], - [-1, -69], - [-19, -44], - [-46, 31], - [-13, -31], - [-513, -5], - [-3624, 0], - [-512, 2], - [-8, 14], - [-63, 200], - [-79, 176], - [-26, 85], - [-41, 61], - [-26, 60], - [-7, 49], - [-65, 110], - [-30, 102], - [-64, 163], - [-47, 71], - [-3, 51], - [-35, 23], - [-67, -13], - [-59, 30], - [-31, -54], - [-16, 30], - [23, 46], - [11, 73], - [33, 106], - [1, 93], - [46, 340], - [11, 45], - [38, 27], - [38, -4] - ], - [ - [20912, 1828], - [104, 122] - ], - [ - [21016, 1950], - [110, 224] - ], - [ - [21346, 3219], - [429, 184] - ], - [ - [22864, 3013], - [67, -63], - [126, -137], - [95, -114], - [550, -669], - [95, -109], - [125, -98] - ], - [ - [22875, 6161], - [-127, -51], - [-19, -17], - [-27, -84] - ], - [ - [22692, 5857], - [4, -43], - [34, -124] - ], - [ - [21133, 3649], - [-89, 23], - [-23, 14], - [-87, 84] - ], - [ - [20905, 3770], - [-23, 68] - ], - [ - [20882, 3838], - [-26, 23] - ], - [ - [20856, 3861], - [-44, 27] - ], - [ - [20795, 3900], - [36, 91] - ], - [ - [20831, 4019], - [-30, 188] - ], - [ - [20810, 4267], - [72, 120] - ], - [ - [20883, 4391], - [-23, 27] - ], - [ - [20917, 4532], - [16, 13], - [62, -10] - ], - [ - [20981, 4585], - [32, 69] - ], - [ - [21025, 4672], - [51, 60] - ], - [ - [21062, 4871], - [-10, 23], - [-51, 35] - ], - [ - [21001, 4929], - [23, 68] - ], - [ - [20884, 5030], - [-21, 21], - [-25, 119], - [0, 35], - [26, 155], - [-13, 101], - [-57, 92], - [-3, 22], - [32, 100], - [-11, 36], - [51, 52], - [15, -5] - ], - [ - [20878, 5758], - [13, -32], - [40, -7] - ], - [ - [20931, 5719], - [27, 72] - ], - [ - [20958, 5791], - [47, 44], - [5, 92], - [12, 14], - [86, 17], - [-25, 46], - [-15, 100], - [26, 153], - [19, 34], - [91, -40], - [52, -74], - [51, 19], - [90, 3], - [34, 14], - [164, 101], - [57, 25], - [84, -30], - [87, -83], - [20, -9], - [99, 3], - [67, -14], - [136, 30], - [54, 28], - [275, 169], - [46, 25], - [54, 10], - [81, -25], - [95, -3], - [164, 47], - [28, 15], - [65, 69] - ], - [ - [23007, 6571], - [15, 4], - [48, -61], - [-9, -106] - ], - [ - [18176, 10386], - [128, -33], - [15, -15], - [-2, -115], - [-46, -74], - [-55, 29], - [-43, -19], - [-16, -28], - [-70, -179], - [-10, -44], - [-3, -133], - [-5, -18], - [-54, -15], - [-72, -101], - [-1, -19], - [67, -31], - [11, -16], - [24, -96], - [71, -111], - [-7, -45], - [-65, 5] - ], - [ - [18043, 9328], - [-67, -37] - ], - [ - [17976, 9291], - [-21, 7] - ], - [ - [17955, 9298], - [-80, 82], - [-19, 11], - [-68, -11], - [-59, -48] - ], - [ - [17729, 9332], - [-87, -19], - [-27, -65], - [-65, -35] - ], - [ - [17550, 9213], - [-48, -25] - ], - [ - [17487, 9005], - [-89, -67] - ], - [ - [17293, 8933], - [-42, -4], - [-75, -25] - ], - [ - [16910, 9073], - [-12, 7], - [-68, 0], - [-50, -19] - ], - [ - [16643, 8994], - [-61, -23] - ], - [ - [16480, 8976], - [-11, -9] - ], - [ - [16370, 8937], - [2, 78] - ], - [ - [16372, 9078], - [0, 26] - ], - [ - [16390, 9177], - [-3, 20] - ], - [ - [16344, 9320], - [-16, 29], - [-91, 68], - [-56, 84] - ], - [ - [16176, 9510], - [-28, 36] - ], - [ - [16148, 9546], - [42, -19] - ], - [ - [16190, 9527], - [10, 19] - ], - [ - [16208, 9571], - [1, 1] - ], - [ - [16227, 9639], - [-30, 62] - ], - [ - [16209, 9824], - [2, 2] - ], - [ - [16238, 10545], - [11, 16], - [29, 114] - ], - [ - [16383, 10582], - [10, -12] - ], - [ - [16396, 10558], - [-14, -31] - ], - [ - [16379, 10521], - [-6, -10] - ], - [ - [16357, 10480], - [1, -13] - ], - [ - [16381, 10423], - [138, 19] - ], - [ - [17955, 9298], - [21, -7] - ], - [ - [18043, 9328], - [75, -11], - [-3, -93], - [45, -111], - [18, -26], - [111, -94], - [156, -90], - [38, -5], - [5, -63], - [-31, -76], - [-56, -29], - [-29, 5], - [-165, 55], - [-32, 1], - [-81, -50], - [-68, 13], - [-70, -24], - [-17, -17], - [-51, -106], - [-32, -34], - [-172, -133], - [-28, -26], - [-27, -50], - [-65, -65], - [-22, -59], - [-51, -25], - [29, 94], - [-14, 37], - [19, 21], - [145, 115], - [21, 21], - [-12, 39], - [-80, -23], - [-125, 2], - [-17, 9], - [-13, 60], - [10, 22] - ], - [ - [17546, 8884], - [11, 26], - [78, 41], - [10, 20], - [-8, 106], - [-12, 24] - ], - [ - [17553, 9165], - [-3, 48] - ], - [ - [17550, 9213], - [65, 35], - [30, 65], - [84, 19] - ], - [ - [23154, 9083], - [69, -2], - [72, -100], - [60, -62] - ], - [ - [23377, 8856], - [12, -5], - [45, 0], - [8, -9], - [11, -65], - [9, -17], - [54, -65], - [10, -24], - [16, -105], - [-4, -27], - [-40, -82], - [0, -31] - ], - [ - [23751, 8174], - [18, -7], - [70, -78], - [62, -106], - [0, -8], - [-62, 41], - [-12, 0], - [-27, -41], - [-8, -23], - [-27, -119], - [-16, -21] - ], - [ - [23836, 6830], - [-4, -50], - [0, -19], - [11, -96], - [9, -21], - [51, -56], - [6, -18], - [-5, -73], - [-8, -10] - ], - [ - [23749, 6393], - [-15, -4] - ], - [ - [23344, 6608], - [-57, -13] - ], - [ - [23273, 6594], - [-65, 14], - [-15, -11], - [-43, -91] - ], - [ - [23150, 6506], - [-61, -40], - [-17, 60], - [-50, 50], - [-15, -5] - ], - [ - [20958, 5791], - [-27, -72] - ], - [ - [20878, 5758], - [-59, 211], - [-3, 40], - [57, 90], - [69, 87], - [9, 23], - [-19, 90], - [-46, 41], - [-18, -7], - [-95, -107], - [-37, -66], - [-67, -23], - [-32, 14], - [-153, 119], - [-32, 13], - [-93, -43], - [-89, -103], - [-51, -87], - [-38, -97], - [-39, 29], - [-56, -79], - [-26, -10], - [-131, 0], - [-38, -7], - [-135, -46], - [-30, 2], - [-78, 55], - [-23, 30], - [-92, 160], - [-24, 30], - [-111, 65], - [-129, 92], - [-38, 15], - [-159, 24], - [-19, 18], - [-39, -50], - [-13, -182], - [-21, -99], - [-44, -29], - [-57, 14], - [-27, -9], - [-158, -85], - [-21, 35], - [-87, 27], - [-73, 67], - [-15, 109], - [-24, 10], - [19, 65], - [-47, 36], - [-43, -38], - [-71, 32], - [-18, 52], - [-100, -10], - [-20, -53], - [-62, -68], - [25, 111], - [-5, 11], - [-75, -31], - [-51, 5], - [-29, -47], - [-85, 5], - [72, 64], - [25, 7], - [105, -10], - [15, 10], - [8, 81], - [29, -14], - [48, 67], - [-78, 8], - [-163, -33], - [-75, 19], - [-35, -18], - [-3, 69], - [12, 11], - [83, 4], - [14, 10], - [16, 64], - [-14, 15], - [-116, 41], - [-15, 20], - [5, 101], - [-53, 68], - [60, 46], - [14, 101], - [-10, 19], - [-75, 55], - [-45, -3], - [-44, 93], - [-11, 5], - [-40, -51], - [-19, 4], - [-97, 78], - [-5, 17], - [62, 36], - [21, 47], - [-44, 32], - [-4, 82], - [50, 13], - [36, -76], - [-6, -64], - [29, -46], - [5, 46], - [58, -23], - [83, 41], - [-56, 6], - [-16, 17], - [-53, 119], - [-1, 19], - [58, 21], - [3, 47], - [42, 38], - [-64, 23], - [-16, 60], - [16, 38], - [-50, 95], - [-27, 5], - [89, 110], - [17, 61], - [-22, 0], - [-197, -48], - [-65, -4], - [-6, 10], - [19, 104], - [2, 152], - [7, 26], - [43, 32], - [45, 106], - [29, 14], - [75, 91], - [16, 10], - [54, -4], - [103, 41], - [18, -4], - [43, -64], - [19, -10], - [94, -4], - [10, 11], - [-24, 96], - [27, 14], - [75, -30], - [-16, -56], - [107, 9], - [248, -14], - [32, 3], - [16, 38], - [-56, 14], - [-51, 44], - [68, 58], - [42, 11], - [234, 37], - [26, 9], - [-54, 23], - [-109, -8], - [-26, 17], - [-97, 128], - [-8, 30], - [40, 83], - [39, 7], - [234, -32], - [42, -1], - [65, 27], - [28, -3], - [135, -56], - [37, -7], - [129, 5], - [24, 7], - [38, 46], - [32, 85], - [29, 27], - [180, 119], - [30, 23], - [27, 46], - [102, 69], - [110, 34], - [132, 66], - [76, 13], - [401, -26], - [56, 6], - [51, 65], - [14, 3], - [51, -48], - [-5, -46], - [45, -95], - [98, -76], - [60, 6], - [78, 41], - [18, -1], - [46, -56], - [28, -118], - [69, -85], - [36, -9], - [47, 58], - [35, 5], - [73, -36], - [30, -62], - [91, -39], - [76, -51], - [60, 47], - [13, -4], - [49, -68], - [22, -15], - [108, -31], - [32, -3], - [157, 29], - [127, 61], - [32, -14], - [51, 29], - [104, -60], - [132, -36], - [30, 2], - [80, 50], - [49, 7], - [107, 94], - [40, 8], - [156, 112], - [43, 63], - [104, -43] - ], - [ - [18230, 17604], - [81, 19] - ], - [ - [18311, 17623], - [15, -5], - [30, -56], - [58, -20] - ], - [ - [18414, 17542], - [75, 37] - ], - [ - [18489, 17579], - [70, -23] - ], - [ - [18559, 17556], - [33, -13] - ], - [ - [18592, 17543], - [21, -26], - [-25, -66], - [34, -55], - [42, 10] - ], - [ - [18664, 17406], - [71, 32] - ], - [ - [18735, 17438], - [14, 8] - ], - [ - [18749, 17446], - [9, 11] - ], - [ - [18758, 17457], - [29, 22], - [82, 4] - ], - [ - [18869, 17483], - [92, -30] - ], - [ - [18961, 17453], - [29, -34] - ], - [ - [18990, 17419], - [24, -38] - ], - [ - [19014, 17381], - [9, -7] - ], - [ - [19023, 17374], - [15, -10] - ], - [ - [19038, 17364], - [76, -38] - ], - [ - [19114, 17326], - [4, -5] - ], - [ - [19118, 17321], - [4, -99] - ], - [ - [19122, 17222], - [-7, -25] - ], - [ - [19115, 17197], - [-22, -60], - [43, -57] - ], - [ - [19136, 17080], - [14, -82] - ], - [ - [19150, 16998], - [-57, -64], - [-16, -64], - [25, -30] - ], - [ - [19102, 16840], - [92, -73], - [12, -19] - ], - [ - [19206, 16748], - [-21, -56], - [13, -22] - ], - [ - [19198, 16670], - [35, -38], - [26, -79] - ], - [ - [19259, 16553], - [20, -22], - [123, -81] - ], - [ - [19402, 16450], - [21, -19], - [18, -62] - ], - [ - [19441, 16369], - [-13, -38] - ], - [ - [19428, 16331], - [-12, -37] - ], - [ - [19416, 16294], - [8, -10], - [90, -2] - ], - [ - [19514, 16282], - [125, -50], - [16, -19] - ], - [ - [19655, 16213], - [11, -86] - ], - [ - [19666, 16127], - [71, -57] - ], - [ - [19737, 16070], - [3, -6] - ], - [ - [19740, 16064], - [3, -3] - ], - [ - [19743, 16061], - [1, -20] - ], - [ - [19744, 16041], - [-13, -39] - ], - [ - [19731, 16002], - [-68, -23], - [-21, -50] - ], - [ - [19642, 15929], - [-22, -21] - ], - [ - [19620, 15908], - [-53, -36], - [-84, -10], - [-79, 51], - [-97, 12], - [-17, -11], - [-41, -82], - [5, -26], - [73, -96], - [20, -64] - ], - [ - [19347, 15646], - [-21, -20] - ], - [ - [19326, 15626], - [37, -79], - [-15, -35], - [10, -115] - ], - [ - [19358, 15397], - [24, -20] - ], - [ - [19382, 15377], - [17, -48] - ], - [ - [19399, 15329], - [3, -47] - ], - [ - [19402, 15282], - [-7, 1] - ], - [ - [19321, 15288], - [-27, -3] - ], - [ - [19230, 15248], - [-7, -2] - ], - [ - [19138, 15252], - [-18, -49] - ], - [ - [19077, 15172], - [-46, -73], - [-14, -39] - ], - [ - [17724, 15078], - [-100, 35] - ], - [ - [16820, 15054], - [-89, -68], - [-72, 19] - ], - [ - [16659, 15005], - [-21, -3] - ], - [ - [16591, 15073], - [28, 120] - ], - [ - [16541, 15522], - [57, 38] - ], - [ - [16708, 15696], - [-4, 94] - ], - [ - [16563, 16370], - [34, -24], - [181, 18], - [112, -21], - [84, 46], - [35, -9], - [20, 93], - [75, 8], - [48, 60], - [85, 23] - ], - [ - [17237, 16564], - [31, -79] - ], - [ - [17268, 16485], - [70, 15], - [-9, 69] - ], - [ - [17329, 16569], - [-51, 19] - ], - [ - [17278, 16588], - [-5, 13], - [32, 93], - [26, 27], - [6, 123], - [38, 87], - [14, 14], - [85, 33], - [51, 77], - [19, 11], - [83, -5], - [19, 9], - [45, 64], - [-5, 14], - [-87, 31], - [-5, 28], - [48, 160] - ], - [ - [17642, 17367], - [14, 24] - ], - [ - [17656, 17391], - [56, 13], - [54, 60], - [18, 5] - ], - [ - [17784, 17469], - [72, -18] - ], - [ - [17856, 17451], - [31, 19], - [75, -14], - [30, 56], - [79, 96], - [98, 48] - ], - [ - [18169, 17656], - [61, -52] - ], - [ - [8941, 9702], - [52, 17], - [56, -29], - [10, -65] - ], - [ - [9059, 9625], - [-18, 4], - [-78, -27], - [-10, 5], - [-12, 95] - ], - [ - [13532, 14958], - [9, -20], - [52, -32] - ], - [ - [13563, 14536], - [-14, -14], - [-51, 26], - [6, 32], - [-62, 65] - ], - [ - [13442, 14645], - [-48, 9] - ], - [ - [13394, 14654], - [-23, -30] - ], - [ - [13371, 14624], - [5, -9] - ], - [ - [13376, 14615], - [37, -26], - [-5, -18], - [-190, -104], - [-63, -5] - ], - [ - [13155, 14462], - [-25, -8], - [-32, -52] - ], - [ - [13098, 14402], - [-16, -1] - ], - [ - [13082, 14401], - [-21, 2] - ], - [ - [13061, 14403], - [-56, -57], - [-34, -11] - ], - [ - [12971, 14335], - [-30, -12] - ], - [ - [12941, 14323], - [-6, -18] - ], - [ - [12935, 14305], - [-7, -16] - ], - [ - [12928, 14289], - [-64, 11] - ], - [ - [12864, 14300], - [-29, -9] - ], - [ - [12835, 14291], - [-80, -47] - ], - [ - [12755, 14244], - [-25, -22] - ], - [ - [12730, 14222], - [-45, -69], - [-32, 64], - [-26, -27], - [46, -104] - ], - [ - [12673, 14086], - [20, -27] - ], - [ - [12693, 14059], - [45, -17], - [35, -56], - [-37, -80], - [29, -52], - [28, -74], - [52, -98], - [26, -31] - ], - [ - [12871, 13651], - [3, -1] - ], - [ - [12874, 13650], - [41, 0] - ], - [ - [12915, 13650], - [19, -19] - ], - [ - [12934, 13631], - [77, -106], - [27, -9], - [41, -67], - [60, -24], - [88, -103] - ], - [ - [13227, 13322], - [-3, -25] - ], - [ - [13224, 13297], - [-6, -61], - [-24, -55], - [-75, 24] - ], - [ - [13119, 13205], - [-11, -10] - ], - [ - [13108, 13195], - [-29, -108], - [-29, -29] - ], - [ - [13050, 13058], - [-35, -18] - ], - [ - [13015, 13040], - [-91, -41] - ], - [ - [12924, 12999], - [-35, -20] - ], - [ - [12889, 12979], - [-33, -41], - [6, -23], - [67, -119], - [5, -25], - [-23, -52], - [36, -21], - [16, -36], - [-12, -96], - [-40, -3], - [-49, 63], - [-14, 45], - [-75, -19], - [-36, 33], - [-64, -11], - [-15, -36], - [-42, -7] - ], - [ - [12616, 12631], - [-130, -4] - ], - [ - [12486, 12627], - [-30, -10], - [-65, -69], - [-24, -13], - [-104, -22], - [-24, 5], - [-40, 64], - [-22, 12], - [-105, 12], - [-17, -6] - ], - [ - [12055, 12600], - [-1, -67] - ], - [ - [12054, 12533], - [-30, -65], - [-62, -23], - [9, 51], - [-73, 90], - [-70, 32], - [-77, -27] - ], - [ - [11751, 12591], - [-86, 63], - [-23, 8] - ], - [ - [11642, 12662], - [-115, 10] - ], - [ - [11527, 12672], - [-108, 67], - [-27, -4], - [-38, -55], - [64, -12], - [-7, -37], - [-118, 11], - [-74, -30] - ], - [ - [11219, 12612], - [-34, 5] - ], - [ - [11185, 12617], - [-42, 7], - [-32, -23], - [-46, 49] - ], - [ - [11065, 12650], - [-13, 41] - ], - [ - [11052, 12691], - [14, 80] - ], - [ - [11066, 12771], - [17, 102], - [-8, 66] - ], - [ - [11075, 12939], - [48, 112], - [9, 35], - [14, 111] - ], - [ - [11146, 13197], - [15, 47], - [31, 46] - ], - [ - [11192, 13290], - [15, 23] - ], - [ - [11207, 13313], - [39, 33] - ], - [ - [11246, 13346], - [5, 9] - ], - [ - [11251, 13355], - [6, 14] - ], - [ - [11257, 13369], - [21, 59] - ], - [ - [11278, 13428], - [-2, 5] - ], - [ - [11276, 13433], - [-2, 4] - ], - [ - [11274, 13437], - [-100, 42], - [-75, 0], - [-84, 64], - [-58, -22], - [-80, 9], - [-10, 33], - [-48, 14], - [-10, -29], - [-77, 79], - [-34, 79], - [-49, 28] - ], - [ - [10692, 13911], - [0, 12] - ], - [ - [10689, 13930], - [-45, 26] - ], - [ - [10638, 13959], - [-8, 5] - ], - [ - [10572, 14044], - [-9, 20] - ], - [ - [10644, 14224], - [4, 8] - ], - [ - [10631, 14328], - [-43, 29] - ], - [ - [10878, 15602], - [14, 90] - ], - [ - [10936, 15821], - [0, 5] - ], - [ - [10936, 15937], - [19, 55], - [-69, 35], - [-6, 18], - [27, 115], - [38, 37], - [32, 8], - [194, 24], - [36, -10], - [56, -87], - [-10, -54], - [46, -26], - [-3, 60], - [30, 55], - [77, -33], - [-18, 86], - [24, 82], - [37, 28], - [82, -31], - [111, 18], - [27, -16], - [93, -138], - [-16, 60], - [-82, 97], - [-22, 13], - [-100, 18], - [-32, 60], - [47, 5], - [0, 60], - [-46, 8], - [6, 87], - [-65, -14], - [-9, 71], - [65, 9], - [54, 37], - [-2, 18], - [-66, 113], - [-32, 23], - [-14, 87], - [25, 13] - ], - [ - [11470, 16928], - [55, -6] - ], - [ - [11525, 16922], - [150, -55] - ], - [ - [11675, 16867], - [77, 36] - ], - [ - [11752, 16903], - [18, -2], - [79, -57], - [35, 10], - [29, -114], - [-2, -21], - [-37, -50], - [65, 19], - [15, -66], - [68, 28], - [23, -3], - [99, -60], - [22, -4], - [72, 37], - [54, 5], - [5, -13], - [-19, -96], - [-15, -23], - [-86, -65], - [-4, -11], - [57, -24], - [75, 13], - [27, -35], - [70, -25], - [26, 61], - [54, 73], - [23, 11], - [114, 10], - [24, 8], - [59, 51], - [70, 111], - [14, 9], - [38, -34], - [-72, -23], - [-26, -61], - [113, 62], - [54, -9], - [47, 35], - [55, -103], - [53, -23], - [43, -56], - [77, 24], - [45, -30] - ], - [ - [13213, 16462], - [-3, -25] - ], - [ - [13210, 16437], - [-3, -24], - [45, -56], - [-24, -27], - [46, -62], - [95, -23], - [22, -14] - ], - [ - [13411, 15857], - [-13, -21] - ], - [ - [13343, 15717], - [6, -7] - ], - [ - [13499, 15538], - [2, -29] - ], - [ - [13501, 15509], - [-26, -47] - ], - [ - [13475, 15459], - [11, -60], - [22, -20] - ], - [ - [13535, 15018], - [-1, -30] - ], - [ - [13210, 16437], - [3, 25] - ], - [ - [13213, 16462], - [20, 25], - [125, -128], - [-9, -16], - [-74, -36], - [-10, 6], - [-8, 80], - [38, -23], - [-22, 60], - [-59, -19], - [-4, 26] - ], - [ - [13032, 16783], - [78, -45], - [51, -7], - [-4, -98], - [38, -32], - [-92, -10], - [-33, -37], - [-78, 37], - [30, 34], - [-14, 95], - [58, 5], - [-34, 58] - ], - [ - [10785, 16146], - [-28, 8], - [24, 17], - [4, -25] - ], - [ - [15148, 10139], - [56, -87], - [16, -18], - [57, -40] - ], - [ - [15345, 9979], - [21, -25] - ], - [ - [15388, 9926], - [13, -10] - ], - [ - [15478, 9832], - [-52, -52], - [-55, -16], - [7, -102] - ], - [ - [15378, 9662], - [-85, -41], - [-14, 6] - ], - [ - [15279, 9627], - [-16, 82], - [-23, 2], - [-120, -232] - ], - [ - [15120, 9479], - [-10, -34] - ], - [ - [15110, 9445], - [25, -45] - ], - [ - [15135, 9400], - [-1, -99] - ], - [ - [15134, 9301], - [0, -4] - ], - [ - [15134, 9297], - [-7, -36], - [-46, 32], - [-29, 81], - [-75, 97], - [-36, 23], - [-35, 67], - [-78, 54] - ], - [ - [14828, 9615], - [0, 55] - ], - [ - [14828, 9670], - [23, 61], - [-25, 63], - [-10, 93], - [14, 37], - [50, 10], - [10, 20] - ], - [ - [14890, 9954], - [11, 108] - ], - [ - [14901, 10062], - [50, 64], - [77, -14], - [2, 10], - [-43, 105], - [91, 14] - ], - [ - [15516, 9060], - [-3, -16] - ], - [ - [15527, 8930], - [30, -111] - ], - [ - [15663, 8703], - [13, -16] - ], - [ - [15692, 8646], - [18, -82] - ], - [ - [15632, 8417], - [-17, -43] - ], - [ - [15465, 8146], - [13, -39] - ], - [ - [15484, 8053], - [-33, -18], - [-21, -73], - [-12, -7], - [-59, 27], - [-7, 14], - [8, 82], - [-36, 35], - [-13, 69], - [-15, 19], - [-94, 65], - [-22, 24], - [-59, 110], - [53, -23], - [-15, 126], - [-38, 37], - [-1, 20], - [38, 125], - [33, 32], - [-24, 61], - [21, 134], - [-30, 76], - [30, 55], - [-17, 58], - [48, 38], - [-3, 82], - [-9, 18], - [-65, 41], - [-8, 17] - ], - [ - [15134, 9301], - [1, 99] - ], - [ - [15110, 9445], - [10, 34] - ], - [ - [15279, 9627], - [13, -6], - [86, 41] - ], - [ - [15378, 9662], - [25, -21], - [32, -96], - [39, -23], - [48, -55], - [37, -133], - [-3, -79] - ], - [ - [11904, 12214], - [42, -16] - ], - [ - [11946, 12198], - [11, 2] - ], - [ - [11957, 12200], - [67, 65], - [14, 0], - [21, -47] - ], - [ - [12059, 12218], - [-19, -121], - [15, -79], - [-9, -4], - [-78, 46] - ], - [ - [11968, 12060], - [-34, -23] - ], - [ - [11934, 12037], - [-12, -79] - ], - [ - [11922, 11958], - [2, -11] - ], - [ - [11924, 11947], - [31, -31], - [-1, -85], - [-30, -9], - [-40, 80], - [-27, -2] - ], - [ - [11857, 11900], - [-51, -7] - ], - [ - [11806, 11893], - [-56, -25], - [-33, 41], - [-4, 58] - ], - [ - [11713, 11967], - [-7, 13] - ], - [ - [11706, 11980], - [-48, 0], - [-1, -84], - [-18, -68], - [-66, -100], - [-10, -28], - [13, -83], - [-48, -19] - ], - [ - [11528, 11598], - [-6, 3] - ], - [ - [11522, 11601], - [-39, 86], - [11, 50], - [-63, 23], - [-38, 47] - ], - [ - [11393, 11807], - [-22, 34] - ], - [ - [11371, 11841], - [-10, 26], - [3, 78], - [-13, -2] - ], - [ - [11351, 11943], - [-97, -92], - [-8, -28] - ], - [ - [11246, 11823], - [10, -47], - [-35, -69], - [-57, -62], - [-18, -2], - [-101, 32] - ], - [ - [11045, 11675], - [-54, -36] - ], - [ - [10991, 11639], - [-20, -5] - ], - [ - [10971, 11634], - [-55, -11] - ], - [ - [10916, 11623], - [-37, 19] - ], - [ - [10879, 11642], - [-45, 99] - ], - [ - [10834, 11741], - [-18, 22] - ], - [ - [10816, 11763], - [-21, 4] - ], - [ - [10795, 11767], - [-1, 10] - ], - [ - [10794, 11777], - [16, 83], - [-13, 69], - [-14, 11] - ], - [ - [10783, 11940], - [-85, 14] - ], - [ - [10698, 11954], - [-71, -34], - [-18, -32] - ], - [ - [10609, 11888], - [-9, -15] - ], - [ - [10600, 11873], - [16, -42] - ], - [ - [10616, 11831], - [-41, -47] - ], - [ - [10575, 11784], - [-61, 29] - ], - [ - [10514, 11813], - [38, 22] - ], - [ - [10552, 11835], - [7, 11] - ], - [ - [10559, 11846], - [13, 56] - ], - [ - [10572, 11902], - [-19, 43], - [15, 88] - ], - [ - [10568, 12033], - [14, 22] - ], - [ - [10582, 12055], - [81, 73], - [11, 22], - [3, 82] - ], - [ - [10677, 12232], - [9, 17] - ], - [ - [10686, 12249], - [46, 28] - ], - [ - [10732, 12277], - [39, 50] - ], - [ - [10771, 12327], - [88, 119], - [11, 27], - [-30, 46] - ], - [ - [10840, 12519], - [3, 7] - ], - [ - [10843, 12526], - [23, 40] - ], - [ - [10866, 12566], - [12, 7] - ], - [ - [10878, 12573], - [57, -10], - [16, -32] - ], - [ - [10951, 12531], - [55, 6] - ], - [ - [11006, 12537], - [0, 1] - ], - [ - [11006, 12538], - [3, 3] - ], - [ - [11009, 12541], - [56, 109] - ], - [ - [11185, 12617], - [34, -5] - ], - [ - [11527, 12672], - [115, -10] - ], - [ - [11751, 12591], - [28, -36], - [-41, -81] - ], - [ - [11738, 12474], - [-25, -165], - [83, 3] - ], - [ - [11796, 12312], - [54, -18] - ], - [ - [11850, 12294], - [9, -10] - ], - [ - [11859, 12284], - [11, -48] - ], - [ - [11870, 12236], - [34, -22] - ], - [ - [11738, 12474], - [2, -18], - [56, -144] - ], - [ - [11410, 9550], - [42, 95], - [38, 46], - [81, 36], - [36, 41], - [60, -5], - [9, 18], - [12, 151], - [26, -16], - [12, -99], - [-10, -78], - [22, -52], - [15, -148], - [-2, -117], - [-43, -96], - [-9, -142], - [-7, -37], - [-48, -157], - [-20, -13], - [-92, 65], - [-37, 45], - [31, 57], - [-70, 43], - [-4, 14], - [32, 64], - [-3, 15], - [-54, 36], - [38, 64], - [-45, 55], - [26, 67], - [-36, 48] - ], - [ - [10160, 13925], - [13, -8] - ], - [ - [10520, 13725], - [58, 16] - ], - [ - [11274, 13437], - [2, -4] - ], - [ - [11278, 13428], - [-21, -59] - ], - [ - [11251, 13355], - [-5, -9] - ], - [ - [11207, 13313], - [-15, -23] - ], - [ - [11146, 13197], - [-15, -104], - [-56, -154] - ], - [ - [11066, 12771], - [-14, -80] - ], - [ - [11009, 12541], - [-3, -3] - ], - [ - [11006, 12537], - [-55, -6] - ], - [ - [10951, 12531], - [-16, 32], - [-57, 10] - ], - [ - [10878, 12573], - [-12, -7] - ], - [ - [10843, 12526], - [-3, -7] - ], - [ - [10771, 12327], - [-39, -50] - ], - [ - [10686, 12249], - [-9, -17] - ], - [ - [10582, 12055], - [-14, -22] - ], - [ - [10572, 11902], - [-13, -56] - ], - [ - [10552, 11835], - [-38, -22] - ], - [ - [10575, 11784], - [41, 47] - ], - [ - [10600, 11873], - [9, 15] - ], - [ - [10698, 11954], - [85, -14] - ], - [ - [10794, 11777], - [1, -10] - ], - [ - [10816, 11763], - [18, -22] - ], - [ - [10879, 11642], - [-13, -5] - ], - [ - [10866, 11637], - [-70, -69] - ], - [ - [10796, 11568], - [12, -47] - ], - [ - [10808, 11521], - [46, -42] - ], - [ - [10854, 11479], - [7, -13] - ], - [ - [10861, 11466], - [8, -56], - [37, -47] - ], - [ - [10906, 11363], - [9, -10] - ], - [ - [10915, 11353], - [-3, -62] - ], - [ - [10912, 11291], - [-9, -30] - ], - [ - [10903, 11261], - [-14, -24], - [-64, -50], - [-51, -16] - ], - [ - [10774, 11171], - [-35, -21], - [34, -76] - ], - [ - [10773, 11074], - [4, -7] - ], - [ - [10777, 11067], - [31, -30] - ], - [ - [10808, 11037], - [53, -28], - [12, -22] - ], - [ - [10873, 10987], - [4, -25] - ], - [ - [10877, 10962], - [-59, -157] - ], - [ - [10818, 10805], - [16, -88] - ], - [ - [10834, 10717], - [38, -53], - [104, -71], - [24, -3], - [87, 27], - [11, -6], - [-3, -68], - [-26, -53] - ], - [ - [11069, 10490], - [-32, -57], - [-7, -51], - [-97, -69], - [-14, -51], - [-57, -20], - [-38, -65], - [-42, -12], - [-49, -80], - [0, -51], - [-19, -13], - [-161, -46], - [-78, 10], - [-153, 79], - [-35, 57], - [-75, 0], - [17, 47], - [-18, 69], - [-27, -61], - [-38, 4], - [-69, -41], - [-17, 1], - [-42, 51], - [-114, 12], - [-37, 47], - [-43, -5], - [-141, -136], - [-27, -21], - [-73, -27], - [-17, -19], - [-48, -106], - [-7, -41], - [-3, -183], - [4, -35], - [33, -77] - ], - [ - [9545, 9600], - [-70, 11], - [-98, -36], - [-59, -35], - [-67, 45] - ], - [ - [9251, 9585], - [-19, 2] - ], - [ - [9232, 9587], - [-80, -32], - [-20, 5], - [-73, 65] - ], - [ - [8941, 9702], - [-17, 42], - [-122, 58], - [-103, 27], - [-17, -5], - [-2, -65] - ], - [ - [8680, 9759], - [-15, -10] - ], - [ - [8665, 9749], - [-99, -14], - [-59, 31], - [-47, -18], - [-24, 6] - ], - [ - [8436, 9754], - [-77, 64] - ], - [ - [8359, 9818], - [-28, 11], - [-70, -27], - [-17, 7], - [-45, 79], - [-72, 10], - [-124, 73], - [-46, 7], - [7, 83], - [-10, 24], - [-62, -11] - ], - [ - [7892, 10074], - [-7, 9] - ], - [ - [7885, 10083], - [-41, 52] - ], - [ - [7844, 10135], - [33, 23], - [60, 98], - [11, 32], - [37, 212], - [46, 348], - [13, 51], - [48, 22], - [-34, 40], - [-27, -51], - [-3, 23], - [15, 265], - [20, 199], - [27, 28], - [81, -96], - [16, -35], - [41, -147], - [-26, 178], - [-46, 88], - [-65, 69], - [-55, 31], - [-6, 44], - [56, 117], - [-2, 58], - [-35, 78], - [20, 32], - [-118, 62], - [-100, 87], - [-18, 23], - [-46, 94], - [-59, 73], - [-4, 21], - [30, 73], - [1, 52], - [-62, 37], - [2, 64], - [-88, 16], - [-15, 52], - [21, 32], - [-18, 57], - [-104, -10], - [-8, 7], - [32, 65], - [-11, 3], - [-114, -41], - [-23, 6], - [-69, 92], - [-30, -14], - [-53, 41], - [-93, 22], - [-30, 46], - [-14, 0], - [-73, -46], - [-18, 6], - [-54, 82], - [-18, 16], - [-78, 27], - [5, 11], - [119, 45], - [10, 14], - [-57, 55], - [-20, -21], - [-33, 41], - [12, 7], - [119, 4], - [8, 7], - [-65, 46], - [-21, 3], - [-86, -27], - [-12, 9], - [3, 96], - [15, 22], - [108, 60], - [43, -2], - [77, 35], - [64, -43], - [31, 40], - [45, -19], - [34, 81], - [16, 12], - [83, 14], - [23, -5], - [75, -50], - [19, -23], - [62, -110], - [24, -5], - [105, 73], - [19, 5], - [48, -41], - [51, 46], - [17, 2], - [96, -35], - [97, 18], - [-35, 31], - [-32, 86], - [14, 50], - [-14, 128], - [-63, 119], - [-10, 31], - [-16, 123], - [-27, 54], - [118, -28], - [97, 19], - [12, -6], - [-11, -65], - [51, -114], - [34, -14], - [197, -9], - [102, -34], - [76, 33], - [40, 41], - [86, 27], - [-82, 18], - [-10, 15], - [14, 92], - [20, 25], - [135, 87], - [38, 17], - [135, 37], - [30, 16], - [91, 89], - [21, 68], - [18, 188], - [0, 147], - [13, 31], - [92, 68], - [35, 15], - [159, 37], - [33, -21] - ], - [ - [9520, 14497], - [12, 1] - ], - [ - [9883, 14174], - [-2, -114] - ], - [ - [10114, 14126], - [3, -3] - ], - [ - [10110, 14034], - [19, -101] - ], - [ - [10129, 13933], - [7, -12] - ], - [ - [16265, 19098], - [83, 13], - [25, -6], - [116, -69], - [-43, -13], - [-40, -55], - [-113, -81], - [-70, 6], - [-57, -19], - [-13, -17], - [-46, -125], - [-55, -32], - [-9, 48], - [65, 78], - [-4, 18], - [-89, 50], - [-8, 16], - [33, 60], - [-44, 78], - [61, -11], - [23, -33], - [53, 73], - [108, 40], - [24, -19] - ], - [ - [16506, 19123], - [23, -40], - [-50, -21], - [-59, 35], - [32, 48], - [54, -22] - ], - [ - [16292, 19348], - [75, -27], - [33, -76], - [-8, -10], - [-91, -16], - [-16, -41], - [-58, -22], - [-32, 91], - [-47, 33], - [-76, 19], - [119, 18], - [20, 10], - [36, 55], - [45, -34] - ], - [ - [18175, 19556], - [-6, -13] - ], - [ - [18169, 19543], - [-93, -49], - [-18, -75], - [-54, -101], - [-68, -60], - [-18, -60], - [2, -31], - [38, -161], - [3, -30], - [-16, -80], - [47, -106] - ], - [ - [17992, 18790], - [11, -83] - ], - [ - [18003, 18707], - [7, -15] - ], - [ - [18010, 18692], - [35, -23], - [-78, -29] - ], - [ - [17967, 18640], - [-11, -10] - ], - [ - [17956, 18630], - [-6, -46] - ], - [ - [17950, 18584], - [-48, -39], - [-16, -69] - ], - [ - [17886, 18476], - [-11, -8], - [-79, 21] - ], - [ - [17796, 18489], - [-59, 37] - ], - [ - [17737, 18526], - [-11, 1] - ], - [ - [17726, 18527], - [-19, -27] - ], - [ - [17707, 18500], - [-14, -7] - ], - [ - [17693, 18493], - [-81, -23] - ], - [ - [17612, 18470], - [-20, 3] - ], - [ - [17592, 18473], - [-83, 61], - [-74, 85] - ], - [ - [17435, 18619], - [-22, 45] - ], - [ - [17413, 18664], - [-107, 27], - [-123, 77] - ], - [ - [17183, 18768], - [-72, 14], - [-24, -5], - [-94, -51] - ], - [ - [16993, 18726], - [-20, -7] - ], - [ - [16973, 18719], - [-45, 0], - [-75, -42], - [38, 100], - [3, 81], - [24, 87], - [-49, 36], - [-47, -65], - [-48, -25], - [-52, 47], - [-65, 9], - [-11, 13], - [-16, 83], - [-58, 33], - [3, 101], - [12, 11], - [85, -6], - [-12, 31], - [-65, 0], - [-52, 63], - [45, 35], - [-43, 33], - [26, 69], - [-6, 52], - [70, 32], - [120, 20], - [23, 13], - [81, 81], - [45, -14], - [194, 45], - [35, 4], - [80, -19], - [49, 19], - [-11, 76], - [55, -44], - [13, 46], - [48, -40], - [35, 21], - [108, -19], - [83, -29], - [48, 8], - [94, -57], - [30, -7], - [169, -2], - [135, -19], - [23, 2], - [34, 37], - [49, -63] - ], - [ - [13501, 5703], - [-27, -32], - [-41, 21], - [-35, 87], - [6, 8], - [68, -25], - [29, -59] - ], - [ - [13366, 5842], - [-34, 25], - [22, 14], - [12, -39] - ], - [ - [12457, 16884], - [26, 40], - [55, -70], - [3, -51], - [-16, -9], - [-119, -19], - [-31, 6], - [-117, 77], - [24, 23], - [-18, 50], - [87, 18], - [93, -63], - [13, -2] - ], - [ - [12669, 16921], - [-27, 14], - [48, 76], - [16, 4], - [77, -31], - [-114, -63] - ], - [ - [11899, 16982], - [19, -62], - [-62, 5], - [-9, 12], - [-6, 88], - [58, -43] - ], - [ - [12154, 16838], - [-33, 46], - [8, 25], - [86, 133], - [8, 5], - [-61, -204], - [-8, -5] - ], - [ - [12076, 17296], - [-12, -45], - [47, 28], - [8, 51], - [35, -40], - [-11, -49], - [38, -60], - [2, -23], - [-19, -106], - [-9, -19], - [-72, -27], - [-119, 27], - [-16, 10], - [-9, 52], - [-74, 48], - [-8, 57], - [-54, 79], - [77, 11], - [150, 47], - [46, -41] - ], - [ - [12804, 17584], - [-25, -41], - [21, -105], - [-27, -78], - [-50, -22], - [-46, -84], - [4, -16], - [59, -37], - [5, -47], - [-92, -45], - [-17, -47], - [11, -68], - [-8, -10], - [-67, -5], - [67, -69], - [3, -18], - [-46, -68], - [-16, -79], - [-28, 103], - [-43, 94], - [41, 32], - [-3, 17], - [-60, 87], - [-72, 33], - [-60, -8], - [-14, 9], - [-51, 87], - [29, 33], - [-35, 57], - [7, 46], - [-65, 69], - [8, 12], - [124, 19], - [22, 13], - [33, 73], - [14, 13], - [73, 18], - [-13, -47], - [33, -101], - [12, 0], - [57, 120], - [-30, 27], - [88, 77], - [74, 15], - [83, -59] - ], - [ - [11511, 18040], - [-62, -60], - [-13, -1], - [-29, 65], - [49, 61], - [74, 26], - [-19, -91] - ], - [ - [11752, 16903], - [-77, -36] - ], - [ - [11675, 16867], - [-150, 55] - ], - [ - [11470, 16928], - [-26, 17], - [6, 96], - [-8, 13], - [-66, -4], - [19, 50], - [49, -14], - [5, 14], - [-14, 110], - [-8, 19], - [-58, 33], - [-41, 56], - [-13, -46], - [-57, 42], - [-4, 18], - [22, 112], - [-12, 96], - [24, -65], - [53, 49], - [2, 17], - [-38, 80], - [-30, 14], - [-19, -45], - [1, 240], - [19, 130], - [7, 6], - [52, -53], - [86, -46], - [52, 25], - [-10, 56], - [68, 78], - [43, 22], - [45, -50], - [22, 14], - [-17, 90], - [41, 54], - [61, 14], - [60, -16], - [82, 44], - [-30, 19], - [-65, -30], - [-139, -18], - [-43, 18], - [-129, -55], - [-22, -17], - [-51, -85], - [29, -63], - [-27, -31], - [-81, 78], - [4, 53], - [91, 131], - [28, 20], - [151, 37], - [89, 0], - [74, 36], - [21, 25], - [97, 147], - [23, 24], - [68, 23], - [110, 72], - [56, 13], - [-59, -83], - [-5, -19], - [31, -81], - [-2, -112], - [-38, -55], - [-45, -134], - [-3, -26], - [24, -159], - [51, -43], - [125, -10], - [35, -48], - [-21, -59], - [-65, -87], - [-20, -12], - [-82, 12], - [27, 46], - [-24, 22], - [-55, -72], - [2, -92], - [-23, -89], - [-15, -9], - [-87, 3], - [38, -19], - [-10, -65], - [-66, -19], - [6, -48], - [-67, -88], - [-5, -27], - [26, -105], - [-4, -20], - [-59, -37], - [0, -13], - [75, -73], - [4, -79], - [-38, 37], - [-21, -29] - ], - [ - [14085, 14421], - [12, -5] - ], - [ - [14378, 14265], - [81, -72], - [22, -2] - ], - [ - [14573, 14174], - [-42, -33], - [7, -17] - ], - [ - [14942, 13763], - [-92, -33] - ], - [ - [14846, 13727], - [-62, -83] - ], - [ - [14716, 13585], - [-25, -93] - ], - [ - [14625, 13421], - [-97, -64], - [-23, -4] - ], - [ - [14311, 13246], - [-9, -8], - [-18, 41], - [-20, 12] - ], - [ - [14264, 13291], - [-119, 41], - [-19, 1], - [-31, -36], - [-87, 13], - [-91, 64], - [-79, 12], - [-101, 50] - ], - [ - [13737, 13436], - [-25, 10] - ], - [ - [13712, 13446], - [-70, 14] - ], - [ - [13642, 13460], - [-14, -18] - ], - [ - [13628, 13442], - [-29, -127], - [-35, 5], - [-48, -99], - [-11, -8], - [-46, 27] - ], - [ - [13459, 13240], - [-70, -38] - ], - [ - [13389, 13202], - [-90, 31] - ], - [ - [13299, 13233], - [-14, 39] - ], - [ - [13285, 13272], - [-20, 18] - ], - [ - [13265, 13290], - [-38, 32] - ], - [ - [12934, 13631], - [-19, 19] - ], - [ - [12874, 13650], - [-3, 1] - ], - [ - [12693, 14059], - [-20, 27] - ], - [ - [12730, 14222], - [25, 22] - ], - [ - [12835, 14291], - [29, 9] - ], - [ - [12928, 14289], - [7, 16] - ], - [ - [12941, 14323], - [30, 12] - ], - [ - [13061, 14403], - [21, -2] - ], - [ - [13098, 14402], - [57, 60] - ], - [ - [13376, 14615], - [-5, 9] - ], - [ - [13394, 14654], - [48, -9] - ], - [ - [13563, 14536], - [55, 18] - ], - [ - [14188, 12716], - [-26, -1], - [-38, -42], - [2, -7], - [54, -14], - [9, -13] - ], - [ - [14189, 12639], - [11, -78], - [-7, -16], - [-59, -31], - [-12, -83], - [18, -136], - [-6, -16], - [-73, -12] - ], - [ - [14061, 12267], - [-40, -51] - ], - [ - [13974, 12168], - [1, -37] - ], - [ - [13977, 12101], - [-12, -7], - [-93, 18] - ], - [ - [13176, 11995], - [-44, 18] - ], - [ - [13132, 12013], - [-38, 7] - ], - [ - [13094, 12020], - [-54, -5] - ], - [ - [13040, 12015], - [-242, 63], - [-38, 16], - [-77, 80] - ], - [ - [12683, 12174], - [-38, 73] - ], - [ - [12645, 12247], - [-8, 27], - [19, 46], - [-15, -1] - ], - [ - [12641, 12319], - [-148, -54] - ], - [ - [12493, 12265], - [-5, -1] - ], - [ - [12488, 12264], - [-64, 13] - ], - [ - [12424, 12277], - [-102, -19], - [-18, -14], - [-43, -82] - ], - [ - [12261, 12162], - [-17, -12] - ], - [ - [12244, 12150], - [-85, 5], - [-29, 42], - [-51, -5], - [-20, 26] - ], - [ - [11957, 12200], - [-11, -2] - ], - [ - [11904, 12214], - [-34, 22] - ], - [ - [11859, 12284], - [-9, 10] - ], - [ - [12054, 12533], - [1, 67] - ], - [ - [12486, 12627], - [130, 4] - ], - [ - [12889, 12979], - [35, 20] - ], - [ - [13015, 13040], - [35, 18] - ], - [ - [13108, 13195], - [11, 10] - ], - [ - [13224, 13297], - [3, 25] - ], - [ - [13227, 13322], - [38, -32] - ], - [ - [13285, 13272], - [14, -39] - ], - [ - [13389, 13202], - [70, 38] - ], - [ - [13628, 13442], - [14, 18] - ], - [ - [13712, 13446], - [25, -10] - ], - [ - [14264, 13291], - [20, -13], - [18, -59] - ], - [ - [14392, 12875], - [-8, -5] - ], - [ - [14384, 12870], - [-54, -70], - [-3, -19] - ], - [ - [14327, 12781], - [14, -73], - [-9, -13], - [-78, -14], - [-66, 35] - ], - [ - [14902, 11149], - [31, -82] - ], - [ - [14933, 11067], - [74, -37], - [21, 13] - ], - [ - [15066, 11053], - [63, -7] - ], - [ - [15067, 10832], - [-8, -54] - ], - [ - [15107, 10681], - [26, -36] - ], - [ - [15136, 10284], - [-12, -4] - ], - [ - [14901, 10062], - [-11, -108] - ], - [ - [14828, 9670], - [-35, 13], - [-157, 128], - [-27, 50], - [-50, 2] - ], - [ - [14559, 9863], - [-15, 46] - ], - [ - [14544, 9909], - [-19, 51], - [-91, 138], - [-16, 82], - [-13, 19], - [-95, 78], - [-101, 132], - [-46, 77], - [-83, 96], - [-34, 81], - [-24, 133], - [-53, 106], - [-64, 32], - [-21, 82], - [27, 174], - [11, 26], - [48, 10], - [19, -12], - [86, -92], - [16, -5], - [21, 55], - [52, 55], - [101, -8] - ], - [ - [14265, 11219], - [33, 22] - ], - [ - [14298, 11241], - [96, -47], - [15, 19], - [92, -37], - [43, 19], - [77, -46], - [49, 34], - [57, -18], - [29, 24], - [98, -49], - [48, 9] - ], - [ - [6866, 16440], - [-55, 7], - [19, 76], - [52, 77], - [64, 34], - [6, -10], - [-8, -97], - [-10, -22], - [-68, -65] - ], - [ - [6608, 5728], - [-10, 35], - [29, -9], - [-19, -26] - ], - [ - [8882, 7507], - [15, 77], - [14, 13], - [89, 36], - [6, -47], - [-67, -94], - [-14, -8], - [-43, 23] - ], - [ - [9316, 7865], - [-41, 60], - [13, 26], - [132, 124], - [31, 23], - [101, 47], - [-27, -47], - [33, -74], - [84, -8], - [3, -21], - [-51, -152], - [-65, -95], - [-19, -2], - [-84, 51], - [-34, 86], - [-76, -18] - ], - [ - [9895, 8198], - [49, -94], - [-13, -38], - [-114, 61], - [-35, 0], - [0, 50], - [113, 21] - ], - [ - [8359, 9818], - [77, -64] - ], - [ - [8665, 9749], - [15, 10] - ], - [ - [9232, 9587], - [19, -2] - ], - [ - [9545, 9600], - [47, -71], - [-41, -34], - [-15, -71], - [30, -63], - [0, -56], - [-80, -112], - [-32, -28], - [-159, -111], - [-33, -27], - [-75, -87], - [-33, -20], - [-159, -56], - [-182, -85], - [-30, -25], - [-73, -101], - [-4, -20], - [43, -41], - [-6, -16], - [-89, -73], - [-22, -31], - [-90, -196], - [-113, -197], - [-23, -49], - [-54, -147], - [-7, -33], - [15, -124], - [41, -138], - [39, -77], - [67, -36], - [24, -41], - [-9, -20], - [-111, -120], - [-65, -32], - [-58, -68], - [-6, -70], - [-40, -50], - [-13, -87], - [-60, -143], - [-4, -24], - [25, -71], - [-40, -19], - [-113, 8], - [-30, -13], - [-140, -129], - [-37, -84], - [-36, -145], - [-59, -101], - [-17, -9], - [-79, 40], - [-78, -18], - [-45, -55], - [-16, -4], - [-85, 31], - [-102, -2], - [-65, -23], - [-89, 23], - [-181, -8], - [-29, -12], - [-67, -88], - [-55, -31], - [-84, -12], - [-73, -46], - [-15, -22], - [-43, -124], - [-24, 9], - [-24, -73], - [-43, -22], - [-17, 7], - [-75, 73], - [-66, 34], - [-27, 41], - [-90, 242], - [-9, 34], - [4, 52], - [-59, 100], - [-113, 115], - [-34, 15], - [-123, -5], - [-22, 23], - [-26, 167] - ], - [ - [5864, 6718], - [4, 40], - [68, 153] - ], - [ - [5936, 6911], - [12, 57], - [50, 41], - [27, -9], - [25, 87], - [-49, 17], - [-15, 18], - [-60, 123], - [-4, 36], - [27, 128] - ], - [ - [5949, 7409], - [66, 82] - ], - [ - [6015, 7491], - [30, 90], - [-15, 48] - ], - [ - [6030, 7629], - [-44, 13] - ], - [ - [5986, 7642], - [-30, 76] - ], - [ - [5956, 7718], - [-22, 104], - [-76, 132], - [9, 16], - [126, 9], - [26, 21], - [54, 137], - [2, 31], - [-41, 78], - [3, 23], - [69, 105], - [-14, 57], - [11, 111], - [-5, 119], - [-34, 104], - [43, 34], - [61, 109], - [87, 68], - [16, 22], - [32, 99], - [-47, 37], - [-54, 10], - [-7, 14], - [5, 92], - [-27, 60] - ], - [ - [6173, 9310], - [-13, 4] - ], - [ - [6160, 9314], - [-72, -9] - ], - [ - [6088, 9305], - [-98, 13] - ], - [ - [5990, 9318], - [-19, -3], - [-22, -57], - [-62, -30], - [-51, 10], - [-38, 37], - [-22, -1], - [-123, -41], - [-20, 1], - [-11, 65], - [30, 51], - [-45, 64], - [-21, 0], - [-103, -49], - [-60, -58] - ], - [ - [5423, 9307], - [-24, -7], - [-11, 96], - [9, 26], - [74, 96], - [-62, -23], - [43, 91], - [-49, 7], - [22, 92], - [-18, 49], - [-52, -69], - [-28, 28], - [49, 125], - [-57, -17], - [-16, 70], - [-43, -7], - [-8, 82], - [31, 73], - [83, 50], - [44, 52], - [50, -15], - [111, 50], - [48, -34], - [8, 46], - [-42, 43], - [20, 61], - [54, 22], - [20, 51], - [59, 6], - [57, 36], - [42, -54], - [72, -8], - [45, -64], - [87, -9], - [110, 14], - [76, -13], - [62, 19], - [113, 2], - [37, 35], - [42, -41], - [89, -11], - [123, -48], - [204, -46], - [47, -4], - [126, 23], - [67, 34], - [11, -31], - [56, 37], - [30, -7], - [150, -82], - [25, -6], - [21, 41], - [55, 22], - [24, -7], - [147, -75], - [78, -9], - [62, 21], - [27, 32], - [21, -17] - ], - [ - [7885, 10083], - [7, -9] - ], - [ - [16314, 12923], - [16, -11] - ], - [ - [16339, 12826], - [-67, -82] - ], - [ - [16226, 12741], - [-23, -1] - ], - [ - [15713, 11835], - [-67, 13], - [-14, -6], - [-38, -60] - ], - [ - [15580, 11775], - [-74, 13] - ], - [ - [15502, 11787], - [-57, -27] - ], - [ - [15383, 11778], - [-110, -8], - [-59, 19], - [-23, -14] - ], - [ - [15111, 11695], - [-72, -2] - ], - [ - [14976, 11641], - [-3, 1] - ], - [ - [14973, 11642], - [-72, -8], - [-95, -87] - ], - [ - [14806, 11547], - [-72, 14] - ], - [ - [14734, 11561], - [-89, -4], - [-80, 36], - [-33, 51], - [-89, 32], - [-41, 67], - [-64, 50], - [-71, 113] - ], - [ - [14267, 11906], - [-61, 46] - ], - [ - [14206, 11952], - [-39, 30] - ], - [ - [14167, 11982], - [-53, 72] - ], - [ - [14106, 12075], - [-16, 92], - [-10, 16], - [-57, 22] - ], - [ - [14021, 12216], - [40, 51] - ], - [ - [14189, 12639], - [-8, 13], - [-49, 14], - [42, 49], - [14, 1] - ], - [ - [14327, 12781], - [57, 89] - ], - [ - [14608, 12733], - [274, 3], - [34, 6] - ], - [ - [15256, 12986], - [67, -36], - [27, 9] - ], - [ - [15452, 13033], - [37, 50] - ], - [ - [15567, 13182], - [81, 11] - ], - [ - [6887, 15953], - [0, 81], - [10, 10], - [74, -1], - [36, -53], - [47, -6], - [-71, -78], - [-43, -20], - [-53, 67] - ], - [ - [6503, 18309], - [-1, 0] - ], - [ - [6502, 18309], - [-18, 35], - [24, 50], - [-52, -19], - [-7, 11], - [-9, 96], - [7, 12], - [54, -14], - [-45, 64], - [-3, 97], - [8, 10], - [67, -17], - [-11, 65], - [44, -28], - [36, 37], - [93, -41], - [-41, 62], - [-51, 27], - [39, 73], - [-34, 65], - [8, 7], - [92, 0], - [8, 10], - [-28, 80], - [38, 15], - [-22, 50], - [29, 50], - [17, 3], - [116, -33], - [123, -14], - [80, 32], - [67, -7], - [80, 25], - [65, -9], - [16, 32], - [110, -10], - [-21, -136], - [-33, -43], - [-213, -183], - [-33, -33], - [-27, -51], - [-84, -12], - [104, -27], - [10, -10], - [-24, -51], - [-105, -19], - [-28, -46], - [117, 46], - [-19, -46], - [-56, -29], - [20, -30], - [51, 52], - [80, 9], - [132, 60], - [30, 5], - [78, -24], - [79, 13], - [152, -14], - [119, 14], - [25, -4], - [62, -46], - [21, -80], - [-64, -95], - [-37, -139], - [-40, -91], - [-64, -82], - [-38, -91], - [-65, -79], - [-81, -32], - [37, -52], - [68, -37], - [1, -11], - [-71, -46], - [-66, -4], - [-54, -65], - [-51, -24], - [-103, 9], - [3, -26], - [140, -29], - [82, 13], - [46, 43], - [48, 5], - [68, -48], - [116, -50], - [26, -21], - [84, -120], - [54, -32], - [12, -30], - [32, -179], - [12, -42], - [57, -147], - [16, -78], - [40, -74], - [24, -18], - [146, -68], - [31, -27], - [78, -124], - [88, -86], - [5, -14], - [-32, -41], - [11, -58], - [94, -148], - [2, -18], - [-68, 0], - [-67, 53], - [-21, 6], - [-94, -5], - [17, -27], - [90, 8], - [167, -166], - [20, -29], - [30, -97], - [1, -60], - [-96, -111], - [2, -20], - [94, -56], - [21, 6], - [51, 91], - [24, 13], - [118, 0], - [115, -31], - [123, -93], - [17, -29], - [21, -128], - [-3, -42], - [-46, -165], - [-25, -44], - [-135, -147], - [-23, -16], - [-32, 16], - [-11, -106], - [-50, -56], - [-99, -16], - [63, -38], - [-38, -20], - [59, -27], - [34, -3], - [177, 9], - [21, -14], - [-26, -111], - [-15, -20], - [-78, -37], - [-52, -87], - [-60, 0], - [-73, -47], - [-105, -41], - [-35, -2], - [-143, 32], - [-36, 1], - [-119, -27], - [-23, 0], - [-46, 32], - [-74, -22], - [-19, 5], - [-81, 55], - [25, -44], - [-17, -14], - [-183, -55], - [-35, 19], - [19, -66], - [-14, -7], - [-121, 14], - [-19, -5], - [-13, -50], - [-41, 47], - [-102, 55], - [-28, 4], - [-97, -27], - [-66, -41], - [-40, -88], - [14, -32], - [-53, -96], - [-50, -12], - [-134, 94], - [-26, 7], - [-87, -37], - [-87, -10], - [-25, -51], - [-101, -82], - [-22, -60], - [-40, 55], - [-69, 24], - [-62, -32], - [15, 64], - [87, 25], - [67, 65], - [55, 108], - [58, 2], - [18, 18], - [75, 132], - [13, 33], - [16, 96], - [48, 8], - [52, 42], - [0, 63], - [14, 10], - [111, 22], - [30, 0], - [134, -24], - [96, 14], - [19, 14], - [45, 100], - [56, 41], - [79, 132], - [-65, -65], - [-84, -22], - [-67, -83], - [-22, -8], - [-108, 4], - [-25, 14], - [-69, 92], - [-16, 10], - [-55, -27], - [-88, 8], - [50, 63], - [-59, 0], - [-23, 57], - [-82, -24], - [-43, -49], - [-77, -27], - [-46, 32], - [70, 31], - [-120, 13], - [39, 31], - [-15, 42], - [-37, 11], - [82, 88], - [70, 1], - [51, 54], - [75, 21], - [65, 52], - [61, 88], - [15, 83], - [-19, 45], - [35, 60], - [-48, 62], - [11, 57], - [-94, -17], - [-49, -53], - [-65, 0], - [43, 74], - [65, 51], - [62, 104], - [21, 18], - [97, 36], - [180, 31], - [28, -2], - [61, -44], - [-24, 77], - [30, 23], - [56, -65], - [-48, 138], - [-1, 27], - [44, 78], - [-35, 27], - [-8, 61], - [69, 59], - [-16, 37], - [27, 58], - [-64, 42], - [-13, -3], - [-24, -65], - [-14, 4], - [-86, 109], - [-8, 44], - [-57, 92], - [2, 35], - [67, 161], - [20, 28], - [73, 42], - [-8, 5], - [-126, 0], - [-20, -6], - [-19, -54], - [-63, -16], - [-66, -47], - [-50, 8], - [-73, 60], - [-10, -6], - [3, -101], - [-16, -3], - [-116, 78], - [-21, 7], - [-35, -27], - [16, -82], - [-86, 120], - [-10, 25], - [11, 65], - [92, 132], - [14, 58], - [54, 73], - [-8, 73], - [-70, 66], - [-7, 20], - [9, 97], - [8, 16], - [51, 24], - [-1, 14], - [-71, 84], - [2, -91], - [-35, -50], - [-61, 32], - [-6, -60], - [-79, 89], - [33, -101], - [-2, -25], - [-48, -88], - [1, -54], - [-49, -136], - [-41, -5], - [-1, 25], - [27, 179], - [2, 43], - [-8, 123], - [6, 32], - [45, 101], - [-11, 79], - [57, 155], - [38, 60], - [84, 33], - [-54, 9], - [6, 29], - [-148, -143], - [-32, -11], - [-84, 65], - [-3, 13], - [52, 30], - [-124, -8], - [-5, 30], - [57, 23], - [51, -13], - [42, 72], - [-47, 9], - [3, 22], - [73, 161], - [5, 30] - ], - [ - [6502, 18309], - [1, 0] - ], - [ - [6503, 18309], - [-27, -47], - [-90, -73], - [40, 73], - [-10, 9], - [-119, -9], - [-53, 40], - [-20, 84], - [-51, -18], - [-51, 55], - [48, 12], - [0, 69], - [11, 1], - [81, -60], - [8, 4], - [-21, 96], - [33, 15], - [43, -47], - [7, -151], - [9, -23], - [81, -31], - [80, 1] - ], - [ - [6666, 17386], - [29, -122], - [-6, -13], - [-74, 16], - [-16, 83], - [38, 55], - [29, -19] - ], - [ - [5906, 16994], - [38, 27] - ], - [ - [5944, 17021], - [67, -6], - [35, 67], - [62, 8], - [120, 39], - [91, -14], - [17, -11], - [43, -100], - [89, -151], - [5, -28], - [-54, -50], - [54, 19], - [80, -30], - [23, -82], - [-13, -67], - [-31, 24], - [-4, 66], - [-33, 23], - [14, -84], - [-19, -31], - [48, -29], - [-32, -46], - [-69, -12], - [-54, -95], - [-19, -7], - [-104, 37], - [-10, -5] - ], - [ - [6218, 17391], - [12, 82], - [13, 16], - [78, 37], - [16, -10], - [37, -126], - [-65, -52], - [-11, 6], - [-21, 87], - [-10, 5], - [-49, -45] - ], - [ - [6409, 17596], - [67, 27], - [-1, -15], - [-74, -142], - [-40, 48], - [48, 37], - [0, 45] - ], - [ - [6458, 17766], - [-42, 10], - [-113, -43], - [-32, 25], - [87, 27], - [-35, 10], - [9, 64], - [-54, 43], - [60, 46], - [13, -1], - [43, -63], - [95, -35], - [7, -47], - [-38, -36] - ], - [ - [14828, 9615], - [-14, -5], - [-162, 169], - [-30, 25], - [-54, 5], - [-32, 15], - [-172, 106], - [-15, 13], - [91, -23], - [119, -57] - ], - [ - [14124, 10035], - [53, 21], - [40, -26], - [137, -24], - [-137, -2], - [-93, 31] - ], - [ - [14248, 10131], - [12, -40], - [-95, 0], - [-18, 58], - [101, -18] - ], - [ - [13597, 10853], - [99, -118], - [-100, 75], - [1, 43] - ], - [ - [13549, 11001], - [18, -63], - [-43, 45], - [25, 18] - ], - [ - [13394, 11051], - [27, 43], - [-30, 60], - [21, 35], - [37, -121], - [-6, -63], - [24, -96], - [-34, 4], - [-39, 138] - ], - [ - [13501, 11122], - [-55, 26], - [-3, 13], - [40, 83], - [31, -78], - [47, -62], - [-47, -17], - [-13, 35] - ], - [ - [14734, 11561], - [72, -14] - ], - [ - [14973, 11642], - [-5, -77] - ], - [ - [15040, 11408], - [-30, -62], - [5, -19] - ], - [ - [15032, 11306], - [36, -32] - ], - [ - [15132, 11247], - [9, -7] - ], - [ - [14933, 11067], - [-31, 82] - ], - [ - [14298, 11241], - [-33, -22] - ], - [ - [14544, 9909], - [-40, -5], - [-46, 70], - [-92, 77], - [-103, 119], - [-71, 23], - [-68, 50], - [-25, 5], - [-119, -19], - [-18, 10], - [-11, 87], - [-10, 17], - [-78, 49], - [-96, 115], - [-73, 111], - [-5, 23], - [35, 60], - [78, -23], - [-88, 74], - [-89, 121], - [-30, 95], - [8, 82], - [-17, 90], - [-101, 126], - [-73, 35], - [-15, -17], - [-54, -133], - [-14, -70], - [-48, -42], - [5, -36], - [-64, 26], - [-18, 61], - [-52, 91], - [-3, 97], - [-20, 105], - [28, 4] - ], - [ - [13870, 11704], - [-21, 84] - ], - [ - [13860, 11804], - [114, 64] - ], - [ - [14063, 11917], - [1, 61] - ], - [ - [14081, 11997], - [13, 10] - ], - [ - [14094, 12007], - [14, -2] - ], - [ - [14120, 12000], - [47, -18] - ], - [ - [14206, 11952], - [26, -31], - [35, -15] - ], - [ - [15730, 17381], - [16, -6], - [-5, -113], - [-45, -107], - [27, 94], - [7, 132] - ], - [ - [17278, 16588], - [51, -19] - ], - [ - [17268, 16485], - [-18, 73], - [-13, 6] - ], - [ - [16549, 16467], - [-6, 10] - ], - [ - [16526, 16510], - [-19, 19] - ], - [ - [16289, 16618], - [0, 156], - [6, 30], - [38, 73], - [-2, 15], - [-62, 69] - ], - [ - [16269, 16961], - [-19, 46] - ], - [ - [16250, 17007], - [-18, 13], - [-91, 5] - ], - [ - [16141, 17025], - [-53, -21] - ], - [ - [16088, 17004], - [-1, 0] - ], - [ - [16087, 17004], - [-20, 7] - ], - [ - [16067, 17011], - [-181, 85] - ], - [ - [15886, 17096], - [-17, 6] - ], - [ - [15869, 17102], - [-47, 47] - ], - [ - [15822, 17149], - [-24, 40], - [-43, 189], - [-22, 36], - [-12, 168], - [4, 22], - [47, 25], - [54, 69] - ], - [ - [15826, 17698], - [241, 109], - [42, 11], - [108, -13], - [48, -24], - [84, 28], - [17, -2], - [65, -48], - [59, 29], - [54, -19], - [75, 8], - [156, -46] - ], - [ - [16775, 17731], - [29, -6], - [72, 0], - [28, 13] - ], - [ - [16904, 17738], - [119, 82], - [22, -3], - [49, -101], - [27, -19], - [149, -32], - [40, -22], - [170, -151], - [49, -69], - [113, -56] - ], - [ - [17886, 18476], - [63, -5], - [1, -47] - ], - [ - [17950, 18424], - [12, -14] - ], - [ - [17962, 18410], - [86, -64], - [12, -17], - [-5, -73], - [-38, -32], - [10, -47], - [-29, -84], - [6, -11], - [70, -19], - [1, -45], - [41, -66], - [11, -37], - [37, -41], - [27, -151], - [-22, -67] - ], - [ - [17856, 17451], - [-72, 18] - ], - [ - [17656, 17391], - [-14, -24] - ], - [ - [16904, 17738], - [-18, -7], - [-81, -5], - [-30, 5] - ], - [ - [15826, 17698], - [-86, -73], - [-17, -3], - [-26, 96], - [9, 202], - [24, 133], - [15, 32], - [81, 87], - [14, 30], - [19, 128], - [14, 36], - [81, 118], - [23, 20], - [115, 29], - [143, 60], - [22, -2], - [13, -73], - [18, -24], - [116, -91], - [25, -33], - [62, -143], - [25, -27], - [110, -50], - [33, 2], - [149, 81], - [54, 60], - [7, 34], - [-3, 179], - [-18, 151], - [6, 20], - [79, 42], - [40, 0] - ], - [ - [16993, 18726], - [103, 51], - [87, -9] - ], - [ - [17413, 18664], - [22, -45] - ], - [ - [17592, 18473], - [20, -3] - ], - [ - [17612, 18470], - [81, 23] - ], - [ - [17707, 18500], - [19, 27] - ], - [ - [17737, 18526], - [59, -37] - ], - [ - [13118, 6576], - [-73, 51], - [-43, 54], - [-41, 5], - [-46, 42], - [-99, 12], - [-47, 55], - [-21, 65], - [15, 114], - [70, 76], - [15, 38], - [59, -74], - [50, 21], - [21, 57], - [63, 22], - [35, -61], - [44, -8], - [38, -47], - [60, -21], - [94, 37], - [53, -14], - [82, 9], - [77, 59], - [75, 23], - [83, -14], - [23, 7], - [117, 77], - [27, -22], - [-119, -240], - [-20, -49], - [-43, -169], - [8, -93], - [38, -32], - [-11, -53], - [32, -92], - [-1, -18], - [-50, -63], - [-6, -110], - [-9, -11], - [-75, 29], - [-29, -14], - [-87, 40], - [-16, 17], - [-54, 104], - [-93, 78], - [-48, -5], - [-74, 41], - [-74, 77] - ], - [ - [11402, 7615], - [-48, 73], - [-7, 94], - [27, 156], - [1, 85], - [25, 60], - [-40, 23], - [-12, 67], - [36, 62], - [-9, 108], - [-28, 46], - [-33, 116], - [-41, 9], - [-4, 25], - [11, 160], - [7, 16], - [38, -46], - [57, -17], - [96, 51], - [19, 20], - [79, 112], - [68, 63], - [95, -63], - [12, -21], - [3, -91], - [49, -60], - [-9, -33], - [44, -149], - [-1, -33], - [-48, -106], - [-4, -33], - [21, -128], - [0, -55], - [-27, -256], - [-1, -115], - [-33, -104], - [-12, -5], - [-54, 46], - [-84, 11], - [-12, -14], - [-16, -111], - [-9, -22], - [-61, -51], - [-75, 20], - [-20, 90] - ], - [ - [10834, 10717], - [-16, 88] - ], - [ - [10877, 10962], - [-4, 25] - ], - [ - [10808, 11037], - [-31, 30] - ], - [ - [10773, 11074], - [-32, 76], - [33, 21] - ], - [ - [10903, 11261], - [9, 30] - ], - [ - [10915, 11353], - [-9, 10] - ], - [ - [10861, 11466], - [-7, 13] - ], - [ - [10808, 11521], - [-12, 47] - ], - [ - [10796, 11568], - [70, 69] - ], - [ - [10916, 11623], - [55, 11] - ], - [ - [10991, 11639], - [54, 36] - ], - [ - [11246, 11823], - [14, 32], - [91, 88] - ], - [ - [11371, 11841], - [22, -34] - ], - [ - [11522, 11601], - [6, -3] - ], - [ - [11706, 11980], - [7, -13] - ], - [ - [11806, 11893], - [51, 7] - ], - [ - [11924, 11947], - [-2, 11] - ], - [ - [11934, 12037], - [34, 23] - ], - [ - [12244, 12150], - [17, 12] - ], - [ - [12424, 12277], - [64, -13] - ], - [ - [12493, 12265], - [22, 3], - [126, 51] - ], - [ - [12645, 12247], - [38, -73] - ], - [ - [13040, 12015], - [54, 5] - ], - [ - [13132, 12013], - [44, -18] - ], - [ - [13171, 11977], - [-89, -106], - [-10, -20] - ], - [ - [13237, 11468], - [-30, 2], - [-65, 71], - [-20, 1], - [-37, -35], - [-21, 33], - [-74, 8], - [-31, -70], - [-73, -27], - [-127, -78], - [24, 48], - [-76, -36], - [-14, -16], - [-21, -73], - [4, -27], - [48, -115], - [47, -57], - [1, -17], - [-37, -88], - [-43, 0], - [-5, -20], - [11, -177], - [38, -142], - [17, -34], - [101, -121], - [65, -42], - [133, -135], - [97, -82], - [21, -39], - [57, -193], - [40, -193], - [36, -97], - [30, -48], - [183, -243], - [41, -43], - [102, -65], - [61, -19], - [272, -6], - [35, -9], - [14, -55], - [-9, -21], - [-88, -111], - [8, -51], - [28, -26], - [191, -138], - [41, -25], - [99, -41], - [88, -64], - [95, -101], - [159, -101], - [22, -46], - [76, -77], - [65, -102], - [24, -65], - [-3, -32], - [-43, -160], - [-17, -15], - [-78, 55], - [-13, 19], - [-22, 102], - [-52, 91], - [-17, 14], - [-96, 13], - [-95, 55], - [0, 39], - [-51, 25], - [-65, -55], - [-18, -29], - [-82, -186], - [3, -55], - [-37, -104], - [18, -72], - [59, -22], - [119, -103], - [14, -35], - [3, -161], - [21, -65], - [-21, -50], - [-91, -10], - [-87, -60], - [-24, -50], - [8, -136], - [-14, -35], - [-105, -138], - [-21, -34], - [-40, -106], - [-16, -15], - [-76, 0], - [-47, 53], - [-5, 95], - [60, 76], - [32, 88], - [-13, 106], - [9, 17], - [84, 36], - [14, 17], - [16, 78], - [-4, 24], - [-48, 128], - [-16, 129], - [-10, 36], - [-54, 128], - [-23, 143], - [-47, 100], - [-27, 10], - [-51, -44], - [-55, 24], - [-51, 79], - [-56, 37], - [19, 78], - [-3, 25], - [-51, 115], - [-25, 16], - [-124, -5], - [23, 36], - [-48, 73], - [-17, 6], - [-72, -14], - [-12, 8], - [-11, 69], - [-81, 161], - [-17, 17], - [-51, -14], - [-99, 42], - [-65, -23], - [-15, 6], - [-43, 65], - [-83, 40], - [-18, 17], - [-78, 110], - [-45, 36], - [-74, 141], - [-16, 21], - [-51, 23], - [-16, 20], - [-59, 118], - [-19, 25], - [-89, 61], - [-53, -10], - [-17, 106], - [-66, 94], - [-60, 36], - [-5, 63], - [-85, 44], - [-9, 21], - [13, 119], - [-6, 36], - [-60, 133], - [-11, 41], - [-18, 156], - [-9, 32], - [-57, 89], - [-57, 31], - [-20, -21], - [-24, 16], - [-162, 138], - [-39, 24], - [-116, 37], - [-27, -2], - [-81, -51], - [-82, -101], - [-67, -137], - [-19, -22], - [-104, -48], - [-65, -9], - [-24, 35], - [30, 62] - ], - [ - [5990, 9318], - [98, -13] - ], - [ - [6160, 9314], - [13, -4] - ], - [ - [5956, 7718], - [30, -76] - ], - [ - [5986, 7642], - [44, -13] - ], - [ - [6015, 7491], - [-56, -57], - [-10, -25] - ], - [ - [5936, 6911], - [-68, -148], - [-4, -45] - ], - [ - [5864, 6718], - [29, -192], - [1, -28], - [-24, 0], - [-108, -88], - [-25, -6], - [-86, 36], - [-135, 27], - [-32, -4], - [-119, -46], - [-9, 20], - [51, 188], - [7, 58], - [0, 219], - [-21, 85], - [28, 105], - [-5, 103], - [-32, 65], - [84, -23], - [-71, 44], - [-23, 0], - [-92, -36], - [-11, 3], - [11, 60], - [-17, 55], - [57, 23], - [36, 42], - [-8, 89], - [-22, -42] - ], - [ - [5328, 7475], - [-35, -73], - [-67, -19], - [-40, 28], - [-1, 83], - [38, 179], - [3, 36], - [-11, 78], - [45, 22], - [46, 84], - [82, 304], - [8, 45], - [-4, 93], - [38, 179], - [36, 219], - [3, 92], - [-24, 61], - [-8, 47], - [-32, 289], - [3, 51], - [15, 34] - ], - [ - [25102, 13980], - [-48, 110], - [-25, 38] - ], - [ - [25029, 14128], - [-43, 62] - ], - [ - [24986, 14190], - [-39, 51], - [-62, 63] - ], - [ - [24846, 14290], - [-56, -68] - ], - [ - [24783, 14211], - [0, -34] - ], - [ - [24642, 13918], - [-28, -171] - ], - [ - [24905, 12732], - [102, 0] - ], - [ - [25216, 12024], - [59, -19] - ], - [ - [25431, 11895], - [34, -49], - [-62, 14], - [1, -77], - [-20, 21], - [-58, -63], - [-75, -3], - [25, -47], - [16, -95], - [-24, -12], - [-2, 36], - [-47, 45], - [-29, -12], - [-60, -57], - [-30, -41], - [4, -31], - [-58, 18], - [-90, -76], - [-76, 80], - [24, -81], - [-92, -180], - [-7, -65], - [-19, -7], - [-42, -130], - [-34, -20], - [-6, -75], - [-102, -71], - [-22, -27], - [-3, -107], - [12, -18], - [99, -45], - [23, -55], - [45, -23], - [38, -112], - [52, -126], - [-16, -81], - [-22, -57], - [27, -14], - [25, 166], - [26, 37], - [28, -12], - [-34, -85], - [-30, -139], - [0, -115], - [28, 1], - [-30, -47], - [-11, -96], - [8, -33], - [64, -69], - [11, -24], - [17, -117], - [43, -47], - [83, -143], - [55, -114], - [34, -100], - [62, -58], - [-8, -40] - ], - [ - [25128, 9078], - [-73, -51], - [-23, -26] - ], - [ - [25032, 9001], - [-47, -107], - [-17, -14] - ], - [ - [24860, 8880], - [-70, 36] - ], - [ - [24734, 9053], - [-13, 23], - [-36, 8] - ], - [ - [24685, 9084], - [-33, 70] - ], - [ - [24593, 9236], - [-12, 11], - [-49, -26] - ], - [ - [24510, 9268], - [-55, 26], - [-68, 47] - ], - [ - [24320, 9355], - [-27, 38], - [-75, 68] - ], - [ - [24210, 9488], - [29, 118], - [-10, 28], - [-46, 17] - ], - [ - [24169, 9655], - [-59, -1] - ], - [ - [24056, 9724], - [-100, 51] - ], - [ - [23956, 9775], - [-22, 1], - [-26, -64] - ], - [ - [23908, 9712], - [-36, 49] - ], - [ - [23872, 9761], - [-10, 8] - ], - [ - [23796, 9773], - [-66, -28], - [-28, -35] - ], - [ - [23702, 9710], - [-78, -36] - ], - [ - [23572, 9757], - [-7, 25], - [-95, 63] - ], - [ - [23338, 9908], - [-56, 88] - ], - [ - [23282, 9996], - [-45, 27] - ], - [ - [23224, 10025], - [-63, -10] - ], - [ - [23092, 10056], - [-31, 6], - [-99, -26] - ], - [ - [22962, 10036], - [-125, 13] - ], - [ - [22609, 10153], - [-110, 80], - [-19, 9], - [-40, -14] - ], - [ - [22359, 10258], - [-55, -1] - ], - [ - [22304, 10257], - [-15, -10], - [-46, -84], - [-60, 82], - [-37, 38], - [-95, 141], - [-44, 55], - [-142, 159], - [-57, 47], - [-142, 51], - [-38, 30], - [-41, 79], - [-31, 11], - [-54, 77], - [0, -42], - [-23, -1], - [-87, 23], - [-42, 50], - [-21, 54], - [-1, 33], - [-20, 24], - [-121, 82], - [-60, 7], - [-43, 40], - [-2, 17], - [56, 9], - [70, 45], - [-49, 0], - [1, 52], - [-48, -27], - [16, 38], - [34, 23], - [100, -50], - [9, -16], - [-16, -43], - [58, 25], - [-25, 18], - [47, -7], - [77, 29], - [57, -31], - [2, 26], - [-22, 110], - [-11, -71], - [-10, 21], - [4, 108], - [73, 62], - [40, 145], - [17, 25], - [91, 62], - [65, -57], - [41, 40], - [-92, 74], - [-54, 79], - [-24, 11], - [-20, -19], - [-56, 66], - [-32, 106], - [11, 7], - [59, -21], - [24, 3], - [78, 53], - [21, 0], - [42, -31], - [53, 10], - [-67, 22], - [10, 58], - [25, 23], - [90, 14], - [98, 75], - [24, 11], - [55, -9], - [8, 47], - [-7, 89], - [-53, 22], - [-62, -57], - [-50, -19], - [-196, -24], - [0, 52], - [25, 38], - [-28, 26] - ], - [ - [21654, 12524], - [6, 27] - ], - [ - [22142, 12771], - [35, 7], - [5, 43] - ], - [ - [22203, 12918], - [3, 11] - ], - [ - [22248, 13011], - [0, 9] - ], - [ - [22206, 13058], - [18, 27] - ], - [ - [22214, 13168], - [-4, 17] - ], - [ - [22208, 13192], - [-6, 7] - ], - [ - [22243, 13336], - [13, 12] - ], - [ - [22261, 13377], - [-8, 2] - ], - [ - [22221, 13483], - [15, 16] - ], - [ - [22299, 13589], - [11, 32] - ], - [ - [22311, 13653], - [-28, 66] - ], - [ - [22296, 13781], - [3, 9] - ], - [ - [22121, 13840], - [-27, 41] - ], - [ - [21986, 13935], - [-15, 22] - ], - [ - [21890, 13933], - [-3, 1] - ], - [ - [21869, 13947], - [-56, 42] - ], - [ - [21791, 14019], - [-30, -2] - ], - [ - [21636, 14074], - [-2, 0] - ], - [ - [21633, 14073], - [-3, -5] - ], - [ - [21594, 13994], - [-14, -5] - ], - [ - [21550, 14027], - [-9, 14] - ], - [ - [21431, 14191], - [-5, 27] - ], - [ - [21374, 14283], - [-27, 1] - ], - [ - [21195, 14238], - [-16, -7] - ], - [ - [21064, 14184], - [-37, 36], - [-11, 1], - [-36, -10] - ], - [ - [20926, 14277], - [-19, 14], - [-78, 0], - [-16, -8] - ], - [ - [20740, 14263], - [-54, 71] - ], - [ - [20691, 14432], - [-9, 41] - ], - [ - [20640, 14651], - [-29, 7] - ], - [ - [20566, 14735], - [-19, 16], - [-53, -13] - ], - [ - [20437, 14733], - [-1, 0] - ], - [ - [20419, 14735], - [-3, 6] - ], - [ - [20399, 14765], - [-30, 6] - ], - [ - [20263, 14789], - [29, 40] - ], - [ - [20255, 14873], - [10, 54], - [-36, 81] - ], - [ - [20313, 15061], - [14, 35], - [-25, 35], - [-62, 48] - ], - [ - [20217, 15261], - [-15, 65], - [-32, 40] - ], - [ - [20017, 15404], - [-20, 27] - ], - [ - [19919, 15435], - [-22, -7], - [-68, -54] - ], - [ - [19712, 15390], - [-63, 18] - ], - [ - [19418, 15281], - [-16, 1] - ], - [ - [19402, 15282], - [-3, 47] - ], - [ - [19382, 15377], - [-24, 20] - ], - [ - [19326, 15626], - [21, 20] - ], - [ - [19620, 15908], - [22, 21] - ], - [ - [19731, 16002], - [13, 39] - ], - [ - [19743, 16061], - [-3, 3] - ], - [ - [19737, 16070], - [-71, 57] - ], - [ - [19655, 16213], - [-17, 21], - [-96, 44], - [-28, 4] - ], - [ - [19416, 16294], - [12, 37] - ], - [ - [19441, 16369], - [0, 33], - [-22, 37], - [-17, 11] - ], - [ - [19259, 16553], - [-28, 92], - [-33, 25] - ], - [ - [19206, 16748], - [-9, 25], - [-95, 67] - ], - [ - [19150, 16998], - [-14, 82] - ], - [ - [19115, 17197], - [7, 25] - ], - [ - [19118, 17321], - [-4, 5] - ], - [ - [19038, 17364], - [-15, 10] - ], - [ - [19014, 17381], - [-24, 38] - ], - [ - [18961, 17453], - [-73, 32], - [-19, -2] - ], - [ - [18758, 17457], - [-9, -11] - ], - [ - [18735, 17438], - [-24, 0], - [-47, -32] - ], - [ - [18592, 17543], - [-33, 13] - ], - [ - [18489, 17579], - [-23, -1], - [-52, -36] - ], - [ - [18311, 17623], - [-81, -19] - ], - [ - [17962, 18410], - [-12, 14] - ], - [ - [17950, 18584], - [6, 46] - ], - [ - [17956, 18630], - [11, 10] - ], - [ - [18010, 18692], - [-7, 15] - ], - [ - [18003, 18707], - [-11, 83] - ], - [ - [18169, 19543], - [6, 13] - ], - [ - [18175, 19556], - [-48, 70], - [13, 59], - [-22, 56], - [3, 37], - [44, 18], - [37, -52], - [54, 9], - [25, 82], - [101, -28], - [64, 15], - [24, 44], - [-6, 22], - [48, 34], - [65, -1], - [143, -27], - [110, -38], - [24, 1], - [24, 58], - [-91, 36], - [-36, 74], - [-40, 16], - [-92, -15], - [-124, 4], - [-23, 12], - [-68, 88], - [-33, -2], - [-46, 33], - [-48, 81], - [69, -33], - [-6, 96], - [-9, 14], - [-75, -6], - [-20, -37], - [-55, -31], - [-98, -7], - [-30, 6] - ], - [ - [18434, 20595], - [84, 52], - [34, 33] - ], - [ - [18595, 20733], - [30, 37] - ], - [ - [18714, 20847], - [14, 15] - ], - [ - [18821, 20969], - [169, 195] - ], - [ - [19138, 21289], - [4, 4] - ], - [ - [19170, 21323], - [65, 75] - ], - [ - [19242, 21409], - [4, 7] - ], - [ - [19341, 21620], - [-2, 26], - [-67, 72] - ], - [ - [18696, 22792], - [-3, 5] - ], - [ - [18731, 23173], - [15, 17] - ], - [ - [18765, 23529], - [-72, 95] - ], - [ - [18669, 24241], - [96, 86], - [21, 34] - ], - [ - [18806, 24427], - [-7, 27], - [-63, 40] - ], - [ - [18595, 24650], - [-31, 22], - [-101, 30] - ], - [ - [18282, 24914], - [1, 10] - ], - [ - [18382, 25100], - [0, 23] - ], - [ - [18635, 25403], - [9, 2] - ], - [ - [18853, 25482], - [27, 91] - ], - [ - [18894, 25588], - [3, -1] - ], - [ - [18915, 25576], - [60, -37], - [65, -4] - ], - [ - [19102, 25535], - [2, 0], - [10, 5], - [7, 9], - [8, 54], - [-3, 19], - [-23, 61], - [12, 8], - [142, -29], - [46, -34], - [125, -2], - [-28, 21], - [5, 63], - [37, 7], - [80, -18], - [-49, 73], - [53, 7], - [73, -47], - [60, -12], - [42, -32], - [124, -15], - [64, -32], - [-25, -56], - [-57, -23], - [-34, 1], - [-189, 32], - [-27, 12], - [-11, 48], - [-36, -103], - [44, 18], - [84, -10], - [23, -43], - [188, -16], - [16, -11], - [-51, -50], - [128, 39], - [75, -7], - [-6, -36], - [-30, -31], - [31, -86], - [-59, -32], - [44, -2], - [46, 57], - [-1, 48], - [25, 22], - [92, 4], - [154, -14], - [124, -39], - [182, -13], - [-32, 27], - [86, -1], - [172, -46], - [110, -43], - [122, -62], - [229, -103], - [84, -57], - [80, -23], - [88, -66], - [38, -46], - [90, -43], - [39, -44], - [49, 14], - [105, -40], - [18, -23], - [191, -108], - [34, -16], - [84, -5], - [-40, 56], - [20, 6], - [40, -23], - [32, -56], - [128, -80], - [-8, -33], - [48, -46], - [57, 31], - [58, -50], - [49, 0], - [30, -34], - [3, -26], - [-16, -82], - [44, -35], - [-6, -92], - [85, -38], - [8, -46], - [-32, -114], - [-34, -65], - [-69, -62], - [-105, -117], - [-88, -67], - [-149, -79], - [-212, -77], - [-46, -12], - [-213, -36], - [-54, -3], - [-205, 25], - [-127, 32], - [-106, 51], - [-130, 28], - [-171, 8], - [-172, 31], - [-144, 36], - [-120, 70], - [-77, 36], - [-106, -31], - [-35, 5], - [-47, 68], - [-160, 17], - [-23, 34], - [-51, 37], - [-33, -21], - [6, -30], - [-39, 10], - [-128, 76], - [-87, 75], - [-31, 57], - [-102, 32], - [-114, -10], - [59, -10], - [96, -78], - [-19, -31], - [73, -75], - [55, -12], - [12, -39], - [89, -17], - [78, -64], - [42, -21], - [-14, -11], - [-83, 27], - [-87, -25], - [99, -3], - [75, -32], - [45, 17], - [-2, -26], - [41, -15], - [-49, -11], - [32, -32], - [-14, -7], - [94, -61], - [60, 5], - [38, -40], - [95, -31], - [78, -68], - [10, -61], - [40, 0], - [26, -90], - [0, -28], - [-63, 47], - [-6, -6], - [22, -92], - [-4, -22], - [-86, -112], - [4, -73], - [39, -18], - [13, -68], - [31, -12], - [18, -42], - [-11, -32], - [48, -62], - [0, -14], - [-49, -40], - [60, -6], - [12, -19], - [-49, -29], - [41, -49], - [-35, -23], - [8, -26], - [40, -19], - [-3, -28], - [109, -46], - [22, -36], - [74, 16], - [6, 44], - [62, -32], - [72, -87], - [20, 9], - [54, -43], - [16, -59], - [20, -21], - [119, -44], - [187, -27], - [72, -50], - [17, -2], - [67, 58], - [84, 21], - [57, 49], - [-4, 69], - [-43, 46], - [-3, 20], - [26, 37], - [-26, 31], - [-30, -1], - [-9, 29], - [-66, -19], - [-102, -18], - [-59, 23], - [-25, 23], - [-108, 141], - [-71, 38], - [-37, 106], - [51, -1], - [65, 27], - [10, 16], - [2, 87], - [58, 24], - [49, -8], - [164, -60], - [28, -16], - [32, -55], - [84, -43], - [125, -11], - [6, -37], - [-32, 13], - [-74, -12], - [8, -41], - [16, 0], - [105, 41], - [-7, 21], - [163, -51], - [116, -41], - [99, -58], - [23, -3], - [95, 24], - [-31, 5], - [32, 36], - [89, -55], - [116, -18], - [10, 13], - [-29, 91], - [-14, 93], - [-24, 53], - [-61, 52], - [-138, 183], - [-8, 54], - [10, 48], - [26, 36], - [201, 111], - [33, 23], - [64, 74], - [34, 16], - [170, 41], - [42, 20], - [137, 107], - [58, 65], - [57, 74], - [44, 10], - [123, -40], - [6, -34], - [188, 23], - [47, -10], - [28, -43], - [50, -11], - [50, -36], - [-3, -23], - [-129, -83], - [18, -23], - [53, 54], - [102, 27], - [23, -3], - [67, -64], - [19, -41], - [14, 46], - [-22, 44], - [9, 88], - [46, 89], - [32, 27], - [21, 74], - [32, 23], - [-42, 77], - [38, 65], - [-2, 17], - [-54, 65], - [15, 30], - [-34, 0], - [-70, 38], - [-75, 8], - [-28, 24], - [16, 89], - [69, 137], - [39, 118], - [-11, 44], - [37, 154], - [7, 71], - [-32, 44], - [-278, 166], - [-16, 23], - [64, 9], - [161, -62], - [70, -7], - [357, -1], - [74, -7], - [84, -18], - [97, -32], - [17, -12], - [23, -56], - [22, -20], - [153, -102], - [10, -59], - [45, -73], - [4, -47], - [-51, -11], - [-372, -41], - [-44, -13], - [1, -35], - [-24, -43], - [-75, -27], - [-44, -51], - [3, -56], - [33, -36], - [119, -50], - [33, -9], - [49, -37], - [51, -99], - [34, -45], - [72, -28], - [126, 21], - [50, -8], - [11, -22], - [279, 61], - [57, -18], - [11, 35], - [36, 39], - [6, 61], - [-16, 37], - [21, 28], - [11, 68], - [50, 61], - [-35, 54], - [3, 29], - [74, 32], - [13, -29], - [64, 47], - [63, -9], - [74, 26], - [63, -14], - [16, 11], - [-41, 14], - [2, 54], - [-62, 58], - [99, -32], - [69, -1], - [45, 15], - [238, 104], - [70, 35], - [36, 29], - [84, 37], - [93, 73], - [25, 9], - [53, -16], - [189, 46], - [15, 31], - [227, 62], - [-50, -49], - [68, -3], - [24, -20], - [-62, -53], - [41, -31], - [54, 16], - [74, 39], - [27, 32], - [-71, 65], - [35, 45], - [-46, -13], - [-31, -27], - [-40, 9], - [14, 16], - [286, 130], - [58, 22], - [169, 44], - [139, 13], - [-18, -16], - [-192, -33], - [24, -21], - [31, 15], - [85, -31], - [-51, -31], - [-13, -50], - [-32, -24], - [62, -97], - [7, -57], - [-38, -28], - [-65, 32], - [-18, -3], - [29, -31], - [-82, 13], - [-32, -11], - [-38, -43], - [26, -8], - [210, -22], - [37, 3], - [52, 46], - [12, -56], - [94, 51], - [18, -3], - [63, -71], - [47, 4], - [26, 46], - [-19, 38], - [25, 38], - [141, 92], - [29, 11], - [82, 6], - [122, 47], - [75, -21], - [81, 4], - [13, -21], - [37, 27], - [72, -34], - [156, -8], - [29, 11], - [74, 82], - [23, 11], - [101, 8], - [9, 49], - [65, 27], - [31, 2], - [-10, -37], - [23, -28], - [56, -10], - [-54, 26], - [-4, 49], - [187, 60], - [36, 7], - [93, -1], - [-93, -41], - [57, -14], - [106, -79], - [4, -39], - [-61, -1], - [-52, -45], - [14, -61], - [-10, -60], - [181, -46], - [30, -2], - [49, 21], - [42, 57], - [-17, 44], - [-49, 56], - [46, 43], - [78, -15], - [103, 16], - [27, 13], - [142, 108], - [10, 42], - [-13, 67], - [-47, 40], - [-25, -40], - [-37, 21], - [0, 57], - [-15, 39], - [-141, 161], - [29, 46], - [148, 10], - [-3, 29], - [26, 12], - [4, 48], - [59, 20], - [41, -4], - [227, -48], - [65, -8], - [232, -10], - [62, -6], - [210, -32], - [3362, 132], - [-49, -9201] - ], - [ - [15869, 17102], - [17, -6] - ], - [ - [16067, 17011], - [20, -7] - ], - [ - [16088, 17004], - [53, 21] - ], - [ - [16250, 17007], - [19, -46] - ], - [ - [16176, 16603], - [-720, 41] - ], - [ - [15456, 16644], - [-187, 7], - [-38, 24], - [60, 65], - [48, 93], - [-8, 73], - [30, 44], - [123, 5], - [23, 6], - [79, 67], - [78, 106], - [33, 10], - [-139, -163], - [3, -24], - [175, -29], - [40, 19], - [4, 19], - [-13, 119], - [4, 23], - [51, 41] - ], - [ - [15824, 9461], - [-27, -57] - ], - [ - [15791, 9403], - [-59, 37] - ], - [ - [15732, 9440], - [-19, -3] - ], - [ - [15528, 9861], - [-6, 34] - ], - [ - [15834, 9786], - [117, -52] - ], - [ - [15960, 9709], - [-7, -22] - ] - ], - "transform": { - "scale": [0.0028973955394529737, 0.0017004002718827881], - "translate": [-24.496999999999996, 26.12] - }, - "objects": { - "in_features": { - "type": "GeometryCollection", - "geometries": [ - { - "arcs": [[0, 1, 2, 3, 4, 5]], - "type": "Polygon", - "properties": { "code": "IRL" } - }, - { - "arcs": [ - [ - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41 - ] - ], - "type": "Polygon", - "properties": { "code": "MKD" } - }, - { "arcs": [[42]], "type": "Polygon", "properties": { "code": "ISL" } }, - { - "arcs": [ - [ - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104 - ] - ], - "type": "Polygon", - "properties": { "code": "POL" } - }, - { - "arcs": [ - [ - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122 - ] - ], - "type": "Polygon", - "properties": { "code": "LUX" } - }, - { - "arcs": [ - [ - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168 - ] - ], - "type": "Polygon", - "properties": { "code": "ROU" } - }, - { - "arcs": [ - [[169]], - [[170]], - [[171]], - [[172]], - [[173]], - [[174]], - [[175]], - [[176]], - [[177]], - [[178]], - [[179]], - [[180]], - [[181]], - [[182]], - [[183]], - [[184]], - [[185]], - [[186]], - [[187]], - [[188]], - [[189]], - [ - [ - 190, 191, 192, 193, 194, 195, 196, 197, 198, -21, 199, -19, 200, - 201, -16, 202, -14, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "GRC" } - }, - { - "arcs": [ - [ - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, -169, 234, -167, 235, -165, 236, 237, -162, - 238, -160, 239, 240, 241 - ] - ], - "type": "Polygon", - "properties": { "code": "MDA" } - }, - { - "arcs": [ - [ - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, - 255, 256, 257, 258, 259, 260, 261, 262, 263, 264 - ] - ], - "type": "Polygon", - "properties": { "code": "SVN" } - }, - { - "arcs": [ - [ - 265, -64, 266, -62, 267, -60, 268, -58, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 291, -72, 292, -70, 293, -68, 294, -66 - ] - ], - "type": "Polygon", - "properties": { "code": "SVK" } - }, - { - "arcs": [ - [ - 295, -137, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, -37, - 306, -35, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, - 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, -143, - 343, -141, 344, -139 - ] - ], - "type": "Polygon", - "properties": { "code": "SRB" } - }, - { - "arcs": [ - [[345]], - [ - [ - 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, - 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, - 398, 399, 400, 401 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "FIN" } - }, - { - "arcs": [ - [[402]], - [[403]], - [[404]], - [[405]], - [[406]], - [[407]], - [[408]], - [[409]], - [[410]], - [[411]], - [ - [ - 412, 413, 414, 415, 416, 417, 418, 419, 420, -397, 421, -395, - 422, -393, 423, -391, 424, -389, 425, 426, 427, 428, 429, 430, - 431, 432, 433, 434, 435, 436, 437, 438, 439 - ], - [442] - ], - [[443]], - [[444]], - [[445]], - [[446]], - [[447]], - [[448]], - [[449]] - ], - "type": "MultiPolygon", - "properties": { "code": "NOR" } - }, - { - "arcs": [ - [ - 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, - 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, - 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, - 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, - 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, -124, -234, 520, -232, 521, 522, -229, - 523, -227, 524, -225, 525, -223, 526, -221, 527, -219, 528, -242, - 529, -240, -159, 530, -157, 531, -155, 532, 533, 534, -272, 535, - -270, -57, 536, -55, 537, -53, 538, -51, 539, 540, -48, 541, 542, - 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, - 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, - 569 - ], - [570] - ], - "type": "Polygon", - "properties": { "code": "UKR" } - }, - { - "arcs": [ - [[571]], - [[572]], - [[573]], - [[574]], - [[575]], - [ - [ - 576, -380, 577, -378, 578, -376, 579, -438, 580, -436, 581, - -434, 582, -432, 583, -430, 584, -428, 585, -426, -388, 586, - -386, 587, -384, 588, -382 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "SWE" } - }, - { - "arcs": [ - [ - 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, - 602, 603, 604 - ] - ], - "type": "Polygon", - "properties": { "code": "KAZ" } - }, - { - "arcs": [ - [[605]], - [[606]], - [ - [ - 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, - 620, 621 - ], - [622] - ], - [[623]], - [[624]], - [[625]], - [[626]], - [[627]] - ], - "type": "MultiPolygon", - "properties": { "code": "NLD" } - }, - { - "arcs": [[628, 629, 630, 631, 632, 633, 634, 635]], - "type": "Polygon", - "properties": { "code": "LBY" } - }, - { - "arcs": [[-629, 638, 639, 640, 641, 642, 643, 644]], - "type": "Polygon", - "properties": { "code": "EGY" } - }, - { - "arcs": [ - [645, 646, -633, 647, -631, 648, 649, 650, 651, 652, 653, 654] - ], - "type": "Polygon", - "properties": { "code": "DZA" } - }, - { "arcs": [[655]], "type": "Polygon", "properties": { "code": "SMR" } }, - { - "arcs": [[656, 657, 658, 659, 660, 661, 662, 663]], - "type": "Polygon", - "properties": { "code": "ARM" } - }, - { - "arcs": [[-635, 666, -646, 667, -654, 668]], - "type": "Polygon", - "properties": { "code": "TUN" } - }, - { - "arcs": [[669, 670]], - "type": "Polygon", - "properties": { "code": "SAH" } - }, - { - "arcs": [[671, -652, 672, -650, 673, -670, 674]], - "type": "Polygon", - "properties": { "code": "MAR" } - }, - { - "arcs": [ - [[-659, 675, 676, 677]], - [ - [ - 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, - 692, 693, 694, 695, 696, -657, 697, 698, 699 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "AZE" } - }, - { "arcs": [[700]], "type": "Polygon", "properties": { "code": "CYP" } }, - { - "arcs": [ - [ - 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, - 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726 - ] - ], - "type": "Polygon", - "properties": { "code": "JOR" } - }, - { - "arcs": [ - [ - 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, - 740, 741, 742, 743, 744, 745, 746, 747, -724, 748, 749, 750, 751, - 752, 753, 754, 755, 756, 757, 758 - ] - ], - "type": "Polygon", - "properties": { "code": "IRQ" } - }, - { - "arcs": [ - [ - 759, 760, 761, -715, 762, 763, 764, 765, 766, 767, 768, 769, 770, - 771, 772, 773, -711, 774, -709, 775, -707, 776, -642, 777, 778, - 779, 780, 781, 782, 783, 784 - ] - ], - "type": "Polygon", - "properties": { "code": "ISR" } - }, - { - "arcs": [ - [ - 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, - 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, - -699, 811, -663, 812, 813, 814, 815, 816, 817, 818, 819 - ] - ], - "type": "Polygon", - "properties": { "code": "GEO" } - }, - { - "arcs": [ - [[-640, 820, -779]], - [[821, -771, 822, -769, 823, -767, 824, -765, 825, -763, -714, 826]] - ], - "type": "MultiPolygon", - "properties": { "code": "PSX" } - }, - { - "arcs": [ - [ - 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, - -783, 840, -781, 841 - ] - ], - "type": "Polygon", - "properties": { "code": "LBN" } - }, - { - "arcs": [[842, 843, 844, -743, 845, 846, -740, 847]], - "type": "Polygon", - "properties": { "code": "KWT" } - }, - { - "arcs": [ - [ - -677, 848, -696, 849, -694, 850, -692, 851, 852, -737, 853, 854, - -734, 855, -732, 856, -730, 857, 858, 859 - ] - ], - "type": "Polygon", - "properties": { "code": "IRN" } - }, - { - "arcs": [ - [ - -613, 860, 861, 862, 863, 864, -117, 865, -115, 866, -113, 867, - 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, - -621, 881, -619, 882, -617, 883, -615, 884 - ] - ], - "type": "Polygon", - "properties": { "code": "BEL" } - }, - { - "arcs": [ - [ - -745, 885, -844, 886, 887, -705, 888, 889, -702, 890, -726, -747, - 891 - ] - ], - "type": "Polygon", - "properties": { "code": "SAU" } - }, - { - "arcs": [ - [ - 892, -751, 893, -749, -723, 894, -721, 895, 896, 897, -717, 898, - -760, 899, -784, 900, -839, 901, -837, 902, -835, 903, -833, 904, - -831, 905, 906, -828, 907, 908, 909, 910, 911, -753 - ] - ], - "type": "Polygon", - "properties": { "code": "SYR" } - }, - { - "arcs": [ - [ - 912, 913, 914, 915, 916, 917, -214, 918, -212, 919, -210, 920, - -208, 921, -206, 922, -204, 923, -12, 924, -10, 925, -42, 926, - -40, 927, 928, 929, -304, 930, -302, 931, -300, 932, -298, 933, - -136, 934, -134, 935, -132, 936, -130, 937, -128, 938, -126 - ] - ], - "type": "Polygon", - "properties": { "code": "BGR" } - }, - { - "arcs": [ - [[939, -914, 940, -191, 941, -216, 942, 943, -916]], - [ - [ - -816, 944, -814, 945, -661, 946, -859, 947, -728, 948, -758, - 949, -756, 950, 951, -911, 952, -909, 953 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "TUR" } - }, - { - "arcs": [ - [ - 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, - 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, - 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, - 993, 994, 995, 996, 997, 998, 999, -555, 1000, -553, 1001, -551, - 1002, -549, 1003, -547, 1004, -545, 1005, 1006, -542, -47, 1007, - -45, 1008, -105, 1009, -103, 1010, 1011, 1012, 1013, 1014, 1015, - 1016, 1017, 1018, 1019 - ] - ], - "type": "Polygon", - "properties": { "code": "BLR" } - }, - { - "arcs": [[1020, 1021]], - "type": "Polygon", - "properties": { "code": "AND" } - }, - { - "arcs": [ - [ - [ - 1022, -81, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, - 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, - 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, - 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, - 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, - 1072, 1073, 1074, 1075, -108, 1076, -106, 1077, -122, 1078, - -120, 1079, -118, -865, 1080, -863, 1081, -861, -612, 1082, - -610, 1083, -608, 1084, 1085, 1086, 1087, 1088, 1089, 1090, -94, - 1091, -92, 1092, -90, 1093, 1094, -87, 1095, -85, 1096, -83 - ] - ], - [[1097, 1098]], - [[1099]], - [[1100]] - ], - "type": "MultiPolygon", - "properties": { "code": "DEU" } - }, - { - "arcs": [ - [ - 1101, -319, 1102, -317, 1103, -315, 1104, 1105, 1106, 1107, 1108, - 1109, 1110, 1111, 1112, 1113, 1114, 1115, -321 - ] - ], - "type": "Polygon", - "properties": { "code": "MNE" } - }, - { - "arcs": [ - [ - -28, 1116, -26, 1117, -24, 1118, -22, -199, 1119, -197, 1120, - -195, 1121, -193, 1122, -1111, 1123, -1109, 1124, -1107, 1125, - 1126 - ] - ], - "type": "Polygon", - "properties": { "code": "ALB" } - }, - { - "arcs": [ - [ - 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, - 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, - 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, - 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, - 1171, 1172, 1173, 1174, 1175, 1176, 1177, -1063, 1178, -1061, - 1179, -1059, 1180, 1181, 1182, 1183, 1184, 1185 - ] - ], - "type": "Polygon", - "properties": { "code": "CHE" } - }, - { - "arcs": [[1186, -1182]], - "type": "Polygon", - "properties": { "code": "LIE" } - }, - { - "arcs": [ - [[1187]], - [ - [ - 1188, -869, -111, 1189, -109, -1076, 1190, -1074, 1191, -1072, - 1192, -1070, 1193, -1068, 1194, -1066, 1195, -1064, -1178, 1196, - -1176, 1197, 1198, 1199, -1172, 1200, -1170, 1201, -1168, 1202, - -1166, 1203, -1164, 1204, -1162, 1205, -1160, 1206, -1158, 1207, - -1156, 1208, -1154, 1209, -1152, 1210, -1150, 1211, 1212, 1213, - 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, - 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, -1021, - 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, -880, 1241, - -878, 1242, -876, 1243, -874, 1244, 1245, -871 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "FRA" } - }, - { - "arcs": [ - [[1246]], - [[1247]], - [[1248]], - [ - [ - 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, - 1259, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "EST" } - }, - { - "arcs": [[[1270]], [[1271]]], - "type": "MultiPolygon", - "properties": { "code": "MLT" } - }, - { - "arcs": [ - [[1272]], - [[1273]], - [[1274]], - [[1275]], - [[1276]], - [[1277]], - [[1278]], - [[1279, 1280, -1086, 1281]] - ], - "type": "MultiPolygon", - "properties": { "code": "DNK" } - }, - { - "arcs": [ - [ - 1282, -77, 1283, -75, 1284, -73, -292, 1285, -290, 1286, -288, - 1287, -286, 1288, -284, 1289, 1290, 1291, 1292, 1293, 1294, 1295, - 1296, 1297, 1298, 1299, -1046, 1300, -1044, 1301, -1042, 1302, - -1040, 1303, -1038, 1304, -1036, 1305, -1034, 1306, -1032, 1307, - -1030, 1308, -1028, 1309, -1026, 1310, -1024, 1311, -79 - ] - ], - "type": "Polygon", - "properties": { "code": "CZE" } - }, - { - "arcs": [ - [ - 1312, 1313, 1314, -261, 1315, -259, 1316, -257, 1317, 1318, 1319, - 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, -1130, 1329, - -1128, 1330, -1185, 1331, -1183, -1187, -1181, -1058, 1332, -1056, - 1333, -1054, 1334, -1052, 1335, -1050, 1336, -1048, 1337, 1338, - -1299, 1339, -1297, 1340, -1295, 1341, -1293, 1342, -1291, 1343, - -282, 1344, 1345, 1346 - ] - ], - "type": "Polygon", - "properties": { "code": "AUT" } - }, - { - "arcs": [ - [ - 1347, 1348, -330, 1349, -328, 1350, -326, 1351, -324, 1352, -322, - -1116, 1353, -1114, 1354, 1355, 1356, 1357, 1358 - ] - ], - "type": "Polygon", - "properties": { "code": "BIH" } - }, - { - "arcs": [[1359]], - "type": "Polygon", - "properties": { "code": "IMN" } - }, - { - "arcs": [ - [[1360]], - [[1361]], - [[1362]], - [[1363]], - [ - [ - 1364, -1236, 1365, -1234, -1022, -1233, 1366, -1231, 1367, 1368, - 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1376, 1377, 1378, - 1379, -1240, 1380, -1238 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "ESP" } - }, - { - "arcs": [ - [ - -535, 1381, -533, -154, 1382, -152, 1383, -150, 1384, -148, 1385, - -146, 1386, -144, -343, 1387, -341, 1388, -339, 1389, 1390, 1391, - 1392, 1393, 1394, 1395, -264, 1396, -262, 1397, -1314, 1398, - -1347, 1399, -1345, -281, 1400, -279, 1401, -277, 1402, -275, - 1403, -273 - ] - ], - "type": "Polygon", - "properties": { "code": "HUN" } - }, - { - "arcs": [ - [[1404]], - [[1405, 1406]], - [[1407, 1408]], - [[1409]], - [[1410, 1411, -2]], - [[1412]], - [[1413]], - [[1414]] - ], - "type": "MultiPolygon", - "properties": { "code": "GBR" } - }, - { - "arcs": [ - [[-1355, -1113, 1415]], - [[1416]], - [[1417]], - [[1418]], - [[1419]], - [[1420]], - [[1421]], - [ - [ - 1422, -1391, 1423, -337, 1424, -335, 1425, -333, 1426, -331, - -1349, 1427, -1359, 1428, -1357, 1429, -252, 1430, -250, 1431, - -248, 1432, -246, 1433, 1434, -243, 1435, -1395, 1436, -1393 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "HRV" } - }, - { - "arcs": [ - [[1437]], - [ - [ - 1438, -1013, 1439, -1011, -102, 1440, -100, 1441, -98, 1442, - 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451, 1452, - 1453, 1454, -1015 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "LTU" } - }, - { - "arcs": [ - [ - -1258, 1455, 1456, 1457, -1019, 1458, -1017, 1459, -1455, 1460, - -1453, 1461, -1269, 1462, -1267, 1463, -1265, 1464, 1465, -1262, - 1466, -1260, 1467 - ] - ], - "type": "Polygon", - "properties": { "code": "LVA" } - }, - { - "arcs": [ - [[1468]], - [[1469]], - [ - [ - -1229, 1470, -1227, 1471, -1225, 1472, -1223, 1473, -1221, 1474, - -1219, 1475, -1217, 1476, -1215, 1477, 1478, -1212, -1149, 1479, - -1147, 1480, -1145, 1481, -1143, 1482, -1141, 1483, -1139, 1484, - -1137, 1485, -1135, 1486, -1133, 1487, -1131, -1329, 1488, - -1327, 1489, -1325, 1490, -1323, 1491, -1321, 1492, -1319, 1493, - -256, 1494, -254, 1495 - ], - [-656] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "ITA" } - }, - { - "arcs": [ - [ - -1379, 1496, -1377, 1497, -1375, 1498, 1499, -1372, 1500, -1370, - 1501, 1502, 1503 - ] - ], - "type": "Polygon", - "properties": { "code": "PRT" } - }, - { - "arcs": [ - [ - [ - 1504, 1505, 1506, -600, 1507, -598, 1508, -596, 1509, -594, - 1510, -592, 1511, -590, 1512, -690, 1513, 1514, -687, 1515, - -685, 1516, 1517, -682, 1518, -680, 1519, -810, 1520, -808, - 1521, -806, 1522, -804, 1523, 1524, 1525, 1526, -799, 1527, - 1528, -796, 1529, -794, 1530, 1531, -791, 1532, -789, 1533, - 1534, -786, 1535, -819, 1536, 1537, -519, 1538, -517, 1539, - -515, 1540, -513, 1541, -511, 1542, -509, 1543, -507, 1544, - -505, 1545, -503, 1546, -501, 1547, -499, 1548, -497, 1549, - -495, 1550, -493, 1551, -491, 1552, -489, 1553, -487, 1554, - -485, 1555, -483, 1556, -481, 1557, -479, 1558, -477, 1559, - -475, 1560, -473, 1561, -471, 1562, -469, 1563, -467, 1564, - -465, 1565, -463, 1566, -461, 1567, -459, 1568, -457, 1569, - -455, 1570, -453, 1571, -451, 1572, -569, 1573, -567, 1574, - -565, 1575, -563, 1576, -561, 1577, -559, 1578, -557, 1579, - 1580, -998, 1581, -996, 1582, -994, 1583, -992, 1584, -990, - 1585, -988, 1586, -986, 1587, -984, 1588, -982, 1589, -980, - 1590, -978, 1591, -976, 1592, -974, 1593, -972, 1594, -970, - 1595, -968, 1596, -966, 1597, -964, 1598, -962, 1599, -960, - 1600, -958, 1601, -956, 1602, -1020, -1458, 1603, -1456, -1257, - 1604, 1605, -1254, 1606, 1607, -1251, 1608, 1609, -374, 1610, - -372, 1611, -370, 1612, -368, 1613, -366, 1614, -364, 1615, - -362, 1616, -360, 1617, -358, 1618, -356, 1619, -354, 1620, - -352, 1621, -350, 1622, -348, 1623, -402, 1624, -400, 1625, - -398, -421, 1626, -419, 1627, -417, 1628, -415, 1629, -413, - 1630, -604 - ] - ], - [ - [ - -1451, 1631, -1449, 1632, -1447, 1633, -1445, 1634, -1443, -97, - 1635, 1636 - ] - ] - ], - "type": "MultiPolygon", - "properties": { "code": "RUS" } - }, - { - "arcs": [ - [ - 1637, -32, 1638, 1639, -29, -1127, -1105, -314, 1640, -312, 1641, - -310, 1642, -308, -34 - ] - ], - "type": "Polygon", - "properties": { "code": "KOS" } - } - ] - } - } -} diff --git a/packages/app/src/types/cms.d.ts b/packages/app/src/types/cms.d.ts index 00a41a8f97..64a8a09a91 100644 --- a/packages/app/src/types/cms.d.ts +++ b/packages/app/src/types/cms.d.ts @@ -3,10 +3,7 @@ import { ArticleSummary } from '~/components/article-teaser'; import { CategoriesTypes } from '~/domain/topical/common/categories'; export type PageIdentifier = - | 'in_positiveTestsPage' | 'hospitalPage' - | 'in_positiveTestsPage' - | 'in_variantsPage' | 'behaviorPage' | 'situationsPage' | 'reproductionPage' @@ -19,7 +16,6 @@ export type PageIdentifier = | 'sewerPage' | 'intensiveCarePage' | 'vaccinationsPage' - | 'in_variantsPage' | 'nursingHomePage' | 'deceasedPage'; @@ -255,7 +251,3 @@ export type LinkProps = { export type VariantsPageQuery = { pageLinks: [LinkProps]; }; - -export type InPositiveTestsQuery = { - pageLinks?: LinkProps[]; -}; diff --git a/packages/app/src/utils/__tests__/use-reverse-router.spec.tsx b/packages/app/src/utils/__tests__/use-reverse-router.spec.tsx index 6e0ee90ab9..5c4034f04a 100644 --- a/packages/app/src/utils/__tests__/use-reverse-router.spec.tsx +++ b/packages/app/src/utils/__tests__/use-reverse-router.spec.tsx @@ -20,19 +20,16 @@ const gmCode = 'GM001'; UseReverseRouter.before((context) => { context.cleanupJsDom = injectJsDom(); - (window as any).matchMedia = () => {}; sinon.stub(window, 'matchMedia').callsFake((mq: string) => { switch (mq) { case theme.mediaQueries.md: { return { matches: largeScreen, - addListener: (callback: any) => {}, } as MediaQueryList; } default: return { matches: false, - addListener: (callback: any) => {}, } as MediaQueryList; } }); @@ -48,8 +45,6 @@ UseReverseRouter.after.each(() => { cleanupHooks(); }); -UseReverseRouter.before.each((context) => {}); - const TestContainer = () => { return ( @@ -68,43 +63,38 @@ const TestBed = () => {
    {router.nl.index()}
    {router.vr.index(vrCode)}
    {router.gm.index(gmCode)}
    -
    {router.in.index()}
    ); }; UseReverseRouter( 'indexes should link to the actual index on small screens', - (context) => { + () => { largeScreen = false; const result = render(); const nlDiv = result.getByTestId('nl'); const vrDiv = result.getByTestId('vr'); const gmDiv = result.getByTestId('gm'); - const inDiv = result.getByTestId('in'); assert.equal(nlDiv.textContent?.endsWith('/landelijk'), true); assert.equal(vrDiv.textContent?.endsWith(vrCode), true); assert.equal(gmDiv.textContent?.endsWith(gmCode), true); - assert.equal(inDiv.textContent?.endsWith('/internationaal'), true); } ); -UseReverseRouter("indexes should 'redirect' to child pages", (context) => { +UseReverseRouter("indexes should 'redirect' to child pages", () => { largeScreen = true; const result = render(); const nlDiv = result.getByTestId('nl'); const vrDiv = result.getByTestId('vr'); const gmDiv = result.getByTestId('gm'); - const inDiv = result.getByTestId('in'); assert.equal(nlDiv.textContent?.endsWith('/vaccinaties'), true); assert.equal(vrDiv.textContent?.endsWith('/vaccinaties'), true); assert.equal(gmDiv.textContent?.endsWith('/vaccinaties'), true); - assert.equal(inDiv.textContent?.endsWith('/positief-geteste-mensen'), true); }); -UseReverseRouter('VR routes should have the VR code in them', (context) => { +UseReverseRouter('VR routes should have the VR code in them', () => { const { result } = renderHook(() => useReverseRouter()); const keys = Object.keys(result.current.vr); @@ -117,7 +107,7 @@ UseReverseRouter('VR routes should have the VR code in them', (context) => { assert.equal(route.indexOf(vrCode) > -1, true); }); -UseReverseRouter('GM routes should have the GM code in them', (context) => { +UseReverseRouter('GM routes should have the GM code in them', () => { const { result } = renderHook(() => useReverseRouter()); const keys = Object.keys(result.current.gm); diff --git a/packages/app/src/utils/get-current-page-scope.ts b/packages/app/src/utils/get-current-page-scope.ts index 204f52ed6b..0ffff5f9d1 100644 --- a/packages/app/src/utils/get-current-page-scope.ts +++ b/packages/app/src/utils/get-current-page-scope.ts @@ -7,9 +7,7 @@ import { NextRouter } from 'next/router'; export function getCurrentPageScope( router: NextRouter ): DataScopeKey | undefined { - return router.pathname.startsWith('/internationaal') - ? 'in' - : router.pathname.startsWith('/landelijk') + return router.pathname.startsWith('/landelijk') ? 'nl' : router.pathname.startsWith('/veiligheidsregio') ? 'vr' diff --git a/packages/cli/src/schema/custom-validations/choropleth.ts b/packages/cli/src/schema/custom-validations/choropleth.ts index 0127215f81..1412c8baed 100644 --- a/packages/cli/src/schema/custom-validations/choropleth.ts +++ b/packages/cli/src/schema/custom-validations/choropleth.ts @@ -34,7 +34,7 @@ export function createChoroplethValidation( } /** - * This validation function receives a data file (either VR, GM or IN) and a choropleth data file (GM_COLLECTION, VR_COLLECTION or IN_COLLECTION). + * This validation function receives a data file (either VR, GM or IN) and a choropleth data file (GM_COLLECTION, VR_COLLECTION). * It extracts all of the data points that both files have in common, then it * compares the last_value property from each of these data point * in the data file with the corresponding value in the choropleth file using the codeProperty to find the correct value. @@ -47,7 +47,7 @@ export function createChoroplethValidation( * */ export const validateChoroplethValues = ( - collectionJsonFilename: string, // GM_COLLECTION.json|VR_COLLECTION.json|IN_COLLECTION.json + collectionJsonFilename: string, // GM_COLLECTION.json|VR_COLLECTION.json collectionJson: JSONObject, // The contents of the aforementioned json file codeProperty: string, //the gmcode, vrcode, country_code property name input: JSONObject, // contents of a GM***.json or VR***.json or IN_***.json file diff --git a/packages/cli/src/schema/schema-info.ts b/packages/cli/src/schema/schema-info.ts index 1ebf060c3c..61bbb3932d 100644 --- a/packages/cli/src/schema/schema-info.ts +++ b/packages/cli/src/schema/schema-info.ts @@ -26,24 +26,6 @@ export function getSchemaInfo( const fileList = fs.readdirSync(jsonDirectory); return { - in: { - files: getFileNames(fileList, /^IN_[A-Z]{3}.json$/), - basePath: jsonDirectory, - customValidations: [ - createChoroplethValidation( - path.join(defaultJsonDirectory, 'IN_COLLECTION.json'), - 'country_code' - ), - validateMovingAverages, - ], - }, - in_collection: { - files: [ - // @TODO enable when file is available - /* 'IN_COLLECTION.json' */ - ], - basePath: jsonDirectory, - }, nl: { files: ['NL.json'], basePath: jsonDirectory, diff --git a/packages/cms/src/components/portable-text/shared/area-select-input.tsx b/packages/cms/src/components/portable-text/shared/area-select-input.tsx index a423e3ec2d..91a26d4869 100644 --- a/packages/cms/src/components/portable-text/shared/area-select-input.tsx +++ b/packages/cms/src/components/portable-text/shared/area-select-input.tsx @@ -13,7 +13,6 @@ const createPatchFrom = (value: string) => { }; export const areaTitles = { - in: 'Internationaal', nl: 'Nationaal', vr: 'Veiligheidsregio', gm: 'Gemeente', diff --git a/packages/cms/src/components/portable-text/shared/collection-metric-property-select-input.tsx b/packages/cms/src/components/portable-text/shared/collection-metric-property-select-input.tsx index 21901a404a..1c09574de1 100644 --- a/packages/cms/src/components/portable-text/shared/collection-metric-property-select-input.tsx +++ b/packages/cms/src/components/portable-text/shared/collection-metric-property-select-input.tsx @@ -10,7 +10,7 @@ const createPatchFrom = (value: string) => { return PatchEvent.from(value === '' ? unset() : set(value)); }; -function getDropdownValues(map: 'in' | 'gm' | 'vr', metricName: string) { +function getDropdownValues(map: 'gm' | 'vr', metricName: string) { const collection = dataStructure[`${map}_collection`]; return (collection as any)?.[metricName].map((x: string) => ({ diff --git a/packages/cms/src/components/portable-text/shared/collection-metric-select-input.tsx b/packages/cms/src/components/portable-text/shared/collection-metric-select-input.tsx index 4e0efc9bb5..0558bf8a25 100644 --- a/packages/cms/src/components/portable-text/shared/collection-metric-select-input.tsx +++ b/packages/cms/src/components/portable-text/shared/collection-metric-select-input.tsx @@ -12,7 +12,7 @@ const createPatchFrom = (value: string) => { return PatchEvent.from(value === '' ? unset() : set(value)); }; -function getDropdownValues(map: 'in' | 'gm' | 'vr') { +function getDropdownValues(map: 'gm' | 'vr') { const collection = dataStructure[`${map}_collection`]; return Object.keys(collection).map((x) => ({ value: x, label: x })); diff --git a/packages/cms/src/data/data-structure.ts b/packages/cms/src/data/data-structure.ts index c0c6d6e66a..f9a62ac426 100644 --- a/packages/cms/src/data/data-structure.ts +++ b/packages/cms/src/data/data-structure.ts @@ -2,7 +2,7 @@ * DO NOT MANUALLY CHANGE THE CONTENTS OF THIS FILE! * This file is generated based on the JSON schema's by yarn generate-data-structures in the cli package. */ - export const dataStructure = { +export const dataStructure = { gm: { deceased_rivm: ["covid_daily", "covid_daily_moving_average", "covid_total"], hospital_nice: [ @@ -27,22 +27,32 @@ vaccine_coverage_per_age_group: [ "age_group_range", "fully_vaccinated_percentage", - "has_one_shot_percentage", "booster_shot_percentage", + "has_one_shot_percentage", "birthyear_range", "fully_vaccinated_percentage_label", - "has_one_shot_percentage_label", "booster_shot_percentage_label", + "has_one_shot_percentage_label", + ], + vaccine_coverage_per_age_group_archived: [ + "age_group_range", + "fully_vaccinated_percentage", + "has_one_shot_percentage", + "birthyear_range", + "fully_vaccinated_percentage_label", + "has_one_shot_percentage_label", ], booster_coverage: ["age_group", "percentage", "percentage_label"], }, gm_collection: { hospital_nice: [ "admissions_on_date_of_admission", + "admissions_on_date_of_admission_per_100000", "admissions_on_date_of_reporting", ], hospital_nice_choropleth: [ "admissions_on_date_of_admission", + "admissions_on_date_of_admission_per_100000", "admissions_on_date_of_reporting", ], tested_overall: ["infected_per_100k", "infected"], @@ -58,15 +68,9 @@ "booster_shot_percentage_label", ], }, - in: { - tested_overall: ["infected", "infected_per_100k_average"], - variants: ["name", "values", "last_value"], - }, - in_collection: { tested_overall: ["infected", "infected_per_100k_average"] }, nl: { booster_shot_administered: [ "administered_total", - "ggd_administered_last_7_days", "ggd_administered_total", "others_administered_total", ], @@ -304,11 +308,22 @@ "age_group_percentage", "age_group_total", "fully_vaccinated", - "has_one_shot", "booster_shot", + "has_one_shot", "fully_vaccinated_percentage", - "has_one_shot_percentage", "booster_shot_percentage", + "has_one_shot_percentage", + "date_of_report_unix", + "birthyear_range", + ], + vaccine_coverage_per_age_group_archived: [ + "age_group_range", + "age_group_percentage", + "age_group_total", + "fully_vaccinated", + "has_one_shot", + "fully_vaccinated_percentage", + "has_one_shot_percentage", "date_of_report_unix", "birthyear_range", ], @@ -456,22 +471,32 @@ vaccine_coverage_per_age_group: [ "age_group_range", "fully_vaccinated_percentage", - "has_one_shot_percentage", "booster_shot_percentage", + "has_one_shot_percentage", "birthyear_range", "fully_vaccinated_percentage_label", - "has_one_shot_percentage_label", "booster_shot_percentage_label", + "has_one_shot_percentage_label", + ], + vaccine_coverage_per_age_group_archived: [ + "age_group_range", + "fully_vaccinated_percentage", + "has_one_shot_percentage", + "birthyear_range", + "fully_vaccinated_percentage_label", + "has_one_shot_percentage_label", ], booster_coverage: ["age_group", "percentage", "percentage_label"], }, vr_collection: { hospital_nice: [ "admissions_on_date_of_admission", + "admissions_on_date_of_admission_per_100000", "admissions_on_date_of_reporting", ], hospital_nice_choropleth: [ "admissions_on_date_of_admission", + "admissions_on_date_of_admission_per_100000", "admissions_on_date_of_reporting", ], tested_overall: ["infected_per_100k", "infected"], diff --git a/packages/cms/src/elements/NOTES.md b/packages/cms/src/elements/NOTES.md index b3f326b724..dbaf64662d 100644 --- a/packages/cms/src/elements/NOTES.md +++ b/packages/cms/src/elements/NOTES.md @@ -38,7 +38,6 @@ The scopes would be: - nl: national - vr: safety-region - gm: municipality -- in: international This combination of properties should be sufficient to generate a globally unique id for each instance of data visualization on the dashboard. It makes a diff --git a/packages/cms/src/elements/add.ts b/packages/cms/src/elements/add.ts index fdd5708865..0fb338cae4 100644 --- a/packages/cms/src/elements/add.ts +++ b/packages/cms/src/elements/add.ts @@ -44,7 +44,6 @@ async function promptForElement(): Promise { { title: 'Municipal', value: 'gm' }, { title: 'Safety region', value: 'vr' }, { title: 'National', value: 'nl' }, - { title: 'International', value: 'in' }, ]; const scopeResponse = (await prompts({ diff --git a/packages/cms/src/migrations/sprint35/page-identifiers.ts b/packages/cms/src/migrations/sprint35/page-identifiers.ts index 7fbaeb148c..6500a39b8b 100644 --- a/packages/cms/src/migrations/sprint35/page-identifiers.ts +++ b/packages/cms/src/migrations/sprint35/page-identifiers.ts @@ -50,27 +50,6 @@ const pageInfo = [ ], links: [{ title: 'Ziekenhuisopnames links', kind: 'hospitalPageLinks' }], }, - /*{ - type: 'in_positiveTestsPage', - title: 'Positieve testen internationaal', - articles: [ - { - title: 'Positieve testen artikelen', - kind: 'in_positiveTestsPageArticles', - }, - ], - links: [ - { title: 'Positieve testen links', kind: 'in_positiveTestsPageLinks' }, - ], - },*/ - { - type: 'in_variantsPage', - title: 'Varianten internationaal', - articles: [ - { title: 'Varianten artikelen', kind: 'in_variantsPageArticles' }, - ], - links: [{ title: 'Varianten links', kind: 'in_variantsPageLinks' }], - }, { type: 'infectiousPeoplePage', title: 'Besmettelijke mensen', diff --git a/packages/cms/src/migrations/sprint43/index.ts b/packages/cms/src/migrations/sprint43/index.ts index c371c4d0b1..68654f671e 100644 --- a/packages/cms/src/migrations/sprint43/index.ts +++ b/packages/cms/src/migrations/sprint43/index.ts @@ -19,8 +19,6 @@ const types = [ '"disabilityCarePage"', '"elderlyAtHomePage"', '"escalationLevelPage"', - '"internationalPage"', - '"in_variantsPage"', '"nursingHomePage"', '"sewerPage"', '"TopicalPage"', diff --git a/packages/cms/src/schemas/documents/choropleth-configuration.ts b/packages/cms/src/schemas/documents/choropleth-configuration.ts index d32f0bc433..2ac7e81fcd 100644 --- a/packages/cms/src/schemas/documents/choropleth-configuration.ts +++ b/packages/cms/src/schemas/documents/choropleth-configuration.ts @@ -55,7 +55,6 @@ export const choroplethConfiguration = { list: [ { title: 'Veiligheidsregio', value: 'vr' }, { title: 'Gemeente', value: 'gm' }, - { title: 'Internationaal', value: 'in' }, ], layout: 'dropdown', }, diff --git a/packages/common/src/data-sorting.ts b/packages/common/src/data-sorting.ts index fb828bec5d..8ae06abd36 100644 --- a/packages/common/src/data-sorting.ts +++ b/packages/common/src/data-sorting.ts @@ -1,7 +1,6 @@ import { isDefined } from 'ts-is-present'; import { GmSewerPerInstallationValue, - InVariantsVariantValue, NlVariantsVariantValue, VrSewerPerInstallationValue, } from './types'; @@ -123,9 +122,7 @@ export function sortTimeSeriesInDataInPlace( return x; } - x.values = sortTimeSeriesValues(x.values) as - | NlVariantsVariantValue[] - | InVariantsVariantValue[]; + x.values = sortTimeSeriesValues(x.values) as NlVariantsVariantValue[]; if (setDatesToMiddleOfDay) { x.values = x.values.map(setValueDatesToMiddleOfDay); @@ -209,7 +206,7 @@ export interface SewerPerInstallationData { } export interface VariantsData { - values: (TimeSeriesMetric & { + values: (TimeSeriesMetric & { name: string; })[]; } diff --git a/packages/common/src/data/reverse-router.ts b/packages/common/src/data/reverse-router.ts index 6671320c08..225e153716 100644 --- a/packages/common/src/data/reverse-router.ts +++ b/packages/common/src/data/reverse-router.ts @@ -20,13 +20,6 @@ export function getReverseRouter(isMobile: boolean) { contact: () => '/contact', }, - in: { - index: () => - isMobile ? `/internationaal` : reverseRouter.in.positiefGetesteMensen(), - positiefGetesteMensen: () => `/internationaal/positief-geteste-mensen`, - varianten: () => `/internationaal/varianten`, - }, - nl: { index: () => (isMobile ? `/landelijk` : reverseRouter.nl.vaccinaties()), vaccinaties: () => `/landelijk/vaccinaties`, diff --git a/packages/common/src/types/data-utils.ts b/packages/common/src/types/data-utils.ts index eac4b92db4..412c827aaf 100644 --- a/packages/common/src/types/data-utils.ts +++ b/packages/common/src/types/data-utils.ts @@ -1,4 +1,4 @@ -import { Gm, In, Nl, Vr } from '.'; +import { Gm, Nl, Vr } from '.'; /** * All possible datascopes. Can be used to access the types of a scope based on @@ -6,7 +6,6 @@ import { Gm, In, Nl, Vr } from '.'; */ export type ScopedData = { gm: Gm; - in: In; nl: Nl; vr: Vr; }; @@ -20,7 +19,7 @@ export type MetricKeys = keyof Omit< 'last_generated' | 'proto_name' | 'name' | 'code' >; -export type MetricName = MetricKeys; +export type MetricName = MetricKeys; type ValuesMetric = { values: T[]; diff --git a/packages/common/src/types/data.ts b/packages/common/src/types/data.ts index 9b36a96722..ca0423ad73 100644 --- a/packages/common/src/types/data.ts +++ b/packages/common/src/types/data.ts @@ -195,75 +195,6 @@ export interface GmCollectionVaccineCoveragePerAgeGroup { date_of_insertion_unix: number; } -export type InCode = string; - -export interface In { - last_generated: string; - proto_name: InCode; - name: InCode; - code: string; - named_difference: InNamedDifference; - tested_overall: InTestedOverall; - variants?: InVariants; -} -export interface InNamedDifference { - variants__percentage?: OptionalNamedDifferenceDecimal[]; -} -export interface OptionalNamedDifferenceDecimal { - name: string; - old_value: number | null; - difference: number | null; - old_date_unix: number; - new_date_unix: number; -} -export interface InTestedOverall { - values: InTestedOverallValue[]; - last_value: InTestedOverallValue; -} -export interface InTestedOverallValue { - infected: number; - infected_per_100k_average: number; - date_start_unix: number; - date_end_unix: number; - date_of_insertion_unix: number; -} -export interface InVariants { - values?: InVariantsVariant[]; -} -export interface InVariantsVariant { - name: string; - values: InVariantsVariantValue[]; - last_value: InVariantsVariantValue; -} -export interface InVariantsVariantValue { - percentage: number | null; - occurrence: number | null; - is_variant_of_concern: boolean; - sample_size: number; - is_reliable: boolean; - date_start_unix: number; - date_end_unix: number; - date_of_insertion_unix: number; -} - -export type InCollectionId = "IN_COLLECTION"; - -export interface InCollection { - last_generated: string; - proto_name: InCollectionId; - name: InCollectionId; - code: InCollectionId; - tested_overall: InCollectionTestedOverall[]; -} -export interface InCollectionTestedOverall { - country_code: string; - infected: number; - infected_per_100k_average: number; - date_start_unix: number; - date_end_unix: number; - date_of_insertion_unix: number; -} - export type NlId = "NL"; export interface Nl { diff --git a/packages/common/src/types/feature-flags.ts b/packages/common/src/types/feature-flags.ts index 9023cdb329..8e3d1c984d 100644 --- a/packages/common/src/types/feature-flags.ts +++ b/packages/common/src/types/feature-flags.ts @@ -39,8 +39,4 @@ export type VerboseFeature = { metricProperties?: string[]; } & SimpleFeature; -export type JsonDataScope = - | DataScopeKey - | 'in_collection' - | 'vr_collection' - | 'gm_collection'; +export type JsonDataScope = DataScopeKey | 'vr_collection' | 'gm_collection'; diff --git a/packages/common/src/types/inline-charts.ts b/packages/common/src/types/inline-charts.ts index f809449e53..192d79c072 100644 --- a/packages/common/src/types/inline-charts.ts +++ b/packages/common/src/types/inline-charts.ts @@ -8,7 +8,6 @@ import { } from '.'; export const areaTitles = { - in: 'Internationaal', nl: 'Nationaal', vr: 'Veiligheidsregio', gm: 'Gemeente', @@ -28,7 +27,7 @@ export type ChoroplethConfiguration< M extends MetricKeys > = { metricProperty: MetricProperty>; - map: 'in' | 'vr' | 'gm'; + map: 'vr' | 'gm'; accessibilityKey: string; sourceKey: string; noDataFillColor?: string; From 0d7da2242184100ffebf1c86409ed212a1e0282d Mon Sep 17 00:00:00 2001 From: L R <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Mon, 18 Jul 2022 14:40:08 +0200 Subject: [PATCH 05/12] feature/COR-936-vaccination-page-table-schema (#4323) * feat: added vaccine_campaigns JSON schema; * feat: removed entry from vaccine_campaigns schema; added vaccine_planned JSON schema; * feat: renamed vaccine_planned to doses for naming consistency; * change vaccine_campaign_index to vaccine_campaign_order Co-authored-by: VWSCoronaDashboard26 Co-authored-by: VWSCoronaDashboard21 --- packages/app/schema/nl/__index.json | 8 +++ packages/app/schema/nl/vaccine_campaigns.json | 64 +++++++++++++++++++ packages/app/schema/nl/vaccine_planned.json | 30 +++++++++ 3 files changed, 102 insertions(+) create mode 100644 packages/app/schema/nl/vaccine_campaigns.json create mode 100644 packages/app/schema/nl/vaccine_planned.json diff --git a/packages/app/schema/nl/__index.json b/packages/app/schema/nl/__index.json index 48a15a91c1..7867508d9b 100644 --- a/packages/app/schema/nl/__index.json +++ b/packages/app/schema/nl/__index.json @@ -37,6 +37,8 @@ "tested_ggd_archived", "tested_overall", "tested_per_age_group", + "vaccine_campaigns", + "vaccine_planned", "vaccine_vaccinated_or_support", "vaccine_delivery_estimate", "vaccine_administered", @@ -195,6 +197,12 @@ "vaccine_administered_planned": { "$ref": "vaccine_administered_planned.json" }, + "vaccine_campaigns": { + "$ref": "vaccine_campaigns.json" + }, + "vaccine_planned": { + "$ref": "vaccine_planned.json" + }, "vaccine_coverage_per_age_group": { "$ref": "vaccine_coverage_per_age_group.json" }, diff --git a/packages/app/schema/nl/vaccine_campaigns.json b/packages/app/schema/nl/vaccine_campaigns.json new file mode 100644 index 0000000000..58c6340ac0 --- /dev/null +++ b/packages/app/schema/nl/vaccine_campaigns.json @@ -0,0 +1,64 @@ +{ + "definitions": { + "vaccine_campaign": { + "title": "nl_vaccine_campaign", + "type": "object", + "required": [ + "vaccine_campaign_order", + "vaccine_campaign_name_nl", + "vaccine_campaign_name_en", + "vaccine_administered_total", + "vaccine_administered_last_week" + ], + "additionalProperties": false, + "properties": { + "vaccine_campaign_order": { + "type": "integer" + }, + "vaccine_campaign_name_nl": { + "type": "string" + }, + "vaccine_campaign_name_en": { + "type": "string" + }, + "vaccine_administered_total": { + "type": "integer" + }, + "vaccine_administered_last_week": { + "type": "integer" + } + } + } + }, + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "nl_vaccine_campaigns", + "type": "object", + "required": [ + "vaccine_campaigns", + "date_unix", + "date_start_unix", + "date_end_unix", + "date_of_insertion_unix" + ], + "additionalProperties": false, + "properties": { + "vaccine_campaigns": { + "type": "array", + "items": { + "$ref": "#/definitions/vaccine_campaign" + } + }, + "date_unix": { + "type": "integer" + }, + "date_start_unix": { + "type": "integer" + }, + "date_end_unix": { + "type": "integer" + }, + "date_of_insertion_unix": { + "type": "integer" + } + } +} diff --git a/packages/app/schema/nl/vaccine_planned.json b/packages/app/schema/nl/vaccine_planned.json new file mode 100644 index 0000000000..ff99337654 --- /dev/null +++ b/packages/app/schema/nl/vaccine_planned.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "nl_vaccine_planned", + "type": "object", + "required": [ + "doses", + "date_unix", + "date_start_unix", + "date_end_unix", + "date_of_insertion_unix" + ], + "additionalProperties": false, + "properties": { + "doses": { + "type": "integer" + }, + "date_unix": { + "type": "integer" + }, + "date_start_unix": { + "type": "integer" + }, + "date_end_unix": { + "type": "integer" + }, + "date_of_insertion_unix": { + "type": "integer" + } + } +} From 5c4d3c649727b2d1d9a29462c83787127d0273c1 Mon Sep 17 00:00:00 2001 From: MN <97020799+VWSCoronaDashboard24@users.noreply.github.com> Date: Mon, 18 Jul 2022 16:30:03 +0200 Subject: [PATCH 06/12] COR-54 Refactor types (#4305) * feat: remove KeysOfType where possible * feat: remove KeysOfType where possible * fix: remove anys where possible * fix: improve types * fix: proper code formatting * feat: cleanup KeysOfType * fix: cleanup KeysOfType and friends * fix: remove as unkown as number casts * fix: cleanup types * fix: remove unused import * feat: types refactor * fix: update types Co-authored-by: VWSCoronaDashboard24 --- .../age-demographic/age-demographic-chart.tsx | 22 ++++--- .../age-demographic-coordinates.ts | 21 ++++--- .../age-demographic-tooltip-content.tsx | 21 ++++--- .../age-demographic/age-demographic.tsx | 6 +- .../components/canvas-choropleth-map.tsx | 2 +- .../app/src/components/choropleth/index.tsx | 9 +-- .../choropleth/logic/create-data-config.ts | 4 +- .../src/components/choropleth/logic/types.ts | 57 ++++++++++++----- .../logic/use-choropleth-tooltip.ts | 38 +++++++---- .../choropleth/logic/use-fill-color.ts | 13 +++- .../src/components/choropleth/logic/utils.ts | 5 +- .../tooltips/choropleth-tooltip.tsx | 18 ++++-- .../components/cms/inline-age-demographic.tsx | 10 +-- .../src/components/cms/inline-choropleth.tsx | 7 ++- .../app/src/components/cms/rich-content.tsx | 3 +- packages/app/src/components/pie-chart.tsx | 17 ++--- packages/app/src/components/spark-line.tsx | 17 +++-- .../time-series-chart/components/axes.tsx | 26 ++++---- .../tooltip/tooltip-series-list-items.tsx | 63 +++++++++---------- .../components/week-numbers.tsx | 9 ++- .../logic/use-format-series-value.ts | 9 +-- .../time-series-chart/time-series-chart.tsx | 4 +- packages/app/src/components/tooltip.tsx | 7 ++- .../behavior/behavior-choropleths-tile.tsx | 9 +-- .../behavior/behavior-line-chart-tile.tsx | 18 +++--- .../topical/mini-tile-selector-layout.tsx | 3 +- ...e-vaccine-coverage-percentage-formatter.ts | 5 +- .../vaccine-coverage-choropleth-per-gm.tsx | 8 +-- packages/app/src/pages/index.tsx | 2 +- .../app/src/pages/veiligheidsregio/index.tsx | 21 ++++--- .../utils/api/strip-trailing-null-values.ts | 2 +- packages/common/src/types/choropleth.ts | 53 ---------------- packages/common/src/types/inline-charts.ts | 5 +- 33 files changed, 261 insertions(+), 253 deletions(-) diff --git a/packages/app/src/components/age-demographic/age-demographic-chart.tsx b/packages/app/src/components/age-demographic/age-demographic-chart.tsx index 8dd6c7a8ed..d5960da447 100644 --- a/packages/app/src/components/age-demographic/age-demographic-chart.tsx +++ b/packages/app/src/components/age-demographic/age-demographic-chart.tsx @@ -1,4 +1,4 @@ -import { Color, colors, KeysOfType } from '@corona-dashboard/common'; +import { Color, colors } from '@corona-dashboard/common'; import css from '@styled-system/css'; import { AxisBottom, TickRendererProps } from '@visx/axis'; import { GridColumns } from '@visx/grid'; @@ -32,8 +32,8 @@ interface AgeDemographicChartProps { onMouseMoveBar: (value: T, event: MouseEvent) => void; onMouseLeaveBar: () => void; onKeyInput: (event: KeyboardEvent) => void; - rightMetricProperty: KeysOfType; - leftMetricProperty: KeysOfType; + rightMetricProperty: keyof T; + leftMetricProperty: keyof T; rightColor: Color; leftColor: Color; maxDisplayValue?: number; @@ -88,16 +88,18 @@ export function AgeDemographicChart({ const annotations = useAccessibilityAnnotations(accessibility); + const getNumberValue = (data: T, key: keyof T): number => { + const value = data[key]; + return typeof value === 'number' ? value : 0; + }; + const hasClippedValue = !!values.find( (value) => getIsClipped( - value[leftMetricProperty] as unknown as number, + getNumberValue(value, leftMetricProperty), maxDisplayValue ) || - getIsClipped( - value[rightMetricProperty] as unknown as number, - maxDisplayValue - ) + getIsClipped(getNumberValue(value, rightMetricProperty), maxDisplayValue) ); return ( @@ -191,12 +193,12 @@ export function AgeDemographicChart({ const rightBarWidth = rightPoint(value); const isClippedLeftGroup = getIsClipped( - value[leftMetricProperty] as unknown as number, + getNumberValue(value, leftMetricProperty), maxDisplayValue ); const isClippedRightGroup = getIsClipped( - value[rightMetricProperty] as unknown as number, + getNumberValue(value, rightMetricProperty), maxDisplayValue ); diff --git a/packages/app/src/components/age-demographic/age-demographic-coordinates.ts b/packages/app/src/components/age-demographic/age-demographic-coordinates.ts index 0b780a405a..c04fb2d9a5 100644 --- a/packages/app/src/components/age-demographic/age-demographic-coordinates.ts +++ b/packages/app/src/components/age-demographic/age-demographic-coordinates.ts @@ -1,4 +1,3 @@ -import { KeysOfType } from '@corona-dashboard/common'; import { localPoint } from '@visx/event'; import { scaleBand, scaleLinear, ScaleTypeToD3Scale } from '@visx/scale'; import { MouseEvent, useMemo } from 'react'; @@ -42,8 +41,8 @@ export function useAgeDemographicCoordinates< T extends AgeDemographicDefaultValue >( data: { values: T[] }, - rightMetricProperty: KeysOfType, - leftMetricProperty: KeysOfType, + rightMetricProperty: keyof T, + leftMetricProperty: keyof T, maxDisplayValue?: number ) { const [ref, { width = 840 }] = useResizeObserver(); @@ -79,8 +78,8 @@ function calculateAgeDemographicCoordinates< T extends AgeDemographicDefaultValue >( data: { values: T[] }, - rightMetricProperty: KeysOfType, - leftMetricProperty: KeysOfType, + rightMetricProperty: keyof T, + leftMetricProperty: keyof T, isSmallScreen: boolean, parentWidth: number, isExtraSmallScreen: boolean, @@ -118,10 +117,14 @@ function calculateAgeDemographicCoordinates< const yMax = height - margin.top - margin.bottom; // Helper functions to retrieve parts of the values - const getLeftValue = (value: T) => - value[leftMetricProperty] as unknown as number; - const getRightValue = (value: T) => - value[rightMetricProperty] as unknown as number; + const getLeftValue = (value: T) => { + const leftValue = value[leftMetricProperty]; + return typeof leftValue === 'number' ? leftValue : 0; + }; + const getRightValue = (value: T) => { + const rightValue = value[rightMetricProperty]; + return typeof rightValue === 'number' ? rightValue : 0; + }; const ageGroupRange = (value: T) => value.age_group_range; // Scales to map between values and coordinates diff --git a/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx b/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx index 42f11af3fe..45ba7eea45 100644 --- a/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx +++ b/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx @@ -1,4 +1,4 @@ -import type { Color, KeysOfType } from '@corona-dashboard/common'; +import type { Color } from '@corona-dashboard/common'; import css from '@styled-system/css'; import styled from 'styled-components'; import { BoldText } from '~/components/typography'; @@ -11,8 +11,8 @@ interface AgeDemographicTooltipContentProps< T extends AgeDemographicDefaultValue > { value: T; - rightMetricProperty: KeysOfType; - leftMetricProperty: KeysOfType; + rightMetricProperty: keyof T; + leftMetricProperty: keyof T; rightColor: Color; leftColor: Color; text: AgeDemographicChartText; @@ -30,6 +30,13 @@ export function AgeDemographicTooltipContent< text, formatValue, }: AgeDemographicTooltipContentProps) { + const valueRight = value[rightMetricProperty]; + const rightMetricPropertyValue = + typeof valueRight === 'number' ? valueRight : 0; + + const valueLeft = value[leftMetricProperty]; + const leftMetricPropertyValue = typeof valueLeft === 'number' ? valueLeft : 0; + return ( <> @@ -41,17 +48,13 @@ export function AgeDemographicTooltipContent< - - {formatValue(value[rightMetricProperty] as unknown as number)} - {' '} + {formatValue(rightMetricPropertyValue)}{' '} {replaceVariablesInText(text.right_tooltip, { ageGroupRange: formatAgeGroupRange(value.age_group_range), })} - - {formatValue(value[leftMetricProperty] as unknown as number)} - {' '} + {formatValue(leftMetricPropertyValue)}{' '} {replaceVariablesInText(text.left_tooltip, { ageGroupRange: formatAgeGroupRange(value.age_group_range), })} diff --git a/packages/app/src/components/age-demographic/age-demographic.tsx b/packages/app/src/components/age-demographic/age-demographic.tsx index 0531ea5654..1df3aec23a 100644 --- a/packages/app/src/components/age-demographic/age-demographic.tsx +++ b/packages/app/src/components/age-demographic/age-demographic.tsx @@ -1,4 +1,4 @@ -import type { Color, KeysOfType } from '@corona-dashboard/common'; +import type { Color } from '@corona-dashboard/common'; import { Box } from '~/components/base'; import { ErrorBoundary } from '~/components/error-boundary'; import { Tooltip, useTooltip } from '~/components/tooltip'; @@ -16,8 +16,8 @@ import { AgeDemographicChartText, AgeDemographicDefaultValue } from './types'; export interface AgeDemographicProps { data: { values: T[] }; - rightMetricProperty: KeysOfType; - leftMetricProperty: KeysOfType; + rightMetricProperty: keyof T; + leftMetricProperty: keyof T; rightColor: Color; leftColor: Color; /** diff --git a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx index 350fb94d95..5eaa21ee3c 100644 --- a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx +++ b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx @@ -321,7 +321,7 @@ const Outlines = memo((props: OutlinesProps) => { type FeaturesProps = { geoInfo: ProjectedGeoInfo[]; featureProps: FeatureProps; - children: any; + children: React.ReactNode; }; const Features = memo((props: FeaturesProps) => { diff --git a/packages/app/src/components/choropleth/index.tsx b/packages/app/src/components/choropleth/index.tsx index 398988d5ec..ae330f6255 100644 --- a/packages/app/src/components/choropleth/index.tsx +++ b/packages/app/src/components/choropleth/index.tsx @@ -1,4 +1,3 @@ -import { KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import type { GeoProjection } from 'd3-geo'; import withLoadingProps from 'next-dynamic-loading-props'; @@ -64,16 +63,12 @@ export type OptionalDataConfig = { /** * A top-level property name of either VR_COLLECTION.json or GM_COLLECTION.json */ - metricName: KeysOfType, T[]>; + metricName: keyof InferedDataCollection; /** * A property name of the object determined by the metric name. This value is used to determine the color * of the feature. */ - metricProperty: KeysOfType< - T, - string | number | null | boolean | undefined, - true - >; + metricProperty: keyof T; /** * The color that is used for the feature when no data is available (a null value for example). */ diff --git a/packages/app/src/components/choropleth/logic/create-data-config.ts b/packages/app/src/components/choropleth/logic/create-data-config.ts index 588085d766..c842339d89 100644 --- a/packages/app/src/components/choropleth/logic/create-data-config.ts +++ b/packages/app/src/components/choropleth/logic/create-data-config.ts @@ -18,8 +18,8 @@ export function createDataConfig( ) { if (partialDataConfig.metricName === 'veiligheidsregio') { return { - metricName: 'veiligheidsregio' as any, - metricProperty: 'admissions_on_date_of_admission' as any, + metricName: 'veiligheidsregio', + metricProperty: 'admissions_on_date_of_admission', areaStroke: colors.white, areaStrokeWidth: 1, hoverFill: colors.white, diff --git a/packages/app/src/components/choropleth/logic/types.ts b/packages/app/src/components/choropleth/logic/types.ts index 854f3b5a7c..6e7dae15d7 100644 --- a/packages/app/src/components/choropleth/logic/types.ts +++ b/packages/app/src/components/choropleth/logic/types.ts @@ -1,7 +1,19 @@ import type { GmCollection, - KeysOfType, + GmCollectionHospitalNice, + GmCollectionSewer, + GmCollectionTestedOverall, + GmCollectionVaccineCoveragePerAgeGroup, VrCollection, + VrCollectionBehavior, + VrCollectionDisabilityCare, + VrCollectionElderlyAtHome, + VrCollectionHospitalNice, + VrCollectionNursingHome, + VrCollectionSewer, + VrCollectionSituations, + VrCollectionTestedOverall, + VrCollectionVaccineCoveragePerAgeGroup, } from '@corona-dashboard/common'; import type { ParsedFeature } from '@visx/geo/lib/projections/Projection'; import type { @@ -35,9 +47,18 @@ export enum CHOROPLETH_ASPECT_RATIO { */ export type MapType = 'gm' | 'vr'; +const CODE_PROP_GM = 'gmcode'; +const CODE_PROP_VR = 'vrcode'; +const CODE_PROP_COUNTRY = 'country_code'; + export type CodeProp = - | KeysOfType - | KeysOfType; + | typeof CODE_PROP_GM + | typeof CODE_PROP_VR + | typeof CODE_PROP_COUNTRY; + +export const isCodeProp = (input: string): input is CodeProp => { + return [CODE_PROP_GM, CODE_PROP_VR, CODE_PROP_COUNTRY].includes(input); +}; export const mapToCodeType: Record = { gm: 'gmcode', @@ -59,22 +80,24 @@ export type InferedDataCollection = ? VrCollection : never; -/** - * Select all the item types of all the properties from the VrCollection with an array type that has a vrcode property - */ -export type VrDataCollection = VrCollection[KeysOfType< - VrCollection, - { vrcode: string }[] ->]; +export type VrDataCollection = + | VrCollectionHospitalNice[] + | VrCollectionHospitalNice[] + | VrCollectionTestedOverall[] + | VrCollectionNursingHome[] + | VrCollectionSewer[] + | VrCollectionBehavior[] + | VrCollectionDisabilityCare[] + | VrCollectionElderlyAtHome[] + | VrCollectionSituations[] + | VrCollectionVaccineCoveragePerAgeGroup[]; export type VrDataItem = VrDataCollection[number]; -/** - * Select all the item types of all the properties from the GmCollection with an array type that has a gmcode property - */ -export type GmDataCollection = GmCollection[KeysOfType< - GmCollection, - { gmcode: string }[] ->]; +export type GmDataCollection = + | GmCollectionHospitalNice[] + | GmCollectionTestedOverall[] + | GmCollectionSewer[] + | GmCollectionVaccineCoveragePerAgeGroup[]; export type GmDataItem = GmDataCollection[number]; /** diff --git a/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts b/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts index 9c682c00b5..05620d2151 100644 --- a/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts +++ b/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts @@ -9,7 +9,13 @@ import { useIsTouchDevice } from '~/utils/use-is-touch-device'; import { DataConfig, DataOptions } from '..'; import { TooltipSettings } from '../tooltips/types'; import { thresholds } from './thresholds'; -import { ChoroplethDataItem, mapToCodeType, MapType } from './types'; +import { + ChoroplethDataItem, + CodeProp, + isCodeProp, + mapToCodeType, + MapType, +} from './types'; import { useFeatureName } from './use-feature-name'; import { isCodedValueType } from './utils'; @@ -62,9 +68,12 @@ export function useChoroplethTooltip( const getFeatureName = useFeatureName(map, dataOptions.getFeatureName); const getItemByCode = useMemo(() => { - return (code: string) => { + return (code: CodeProp) => { const item = data - .filter(isCodedValueType(codeType)) + .filter((x) => { + const filterFn = isCodedValueType(codeType); + return filterFn && filterFn(x); + }) .find((x) => (x as any)[codeType] === code); assert( item, @@ -77,7 +86,9 @@ export function useChoroplethTooltip( const threshold = thresholds[map][dataConfig.metricProperty as string]; assert( isDefined(threshold), - `[${useChoroplethTooltip.name}] No threshold configured for map type ${map} and metric property ${dataConfig.metricProperty.toString()}` + `[${ + useChoroplethTooltip.name + }] No threshold configured for map type ${map} and metric property ${dataConfig.metricProperty.toString()}` ); useEffect(() => { @@ -91,7 +102,7 @@ export function useChoroplethTooltip( return; } - function handleBubbledFocusIn(event: FocusEvent): any { + function handleBubbledFocusIn(event: FocusEvent): void { const link = event.target as HTMLAnchorElement; if (!isDefined(link)) { return; @@ -99,7 +110,7 @@ export function useChoroplethTooltip( const code = link.getAttribute('data-id'); - if (isPresent(code) && isPresent(container)) { + if (isPresent(code) && isPresent(container) && isCodeProp(code)) { const bboxContainer = container.getBoundingClientRect(); const bboxLink = link.getBoundingClientRect(); const left = bboxLink.left - bboxContainer.left; @@ -183,7 +194,7 @@ type HoverInfo = { code: string; x: number; y: number }; const createTooltipTrigger = ( setTooltip: (settings: TooltipSettings | undefined) => void, - getItemByCode: (code: string) => T, + getItemByCode: (code: CodeProp) => T, dataConfig: DataConfig, dataOptions: DataOptions, threshold: ChoroplethThresholdsValue[], @@ -192,7 +203,7 @@ const createTooltipTrigger = ( metricPropertyFormatter: (value: number) => string ) => { return (hoverInfo?: HoverInfo) => { - if (!isDefined(hoverInfo)) { + if (!isDefined(hoverInfo) || !isCodeProp(hoverInfo.code)) { return setTooltip(undefined); } @@ -218,7 +229,7 @@ const createFeatureMouseOverHandler = ( timeout: MutableRefObject, setTooltip: (settings: TooltipSettings | undefined) => void, ref: RefObject, - getItemByCode: (code: string) => T, + getItemByCode: (code: CodeProp) => T, dataConfig: DataConfig, dataOptions: DataOptions, threshold: ChoroplethThresholdsValue[], @@ -230,7 +241,7 @@ const createFeatureMouseOverHandler = ( const elm = event.target as HTMLElement; const code = elm.getAttribute('data-id'); - if (isPresent(code) && ref.current) { + if (isPresent(code) && isCodeProp(code) && ref.current) { if (timeout.current > -1) { clearTimeout(timeout.current); timeout.current = -1; @@ -281,9 +292,10 @@ function useMetricPropertyFormatter( intl: IntlContextProps ) { return useMemo(() => { - const values = data.map( - (x) => x[dataConfig.metricProperty] as unknown as number - ); + const values = data.map((value) => { + const valueEntry = value[dataConfig.metricProperty]; + return typeof valueEntry === 'number' ? valueEntry : 0; + }); const numberOfDecimals = getMaximumNumberOfDecimals(values); return (value: number) => intl.formatPercentage(value, { diff --git a/packages/app/src/components/choropleth/logic/use-fill-color.ts b/packages/app/src/components/choropleth/logic/use-fill-color.ts index 9c9a164b39..68088f29c0 100644 --- a/packages/app/src/components/choropleth/logic/use-fill-color.ts +++ b/packages/app/src/components/choropleth/logic/use-fill-color.ts @@ -34,7 +34,9 @@ export function useFillColor( const threshold = thresholds[thresholdMap || map][metricProperty as string]; assert( isDefined(threshold), - `[${useFillColor.name}] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` + `[${ + useFillColor.name + }] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` ); const colorScale = useMemo(() => createColorScale(threshold), [threshold]); @@ -58,7 +60,9 @@ export function getFillColor( const threshold = thresholds[thresholdMap || map][metricProperty as string]; assert( isDefined(threshold), - `[${getFillColor.name}] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` + `[${ + getFillColor.name + }] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` ); const colorScale = createColorScale(threshold); @@ -94,7 +98,10 @@ function createGetValueByCode( ) { return (code: string) => { const item = data - .filter(isCodedValueType(codeType)) + .filter((x) => { + const filterFn = isCodedValueType(codeType); + return filterFn && filterFn(x); + }) .find((x) => (x as unknown as Record)[codeType] === code); return isDefined(item) && isPresent(item[metricProperty]) diff --git a/packages/app/src/components/choropleth/logic/utils.ts b/packages/app/src/components/choropleth/logic/utils.ts index 4c81a00f31..1d6d0414a4 100644 --- a/packages/app/src/components/choropleth/logic/utils.ts +++ b/packages/app/src/components/choropleth/logic/utils.ts @@ -2,7 +2,6 @@ import type { ParsedFeature } from '@visx/geo/lib/projections/Projection'; import type { Feature, MultiPolygon, Polygon } from 'geojson'; import { isPresent } from 'ts-is-present'; import type { - ChoroplethDataItem, CodedGeoProperties, CodeProp, GmDataItem, @@ -19,11 +18,11 @@ export function isCodedValueType(codeType: CodeProp) { } } -export function isGmData(item: ChoroplethDataItem): item is GmDataItem { +export function isGmData(item: any): item is GmDataItem { return 'gmcode' in item; } -export function isVrData(item: ChoroplethDataItem): item is VrDataItem { +export function isVrData(item: any): item is VrDataItem { return 'vrcode' in item; } diff --git a/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx b/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx index 037fc3f93e..c2281a4448 100644 --- a/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx +++ b/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx @@ -36,7 +36,11 @@ export function ChoroplethTooltip( )[data.map]?.[data.dataConfig.metricProperty as string]?.subject; assert( isDefined(subject), - `[${ChoroplethTooltip.name}] No tooltip subject found in siteText.choropleth_tooltip.${data.map}.${data.dataConfig.metricProperty.toString()}` + `[${ + ChoroplethTooltip.name + }] No tooltip subject found in siteText.choropleth_tooltip.${ + data.map + }.${data.dataConfig.metricProperty.toString()}` ); const tooltipContent = ( @@ -44,7 +48,11 @@ export function ChoroplethTooltip( )[data.map]?.[data.dataConfig.metricProperty as string]?.content; assert( isDefined(tooltipContent), - `[${ChoroplethTooltip.name}] No tooltip content found in siteText.choropleth_tooltip.${data.map}.${data.dataConfig.metricProperty.toString()}` + `[${ + ChoroplethTooltip.name + }] No tooltip content found in siteText.choropleth_tooltip.${ + data.map + }.${data.dataConfig.metricProperty.toString()}` ); const tooltipVars = { @@ -74,6 +82,8 @@ export function ChoroplethTooltip( // This line is to make sure the content is readible by screenreaders and does not skip numbers after a new line const ariaContent = content.replace(/(\n|\*)/g, ''); + const dataItem = data.dataItem[data.dataConfig.metricProperty]; + const filterBelow = typeof dataItem === 'number' ? dataItem : null; return ( ( {ariaContent} diff --git a/packages/app/src/components/cms/inline-age-demographic.tsx b/packages/app/src/components/cms/inline-age-demographic.tsx index 391dd2ea39..bc0bc16bc1 100644 --- a/packages/app/src/components/cms/inline-age-demographic.tsx +++ b/packages/app/src/components/cms/inline-age-demographic.tsx @@ -8,6 +8,7 @@ import { get } from 'lodash'; import useSWRImmutable from 'swr/immutable'; import { isDefined } from 'ts-is-present'; import { useIntl } from '~/intl'; +import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations'; import { AgeDemographic } from '../age-demographic'; import { ErrorBoundary } from '../error-boundary'; import { Metadata } from '../metadata'; @@ -18,7 +19,8 @@ import { getDataUrl } from './logic/get-data-url'; interface InlineAgeDemographicProps { configuration: AgeDemographicConfiguration< DataScopeKey, - MetricKeys + MetricKeys, + AccessibilityDefinition['key'] >; startDate?: string; endDate?: string; @@ -45,11 +47,11 @@ export function InlineAgeDemographic(props: InlineAgeDemographicProps) { return ( `${n}`} diff --git a/packages/app/src/components/cms/inline-choropleth.tsx b/packages/app/src/components/cms/inline-choropleth.tsx index 6016cf616f..d1cbd8b435 100644 --- a/packages/app/src/components/cms/inline-choropleth.tsx +++ b/packages/app/src/components/cms/inline-choropleth.tsx @@ -15,7 +15,7 @@ import { DynamicChoropleth, OptionalDataConfig, } from '../choropleth'; -import { ChoroplethDataItem } from '../choropleth/logic'; +import { ChoroplethDataItem, InferedDataCollection } from '../choropleth/logic'; import { ErrorBoundary } from '../error-boundary'; import { Metadata } from '../metadata'; import { InlineLoader } from './inline-loader'; @@ -58,8 +58,9 @@ export function InlineChoropleth(props: InlineChoroplethProps) { }; const dataConfig: OptionalDataConfig = { - metricName: configuration.metricName as any, - metricProperty: configuration.metricProperty as any, + metricName: + configuration.metricName as keyof InferedDataCollection, + metricProperty: configuration.metricProperty as keyof ChoroplethDataItem, areaStroke: getColor(configuration.areaStroke), areaStrokeWidth: configuration.areaStrokeWidth, highlightStroke: getColor(configuration.highlightStroke), diff --git a/packages/app/src/components/cms/rich-content.tsx b/packages/app/src/components/cms/rich-content.tsx index 938e22590f..ddf11f0ee8 100644 --- a/packages/app/src/components/cms/rich-content.tsx +++ b/packages/app/src/components/cms/rich-content.tsx @@ -30,6 +30,7 @@ import { import { assert } from '~/utils/assert'; import { isAbsoluteUrl } from '~/utils/is-absolute-url'; import { Link } from '~/utils/link'; +import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations'; import { Heading } from '../typography'; import { ContentImage } from './content-image'; import { InlineAgeDemographic } from './inline-age-demographic'; @@ -55,7 +56,7 @@ interface AgeDemographicConfigNode { title: string; startDate?: string; endDate?: string; - config: AgeDemographicConfiguration>; + config: AgeDemographicConfiguration, AccessibilityDefinition['key']>; } interface ChoroplethConfigNode { diff --git a/packages/app/src/components/pie-chart.tsx b/packages/app/src/components/pie-chart.tsx index 3b10099fd3..78bc9ad48c 100644 --- a/packages/app/src/components/pie-chart.tsx +++ b/packages/app/src/components/pie-chart.tsx @@ -1,4 +1,3 @@ -import type { KeysOfType } from '@corona-dashboard/common'; import { Chevron } from '@corona-dashboard/icons'; import css from '@styled-system/css'; import { Group } from '@visx/group'; @@ -16,7 +15,7 @@ import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; const ICON_SIZE = 55; export interface PiePartConfig { - metricProperty: KeysOfType; + metricProperty: keyof T; color: string; label: string; tooltipLabel: string; @@ -72,11 +71,13 @@ export function PieChart({ formatDateSpan, }; - const totalValue = dataConfig.reduce( - (previousValue, currentValue) => - previousValue + (data[currentValue.metricProperty] as unknown as number), - 0 - ); + const totalValue = dataConfig.reduce((previousValue, currentValue) => { + const metricPropertyValue = data[currentValue.metricProperty]; + return ( + previousValue + + (typeof metricPropertyValue === 'number' ? metricPropertyValue : 0) + ); + }, 0); const mappedDataWithValues = useMemo( () => @@ -85,7 +86,7 @@ export function PieChart({ return { __value: Math.max( - currentProperty as unknown as number, + typeof currentProperty === 'number' ? currentProperty : 0, totalValue * (minimumPercentage / 100) * 2 ), ...config, diff --git a/packages/app/src/components/spark-line.tsx b/packages/app/src/components/spark-line.tsx index 36d1af5009..4f64084955 100644 --- a/packages/app/src/components/spark-line.tsx +++ b/packages/app/src/components/spark-line.tsx @@ -1,8 +1,7 @@ -import type { KeysOfType, TimestampedValue } from '@corona-dashboard/common'; +import type { TimestampedValue } from '@corona-dashboard/common'; import { colors } from '@corona-dashboard/common'; import { scaleLinear } from '@visx/scale'; import { AreaClosed, LinePath } from '@visx/shape'; -import { NumberValue } from 'd3-scale'; import { first, last } from 'lodash'; import { isPresent } from 'ts-is-present'; @@ -11,7 +10,7 @@ const HEIGHT = 24; const MARKER_RADIUS = 2.5; type SparkLineProps = { - averageProperty: KeysOfType; + averageProperty: keyof T; data: T[]; }; @@ -31,14 +30,20 @@ export function SparkLine( props: SparkLineProps ) { const { data, averageProperty } = props; + + const getNumberValue = (data: T, key: keyof T): number => { + const value = data[key]; + return typeof value === 'number' ? value : 0; + }; + const numberOfPoints = data.length; const min = Math.min( 0, - ...data.map((d) => (d[averageProperty] as unknown as number) ?? 0) + ...data.map((d) => getNumberValue(d, averageProperty)) ); const max = Math.max( 0.1, - ...data.map((d) => (d[averageProperty] as unknown as number) ?? 0) + ...data.map((d) => getNumberValue(d, averageProperty)) ); const xScale = scaleLinear({ domain: [getDate(first(data)), getDate(last(data))], @@ -55,7 +60,7 @@ export function SparkLine( } function getY(dataPoint: T) { - return yScale(dataPoint[averageProperty] as unknown as NumberValue); + return yScale(getNumberValue(dataPoint, averageProperty)); } const nonNullValues = data.filter((x) => isPresent(x[averageProperty])); diff --git a/packages/app/src/components/time-series-chart/components/axes.tsx b/packages/app/src/components/time-series-chart/components/axes.tsx index dc42a92bd3..ac115f1792 100644 --- a/packages/app/src/components/time-series-chart/components/axes.tsx +++ b/packages/app/src/components/time-series-chart/components/axes.tsx @@ -13,7 +13,7 @@ import { DateSpanValue, } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { AxisBottom, AxisLeft } from '@visx/axis'; +import { AxisBottom, AxisLeft, TickFormatter } from '@visx/axis'; import { GridRows } from '@visx/grid'; import { scaleLinear } from '@visx/scale'; import { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale'; @@ -49,7 +49,7 @@ export type AxesProps = { timeDomain: [number, number]; xTickNumber?: number; values?: T[]; - formatYTickValue?: (value: number) => string; + formatYTickValue?: TickFormatter; /** * On narrow screens we'll "collapse" the Y-axis. Only the low value will be @@ -92,8 +92,6 @@ function createTimeTicks(startTick: number, endTick: number, count: number) { return ticks; } -export type AnyTickFormatter = (value: any) => string; - export const Axes = memo(function Axes({ numGridLines, showWeekNumbers, @@ -129,13 +127,13 @@ export const Axes = memo(function Axes({ const { formatDateFromSeconds, formatNumber, formatPercentage } = useIntl(); - const formatYAxis = useCallback( - (y: number) => formatNumber(y), + const formatYAxis: TickFormatter = useCallback( + (y: NumberValue) => formatNumber(y as number), [formatNumber] ); - const formatYAxisPercentage = useCallback( - (y: number) => `${formatPercentage(y)}%`, + const formatYAxisPercentage: TickFormatter = useCallback( + (y: NumberValue) => `${formatPercentage(y as number)}%`, [formatPercentage] ); @@ -356,10 +354,10 @@ export const Axes = memo(function Axes({ stroke={colors.silver} tickFormat={ formatYTickValue - ? (formatYTickValue as AnyTickFormatter) + ? formatYTickValue : isPercentage - ? (formatYAxisPercentage as AnyTickFormatter) - : (formatYAxis as AnyTickFormatter) + ? formatYAxisPercentage + : formatYAxis } tickLabelProps={() => ({ fill: colors.data.axisLabels, @@ -388,10 +386,10 @@ export const Axes = memo(function Axes({ stroke={colors.silver} tickFormat={ formatYTickValue - ? (formatYTickValue as AnyTickFormatter) + ? formatYTickValue : isPercentage - ? (formatYAxisPercentage as AnyTickFormatter) - : (formatYAxis as AnyTickFormatter) + ? formatYAxisPercentage + : formatYAxis } tickLabelProps={() => ({ fill: colors.data.axisLabels, diff --git a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx index 633697e751..606dbd8f75 100644 --- a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx +++ b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx @@ -37,7 +37,7 @@ export function TooltipSeriesListItems({ return ( - {seriesConfig.map((x, index) => { + {seriesConfig.map((serie, index) => { /** * The key is unique for every date to make sure a screenreader * will read `[label]: [value]`. Otherwise it would read the @@ -45,23 +45,27 @@ export function TooltipSeriesListItems({ * context. */ const key = index + getDateUnixString(value); - const metricPropertyValue = - x.type !== 'range' && - (value[x.metricProperty] as unknown as number | null); + const metricProperty = serie.type !== 'range' && serie.metricProperty; + const metricPropertyValue = metricProperty + ? value[metricProperty] + : null; - switch (x.type) { + const tooltipValue = + typeof metricPropertyValue === 'number' ? metricPropertyValue : null; + + switch (serie.type) { case 'range': return ( } - label={x.shortLabel ?? x.label} - ariaLabel={x.ariaLabel} + icon={} + label={serie.shortLabel ?? serie.label} + ariaLabel={serie.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={x.nonInteractive} + isVisuallyHidden={serie.nonInteractive} > - {formatSeriesValue(value, x, options.isPercentage)} + {formatSeriesValue(value, serie, options.isPercentage)} ); @@ -70,15 +74,15 @@ export function TooltipSeriesListItems({ return ( {formatSeriesValue( value, - x, - x.isPercentage ?? options.isPercentage + serie, + serie.isPercentage ?? options.isPercentage )} ); @@ -88,18 +92,13 @@ export function TooltipSeriesListItems({ return ( - } - label={x.shortLabel ?? x.label} - ariaLabel={x.ariaLabel} + icon={} + label={serie.shortLabel ?? serie.label} + ariaLabel={serie.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={x.nonInteractive} + isVisuallyHidden={serie.nonInteractive} > - {formatSeriesValue(value, x, options.isPercentage)} + {formatSeriesValue(value, serie, options.isPercentage)} ); @@ -108,20 +107,20 @@ export function TooltipSeriesListItems({ ) : ( - + ) } - label={x.shortLabel ?? x.label} - ariaLabel={x.ariaLabel} + label={serie.shortLabel ?? serie.label} + ariaLabel={serie.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={x.nonInteractive} + isVisuallyHidden={serie.nonInteractive} > - {formatSeriesValue(value, x, options.isPercentage)} + {formatSeriesValue(value, serie, options.isPercentage)} ); } diff --git a/packages/app/src/components/time-series-chart/components/week-numbers.tsx b/packages/app/src/components/time-series-chart/components/week-numbers.tsx index d8824a748b..7ee582b5d2 100644 --- a/packages/app/src/components/time-series-chart/components/week-numbers.tsx +++ b/packages/app/src/components/time-series-chart/components/week-numbers.tsx @@ -4,10 +4,10 @@ import { WEEK_IN_SECONDS, } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { AxisTop } from '@visx/axis'; +import { AxisTop, TickFormatter } from '@visx/axis'; import { RectClipPath } from '@visx/clip-path'; import { GridColumns } from '@visx/grid'; -import { ScaleBand, ScaleLinear } from 'd3-scale'; +import { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale'; import { useCallback, useMemo } from 'react'; import { isDefined } from 'ts-is-present'; import { useIntl } from '~/intl'; @@ -15,7 +15,6 @@ import { createDateFromUnixTimestamp } from '~/utils/create-date-from-unix-times import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; import { useUniqueId } from '~/utils/use-unique-id'; import { Bounds, getWeekInfo } from '../logic'; -import { AnyTickFormatter } from './axes'; /** * Only show this amount of week numbers @@ -72,7 +71,7 @@ export function WeekNumbers({ }); }, [commonTexts.common] - ); + ) as TickFormatter; return ( <> @@ -101,7 +100,7 @@ export function WeekNumbers({ ({ diff --git a/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts b/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts index 6ba50a12f2..f0b0208ff3 100644 --- a/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts +++ b/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts @@ -18,10 +18,11 @@ export function useFormatSeriesValue( ) { const formatter = metricPropertyFormatters[metricProperty] || intl.formatNumber; - const numberValue = value[metricProperty] as unknown as number | null; - const formattedValue = isPresent(numberValue) - ? formatter(numberValue) - : numberValue; + const numberValue = value[metricProperty]; + const formattedValue = + isPresent(numberValue) && typeof numberValue === 'number' + ? formatter(numberValue) + : String(numberValue); return isPresent(formattedValue) ? isPercentage diff --git a/packages/app/src/components/time-series-chart/time-series-chart.tsx b/packages/app/src/components/time-series-chart/time-series-chart.tsx index 220d9afacc..faa67e2025 100644 --- a/packages/app/src/components/time-series-chart/time-series-chart.tsx +++ b/packages/app/src/components/time-series-chart/time-series-chart.tsx @@ -1,6 +1,8 @@ import { TimeframeOption, TimestampedValue } from '@corona-dashboard/common'; import css from '@styled-system/css'; +import { TickFormatter } from '@visx/axis'; import { useTooltip } from '@visx/tooltip'; +import { NumberValue } from 'd3-scale'; import { first, isFunction, last } from 'lodash'; import { useCallback, useEffect, useMemo } from 'react'; import { isDefined } from 'ts-is-present'; @@ -120,7 +122,7 @@ export type TimeSeriesChartProps< showWeekNumbers?: boolean; tickValues?: number[]; xTickNumber?: number; - formatTickValue?: (value: number) => string; + formatTickValue?: TickFormatter; paddingLeft?: number; /** * The data specific options are grouped together. This way we can pass them diff --git a/packages/app/src/components/tooltip.tsx b/packages/app/src/components/tooltip.tsx index 6e6bbe96d5..71abee4bcf 100644 --- a/packages/app/src/components/tooltip.tsx +++ b/packages/app/src/components/tooltip.tsx @@ -1,6 +1,7 @@ import css from '@styled-system/css'; import { MouseEvent, + KeyboardEvent, ReactNode, useCallback, useEffect, @@ -16,7 +17,7 @@ export interface TooltipCoordinates { export type GetTooltipCoordinates = ( value: T, - event?: MouseEvent + event?: MouseEvent ) => TooltipCoordinates; interface TooltipProps { @@ -76,7 +77,7 @@ export function useTooltip({ } const openTooltip = useCallback( - (value: T, event: MouseEvent) => { + (value: T, event: MouseEvent) => { debounceMouseEvents(() => { setCoordinates(getTooltipCoordinates(value, event)); setIsVisible(true); @@ -93,7 +94,7 @@ export function useTooltip({ }, []); const keyboardNavigateTooltip = useCallback( - (event: any) => { + (event: KeyboardEvent) => { if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') { return; } diff --git a/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx b/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx index c083eb4322..327dbc53e8 100644 --- a/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx +++ b/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx @@ -1,6 +1,5 @@ import { colors, - KeysOfType, VrCollectionBehavior, } from '@corona-dashboard/common'; import css from '@styled-system/css'; @@ -119,7 +118,7 @@ function ChoroplethBlock({ const breakpoints = useBreakpoints(); const isSmallScreen = breakpoints.sm; - const metricProperty = `${currentId}_${behaviorType}` as const; + const metricProperty = `${currentId}_${behaviorType}` as keyof VrCollectionBehavior; return ( @@ -153,11 +152,7 @@ function ChoroplethBlock({ data={data.behavior} dataConfig={{ metricName: 'behavior', - metricProperty: metricProperty as unknown as KeysOfType< - VrCollectionBehavior, - number | null | boolean | undefined, - true - >, + metricProperty, noDataFillColor: colors.offWhite, }} dataOptions={{ diff --git a/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx b/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx index e2a1222420..945dc7a915 100644 --- a/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx +++ b/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx @@ -10,7 +10,7 @@ import { Box } from '~/components/base'; import { ChartTile } from '~/components/chart-tile'; import { InlineTooltip } from '~/components/inline-tooltip'; import { MetadataProps } from '~/components/metadata'; -import { TimeSeriesChart } from '~/components/time-series-chart'; +import { SeriesConfig, TimeSeriesChart } from '~/components/time-series-chart'; import { TimelineEventConfig } from '~/components/time-series-chart/components/timeline'; import { BoldText } from '~/components/typography'; import { SiteText } from '~/locale'; @@ -20,8 +20,12 @@ import { BehaviorIdentifier, behaviorIdentifiers, } from './logic/behavior-types'; + +type ValueType = NlBehaviorValue | VrBehaviorValue; +type ValueKey = keyof ValueType; + interface BehaviorLineChartTileProps { - values: NlBehaviorValue[] | VrBehaviorValue[]; + values: ValueType[]; metadata: MetadataProps; currentId: BehaviorIdentifier; setCurrentId: React.Dispatch>; @@ -42,15 +46,15 @@ export function BehaviorLineChartTile({ text, }: BehaviorLineChartTileProps) { const selectedComplianceValueKey = - `${currentId}_compliance` as keyof NlBehaviorValue; + `${currentId}_compliance` as ValueKey; const selectedSupportValueKey = - `${currentId}_support` as keyof NlBehaviorValue; + `${currentId}_support` as ValueKey; - const complianceValuesHasGap = useDataHasGaps( + const complianceValuesHasGap = useDataHasGaps( values, selectedComplianceValueKey ); - const supportValuesHasGap = useDataHasGaps(values, selectedSupportValueKey); + const supportValuesHasGap = useDataHasGaps(values, selectedSupportValueKey); const breakpoints = useBreakpoints(); @@ -88,7 +92,7 @@ export function BehaviorLineChartTile({ )} - > accessibility={{ key: 'behavior_line_chart', }} diff --git a/packages/app/src/domain/topical/mini-tile-selector-layout.tsx b/packages/app/src/domain/topical/mini-tile-selector-layout.tsx index fa2c829ca0..f226908220 100644 --- a/packages/app/src/domain/topical/mini-tile-selector-layout.tsx +++ b/packages/app/src/domain/topical/mini-tile-selector-layout.tsx @@ -1,6 +1,5 @@ import { colors, - KeysOfType, TimestampedValue, Unpack, } from '@corona-dashboard/common'; @@ -27,7 +26,7 @@ import { Bar } from '../vaccine/components/bar'; export type MiniTileSelectorItem = { label: string; data: T[]; - dataProperty: KeysOfType, number | null, true>; + dataProperty: keyof Unpack; value: number | string; valueIsPercentage?: boolean; warning?: string; diff --git a/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts b/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts index 008405785d..446d91f1e7 100644 --- a/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts +++ b/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts @@ -66,9 +66,10 @@ function getVaccineCoveragePercentageFormatter( } } - if (isPresent(data[property]) && typeof data[property] === 'number') { + const dataEntry = data[property]; + if (isPresent(dataEntry) && typeof dataEntry === 'number') { return ( - formatPercentage(data[property] as unknown as number, { + formatPercentage(dataEntry, { minimumFractionDigits: numFractionDigits, maximumFractionDigits: numFractionDigits, }) + '%' diff --git a/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx b/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx index 7d8648dfd1..ed565718d7 100644 --- a/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx +++ b/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx @@ -2,7 +2,6 @@ import { assert, colors, GmCollectionVaccineCoveragePerAgeGroup, - KeysOfType, VrCollectionVaccineCoveragePerAgeGroup, } from '@corona-dashboard/common'; import css from '@styled-system/css'; @@ -244,10 +243,7 @@ export function ChoroplethTooltip( ...data.dataOptions.tooltipVariables, } as Record; - const dataItemKey = data.dataConfig.metricProperty as KeysOfType< - VaccineCoverageData, - number - >; + const dataItemKey = data.dataConfig.metricProperty as keyof VaccineCoverageData; const filterBelow = (dataItemKey === undefined ? null : data.dataItem[dataItemKey]) || null; @@ -300,7 +296,7 @@ export function ChoroplethTooltip( ) => { {isPresent(content.articles) && ( )} diff --git a/packages/app/src/pages/veiligheidsregio/index.tsx b/packages/app/src/pages/veiligheidsregio/index.tsx index 0592b86bfc..68336298c3 100644 --- a/packages/app/src/pages/veiligheidsregio/index.tsx +++ b/packages/app/src/pages/veiligheidsregio/index.tsx @@ -39,15 +39,18 @@ const VrIndexPage = (props: StaticProps) => { }; const code = router.query.code as string; - const data = useMemo(() => { - return vrData.map( - (x) => - ({ - vrcode: x.code, - admissions_on_date_of_reporting: null, - } as unknown as VrCollectionHospitalNice) - ); - }, []); + const data = useMemo( + () => + vrData.map((x) => ({ + date_unix: 0, + admissions_on_date_of_admission: 0, + admissions_on_date_of_admission_per_100000: 0, + admissions_on_date_of_reporting: 0, + date_of_insertion_unix: 0, + vrcode: x.code, + })), + [] + ); return ( diff --git a/packages/app/src/utils/api/strip-trailing-null-values.ts b/packages/app/src/utils/api/strip-trailing-null-values.ts index 34b4e7369c..43ea0decb0 100644 --- a/packages/app/src/utils/api/strip-trailing-null-values.ts +++ b/packages/app/src/utils/api/strip-trailing-null-values.ts @@ -15,7 +15,7 @@ export function stripTrailingNullValues( ) { if ( !metricsInaccurateItems.includes(metric) || - !strippableMetricProperties.includes(metricProperty as unknown as string) + !strippableMetricProperties.includes(metricProperty ?? '') ) { return data; } diff --git a/packages/common/src/types/choropleth.ts b/packages/common/src/types/choropleth.ts index d8a1ef71d4..46dc057237 100644 --- a/packages/common/src/types/choropleth.ts +++ b/packages/common/src/types/choropleth.ts @@ -8,59 +8,6 @@ import type { VrDifference, } from './data'; -/** - * This type was taken from this Stack Overflow post: https://stackoverflow.com/questions/46583883/typescript-pick-properties-with-a-defined-type - * - * Returns an interface stripped of all keys that don't resolve to U, defaulting - * to a non-strict comparison of T[key] extends U. Setting B to true performs - * a strict type comparison of T[key] extends U & U extends T[key] - * - * Example, if one needs just the keys of type string: - * - * type SomeType = { - * key1: string; - * key2: string; - * key3: number; - * } - * - * const stringKeys = KeysOfType - * - * (stringKeys = key1 | key2) - * - * @TODO Since TypeScript v4.5.5 this util is no longer working as expected. - * Refactoring is needed before a couple of typecasts (as unknown as number) can be removed. - */ -export type KeysOfType = { - [P in keyof T]: B extends true - ? T[P] extends U - ? U extends T[P] - ? P - : never - : never - : T[P] extends U - ? P - : never; -}[keyof T]; - -/** - * This returns a filtered type that only contains the keys of the specified type. - * - * type SomeType = { - * key1: string; - * key2: string; - * key3: number; - * } - * - * const TypeWithJustStringKeys = PickByType - * - * (TypeWithJustStringKeys = { - * key1: string; - * key2: string; - * }) - * - */ -export type PickByType = Pick>; - export type Metric = { values: T[]; last_value: T; diff --git a/packages/common/src/types/inline-charts.ts b/packages/common/src/types/inline-charts.ts index 192d79c072..706c0893c4 100644 --- a/packages/common/src/types/inline-charts.ts +++ b/packages/common/src/types/inline-charts.ts @@ -82,9 +82,10 @@ export type DonutMetricPropertyConfig< export type AgeDemographicConfiguration< S extends DataScopeKey, - M extends MetricKeys + M extends MetricKeys, + K extends string > = { - accessibilityKey: string; + accessibilityKey: K; sourceKey: string; text: string; leftMetricProperty: MetricProperty>; From f22290b0bcfbeec3ab4865adf5e7a91fbc0403d5 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard25 <98813868+VWSCoronaDashboard25@users.noreply.github.com> Date: Tue, 19 Jul 2022 08:41:24 +0200 Subject: [PATCH 07/12] feature: archive obsolete vaccine graphs (#4324) * feature: archive obsolete vaccine graphs closes: COR-901 * feature: archive obsolete vaccine graphs closes: COR-901 * remove InView as lazy loading is not needed in the archived section * removed import inview Co-authored-by: VWSCoronaDashboard25 Co-authored-by: VWSCoronaDashboard21 --- .../app/src/pages/landelijk/vaccinaties.tsx | 160 +++++++++--------- 1 file changed, 83 insertions(+), 77 deletions(-) diff --git a/packages/app/src/pages/landelijk/vaccinaties.tsx b/packages/app/src/pages/landelijk/vaccinaties.tsx index edf8091b0f..6801228b8c 100644 --- a/packages/app/src/pages/landelijk/vaccinaties.tsx +++ b/packages/app/src/pages/landelijk/vaccinaties.tsx @@ -6,7 +6,6 @@ import { useState } from 'react'; import { isDefined } from 'ts-is-present'; import { ChartTile, - InView, PageInformationBlock, TileList, TimeSeriesChart, @@ -288,37 +287,6 @@ const VaccinationPage = (props: StaticProps) => { } /> - - - - ) => { }} values={data.vaccine_coverage_per_age_group.values} /> - - ) => { } /> {hasHideArchivedCharts && ( - + <> + + + + + + + + + + ) => { }} values={data.vaccine_coverage_per_age_group_archived.values} /> + ) => { ]} /> - + )} From 02fedb84e63ac2b4d643c9ed56c984cadf87b989 Mon Sep 17 00:00:00 2001 From: VWSCoronaDashboard22 <93981265+VWSCoronaDashboard22@users.noreply.github.com> Date: Tue, 19 Jul 2022 09:00:32 +0200 Subject: [PATCH 08/12] Regrouped non tooltip labels (#4325) --- .../app/src/domain/variants/variants-over-time.tsx | 13 ++++--------- .../gemeente/[code]/positief-geteste-mensen.tsx | 8 +++----- .../src/pages/landelijk/positief-geteste-mensen.tsx | 6 +++--- .../src/pages/landelijk/verdenkingen-huisartsen.tsx | 2 +- .../[code]/positief-geteste-mensen.tsx | 10 +++------- packages/cms/src/lokalize/key-mutations.csv | 9 +++++++++ 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/packages/app/src/domain/variants/variants-over-time.tsx b/packages/app/src/domain/variants/variants-over-time.tsx index 9531fb21d2..ce55b61bcd 100644 --- a/packages/app/src/domain/variants/variants-over-time.tsx +++ b/packages/app/src/domain/variants/variants-over-time.tsx @@ -36,7 +36,7 @@ export function VariantsOverTime({ const underReportedLegendItem: LegendItem = { shape: 'square', color: colors.data.underReported, - label: text.legend_niet_compleet_label, + label: text.labels.niet_compleet, }; const alwaysEnabled: keyof VariantChartValue | [] = useMemo(() => [], []); @@ -60,16 +60,11 @@ export function VariantsOverTime({ { type: 'invisible', metricProperty: 'sample_size', - label: text.tooltip_labels.totaal_monsters, + label: text.labels.totaal_monsters, isPercentage: false, }, ] as SeriesConfig, - [ - seriesConfig, - alwaysEnabled, - compareList, - text.tooltip_labels.totaal_monsters, - ] + [seriesConfig, alwaysEnabled, compareList, text.labels.totaal_monsters] ); /* Static legend contains only the inaccurate item */ @@ -110,7 +105,7 @@ export function VariantsOverTime({ { start: underReportedDateStart, end: Infinity, - label: text.legend_niet_compleet_label, + label: text.labels.niet_compleet, shortLabel: text.tooltip_labels.niet_compleet, }, ], diff --git a/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx b/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx index 5531f15e13..9225a4f4b6 100644 --- a/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx +++ b/packages/app/src/pages/gemeente/[code]/positief-geteste-mensen.tsx @@ -53,9 +53,7 @@ export { getStaticPaths } from '~/static-paths/gm'; import { getLastInsertionDateOfPage } from '~/utils/get-last-insertion-date-of-page'; -const pageMetrics = [ - 'tested_overall', -]; +const pageMetrics = ['tested_overall']; export const getStaticProps = createGetStaticProps( ({ locale }: { locale: keyof Languages }) => @@ -264,13 +262,13 @@ const PositivelyTestedPeople = (props: StaticProps) => { { type: 'line', metricProperty: 'infected_moving_average', - label: textShared.tooltip_labels.infected_moving_average, + label: textShared.labels.infected_moving_average, color: colors.data.primary, }, { type: 'bar', metricProperty: 'infected', - label: textShared.tooltip_labels.infected, + label: textShared.labels.infected, color: colors.data.primary, }, ]} diff --git a/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx b/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx index 7edb1be8ce..9d16ad9799 100644 --- a/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx +++ b/packages/app/src/pages/landelijk/positief-geteste-mensen.tsx @@ -227,20 +227,20 @@ const PositivelyTestedPeople = (props: StaticProps) => { { type: 'line', metricProperty: 'infected_moving_average', - label: textShared.tooltip_labels.infected_moving_average, + label: textShared.labels.infected_moving_average, color: colors.data.primary, }, { type: 'bar', metricProperty: 'infected', - label: textShared.tooltip_labels.infected, + label: textShared.labels.infected, color: colors.data.primary, }, ]} dataOptions={{ forcedMaximumValue: 150000, outOfBoundsConfig: { - label: textShared.tooltip_labels.infected_out_of_bounds, + label: textShared.labels.infected_out_of_bounds, tooltipLabel: textShared.tooltip_labels.annotations, checkIsOutofBounds: ( x: NlTestedOverallValue, diff --git a/packages/app/src/pages/landelijk/verdenkingen-huisartsen.tsx b/packages/app/src/pages/landelijk/verdenkingen-huisartsen.tsx index d64c8c206d..f34686c65f 100644 --- a/packages/app/src/pages/landelijk/verdenkingen-huisartsen.tsx +++ b/packages/app/src/pages/landelijk/verdenkingen-huisartsen.tsx @@ -131,7 +131,7 @@ const SuspectedPatients = (props: StaticProps) => { { type: 'area', metricProperty: 'covid_symptoms_per_100k', - label: text.tooltip_labels.covid_klachten, + label: text.labels.covid_klachten, color: colors.data.primary, }, ]} diff --git a/packages/app/src/pages/veiligheidsregio/[code]/positief-geteste-mensen.tsx b/packages/app/src/pages/veiligheidsregio/[code]/positief-geteste-mensen.tsx index ae86ee3a84..3d60f6af9e 100644 --- a/packages/app/src/pages/veiligheidsregio/[code]/positief-geteste-mensen.tsx +++ b/packages/app/src/pages/veiligheidsregio/[code]/positief-geteste-mensen.tsx @@ -53,11 +53,7 @@ import { import { getLastInsertionDateOfPage } from '~/utils/get-last-insertion-date-of-page'; -const pageMetrics = [ - 'g_number', - 'tested_ggd', - 'tested_overall', -]; +const pageMetrics = ['g_number', 'tested_ggd', 'tested_overall']; export { getStaticPaths } from '~/static-paths/vr'; @@ -235,13 +231,13 @@ const PositivelyTestedPeople = (props: StaticProps) => { { type: 'line', metricProperty: 'infected_moving_average', - label: textShared.tooltip_labels.infected_moving_average, + label: textShared.labels.infected_moving_average, color: colors.data.primary, }, { type: 'bar', metricProperty: 'infected', - label: textShared.tooltip_labels.infected, + label: textShared.labels.infected, color: colors.data.primary, }, ]} diff --git a/packages/cms/src/lokalize/key-mutations.csv b/packages/cms/src/lokalize/key-mutations.csv index a7c6419a8a..a53943a175 100755 --- a/packages/cms/src/lokalize/key-mutations.csv +++ b/packages/cms/src/lokalize/key-mutations.csv @@ -1 +1,10 @@ timestamp,action,key,document_id,move_to +2022-07-18T09:23:55.208Z,move,pages.variantsPage.nl.varianten_over_tijd.tooltip_labels.totaal_monsters,JtApmkyAs5Fi3aTDStcdtl,pages.variantsPage.nl.varianten_over_tijd.labels.totaal_monsters +2022-07-18T09:32:08.990Z,add,pages.in_variantsPage.shared.varianten_over_tijd_grafiek.labels,eqFl28ScTYzTImF144LuNw,__ +2022-07-18T09:32:09.994Z,add,pages.variantsPage.nl.varianten_over_tijd.labels.niet_compleet,rqPl4RDgHRhhQeuZ9blFFw,__ +2022-07-18T09:32:09.994Z,delete,pages.in_variantsPage.shared.varianten_over_tijd_grafiek.labels.niet_compleet,eqFl28ScTYzTImF144Lf2E,__ +2022-07-18T09:32:09.995Z,delete,pages.variantsPage.nl.varianten_over_tijd.legend_niet_compleet_label,0Fi2ZNty1p5jcXUiTmaRVr,__ +2022-07-18T09:35:53.376Z,add,pages.positiveTestsPage.shared.labels.infected,rqPl4RDgHRhhQeuZ9blice,__ +2022-07-18T09:35:54.396Z,add,pages.positiveTestsPage.shared.labels.infected_moving_average,rqPl4RDgHRhhQeuZ9bliyu,__ +2022-07-18T09:37:37.631Z,add,pages.positiveTestsPage.shared.labels.infected_out_of_bounds,M1X5uhtA0L6eSCc3lIjw3R,__ +2022-07-18T09:40:19.115Z,add,common.verdenkingen_huisartsen.labels.covid_klachten,M1X5uhtA0L6eSCc3lIkDll,__ From 3f1d33cfacaacfaaa947a46fdc894c6c7f439b73 Mon Sep 17 00:00:00 2001 From: L R <107395524+VWSCoronaDashboard26@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:26:14 +0200 Subject: [PATCH 09/12] feature/COR-936-vaccination-page-table (#4326) * feat (WIP): added VaccinatedPeopleTile component " added added NarrowVaccinatedPeopleTable component added WideVaccinatedPeopleTable component added shared table components for the new tables * feat: updated NarrowVaccinatedPeopleTable component to reduce layout issues; updated WideVaccinatedPeopleTable component to reduce layout issues; added new styled Row component; * feat: fixed layout issues; * feat: updated small layout inconsistencies; * feat: finalised layout issues; added Sanity keys; used proper data; * feat: updated various components for TypeScript issues; updated Sanity keys; wrap-up; * feat: small consistency fixes; * feat: updated code base with pull request comments; * change descriptionFooter Co-authored-by: VWSCoronaDashboard26 Co-authored-by: VWSCoronaDashboard21 --- .../components/index.tsx | 1 + .../narrow-vaccine-campaign-table.tsx | 131 ++++++++++++++++++ .../components/shared-table-components.tsx | 49 +++++++ .../wide-vaccine-campaign-table.tsx | 125 +++++++++++++++++ .../vaccine/vaccine-campaigns-tile/types.ts | 10 ++ .../vaccine-campaigns-tile.tsx | 63 +++++++++ .../app/src/pages/landelijk/vaccinaties.tsx | 24 +++- packages/cms/src/lokalize/key-mutations.csv | 19 +++ packages/common/src/types/data.ts | 23 +++ 9 files changed, 444 insertions(+), 1 deletion(-) create mode 100644 packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/index.tsx create mode 100644 packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/narrow-vaccine-campaign-table.tsx create mode 100644 packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/shared-table-components.tsx create mode 100644 packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/wide-vaccine-campaign-table.tsx create mode 100644 packages/app/src/domain/vaccine/vaccine-campaigns-tile/types.ts create mode 100644 packages/app/src/domain/vaccine/vaccine-campaigns-tile/vaccine-campaigns-tile.tsx diff --git a/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/index.tsx b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/index.tsx new file mode 100644 index 0000000000..a1abdaf37b --- /dev/null +++ b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/index.tsx @@ -0,0 +1 @@ +export * from './shared-table-components'; diff --git a/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/narrow-vaccine-campaign-table.tsx b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/narrow-vaccine-campaign-table.tsx new file mode 100644 index 0000000000..b343712860 --- /dev/null +++ b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/narrow-vaccine-campaign-table.tsx @@ -0,0 +1,131 @@ +import css from '@styled-system/css'; +import { useCollapsible } from '~/utils/use-collapsible'; +import { useIntl } from '~/intl'; +import { Cell, HeaderCell, Row, StyledTable } from '.'; +import { Markdown } from '~/components'; +import { + VaccineCampaign, + VaccineCampaignDescriptions, + VaccineCampaignHeaders, +} from '../types'; + +interface NarrowVaccineCampaignTableProps { + campaigns: VaccineCampaign[]; + campaignDescriptions: VaccineCampaignDescriptions; + headers: VaccineCampaignHeaders; +} + +export const NarrowVaccineCampaignTable = ({ + campaigns, + campaignDescriptions, + headers, +}: NarrowVaccineCampaignTableProps) => { + return ( + + + + {headers.vaccine} + + + + + {campaigns.map((campaign, index) => ( + + ))} + + + ); +}; + +interface VaccineCampaignRowProps { + campaign: VaccineCampaign; + campaignDescriptions: VaccineCampaignDescriptions; + headers: VaccineCampaignHeaders; + isFirst: boolean; + isLast: boolean; +} + +const VaccineCampaignRow = ({ + campaign, + campaignDescriptions, + headers, + isFirst, + isLast, +}: VaccineCampaignRowProps) => { + const { formatNumber } = useIntl(); + const collapsible = useCollapsible({ isOpen: isFirst }); + const isOpen = collapsible.isOpen; + + return ( + collapsible.toggle()}> + + + + + + {campaign.vaccine_campaign_name_nl} + + + + {collapsible.button()} + + + + + + {headers.last_week}:{' '} + {isOpen ? ( + + {formatNumber(campaign.vaccine_administered_last_week)} + + ) : ( + <>{formatNumber(campaign.vaccine_administered_last_week)} + )} + + + + + + {headers.total}:{' '} + {isOpen ? ( + + {formatNumber(campaign.vaccine_administered_total)} + + ) : ( + <>{formatNumber(campaign.vaccine_administered_total)} + )} + + + + + + {collapsible.content( + + )} + + + + + + + ); +}; diff --git a/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/shared-table-components.tsx b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/shared-table-components.tsx new file mode 100644 index 0000000000..c5e952a319 --- /dev/null +++ b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/shared-table-components.tsx @@ -0,0 +1,49 @@ +import { colors } from '@corona-dashboard/common'; +import css from '@styled-system/css'; +import styled from 'styled-components'; + +export const StyledTable = styled.table( + css({ + borderCollapse: 'collapse', + width: '100%', + }) +); + +export const HeaderCell = styled.th<{ mobile?: boolean }>((x) => + css({ + textAlign: 'left', + fontSize: 14, + fontWeight: 'bold', + px: 3, + py: x.mobile ? 3 : 2, + verticalAlign: 'top', + width: !x.mobile ? '33%' : undefined, + }) +); + +export const Cell = styled.td<{ + alignRight?: boolean; + isOpen?: boolean; + mobile?: boolean; +}>((x) => + css({ + float: x.alignRight ? 'right' : undefined, + px: 3, + py: x.mobile ? 2 : 4, + verticalAlign: 'top', + width: !x.mobile ? '33%' : undefined, + }) +); + +export const Row = styled.tr<{ + isLast: boolean; + isOpen?: boolean; +}>((x) => + css({ + background: x.isOpen ? colors.data.fill : undefined, + borderTop: '1px solid', + borderBottom: x.isOpen || x.isLast ? '1px solid' : undefined, + borderColor: x.isOpen ? colors.blue : colors.lightGray, + cursor: 'pointer', + }) +); diff --git a/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/wide-vaccine-campaign-table.tsx b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/wide-vaccine-campaign-table.tsx new file mode 100644 index 0000000000..cb5766f361 --- /dev/null +++ b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/components/wide-vaccine-campaign-table.tsx @@ -0,0 +1,125 @@ +import css from '@styled-system/css'; +import { useCollapsible } from '~/utils/use-collapsible'; +import { useIntl } from '~/intl'; +import { Cell, HeaderCell, Row, StyledTable } from '.'; +import { Box } from '~/components/base'; +import { Markdown } from '~/components'; +import { + VaccineCampaign, + VaccineCampaignDescriptions, + VaccineCampaignHeaders, +} from '../types'; + +interface WideVaccineCampaignTableProps { + campaigns: VaccineCampaign[]; + campaignDescriptions: VaccineCampaignDescriptions; + headers: VaccineCampaignHeaders; +} + +export const WideVaccineCampaignTable = ({ + campaigns, + campaignDescriptions, + headers, +}: WideVaccineCampaignTableProps) => { + return ( + + + + {headers.vaccine} + {headers.last_week} + {headers.total} + + + + + {campaigns.map((campaign, index) => ( + + ))} + + + ); +}; + +interface VaccineCampaignRowProps { + campaign: VaccineCampaign; + campaignDescriptions: VaccineCampaignDescriptions; + isFirst: boolean; + isLast: boolean; +} + +const VaccineCampaignRow = ({ + campaign, + campaignDescriptions, + isFirst, + isLast, +}: VaccineCampaignRowProps) => { + const { formatNumber } = useIntl(); + const collapsible = useCollapsible({ isOpen: isFirst }); + const isOpen = collapsible.isOpen; + + return ( + collapsible.toggle()}> + + + + + + {campaign.vaccine_campaign_name_nl} + + + + {isOpen ? ( + + {formatNumber(campaign.vaccine_administered_last_week)} + + ) : ( + <>{formatNumber(campaign.vaccine_administered_last_week)} + )} + + + + + {isOpen ? ( + + {formatNumber(campaign.vaccine_administered_total)} + + ) : ( + <>{formatNumber(campaign.vaccine_administered_total)} + )} + + {collapsible.button()} + + + + + + + {collapsible.content( + + )} + + + + + + + ); +}; diff --git a/packages/app/src/domain/vaccine/vaccine-campaigns-tile/types.ts b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/types.ts new file mode 100644 index 0000000000..413782f155 --- /dev/null +++ b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/types.ts @@ -0,0 +1,10 @@ +export interface VaccineCampaign { + vaccine_campaign_order: number; + vaccine_campaign_name_nl: string; + vaccine_campaign_name_en: string; + vaccine_administered_total: number; + vaccine_administered_last_week: number; +} + +export type VaccineCampaignDescriptions = Record; +export type VaccineCampaignHeaders = Record; diff --git a/packages/app/src/domain/vaccine/vaccine-campaigns-tile/vaccine-campaigns-tile.tsx b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/vaccine-campaigns-tile.tsx new file mode 100644 index 0000000000..2705261f23 --- /dev/null +++ b/packages/app/src/domain/vaccine/vaccine-campaigns-tile/vaccine-campaigns-tile.tsx @@ -0,0 +1,63 @@ +import { useBreakpoints } from '~/utils/use-breakpoints'; +import { ChartTile, Markdown, MetadataProps } from '~/components'; +import { Text } from '~/components/typography'; +import { NarrowVaccineCampaignTable } from './components/narrow-vaccine-campaign-table'; +import { WideVaccineCampaignTable } from './components/wide-vaccine-campaign-table'; +import { + VaccineCampaign, + VaccineCampaignDescriptions, + VaccineCampaignHeaders, +} from './types'; +import { Box } from '~/components/base'; + +interface VaccineCampaignsTileProps { + title: string; + description: string; + descriptionFooter: string; + metadata: MetadataProps; + headers: VaccineCampaignHeaders; + campaigns: VaccineCampaign[]; + campaignDescriptions: VaccineCampaignDescriptions; +} + +export const VaccineCampaignsTile = ({ + title, + headers, + campaigns, + campaignDescriptions, + description, + descriptionFooter, + metadata, +}: VaccineCampaignsTileProps) => { + const breakpoints = useBreakpoints(); + + const sortedCampaigns = campaigns.sort( + (campaignA, campaignB) => + campaignA.vaccine_campaign_order - campaignB.vaccine_campaign_order + ); + + return ( + <> + + {breakpoints.sm ? ( + + ) : ( + + )} + + + + + + + + ); +}; diff --git a/packages/app/src/pages/landelijk/vaccinaties.tsx b/packages/app/src/pages/landelijk/vaccinaties.tsx index 6801228b8c..ca41c2392e 100644 --- a/packages/app/src/pages/landelijk/vaccinaties.tsx +++ b/packages/app/src/pages/landelijk/vaccinaties.tsx @@ -27,6 +27,7 @@ import { VaccineStockPerSupplierChart, BoosterShotCoveragePerAgeGroup, } from '~/domain/vaccine'; +import { VaccineCampaignsTile } from '~/domain/vaccine/vaccine-campaigns-tile/vaccine-campaigns-tile'; import { useIntl } from '~/intl'; import { Languages } from '~/locale'; import { @@ -102,6 +103,8 @@ export const getStaticProps = createGetStaticProps( 'vaccine_stock', 'vaccine_vaccinated_or_support', 'vaccine_coverage_per_age_group_estimated', + 'vaccine_campaigns', + 'vaccine_planned', 'booster_coverage', 'booster_shot_administered', 'repeating_shot_administered' @@ -178,7 +181,7 @@ const VaccinationPage = (props: StaticProps) => { lastGenerated, administrationData, } = props; - const { commonTexts } = useIntl(); + const { commonTexts, formatNumber } = useIntl(); const { metadataTexts, textNl } = pageText; const { formatPercentageAsNumber } = useFormatLokalizePercentage(); const [hasHideArchivedCharts, setHideArchivedCharts] = @@ -287,6 +290,25 @@ const VaccinationPage = (props: StaticProps) => { } /> + + Date: Wed, 20 Jul 2022 10:31:10 +0200 Subject: [PATCH 10/12] Replace konva-node with konva and remove it (#4327) * feat: replace konva-node with konva en remove it * feat: backtick to regular conditional string --- packages/app/package.json | 1 - .../src/pages/api/choropleth/[...param].ts | 3 +- yarn.lock | 100 +++--------------- 3 files changed, 18 insertions(+), 86 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index e2f304fee1..6f9b8c052b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -43,7 +43,6 @@ "http-proxy-middleware": "^2.0.1", "intercept-stdout": "^0.1.2", "konva": "^7.2.5", - "konva-node": "^0.11.2", "lodash": "^4.17.21", "match-sorter": "^6.3.1", "next": "^12.0.4", diff --git a/packages/app/src/pages/api/choropleth/[...param].ts b/packages/app/src/pages/api/choropleth/[...param].ts index 53569ba2f6..65b5145937 100644 --- a/packages/app/src/pages/api/choropleth/[...param].ts +++ b/packages/app/src/pages/api/choropleth/[...param].ts @@ -2,7 +2,7 @@ import { assert, vrData } from '@corona-dashboard/common'; import { geoMercator } from 'd3-geo'; import fs from 'fs'; import hash from 'hash-sum'; -import Konva from 'konva-node'; +import Konva from 'konva'; import { NextApiRequest, NextApiResponse } from 'next/dist/shared/lib/utils'; import path from 'path'; import sanitize from 'sanitize-filename'; @@ -193,6 +193,7 @@ async function generateChoroplethImage( const featureProps = getFeatureProps(map, fColor, dataOptions, dataConfig); const stage = new Konva.Stage({ + container: selectedCode ? selectedCode : '', width, height, }); diff --git a/yarn.lock b/yarn.lock index 254b688592..394be9eb4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2630,7 +2630,6 @@ __metadata: jsdom: ^18.1.1 jsdom-global: ^3.0.2 konva: ^7.2.5 - konva-node: ^0.11.2 lint-staged: ^11.2.6 lodash: ^4.17.21 lodash-webpack-plugin: ^0.11.6 @@ -3311,25 +3310,6 @@ __metadata: languageName: node linkType: hard -"@mapbox/node-pre-gyp@npm:^1.0.0": - version: 1.0.5 - resolution: "@mapbox/node-pre-gyp@npm:1.0.5" - dependencies: - detect-libc: ^1.0.3 - https-proxy-agent: ^5.0.0 - make-dir: ^3.1.0 - node-fetch: ^2.6.1 - nopt: ^5.0.0 - npmlog: ^4.1.2 - rimraf: ^3.0.2 - semver: ^7.3.4 - tar: ^6.1.0 - bin: - node-pre-gyp: bin/node-pre-gyp - checksum: c1f182a707f5782e47b77a76e9d6a073fb043999cf9ad965bc86732e88db27ad00926d1602918edb7105f05cde67871b84a178ee9844eb742319ade419636675 - languageName: node - linkType: hard - "@mdx-js/react@npm:^1.0.0": version: 1.6.22 resolution: "@mdx-js/react@npm:1.6.22" @@ -7423,6 +7403,15 @@ __metadata: languageName: node linkType: hard +"@types/react-reconciler@npm:~0.26.2": + version: 0.26.7 + resolution: "@types/react-reconciler@npm:0.26.7" + dependencies: + "@types/react": "*" + checksum: 4122d2b08580f775d0aeae9bd10b68248f894096ed14c0ebbc143ef712e21b159e89d0c628bd95dd3329947fc1ee94a0cb1d2d32b32b1d5d225e70030e91e58f + languageName: node + linkType: hard + "@types/react-test-renderer@npm:>=16.9.0, @types/react-test-renderer@npm:^17.0.1": version: 17.0.1 resolution: "@types/react-test-renderer@npm:17.0.1" @@ -10637,18 +10626,6 @@ __metadata: languageName: node linkType: hard -"canvas@npm:^2.5.0": - version: 2.8.0 - resolution: "canvas@npm:2.8.0" - dependencies: - "@mapbox/node-pre-gyp": ^1.0.0 - nan: ^2.14.0 - node-gyp: latest - simple-get: ^3.0.3 - checksum: 4cc909f63eaf88d22f9164601903745abcc6ccb7f70090b9389dc2cb68cbf139c220dbd75837e6d04602ff122b44a2eb17413bca850f9c6c602f74f1f0f1cc3f - languageName: node - linkType: hard - "capital-case@npm:^1.0.4": version: 1.0.4 resolution: "capital-case@npm:1.0.4" @@ -12487,15 +12464,6 @@ __metadata: languageName: node linkType: hard -"decompress-response@npm:^4.2.0": - version: 4.2.1 - resolution: "decompress-response@npm:4.2.1" - dependencies: - mimic-response: ^2.0.0 - checksum: 4e783ca4dfe9417354d61349750fe05236f565a4415a6ca20983a311be2371debaedd9104c0b0e7b36e5f167aeaae04f84f1a0b3f8be4162f1d7d15598b8fdba - languageName: node - linkType: hard - "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -12727,15 +12695,6 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^1.0.3": - version: 1.0.3 - resolution: "detect-libc@npm:1.0.3" - bin: - detect-libc: ./bin/detect-libc.js - checksum: daaaed925ffa7889bd91d56e9624e6c8033911bb60f3a50a74a87500680652969dbaab9526d1e200a4c94acf80fc862a22131841145a0a8482d60a99c24f4a3e - languageName: node - linkType: hard - "detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.1": version: 2.0.1 resolution: "detect-libc@npm:2.0.1" @@ -17648,17 +17607,7 @@ __metadata: languageName: node linkType: hard -"konva-node@npm:^0.11.2": - version: 0.11.2 - resolution: "konva-node@npm:0.11.2" - dependencies: - canvas: ^2.5.0 - konva: ^7 - checksum: 11d99492c653d6e52c370af5831a4dce60b6cabbf81016806fa58c8563174272db39940b8d638fc29f83f949cf5934471ed7c1d3d1d6c3bad60152450f308fd2 - languageName: node - linkType: hard - -"konva@npm:^7, konva@npm:^7.2.5": +"konva@npm:^7.2.5": version: 7.2.5 resolution: "konva@npm:7.2.5" checksum: 795ab73af38307243f867be3dab122ec6a5c37bc7f44a20359baf2bf6e1d5cd8a9ce9d7e3b69b21dd6429615b8f96254858e346e8ccb4b5fff8be6c5b60cd12d @@ -18785,13 +18734,6 @@ __metadata: languageName: node linkType: hard -"mimic-response@npm:^2.0.0": - version: 2.1.0 - resolution: "mimic-response@npm:2.1.0" - checksum: 014fad6ab936657e5f2f48bd87af62a8e928ebe84472aaf9e14fec4fcb31257a5edff77324d8ac13ddc6685ba5135cf16e381efac324e5f174fb4ddbf902bf07 - languageName: node - linkType: hard - "mimic-response@npm:^3.1.0": version: 3.1.0 resolution: "mimic-response@npm:3.1.0" @@ -19034,7 +18976,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.12.1, nan@npm:^2.14.0": +"nan@npm:^2.12.1": version: 2.15.0 resolution: "nan@npm:2.15.0" dependencies: @@ -22704,16 +22646,17 @@ __metadata: linkType: hard "react-konva@npm:^17.0.2-5": - version: 17.0.2-5 - resolution: "react-konva@npm:17.0.2-5" + version: 17.0.2-6 + resolution: "react-konva@npm:17.0.2-6" dependencies: + "@types/react-reconciler": ~0.26.2 react-reconciler: ~0.26.2 scheduler: ^0.20.2 peerDependencies: konva: ^8.0.1 || ^7.2.5 react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 614522753fe95322fc022569cd95443eacfc1b9d2d84c0bb4ea40ce6cdce9b7c5843268e67ebef7cdb6d50ab08b8a5038ec760c3977a105e233bcceb8408de56 + checksum: 5e868f6941090243c998f2817fbc9f031f60c83e236dc3f6328c904114582cfe281a08df9b5146b3339f6e1ccf30f3707d03de85fd534fb42fbe0ee6c6531b0c languageName: node linkType: hard @@ -24439,17 +24382,6 @@ __metadata: languageName: node linkType: hard -"simple-get@npm:^3.0.3": - version: 3.1.1 - resolution: "simple-get@npm:3.1.1" - dependencies: - decompress-response: ^4.2.0 - once: ^1.3.1 - simple-concat: ^1.0.0 - checksum: 80195e70bf171486e75c31e28e5485468195cc42f85940f8b45c4a68472160144d223eb4d07bc82ef80cb974b7c401db021a540deb2d34ac4b3b8883da2d6401 - languageName: node - linkType: hard - "simple-get@npm:^4.0.0, simple-get@npm:^4.0.1": version: 4.0.1 resolution: "simple-get@npm:4.0.1" @@ -25610,7 +25542,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.2": +"tar@npm:^6.0.2, tar@npm:^6.1.2": version: 6.1.11 resolution: "tar@npm:6.1.11" dependencies: From 13aeaa7d2a7e05af80d0d6181543cc634c1d1fde Mon Sep 17 00:00:00 2001 From: MN <97020799+VWSCoronaDashboard24@users.noreply.github.com> Date: Thu, 21 Jul 2022 11:11:48 +0200 Subject: [PATCH 11/12] Revert "COR-54 Refactor types (#4305)" (#4329) This reverts commit 5c4d3c649727b2d1d9a29462c83787127d0273c1. --- .../age-demographic/age-demographic-chart.tsx | 22 +++---- .../age-demographic-coordinates.ts | 21 +++---- .../age-demographic-tooltip-content.tsx | 21 +++---- .../age-demographic/age-demographic.tsx | 6 +- .../components/canvas-choropleth-map.tsx | 2 +- .../app/src/components/choropleth/index.tsx | 9 ++- .../choropleth/logic/create-data-config.ts | 4 +- .../src/components/choropleth/logic/types.ts | 57 +++++------------ .../logic/use-choropleth-tooltip.ts | 38 ++++------- .../choropleth/logic/use-fill-color.ts | 13 +--- .../src/components/choropleth/logic/utils.ts | 5 +- .../tooltips/choropleth-tooltip.tsx | 18 ++---- .../components/cms/inline-age-demographic.tsx | 10 ++- .../src/components/cms/inline-choropleth.tsx | 7 +-- .../app/src/components/cms/rich-content.tsx | 3 +- packages/app/src/components/pie-chart.tsx | 17 +++-- packages/app/src/components/spark-line.tsx | 17 ++--- .../time-series-chart/components/axes.tsx | 26 ++++---- .../tooltip/tooltip-series-list-items.tsx | 63 ++++++++++--------- .../components/week-numbers.tsx | 9 +-- .../logic/use-format-series-value.ts | 9 ++- .../time-series-chart/time-series-chart.tsx | 4 +- packages/app/src/components/tooltip.tsx | 7 +-- .../behavior/behavior-choropleths-tile.tsx | 9 ++- .../behavior/behavior-line-chart-tile.tsx | 18 +++--- .../topical/mini-tile-selector-layout.tsx | 3 +- ...e-vaccine-coverage-percentage-formatter.ts | 5 +- .../vaccine-coverage-choropleth-per-gm.tsx | 8 ++- packages/app/src/pages/index.tsx | 2 +- .../app/src/pages/veiligheidsregio/index.tsx | 21 +++---- .../utils/api/strip-trailing-null-values.ts | 2 +- packages/common/src/types/choropleth.ts | 53 ++++++++++++++++ packages/common/src/types/inline-charts.ts | 5 +- 33 files changed, 253 insertions(+), 261 deletions(-) diff --git a/packages/app/src/components/age-demographic/age-demographic-chart.tsx b/packages/app/src/components/age-demographic/age-demographic-chart.tsx index d5960da447..8dd6c7a8ed 100644 --- a/packages/app/src/components/age-demographic/age-demographic-chart.tsx +++ b/packages/app/src/components/age-demographic/age-demographic-chart.tsx @@ -1,4 +1,4 @@ -import { Color, colors } from '@corona-dashboard/common'; +import { Color, colors, KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import { AxisBottom, TickRendererProps } from '@visx/axis'; import { GridColumns } from '@visx/grid'; @@ -32,8 +32,8 @@ interface AgeDemographicChartProps { onMouseMoveBar: (value: T, event: MouseEvent) => void; onMouseLeaveBar: () => void; onKeyInput: (event: KeyboardEvent) => void; - rightMetricProperty: keyof T; - leftMetricProperty: keyof T; + rightMetricProperty: KeysOfType; + leftMetricProperty: KeysOfType; rightColor: Color; leftColor: Color; maxDisplayValue?: number; @@ -88,18 +88,16 @@ export function AgeDemographicChart({ const annotations = useAccessibilityAnnotations(accessibility); - const getNumberValue = (data: T, key: keyof T): number => { - const value = data[key]; - return typeof value === 'number' ? value : 0; - }; - const hasClippedValue = !!values.find( (value) => getIsClipped( - getNumberValue(value, leftMetricProperty), + value[leftMetricProperty] as unknown as number, maxDisplayValue ) || - getIsClipped(getNumberValue(value, rightMetricProperty), maxDisplayValue) + getIsClipped( + value[rightMetricProperty] as unknown as number, + maxDisplayValue + ) ); return ( @@ -193,12 +191,12 @@ export function AgeDemographicChart({ const rightBarWidth = rightPoint(value); const isClippedLeftGroup = getIsClipped( - getNumberValue(value, leftMetricProperty), + value[leftMetricProperty] as unknown as number, maxDisplayValue ); const isClippedRightGroup = getIsClipped( - getNumberValue(value, rightMetricProperty), + value[rightMetricProperty] as unknown as number, maxDisplayValue ); diff --git a/packages/app/src/components/age-demographic/age-demographic-coordinates.ts b/packages/app/src/components/age-demographic/age-demographic-coordinates.ts index c04fb2d9a5..0b780a405a 100644 --- a/packages/app/src/components/age-demographic/age-demographic-coordinates.ts +++ b/packages/app/src/components/age-demographic/age-demographic-coordinates.ts @@ -1,3 +1,4 @@ +import { KeysOfType } from '@corona-dashboard/common'; import { localPoint } from '@visx/event'; import { scaleBand, scaleLinear, ScaleTypeToD3Scale } from '@visx/scale'; import { MouseEvent, useMemo } from 'react'; @@ -41,8 +42,8 @@ export function useAgeDemographicCoordinates< T extends AgeDemographicDefaultValue >( data: { values: T[] }, - rightMetricProperty: keyof T, - leftMetricProperty: keyof T, + rightMetricProperty: KeysOfType, + leftMetricProperty: KeysOfType, maxDisplayValue?: number ) { const [ref, { width = 840 }] = useResizeObserver(); @@ -78,8 +79,8 @@ function calculateAgeDemographicCoordinates< T extends AgeDemographicDefaultValue >( data: { values: T[] }, - rightMetricProperty: keyof T, - leftMetricProperty: keyof T, + rightMetricProperty: KeysOfType, + leftMetricProperty: KeysOfType, isSmallScreen: boolean, parentWidth: number, isExtraSmallScreen: boolean, @@ -117,14 +118,10 @@ function calculateAgeDemographicCoordinates< const yMax = height - margin.top - margin.bottom; // Helper functions to retrieve parts of the values - const getLeftValue = (value: T) => { - const leftValue = value[leftMetricProperty]; - return typeof leftValue === 'number' ? leftValue : 0; - }; - const getRightValue = (value: T) => { - const rightValue = value[rightMetricProperty]; - return typeof rightValue === 'number' ? rightValue : 0; - }; + const getLeftValue = (value: T) => + value[leftMetricProperty] as unknown as number; + const getRightValue = (value: T) => + value[rightMetricProperty] as unknown as number; const ageGroupRange = (value: T) => value.age_group_range; // Scales to map between values and coordinates diff --git a/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx b/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx index 45ba7eea45..42f11af3fe 100644 --- a/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx +++ b/packages/app/src/components/age-demographic/age-demographic-tooltip-content.tsx @@ -1,4 +1,4 @@ -import type { Color } from '@corona-dashboard/common'; +import type { Color, KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import styled from 'styled-components'; import { BoldText } from '~/components/typography'; @@ -11,8 +11,8 @@ interface AgeDemographicTooltipContentProps< T extends AgeDemographicDefaultValue > { value: T; - rightMetricProperty: keyof T; - leftMetricProperty: keyof T; + rightMetricProperty: KeysOfType; + leftMetricProperty: KeysOfType; rightColor: Color; leftColor: Color; text: AgeDemographicChartText; @@ -30,13 +30,6 @@ export function AgeDemographicTooltipContent< text, formatValue, }: AgeDemographicTooltipContentProps) { - const valueRight = value[rightMetricProperty]; - const rightMetricPropertyValue = - typeof valueRight === 'number' ? valueRight : 0; - - const valueLeft = value[leftMetricProperty]; - const leftMetricPropertyValue = typeof valueLeft === 'number' ? valueLeft : 0; - return ( <> @@ -48,13 +41,17 @@ export function AgeDemographicTooltipContent< - {formatValue(rightMetricPropertyValue)}{' '} + + {formatValue(value[rightMetricProperty] as unknown as number)} + {' '} {replaceVariablesInText(text.right_tooltip, { ageGroupRange: formatAgeGroupRange(value.age_group_range), })} - {formatValue(leftMetricPropertyValue)}{' '} + + {formatValue(value[leftMetricProperty] as unknown as number)} + {' '} {replaceVariablesInText(text.left_tooltip, { ageGroupRange: formatAgeGroupRange(value.age_group_range), })} diff --git a/packages/app/src/components/age-demographic/age-demographic.tsx b/packages/app/src/components/age-demographic/age-demographic.tsx index 1df3aec23a..0531ea5654 100644 --- a/packages/app/src/components/age-demographic/age-demographic.tsx +++ b/packages/app/src/components/age-demographic/age-demographic.tsx @@ -1,4 +1,4 @@ -import type { Color } from '@corona-dashboard/common'; +import type { Color, KeysOfType } from '@corona-dashboard/common'; import { Box } from '~/components/base'; import { ErrorBoundary } from '~/components/error-boundary'; import { Tooltip, useTooltip } from '~/components/tooltip'; @@ -16,8 +16,8 @@ import { AgeDemographicChartText, AgeDemographicDefaultValue } from './types'; export interface AgeDemographicProps { data: { values: T[] }; - rightMetricProperty: keyof T; - leftMetricProperty: keyof T; + rightMetricProperty: KeysOfType; + leftMetricProperty: KeysOfType; rightColor: Color; leftColor: Color; /** diff --git a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx index 5eaa21ee3c..350fb94d95 100644 --- a/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx +++ b/packages/app/src/components/choropleth/components/canvas-choropleth-map.tsx @@ -321,7 +321,7 @@ const Outlines = memo((props: OutlinesProps) => { type FeaturesProps = { geoInfo: ProjectedGeoInfo[]; featureProps: FeatureProps; - children: React.ReactNode; + children: any; }; const Features = memo((props: FeaturesProps) => { diff --git a/packages/app/src/components/choropleth/index.tsx b/packages/app/src/components/choropleth/index.tsx index ae330f6255..398988d5ec 100644 --- a/packages/app/src/components/choropleth/index.tsx +++ b/packages/app/src/components/choropleth/index.tsx @@ -1,3 +1,4 @@ +import { KeysOfType } from '@corona-dashboard/common'; import css from '@styled-system/css'; import type { GeoProjection } from 'd3-geo'; import withLoadingProps from 'next-dynamic-loading-props'; @@ -63,12 +64,16 @@ export type OptionalDataConfig = { /** * A top-level property name of either VR_COLLECTION.json or GM_COLLECTION.json */ - metricName: keyof InferedDataCollection; + metricName: KeysOfType, T[]>; /** * A property name of the object determined by the metric name. This value is used to determine the color * of the feature. */ - metricProperty: keyof T; + metricProperty: KeysOfType< + T, + string | number | null | boolean | undefined, + true + >; /** * The color that is used for the feature when no data is available (a null value for example). */ diff --git a/packages/app/src/components/choropleth/logic/create-data-config.ts b/packages/app/src/components/choropleth/logic/create-data-config.ts index c842339d89..588085d766 100644 --- a/packages/app/src/components/choropleth/logic/create-data-config.ts +++ b/packages/app/src/components/choropleth/logic/create-data-config.ts @@ -18,8 +18,8 @@ export function createDataConfig( ) { if (partialDataConfig.metricName === 'veiligheidsregio') { return { - metricName: 'veiligheidsregio', - metricProperty: 'admissions_on_date_of_admission', + metricName: 'veiligheidsregio' as any, + metricProperty: 'admissions_on_date_of_admission' as any, areaStroke: colors.white, areaStrokeWidth: 1, hoverFill: colors.white, diff --git a/packages/app/src/components/choropleth/logic/types.ts b/packages/app/src/components/choropleth/logic/types.ts index 6e7dae15d7..854f3b5a7c 100644 --- a/packages/app/src/components/choropleth/logic/types.ts +++ b/packages/app/src/components/choropleth/logic/types.ts @@ -1,19 +1,7 @@ import type { GmCollection, - GmCollectionHospitalNice, - GmCollectionSewer, - GmCollectionTestedOverall, - GmCollectionVaccineCoveragePerAgeGroup, + KeysOfType, VrCollection, - VrCollectionBehavior, - VrCollectionDisabilityCare, - VrCollectionElderlyAtHome, - VrCollectionHospitalNice, - VrCollectionNursingHome, - VrCollectionSewer, - VrCollectionSituations, - VrCollectionTestedOverall, - VrCollectionVaccineCoveragePerAgeGroup, } from '@corona-dashboard/common'; import type { ParsedFeature } from '@visx/geo/lib/projections/Projection'; import type { @@ -47,18 +35,9 @@ export enum CHOROPLETH_ASPECT_RATIO { */ export type MapType = 'gm' | 'vr'; -const CODE_PROP_GM = 'gmcode'; -const CODE_PROP_VR = 'vrcode'; -const CODE_PROP_COUNTRY = 'country_code'; - export type CodeProp = - | typeof CODE_PROP_GM - | typeof CODE_PROP_VR - | typeof CODE_PROP_COUNTRY; - -export const isCodeProp = (input: string): input is CodeProp => { - return [CODE_PROP_GM, CODE_PROP_VR, CODE_PROP_COUNTRY].includes(input); -}; + | KeysOfType + | KeysOfType; export const mapToCodeType: Record = { gm: 'gmcode', @@ -80,24 +59,22 @@ export type InferedDataCollection = ? VrCollection : never; -export type VrDataCollection = - | VrCollectionHospitalNice[] - | VrCollectionHospitalNice[] - | VrCollectionTestedOverall[] - | VrCollectionNursingHome[] - | VrCollectionSewer[] - | VrCollectionBehavior[] - | VrCollectionDisabilityCare[] - | VrCollectionElderlyAtHome[] - | VrCollectionSituations[] - | VrCollectionVaccineCoveragePerAgeGroup[]; +/** + * Select all the item types of all the properties from the VrCollection with an array type that has a vrcode property + */ +export type VrDataCollection = VrCollection[KeysOfType< + VrCollection, + { vrcode: string }[] +>]; export type VrDataItem = VrDataCollection[number]; -export type GmDataCollection = - | GmCollectionHospitalNice[] - | GmCollectionTestedOverall[] - | GmCollectionSewer[] - | GmCollectionVaccineCoveragePerAgeGroup[]; +/** + * Select all the item types of all the properties from the GmCollection with an array type that has a gmcode property + */ +export type GmDataCollection = GmCollection[KeysOfType< + GmCollection, + { gmcode: string }[] +>]; export type GmDataItem = GmDataCollection[number]; /** diff --git a/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts b/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts index 05620d2151..9c682c00b5 100644 --- a/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts +++ b/packages/app/src/components/choropleth/logic/use-choropleth-tooltip.ts @@ -9,13 +9,7 @@ import { useIsTouchDevice } from '~/utils/use-is-touch-device'; import { DataConfig, DataOptions } from '..'; import { TooltipSettings } from '../tooltips/types'; import { thresholds } from './thresholds'; -import { - ChoroplethDataItem, - CodeProp, - isCodeProp, - mapToCodeType, - MapType, -} from './types'; +import { ChoroplethDataItem, mapToCodeType, MapType } from './types'; import { useFeatureName } from './use-feature-name'; import { isCodedValueType } from './utils'; @@ -68,12 +62,9 @@ export function useChoroplethTooltip( const getFeatureName = useFeatureName(map, dataOptions.getFeatureName); const getItemByCode = useMemo(() => { - return (code: CodeProp) => { + return (code: string) => { const item = data - .filter((x) => { - const filterFn = isCodedValueType(codeType); - return filterFn && filterFn(x); - }) + .filter(isCodedValueType(codeType)) .find((x) => (x as any)[codeType] === code); assert( item, @@ -86,9 +77,7 @@ export function useChoroplethTooltip( const threshold = thresholds[map][dataConfig.metricProperty as string]; assert( isDefined(threshold), - `[${ - useChoroplethTooltip.name - }] No threshold configured for map type ${map} and metric property ${dataConfig.metricProperty.toString()}` + `[${useChoroplethTooltip.name}] No threshold configured for map type ${map} and metric property ${dataConfig.metricProperty.toString()}` ); useEffect(() => { @@ -102,7 +91,7 @@ export function useChoroplethTooltip( return; } - function handleBubbledFocusIn(event: FocusEvent): void { + function handleBubbledFocusIn(event: FocusEvent): any { const link = event.target as HTMLAnchorElement; if (!isDefined(link)) { return; @@ -110,7 +99,7 @@ export function useChoroplethTooltip( const code = link.getAttribute('data-id'); - if (isPresent(code) && isPresent(container) && isCodeProp(code)) { + if (isPresent(code) && isPresent(container)) { const bboxContainer = container.getBoundingClientRect(); const bboxLink = link.getBoundingClientRect(); const left = bboxLink.left - bboxContainer.left; @@ -194,7 +183,7 @@ type HoverInfo = { code: string; x: number; y: number }; const createTooltipTrigger = ( setTooltip: (settings: TooltipSettings | undefined) => void, - getItemByCode: (code: CodeProp) => T, + getItemByCode: (code: string) => T, dataConfig: DataConfig, dataOptions: DataOptions, threshold: ChoroplethThresholdsValue[], @@ -203,7 +192,7 @@ const createTooltipTrigger = ( metricPropertyFormatter: (value: number) => string ) => { return (hoverInfo?: HoverInfo) => { - if (!isDefined(hoverInfo) || !isCodeProp(hoverInfo.code)) { + if (!isDefined(hoverInfo)) { return setTooltip(undefined); } @@ -229,7 +218,7 @@ const createFeatureMouseOverHandler = ( timeout: MutableRefObject, setTooltip: (settings: TooltipSettings | undefined) => void, ref: RefObject, - getItemByCode: (code: CodeProp) => T, + getItemByCode: (code: string) => T, dataConfig: DataConfig, dataOptions: DataOptions, threshold: ChoroplethThresholdsValue[], @@ -241,7 +230,7 @@ const createFeatureMouseOverHandler = ( const elm = event.target as HTMLElement; const code = elm.getAttribute('data-id'); - if (isPresent(code) && isCodeProp(code) && ref.current) { + if (isPresent(code) && ref.current) { if (timeout.current > -1) { clearTimeout(timeout.current); timeout.current = -1; @@ -292,10 +281,9 @@ function useMetricPropertyFormatter( intl: IntlContextProps ) { return useMemo(() => { - const values = data.map((value) => { - const valueEntry = value[dataConfig.metricProperty]; - return typeof valueEntry === 'number' ? valueEntry : 0; - }); + const values = data.map( + (x) => x[dataConfig.metricProperty] as unknown as number + ); const numberOfDecimals = getMaximumNumberOfDecimals(values); return (value: number) => intl.formatPercentage(value, { diff --git a/packages/app/src/components/choropleth/logic/use-fill-color.ts b/packages/app/src/components/choropleth/logic/use-fill-color.ts index 68088f29c0..9c9a164b39 100644 --- a/packages/app/src/components/choropleth/logic/use-fill-color.ts +++ b/packages/app/src/components/choropleth/logic/use-fill-color.ts @@ -34,9 +34,7 @@ export function useFillColor( const threshold = thresholds[thresholdMap || map][metricProperty as string]; assert( isDefined(threshold), - `[${ - useFillColor.name - }] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` + `[${useFillColor.name}] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` ); const colorScale = useMemo(() => createColorScale(threshold), [threshold]); @@ -60,9 +58,7 @@ export function getFillColor( const threshold = thresholds[thresholdMap || map][metricProperty as string]; assert( isDefined(threshold), - `[${ - getFillColor.name - }] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` + `[${getFillColor.name}] No threshold configured for map type ${map} and metric property ${metricProperty.toString()}` ); const colorScale = createColorScale(threshold); @@ -98,10 +94,7 @@ function createGetValueByCode( ) { return (code: string) => { const item = data - .filter((x) => { - const filterFn = isCodedValueType(codeType); - return filterFn && filterFn(x); - }) + .filter(isCodedValueType(codeType)) .find((x) => (x as unknown as Record)[codeType] === code); return isDefined(item) && isPresent(item[metricProperty]) diff --git a/packages/app/src/components/choropleth/logic/utils.ts b/packages/app/src/components/choropleth/logic/utils.ts index 1d6d0414a4..4c81a00f31 100644 --- a/packages/app/src/components/choropleth/logic/utils.ts +++ b/packages/app/src/components/choropleth/logic/utils.ts @@ -2,6 +2,7 @@ import type { ParsedFeature } from '@visx/geo/lib/projections/Projection'; import type { Feature, MultiPolygon, Polygon } from 'geojson'; import { isPresent } from 'ts-is-present'; import type { + ChoroplethDataItem, CodedGeoProperties, CodeProp, GmDataItem, @@ -18,11 +19,11 @@ export function isCodedValueType(codeType: CodeProp) { } } -export function isGmData(item: any): item is GmDataItem { +export function isGmData(item: ChoroplethDataItem): item is GmDataItem { return 'gmcode' in item; } -export function isVrData(item: any): item is VrDataItem { +export function isVrData(item: ChoroplethDataItem): item is VrDataItem { return 'vrcode' in item; } diff --git a/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx b/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx index c2281a4448..037fc3f93e 100644 --- a/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx +++ b/packages/app/src/components/choropleth/tooltips/choropleth-tooltip.tsx @@ -36,11 +36,7 @@ export function ChoroplethTooltip( )[data.map]?.[data.dataConfig.metricProperty as string]?.subject; assert( isDefined(subject), - `[${ - ChoroplethTooltip.name - }] No tooltip subject found in siteText.choropleth_tooltip.${ - data.map - }.${data.dataConfig.metricProperty.toString()}` + `[${ChoroplethTooltip.name}] No tooltip subject found in siteText.choropleth_tooltip.${data.map}.${data.dataConfig.metricProperty.toString()}` ); const tooltipContent = ( @@ -48,11 +44,7 @@ export function ChoroplethTooltip( )[data.map]?.[data.dataConfig.metricProperty as string]?.content; assert( isDefined(tooltipContent), - `[${ - ChoroplethTooltip.name - }] No tooltip content found in siteText.choropleth_tooltip.${ - data.map - }.${data.dataConfig.metricProperty.toString()}` + `[${ChoroplethTooltip.name}] No tooltip content found in siteText.choropleth_tooltip.${data.map}.${data.dataConfig.metricProperty.toString()}` ); const tooltipVars = { @@ -82,8 +74,6 @@ export function ChoroplethTooltip( // This line is to make sure the content is readible by screenreaders and does not skip numbers after a new line const ariaContent = content.replace(/(\n|\*)/g, ''); - const dataItem = data.dataItem[data.dataConfig.metricProperty]; - const filterBelow = typeof dataItem === 'number' ? dataItem : null; return ( ( {ariaContent} diff --git a/packages/app/src/components/cms/inline-age-demographic.tsx b/packages/app/src/components/cms/inline-age-demographic.tsx index bc0bc16bc1..391dd2ea39 100644 --- a/packages/app/src/components/cms/inline-age-demographic.tsx +++ b/packages/app/src/components/cms/inline-age-demographic.tsx @@ -8,7 +8,6 @@ import { get } from 'lodash'; import useSWRImmutable from 'swr/immutable'; import { isDefined } from 'ts-is-present'; import { useIntl } from '~/intl'; -import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations'; import { AgeDemographic } from '../age-demographic'; import { ErrorBoundary } from '../error-boundary'; import { Metadata } from '../metadata'; @@ -19,8 +18,7 @@ import { getDataUrl } from './logic/get-data-url'; interface InlineAgeDemographicProps { configuration: AgeDemographicConfiguration< DataScopeKey, - MetricKeys, - AccessibilityDefinition['key'] + MetricKeys >; startDate?: string; endDate?: string; @@ -47,11 +45,11 @@ export function InlineAgeDemographic(props: InlineAgeDemographicProps) { return ( `${n}`} diff --git a/packages/app/src/components/cms/inline-choropleth.tsx b/packages/app/src/components/cms/inline-choropleth.tsx index d1cbd8b435..6016cf616f 100644 --- a/packages/app/src/components/cms/inline-choropleth.tsx +++ b/packages/app/src/components/cms/inline-choropleth.tsx @@ -15,7 +15,7 @@ import { DynamicChoropleth, OptionalDataConfig, } from '../choropleth'; -import { ChoroplethDataItem, InferedDataCollection } from '../choropleth/logic'; +import { ChoroplethDataItem } from '../choropleth/logic'; import { ErrorBoundary } from '../error-boundary'; import { Metadata } from '../metadata'; import { InlineLoader } from './inline-loader'; @@ -58,9 +58,8 @@ export function InlineChoropleth(props: InlineChoroplethProps) { }; const dataConfig: OptionalDataConfig = { - metricName: - configuration.metricName as keyof InferedDataCollection, - metricProperty: configuration.metricProperty as keyof ChoroplethDataItem, + metricName: configuration.metricName as any, + metricProperty: configuration.metricProperty as any, areaStroke: getColor(configuration.areaStroke), areaStrokeWidth: configuration.areaStrokeWidth, highlightStroke: getColor(configuration.highlightStroke), diff --git a/packages/app/src/components/cms/rich-content.tsx b/packages/app/src/components/cms/rich-content.tsx index ddf11f0ee8..938e22590f 100644 --- a/packages/app/src/components/cms/rich-content.tsx +++ b/packages/app/src/components/cms/rich-content.tsx @@ -30,7 +30,6 @@ import { import { assert } from '~/utils/assert'; import { isAbsoluteUrl } from '~/utils/is-absolute-url'; import { Link } from '~/utils/link'; -import { AccessibilityDefinition } from '~/utils/use-accessibility-annotations'; import { Heading } from '../typography'; import { ContentImage } from './content-image'; import { InlineAgeDemographic } from './inline-age-demographic'; @@ -56,7 +55,7 @@ interface AgeDemographicConfigNode { title: string; startDate?: string; endDate?: string; - config: AgeDemographicConfiguration, AccessibilityDefinition['key']>; + config: AgeDemographicConfiguration>; } interface ChoroplethConfigNode { diff --git a/packages/app/src/components/pie-chart.tsx b/packages/app/src/components/pie-chart.tsx index 78bc9ad48c..3b10099fd3 100644 --- a/packages/app/src/components/pie-chart.tsx +++ b/packages/app/src/components/pie-chart.tsx @@ -1,3 +1,4 @@ +import type { KeysOfType } from '@corona-dashboard/common'; import { Chevron } from '@corona-dashboard/icons'; import css from '@styled-system/css'; import { Group } from '@visx/group'; @@ -15,7 +16,7 @@ import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; const ICON_SIZE = 55; export interface PiePartConfig { - metricProperty: keyof T; + metricProperty: KeysOfType; color: string; label: string; tooltipLabel: string; @@ -71,13 +72,11 @@ export function PieChart({ formatDateSpan, }; - const totalValue = dataConfig.reduce((previousValue, currentValue) => { - const metricPropertyValue = data[currentValue.metricProperty]; - return ( - previousValue + - (typeof metricPropertyValue === 'number' ? metricPropertyValue : 0) - ); - }, 0); + const totalValue = dataConfig.reduce( + (previousValue, currentValue) => + previousValue + (data[currentValue.metricProperty] as unknown as number), + 0 + ); const mappedDataWithValues = useMemo( () => @@ -86,7 +85,7 @@ export function PieChart({ return { __value: Math.max( - typeof currentProperty === 'number' ? currentProperty : 0, + currentProperty as unknown as number, totalValue * (minimumPercentage / 100) * 2 ), ...config, diff --git a/packages/app/src/components/spark-line.tsx b/packages/app/src/components/spark-line.tsx index 4f64084955..36d1af5009 100644 --- a/packages/app/src/components/spark-line.tsx +++ b/packages/app/src/components/spark-line.tsx @@ -1,7 +1,8 @@ -import type { TimestampedValue } from '@corona-dashboard/common'; +import type { KeysOfType, TimestampedValue } from '@corona-dashboard/common'; import { colors } from '@corona-dashboard/common'; import { scaleLinear } from '@visx/scale'; import { AreaClosed, LinePath } from '@visx/shape'; +import { NumberValue } from 'd3-scale'; import { first, last } from 'lodash'; import { isPresent } from 'ts-is-present'; @@ -10,7 +11,7 @@ const HEIGHT = 24; const MARKER_RADIUS = 2.5; type SparkLineProps = { - averageProperty: keyof T; + averageProperty: KeysOfType; data: T[]; }; @@ -30,20 +31,14 @@ export function SparkLine( props: SparkLineProps ) { const { data, averageProperty } = props; - - const getNumberValue = (data: T, key: keyof T): number => { - const value = data[key]; - return typeof value === 'number' ? value : 0; - }; - const numberOfPoints = data.length; const min = Math.min( 0, - ...data.map((d) => getNumberValue(d, averageProperty)) + ...data.map((d) => (d[averageProperty] as unknown as number) ?? 0) ); const max = Math.max( 0.1, - ...data.map((d) => getNumberValue(d, averageProperty)) + ...data.map((d) => (d[averageProperty] as unknown as number) ?? 0) ); const xScale = scaleLinear({ domain: [getDate(first(data)), getDate(last(data))], @@ -60,7 +55,7 @@ export function SparkLine( } function getY(dataPoint: T) { - return yScale(getNumberValue(dataPoint, averageProperty)); + return yScale(dataPoint[averageProperty] as unknown as NumberValue); } const nonNullValues = data.filter((x) => isPresent(x[averageProperty])); diff --git a/packages/app/src/components/time-series-chart/components/axes.tsx b/packages/app/src/components/time-series-chart/components/axes.tsx index ac115f1792..dc42a92bd3 100644 --- a/packages/app/src/components/time-series-chart/components/axes.tsx +++ b/packages/app/src/components/time-series-chart/components/axes.tsx @@ -13,7 +13,7 @@ import { DateSpanValue, } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { AxisBottom, AxisLeft, TickFormatter } from '@visx/axis'; +import { AxisBottom, AxisLeft } from '@visx/axis'; import { GridRows } from '@visx/grid'; import { scaleLinear } from '@visx/scale'; import { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale'; @@ -49,7 +49,7 @@ export type AxesProps = { timeDomain: [number, number]; xTickNumber?: number; values?: T[]; - formatYTickValue?: TickFormatter; + formatYTickValue?: (value: number) => string; /** * On narrow screens we'll "collapse" the Y-axis. Only the low value will be @@ -92,6 +92,8 @@ function createTimeTicks(startTick: number, endTick: number, count: number) { return ticks; } +export type AnyTickFormatter = (value: any) => string; + export const Axes = memo(function Axes({ numGridLines, showWeekNumbers, @@ -127,13 +129,13 @@ export const Axes = memo(function Axes({ const { formatDateFromSeconds, formatNumber, formatPercentage } = useIntl(); - const formatYAxis: TickFormatter = useCallback( - (y: NumberValue) => formatNumber(y as number), + const formatYAxis = useCallback( + (y: number) => formatNumber(y), [formatNumber] ); - const formatYAxisPercentage: TickFormatter = useCallback( - (y: NumberValue) => `${formatPercentage(y as number)}%`, + const formatYAxisPercentage = useCallback( + (y: number) => `${formatPercentage(y)}%`, [formatPercentage] ); @@ -354,10 +356,10 @@ export const Axes = memo(function Axes({ stroke={colors.silver} tickFormat={ formatYTickValue - ? formatYTickValue + ? (formatYTickValue as AnyTickFormatter) : isPercentage - ? formatYAxisPercentage - : formatYAxis + ? (formatYAxisPercentage as AnyTickFormatter) + : (formatYAxis as AnyTickFormatter) } tickLabelProps={() => ({ fill: colors.data.axisLabels, @@ -386,10 +388,10 @@ export const Axes = memo(function Axes({ stroke={colors.silver} tickFormat={ formatYTickValue - ? formatYTickValue + ? (formatYTickValue as AnyTickFormatter) : isPercentage - ? formatYAxisPercentage - : formatYAxis + ? (formatYAxisPercentage as AnyTickFormatter) + : (formatYAxis as AnyTickFormatter) } tickLabelProps={() => ({ fill: colors.data.axisLabels, diff --git a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx index 606dbd8f75..633697e751 100644 --- a/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx +++ b/packages/app/src/components/time-series-chart/components/tooltip/tooltip-series-list-items.tsx @@ -37,7 +37,7 @@ export function TooltipSeriesListItems({ return ( - {seriesConfig.map((serie, index) => { + {seriesConfig.map((x, index) => { /** * The key is unique for every date to make sure a screenreader * will read `[label]: [value]`. Otherwise it would read the @@ -45,27 +45,23 @@ export function TooltipSeriesListItems({ * context. */ const key = index + getDateUnixString(value); - const metricProperty = serie.type !== 'range' && serie.metricProperty; - const metricPropertyValue = metricProperty - ? value[metricProperty] - : null; + const metricPropertyValue = + x.type !== 'range' && + (value[x.metricProperty] as unknown as number | null); - const tooltipValue = - typeof metricPropertyValue === 'number' ? metricPropertyValue : null; - - switch (serie.type) { + switch (x.type) { case 'range': return ( } - label={serie.shortLabel ?? serie.label} - ariaLabel={serie.ariaLabel} + icon={} + label={x.shortLabel ?? x.label} + ariaLabel={x.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={serie.nonInteractive} + isVisuallyHidden={x.nonInteractive} > - {formatSeriesValue(value, serie, options.isPercentage)} + {formatSeriesValue(value, x, options.isPercentage)} ); @@ -74,15 +70,15 @@ export function TooltipSeriesListItems({ return ( {formatSeriesValue( value, - serie, - serie.isPercentage ?? options.isPercentage + x, + x.isPercentage ?? options.isPercentage )} ); @@ -92,13 +88,18 @@ export function TooltipSeriesListItems({ return ( } - label={serie.shortLabel ?? serie.label} - ariaLabel={serie.ariaLabel} + icon={ + + } + label={x.shortLabel ?? x.label} + ariaLabel={x.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={serie.nonInteractive} + isVisuallyHidden={x.nonInteractive} > - {formatSeriesValue(value, serie, options.isPercentage)} + {formatSeriesValue(value, x, options.isPercentage)} ); @@ -107,20 +108,20 @@ export function TooltipSeriesListItems({ ) : ( - + ) } - label={serie.shortLabel ?? serie.label} - ariaLabel={serie.ariaLabel} + label={x.shortLabel ?? x.label} + ariaLabel={x.ariaLabel} displayTooltipValueOnly={displayTooltipValueOnly} - isVisuallyHidden={serie.nonInteractive} + isVisuallyHidden={x.nonInteractive} > - {formatSeriesValue(value, serie, options.isPercentage)} + {formatSeriesValue(value, x, options.isPercentage)} ); } diff --git a/packages/app/src/components/time-series-chart/components/week-numbers.tsx b/packages/app/src/components/time-series-chart/components/week-numbers.tsx index 7ee582b5d2..d8824a748b 100644 --- a/packages/app/src/components/time-series-chart/components/week-numbers.tsx +++ b/packages/app/src/components/time-series-chart/components/week-numbers.tsx @@ -4,10 +4,10 @@ import { WEEK_IN_SECONDS, } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { AxisTop, TickFormatter } from '@visx/axis'; +import { AxisTop } from '@visx/axis'; import { RectClipPath } from '@visx/clip-path'; import { GridColumns } from '@visx/grid'; -import { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale'; +import { ScaleBand, ScaleLinear } from 'd3-scale'; import { useCallback, useMemo } from 'react'; import { isDefined } from 'ts-is-present'; import { useIntl } from '~/intl'; @@ -15,6 +15,7 @@ import { createDateFromUnixTimestamp } from '~/utils/create-date-from-unix-times import { replaceVariablesInText } from '~/utils/replace-variables-in-text'; import { useUniqueId } from '~/utils/use-unique-id'; import { Bounds, getWeekInfo } from '../logic'; +import { AnyTickFormatter } from './axes'; /** * Only show this amount of week numbers @@ -71,7 +72,7 @@ export function WeekNumbers({ }); }, [commonTexts.common] - ) as TickFormatter; + ); return ( <> @@ -100,7 +101,7 @@ export function WeekNumbers({ ({ diff --git a/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts b/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts index f0b0208ff3..6ba50a12f2 100644 --- a/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts +++ b/packages/app/src/components/time-series-chart/logic/use-format-series-value.ts @@ -18,11 +18,10 @@ export function useFormatSeriesValue( ) { const formatter = metricPropertyFormatters[metricProperty] || intl.formatNumber; - const numberValue = value[metricProperty]; - const formattedValue = - isPresent(numberValue) && typeof numberValue === 'number' - ? formatter(numberValue) - : String(numberValue); + const numberValue = value[metricProperty] as unknown as number | null; + const formattedValue = isPresent(numberValue) + ? formatter(numberValue) + : numberValue; return isPresent(formattedValue) ? isPercentage diff --git a/packages/app/src/components/time-series-chart/time-series-chart.tsx b/packages/app/src/components/time-series-chart/time-series-chart.tsx index faa67e2025..220d9afacc 100644 --- a/packages/app/src/components/time-series-chart/time-series-chart.tsx +++ b/packages/app/src/components/time-series-chart/time-series-chart.tsx @@ -1,8 +1,6 @@ import { TimeframeOption, TimestampedValue } from '@corona-dashboard/common'; import css from '@styled-system/css'; -import { TickFormatter } from '@visx/axis'; import { useTooltip } from '@visx/tooltip'; -import { NumberValue } from 'd3-scale'; import { first, isFunction, last } from 'lodash'; import { useCallback, useEffect, useMemo } from 'react'; import { isDefined } from 'ts-is-present'; @@ -122,7 +120,7 @@ export type TimeSeriesChartProps< showWeekNumbers?: boolean; tickValues?: number[]; xTickNumber?: number; - formatTickValue?: TickFormatter; + formatTickValue?: (value: number) => string; paddingLeft?: number; /** * The data specific options are grouped together. This way we can pass them diff --git a/packages/app/src/components/tooltip.tsx b/packages/app/src/components/tooltip.tsx index 71abee4bcf..6e6bbe96d5 100644 --- a/packages/app/src/components/tooltip.tsx +++ b/packages/app/src/components/tooltip.tsx @@ -1,7 +1,6 @@ import css from '@styled-system/css'; import { MouseEvent, - KeyboardEvent, ReactNode, useCallback, useEffect, @@ -17,7 +16,7 @@ export interface TooltipCoordinates { export type GetTooltipCoordinates = ( value: T, - event?: MouseEvent + event?: MouseEvent ) => TooltipCoordinates; interface TooltipProps { @@ -77,7 +76,7 @@ export function useTooltip({ } const openTooltip = useCallback( - (value: T, event: MouseEvent) => { + (value: T, event: MouseEvent) => { debounceMouseEvents(() => { setCoordinates(getTooltipCoordinates(value, event)); setIsVisible(true); @@ -94,7 +93,7 @@ export function useTooltip({ }, []); const keyboardNavigateTooltip = useCallback( - (event: KeyboardEvent) => { + (event: any) => { if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') { return; } diff --git a/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx b/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx index 327dbc53e8..c083eb4322 100644 --- a/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx +++ b/packages/app/src/domain/behavior/behavior-choropleths-tile.tsx @@ -1,5 +1,6 @@ import { colors, + KeysOfType, VrCollectionBehavior, } from '@corona-dashboard/common'; import css from '@styled-system/css'; @@ -118,7 +119,7 @@ function ChoroplethBlock({ const breakpoints = useBreakpoints(); const isSmallScreen = breakpoints.sm; - const metricProperty = `${currentId}_${behaviorType}` as keyof VrCollectionBehavior; + const metricProperty = `${currentId}_${behaviorType}` as const; return ( @@ -152,7 +153,11 @@ function ChoroplethBlock({ data={data.behavior} dataConfig={{ metricName: 'behavior', - metricProperty, + metricProperty: metricProperty as unknown as KeysOfType< + VrCollectionBehavior, + number | null | boolean | undefined, + true + >, noDataFillColor: colors.offWhite, }} dataOptions={{ diff --git a/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx b/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx index 945dc7a915..e2a1222420 100644 --- a/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx +++ b/packages/app/src/domain/behavior/behavior-line-chart-tile.tsx @@ -10,7 +10,7 @@ import { Box } from '~/components/base'; import { ChartTile } from '~/components/chart-tile'; import { InlineTooltip } from '~/components/inline-tooltip'; import { MetadataProps } from '~/components/metadata'; -import { SeriesConfig, TimeSeriesChart } from '~/components/time-series-chart'; +import { TimeSeriesChart } from '~/components/time-series-chart'; import { TimelineEventConfig } from '~/components/time-series-chart/components/timeline'; import { BoldText } from '~/components/typography'; import { SiteText } from '~/locale'; @@ -20,12 +20,8 @@ import { BehaviorIdentifier, behaviorIdentifiers, } from './logic/behavior-types'; - -type ValueType = NlBehaviorValue | VrBehaviorValue; -type ValueKey = keyof ValueType; - interface BehaviorLineChartTileProps { - values: ValueType[]; + values: NlBehaviorValue[] | VrBehaviorValue[]; metadata: MetadataProps; currentId: BehaviorIdentifier; setCurrentId: React.Dispatch>; @@ -46,15 +42,15 @@ export function BehaviorLineChartTile({ text, }: BehaviorLineChartTileProps) { const selectedComplianceValueKey = - `${currentId}_compliance` as ValueKey; + `${currentId}_compliance` as keyof NlBehaviorValue; const selectedSupportValueKey = - `${currentId}_support` as ValueKey; + `${currentId}_support` as keyof NlBehaviorValue; - const complianceValuesHasGap = useDataHasGaps( + const complianceValuesHasGap = useDataHasGaps( values, selectedComplianceValueKey ); - const supportValuesHasGap = useDataHasGaps(values, selectedSupportValueKey); + const supportValuesHasGap = useDataHasGaps(values, selectedSupportValueKey); const breakpoints = useBreakpoints(); @@ -92,7 +88,7 @@ export function BehaviorLineChartTile({ )} - > + = { label: string; data: T[]; - dataProperty: keyof Unpack; + dataProperty: KeysOfType, number | null, true>; value: number | string; valueIsPercentage?: boolean; warning?: string; diff --git a/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts b/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts index 446d91f1e7..008405785d 100644 --- a/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts +++ b/packages/app/src/domain/vaccine/logic/use-vaccine-coverage-percentage-formatter.ts @@ -66,10 +66,9 @@ function getVaccineCoveragePercentageFormatter( } } - const dataEntry = data[property]; - if (isPresent(dataEntry) && typeof dataEntry === 'number') { + if (isPresent(data[property]) && typeof data[property] === 'number') { return ( - formatPercentage(dataEntry, { + formatPercentage(data[property] as unknown as number, { minimumFractionDigits: numFractionDigits, maximumFractionDigits: numFractionDigits, }) + '%' diff --git a/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx b/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx index ed565718d7..7d8648dfd1 100644 --- a/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx +++ b/packages/app/src/domain/vaccine/vaccine-coverage-choropleth-per-gm.tsx @@ -2,6 +2,7 @@ import { assert, colors, GmCollectionVaccineCoveragePerAgeGroup, + KeysOfType, VrCollectionVaccineCoveragePerAgeGroup, } from '@corona-dashboard/common'; import css from '@styled-system/css'; @@ -243,7 +244,10 @@ export function ChoroplethTooltip( ...data.dataOptions.tooltipVariables, } as Record; - const dataItemKey = data.dataConfig.metricProperty as keyof VaccineCoverageData; + const dataItemKey = data.dataConfig.metricProperty as KeysOfType< + VaccineCoverageData, + number + >; const filterBelow = (dataItemKey === undefined ? null : data.dataItem[dataItemKey]) || null; @@ -296,7 +300,7 @@ export function ChoroplethTooltip( ) => { {isPresent(content.articles) && ( )} diff --git a/packages/app/src/pages/veiligheidsregio/index.tsx b/packages/app/src/pages/veiligheidsregio/index.tsx index 68336298c3..0592b86bfc 100644 --- a/packages/app/src/pages/veiligheidsregio/index.tsx +++ b/packages/app/src/pages/veiligheidsregio/index.tsx @@ -39,18 +39,15 @@ const VrIndexPage = (props: StaticProps) => { }; const code = router.query.code as string; - const data = useMemo( - () => - vrData.map((x) => ({ - date_unix: 0, - admissions_on_date_of_admission: 0, - admissions_on_date_of_admission_per_100000: 0, - admissions_on_date_of_reporting: 0, - date_of_insertion_unix: 0, - vrcode: x.code, - })), - [] - ); + const data = useMemo(() => { + return vrData.map( + (x) => + ({ + vrcode: x.code, + admissions_on_date_of_reporting: null, + } as unknown as VrCollectionHospitalNice) + ); + }, []); return ( diff --git a/packages/app/src/utils/api/strip-trailing-null-values.ts b/packages/app/src/utils/api/strip-trailing-null-values.ts index 43ea0decb0..34b4e7369c 100644 --- a/packages/app/src/utils/api/strip-trailing-null-values.ts +++ b/packages/app/src/utils/api/strip-trailing-null-values.ts @@ -15,7 +15,7 @@ export function stripTrailingNullValues( ) { if ( !metricsInaccurateItems.includes(metric) || - !strippableMetricProperties.includes(metricProperty ?? '') + !strippableMetricProperties.includes(metricProperty as unknown as string) ) { return data; } diff --git a/packages/common/src/types/choropleth.ts b/packages/common/src/types/choropleth.ts index 46dc057237..d8a1ef71d4 100644 --- a/packages/common/src/types/choropleth.ts +++ b/packages/common/src/types/choropleth.ts @@ -8,6 +8,59 @@ import type { VrDifference, } from './data'; +/** + * This type was taken from this Stack Overflow post: https://stackoverflow.com/questions/46583883/typescript-pick-properties-with-a-defined-type + * + * Returns an interface stripped of all keys that don't resolve to U, defaulting + * to a non-strict comparison of T[key] extends U. Setting B to true performs + * a strict type comparison of T[key] extends U & U extends T[key] + * + * Example, if one needs just the keys of type string: + * + * type SomeType = { + * key1: string; + * key2: string; + * key3: number; + * } + * + * const stringKeys = KeysOfType + * + * (stringKeys = key1 | key2) + * + * @TODO Since TypeScript v4.5.5 this util is no longer working as expected. + * Refactoring is needed before a couple of typecasts (as unknown as number) can be removed. + */ +export type KeysOfType = { + [P in keyof T]: B extends true + ? T[P] extends U + ? U extends T[P] + ? P + : never + : never + : T[P] extends U + ? P + : never; +}[keyof T]; + +/** + * This returns a filtered type that only contains the keys of the specified type. + * + * type SomeType = { + * key1: string; + * key2: string; + * key3: number; + * } + * + * const TypeWithJustStringKeys = PickByType + * + * (TypeWithJustStringKeys = { + * key1: string; + * key2: string; + * }) + * + */ +export type PickByType = Pick>; + export type Metric = { values: T[]; last_value: T; diff --git a/packages/common/src/types/inline-charts.ts b/packages/common/src/types/inline-charts.ts index 706c0893c4..192d79c072 100644 --- a/packages/common/src/types/inline-charts.ts +++ b/packages/common/src/types/inline-charts.ts @@ -82,10 +82,9 @@ export type DonutMetricPropertyConfig< export type AgeDemographicConfiguration< S extends DataScopeKey, - M extends MetricKeys, - K extends string + M extends MetricKeys > = { - accessibilityKey: K; + accessibilityKey: string; sourceKey: string; text: string; leftMetricProperty: MetricProperty>; From de815ad51cbd42975757a5c5984952d6b6e12046 Mon Sep 17 00:00:00 2001 From: HO <93981322+VWSCoronaDashboard19@users.noreply.github.com> Date: Thu, 21 Jul 2022 11:18:02 +0200 Subject: [PATCH 12/12] Revert "Replace konva-node with konva and remove it (#4327)" (#4330) This reverts commit c9f6cd0734a14355cdf93f9e919363090368bcc7. --- packages/app/package.json | 1 + .../src/pages/api/choropleth/[...param].ts | 3 +- yarn.lock | 100 +++++++++++++++--- 3 files changed, 86 insertions(+), 18 deletions(-) diff --git a/packages/app/package.json b/packages/app/package.json index 6f9b8c052b..e2f304fee1 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -43,6 +43,7 @@ "http-proxy-middleware": "^2.0.1", "intercept-stdout": "^0.1.2", "konva": "^7.2.5", + "konva-node": "^0.11.2", "lodash": "^4.17.21", "match-sorter": "^6.3.1", "next": "^12.0.4", diff --git a/packages/app/src/pages/api/choropleth/[...param].ts b/packages/app/src/pages/api/choropleth/[...param].ts index 65b5145937..53569ba2f6 100644 --- a/packages/app/src/pages/api/choropleth/[...param].ts +++ b/packages/app/src/pages/api/choropleth/[...param].ts @@ -2,7 +2,7 @@ import { assert, vrData } from '@corona-dashboard/common'; import { geoMercator } from 'd3-geo'; import fs from 'fs'; import hash from 'hash-sum'; -import Konva from 'konva'; +import Konva from 'konva-node'; import { NextApiRequest, NextApiResponse } from 'next/dist/shared/lib/utils'; import path from 'path'; import sanitize from 'sanitize-filename'; @@ -193,7 +193,6 @@ async function generateChoroplethImage( const featureProps = getFeatureProps(map, fColor, dataOptions, dataConfig); const stage = new Konva.Stage({ - container: selectedCode ? selectedCode : '', width, height, }); diff --git a/yarn.lock b/yarn.lock index 394be9eb4e..254b688592 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2630,6 +2630,7 @@ __metadata: jsdom: ^18.1.1 jsdom-global: ^3.0.2 konva: ^7.2.5 + konva-node: ^0.11.2 lint-staged: ^11.2.6 lodash: ^4.17.21 lodash-webpack-plugin: ^0.11.6 @@ -3310,6 +3311,25 @@ __metadata: languageName: node linkType: hard +"@mapbox/node-pre-gyp@npm:^1.0.0": + version: 1.0.5 + resolution: "@mapbox/node-pre-gyp@npm:1.0.5" + dependencies: + detect-libc: ^1.0.3 + https-proxy-agent: ^5.0.0 + make-dir: ^3.1.0 + node-fetch: ^2.6.1 + nopt: ^5.0.0 + npmlog: ^4.1.2 + rimraf: ^3.0.2 + semver: ^7.3.4 + tar: ^6.1.0 + bin: + node-pre-gyp: bin/node-pre-gyp + checksum: c1f182a707f5782e47b77a76e9d6a073fb043999cf9ad965bc86732e88db27ad00926d1602918edb7105f05cde67871b84a178ee9844eb742319ade419636675 + languageName: node + linkType: hard + "@mdx-js/react@npm:^1.0.0": version: 1.6.22 resolution: "@mdx-js/react@npm:1.6.22" @@ -7403,15 +7423,6 @@ __metadata: languageName: node linkType: hard -"@types/react-reconciler@npm:~0.26.2": - version: 0.26.7 - resolution: "@types/react-reconciler@npm:0.26.7" - dependencies: - "@types/react": "*" - checksum: 4122d2b08580f775d0aeae9bd10b68248f894096ed14c0ebbc143ef712e21b159e89d0c628bd95dd3329947fc1ee94a0cb1d2d32b32b1d5d225e70030e91e58f - languageName: node - linkType: hard - "@types/react-test-renderer@npm:>=16.9.0, @types/react-test-renderer@npm:^17.0.1": version: 17.0.1 resolution: "@types/react-test-renderer@npm:17.0.1" @@ -10626,6 +10637,18 @@ __metadata: languageName: node linkType: hard +"canvas@npm:^2.5.0": + version: 2.8.0 + resolution: "canvas@npm:2.8.0" + dependencies: + "@mapbox/node-pre-gyp": ^1.0.0 + nan: ^2.14.0 + node-gyp: latest + simple-get: ^3.0.3 + checksum: 4cc909f63eaf88d22f9164601903745abcc6ccb7f70090b9389dc2cb68cbf139c220dbd75837e6d04602ff122b44a2eb17413bca850f9c6c602f74f1f0f1cc3f + languageName: node + linkType: hard + "capital-case@npm:^1.0.4": version: 1.0.4 resolution: "capital-case@npm:1.0.4" @@ -12464,6 +12487,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^4.2.0": + version: 4.2.1 + resolution: "decompress-response@npm:4.2.1" + dependencies: + mimic-response: ^2.0.0 + checksum: 4e783ca4dfe9417354d61349750fe05236f565a4415a6ca20983a311be2371debaedd9104c0b0e7b36e5f167aeaae04f84f1a0b3f8be4162f1d7d15598b8fdba + languageName: node + linkType: hard + "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -12695,6 +12727,15 @@ __metadata: languageName: node linkType: hard +"detect-libc@npm:^1.0.3": + version: 1.0.3 + resolution: "detect-libc@npm:1.0.3" + bin: + detect-libc: ./bin/detect-libc.js + checksum: daaaed925ffa7889bd91d56e9624e6c8033911bb60f3a50a74a87500680652969dbaab9526d1e200a4c94acf80fc862a22131841145a0a8482d60a99c24f4a3e + languageName: node + linkType: hard + "detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.1": version: 2.0.1 resolution: "detect-libc@npm:2.0.1" @@ -17607,7 +17648,17 @@ __metadata: languageName: node linkType: hard -"konva@npm:^7.2.5": +"konva-node@npm:^0.11.2": + version: 0.11.2 + resolution: "konva-node@npm:0.11.2" + dependencies: + canvas: ^2.5.0 + konva: ^7 + checksum: 11d99492c653d6e52c370af5831a4dce60b6cabbf81016806fa58c8563174272db39940b8d638fc29f83f949cf5934471ed7c1d3d1d6c3bad60152450f308fd2 + languageName: node + linkType: hard + +"konva@npm:^7, konva@npm:^7.2.5": version: 7.2.5 resolution: "konva@npm:7.2.5" checksum: 795ab73af38307243f867be3dab122ec6a5c37bc7f44a20359baf2bf6e1d5cd8a9ce9d7e3b69b21dd6429615b8f96254858e346e8ccb4b5fff8be6c5b60cd12d @@ -18734,6 +18785,13 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^2.0.0": + version: 2.1.0 + resolution: "mimic-response@npm:2.1.0" + checksum: 014fad6ab936657e5f2f48bd87af62a8e928ebe84472aaf9e14fec4fcb31257a5edff77324d8ac13ddc6685ba5135cf16e381efac324e5f174fb4ddbf902bf07 + languageName: node + linkType: hard + "mimic-response@npm:^3.1.0": version: 3.1.0 resolution: "mimic-response@npm:3.1.0" @@ -18976,7 +19034,7 @@ __metadata: languageName: node linkType: hard -"nan@npm:^2.12.1": +"nan@npm:^2.12.1, nan@npm:^2.14.0": version: 2.15.0 resolution: "nan@npm:2.15.0" dependencies: @@ -22646,17 +22704,16 @@ __metadata: linkType: hard "react-konva@npm:^17.0.2-5": - version: 17.0.2-6 - resolution: "react-konva@npm:17.0.2-6" + version: 17.0.2-5 + resolution: "react-konva@npm:17.0.2-5" dependencies: - "@types/react-reconciler": ~0.26.2 react-reconciler: ~0.26.2 scheduler: ^0.20.2 peerDependencies: konva: ^8.0.1 || ^7.2.5 react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 5e868f6941090243c998f2817fbc9f031f60c83e236dc3f6328c904114582cfe281a08df9b5146b3339f6e1ccf30f3707d03de85fd534fb42fbe0ee6c6531b0c + checksum: 614522753fe95322fc022569cd95443eacfc1b9d2d84c0bb4ea40ce6cdce9b7c5843268e67ebef7cdb6d50ab08b8a5038ec760c3977a105e233bcceb8408de56 languageName: node linkType: hard @@ -24382,6 +24439,17 @@ __metadata: languageName: node linkType: hard +"simple-get@npm:^3.0.3": + version: 3.1.1 + resolution: "simple-get@npm:3.1.1" + dependencies: + decompress-response: ^4.2.0 + once: ^1.3.1 + simple-concat: ^1.0.0 + checksum: 80195e70bf171486e75c31e28e5485468195cc42f85940f8b45c4a68472160144d223eb4d07bc82ef80cb974b7c401db021a540deb2d34ac4b3b8883da2d6401 + languageName: node + linkType: hard + "simple-get@npm:^4.0.0, simple-get@npm:^4.0.1": version: 4.0.1 resolution: "simple-get@npm:4.0.1" @@ -25542,7 +25610,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.0.2, tar@npm:^6.1.2": +"tar@npm:^6.0.2, tar@npm:^6.1.0, tar@npm:^6.1.2": version: 6.1.11 resolution: "tar@npm:6.1.11" dependencies: