From 2f64d696935b3101facd05c780cbc87aba0c4bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thea=20Sch=C3=B6bl?= Date: Fri, 12 Jan 2024 10:47:53 +0100 Subject: [PATCH] feat: migrate to protomaps and maplibre --- .syncpackrc.cjs | 8 +- backend/backend/src/storage/database.ts | 26 +- .../storage/elasticsearch/elasticsearch.ts | 48 +- .../elasticsearch/query/filters/geo.ts | 29 +- backend/backend/test/common.ts | 7 +- .../test/storage/elasticsearch/query.spec.ts | 86 ++- flake.lock | 12 +- flake.nix | 10 +- frontend/app/angular.json | 14 +- frontend/app/package.json | 19 +- frontend/app/src/app/app.module.ts | 5 +- .../app/src/app/modules/about/about.module.ts | 2 - .../src/app/modules/config/config.module.ts | 27 - .../src/app/modules/config/config.provider.ts | 1 + .../app/src/app/modules/data/data.module.ts | 6 +- .../data/detail/data-detail-content.scss | 15 +- .../app/modules/data/detail/data-detail.scss | 1 - .../data/elements/origin-detail.component.ts | 1 + .../modules/data/elements/origin-detail.html | 120 ++-- .../modules/data/elements/origin-detail.scss | 15 + .../date-series-detail-content.html | 2 +- .../types/place/place-list-item.component.ts | 14 +- .../mensa/place-mensa-detail.component.ts | 10 +- .../app/src/app/modules/jobs/jobs.module.ts | 2 - .../app/modules/map/cluster-leaves.pipe.ts | 51 ++ .../map/controls/attribution.component.ts | 38 ++ .../app/modules/map/controls/attribution.html | 8 + .../app/modules/map/controls/attribution.scss | 36 ++ .../map/controls/compass-control.component.ts | 40 ++ .../modules/map/controls/compass-control.html | 7 + .../modules/map/controls/compass-control.scss | 11 + .../controls/geolocate-control.component.ts | 91 +++ .../map/controls/geolocate-control.html | 18 + .../map/controls/geolocate-control.scss | 0 .../elements/building-markers.component.ts | 86 +++ .../map/elements/building-markers.html | 26 + .../map/elements/building-markers.scss | 0 .../map/elements/poi-marker.component.ts | 43 ++ .../app/modules/map/elements/poi-marker.html | 9 + .../app/modules/map/elements/poi-marker.scss | 38 ++ .../map/elements/poi-markers.component.ts | 43 ++ .../app/modules/map/elements/poi-markers.html | 33 ++ .../app/modules/map/elements/poi-markers.scss | 24 + .../modules/map/feature-collection.pipe.ts | 81 +++ .../app/modules/map/map-auto-3d.directive.ts | 36 ++ .../src/app/modules/map/map-data.provider.ts | 59 ++ .../src/app/modules/map/map-icon.directive.ts | 37 ++ .../app/modules/map/map-maximize-animation.ts | 109 ++++ .../src/app/modules/map/map-page.component.ts | 144 +++++ .../app/src/app/modules/map/map-page.html | 50 ++ .../app/src/app/modules/map/map-page.scss | 101 ++++ .../app/modules/map/map-size-fix.directive.ts | 39 ++ .../app/modules/map/map-style.directive.ts | 20 + .../app/modules/map/map-widget.component.ts | 75 +++ .../app/src/app/modules/map/map-widget.html | 51 ++ .../modules/map/{widget => }/map-widget.scss | 11 +- .../app/src/app/modules/map/map.module.ts | 59 +- .../src/app/modules/map/map.provider.spec.ts | 60 -- .../app/src/app/modules/map/map.provider.ts | 237 -------- .../map/page/map-list-modal.component.ts | 93 --- .../app/modules/map/page/map-list-modal.html | 28 - .../app/modules/map/page/map-list-modal.scss | 20 - .../modules/map/page/map-page.component.ts | 430 -------------- .../src/app/modules/map/page/map-page.html | 106 ---- .../src/app/modules/map/page/map-page.scss | 99 ---- .../src/app/modules/map/position.service.ts | 35 +- .../src/app/modules/map/thing-bounds.pipe.ts | 23 + .../map/widget/map-widget.component.ts | 93 --- .../app/modules/map/widget/map-widget.html | 33 -- .../context/context-menu.component.spec.ts | 5 +- .../menu/navigation/tabs-transition.ts | 40 +- .../src/app/modules/news/page/news-page.html | 2 +- .../src/app/modules/news/page/news-page.scss | 4 + .../app/modules/settings/settings.module.ts | 10 +- .../property-name-translate.pipe.ts | 1 + .../src/app/util/ion-icon/icon-match.spec.ts | 1 + frontend/app/src/app/util/ion-icon/icon.ts | 2 +- frontend/app/src/app/util/media-query.pipe.ts | 18 + .../app/util/word-break-opportunities.pipe.ts | 11 + frontend/app/src/assets/i18n/de.json | 2 +- frontend/app/src/assets/i18n/en.json | 2 +- frontend/app/src/assets/icon/favicon.png | Bin 2573 -> 0 bytes frontend/app/src/assets/icons.min.woff2 | Bin 100272 -> 110916 bytes frontend/app/src/global.scss | 2 + .../theme/common/_ion-content-parallax.scss | 5 + .../app/src/theme/common/_leaflet-tile.scss | 25 - frontend/app/src/theme/common/_maplibre.scss | 3 +- frontend/app/src/theme/variables.scss | 15 - frontend/app/tsconfig.json | 1 - pnpm-lock.yaml | 536 +++++++++++++----- 90 files changed, 2203 insertions(+), 1693 deletions(-) delete mode 100644 frontend/app/src/app/modules/config/config.module.ts create mode 100644 frontend/app/src/app/modules/data/elements/origin-detail.scss create mode 100644 frontend/app/src/app/modules/map/cluster-leaves.pipe.ts create mode 100644 frontend/app/src/app/modules/map/controls/attribution.component.ts create mode 100644 frontend/app/src/app/modules/map/controls/attribution.html create mode 100644 frontend/app/src/app/modules/map/controls/attribution.scss create mode 100644 frontend/app/src/app/modules/map/controls/compass-control.component.ts create mode 100644 frontend/app/src/app/modules/map/controls/compass-control.html create mode 100644 frontend/app/src/app/modules/map/controls/compass-control.scss create mode 100644 frontend/app/src/app/modules/map/controls/geolocate-control.component.ts create mode 100644 frontend/app/src/app/modules/map/controls/geolocate-control.html create mode 100644 frontend/app/src/app/modules/map/controls/geolocate-control.scss create mode 100644 frontend/app/src/app/modules/map/elements/building-markers.component.ts create mode 100644 frontend/app/src/app/modules/map/elements/building-markers.html create mode 100644 frontend/app/src/app/modules/map/elements/building-markers.scss create mode 100644 frontend/app/src/app/modules/map/elements/poi-marker.component.ts create mode 100644 frontend/app/src/app/modules/map/elements/poi-marker.html create mode 100644 frontend/app/src/app/modules/map/elements/poi-marker.scss create mode 100644 frontend/app/src/app/modules/map/elements/poi-markers.component.ts create mode 100644 frontend/app/src/app/modules/map/elements/poi-markers.html create mode 100644 frontend/app/src/app/modules/map/elements/poi-markers.scss create mode 100644 frontend/app/src/app/modules/map/feature-collection.pipe.ts create mode 100644 frontend/app/src/app/modules/map/map-auto-3d.directive.ts create mode 100644 frontend/app/src/app/modules/map/map-data.provider.ts create mode 100644 frontend/app/src/app/modules/map/map-icon.directive.ts create mode 100644 frontend/app/src/app/modules/map/map-maximize-animation.ts create mode 100644 frontend/app/src/app/modules/map/map-page.component.ts create mode 100644 frontend/app/src/app/modules/map/map-page.html create mode 100644 frontend/app/src/app/modules/map/map-page.scss create mode 100644 frontend/app/src/app/modules/map/map-size-fix.directive.ts create mode 100644 frontend/app/src/app/modules/map/map-style.directive.ts create mode 100644 frontend/app/src/app/modules/map/map-widget.component.ts create mode 100644 frontend/app/src/app/modules/map/map-widget.html rename frontend/app/src/app/modules/map/{widget => }/map-widget.scss (83%) delete mode 100644 frontend/app/src/app/modules/map/map.provider.spec.ts delete mode 100644 frontend/app/src/app/modules/map/map.provider.ts delete mode 100644 frontend/app/src/app/modules/map/page/map-list-modal.component.ts delete mode 100644 frontend/app/src/app/modules/map/page/map-list-modal.html delete mode 100644 frontend/app/src/app/modules/map/page/map-list-modal.scss delete mode 100644 frontend/app/src/app/modules/map/page/map-page.component.ts delete mode 100644 frontend/app/src/app/modules/map/page/map-page.html delete mode 100644 frontend/app/src/app/modules/map/page/map-page.scss create mode 100644 frontend/app/src/app/modules/map/thing-bounds.pipe.ts delete mode 100644 frontend/app/src/app/modules/map/widget/map-widget.component.ts delete mode 100644 frontend/app/src/app/modules/map/widget/map-widget.html create mode 100644 frontend/app/src/app/util/media-query.pipe.ts create mode 100644 frontend/app/src/app/util/word-break-opportunities.pipe.ts delete mode 100644 frontend/app/src/assets/icon/favicon.png delete mode 100644 frontend/app/src/theme/common/_leaflet-tile.scss diff --git a/.syncpackrc.cjs b/.syncpackrc.cjs index b9b89cdc..b28db580 100644 --- a/.syncpackrc.cjs +++ b/.syncpackrc.cjs @@ -2,7 +2,13 @@ /** @type {import('syncpack').RcFile} */ const config = { - semverGroups: [{range: ''}], + semverGroups: [ + { + range: '', + dependencies: ['**'], + packages: ['**'], + } + ], source: ['package.json', '**/package.json'], indent: ' ', sortFirst: [ diff --git a/backend/backend/src/storage/database.ts b/backend/backend/src/storage/database.ts index 770088b7..98027455 100644 --- a/backend/backend/src/storage/database.ts +++ b/backend/backend/src/storage/database.ts @@ -13,15 +13,34 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import {SCConfigFile, SCSearchQuery, SCSearchResponse, SCThings, SCUuid} from '@openstapps/core'; +import { + SCConfigFile, + SCPlace, + SCPlaceWithoutReferences, + SCSearchQuery, + SCSearchResponse, + SCThingWithCategoriesWithoutReferences, + SCThings, + SCUuid, +} from '@openstapps/core'; import {MailQueue} from '../notification/mail-queue.js'; import {Bulk} from './bulk-storage.js'; +import {FeatureCollection, Point, Polygon} from 'geojson'; /** * Creates an instance of a database */ export type DatabaseConstructor = new (config: SCConfigFile, mailQueue?: MailQueue) => Database; +export type SupplementaryGeoJSON = FeatureCollection; +export type SupplementaryGeoJSONThing = Pick< + Extract, + Exclude< + keyof SCPlaceWithoutReferences | keyof SCThingWithCategoriesWithoutReferences, + 'geo' | 'origin' | 'translations' + > +>; + /** * Defines what one database class needs to have defined */ @@ -82,4 +101,9 @@ export interface Database { * @param params Parameters which form a search query to search the backend data */ search(parameters: SCSearchQuery): Promise; + + /** + * Get geo info for display on a map + */ + geo(): Promise; } diff --git a/backend/backend/src/storage/elasticsearch/elasticsearch.ts b/backend/backend/src/storage/elasticsearch/elasticsearch.ts index 37d58185..dad86eef 100644 --- a/backend/backend/src/storage/elasticsearch/elasticsearch.ts +++ b/backend/backend/src/storage/elasticsearch/elasticsearch.ts @@ -26,7 +26,7 @@ import {Logger} from '@openstapps/logger'; import moment from 'moment'; import {MailQueue} from '../../notification/mail-queue.js'; import {Bulk} from '../bulk-storage.js'; -import {Database} from '../database.js'; +import {Database, SupplementaryGeoJSON, SupplementaryGeoJSONThing} from '../database.js'; import {parseAggregations} from './aggregations.js'; import * as Monitoring from './monitoring.js'; import {buildQuery} from './query/query.js'; @@ -46,6 +46,7 @@ import { } from './util/index.js'; import {noUndefined} from './util/no-undefined.js'; import {retryCatch, RetryOptions} from './util/retry.js'; +import {Feature, Point, Polygon} from 'geojson'; /** * A database interface for elasticsearch @@ -405,4 +406,49 @@ export class Elasticsearch implements Database { }, }; } + + async geo(): Promise { + const searchResponse = await this.client.search>({ + body: { + query: { + exists: { + field: 'geo', + }, + }, + }, + from: 0, + allow_no_indices: true, + index: ACTIVE_INDICES_ALIAS, + size: 1, + }); + + return { + type: 'FeatureCollection', + features: searchResponse.hits.hits + .map(thing => { + return thing._source?.geo + ? ({ + id: Number(thing._source.identifiers?.['OSM']) || undefined, + type: 'Feature', + geometry: thing._source.geo.polygon ?? thing._source.geo.point, + properties: { + name: thing._source.name, + sameAs: thing._source.sameAs, + image: thing._source.image, + alternateNames: thing._source.alternateNames, + description: thing._source.description, + identifiers: thing._source.identifiers, + categories: thing._source.categories, + categorySpecificValues: thing._source.categorySpecificValues, + openingHours: thing._source.openingHours, + address: thing._source.address, + uid: thing._source.uid, + type: thing._source.type, + }, + } satisfies Feature) + : undefined; + }) + .filter(noUndefined), + }; + } } diff --git a/backend/backend/src/storage/elasticsearch/query/filters/geo.ts b/backend/backend/src/storage/elasticsearch/query/filters/geo.ts index c9f8cb07..a6c87ccd 100644 --- a/backend/backend/src/storage/elasticsearch/query/filters/geo.ts +++ b/backend/backend/src/storage/elasticsearch/query/filters/geo.ts @@ -19,14 +19,29 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js'; * Converts a geo filter to elasticsearch syntax * @param filter A search filter for the retrieval of the data */ -export function buildGeoFilter(filter: SCGeoFilter): QueryDslSpecificQueryContainer<'geo_shape'> { +export function buildGeoFilter(filter: SCGeoFilter): QueryDslSpecificQueryContainer<'bool'> { return { - geo_shape: { - ignore_unmapped: true, - [`${filter.arguments.field}.polygon`]: { - shape: filter.arguments.shape, - relation: filter.arguments.spatialRelation, - }, + bool: { + should: [ + { + geo_shape: { + ignore_unmapped: true, + [`${filter.arguments.field}.polygon`]: { + shape: filter.arguments.shape, + relation: filter.arguments.spatialRelation, + }, + }, + } satisfies QueryDslSpecificQueryContainer<'geo_shape'>, + { + geo_shape: { + ignore_unmapped: true, + [`${filter.arguments.field}.point`]: { + shape: filter.arguments.shape, + relation: filter.arguments.spatialRelation, + }, + }, + } satisfies QueryDslSpecificQueryContainer<'geo_shape'>, + ], }, }; } diff --git a/backend/backend/test/common.ts b/backend/backend/test/common.ts index d576ae48..f68f4f47 100644 --- a/backend/backend/test/common.ts +++ b/backend/backend/test/common.ts @@ -22,7 +22,7 @@ import http from 'http'; import {MailQueue} from '../src/notification/mail-queue.js'; import {Bulk, BulkStorage} from '../src/storage/bulk-storage.js'; import getPort from 'get-port'; -import {Database} from '../src/storage/database.js'; +import {Database, SupplementaryGeoJSON} from '../src/storage/database.js'; import {v4} from 'uuid'; import {backendConfig} from '../src/config.js'; import {getIndexUID} from '../src/storage/elasticsearch/util/index.js'; @@ -58,7 +58,6 @@ export async function startApp(): Promise { * An elasticsearch mock */ export class ElasticsearchMock implements Database { - // @ts-expect-error never read private bulk: Bulk | undefined; private storageMock = new Map(); @@ -67,6 +66,10 @@ export class ElasticsearchMock implements Database { // Nothing to do here } + geo(): Promise { + throw new Error('Method not implemented.'); + } + bulkCreated(bulk: Bulk): Promise { this.bulk = bulk; return Promise.resolve(undefined); diff --git a/backend/backend/test/storage/elasticsearch/query.spec.ts b/backend/backend/test/storage/elasticsearch/query.spec.ts index af7087cb..00ebb9cf 100644 --- a/backend/backend/test/storage/elasticsearch/query.spec.ts +++ b/backend/backend/test/storage/elasticsearch/query.spec.ts @@ -479,18 +479,39 @@ describe('Query', function () { it('should build geo filter for shapes and points', function () { const filter = buildFilter(searchFilters.geoPoint); const expectedFilter = { - geo_shape: { - 'geo.polygon': { - relation: undefined, - shape: { - type: 'envelope', - coordinates: [ - [50.123, 8.123], - [50.123, 8.123], - ], + bool: { + should: [ + { + geo_shape: { + 'geo.polygon': { + relation: undefined, + shape: { + coordinates: [ + [50.123, 8.123], + [50.123, 8.123], + ], + type: 'envelope', + }, + }, + 'ignore_unmapped': true, + }, }, - }, - 'ignore_unmapped': true, + { + geo_shape: { + 'geo.point': { + relation: undefined, + shape: { + coordinates: [ + [50.123, 8.123], + [50.123, 8.123], + ], + type: 'envelope', + }, + }, + 'ignore_unmapped': true, + }, + }, + ], }, }; @@ -500,18 +521,39 @@ describe('Query', function () { it('should build geo filter for shapes only', function () { const filter = buildFilter(searchFilters.geoShape); const expectedFilter = { - geo_shape: { - 'geo.polygon': { - relation: 'contains', - shape: { - type: 'envelope', - coordinates: [ - [50.123, 8.123], - [50.123, 8.123], - ], + bool: { + should: [ + { + geo_shape: { + 'geo.polygon': { + relation: 'contains', + shape: { + coordinates: [ + [50.123, 8.123], + [50.123, 8.123], + ], + type: 'envelope', + }, + }, + 'ignore_unmapped': true, + }, }, - }, - 'ignore_unmapped': true, + { + geo_shape: { + 'geo.point': { + relation: 'contains', + shape: { + coordinates: [ + [50.123, 8.123], + [50.123, 8.123], + ], + type: 'envelope', + }, + }, + 'ignore_unmapped': true, + }, + }, + ], }, }; diff --git a/flake.lock b/flake.lock index e3eacb52..3ac48479 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "lastModified": 1709126324, + "narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=", "owner": "numtide", "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "rev": "d465f4819400de7c8d874d50b982301f28a84605", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1701626906, - "narHash": "sha256-ugr1QyzzwNk505ICE4VMQzonHQ9QS5W33xF2FXzFQ00=", + "lastModified": 1709747860, + "narHash": "sha256-RT4zuBy579m+l8VyIQFOR66WXfcs4g1jntZUHjh6eoI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "0c6d8c783336a59f4c59d4a6daed6ab269c4b361", + "rev": "58ae79ea707579c40102ddf62d84b902a987c58b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 12461e7d..0fe1f26c 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,7 @@ hash = "sha256-9o0nprGcJhudS1LNm+T7Vf0Dwd1RBauYKI+w1FBQ3ZM="; }; }); + nodejs = prev.nodejs_18; }) ]; config = { @@ -49,21 +50,16 @@ devShell = pkgs.mkShell rec { nativeBuildInputs = [androidFhs]; buildInputs = with pkgs; [ - nodejs-18_x - nodePackages.pnpm + nodejs + corepack # tools curl jq fontMin - # browsers - firefox - google-chrome - epiphany # Safari-ish browser cypress # android jdk17 android.androidsdk - musl ]; ANDROID_JAVA_HOME = "${pkgs.jdk.home}"; ANDROID_SDK_ROOT = "${pkgs.android.androidsdk}/libexec/android-sdk"; diff --git a/frontend/app/angular.json b/frontend/app/angular.json index 037e4e50..ce335c00 100644 --- a/frontend/app/angular.json +++ b/frontend/app/angular.json @@ -35,20 +35,13 @@ "glob": "**/*", "input": "src/assets", "output": "assets" - }, - { - "glob": "**/*", - "input": "./node_modules/leaflet/dist/images", - "output": "assets/" } ], "styles": [ { "input": "src/global.scss", "inject": true - }, - "./node_modules/leaflet/dist/leaflet.css", - "./node_modules/leaflet.markercluster/dist/MarkerCluster.Default.css" + } ] }, "configurations": { @@ -131,11 +124,6 @@ "glob": "**/*", "input": "src/assets", "output": "/assets" - }, - { - "glob": "**/*", - "input": "./node_modules/leaflet/dist/images", - "output": "assets/" } ] } diff --git a/frontend/app/package.json b/frontend/app/package.json index f21738ac..c32257ef 100644 --- a/frontend/app/package.json +++ b/frontend/app/package.json @@ -38,13 +38,7 @@ "licenses": "license-checker --json > src/assets/about/licenses.json && node ./scripts/accumulate-licenses.mjs && git add src/assets/about/licenses.json", "lint": "ng lint && stylelint \"**/*.scss\"", "lint:fix": "eslint --fix -c .eslintrc.json --ignore-path .eslintignore --ext .ts,.html src/ && stylelint --fix \"**/*.scss\"", -<<<<<<< HEAD - "minify-icons": "ts-node-esm scripts/minify-icon-font.ts", -||||||| parent of 7b431b8f (feat: type-safe sc-icons) - "minify-icons": "ts-node scripts/minify-icon-font.ts", -======= "minify-icons": "node scripts/minify-icon-font.mjs", ->>>>>>> 7b431b8f (feat: type-safe sc-icons) "postinstall": "jetify && echo \"skipping jetify in production mode\"", "preview": "http-server www --p 8101 -o", "push": "git push && git push origin \"v$npm_package_version\"", @@ -65,8 +59,6 @@ "@angular/forms": "17.3.0", "@angular/platform-browser": "17.3.0", "@angular/router": "17.3.0", - "@asymmetrik/ngx-leaflet": "17.0.0", - "@asymmetrik/ngx-leaflet-markercluster": "17.0.0", "@awesome-cordova-plugins/calendar": "6.6.0", "@awesome-cordova-plugins/core": "6.6.0", "@capacitor/app": "5.0.7", @@ -87,6 +79,7 @@ "@ionic-native/core": "5.36.0", "@ionic/angular": "7.8.0", "@ionic/storage-angular": "4.0.0", + "@maplibre/ngx-maplibre-gl": "17.4.1", "@ngx-translate/core": "15.0.0", "@ngx-translate/http-loader": "8.0.0", "@openid/appauth": "1.3.1", @@ -103,15 +96,15 @@ "geojson": "0.5.0", "ionic-appauth": "0.9.0", "jsonpath-plus": "6.0.1", - "leaflet": "1.9.4", - "leaflet.markercluster": "1.5.3", - "material-symbols": "0.17.0", + "maplibre-gl": "4.0.2", + "material-symbols": "0.17.1", "moment": "2.30.1", "ngx-date-fns": "11.0.0", "ngx-logger": "5.0.12", "ngx-markdown": "17.1.1", "ngx-moment": "6.0.2", "opening_hours": "3.8.0", + "pmtiles": "3.0.3", "rxjs": "7.8.1", "semver": "7.6.0", "swiper": "8.4.5", @@ -153,8 +146,6 @@ "@types/karma": "6.3.8", "@types/karma-coverage": "2.0.3", "@types/karma-jasmine": "4.0.5", - "@types/leaflet": "1.9.8", - "@types/leaflet.markercluster": "1.5.4", "@types/node": "18.15.3", "@types/semver": "7.5.8", "@typescript-eslint/eslint-plugin": "7.2.0", @@ -181,7 +172,7 @@ "karma-junit-reporter": "2.0.1", "karma-mocha-reporter": "2.2.5", "license-checker": "25.0.1", - "stylelint": "16.2.1", + "stylelint": "16.3.1", "stylelint-config-clean-order": "5.4.1", "stylelint-config-prettier-scss": "1.0.0", "stylelint-config-recommended-scss": "14.0.0", diff --git a/frontend/app/src/app/app.module.ts b/frontend/app/src/app/app.module.ts index fd6549a6..80c0fcd6 100644 --- a/frontend/app/src/app/app.module.ts +++ b/frontend/app/src/app/app.module.ts @@ -30,7 +30,6 @@ import {environment} from '../environments/environment'; import {AppRoutingModule} from './app-routing.module'; import {AppComponent} from './app.component'; import {CatalogModule} from './modules/catalog/catalog.module'; -import {ConfigModule} from './modules/config/config.module'; import {ConfigProvider} from './modules/config/config.provider'; import {DashboardModule} from './modules/dashboard/dashboard.module'; import {DataModule} from './modules/data/data.module'; @@ -70,6 +69,8 @@ import {setDefaultOptions} from 'date-fns'; import {DateFnsConfigurationService} from 'ngx-date-fns'; import {Capacitor} from '@capacitor/core'; import {SplashScreen} from '@capacitor/splash-screen'; +import maplibregl from 'maplibre-gl'; +import {Protocol} from 'pmtiles'; registerLocaleData(localeDe); @@ -91,6 +92,7 @@ export function initializerFactory( ) { return async () => { try { + maplibregl.addProtocol('pmtiles', new Protocol().tile); initLogger(logger); await storageProvider.init(); await configProvider.init(); @@ -151,7 +153,6 @@ export function createTranslateLoader(http: HttpClient) { BrowserAnimationsModule, CatalogModule, CommonModule, - ConfigModule, DashboardModule, DataModule, HebisModule, diff --git a/frontend/app/src/app/modules/about/about.module.ts b/frontend/app/src/app/modules/about/about.module.ts index 5c975fa3..0dc3876d 100644 --- a/frontend/app/src/app/modules/about/about.module.ts +++ b/frontend/app/src/app/modules/about/about.module.ts @@ -19,7 +19,6 @@ import {FormsModule} from '@angular/forms'; import {IonicModule} from '@ionic/angular'; import {TranslateModule} from '@ngx-translate/core'; import {ThingTranslateModule} from '../../translation/thing-translate.module'; -import {ConfigProvider} from '../config/config.provider'; import {AboutPageComponent} from './about-page/about-page.component'; import {MarkdownModule} from 'ngx-markdown'; import {AboutPageContentComponent} from './about-page/about-page-content.component'; @@ -64,6 +63,5 @@ const settingsRoutes: Routes = [ ScrollingModule, UtilModule, ], - providers: [ConfigProvider], }) export class AboutModule {} diff --git a/frontend/app/src/app/modules/config/config.module.ts b/frontend/app/src/app/modules/config/config.module.ts deleted file mode 100644 index cd3ee9cb..00000000 --- a/frontend/app/src/app/modules/config/config.module.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2019 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {NgModule} from '@angular/core'; -import {DataModule} from '../data/data.module'; -import {StorageModule} from '../storage/storage.module'; -import {ConfigProvider} from './config.provider'; - -/** - * TODO - */ -@NgModule({ - imports: [StorageModule, DataModule], - providers: [ConfigProvider], -}) -export class ConfigModule {} diff --git a/frontend/app/src/app/modules/config/config.provider.ts b/frontend/app/src/app/modules/config/config.provider.ts index eed00bec..46671e03 100644 --- a/frontend/app/src/app/modules/config/config.provider.ts +++ b/frontend/app/src/app/modules/config/config.provider.ts @@ -73,6 +73,7 @@ export class ConfigProvider { swHttpClient: StAppsWebHttpClient, private readonly logger: NGXLogger, ) { + console.log('config init'); this.client = new Client(swHttpClient, environment.backend_url, environment.backend_version); } diff --git a/frontend/app/src/app/modules/data/data.module.ts b/frontend/app/src/app/modules/data/data.module.ts index 09697966..a8f89ec5 100644 --- a/frontend/app/src/app/modules/data/data.module.ts +++ b/frontend/app/src/app/modules/data/data.module.ts @@ -17,7 +17,6 @@ import {CommonModule} from '@angular/common'; import {HttpClientModule} from '@angular/common/http'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; -import {LeafletModule} from '@asymmetrik/ngx-leaflet'; import {IonicModule, Platform} from '@ionic/angular'; import {TranslateModule} from '@ngx-translate/core'; import {MarkdownModule} from 'ngx-markdown'; @@ -30,7 +29,7 @@ import {UtilModule} from '../../util/util.module'; import {CalendarService} from '../calendar/calendar.service'; import {ScheduleProvider} from '../calendar/schedule.provider'; import {GeoNavigationDirective} from '../map/geo-navigation.directive'; -import {MapWidgetComponent} from '../map/widget/map-widget.component'; +import {MapWidgetComponent} from '../map/map-widget.component'; import {MenuModule} from '../menu/menu.module'; import {SettingsProvider} from '../settings/settings.provider'; import {StorageModule} from '../storage/storage.module'; @@ -142,7 +141,6 @@ import {ShareButtonComponent} from './elements/share-button.component'; FoodDataListComponent, LocateActionChipComponent, LongInlineTextComponent, - MapWidgetComponent, MessageDetailContentComponent, MessageListItemComponent, JobPostingDetailContentComponent, @@ -187,9 +185,9 @@ import {ShareButtonComponent} from './elements/share-button.component'; CommonModule, DataRoutingModule, FormsModule, + MapWidgetComponent, HttpClientModule, IonicModule.forRoot(), - LeafletModule, MarkdownModule.forRoot(), MenuModule, IonIconModule, diff --git a/frontend/app/src/app/modules/data/detail/data-detail-content.scss b/frontend/app/src/app/modules/data/detail/data-detail-content.scss index 09eac6e3..3586c18d 100644 --- a/frontend/app/src/app/modules/data/detail/data-detail-content.scss +++ b/frontend/app/src/app/modules/data/detail/data-detail-content.scss @@ -14,6 +14,10 @@ */ @import '../../../../theme/util/mixins'; +:host { + display: contents; +} + stapps-origin-detail { // css hack to make the element stick to the bottom of the scroll container even // when the content is not filling it @@ -49,13 +53,10 @@ stapps-origin-detail { background: var(--ion-color-primary); } - // Firefox doesn't support this yet... - @supports selector(:has(*)) { - & > .expand-when-space, - &:has(> .expand-when-space) { - flex: 1; - height: unset; - } + & > .expand-when-space, + &:has(> .expand-when-space) { + flex: 1; + height: unset; } } } diff --git a/frontend/app/src/app/modules/data/detail/data-detail.scss b/frontend/app/src/app/modules/data/detail/data-detail.scss index 5887f46f..dac662b4 100644 --- a/frontend/app/src/app/modules/data/detail/data-detail.scss +++ b/frontend/app/src/app/modules/data/detail/data-detail.scss @@ -17,7 +17,6 @@ ion-content > div { display: flex; flex: 1; flex-direction: column; - min-height: 100%; } ion-title { diff --git a/frontend/app/src/app/modules/data/elements/origin-detail.component.ts b/frontend/app/src/app/modules/data/elements/origin-detail.component.ts index 5ede56ec..903477ef 100644 --- a/frontend/app/src/app/modules/data/elements/origin-detail.component.ts +++ b/frontend/app/src/app/modules/data/elements/origin-detail.component.ts @@ -21,6 +21,7 @@ import {SCThingUserOrigin, SCThingRemoteOrigin} from '@openstapps/core'; @Component({ selector: 'stapps-origin-detail', templateUrl: 'origin-detail.html', + styleUrl: 'origin-detail.scss', }) export class OriginDetailComponent { /** diff --git a/frontend/app/src/app/modules/data/elements/origin-detail.html b/frontend/app/src/app/modules/data/elements/origin-detail.html index 40cba4da..6648e044 100644 --- a/frontend/app/src/app/modules/data/elements/origin-detail.html +++ b/frontend/app/src/app/modules/data/elements/origin-detail.html @@ -14,71 +14,61 @@ --> @if (origin.type === 'user') { - - {{ 'data.types.origin.TITLE' | translate | titlecase }}: - {{ 'data.types.origin.USER' | translate | titlecase }} - -

- {{ 'data.types.origin.detail.CREATED' | translate | titlecase }}: - {{ origin.created | amDateFormat: 'll' }} -

- @if (origin.updated) { -

- {{ 'data.types.origin.detail.UPDATED' | translate | titlecase }}: - {{ origin.updated | amDateFormat: 'll' }} -

- } - @if (origin.modified) { -

- {{ 'data.types.origin.detail.MODIFIED' | translate | titlecase }}: - {{ origin.modified | amDateFormat: 'll' }} -

- } - @if (origin.maintainer) { -

- {{ 'data.types.origin.detail.MAINTAINER' | translate }}: - {{ origin.maintainer.name }} -

- } -
-
+

+ {{ 'data.types.origin.TITLE' | translate | sentencecase }}: + {{ 'data.types.origin.USER' | translate | sentencecase }} +

+

+ {{ 'data.types.origin.detail.CREATED' | translate | sentencecase }}: + {{ origin.created | amDateFormat: 'll' }} +

+ @if (origin.updated) { +

+ {{ 'data.types.origin.detail.UPDATED' | translate | sentencecase }}: + {{ origin.updated | amDateFormat: 'll' }} +

+ } + @if (origin.modified) { +

+ {{ 'data.types.origin.detail.MODIFIED' | translate | sentencecase }}: + {{ origin.modified | amDateFormat: 'll' }} +

+ } + @if (origin.maintainer) { +

+ {{ 'data.types.origin.detail.MAINTAINER' | translate | sentencecase }}: + {{ origin.maintainer.name }} +

+ } } @if (origin.type === 'remote') { - - {{ 'data.types.origin.TITLE' | translate | titlecase }}: - {{ 'data.types.origin.REMOTE' | translate | titlecase }} - -

- {{ 'data.types.origin.detail.INDEXED' | translate | titlecase }}: - {{ origin.indexed | amDateFormat: 'll' }} -

- @if (origin.modified) { -

- {{ 'data.types.origin.detail.MODIFIED' | translate | titlecase }}: - {{ origin.modified | amDateFormat: 'll' }} -

- } - @if (origin.name) { -

{{ 'data.types.origin.detail.MAINTAINER' | translate }}: {{ origin.name }}

- } - @if (origin.maintainer) { -

- {{ 'data.types.origin.detail.MAINTAINER' | translate | titlecase }}: - {{ origin.maintainer.name }} -

- } - @if (origin.responsibleEntity) { -

- {{ 'data.types.origin.detail.RESPONSIBLE' | translate | titlecase }}: - {{ - origin.responsibleEntity.name - }} -

- } -
-
+

+ {{ 'data.types.origin.TITLE' | translate | sentencecase }}: + {{ 'data.types.origin.REMOTE' | translate | sentencecase }} +

+

+ {{ 'data.types.origin.detail.INDEXED' | translate | sentencecase }}: + {{ origin.indexed | amDateFormat: 'll' }} +

+ @if (origin.modified) { +

+ {{ 'data.types.origin.detail.MODIFIED' | translate | sentencecase }}: + {{ origin.modified | amDateFormat: 'll' }} +

+ } + @if (origin.name) { +

{{ 'data.types.origin.detail.MAINTAINER' | translate | sentencecase }}: {{ origin.name }}

+ } + @if (origin.maintainer) { +

+ {{ 'data.types.origin.detail.MAINTAINER' | translate | sentencecase }}: + {{ origin.maintainer.name }} +

+ } + @if (origin.responsibleEntity) { +

+ {{ 'data.types.origin.detail.RESPONSIBLE' | translate | sentencecase }}: + {{ origin.responsibleEntity.name }} +

+ } } diff --git a/frontend/app/src/app/modules/data/elements/origin-detail.scss b/frontend/app/src/app/modules/data/elements/origin-detail.scss new file mode 100644 index 00000000..049ff9d0 --- /dev/null +++ b/frontend/app/src/app/modules/data/elements/origin-detail.scss @@ -0,0 +1,15 @@ +:host { + padding: var(--spacing-lg); + padding-top: 0; +} + +h3 { + font-weight: bold; +} + +h3, +p { + margin: 0; + font-size: 0.8em; + opacity: 0.8; +} diff --git a/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.html b/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.html index 9ca39b93..e824836b 100644 --- a/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.html +++ b/frontend/app/src/app/modules/data/types/date-series/date-series-detail-content.html @@ -68,5 +68,5 @@ } @if (item.inPlace && item.inPlace.geo) { - + } diff --git a/frontend/app/src/app/modules/data/types/place/place-list-item.component.ts b/frontend/app/src/app/modules/data/types/place/place-list-item.component.ts index b15d6c01..63e4f263 100644 --- a/frontend/app/src/app/modules/data/types/place/place-list-item.component.ts +++ b/frontend/app/src/app/modules/data/types/place/place-list-item.component.ts @@ -17,7 +17,6 @@ import {PositionService} from '../../../map/position.service'; import {filter, Observable} from 'rxjs'; import {hasValidLocation, isSCFloor, PlaceTypes, PlaceTypesWithDistance} from './place-types'; import {map} from 'rxjs/operators'; -import {LatLng, geoJSON} from 'leaflet'; import {trigger, transition, style, animate} from '@angular/animations'; /** @@ -39,13 +38,14 @@ export class PlaceListItemComponent { @Input() set item(item: PlaceTypes) { this._item = item; if (!isSCFloor(item) && hasValidLocation(item)) { - this.distance = this.positionService.watchCurrentLocation().pipe( - map(position => - new LatLng(position.latitude, position.longitude).distanceTo( - geoJSON(item.geo.point).getBounds().getCenter(), - ), + this.distance = this.positionService.geoLocation.pipe( + map( + position => + Math.hypot( + position.coords.latitude - item.geo.point.coordinates[1], + position.coords.longitude - item.geo.point.coordinates[0], + ) * 111_139, ), - filter(it => it !== undefined), ); } diff --git a/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts b/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts index 15bd2bd0..4a739f5d 100644 --- a/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts +++ b/frontend/app/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts @@ -12,7 +12,6 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import moment, {Moment} from 'moment'; import {AfterViewInit, Component, DestroyRef, inject, Input} from '@angular/core'; import {SCDish, SCISO8601Date, SCPlace} from '@openstapps/core'; import {PlaceMensaService} from './place-mensa-service'; @@ -53,11 +52,6 @@ export class PlaceMensaDetailComponent implements AfterViewInit { */ selectedDay: string; - /** - * First day to display menu items for - */ - startingDay: Moment; - destroy$ = inject(DestroyRef); constructor( @@ -65,9 +59,7 @@ export class PlaceMensaDetailComponent implements AfterViewInit { protected router: Router, readonly routerOutlet: IonRouterOutlet, private readonly dataRoutingService: DataRoutingService, - ) { - this.startingDay = moment().startOf('day'); - } + ) {} ngAfterViewInit() { if (!this.openAsModal) { diff --git a/frontend/app/src/app/modules/jobs/jobs.module.ts b/frontend/app/src/app/modules/jobs/jobs.module.ts index 90703617..5d00f5be 100644 --- a/frontend/app/src/app/modules/jobs/jobs.module.ts +++ b/frontend/app/src/app/modules/jobs/jobs.module.ts @@ -6,7 +6,6 @@ import {MomentModule} from 'ngx-moment'; import {DataModule} from '../data/data.module'; import {UtilModule} from '../../util/util.module'; import {IonIconModule} from '../../util/ion-icon/ion-icon.module'; -import {ConfigProvider} from '../config/config.provider'; import {ThingTranslateModule} from '../../translation/thing-translate.module'; import {RouterModule, Routes} from '@angular/router'; import {JobsPageComponent} from './page/jobs-page.component'; @@ -26,6 +25,5 @@ const jobsRoutes: Routes = [{path: 'jobs', component: JobsPageComponent}]; DataModule, UtilModule, ], - providers: [ConfigProvider], }) export class JobModule {} diff --git a/frontend/app/src/app/modules/map/cluster-leaves.pipe.ts b/frontend/app/src/app/modules/map/cluster-leaves.pipe.ts new file mode 100644 index 00000000..4f960438 --- /dev/null +++ b/frontend/app/src/app/modules/map/cluster-leaves.pipe.ts @@ -0,0 +1,51 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {MapService} from '@maplibre/ngx-maplibre-gl'; +import {Feature, Point} from 'geojson'; +import {MapGeoJSONFeature, type GeoJSONSource} from 'maplibre-gl'; +import {combineLatest, distinctUntilChanged, map, mergeMap, from, Observable, ReplaySubject} from 'rxjs'; +import {SCFeatureProperties} from './feature-collection.pipe'; + +@Pipe({ + name: 'mglClusterLeaves', + standalone: true, + pure: true, +}) +export class MglClusterLeavesPipe implements PipeTransform { + source = new ReplaySubject(1); + + feature = new ReplaySubject(1); + + limit = new ReplaySubject(1); + + offset = new ReplaySubject(1); + + leaves: Observable[]> = combineLatest([ + this.source.pipe( + distinctUntilChanged(), + map(source => this.mapService.getSource(source) as GeoJSONSource), + ), + this.feature.pipe(distinctUntilChanged(it => it.properties.cluster_id)), + this.limit.pipe(distinctUntilChanged()), + this.offset.pipe(distinctUntilChanged()), + ]).pipe( + mergeMap(([source, feature, limit, offset]) => + from(source.getClusterLeaves(feature.properties.cluster_id, limit, offset)), + ), + ); + + constructor(private mapService: MapService) {} + + transform( + source: string, + feature: MapGeoJSONFeature, + limit = 0, + offset = 0, + ): Observable[]> { + // MapLibre triggers change detection when the map moves, so this is to prevent flicker + this.source.next(source); + this.feature.next(feature); + this.limit.next(limit); + this.offset.next(offset); + return this.leaves; + } +} diff --git a/frontend/app/src/app/modules/map/controls/attribution.component.ts b/frontend/app/src/app/modules/map/controls/attribution.component.ts new file mode 100644 index 00000000..7c5186b2 --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/attribution.component.ts @@ -0,0 +1,38 @@ +import {animate, style, transition, trigger} from '@angular/animations'; +import {AsyncPipe} from '@angular/common'; +import {ChangeDetectionStrategy, Component, Input, inject} from '@angular/core'; +import {IonicModule} from '@ionic/angular'; +import {MapService} from '@maplibre/ngx-maplibre-gl'; +import {map, delay, Subject, race, mergeWith} from 'rxjs'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; + +@Component({ + selector: 'stapps-map-attribution', + templateUrl: './attribution.html', + styleUrl: './attribution.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [IonicModule, IonIconModule, AsyncPipe], + animations: [ + trigger('fade', [ + transition(':enter', [ + style({opacity: 0, scale: '0.8 1'}), + animate('0.2s ease', style({opacity: 1, scale: 1})), + ]), + transition(':leave', [ + style({opacity: 1, scale: 1}), + animate('0.2s ease', style({opacity: 0, scale: '0.8 1'})), + ]), + ]), + ], +}) +export class AttributionComponent { + @Input() direction: 'left' | 'right' = 'right'; + + manualVisible = new Subject(); + + hideAttribution = race( + this.manualVisible, + inject(MapService).mapCreated$.pipe(delay(5000), mergeWith(this.manualVisible)), + ).pipe(map((_, i) => i % 2 === 0)); +} diff --git a/frontend/app/src/app/modules/map/controls/attribution.html b/frontend/app/src/app/modules/map/controls/attribution.html new file mode 100644 index 00000000..0dd33c15 --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/attribution.html @@ -0,0 +1,8 @@ +@if ((hideAttribution | async) === null) { + © OpenStreetMap +} + + + diff --git a/frontend/app/src/app/modules/map/controls/attribution.scss b/frontend/app/src/app/modules/map/controls/attribution.scss new file mode 100644 index 00000000..131e6fbd --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/attribution.scss @@ -0,0 +1,36 @@ +:host { + position: relative; +} + +ion-button { + height: 28px; + min-height: 28px; + margin: 0; + font-size: 10px; +} + +ion-button.info { + --padding-start: 4px; + --padding-end: 4px; +} + +ion-button.attribution { + position: absolute; + top: -3px; + + &[direction='right'] { + --border-radius: 0 14px 14px 0; + --padding-start: 14px; + + left: 16px; + transform-origin: 0 0; + } + + &[direction='left'] { + --border-radius: 14px 0 0 14px; + --padding-end: 14px; + + right: 16px; + transform-origin: 100% 0; + } +} diff --git a/frontend/app/src/app/modules/map/controls/compass-control.component.ts b/frontend/app/src/app/modules/map/controls/compass-control.component.ts new file mode 100644 index 00000000..9a931ba3 --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/compass-control.component.ts @@ -0,0 +1,40 @@ +import {AsyncPipe} from '@angular/common'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {IonicModule} from '@ionic/angular'; +import {MapService} from '@maplibre/ngx-maplibre-gl'; +import {MapEventType} from 'maplibre-gl'; +import {map, mergeMap, fromEventPattern, merge} from 'rxjs'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; + +@Component({ + selector: 'stapps-compass-control', + templateUrl: './compass-control.html', + styleUrl: './compass-control.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [AsyncPipe, IonicModule, IonIconModule], +}) +export class CompassControlComponent { + transform = this.mapService.mapCreated$.pipe( + mergeMap(() => + merge( + fromEventPattern( + handler => this.mapService.mapInstance.on('rotate', handler), + handler => this.mapService.mapInstance.off('rotate', handler), + ), + fromEventPattern( + handler => this.mapService.mapInstance.on('pitch', handler), + handler => this.mapService.mapInstance.off('pitch', handler), + ), + ), + ), + map(event => { + const pitch = event.target.transform.pitch; + const angle = event.target.transform.angle; + + return `rotateX(${pitch}deg) rotateZ(${angle}rad)`; + }), + ); + + constructor(readonly mapService: MapService) {} +} diff --git a/frontend/app/src/app/modules/map/controls/compass-control.html b/frontend/app/src/app/modules/map/controls/compass-control.html new file mode 100644 index 00000000..032ad172 --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/compass-control.html @@ -0,0 +1,7 @@ + + + > + + + + diff --git a/frontend/app/src/app/modules/map/controls/compass-control.scss b/frontend/app/src/app/modules/map/controls/compass-control.scss new file mode 100644 index 00000000..2806a70c --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/compass-control.scss @@ -0,0 +1,11 @@ +path { + stroke: none; + + &:first-child { + fill: var(--ion-color-primary); + } + + &:last-child { + fill: var(--ion-color-medium); + } +} diff --git a/frontend/app/src/app/modules/map/controls/geolocate-control.component.ts b/frontend/app/src/app/modules/map/controls/geolocate-control.component.ts new file mode 100644 index 00000000..98b955d9 --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/geolocate-control.component.ts @@ -0,0 +1,91 @@ +import {AsyncPipe} from '@angular/common'; +import { + AfterContentInit, + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + OnDestroy, + ViewChild, +} from '@angular/core'; +import {IonicModule} from '@ionic/angular'; +import {MapService} from '@maplibre/ngx-maplibre-gl'; +import {FitBoundsOptions, GeolocateControl, GeolocateControlOptions} from 'maplibre-gl'; +import {Map as MapLibre} from 'maplibre-gl'; +import {BehaviorSubject} from 'rxjs'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; + +type WatchState = InstanceType['_watchState']; + +class CustomGeolocateControl extends GeolocateControl { + constructor( + public _container: HTMLElement, + watchState: BehaviorSubject, + options: GeolocateControlOptions, + ) { + super(options); + Object.defineProperty(this, '_watchState', { + get() { + return watchState.value; + }, + set(value: WatchState) { + watchState.next(value); + }, + }); + } + + override onAdd(map: MapLibre): HTMLElement { + const container = this._container; + this._container = document.createElement('div'); + this._map = map; + this._setupUI(true); + this._container = container; + return this._container; + } + + override onRemove() {} +} + +@Component({ + selector: 'stapps-geolocate-control', + templateUrl: './geolocate-control.html', + styleUrl: './geolocate-control.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [AsyncPipe, IonicModule, IonIconModule], +}) +export class GeolocateControlComponent implements AfterContentInit, OnDestroy { + @Input() position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; + + @Input() positionOptions?: PositionOptions; + + @Input() fitBoundsOptions?: FitBoundsOptions; + + @Input() trackUserLocation?: boolean; + + @Input() showUserLocation?: boolean; + + @ViewChild('content', {static: true}) content: ElementRef; + + watchState = new BehaviorSubject('OFF'); + + control: CustomGeolocateControl; + + constructor(private mapService: MapService) {} + + ngAfterContentInit() { + this.control = new CustomGeolocateControl(this.content.nativeElement, this.watchState, { + positionOptions: this.positionOptions, + fitBoundsOptions: this.fitBoundsOptions, + trackUserLocation: this.trackUserLocation, + showUserLocation: this.showUserLocation, + }); + this.mapService.mapCreated$.subscribe(() => { + this.mapService.addControl(this.control, this.position); + }); + } + + ngOnDestroy(): void { + this.mapService.removeControl(this.control); + } +} diff --git a/frontend/app/src/app/modules/map/controls/geolocate-control.html b/frontend/app/src/app/modules/map/controls/geolocate-control.html new file mode 100644 index 00000000..b48772c9 --- /dev/null +++ b/frontend/app/src/app/modules/map/controls/geolocate-control.html @@ -0,0 +1,18 @@ +
+ + @switch (watchState | async) { + @case ('ACTIVE_LOCK') { + + } + @case ('BACKGROUND') { + + } + @case ('WAITING_ACTIVE') { + + } + @default { + + } + } + +
diff --git a/frontend/app/src/app/modules/map/controls/geolocate-control.scss b/frontend/app/src/app/modules/map/controls/geolocate-control.scss new file mode 100644 index 00000000..e69de29b diff --git a/frontend/app/src/app/modules/map/elements/building-markers.component.ts b/frontend/app/src/app/modules/map/elements/building-markers.component.ts new file mode 100644 index 00000000..d64bc6e8 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/building-markers.component.ts @@ -0,0 +1,86 @@ +import {ChangeDetectionStrategy, Component, Input, Optional} from '@angular/core'; +import {GeoJSONSourceComponent, LayerComponent, MapService} from '@maplibre/ngx-maplibre-gl'; +import {FeatureCollection, Polygon} from 'geojson'; +import {SCFeatureProperties} from '../feature-collection.pipe'; +import { + FillLayerSpecification, + LineLayerSpecification, + MapLayerMouseEvent, + SymbolLayerSpecification, +} from 'maplibre-gl'; +import {DataRoutingService} from '../../data/data-routing.service'; +import {MapDataProvider} from '../map-data.provider'; +import {fromEvent, map, startWith, Observable} from 'rxjs'; +import {AsyncPipe} from '@angular/common'; + +/** + * Get a CCS variable value + */ +function getCssVariable(color: string) { + return getComputedStyle(document.documentElement).getPropertyValue(color); +} + +@Component({ + selector: 'stapps-building-markers', + templateUrl: './building-markers.html', + styleUrl: './building-markers.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [GeoJSONSourceComponent, LayerComponent, AsyncPipe], +}) +export class BuildingMarkersComponent { + accentColor = getCssVariable('--ion-color-primary'); + + haloColor = fromEvent( + window.matchMedia('(prefers-color-scheme: dark)'), + 'change', + ).pipe( + map(() => getCssVariable('--ion-background-color')), + startWith(getCssVariable('--ion-background-color')), + ); + + buildingPaint: LineLayerSpecification['paint'] = { + 'line-color': this.accentColor, + 'line-width': 2, + }; + + buildingFillPaint: FillLayerSpecification['paint'] = { + 'fill-color': `${this.accentColor}22`, + }; + + buildingLabelLayout: SymbolLayerSpecification['layout'] = { + 'text-field': '{name}', + 'text-font': ['barlow-700-normal'], + 'text-max-width': 8, + 'text-size': 13, + }; + + buildingLabelPaint: Observable = this.haloColor.pipe( + map(haloColor => ({ + 'text-color': this.accentColor, + 'text-halo-color': haloColor, + 'text-halo-width': 1, + })), + ); + + @Input({required: true}) data: FeatureCollection; + + constructor( + @Optional() readonly dataProvider: MapDataProvider | null, + readonly dataRoutingService: DataRoutingService, + readonly mapService: MapService, + ) {} + + async featureClick(event: MapLayerMouseEvent) { + if (this.dataProvider === null) return; + + if (event.originalEvent.target !== event.target._canvas) return; + const feature = event.features?.[0]; + if (!feature) return; + + const item = this.dataProvider.current.value?.data.find(it => it.uid === feature.properties.uid); + if (item === undefined) return; + + this.dataRoutingService.emitChildEvent(item); + } +} diff --git a/frontend/app/src/app/modules/map/elements/building-markers.html b/frontend/app/src/app/modules/map/elements/building-markers.html new file mode 100644 index 00000000..df243714 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/building-markers.html @@ -0,0 +1,26 @@ + + + + diff --git a/frontend/app/src/app/modules/map/elements/building-markers.scss b/frontend/app/src/app/modules/map/elements/building-markers.scss new file mode 100644 index 00000000..e69de29b diff --git a/frontend/app/src/app/modules/map/elements/poi-marker.component.ts b/frontend/app/src/app/modules/map/elements/poi-marker.component.ts new file mode 100644 index 00000000..e4ad1132 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/poi-marker.component.ts @@ -0,0 +1,43 @@ +import {ChangeDetectionStrategy, Component, HostBinding, Input, OnInit, Optional} from '@angular/core'; +import {IonicModule} from '@ionic/angular'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; +import {MapIconDirective} from '../map-icon.directive'; +import {Feature, Point} from 'geojson'; +import {SCFeatureProperties} from '../feature-collection.pipe'; +import {MapDataProvider} from '../map-data.provider'; +import {DataRoutingService} from '../../data/data-routing.service'; +import {AddWordBreakOpportunitiesPipe} from '../../../util/word-break-opportunities.pipe'; + +@Component({ + selector: 'stapps-poi-marker', + templateUrl: './poi-marker.html', + styleUrl: './poi-marker.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [IonicModule, IonIconModule, MapIconDirective, AddWordBreakOpportunitiesPipe], +}) +export class PoiMarkerComponent implements OnInit { + @Input({required: true}) feature: Feature; + + @HostBinding('disabled') disabled = this.dataProvider === null; + + fontSize = 0; + + constructor( + @Optional() readonly dataProvider: MapDataProvider | null, + readonly dataRoutingService: DataRoutingService, + ) {} + + async featureClick() { + if (this.dataProvider === null) return; + + const item = this.dataProvider.current.value?.data.find(it => it.uid === this.feature.properties.uid); + if (item === undefined) return; + + this.dataRoutingService.emitChildEvent(item); + } + + ngOnInit() { + this.fontSize = Math.max(10, 12 - Math.max(0, this.feature.properties.name.length - 16)); + } +} diff --git a/frontend/app/src/app/modules/map/elements/poi-marker.html b/frontend/app/src/app/modules/map/elements/poi-marker.html new file mode 100644 index 00000000..f2829b42 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/poi-marker.html @@ -0,0 +1,9 @@ + + + {{ feature.properties.name | addWordBreakOpportunities }} + diff --git a/frontend/app/src/app/modules/map/elements/poi-marker.scss b/frontend/app/src/app/modules/map/elements/poi-marker.scss new file mode 100644 index 00000000..4c1655f5 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/poi-marker.scss @@ -0,0 +1,38 @@ +ion-button { + --padding-top: 0; + --padding-bottom: 0; + --padding-start: var(--spacing-md); + --padding-end: var(--spacing-sm); + + max-width: 120px; + min-height: 0; + margin: 0; + margin-block-end: 4px; + + font: inherit; + font-size: 0.9em; + font-weight: bold; + + &::part(native) { + height: 32px; + line-height: 1.2; + } +} + +ion-icon { + flex-shrink: 0; +} + +ion-label { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + + padding: 4px 0; + + text-align: left; + overflow-wrap: normal; + white-space: wrap; + + -webkit-line-clamp: 2; +} diff --git a/frontend/app/src/app/modules/map/elements/poi-markers.component.ts b/frontend/app/src/app/modules/map/elements/poi-markers.component.ts new file mode 100644 index 00000000..d44b709b --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/poi-markers.component.ts @@ -0,0 +1,43 @@ +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; +import {MapIconDirective} from '../map-icon.directive'; +import {FeatureCollection, Point} from 'geojson'; +import {SCFeatureProperties} from '../feature-collection.pipe'; +import {animate, style, transition, trigger} from '@angular/animations'; +import {MglClusterLeavesPipe} from '../cluster-leaves.pipe'; +import { + ClusterPointDirective, + GeoJSONSourceComponent, + MarkersForClustersComponent, + PointDirective, +} from '@maplibre/ngx-maplibre-gl'; +import {AsyncPipe} from '@angular/common'; +import {PoiMarkerComponent} from './poi-marker.component'; + +@Component({ + selector: 'stapps-poi-markers', + templateUrl: './poi-markers.html', + styleUrl: './poi-markers.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + MapIconDirective, + MglClusterLeavesPipe, + GeoJSONSourceComponent, + MarkersForClustersComponent, + AsyncPipe, + ClusterPointDirective, + PointDirective, + PoiMarkerComponent, + ], + animations: [ + trigger('fade', [ + transition(':enter', [style({opacity: 0}), animate('200ms', style({opacity: 1}))]), + transition(':leave', [style({opacity: 1}), animate('200ms', style({opacity: 0}))]), + ]), + ], +}) +export class PoiMarkersComponent { + @Input({required: true}) data: FeatureCollection; + + @Input() clusterPreviewCount = 3; +} diff --git a/frontend/app/src/app/modules/map/elements/poi-markers.html b/frontend/app/src/app/modules/map/elements/poi-markers.html new file mode 100644 index 00000000..2b4c6749 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/poi-markers.html @@ -0,0 +1,33 @@ + + + +
+ +
+
+ +
+ @if ( + 'pois' + | mglClusterLeaves + : feature + : clusterPreviewCount - (feature.properties.point_count > clusterPreviewCount ? 1 : 0) + | async; + as leaves + ) { + @for (feature of leaves; track feature.id) { + + } + @if (feature.properties.point_count > leaves.length) { +
+{{ feature.properties.point_count - leaves.length }}
+ } + } +
+
+
diff --git a/frontend/app/src/app/modules/map/elements/poi-markers.scss b/frontend/app/src/app/modules/map/elements/poi-markers.scss new file mode 100644 index 00000000..63382381 --- /dev/null +++ b/frontend/app/src/app/modules/map/elements/poi-markers.scss @@ -0,0 +1,24 @@ +.ellipsis { + display: flex; + align-items: center; + justify-content: flex-start; + + width: fit-content; + padding-inline: var(--spacing-md); + + font-size: 0.8em; + color: var(--ion-color-primary-contrast); + + opacity: 0.8; + background: var(--ion-color-primary); + border-radius: 15px; +} + +button:not(:only-child) { + margin-bottom: 2px; +} + +.marker { + display: flex; + flex-direction: column; +} diff --git a/frontend/app/src/app/modules/map/feature-collection.pipe.ts b/frontend/app/src/app/modules/map/feature-collection.pipe.ts new file mode 100644 index 00000000..1ecb8c55 --- /dev/null +++ b/frontend/app/src/app/modules/map/feature-collection.pipe.ts @@ -0,0 +1,81 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {SCThing, SCThings} from '@openstapps/core'; +import {Feature, FeatureCollection, Point, Polygon} from 'geojson'; + +/** + * Very simple hash function + * + * MapLibre cannot use strings as feature ids because of + * vector tile spec limitations + */ +function simpleHash(value: string): number { + let hash = 0; + for (let i = 0; i < value.length; i++) { + hash = Math.trunc((hash << 5) - hash + value.codePointAt(i)!); + } + return hash >>> 0; +} + +/** + * Finds the best name for a thing to display on the map + */ +function findBestName(thing: SCThing, targetLength = 14): string { + if (!thing.alternateNames || thing.name.length <= targetLength) return thing.name; + return thing.alternateNames.reduce( + (accumulator, current) => + accumulator.length <= targetLength || accumulator.length <= current.length ? accumulator : current, + thing.name, + ); +} + +export interface SCFeatureProperties { + name: string; + category?: string; + uid: string; +} + +@Pipe({ + name: 'thingPoiFeatureCollection', + standalone: true, + pure: true, +}) +export class ThingPoiFeatureCollectionPipe implements PipeTransform { + transform(things: SCThings[]): FeatureCollection { + return { + type: 'FeatureCollection', + features: things + .filter(thing => 'geo' in thing && thing.geo.polygon === undefined) + .map>(thing => ({ + type: 'Feature', + properties: { + name: findBestName(thing), + category: 'categories' in thing ? thing.categories[0] : undefined, + uid: thing.uid, + }, + geometry: (thing as Extract).geo.point, + id: simpleHash(thing.uid), + })), + }; + } +} + +@Pipe({ + name: 'thingPolygonFeatureCollection', + standalone: true, + pure: true, +}) +export class ThingPolygonFeatureCollectionPipe implements PipeTransform { + transform(things: SCThings[]): FeatureCollection { + return { + type: 'FeatureCollection', + features: things + .filter(thing => 'geo' in thing && thing.geo.polygon !== undefined) + .map>(thing => ({ + type: 'Feature', + geometry: (thing as Extract).geo.polygon!, + properties: {uid: thing.uid, name: findBestName(thing)}, + id: simpleHash(thing.uid), + })), + }; + } +} diff --git a/frontend/app/src/app/modules/map/map-auto-3d.directive.ts b/frontend/app/src/app/modules/map/map-auto-3d.directive.ts new file mode 100644 index 00000000..b1ae9f50 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-auto-3d.directive.ts @@ -0,0 +1,36 @@ +import {Directive, HostListener} from '@angular/core'; +import {Map, MapMouseEvent, MapStyleDataEvent} from 'maplibre-gl'; + +@Directive({ + selector: 'mgl-map[auto-3d]', + standalone: true, +}) +export class MapAuto3dDirective { + @HostListener('styleData', ['$event']) + styleData(event: MapStyleDataEvent) { + this.updatePitch(event.target); + } + + @HostListener('pitchEvt', ['$event']) + pitch(event: MapMouseEvent) { + this.updatePitch(event.target); + } + + updatePitch(map: Map) { + if (map.getPitch() === 0) { + const layer = map.getLayer('building-3d'); + if (layer && layer?.visibility !== 'none') { + layer.visibility = 'none'; + map.setPaintProperty('building', 'fill-opacity', 1); + map.setLayerZoomRange('building', 13, 24); + } + } else { + const layer = map.getLayer('building-3d'); + if (layer && layer?.visibility !== 'visible') { + layer.visibility = 'visible'; + map.setPaintProperty('building', 'fill-opacity', ['interpolate', ['linear'], ['zoom'], 15, 1, 16, 0]); + map.setLayerZoomRange('building', 13, 16); + } + } + } +} diff --git a/frontend/app/src/app/modules/map/map-data.provider.ts b/frontend/app/src/app/modules/map/map-data.provider.ts new file mode 100644 index 00000000..b797f276 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-data.provider.ts @@ -0,0 +1,59 @@ +import {Injectable} from '@angular/core'; +import {DataProvider} from '../data/data.provider'; +import {SCGeoFilter, SCSearchRequest, SCSearchResponse} from '@openstapps/core'; +import {BehaviorSubject} from 'rxjs'; + +@Injectable() +export class MapDataProvider extends DataProvider { + readonly current = new BehaviorSubject(undefined); + + readonly currentBounds = new BehaviorSubject< + [[minLon: number, maxLat: number], [maxLon: number, minLat: number]] | undefined + >(undefined); + + override async search(query: SCSearchRequest): Promise { + if (query.query && this.currentBounds.value !== undefined) { + const boundsFilter: SCGeoFilter = { + type: 'geo', + arguments: { + field: 'geo', + shape: { + type: 'envelope', + coordinates: this.currentBounds.value, + }, + }, + }; + query.filter = query.filter + ? { + type: 'boolean', + arguments: { + operation: 'and', + filters: [query.filter, boundsFilter], + }, + } + : boundsFilter; + } + + if (query.from === 0 || this.current.value === undefined) { + this.current.next( + await super.search({ + ...query, + size: undefined, + }), + ); + } + if (query.from === undefined || query.size === undefined) { + return this.current.value!; + } + + return { + ...this.current.value!, + data: this.current.value!.data.slice(query.from, query.from + query.size), + pagination: { + ...this.current.value!.pagination, + offset: query.from, + count: Math.min(query.size, this.current.value!.data.length - query.from), + }, + }; + } +} diff --git a/frontend/app/src/app/modules/map/map-icon.directive.ts b/frontend/app/src/app/modules/map/map-icon.directive.ts new file mode 100644 index 00000000..795d8a55 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-icon.directive.ts @@ -0,0 +1,37 @@ +import {SCThings, SCPlace} from '@openstapps/core'; +import {SCIcon} from '../../util/ion-icon/icon'; +import {Pipe, PipeTransform} from '@angular/core'; +import {MaterialSymbol} from 'material-symbols'; + +const mapIcons: Record['categories'][number], MaterialSymbol> = { + 'cafe': SCIcon.local_cafe, + 'learn': SCIcon.school, + 'canteen': SCIcon.restaurant, + 'computer': SCIcon.computer, + 'education': SCIcon.school, + 'laboratory': SCIcon.science, + 'library': SCIcon.local_library, + 'lounge': SCIcon.weekend, + 'office': SCIcon.meeting_room, + 'restaurant': SCIcon.restaurant, + 'restroom': SCIcon.wc, + 'student canteen': SCIcon.restaurant, + 'student union': SCIcon.groups, + 'validator': SCIcon.badge, + 'card charger': SCIcon.credit_card, + 'printer': SCIcon.print, + 'disabled access': SCIcon.accessible, +}; + +const defaultIcon = SCIcon.not_listed_location; + +@Pipe({ + name: 'stappsMapIcon', + standalone: true, + pure: true, +}) +export class MapIconDirective implements PipeTransform { + transform(value: keyof typeof mapIcons | string | undefined): MaterialSymbol { + return mapIcons[value as keyof typeof mapIcons] ?? defaultIcon; + } +} diff --git a/frontend/app/src/app/modules/map/map-maximize-animation.ts b/frontend/app/src/app/modules/map/map-maximize-animation.ts new file mode 100644 index 00000000..46ee5f53 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-maximize-animation.ts @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2024 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +import type {AnimationBuilder} from '@ionic/angular'; +import {AnimationController} from '@ionic/angular'; +import type {AnimationOptions} from '@ionic/angular/common/providers/nav-controller'; +import {iosDuration, iosEasing, mdDuration, mdEasing} from 'src/app/animation/easings'; + +/** + * Get the center of an element + */ +function center(element: HTMLElement): {x: number; y: number} { + const bounds = element.getBoundingClientRect(); + return { + x: bounds.left + bounds.width / 2, + y: bounds.top + bounds.height / 2, + }; +} + +/** + * Get the flip transform for an element + */ +function flipTransform(from: HTMLElement, to: HTMLElement): string { + const fromCenter = center(from); + const toCenter = center(to); + const dx = fromCenter.x - toCenter.x; + const dy = fromCenter.y - toCenter.y; + return `translate(${dx}px, ${dy}px)`; +} + +/** + * Get the flip clip path for an element + */ +function flipClipPath(from: HTMLElement, to: HTMLElement): string { + const fromBounds = from.getBoundingClientRect(); + const toBounds = to.getBoundingClientRect(); + const y = Math.max(0, (toBounds.height - fromBounds.height) / 2); + const x = Math.max(0, (toBounds.width - fromBounds.width) / 2); + return `inset(${y}px ${x}px)`; +} + +/** + * Animation of the map maximize + */ +export function mapMaximizeAnimation(animationController: AnimationController): AnimationBuilder { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (_baseElement: HTMLElement, options: AnimationOptions | any) => { + const rootTransition = animationController + .create() + .duration(options.duration ?? (options.mode === 'ios' ? iosDuration * 1.5 : mdDuration * 2.5)) + .easing(options.mode === 'ios' ? iosEasing : mdEasing); + + const enteringMap = options.enteringEl.querySelector('mgl-map') as HTMLElement; + const leavingMap = options.leavingEl.querySelector('mgl-map') as HTMLElement; + + if (!enteringMap.classList.contains('ready')) { + rootTransition.delay(2000); + enteringMap.addEventListener( + 'ready', + event => { + event.preventDefault(); + setTimeout(() => { + if (rootTransition.isRunning()) { + rootTransition.stop(); + rootTransition.delay(0); + rootTransition.play(); + } + }); + }, + {once: true}, + ); + } + + const mapEnterTransition = animationController + .create() + .fromTo('transform', flipTransform(leavingMap, enteringMap), 'translate(0, 0)') + .fromTo('clipPath', flipClipPath(leavingMap, enteringMap), 'inset(0px 0px)') + .addElement(enteringMap); + const mapExitTransition = animationController + .create() + .fromTo('transform', 'translate(0, 0)', flipTransform(enteringMap, leavingMap)) + .fromTo('clipPath', 'inset(0px 0px)', flipClipPath(enteringMap, leavingMap)) + .addElement(leavingMap); + + const enterTransition = animationController + .create() + .fromTo('opacity', options.direction === 'back' ? '1' : '0', '1') + + .addElement(options.enteringEl); + const exitTransition = animationController + .create() + .fromTo('opacity', '1', options.direction === 'back' ? '0' : '1') + .addElement(options.leavingEl); + + rootTransition.addAnimation([enterTransition, exitTransition, mapEnterTransition, mapExitTransition]); + return rootTransition; + }; +} diff --git a/frontend/app/src/app/modules/map/map-page.component.ts b/frontend/app/src/app/modules/map/map-page.component.ts new file mode 100644 index 00000000..81d6c939 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-page.component.ts @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2022 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {IonicModule} from '@ionic/angular'; +import {LngLatBoundsLike, MapLibreEvent} from 'maplibre-gl'; +import { + ControlComponent, + GeolocateControlDirective, + MapComponent, + ScaleControlDirective, +} from '@maplibre/ngx-maplibre-gl'; +import {TranslateModule} from '@ngx-translate/core'; +import {ActivatedRoute, RouterLink} from '@angular/router'; +import {MapAuto3dDirective} from './map-auto-3d.directive'; +import {MediaQueryPipe} from '../../util/media-query.pipe'; +import {MapStyleDirective} from './map-style.directive'; +import {DataProvider} from '../data/data.provider'; +import {SCSearchFilter, SCThingType} from '@openstapps/core'; +import {IonIconModule} from '../../util/ion-icon/ion-icon.module'; +import {DataModule} from '../data/data.module'; +import {AsyncPipe} from '@angular/common'; +import {GeolocateControlComponent} from './controls/geolocate-control.component'; +import {CompassControlComponent} from './controls/compass-control.component'; +import {MapSizeFixDirective} from './map-size-fix.directive'; +import {MapDataProvider} from './map-data.provider'; +import {ThingPoiFeatureCollectionPipe, ThingPolygonFeatureCollectionPipe} from './feature-collection.pipe'; +import {BuildingMarkersComponent} from './elements/building-markers.component'; +import {PoiMarkersComponent} from './elements/poi-markers.component'; +import {AttributionComponent} from './controls/attribution.component'; +import {filter, map} from 'rxjs'; + +/** + * The main page of the map + */ +@Component({ + styleUrls: ['./map-page.scss'], + templateUrl: './map-page.html', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + MapDataProvider, + { + provide: DataProvider, + useExisting: MapDataProvider, + }, + ], + imports: [ + AsyncPipe, + AttributionComponent, + BuildingMarkersComponent, + CompassControlComponent, + ControlComponent, + DataModule, + GeolocateControlComponent, + GeolocateControlDirective, + IonIconModule, + IonicModule, + MapAuto3dDirective, + MapComponent, + MapSizeFixDirective, + MapStyleDirective, + MediaQueryPipe, + PoiMarkersComponent, + RouterLink, + ScaleControlDirective, + ThingPoiFeatureCollectionPipe, + ThingPolygonFeatureCollectionPipe, + TranslateModule, + ], +}) +export class MapPageComponent { + forcedFilter: SCSearchFilter = { + type: 'boolean', + arguments: { + operation: 'or', + filters: [ + { + type: 'value', + arguments: { + field: 'type', + value: [SCThingType.Building], + }, + }, + { + type: 'boolean', + arguments: { + operation: 'and', + filters: [ + { + type: 'value', + arguments: { + field: 'categories', + value: ['restaurant', 'library', 'canteen', 'cafe'], + }, + }, + { + type: 'value', + arguments: { + field: 'type', + value: [SCThingType.Building, SCThingType.Room, SCThingType.PointOfInterest], + }, + }, + ], + }, + }, + ], + }, + }; + + bounds = this.activatedRoute.queryParams.pipe( + map( + parameters => + (parameters?.bounds as [string, string])?.map(it => + it.split(',').map(Number.parseFloat), + ) as LngLatBoundsLike, + ), + filter(uid => uid !== undefined), + ); + + constructor( + readonly dataProvider: MapDataProvider, + readonly activatedRoute: ActivatedRoute, + ) {} + + mapMove(event: MapLibreEvent) { + const bounds = event.target.getBounds(); + this.dataProvider.currentBounds.next([ + [bounds.getWest(), bounds.getNorth()], + [bounds.getEast(), bounds.getSouth()], + ]); + } +} diff --git a/frontend/app/src/app/modules/map/map-page.html b/frontend/app/src/app/modules/map/map-page.html new file mode 100644 index 00000000..d8865525 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-page.html @@ -0,0 +1,50 @@ + + + + + + @if (dataProvider.current | async; as result) { + + + } + + + + + + + + + + diff --git a/frontend/app/src/app/modules/map/map-page.scss b/frontend/app/src/app/modules/map/map-page.scss new file mode 100644 index 00000000..b9ca5fdb --- /dev/null +++ b/frontend/app/src/app/modules/map/map-page.scss @@ -0,0 +1,101 @@ +/*! + * Copyright (C) 2023 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +ion-content { + position: fixed; + transition: opacity 0.2s ease; +} + +stapps-search-page { + ::ng-deep ion-content { + transform: translateY(48px); + transition: transform 0.2s ease; + } + + ::ng-deep ion-back-button { + transform: translateX(24px); + display: block; + opacity: 0; + transition: + opacity 0.2s ease, + transform 0.2s ease; + } +} + +stapps-search-page:has(::ng-deep .searchbar-has-focus), +stapps-search-page:has(::ng-deep ion-content:focus-within) { + + ion-content { + pointer-events: none; + opacity: 0; + } + + ::ng-deep ion-content { + transform: translateY(0); + } + + ::ng-deep ion-back-button { + pointer-events: none; + transform: translateX(0); + opacity: 1; + } +} + +:host.can-go-back stapps-search-page ::ng-deep ion-back-button { + transform: translateX(0); + opacity: 1; +} + +mgl-map { + width: 100%; + height: 100%; +} + +ion-toolbar:first-of-type { + padding: 0 var(--spacing-md) var(--spacing-xs); +} + +.filter-options { + overflow: hidden; + display: flex; + flex-direction: row; + border-radius: var(--border-radius-default); + + label { + cursor: pointer; + user-select: none; + + padding: var(--spacing-xs) var(--spacing-md); + + font-family: inherit; + color: var(--ion-item-color); + + background-color: var(--ion-item-background); + + transition: all 0.2s ease; + + input[type='radio'] { + display: none; + } + + &:has(:checked) { + color: var(--ion-color-primary-contrast); + background-color: var(--ion-color-primary); + } + } +} + +:host ::ng-deep .maplibregl-ctrl-top-left, +:host ::ng-deep .maplibregl-ctrl-top-right { + top: 92px; +} diff --git a/frontend/app/src/app/modules/map/map-size-fix.directive.ts b/frontend/app/src/app/modules/map/map-size-fix.directive.ts new file mode 100644 index 00000000..20d15b08 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-size-fix.directive.ts @@ -0,0 +1,39 @@ +import {AfterViewInit, Directive, Host, HostBinding, HostListener, ViewContainerRef} from '@angular/core'; +import {MapComponent} from '@maplibre/ngx-maplibre-gl'; + +/** + * Fixes an issue related to page transitions where + * the map would only appear with a size of 300x400px + */ +@Directive({ + selector: 'mgl-map', + standalone: true, +}) +export class MapSizeFixDirective implements AfterViewInit { + private animation: Animation; + + @HostBinding('class.ready') ready = false; + + constructor( + @Host() private map: MapComponent, + private viewContainerRef: ViewContainerRef, + ) {} + + @HostListener('mapLoad') + mapLoad() { + this.map.mapInstance.resize(); + this.ready = true; + const element = this.viewContainerRef.element.nativeElement as HTMLElement; + if (element.dispatchEvent(new CustomEvent('ready', {cancelable: true}))) { + this.animation.play(); + } else { + this.animation.cancel(); + } + } + + ngAfterViewInit() { + const element: HTMLDivElement = this.viewContainerRef.element.nativeElement; + this.animation = element.animate([{opacity: 0}, {opacity: 1}], {duration: 200, fill: 'backwards'}); + this.animation.pause(); + } +} diff --git a/frontend/app/src/app/modules/map/map-style.directive.ts b/frontend/app/src/app/modules/map/map-style.directive.ts new file mode 100644 index 00000000..ffddd478 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-style.directive.ts @@ -0,0 +1,20 @@ +import {Directive, Input, Host} from '@angular/core'; +import {MapComponent} from '@maplibre/ngx-maplibre-gl'; + +@Directive({ + selector: 'mgl-map[styleName]', + standalone: true, +}) +export class MapStyleDirective { + constructor(@Host() readonly map: MapComponent) {} + + @Input() + set styleName(name: string) { + const style = `https://maps.server.uni-frankfurt.de/static/styles/${name}/style.json`; + if (this.map.style) { + this.map.mapInstance.setStyle(style); + } else { + this.map.style = style; + } + } +} diff --git a/frontend/app/src/app/modules/map/map-widget.component.ts b/frontend/app/src/app/modules/map/map-widget.component.ts new file mode 100644 index 00000000..675d1788 --- /dev/null +++ b/frontend/app/src/app/modules/map/map-widget.component.ts @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2022 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +import {ChangeDetectionStrategy, Component, HostBinding, Input, inject} from '@angular/core'; +import {RouterLink} from '@angular/router'; +import {ControlComponent, MapComponent, MarkerComponent} from '@maplibre/ngx-maplibre-gl'; +import {AnimationController, IonicModule} from '@ionic/angular'; +import {GeoNavigationDirective} from './geo-navigation.directive'; +import {TranslateModule} from '@ngx-translate/core'; +import {CommonModule} from '@angular/common'; +import {IonIconModule} from '../../util/ion-icon/ion-icon.module'; +import {MapAuto3dDirective} from './map-auto-3d.directive'; +import {MediaQueryPipe} from 'src/app/util/media-query.pipe'; +import {MapStyleDirective} from './map-style.directive'; +import {MapSizeFixDirective} from './map-size-fix.directive'; +import {SCThings} from '@openstapps/core'; +import {ThingPolygonFeatureCollectionPipe, ThingPoiFeatureCollectionPipe} from './feature-collection.pipe'; +import {PoiMarkersComponent} from './elements/poi-markers.component'; +import {BuildingMarkersComponent} from './elements/building-markers.component'; +import {ThingBoundsPipe} from './thing-bounds.pipe'; +import {AttributionComponent} from './controls/attribution.component'; +import {mapMaximizeAnimation} from './map-maximize-animation'; + +/** + * The map widget (needs a container with explicit size) + */ +@Component({ + selector: 'stapps-map-widget', + styleUrls: ['./map-widget.scss'], + templateUrl: './map-widget.html', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + AttributionComponent, + BuildingMarkersComponent, + CommonModule, + ControlComponent, + GeoNavigationDirective, + IonIconModule, + IonicModule, + MapAuto3dDirective, + MapComponent, + MapSizeFixDirective, + MapStyleDirective, + MarkerComponent, + MediaQueryPipe, + PoiMarkersComponent, + RouterLink, + ThingBoundsPipe, + ThingPoiFeatureCollectionPipe, + ThingPolygonFeatureCollectionPipe, + TranslateModule, + ], +}) +export class MapWidgetComponent { + @HostBinding('class.expand-when-space') expandWhenSpace = true; + + /** + * A place to show on the map + */ + @Input({required: true}) place: Extract; + + maximizeAnimation = mapMaximizeAnimation(inject(AnimationController)); +} diff --git a/frontend/app/src/app/modules/map/map-widget.html b/frontend/app/src/app/modules/map/map-widget.html new file mode 100644 index 00000000..003efeef --- /dev/null +++ b/frontend/app/src/app/modules/map/map-widget.html @@ -0,0 +1,51 @@ + + + @if (place.geo.polygon) { + + } @else if (place.geo.point) { + + } + + + + {{ 'map.directions.TITLE' | translate }} + + + + + + + + + + + diff --git a/frontend/app/src/app/modules/map/widget/map-widget.scss b/frontend/app/src/app/modules/map/map-widget.scss similarity index 83% rename from frontend/app/src/app/modules/map/widget/map-widget.scss rename to frontend/app/src/app/modules/map/map-widget.scss index 7cbe7ef2..f41efc51 100644 --- a/frontend/app/src/app/modules/map/widget/map-widget.scss +++ b/frontend/app/src/app/modules/map/map-widget.scss @@ -19,16 +19,11 @@ min-height: 300px; } -div.map-container { - pointer-events: none; - display: block; +mgl-map { width: 100%; height: 100%; } -div.map-buttons { - position: absolute; - z-index: 10000; - top: 10px; - right: 10px; +.marker { + filter: drop-shadow(0 0 2px rgba(0 0 0 / 50%)); } diff --git a/frontend/app/src/app/modules/map/map.module.ts b/frontend/app/src/app/modules/map/map.module.ts index 6d631630..6cd76209 100644 --- a/frontend/app/src/app/modules/map/map.module.ts +++ b/frontend/app/src/app/modules/map/map.module.ts @@ -12,67 +12,14 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import {CommonModule} from '@angular/common'; -import {FormsModule} from '@angular/forms'; -import {RouterModule, Routes} from '@angular/router'; -import {LeafletModule} from '@asymmetrik/ngx-leaflet'; -import {LeafletMarkerClusterModule} from '@asymmetrik/ngx-leaflet-markercluster'; -import {IonicModule} from '@ionic/angular'; -import {TranslateModule} from '@ngx-translate/core'; -import {Polygon} from 'geojson'; -import {ThingTranslateModule} from '../../translation/thing-translate.module'; -import {ConfigProvider} from '../config/config.provider'; -import {DataFacetsProvider} from '../data/data-facets.provider'; -import {DataModule} from '../data/data.module'; -import {DataProvider} from '../data/data.provider'; -import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider'; -import {MenuModule} from '../menu/menu.module'; -import {MapProvider} from './map.provider'; -import {MapPageComponent} from './page/map-page.component'; -import {MapListModalComponent} from './page/map-list-modal.component'; +import {RouterModule} from '@angular/router'; +import {MapPageComponent} from './map-page.component'; import {NgModule} from '@angular/core'; -import {UtilModule} from '../../util/util.module'; -import {IonIconModule} from '../../util/ion-icon/ion-icon.module'; -import {GeoNavigationDirective} from './geo-navigation.directive'; - -/** - * Initializes the default area to show in advance (before components are initialized) - * @param configProvider An instance of the ConfigProvider to read the campus polygon from - * @param mapProvider An instance of the MapProvider to set the default polygon (area to show on the map) - */ -export function initMapConfigFactory(configProvider: ConfigProvider, mapProvider: MapProvider) { - return async () => { - mapProvider.defaultPolygon = (await configProvider.getValue('campusPolygon')) as Polygon; - }; -} - -const mapRoutes: Routes = [ - {path: 'map', component: MapPageComponent}, - {path: 'map/:uid', component: MapPageComponent}, -]; /** * Module containing map related stuff */ @NgModule({ - declarations: [MapPageComponent, MapListModalComponent], - exports: [], - imports: [ - CommonModule, - IonicModule.forRoot(), - LeafletModule, - IonIconModule, - LeafletMarkerClusterModule, - RouterModule.forChild(mapRoutes), - TranslateModule.forChild(), - MenuModule, - DataModule, - FormsModule, - ThingTranslateModule, - UtilModule, - GeoNavigationDirective, - GeoNavigationDirective, - ], - providers: [Geolocation, MapProvider, DataProvider, DataFacetsProvider, StAppsWebHttpClient], + imports: [RouterModule.forChild([{path: 'map', component: MapPageComponent}])], }) export class MapModule {} diff --git a/frontend/app/src/app/modules/map/map.provider.spec.ts b/frontend/app/src/app/modules/map/map.provider.spec.ts deleted file mode 100644 index 566eeaa5..00000000 --- a/frontend/app/src/app/modules/map/map.provider.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2023 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {TestBed} from '@angular/core/testing'; - -import {MapProvider} from './map.provider'; -import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider'; -import {HttpClientModule} from '@angular/common/http'; -import {StorageProvider} from '../storage/storage.provider'; -import {MapModule} from './map.module'; -import {StorageModule} from '../storage/storage.module'; -import {LoggerModule, NGXLogger, NgxLoggerLevel} from 'ngx-logger'; -import {ConfigProvider} from '../config/config.provider'; -import {sampleDefaultPolygon} from '../../_helpers/data/sample-configuration'; -import {RouterModule} from '@angular/router'; - -describe('MapProvider', () => { - let provider: MapProvider; - let configProvider: jasmine.SpyObj; - - beforeEach(() => { - configProvider = jasmine.createSpyObj('ConfigProvider', ['getValue']); - TestBed.configureTestingModule({ - imports: [ - MapModule, - HttpClientModule, - StorageModule, - LoggerModule.forRoot({level: NgxLoggerLevel.TRACE}), - RouterModule.forRoot([]), - ], - providers: [ - { - provide: ConfigProvider, - useValue: configProvider, - }, - StAppsWebHttpClient, - StorageProvider, - NGXLogger, - ], - }); - - configProvider.getValue.and.returnValue(sampleDefaultPolygon); - provider = TestBed.inject(MapProvider); - }); - - it('should be created', () => { - expect(provider).toBeTruthy(); - }); -}); diff --git a/frontend/app/src/app/modules/map/map.provider.ts b/frontend/app/src/app/modules/map/map.provider.ts deleted file mode 100644 index ee488dce..00000000 --- a/frontend/app/src/app/modules/map/map.provider.ts +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2022 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {ElementRef, Injectable} from '@angular/core'; -import { - SCBuilding, - SCSearchFilter, - SCSearchQuery, - SCSearchResponse, - SCThingType, - SCUuid, -} from '@openstapps/core'; -import {Point, Polygon} from 'geojson'; -import {divIcon, geoJSON, LatLng, Map, marker, Marker} from 'leaflet'; -import {DataProvider} from '../data/data.provider'; -import {MapPosition, PositionService} from './position.service'; -import {hasValidLocation} from '../data/types/place/place-types'; -import {ConfigProvider} from '../config/config.provider'; -import {SCIcon} from '../../util/ion-icon/icon'; - -/** - * Provides methods for presenting the map - */ -@Injectable({ - providedIn: 'root', -}) -export class MapProvider { - /** - * Area to show when the map is initialized (shown for the first time) - */ - defaultPolygon: Polygon; - - /** - * Provide a point marker for a leaflet map - * @param point Point to get marker for - * @param className CSS class name - * @param iconSize Size of the position icon - */ - static getPointMarker(point: Point, className: string, iconSize: number) { - return marker(geoJSON(point).getBounds().getCenter(), { - icon: divIcon({ - className: className, - html: `${SCIcon`location_on`}`, - iconSize: [iconSize, iconSize], - iconAnchor: [iconSize / 2, iconSize], - }), - }); - } - - /** - * Provide a position marker for a leaflet map - * @param position Current position - * @param className CSS class name - * @param iconSize Size of the position icon - */ - static getPositionMarker(position: MapPosition, className: string, iconSize: number) { - return new Marker(new LatLng(position.latitude, position.longitude), { - icon: divIcon({ - className: className, - html: - position.heading === undefined - ? `${SCIcon`person_pin_circle`}` - : `${SCIcon`navigation`}`, - iconSize: [iconSize, iconSize], - }), - zIndexOffset: 1000, - }); - } - - /** - * Fixes the issue of missing tiles when map renders before its container element - * @param map The initialized map - * @param element The element containing the map - * @param interval Interval to clear when map's appearance is corrected - */ - static invalidateWhenRendered = (map: Map, element: ElementRef, interval: number) => { - if (element.nativeElement.offsetWidth === 0) { - return; - } - - // map's container is ready - map.invalidateSize(); - // stop repeating when it's rendered and invalidateSize done - clearInterval(interval); - }; - - constructor( - private dataProvider: DataProvider, - private positionService: PositionService, - private configProvider: ConfigProvider, - ) { - this.defaultPolygon = this.configProvider.getValue('campusPolygon') as Polygon; - } - - /** - * Provide the specific place by its UID - * @param uid UUID of the place to look for - */ - async searchPlace(uid: SCUuid): Promise { - const uidFilter: SCSearchFilter = { - arguments: { - field: 'uid', - value: uid, - }, - type: 'value', - }; - - return this.dataProvider.search({filter: uidFilter}); - } - - /** - * Provide places (buildings and canteens) const result = await this.dataProvider.search(query); - * @param contextFilter Additional contextual filter (e.g. from the context menu) - * @param queryText Query (text) of the search query - */ - async searchPlaces(contextFilter?: SCSearchFilter, queryText?: string): Promise { - const buildingFilter: SCSearchFilter = { - arguments: { - field: 'type', - value: SCThingType.Building, - }, - type: 'value', - }; - - const mensaFilter: SCSearchFilter = { - arguments: { - filters: [ - { - arguments: { - field: 'categories', - value: 'canteen', - }, - type: 'value', - }, - { - arguments: { - field: 'categories', - value: 'student canteen', - }, - type: 'value', - }, - { - arguments: { - field: 'categories', - value: 'cafe', - }, - type: 'value', - }, - { - arguments: { - field: 'categories', - value: 'restaurant', - }, - type: 'value', - }, - ], - operation: 'or', - }, - type: 'boolean', - }; - - // initial filter for the places - const baseFilter: SCSearchFilter = { - arguments: { - operation: 'or', - filters: [buildingFilter, mensaFilter], - }, - type: 'boolean', - }; - - let filter = baseFilter; - - if (contextFilter !== undefined) { - filter = { - arguments: { - operation: 'and', - filters: [baseFilter, contextFilter], - }, - type: 'boolean', - }; - } - - const query: SCSearchQuery = { - filter, - }; - - if (queryText && queryText.length > 0) { - query.query = queryText; - } - - if (this.positionService.position) { - query.sort = [ - { - type: 'distance', - order: 'asc', - arguments: { - field: 'geo', - position: [this.positionService.position.longitude, this.positionService.position.latitude], - }, - }, - ]; - } - - const result = await this.dataProvider.search(query); - - result.data = result.data.filter(place => hasValidLocation(place as SCBuilding)); - - return result; - } -} diff --git a/frontend/app/src/app/modules/map/page/map-list-modal.component.ts b/frontend/app/src/app/modules/map/page/map-list-modal.component.ts deleted file mode 100644 index 66b98f0c..00000000 --- a/frontend/app/src/app/modules/map/page/map-list-modal.component.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2022 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {Component, Input, OnInit} from '@angular/core'; -import {SCSearchBooleanFilter, SCPlace, SCSearchFilter} from '@openstapps/core'; -import {MapProvider} from '../map.provider'; -import {ModalController} from '@ionic/angular'; -import {LatLngBounds} from 'leaflet'; - -/** - * Modal showing a provided list of places - */ -@Component({ - selector: 'map-list-modal', - templateUrl: 'map-list-modal.html', - styleUrls: ['map-list-modal.scss'], -}) -export class MapListModalComponent implements OnInit { - /** - * Used for creating the search for the shown list - */ - @Input() filterQuery?: SCSearchFilter; - - /** - * Map visible boundaries limiting items in lust - */ - @Input() mapBounds?: LatLngBounds; - - /** - * Places to show in the list - */ - items: SCPlace[]; - - /** - * Used for creating the search for the shown list - */ - @Input() queryText?: string; - - constructor( - private mapProvider: MapProvider, - readonly modalController: ModalController, - ) {} - - /** - * Populate the list with the results from the search - */ - ngOnInit() { - let geofencedFilter: SCSearchBooleanFilter | undefined; - if (this.mapBounds !== undefined) { - geofencedFilter = { - arguments: { - operation: 'and', - filters: [ - { - type: 'geo', - arguments: { - field: 'geo', - shape: { - coordinates: [ - [this.mapBounds.getNorthWest().lng, this.mapBounds.getNorthWest().lat], - [this.mapBounds.getSouthEast().lng, this.mapBounds.getSouthEast().lat], - ], - type: 'envelope', - }, - spatialRelation: 'intersects', - }, - }, - ], - }, - type: 'boolean', - }; - if (this.filterQuery !== undefined) { - geofencedFilter.arguments.filters.push(this.filterQuery); - } - } - - const geofencedFilterQuery = geofencedFilter ?? this.filterQuery; - this.mapProvider.searchPlaces(geofencedFilterQuery, this.queryText).then(result => { - this.items = result.data as SCPlace[]; - }); - } -} diff --git a/frontend/app/src/app/modules/map/page/map-list-modal.html b/frontend/app/src/app/modules/map/page/map-list-modal.html deleted file mode 100644 index d137f0aa..00000000 --- a/frontend/app/src/app/modules/map/page/map-list-modal.html +++ /dev/null @@ -1,28 +0,0 @@ - - -
- - - {{ 'map.modals.list.TITLE' | translate }} - - {{ 'app.ui.CLOSE' | translate }} - - - - - - -
diff --git a/frontend/app/src/app/modules/map/page/map-list-modal.scss b/frontend/app/src/app/modules/map/page/map-list-modal.scss deleted file mode 100644 index 04a923c5..00000000 --- a/frontend/app/src/app/modules/map/page/map-list-modal.scss +++ /dev/null @@ -1,20 +0,0 @@ -/*! - * Copyright (C) 2022 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -.container { - display: flex; - flex-direction: column; - height: 100%; -} diff --git a/frontend/app/src/app/modules/map/page/map-page.component.ts b/frontend/app/src/app/modules/map/page/map-page.component.ts deleted file mode 100644 index 4a2453d0..00000000 --- a/frontend/app/src/app/modules/map/page/map-page.component.ts +++ /dev/null @@ -1,430 +0,0 @@ -/* - * Copyright (C) 2022 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {Location} from '@angular/common'; -import {ChangeDetectorRef, Component, DestroyRef, ElementRef, inject, OnInit, ViewChild} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; -import {Keyboard} from '@capacitor/keyboard'; -import {AlertController, IonRouterOutlet, ModalController} from '@ionic/angular'; -import {TranslateService} from '@ngx-translate/core'; -import {SCBuilding, SCPlace, SCRoom, SCSearchFilter, SCUuid} from '@openstapps/core'; -import {featureGroup, geoJSON, LatLng, Layer, Map, MapOptions, Marker, tileLayer} from 'leaflet'; -import {BehaviorSubject} from 'rxjs'; -import {DataRoutingService} from '../../data/data-routing.service'; -import {ContextMenuService} from '../../menu/context/context-menu.service'; -import {MapProvider} from '../map.provider'; -import {MapPosition, PositionService} from '../position.service'; -import {Geolocation, PermissionStatus} from '@capacitor/geolocation'; -import {Capacitor} from '@capacitor/core'; -import {pauseWhen} from '../../../util/rxjs/pause-when'; -import {takeUntilDestroyed} from '@angular/core/rxjs-interop'; -import {startViewTransition} from '../../../util/view-transition'; - -/** - * The main page of the map - */ -@Component({ - styleUrls: ['./map-page.scss'], - templateUrl: './map-page.html', - providers: [ContextMenuService], -}) -export class MapPageComponent implements OnInit { - /** - * Default map zoom level - */ - DEFAULT_ZOOM = 16; - - /** - * Distance to the shown place - */ - distance?: number; - - /** - * Api query filter - */ - filterQuery?: SCSearchFilter; - - /** - * Places to show - */ - items: SCPlace[] = []; - - /** - * Leaflet (map) layers to show items on (not the position) - */ - layers: Layer[] = []; - - /** - * Location settings on the user's device - */ - locationStatus?: PermissionStatus; - - /** - * The leaflet map - */ - map: Map; - - /** - * Container element of the map - */ - @ViewChild('mapContainer') mapContainer: ElementRef; - - /** - * Map layers to show as marker clusters - */ - markerClusterData: Layer[] = []; - - /** - * Options how to show the marker clusters - */ - markerClusterOptions = { - // don't show rectangles containing the markers in a cluster - showCoverageOnHover: false, - }; - - /** - * Maximal map zoom level - */ - MAX_ZOOM = 18; - - /** - * Options of the leaflet map - */ - options: MapOptions = { - center: geoJSON(this.mapProvider.defaultPolygon).getBounds().getCenter(), - layers: [ - tileLayer('https://osm.server.uni-frankfurt.de/tiles/roads/x={x}&y={y}&z={z}', { - attribution: '© OpenStreetMap contributors', - maxZoom: this.MAX_ZOOM, - }), - ], - zoom: this.DEFAULT_ZOOM, - zoomControl: false, - }; - - /** - * Position of the user on the map - */ - position: MapPosition | null; - - /** - * Marker showing the position of the user on the map - */ - positionMarker: Marker; - - /** - * Search value from search bar - */ - queryText: string; - - isNotInView$ = new BehaviorSubject(true); - - destroy$ = inject(DestroyRef); - - constructor( - private translateService: TranslateService, - private router: Router, - private mapProvider: MapProvider, - public location: Location, - private ref: ChangeDetectorRef, - private readonly contextMenuService: ContextMenuService, - private alertController: AlertController, - private route: ActivatedRoute, - private modalController: ModalController, - private dataRoutingService: DataRoutingService, - private positionService: PositionService, - readonly routerOutlet: IonRouterOutlet, - ) {} - - ngOnInit() { - this.dataRoutingService - .itemSelectListener() - .pipe(pauseWhen(this.isNotInView$), takeUntilDestroyed(this.destroy$)) - .subscribe(async item => { - // in case the list item is clicked - if (this.items.length > 1) { - await Promise.all([this.modalController.dismiss(), this.showItem(item.uid)]); - } else { - void this.router.navigate(['/data-detail', item.uid], {state: {item}}); - } - }); - this.positionService - .watchCurrentLocation({enableHighAccuracy: true, maximumAge: 1000}) - .pipe(pauseWhen(this.isNotInView$), takeUntilDestroyed(this.destroy$)) - .subscribe({ - next: (position: MapPosition) => { - this.position = position; - this.positionMarker = MapProvider.getPositionMarker(position, 'stapps-device-location', 32); - }, - error: async _error => { - this.locationStatus = await Geolocation.checkPermissions(); - // eslint-disable-next-line unicorn/no-null - this.position = null; - }, - }); - } - - /** - * Animate to coordinates - * @param latLng Coordinates to animate to - */ - private focus(latLng?: LatLng) { - if (latLng !== undefined) { - this.map.flyTo(latLng, this.MAX_ZOOM); - - return; - } - } - - /** - * Add places to the map - * @param items Places to add to the map - * @param clean Remove everything from the map first - * @param focus Animate to the item(s) - */ - addToMap(items: SCPlace[], clean = false, focus = false) { - if (clean) { - this.removeAll(); - } - const addSCPlace = (place: SCPlace): Layer | Marker => { - if (place.geo.polygon !== undefined) { - const polygonLayer = geoJSON(place.geo.polygon, { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - bubblingMouseEvents: false, - }).getLayers()[0]; - - return polygonLayer.on('click', this.showItem.bind(this, place.uid)); - } - - const markerLayer = MapProvider.getPointMarker(place.geo.point, 'stapps-location', 32); - - return markerLayer.on('click', this.showItem.bind(this, place.uid)); - }; - - items.map(thing => { - // IMPORTANT: change this to support inPlace.geo when there is a need to show floors (the building of the floor) - if (thing.geo !== undefined) { - this.layers.push(addSCPlace(thing as SCPlace)); - } - }); - - this.markerClusterData = this.layers; - - if (!focus || this.items.length === 0) { - return; - } - - if (this.items.length === 1) { - this.focus(geoJSON(this.items[0].geo.point).getBounds().getCenter()); - - return; - } - - const groupedLayers = featureGroup(this.layers); - this.map.flyToBounds(groupedLayers.getBounds()); - } - - /** - * Fetches items with set query configuration - * @param fetchAll Should fetch all items - * @param animate Should the fly animation be used - */ - async fetchAndUpdateItems(fetchAll = false, animate?: boolean): Promise { - try { - const result = await this.mapProvider.searchPlaces(this.filterQuery, fetchAll ? '' : this.queryText); - if (result.data.length === 0) { - const alert = await this.alertController.create({ - buttons: [this.translateService.instant('ok')], - header: this.translateService.instant('search.nothing_found'), - }); - await alert.present(); - - return; - } - // override items with results - this.items = result.data as SCPlace[]; - this.addToMap(result.data as Array, true, animate); - // update filter options if result contains facets - if (result.facets !== undefined) { - this.contextMenuService.updateContextFilter(result.facets); - } - } catch (error) { - const alert: HTMLIonAlertElement = await this.alertController.create({ - buttons: ['Dismiss'], - header: 'Error', - subHeader: (error as Error).message, - }); - - await alert.present(); - } - } - - /** - * Hides keyboard in native app environments - */ - hideKeyboard() { - if (Capacitor.isNativePlatform()) { - Keyboard.hide(); - } - } - - /** - * Subscribe to needed observables and get the location status when user is entering the page - */ - async ionViewWillEnter() { - this.isNotInView$.next(false); - if (this.positionService.position) { - this.position = this.positionService.position; - this.positionMarker = MapProvider.getPositionMarker(this.position, 'stapps-device-location', 32); - } - - // get detailed location status (diagnostics only supports devices) - this.locationStatus = await Geolocation.checkPermissions(); - } - - ionViewWillLeave() { - this.isNotInView$.next(true); - } - - /** - * What happens when the leaflet map is ready (note: doesn't mean that tiles are loaded) - */ - async onMapReady(map: Map) { - this.map = map; - this.map.attributionControl.setPosition('topright'); - const interval = window.setInterval(() => - MapProvider.invalidateWhenRendered(map, this.mapContainer, interval), - ); - - const uid = this.route.snapshot.paramMap.get('uid'); - const response = await (uid === null - ? this.mapProvider.searchPlaces() - : this.mapProvider.searchPlace(uid)); - - if (response.data.length === 0) { - return; - } - - this.items = response.data as SCBuilding[]; - this.addToMap(this.items, true, uid !== null); - this.contextMenuService.updateContextFilter(response.facets); - - this.contextMenuService.filterQueryChanged$ - .pipe(pauseWhen(this.isNotInView$), takeUntilDestroyed(this.destroy$)) - .subscribe(query => { - this.filterQuery = query; - this.fetchAndUpdateItems(false, true); - }); - - this.distance = this.positionService.getDistance(this.items[0].geo.point); - } - - /** - * What happens when position button is clicked - */ - async onPositionClick() { - if (this.position) { - this.focus(this.positionMarker.getLatLng()); - - return; - } - - this.locationStatus = await (Capacitor.isNativePlatform() - ? Geolocation.requestPermissions() - : Geolocation.checkPermissions()); - - this.translateService - .get(['map.page.geolocation', 'app.errors.UNKNOWN']) - .subscribe(async translations => { - const [location, unknownError] = [ - translations['map.page.geolocation'], - translations['app.errors.UNKNOWN'], - ]; - await ( - await this.alertController.create({ - header: location.TITLE, - message: `${ - this.locationStatus?.location === 'denied' - ? location.NOT_ALLOWED - : this.locationStatus?.location === 'granted' - ? unknownError - : location.NOT_ENABLED - }`, - buttons: ['OK'], - }) - ).present(); - }); - } - - /** - * Remove all of the layers - */ - removeAll() { - for (const layer of this.layers) { - this.map.removeLayer(layer); - } - - this.layers = []; - } - - /** - * Resets the map = fetch all the items based on the filters (and go to component's base location) - */ - async resetView() { - startViewTransition(async () => { - this.location.go('/map'); - await this.fetchAndUpdateItems(this.items.length > 0); - - this.ref.detectChanges(); - }); - } - - /** - * On enter key up do the search - * @param event Keyboard keyup event - */ - searchKeyUp(event: KeyboardEvent) { - if (event.key === 'Enter') { - this.searchStringChanged((event.target as HTMLInputElement).value); - } - } - - /** - * Search event of search bar - * @param queryText New query text to be set - */ - searchStringChanged(queryText?: string) { - this.queryText = queryText || ''; - void this.fetchAndUpdateItems(false, true); - } - - /** - * Show an single place - * @param uid Uuid of the place - */ - async showItem(uid: SCUuid) { - startViewTransition(async () => { - const response = await this.mapProvider.searchPlace(uid); - this.items = response.data as SCPlace[]; - this.distance = this.positionService.getDistance(this.items[0].geo.point); - this.addToMap(this.items, true); - this.ref.detectChanges(); - const url = this.router.createUrlTree(['/map', uid]).toString(); - this.location.go(url); - // center the selected place - this.focus(geoJSON(this.items[0].geo.point).getBounds().getCenter()); - }); - } -} diff --git a/frontend/app/src/app/modules/map/page/map-page.html b/frontend/app/src/app/modules/map/page/map-page.html deleted file mode 100644 index 3e3bf90d..00000000 --- a/frontend/app/src/app/modules/map/page/map-page.html +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - {{ 'map.page.TITLE' | translate }} - - - - - - - - - - - -
- @if (position) { -
- } -
-
-
- @if (items.length > 1) { - -   {{ 'map.page.buttons.SHOW_LIST' | translate }} - - } - - @if (position !== null) { - - } @else { - @if (locationStatus?.location !== 'denied') { - - } @else { - - } - } - -
- - @if (items.length === 1) { - - } - - - - -
- - - - - - -
diff --git a/frontend/app/src/app/modules/map/page/map-page.scss b/frontend/app/src/app/modules/map/page/map-page.scss deleted file mode 100644 index 071bcd4f..00000000 --- a/frontend/app/src/app/modules/map/page/map-page.scss +++ /dev/null @@ -1,99 +0,0 @@ -/*! - * Copyright (C) 2023 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -@import '../../../../theme/util/mixins'; - -$bottom-offset: 7px; // no idea what happened here - -.map-container { - width: 100%; - height: 100%; -} - -ion-toolbar:first-of-type { - padding: 0 var(--spacing-md) var(--spacing-xs); -} - -.floating-content { - position: fixed; - z-index: 1000; - right: 0; - bottom: 0; - left: 0; - - display: flex; - flex-flow: row-reverse wrap; - align-items: flex-end; - justify-content: space-between; -} - -.map-buttons { - display: flex; - justify-content: flex-end; - - ion-button { - // important for iOS - // TODO: find an option that is better suited for the iOS theme - --box-shadow: var(--map-box-shadow); - - align-self: flex-end; - margin: var(--spacing-md); - - &.location-button { - view-transition-name: location-button; - } - } -} - -.map-item { - position: relative; - flex: 1 0 auto; - max-width: 550px; - margin: var(--spacing-md); - - .close { - position: absolute; - top: 0; - right: 0; - } - - ::ng-deep ion-item { - margin: 0; - } -} - -@include ion-md-down { - .md { - ion-content { - --padding-bottom: $bottom-offset; - } - - .floating-content { - bottom: $bottom-offset; - } - } - - .map-buttons ion-button { - margin: var(--spacing-sm); - } - - .map-item { - width: 100%; - max-width: unset; - margin: 0; - - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - } -} diff --git a/frontend/app/src/app/modules/map/position.service.ts b/frontend/app/src/app/modules/map/position.service.ts index 53d36b1a..418145f2 100644 --- a/frontend/app/src/app/modules/map/position.service.ts +++ b/frontend/app/src/app/modules/map/position.service.ts @@ -14,7 +14,6 @@ */ import {Injectable} from '@angular/core'; import {Point} from 'geojson'; -import {geoJSON, LatLng} from 'leaflet'; import {Observable} from 'rxjs'; import {Geolocation, Position} from '@capacitor/geolocation'; @@ -40,16 +39,35 @@ export interface MapPosition extends Coordinates { providedIn: 'root', }) export class PositionService { + geoLocation = new Observable(subscriber => { + const watcherID = Geolocation.checkPermissions().then(permissions => { + if (permissions.location === 'granted') { + return Geolocation.watchPosition({}, (position, error) => { + if (error) { + subscriber.error(position); + } else if (position) { + subscriber.next(position); + } + }); + } + return; + }); + return { + unsubscribe() { + watcherID.then(id => { + if (id) { + Geolocation.clearWatch({id}); + } + }); + }, + }; + }); + /** * Current position */ position?: MapPosition; - /** - * Map of callers and their running watchers. Both by their ID - */ - watchers: Map> = new Map(); - /** * Gets current coordinates information of the device * @param options Options which define which data should be provided (e.g. how accurate or how old) @@ -79,8 +97,9 @@ export class PositionService { return undefined; } - return new LatLng(this.position.latitude, this.position.longitude).distanceTo( - geoJSON(point).getBounds().getCenter(), + return Math.hypot( + this.position.longitude - point.coordinates[0], + this.position.latitude - point.coordinates[1], ); } diff --git a/frontend/app/src/app/modules/map/thing-bounds.pipe.ts b/frontend/app/src/app/modules/map/thing-bounds.pipe.ts new file mode 100644 index 00000000..ec05c033 --- /dev/null +++ b/frontend/app/src/app/modules/map/thing-bounds.pipe.ts @@ -0,0 +1,23 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {SCGeoInformation} from '@openstapps/core'; + +@Pipe({ + name: 'thingBounds', + standalone: true, + pure: true, +}) +export class ThingBoundsPipe implements PipeTransform { + transform(geo: SCGeoInformation): [[number, number], [number, number]] { + if (geo.polygon) { + const lngs = geo.polygon.coordinates[0].map(it => it[0]); + const lats = geo.polygon.coordinates[0].map(it => it[1]); + + return [ + [Math.max(...lngs), Math.max(...lats)], + [Math.min(...lngs), Math.min(...lats)], + ]; + } else { + return [geo.point.coordinates as [number, number], geo.point.coordinates as [number, number]]; + } + } +} diff --git a/frontend/app/src/app/modules/map/widget/map-widget.component.ts b/frontend/app/src/app/modules/map/widget/map-widget.component.ts deleted file mode 100644 index 74477408..00000000 --- a/frontend/app/src/app/modules/map/widget/map-widget.component.ts +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2022 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -import {Component, ElementRef, HostBinding, Input, OnInit, ViewChild} from '@angular/core'; -import {Router} from '@angular/router'; -import {SCPlaceWithoutReferences, SCThingWithoutReferences} from '@openstapps/core'; -import {geoJSON, Map, MapOptions, tileLayer} from 'leaflet'; -import {MapProvider} from '../map.provider'; - -/** - * The map widget (needs a container with explicit size) - */ -@Component({ - selector: 'stapps-map-widget', - styleUrls: ['./map-widget.scss'], - templateUrl: './map-widget.html', -}) -export class MapWidgetComponent implements OnInit { - @HostBinding('class.expand-when-space') expandWhenSpace = true; - - /** - * A leaflet map showed - */ - map: Map; - - /** - * Container element of the map - */ - @ViewChild('mapContainer') mapContainer: ElementRef; - - /** - * Options of the leaflet map - */ - options: MapOptions; - - /** - * A place to show on the map - */ - @Input() place: SCThingWithoutReferences & Pick; - - /** - * Indicates if the expand button should be visible - */ - showExpandButton = true; - - constructor(private router: Router) {} - - /** - * Prepare the map - */ - ngOnInit() { - const markerLayer = MapProvider.getPointMarker(this.place.geo.point, 'stapps-location', 32); - this.options = { - center: geoJSON(this.place.geo.polygon || this.place.geo.point) - .getBounds() - .getCenter(), - layers: [ - tileLayer('https://osm.server.uni-frankfurt.de/tiles/roads/x={x}&y={y}&z={z}', { - attribution: '© OpenStreetMap contributors', - maxZoom: 18, - }), - markerLayer, - ], - zoom: 16, - zoomControl: false, - }; - if (this.router) { - this.showExpandButton = !this.router.url.startsWith('/map'); - } - } - - /** - * What happens when the leaflet map is ready (note: doesn't mean that tiles are loaded) - */ - onMapReady(map: Map) { - this.map = map; - this.map.dragging.disable(); - const interval = window.setInterval(() => { - MapProvider.invalidateWhenRendered(map, this.mapContainer, interval); - }); - } -} diff --git a/frontend/app/src/app/modules/map/widget/map-widget.html b/frontend/app/src/app/modules/map/widget/map-widget.html deleted file mode 100644 index e35b89d7..00000000 --- a/frontend/app/src/app/modules/map/widget/map-widget.html +++ /dev/null @@ -1,33 +0,0 @@ - - -
-@if (showExpandButton) { -
- - - {{ 'map.directions.TITLE' | translate }} - - - - -
-} diff --git a/frontend/app/src/app/modules/menu/context/context-menu.component.spec.ts b/frontend/app/src/app/modules/menu/context/context-menu.component.spec.ts index 5e6e1597..58d2e78c 100644 --- a/frontend/app/src/app/modules/menu/context/context-menu.component.spec.ts +++ b/frontend/app/src/app/modules/menu/context/context-menu.component.spec.ts @@ -27,11 +27,8 @@ import {FilterContext, SortContext} from './context-type'; import {Component} from '@angular/core'; import {By} from '@angular/platform-browser'; -// prettier-ignore @Component({ - template: ` -`, + template: ` `, }) class ContextMenuContainerComponent {} diff --git a/frontend/app/src/app/modules/menu/navigation/tabs-transition.ts b/frontend/app/src/app/modules/menu/navigation/tabs-transition.ts index 8bb354a9..e9c6ba00 100644 --- a/frontend/app/src/app/modules/menu/navigation/tabs-transition.ts +++ b/frontend/app/src/app/modules/menu/navigation/tabs-transition.ts @@ -16,6 +16,7 @@ import type {AnimationBuilder} from '@ionic/angular'; import {AnimationController} from '@ionic/angular'; import type {AnimationOptions} from '@ionic/angular/common/providers/nav-controller'; +import {iosDuration, iosEasing, mdDuration, mdEasing} from 'src/app/animation/easings'; /** * @@ -23,42 +24,19 @@ import type {AnimationOptions} from '@ionic/angular/common/providers/nav-control export function tabsTransition(animationController: AnimationController): AnimationBuilder { // eslint-disable-next-line @typescript-eslint/no-explicit-any return (_baseElement: HTMLElement, options: AnimationOptions | any) => { - const duration = options.duration || 350; - const contentExitDuration = options.contentExitDuration || 100; + const rootTransition = animationController + .create() + .duration(options.duration ?? (options.mode === 'ios' ? iosDuration : mdDuration * 1.4)) + .easing(options.mode === 'ios' ? iosEasing : mdEasing); - const rootTransition = animationController.create().duration(duration); - - const enterTransition = animationController - .create() - .fromTo('opacity', '1', '1') - .addElement(options.enteringEl); - const exitZIndex = animationController - .create() - .beforeStyles({zIndex: 0}) - .afterClearStyles(['zIndex']) - .addElement(options.leavingEl); - const exitTransition = animationController - .create() - .duration(contentExitDuration * 2) - .easing('cubic-bezier(0.87, 0, 0.13, 1)') - .fromTo('opacity', '1', '0') - .addElement(options.leavingEl.querySelector('ion-header')); - const contentExit = animationController - .create() - .easing('linear') - .duration(contentExitDuration) - .fromTo('opacity', '1', '0') - .addElement(options.leavingEl.querySelectorAll(':scope > *:not(ion-header)')); + const exitZIndex = animationController.create().fromTo('opacity', '1', '0').addElement(options.leavingEl); const contentEnter = animationController .create() - .delay(contentExitDuration) - .duration(duration - contentExitDuration) - .easing('cubic-bezier(0.16, 1, 0.3, 1)') - .fromTo('transform', 'scale(1.025)', 'scale(1)') + .fromTo('transform', 'scale(1.05)', 'scale(1)') .fromTo('opacity', '0', '1') - .addElement(options.enteringEl.querySelectorAll(':scope > *:not(ion-header)')); + .addElement(options.enteringEl); - rootTransition.addAnimation([enterTransition, contentExit, contentEnter, exitTransition, exitZIndex]); + rootTransition.addAnimation([contentEnter, exitZIndex]); return rootTransition; }; } diff --git a/frontend/app/src/app/modules/news/page/news-page.html b/frontend/app/src/app/modules/news/page/news-page.html index 6bb214f3..5f7d1214 100644 --- a/frontend/app/src/app/modules/news/page/news-page.html +++ b/frontend/app/src/app/modules/news/page/news-page.html @@ -32,7 +32,7 @@ > - + @if (settings) { diff --git a/frontend/app/src/app/modules/news/page/news-page.scss b/frontend/app/src/app/modules/news/page/news-page.scss index cfe9a606..6a80e144 100644 --- a/frontend/app/src/app/modules/news/page/news-page.scss +++ b/frontend/app/src/app/modules/news/page/news-page.scss @@ -32,3 +32,7 @@ ion-content.ios > div > .news-grid { gap: var(--spacing-lg); margin: var(--spacing-lg); } + +.filter { + flex: 0; +} diff --git a/frontend/app/src/app/modules/settings/settings.module.ts b/frontend/app/src/app/modules/settings/settings.module.ts index 911f4978..85b00f58 100644 --- a/frontend/app/src/app/modules/settings/settings.module.ts +++ b/frontend/app/src/app/modules/settings/settings.module.ts @@ -20,7 +20,6 @@ import {IonicModule} from '@ionic/angular'; import {TranslateModule} from '@ngx-translate/core'; import {ThingTranslateModule} from '../../translation/thing-translate.module'; -import {ConfigProvider} from '../config/config.provider'; import {SettingsItemComponent} from './item/settings-item.component'; import {SettingsPageComponent} from './page/settings-page.component'; import {SettingTranslatePipe} from './setting-translate.pipe'; @@ -60,13 +59,6 @@ const settingsRoutes: Routes = [{path: 'settings', component: SettingsPageCompon RouterModule.forChild(settingsRoutes), UtilModule, ], - providers: [ - ScheduleSyncService, - ConfigProvider, - SettingsProvider, - CalendarService, - ScheduleProvider, - ThingTranslatePipe, - ], + providers: [ScheduleSyncService, SettingsProvider, CalendarService, ScheduleProvider, ThingTranslatePipe], }) export class SettingsModule {} diff --git a/frontend/app/src/app/translation/property-name-translate.pipe.ts b/frontend/app/src/app/translation/property-name-translate.pipe.ts index d75876ac..e476ec89 100644 --- a/frontend/app/src/app/translation/property-name-translate.pipe.ts +++ b/frontend/app/src/app/translation/property-name-translate.pipe.ts @@ -43,6 +43,7 @@ export class PropertyNameTranslatePipe implements PipeTransform, OnDestroy { transform>(query: Q, type: K): string; transform(query: K, thing: T): string; + transform(query: string, thingOrType: string): string; transform(query: unknown, thingOrType: SCThings | string | unknown): unknown { if (typeof query !== 'string' || query.length <= 0) { return query; diff --git a/frontend/app/src/app/util/ion-icon/icon-match.spec.ts b/frontend/app/src/app/util/ion-icon/icon-match.spec.ts index 6b594c5a..edf8adef 100644 --- a/frontend/app/src/app/util/ion-icon/icon-match.spec.ts +++ b/frontend/app/src/app/util/ion-icon/icon-match.spec.ts @@ -12,6 +12,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +/* eslint-disable unicorn/no-null */ import {matchPropertyAccess, matchPropertyContent, matchTagProperties} from './icon-match.mjs'; describe('matchTagProperties', function () { diff --git a/frontend/app/src/app/util/ion-icon/icon.ts b/frontend/app/src/app/util/ion-icon/icon.ts index 3da2fd38..627143a7 100644 --- a/frontend/app/src/app/util/ion-icon/icon.ts +++ b/frontend/app/src/app/util/ion-icon/icon.ts @@ -16,5 +16,5 @@ import {MaterialSymbol} from 'material-symbols'; export const SCIcon = new Proxy({} as {[key in MaterialSymbol]: key}, { - get: (_target, prop: string) => prop as MaterialSymbol, + get: (_target, property: string) => property as MaterialSymbol, }); diff --git a/frontend/app/src/app/util/media-query.pipe.ts b/frontend/app/src/app/util/media-query.pipe.ts new file mode 100644 index 00000000..b4a98bcb --- /dev/null +++ b/frontend/app/src/app/util/media-query.pipe.ts @@ -0,0 +1,18 @@ +import {PipeTransform} from '@angular/core'; +import {Pipe} from '@angular/core'; +import {Observable, fromEvent, map, startWith} from 'rxjs'; + +@Pipe({ + name: 'mediaQuery', + pure: true, + standalone: true, +}) +export class MediaQueryPipe implements PipeTransform { + transform(query: string): Observable { + const match = window.matchMedia(query); + return fromEvent(match, 'change').pipe( + map(event => event.matches), + startWith(match.matches), + ); + } +} diff --git a/frontend/app/src/app/util/word-break-opportunities.pipe.ts b/frontend/app/src/app/util/word-break-opportunities.pipe.ts new file mode 100644 index 00000000..a6163b1c --- /dev/null +++ b/frontend/app/src/app/util/word-break-opportunities.pipe.ts @@ -0,0 +1,11 @@ +import {Pipe, PipeTransform} from '@angular/core'; + +@Pipe({ + name: 'addWordBreakOpportunities', + standalone: true, +}) +export class AddWordBreakOpportunitiesPipe implements PipeTransform { + transform(value: string): string { + return value.replaceAll('/', '/​').replaceAll(/([a-z])([A-Z])/g, '$1​$2'); + } +} diff --git a/frontend/app/src/assets/i18n/de.json b/frontend/app/src/assets/i18n/de.json index 214344ad..08d7db92 100644 --- a/frontend/app/src/assets/i18n/de.json +++ b/frontend/app/src/assets/i18n/de.json @@ -276,7 +276,7 @@ "page": { "TITLE": "Karte", "search_bar": { - "placeholder": "Gebäude, Points of Interest, Mensen und mehr" + "placeholder": "Diesen Bereich durchsuchen" }, "buttons": { "SHOW_LIST": "Als Liste ansehen", diff --git a/frontend/app/src/assets/i18n/en.json b/frontend/app/src/assets/i18n/en.json index 9c7abe84..0591313f 100644 --- a/frontend/app/src/assets/i18n/en.json +++ b/frontend/app/src/assets/i18n/en.json @@ -276,7 +276,7 @@ "page": { "TITLE": "Map", "search_bar": { - "placeholder": "Buildings, points of interests, canteens and more" + "placeholder": "Search this area" }, "buttons": { "SHOW_LIST": "Show as list", diff --git a/frontend/app/src/assets/icon/favicon.png b/frontend/app/src/assets/icon/favicon.png deleted file mode 100644 index b77053663c9ae5f2626d38dc004635b1e698c74c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2573 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 literal 100272 zcmV(_K-9l?Pew8T0RR910f(>v5&!@I17pwt0f#~W0=gXl00000000000000000000 z0000Sn|41)RzXrP24Fu^R6$gML?=)Hh!QV>Y!L_wfx0Ato?kGF)mi~I0we>1APa&Z z00bZfh8hPT3cT>n;uZ1wC)#ZiFn&R;--ihVE(m=wa@SNfTFh^ zgziL;tiQI3we0`@oa1B+VIHQYne}%lFfx&nYMK+7nMlseW-FoAElG!ActD-zc_yC{ z6k5enC`B_zMys9InJMfWk65hB*wm`&=`_)H#xs6`C47UfqFHi9(r2?|vIZHqa8os` zvL7455+z=^d`r}CIOqe88WasERh()nd+E}=GYNHe#ZQ_FTP!;d^O;pis;I-^yQ6>acO={-EREoF7Y6jLD>1jT8$Jxm9)*v*HjCbGk4+$)-{gcBaM+8ZZKBAql z3};sqmSkC$cZa}j9SVqmY(;V52+?$-BB%_-h00D`D2f{#3si8dY--cd(3aZxudMBt zSyr~T{nCbI+Ju#^$HC_S) zmSuN#hNxKkxA)%rL?Ij%Kw*H;#}ZjYpNfoTRyHyU6hcqLvo7Y+J-<5z8W;zJA1md-CAjC-||`*G&Ka z49i0%*`7Fl_QaP04*+Zbmw&bU%V;{uC!{<|95TuSnvv9kZk?vn2e4VKmgc9N`QIO* zWw+byBptX6?+wywK5Tc9l?))RaQhL5;9_plX)wrAsftgXs`@`&)%Q0dq=f3~ntp^c z3kbPSWjmyA3~ItMvQB7vctFW)yTaRRgO9&uu^reO@8% zKQC4lneqVQ>I2bs2xNIITU1gPWF-XNv!A;IzXLy+RI#|Wkcl(@+Ya%HSMnaAlkBH9 z?dLJ!GLM1p*A?@2T}G17%?4i)fh$}k{o<{EGr7-J_C+LCW)?vc&u|ZjMx#?4qGO-q zRFAaK(tC?6TmYy~Y*d++4si0bJ?3k z>YnN@DV55I_{sL!zvpm4clEt@MzE+|X@MR??#!8EM~Qk`|FgZ{Ko~oFQDCG;8foT2 zcUAe7tv+97RrSp5?k6(uSb&ziAF{ox?im51B~!K>gTOnYrRnaf%zT$~W#kKI6Wh+b zD$sGDJ%;occ9R0h{9jcw_y8d`ff7y0wdqRNrSvId8|Exa#*BHHwhU|DUb|a6xxq3; zkuV9O_+QhMdfnk&0BeG2fO!I7!pQDZ*8l!~?2x`W9HA@kns+ z@0zH8)T0oHt}1mE!u3w=sz!vYiyO?$PtKYXcKq|T_rKY{rmCqu!5EaAaIH9yyQn5e zvI3h~zZLQ+L#}h9IAqn~WK@b3yyFg~E9+xNwm;tWcvAs!VEj3LPeV$qk$|0~=Hu7cbUjRk_!Q2ZM|5HqjsN3`Mx4=xbGv zDa|@%40EADw@Dr0xj2vk&q8vO%F&R_oYVd_a|m<{{;(PuJJuT;16)$d%B6o5%fS@0 zTs{gXPzDXvh+rxAfA+fRZ6TV+4`+4$uNo^S?>^1wlguT z#6SxRs;q74vxV(oE2m*=C$ArZXD6kSo!hnk}l!P`? zGO+9jgV{(Tyiz+~tDFNN=Z{n!Byps=7F*yg>nmVQ5iMU6%wc;-5-Ex8-BxyB4feiL zD~yaX<87U`8#CoG1t1+9zETxevM>VGQY8$#ZQ)*%X|*yJ7-W1_q(GW<`lSg_M>aJe zS5>x5BsR&m>w?-RK!zgGI=+NKsGZi8r-M186cAEVI;b>*0E15N3zsNE5G!?_V?F0h z0hgAYl)Y`f`RU1y2!G@+yX^D4uwP$DH)1Y^tv?>q~TNwWp{nLRVPYaE8DL9bO&2bY5-vtqOY z+JO*Z*}PuN*DV(8%tl-EGE~x+q=9 zsj~Idh%b7eBjt=}^}sIb2X?3&sq6Qq>_ZepD{xdU1fSSxq;3gP?W9`l1M}t6`AHv|YXkS^EcAL~5;U|SBNAy(LHLb^F-zxJO&9N(B7yl4mnki+k&s)v}t z?DXpkt0CqvM?&R|DVkWuPNlWGIm$}&b3J6jo86(q_SZHCs141xc3`@sO(Q=x%Is_UG>X91(#L zIMwVlh}H{jx&Qy{P0ir)g~@VQs-N?o^P4*|cYbbq?$+G1XM$&m&!o>%pQ)c|o|QeT zc(&`=spq2S>z_|PpLz*>Y5CIgWx%}ee8@a+UN|qA&z>)tpPIime`o%|{G<7q`Jd*W zy|RAg@rwEC^y`nWjn^Fe7i0^03)+R!g{lR^LgPZm!s>?p>GI)Kga^=@3^;e z?_>Kz+>t(CeCLh%`@iknE7HwAzVdH3EwnFm-Sx5W8K3<<=w$w}qk?6?k{aOr(Ye*R z)H%XA&spef>1^)wCjh4_POqKLJKb|S3Bd8XW0T`H$3}-#031T>KTw|A2icSD9VpKL z0D#g!;lm9HqZCr|DJc}V-GbdGyS27iwnerD0NCQmXUN;hM*xs_0WybdB%dT7AYZut zXM&03gJdar4LOWVB!`d_Z2lty0BoMyytf&$Sz|-72_k88f%iMV^*_~1F$tZN;vBTzm2Rp57lCk2uK{D=J6elPzs{i()(s|f)01R$XP&dJ{Y z<^Syi<4^G?bkvpVF!Vd5{o>=??;V+`N`8xcO{3R<_JV=hS4S9v1dH8d7`AkCJ)kVW z_=1bV5>6ySqAJ>L3PC+5qG<7=$)FJ_d*aKdpj#>WJ{dD%wy#00YclOuK|J+Yc58Jm- zFHLQyApet`zz!jSrrnpm19XoC$arL!=3E^l5JX^bLG@jy>n9++yFaiDd8X_-VPvs^<&) zhM{RbA2Y67LT+;44O{4Ehu2ZWjt(6cXGlh*Q-lFoVn10Rj>I&^nUqb@DPpYX#4!_Y z0!|`_9Ef9#oi3by=CFB&k%OX0iwLbn77DEC^7Ohz5sC;T5#$<|zm$>|mN|61D0f`J z^(4@d@o{n-XZCzmhJbT~82yT($h2qqW11#gYyf?TP*`{BQJxccKn-X}NYDnVkco6P zM?-HGJBHKI)(9OpBMF34hgbo!rTDX91tpQ6a8q;ay7^1})MvkI11QEEA;-r9E6R6J z;?{_rJa7z+SXKq013QirnVQZm6IJ&(?a?e}r&vMKCE2-3x}~r>@-scj1=mwm zASE+j%eDak!T(g5GEY+fgHn&Ah_u7KjN)4X{N)Dkbz*OO9``;bT6GaqvFCv@{`8j~`>_oekBryv;S@n~?Ab zx8hyw5t1Ko^UPgYr-XGu8_CPyVEz}AGSDMqU}5*C0eKTmK-3MmB*lOCVIAw)pSoLx z3={7<*r4zj?3R|DUQ zyj(A@V)8X!qY99=>)SOpUiT5D!uha_nxPj!pP={IOFu4alTIPwBdWa&aeP9AeGlkn0* zQd9g4e(mB>#brjyJ)NLI9i|t%*4fLdt3s1bsLz0;1mUaBn1N=*(c1f5X-tP*F8tlQ zFT{94LQ?6}9 zU8f%F^ni(?lP^^1JgUM%-0%BPOas2DlLGB@W0$oUaBOM*tRCEn{_b8(ZGBL`%uJ=tR;<<_+QHjbUhvdG(5UjG07>6j4NlD z8>#|EXMJnE641UdrXR3TDW4i%M01A(=O%Yk3x?52D&v|BnK_Ic(T z%+XcDflY`g4$u%L(1>9G`-&RWGaYG_mR+AWbJr?ztDTQ(kb1bm0*Q=-Qt8#PPY!xs zl%@t|Yq}I6KQ@gqi>$8}lrs^f1D7TV^no1oys~J-S5(21d%I%ns@dL@o2Uj354iPD zk$1YCZ+MI*F*oo)6dyVbKN7J8dYF;1b}s_6>;#(Nc-!(IA}&3Fsl~jtEb?xrsAu8i za0{;HX7G+WBN@(q%%bCq$9c2BtRIVHcK z*f%hV@#7NXhXSnuegi=@I;yL%jk)Wh!N7vyZS*}!1&EIOt~sB1fQobmL379A9AB+a z`}&KXu^Cj)EV#U$ujLdCwpCdxE%XotY*dgp9RWok_e*&YkbN}ifq`R?^ddvgMWwO# zPuk^8iYi``Bn$45HUfi~Z|x2IaUP<{;HOmJ(d*m7LgH8;RYPzrP)LQuqFyg<^>jXZ zk|xbMu1D>>tXh!aCeM{pFrs4qqpI=rNE<H_7i*Q=?PEf38MFrL}yHyp#{bUYHoiRPYU!5jck^!fQNC2)fWBnuRfEv|~x}hQ2 zdK_vZqhp(lydkYy^7^ujq`+EO$?gnYGD^`ct_Pl`57tqCe}C2vZS`vR>M=~23+T}qB%Kx%6Y2>NzYEDD zN;=-2^}cczzo2Hed(q5dp(rh4WiY0Jh=nZEqRQAwQV}-&9vE<1vRaGjL#{7$7H0T7 zE(362&{8s%cXXXH`eme!*hfDeUI!8Wr3iaOhdC@!VN8F6BP~!vqzg6sg$H(l7F4GF zp{XVbeTM~0IqAh{Cp|B8wFBn$GPtbotZ(Y)r@a^T<9=N~2YWB-lf{_`MAd2+&V=GZ z5Jz;$Uf7nSys9QN7tV65muRW9QbI`CaUe*!Nb!3lEK?LI%T-mEC^f@vh_W|Qn5!0Y zlq<#im2PuiMcbOnaK6Zx+(*^^wl{oOj^*B@QS7iBeG&@0BI??AJ7W#Mz^R z<>fBi)GO?(QM074XJ8tt{zl1h_sw|oh1t8G2n`2+fQ8dqYierm+IRGd)0`EHnfJ2c zgF>x@_qExmzFRCya+OiFu-!w~KL1p$dZ^}pb3Zsy&FZIbv-b3)3!5>s(z4>ZZ}g&) zC(EV%6=_=21LKvH7(CD3TQbplOH!yuZwsVW1{zWmF>#%(m>4?GtqNrsKnqnLsK+m} zbZ|UGiBIKj)hm|!dp(yQ_+0Pz>hDWv{|??rvYhT}mWk{M z!%Qx99j!9m^5iOCjh3r?;XB62PJ5>4JncP07u0M;?wPlos4 z*uWbej%3fxf%ypOmx4&WQ}CgLg%-ztIhqd>n>aB&tzw+R);)~`Z?+FC;Ko&=;ZSTa zY8wdLwBTW4H8`QgMpOkb=_y!8BMn=iaRo0DC)Ux#8stjw_%aSUfuY3==HF!P<>X@Q zj9tU&rc?b28W3x@8FU z8eTyxoBiG|>_>o2Q-rpPu-tGdfV#q~96Sy0G)5A2f+uAMk56N_6JK)&SZ6v>2QaAz zhb(kr7Go6S^pZS+$2M9T2sdnam|S&;RLy*7=4^H$zy`vVkGF_x{wwb3gxp%SKDM8igup zvL^xMt(f1=^)4S=5CET#e^^5x6deNqb}Hh;RQ7~D0O$b#$RgfWIxIYzIRZZgydXNR zfuq~HRkxe#ZJ%VCoju@sz@h%LKS{D*E)o_N3Y|Sbr9}q-FhoG3$JzZoT4d>7?L~|J zIqdSm#lIoR#$a|4qMOp_^|6V#e4!A95|Wu18y9J&E>~QV)!M1QTx>dfrmn2!WUOxW z>b$(h)WuHQsXLE3v!Bb(t>72C=J;&AaI~pO=2jn}7_HIXgZ7`X`s2*QVwVptAMad5 zO{STtA=|xEoB{$G(|h~0GW06u4ZL$inoT?=J^6^h+R@P{M@Ey$TWy@P7rCrP9J%X! zd2C>@C^pyaU1U|!WX6`S(cU9#mRb6th~GZdnflz}e2WkejgRyy6x}$pqGFsn{_I(* z**YuPhRBkV$PF@CgL*U}1!NyrD(XCQrZYabg9D=X-K?mnB^vCn2EEUYiHF3XCl_#& zTN(wksh)3ZxzQ-H_01o=8qQ#N_l{ z%EQ2LcQ3zl8C^~iW{GM~qc&4-K0z1bLF~dL+_I(pa7@OE>ia7-mR^nO)sqOen&i0@ z9qy=x)V#d5qhnp3I~C5mQLjW1Z9)kXOwL z<4%?W4pWXDuw3B6q5k}7@5p<4j^#KPi0;?qyiXqxYTwy4J`N_fYPq}R$NTo-XIyWa z%YVxrWyP1(jTpzgB7rHYFdJx_G7O7{#YkZS#`C{p0Sns%SuoDr_)-i zq>-eSEY>J}k|v&QkXTY`02(QVu459ml6%IXtw=ClOMbcGB%?NU#L^t)Z$E3hf4g;a zD8cvle1pDA{t;^<_(~woVfg^s1wxQ?IeW5q__mYR_>L`y8={lQ(b!tXv|Gso<&^vo zCO(%ikmRq?`r})E%(sTT-M5471Ek|H(G_^3yfFh0Q?@< z3biD+x-rR%E*zLG{)cYHty{*`(9D@-Qc;?lWLa+a1QYIx4s$N#tp}5Kt4!oI+z;ak zzdV{)4u2zTMPgzcmcKbr7b_j%9CY6%06eI#>)NZkG)7b31|t=dvA?Rm@wVQmCr*sx z_pNdObFs;rdJ!QtR#R!112818MCp2hF`|!{WLe&B!}pnt7IsRkM!w!D3HNgt77T_5 zp^auiAS`%Z6C-kyNo|IkW4ISR+=5-z!@?wx<_w~GSKDA#>y6L6d2?nr8p=@EcV?{` z1*EC^A@yW=K&-qqQ=d8JM(D9Idv>QNfwBI&R$~d7Gr2b&-A=@jLlUdE3fm1{l>E+~ z-Mi~{ic!pXJ^Gw5X+?>qvM*VUusc#abw^p&koX=D8e4;r4h-db+$ceOX}9Z!d(sx@ zU?pmHm;Mcf@WzECR5dS((LANvHSV zr?uzot`;t)K6H54KC{BBcISk?>(79NL;VE>l-1V!%uK%5)Mj+|IMX`S?;HS-CObdV z=jv8oE}(w??b#Fa9bkXi47;*Gaum)sSRXDu5k$KO%o$9-Yjb}Tw7;7Odctmu)WL3z zvqGP(W`smzKSVJUnVDVF_g2|IAX)7u=p$!&JOBVL697Q^u|RrS}CzjtQUHdBIEoq{O%FHzd zDTar~UB=G>Oig!Bu-{Bw3->78-G&A$T$FopF5um?EalE=r(oUevSlAEK762m2nrlO zhsB;74+{FwoV5V|I*0g`o*x2(SUH#mhpA!j-AlzR(^Sj7-g32v=qeOFbsz?b|olnFMp~IT-B#04)ali5p$NFX;wc z5^N<3>pBLf0ZU2}V3h=m=HQ@Rq{RPoT1=2fyhn!yOSZ41<&h(sf_hI_CC}NK{~x>i z&qsl0$}3teVj&=je2qY)g?An5KUOdilUivXPub~uG!0puC3*o#kNhKs&fpRwDIO2u z)~#X-Ec)nRfJb}8a1owP*GGeGLUb(##v<>?b{IGFSqePVLFz=*OWl@8dA9jORK>34 z@2zDljo#c3U$O-fU_y2&-MlNxd#d8?iZx(hfBLOtV3%{&Hgn(eWkdxUhbiW7kp4Yv zxJI2gco37Yl~SuDXWNvziM$5z(|!OXniZXe+eboI4Q)c+ z1kJb_dcGKwzH<&uQlbRckMyiNasULO&&V=&<72ev$6x#RlaCV`A7AJ9uN&#jhcq^S zecX#4yD!5>W5*_p#)h*h{yp}iJObR}zYW85jjd_J3UGMw*k^&LppXc8`*K7fBDrrN zMB5&Q!Rve*fFkH}evU7Qp4Z13OHRI!#n`t2h1#%Ba;n`OiF9u_-r2kx1t>W2y=eIb zvYd6b!;Ut&jNcR=GuYi$fE26=c`mElPWmV8x9XF`1EY6 z_D_^#M@1aC7UVR|^YRN9iNYE2)%iMYmJ5jh9oH4E`en(&I>7ptiN_ayMO4$~a7F3u3iV9)O^B~W_u|^mSBZoB zDf0wwdlJ@D%9(;R9x{dZLUXj76)!RlM-){Twdn>65P_|<4#Mmuij=I{cQlWYrIbsq z*U#cK^MBV;G|z4WZ&*k+P*-FVt>4m3!(aHbLG2^Tm3YulX1GW$ik1}P_Uw)xA&W6j ziMzX9{Hk@x&jk!3Nzj!mJ1ia({&aB!Cnhf8@ySiVA6zAifX{suzU03II<}m)-kf-$ zcgOEf`H1W|m@Ov?_IuJu&Zwe@zJ6&kv|7eqNtTjVvaj;AIc9O)lsfEWpPzm5X(oDv z8tv)XtZ>qSpZ5{Xj}p$rZgQ=zZbk)Iy_h-^DVemen3UYuh?w?pF!bSKsNUm8z0av@ zMtL|EpTdHNfP-qE8ki4eG&N-;sq_gr4;6jYDx(I3*b{^Lq{RKAG#-yaM3Jn5=YARj zQM=ved##{kuYRv^@oR;>gRb8r+1C44JFgx9(H3d>0uM(%{WFLPkmgj;pdk#2ccOw! zG;L`!1b**P*Syp2Z0q00!pYih52lB_(sIZ>nD};UCyT(#Ah_iLOiACfckZM86KtoqFSNb)y1Oi6)GBs=$Fy;TMcwcpie%?21|K125Kjh(3D8+F3sA2 z4qF-4nOwW)QJS4Gv@dtKqO)_e_wpY$HulA^SpVJo6qj)HxHIa}WZwI4ZN~KNqchWc zbI#i*qLB6D+iq?f*ONI{kB1I!$m`B)`MP1(;Wbp8U+W`qL}Z^EhTu)G5+sS0uki7cKa;Imr=tTtxD4NPMGvj4igP`QBl!0i^H^k!JE12=taTI<0`+ zarSJ7!k!-2ww^5(v*A5s6|@dd1ZO&FwK9Uuql^Lyp7OM88z2h{V}Y-V_4BE5kW04h zEgC3saw-`p>b31YIaj;2k}4Vm!fLa#<;vMDi&R(o?O&UmW~iC|^)}s=no2YkQRk?r zUF~T)3X`c%QCj;h)S`0LWl1VrK07))M5-v0=(nY!Q`-Hz8zD;}AY6`OOBy|B$0jt6< zPF)flE8)8NsIeqdV4hj5efFXHb*V>R+=G8krC z9~-4mAqu?b{!Bczj{o})fJ5Ks9r(Vuwp3pldStoK%UcL^2meSPjMIj3qVGT&V?ZXs3%%2TYO z({9FwrMqUMJ-9}<96@+Nbob-VPSYkwRg!!Zl#+ID%(>b|F@RcR}6+Xg)oI#5Z0x0eCk!8DpbE#qJY+n){C z2?nwuA;EajzyyZZ?VyiJDwRUhpxg+l%C{6B5L8CY2xKex>s0GxiIw`89%skbeOLU@ znuniH>c&fAy}u1==9%o$X(7lxShIvngC;EDY7VCS#etT+`cwM)&n&3lU-{cr1@NGe z<|__n`9?yWzYzyB`upCK_>=9x(UISWkK>PD&TvxuxTzc8J>J;fdDhf}?-@6KvH>hG zk0kM9h}i5Pk<@Q`Hh~9Gii6S3fihWZ0RJFxFyhUg6^iIqC0=RJ4b8G*@g^?|pTe~u zyv*z_|=nbjZKp+Yw>F*n?Gt(p4q3&0o_4-W{4Gs-@&_fT-qvVy=)s)>;Mq>iZd6bd=wG1b#gBc&_g z>2TiWkOO8W@9)9nNR}6`_T4w5-3>Cl7Cgeq(ahiz-K50UY5X@qR7k2e!Zh1GbXYbqIUe&m({g|$``FMG? zs_s|~a8A{xtT>cmdmM}x1o^tA@V(t{DJg0s%~Olcc8+3r!dAdIVu`_T4UrwviY})M z6S)yt>Lkzcw`+OeB_?PsuE|T85C&JmJ!5_IY;>??UOH$lIXcMCFNINSR|9j(jZ5D? z91+Ic6w=|E15da9%N?qKhKK}J^k!_p&U;x3|5RDNjd>}?q~!4wB9qs83^7C=3&?yStvp zpgf(M%fo^hza;Bb4`}|qJ*iXO#LljcEZnv~IU&Azfwl?sM42qq-6JSW{QdX6PFaeT zPLYv8;-Da=WN>hkW4f}}mFrdv=2VEW1&SRhp=a|onP#Yhct6+P*@E zXpVpHT&pWy?tbyhU9S>-_~Of7+W$vEBa3jP)$HfE{20%*K!S*!;*3OHQmAqQE2P8<%~l=O z^PyPxFd!y0f&qKv?QdCh^F$P~fH4{$1|p$2A~a!W3t=b#BI{-q*@#$JsKopK2%4jz zJPJCaqBb&CNBA1tid<-z7!paL39iMSK+wf`_tY;1_;jj4!U%>VXweR)ezLjK0l!C!vORKFb`Z&!clBB>pVFPT(&f_RJ%2{C~DpjGSE3CnshoT zsiUHwQ9U9pR!7eOATm;0NhpX&$SUtZs{&t@`(VQ^e5c=c{8inTr|r?GT@+03>!G4| z5QpCM?5G#(uwm8HH(fwkm+3Ie8l6r%C=-sf1B4l0_>Bv5ryJj-vTWaM0E{TU((yG$ zbUR2W@6W>O+#ENz>Q4Ls?p6%0&vR1 zYZ|RQd-39n4?g(rr=$dvqf-knFK35ChgN8=mUOF^=q-ti96$balgR?e1;2FeIK13EU1Ka( z*v>#oIAENlg=nYkat@>V^(@67Y{#I{`yiJt9)h`3jZ37$@KcDu2DpCTl2b%Hge0ag z+5f&&TGc5;*oks!{my3eC71?jQXHtX5l1nuyFXLIG#v!SrV-ovUbD4ptfASI^Ql&j zMD&ahi(B2+CoZX{YANo>F7Y<^vcbKUz8HL0FyXCMeDkB2nQB(|{sADh4_Eo__FiM? zSD2hwe!ouQAFAoV{5bZRQYGU53q#6zMsb^~&f|E=nIbJes9B0*(|IczKiyHC9*kPDkFCCKmr2QpT6yFB4^@yi!z~5Zw1X4;M040cq*Z;#> z*>O&g5uo?HK61@9)zGP=N>#)KnIBs<_1=5UaQ%j|r+VfJl4j((C`rII)ww;S9kW@a zwY3v4aYa&9HDX;UV}X6?l2tiDZWfk%Al!A=WjFVOAtFA+gX2a-R2ULKnn{4iMZ2kr z=Bi*s20wzzIKt}*Yn%vxW{_Sur(0#L;DvBWXmScQ)q@ziS#rf$-!C@8a=E5O+{ z;XEpesJ~HgEfFkfuz@DKNjZ99Rb}PNUIh41Aa^sA)(sU*D7Yjggd;9y0n0ejQ^tH6+RKg7x61r9;1c53{LZnGa1Jr{VH6mM_1vqmH7YI;v z43%y>`*ewlsS2j3Ae~7s(&_X|JnwNx6qC>>&Rs9ki}0q_S9~>Hp`D3+rrT z5nJ_1uG?$Jh}jpiT9cY1uES=|(Mszq3*q5I#Mx`^c-C%^)%<8pLbaIkqAg=sSEOu& zG(j{E^qSw#+}8_l_`v7ZgV$Wt^Mb`p??&%ES92|=6W&+Na<$X?kyZ5Y$Ehc7s%?hm z?v+xp;H)Agzw^0xKnA(mPS$IgZk{$M=XLG$^Dd^gJ%z`us%rUsjc3&|bK!@;wWQ&9;sefYxeep*x70**Id| zL;x#7U6Gs(Gk1i5F0U<+_-Yg?Bbu^%_M`_{oiWJy;8**Yp`vGD?>$MwSIHQpR)N`=YqbuP&@2JqtR6yEp(g`NJZH<`EceALQV+i$&InyuWKtS8`O_iF-wtSRqjZ3!K*7XI+A|E}v;dv&cH0_ibkdk705S zM_qIbl+upI^P9l~GM`r|NbWfk&KCRo$Fj3WX?aJ*?T*;h0$h-lI)dJK{QtnfeXn<7 z=rvvpURyi~8O@yU2Xaj}!s=;AXPrPyLAL<8{+fAPbf%CAr>T1WtnI%zu4a3x;=*=5 zWLrSWyL$|KXD$va@+OFd;DE0T?y0c}%k*@7p&Zkc-F+u}S>D)t4cH#9^qwVvcXu>D za~_wVDrIiS{}U!&;yPFHXOkYp=VrFtKLPXQdiL-t#;P;@_s&@#GRM+URACZ%v|s$` zwa1P!#V8worA9*4RB1~=>0HO=v%I<6)>73wX2SBlZ91ydXg+Y?{ zJI^8n&3;MrE$yN`MIrBi&wmaauA~OU8#mtt&FFG=WticI&GDRanR$M| z#5G-I6{I4tdS+?|IroGdTz&CV7KaaZ!jpObwLbtpy`S|hvN@3U(?MT17}dU`x*E^{ z43#C=b6p5x&wFEKPoeDY%S@IxuKyO`MSbhY5bE9b+#=F8*|~L%nXYJ+GA-T#-40-M zpAnv>hWRt8_-8VC6TENW62@~2$O$|MFCB(JU`3JZ>I0y6v;K(2ZPOgr+l}k5q}-s> z=7TD=JF?fm2%NG~edvv&IZ$>BNEjgQviY0}S(f}jDK~VL@gNn0_yVwEqLX{}6I_1r zlg}Ocum$%TKrO|pd>g1J{3%4u5%gF$7kCrdZHrz&Y@COCpdbP9LD5haG-dZ}=0KJ= zwtoXCJ-ag=P4M;gRU#uj@%d|0w0I3=KdWzxAtlC>`ci&u-rBn3j z#Kd_QJozXy)o2uoB+-Y7MJE1YQlRCez=x|d&0Pf{fT2(e@B=(EqqrD!Uj7PLc|RQ4 z9d~gRue0l)zFy^U%z`77R^)#N4j$32TW!qw_s{?S+E%-*_Lu*wGc~+mt@LkE6?twl zxEugHK*PT>S;IUkn(5Cb?6B61*H;{G{`8BBw{%DFfYib!rg3hy`{L^_CfT3)oi*~^ z*O&yOSE!b=TtMf)4#b5q*@F2vDR0ZBcN3J}Yv22+w;8W1)d$tKidwX{np6f#)nSUE zj=RhaAiuRgH>Hg0`OJ(lsY6Xtq+;aRbafTv72|^ILcqu$DVJKP4ETG^x^WVR0cRiB zpd!t0^B`O)mU=Y26FuCMRa}ITG;9Lh7RABV9GcBG%0`}s;vJ`$TxG=4e5Kg*SO&he zf)uPa-n$6o++@kg=-Z%FPgZ7xEFrsA#uz1pCgjQ#) zT~1U{g7WAG@0|0YiFvV_1PJT|M12qFz4&~?jUcJ?{N0^i3BFe?dcB-<%zI}*te5>? zhrKme4ov~4er%R5fa-p(J0yy!v~fh?m?MtmkV0K9@^T?^%mIfSsm3{$+O2a1IQ={3 z>&ROHmM%2!_QCo3OKv^?ZEdzCdu{E1&Q<->?QMW$pq^VDqGXx{6F%$JS}5c7SG3b% zlXGj^bLR@yDSWPXbp-7+k#L6)GH)}trIf(PBi237=|J=JCPg700jJLj$4b-5+T+1hC z0|hP*&fH8ddR;zjfVN2Qm&Li%yjY%VC-m%J$Bmt}Wyz8H{%;Vw;-4b~3;W0zZ4Mngdd!KWD*& z5iAD#G!_M7YtIDI`xw)-GwBRre)LpEVTa{3`X4wo#~Rsd?*!mQB$Q!f&=gLkwsTuF zFaul2$|F0*D;G(VQQ=#A?NUQCxQsby=Z9;)ggln^fhQS|{}xIlp|Owk4+^Zj>h?}G zu*HcoM(**=g8&N^Y_>R6)tRL3R69()GD61CBw>#Z@;DxN%7Hx%jNMa%_J>w%g|H}I z#+I-_{wAP-_7s;Cl$s|#)pbP;sZ9Gn?t(G2#+UAKz+0*(o*%y;=ge~{*08^c%*I>3 z6!%|Mb;TKMKrCV*_6gJxBiXt453R+=Q?`sp z4*kDOm-WaXQx)octi`UPYVLpJJR@tYwcG~#@hz8xIP_;R$(Oe+?+EKqR#X1upkO|5 z)tknaA&s)vh)|G56r-^gS<8$vCONzYLO0yh{7Jzcr!_W>#Whu#?xDgK3?CrU7Mv5; zVR)~x68u{SL*_@-l^^lEDSNw|FMk5q0{Wy+d&E2YGF*L)Px(-v;?upKRQK?k?$+Jk z*}vMjgqC-~v0vgGWGV>B#oQ9eQa?hQe~4grW_5v`jY>D}A%V7AO5jJr3e$f23_*p} znT>;HWfa$~%UsE{t?z3pJsXZ*Svl5H82m6~2WYwnujaojo#=|o>mv@239*CTa3At+ zJ~I8U?xyRsTe}`X7#;!|dH= z13~})2^Y}5nT8927NH(W>A9_H%}{#Myln5@Ztye?{r}(c=3&fRN1*M4Ps8&Z)XrkA z&9pnI}N^jfF$NMJFi9KR~4=NbE)d3y(bDr_* zS?tZmDTO`{t=TwbOngP9j7APv3VbS`IzARwP2}!KMm@zYQ?_TK!O}>))=AD`24CU^ zka)|F$TIrll0)24M^~IMgQ9EK3@O#}7NZ`a@!wT6see?RYr$+)F|my0y?LC8q9`x|CtCT z|I56vA7SjABdr%HC1+2Mpk8E4pIKB-o2MA04clRV3D*sxI#J8ycVIr5=Bs+%pZ2|B z^fZoI%Rfs+9LH}tuz+3I9pi<2clq<;goKVwEqHmnPal@>5q#RN)#v2@CB`Srb-T0O z^mUezcqbeQ#Eh0)ZxTYG=bdSg7YoL|tJQTS)se!mb6&6IYr1qBD4wUWnAEB4Md_>g z74*KSnk6_CO!3ITLx_sUASWq4VGpWKLI|&%jXAn^G8qFcOHT^?7Ud}K(tp%8o{x7#W@VZO zf!j^}R|H}6DD#x#*qLw>u|kh4RJQyD4yJ#OB2ON^_l_cveM)PiY;v>n&N#(KzfO`C|$vo zCE4uOn0Nm$8E*513n7?NHyVRqt=0QM&~R9R;v&DO!}R9VUDQ{ROAMI>ML%tc0B(*Uhu|-7f3AXwc4sK3RW~O)|#e8uX{eeD+HP9!_ z5R=96e+co6S;~lR#J(5+@ zW7Y?gW>YK|@kdRG7&L%cugI`Q_59D=z~(N!(QJ%e)VpS=;J)-QE)eIGdc(Tsy(0N# zEr{kdu|ORLf<}h1nd?a5~1!&r(YZCzL&vyyv`RhZYLh^)z`Bcbs2TmoRAi*oq;8X z+Z=!@31DHOb6@7znYUGr^eNc9j>10fz&6i(4p2tl-l+yA58k;-i*v9K>MDRzDlW-r zhB6VdjCj2}k9bBwd)!T$EmKfU|C>D;tPxqJVf>h<~ePV-F-?swsj z!;|fosB+ijai{1-&+mfjiCZ;KOLHqlreTmLO>3I?)zebzb5=}KT!vEO`?5Uh`LogE zkz}s3KAp_iU)@T_O2E_G7;+>{rr_sCK5wphkO-QmcVyUJ^yul~_X_}4M-z^FnOKzY z-oB?x)+}fy(L%}wtve{j6pgg;Cma#VX(}{;6J}Yan1>9L%J&(tbts-dnrriWCjkbI zr{Pp&sO?g+Lrp+slJ?B>=rf`^XMk{JV&r^=t=ZY%Z|`z$-GIFca}6XnaAj|cKkfC zbuEv4QSG?aB*H;8M`j|fUc9mSql0|`>?>By!xG}<>X+$4%}kq4h;re8#Iz)gfsO7g z3hoYnIXnl%Nt$ubGm0>Q-zOg`7YW7n(WYP^C-vxU@FJPPT)%v4VxANkmCNUNc5OT$ zR$VwV82$!&VG6hbET7aa#Q^$RhaJ(+>x#$Pfy2(=QM!|{wH*<@>l^YV1>LW?aeCy{ z?B%;6Gd5K_9t;fP8g!pJRxK_5l}a6SG-_!t8ktWe^nx*Kx&UX+N6)u7 zwo6T*(*#0jF$87UVjBGoKjYsZG>aJ2fYV|XDnSG%^K(CH13_LlMSFady}PcTiFC~_ z2PrV@YrVhP!LAMYIBn!SzDu|(JA}>i&?=| z!Ywz6bW}(}sW3=5K?rU56bMG<(JC=d=3U4tU_$FF0@<|q{G#iohMBUqIE0z}N5(w1 z1I&P>m##Swd?|O}iyD>NYU{pYva=j)`xLMk07v9N;fWn3%j5JjP#f767S3>pE2{do z!rNxt2k~!pta4>XujDMVgHN@-Auh&d>RBLA(Zu`t<`*ddppEOpv7n9fGJb#po1D_4 zKsVY>TlDaVk61gsBTu1V*2~T49LK5u|Db#C!8uOT3=ik|ysv-(E1iX+KvLG|GgwHw z@MU_cR5~?R*~1d)J4`bgBiyRE>+P~pyTLJLU458;F1)pivM&d*1w^-oYVM*R>*l*B;9GZG#8 zyz}@`ToP>civDQqH=7m4#yxbGj(u!F`w6Y>8L8QAT?8Yhrb5u;U?l0A>S9| z1xR|saOHoZ;)Pm}P*cZ2i?19NJ|8L()MeL}duGE5;K|cJk4ntkv!CpGvB_W(s{&Pt z@h31S)O<1;(kZX47wo;4B;V2ty|$GPlPPVD{Pj)09lDPt&%2KGRn`(O@pDq49uuY- zxRkxK6N&QgR>hUq@*Pu#FbI@kn38xi^!U+8Nby8Z*TCm0CI^w5^u$Bk-$C;zlpho1 zh#%%2sf-|Mk9XLR1uuhxP@x=*(9b=2`bWRP2rC2uBe@Jhhgb7?YdOK04Gw~rAtCw3 zd#J&?|Cs=}K#DybOhN`J00h)0dnD7%!Y@RS;AbBf_*sIoS8}pIBjxv!_eV$&xfUqk zohMsF(8DL*m;tKYZ~7Bc$RU!P_WUdp)mZ*+>Ib>+HR|5+0T(;S*RKCYyF*rpv}ru0 z-g*T(bOvvFPwtKA{AMH#d=nuBNOYf{DV2$Sp@e6Rx7v#&8&@etl|@zz$RfqF?-aS|8auySDef&-MQ^ z8h=3;8C5Hzxza(cgOX8++DjBk?in7&yhRTf8Z<)T>pnM@N1=@7n}%KuJjM`WbeuyW ztjj!~)6P6l7>|C^1vUR`)!ZI^k&j~@>=yDQrMw^WIX4f&AFPmv?$>+X z(9m#2EgRNSOmxH5TNB@+ zTlk;omxz*hl0^_Y3<8wYbLrR}b5R>XQ;qBBvYJnV^O=mR`9!Rb4rvg`cVdyef84!0 zM6PP_`A%%X%u2sfb#*)Ttj9ttTIQVk6k*RomlJS*v(X+t^0hEi~4J?~Aw zxitV#psG1jhZ$UHA1`2=26sLhj9bg)GxTqQV|hBG9}F^G&kE!+Fr4?@vx`xcB0ISn zJCiQ#W5gB+5;%QJGsaWnR$9DZ8-TiX4>O-4axN+rt%HzIK=IZ&?b%VwR3aLR{blE9C!`FjIV-vD$MsXi7ZQMk6 z+Y*BrE4FRUUJZ=tb8+_~mRU&MSd5vCn%*ItS|Q1ix{zTyF7%eyMVnVm{f)npBSeE|8-B2_OF2F}Js1whEkf=X3ym)-;?#sMFy8Wm zEkr!6pTkT$cq5XNf5W-kuyA^a{5}C@-YVEYIus_6G#qsF?OR+WADthLh7+;iz-)@+ z-el4aaWkhpH@S;kTXKPX2+;CD<+D$^`|bXT+n8$?XTDkJ_Dk~fd4YjL?83{}m$3bM zq4?$N*SM9-bs|>NOry{Vw6^}JSR8}YyKkLtx9{(@_fExY_jYe2_>g*8gFa7kbY#r%h^$kBps?h9rlSabsR=+jvUwDyNq~mR|TuYhv z)UunTd&ELkb;{JcdkRcF`MIb=6@NPl>BtxpgY+<8Y#&e653!yFb&Nm0 zDCF--3urP=?gwKJSII|WLHV$sw(6ckOjo?nN|KmJ`!URXb{r0NM<3jt@(^$(#MWAm zvdMIxtLMsKimm^@$_HG_?fV?(K;TRTyGgLJ*l!lZJ=0`CZDl_D*+1yTd|p4;!3sI+WDBx z9=#sLGUx~W7(CLq!PomfxbCaI;j4WYl;=)n;g0=~vPcifc`hPF8u+f4>YO?iOHf5{ zS&8*8)|aN#(KeJWVk$5uJH+(E#mZV~t(Du?O0hg!4E}*l7aEZM#yh}^r!kVMz zSVE2x9BePud|FUW5AyDSi*<8f0jE&&Gb8cNDZh5+0xtA8L?R6)rlEo?56rFW2qhG; z?U?CMo+G&J_)@p6wjsx!!j89_ylh_{ap+_L@xZvrf=Y6FzFGX%o}+V@$I0tDAl6MA z{g-NZ-nQ1JCf_I6S$h|cJgw{65xr6zsu?9@B|o%%;@~XPOuU?3GpJt8E!5txVc3Z< zaRNEqeK+(v*V2QCg#!;o1XE}3b+zF0+Jqv)i)y$QMBLYC_a>2EJM{6O2VrfIKzgP) z3*C0H#p%fz$H>faTy7D!G=c-~*`zO~&=xpBwhZHV`R2x(X**(d zXt=B4vs?bxpso!TgT4ulKi&0r{)}beVK0n^nL%iGZ>Dz=`Zv__|HDigRYGFZK0eA9 zp<3ul-P-PkM_o=KNafOb)b){E1ZV%$UYWg9}hY7U|jt(X4$OWxqW42r+ zoaKTQujLOM5xu!a2puq=q_81u?a#LG!D0dmZmHs1IWvQ*YM`pagdo43n;xb%)GXRj zRsLeo`}Ls=(MNL|QsUhmp6r*O?sRK9e0s{kna* zT0x9w3REOy@FdO}N#dh{RewOi%EgTNKa&;%srpr06a$EQd=$LbQDTai>k?uMLVF31 zQ45hTpGFqxOdIPlROO?gNJGMme<>j%3W1P{eZ6eAh>^fLh+z^JaX1ni)2Jn{xytom zKQkdeE23n|p8K_Ml`wUqA=Ho8JYAkixg64&-B(~DO(3Ulx(*wWkgxU+C8>2c-*Izs zR|}zv4;n_^G+H=DnQA& z6D!XK?6g2Yk2loaQMl>l7pR0|h`uvoQn-xE%&VtZ0VCJqsR{Ef-aVG%2M?b7L{d^j z@eE*T5V)=qXo8}x`ZQKN!sH|{_jVzoOS$6^KANke)rukDBhQa{w=PFOO~(*oty#{K zMKZaS}bE?osprY!!jGeJxEBH_i*Ab*_Cr3QBc}KB5)jM4)k{xJM&V#v8F!fs7 zHz+mMo6^T(EJ{lWtCK3?O6F;NF8=-Bh^4q~jydYEz3py=I}nW1&VX_cFE1bmq0v}k z>`4w92)=o3d*oR)>ecT97zv>?-E#fdH!mL;CuuvCmcxMD-4tb~!9*<$yU+D{&p9`g zYrkSmC7Ox4+6Gc+IhbxrBr0wuriXYMQ*OPCfSN-PFl*#8>Bt(ivAteGk}Ze~V~C?G zPEz)lM-|3U(m+tG1LiFHy4}R9Wo%-OFo|T~cnlNXWS64!gJUG*^(EWw+3)<`&;8W5 z{iau7_PD5NQrlj%+(`HpuzRDj66iAqjR41?3>acb(-@AX{j&ndRn6{8o{?U%29}=N z%h$VfrP_tT=vM*}Z3(u7=}t^UQWo4s-D@9ej^oTGLQEixitVoC{v@8$P;v}R_=2Ki z0aw!VKt%eS-w#O4|4qcx`Zn1fLF( zN0J4^l!+ak)Pg?{0ZzIOG+(!8M2HE*l#MMX6lUl488VMF&bV-NMLiGfQxs1@<9>=06RCNxXGoPv6fiQ2Gmq9$ z=DY=jTQhQbtf*zXklK4iBkEDeMYsP5;6U-*7S=b9Cu#AYL9buQ`{MnD&sz`8H!O@I zX7lA?&R%4%>CJl?Up=Y*QX-^^xE92yM!Wvo=AwB}mfJzzp*yw5f!a6;)cUb@Py5_; zH|FeZb8-}BbbCPLw|t)=Gs}vZPsAAKMgv^@xfJn6RhiWyK$ai8VKPDbv|xwCJWsc{ zuQ4|>{#BU0>M2Q39IRT>au(jvW~yA#_JoZz{;QizfOtE}s5z~@nnOE{@s2Eejvwlp zFma<^Mwu}vSD~+}tl|_hjfD)(`qY64m=O*jK}K>#_3spnyd2TT1ZIQcqDq`Mb@i{7 z%G5^&prxK3F_lCxfU9OzhcRHW{30QoXMil>TxeJS#5bIJ)6`_bX5vYs3 zUBY?cIniA8Wf?dX0ur(2V`LF}CoF0{z-+PP;-S#bmBqGOca0>+R>dk+>U8K5L5v77 z&mij5p;fC^<%ozaPn1kAbQAO`k0*1TX=K66u4myq&s;MvM`X;h85xB9-eNGPhWC_l z@c_&_u2n1q=#)c|sG3GXvPAgCI9_7xDb;*0Y3J46j;n3I5E4b%rz!$>L%SkGeyUA! zH>x`%t}^jSl9K%ugbZAtRvhPs;d6bdKnoTDOhpKgHi|f+2w|yx_MQ{QiS~>nBl^&B z+PmV?{DtIa?deE(>FanPIdLzI)M_`xcU#0l)nFBqk!v4^9yPFI14hvjOH$H*biP(} z3=uIeJO+G1QKik}Ybl=lK`K{SbOr>?hdjzvpz`~3m2u$-cHqyZK{=7ziHgo8UkFR6 zK4rzTlE(^IE!wDY5H-P7}3w1zVGDIVuKp{a%A_>B)S5A(~h%FkE zk3-6fA2tVr)eThG#|qv!r8zA^3(7#K_oGB=TkG2I_Rijxaa5pMt42Gi_{J?wU40U} zG0R+wG^H8)wtycw*e1;+L``d%iY<_+u+lU;8Dz=5t$kx;GJBCw^snz091=CkdttyS%BmoIW^Bp0p#*k_ zUg@01Lj4b7pgMZlbKXlwjUd3;LmZOQ+RC7%7oi(dtY{-SfX+@Xg%|{`=Qi$liXJ*Q-v7@1!iV{%}A zYSN1FG6n?>0YW~fG)yf6*_`^Z>F3$#sWzzK#t?HEj4SP1X=7<8NEw8Ow6(ge;`)Am zlBb;p)$>lOEotD%k>NKKrizv8K3wZg(`ieiep1qKq-gQP#^Y=Ow!yw$WWRcqqvUZ2 z4iTaa?1+U}fsgmqVcN7R^FhfQd$#?7qmVW~i(riw#Dhy{L+Tw8IH)feNm!bwxGx0* zFJ+B1HRf)$fdfLK8PyiRNSv=l@xW&Is_Z}m3TlVk3_yM`t`ADFJ-1hPDfMsMEL+X- z4PoI7%WM4O81#|Je|4kU%s|4$!x`t)klu})t2veK&w|hb3%v?)hD2P#=gMJ>wbN)b z?bC0P7M-+OX*wVSG$4~)Bsn$<_1ogF;`f$(%c%u~%q{sVK)%svk+ z+YqL8iQi;O#mDHivszm}(Vqyb%@cHGNpBPiOH3A(6P+iQp0Qec*a#4n#dUw)%HZUX z{b#rIkt;T|86|9Jr>aUV@7PjK!wRkV=Ub(En|L)lVMQ5U(XhBQsMe^PCjB9ThyM5Y zebR4&q8*UDRuitBWECYtuNJ{G=+HRnDk^I^BX790_Cz5+smYs*;d$QiqHo))c2M&L zTp-PN`E?MdoEv(}mmQD6QH!_iAHIcjCwb(c<|-ko)ChBOdE-h^hSzbhkxcq))lW^Rq#n3av(xgNB_y zMsxbDky0qAD3ogPCAv0EwV;b8YWa#S<+O}y#h=+KH#_VMkR_?6DGU`*T+vk?N@M-B z?fY~0g0JoY#bT%5fpj)L=#3x5iDz<#Ei%hf1~m1gkwzU21vWYS#j#CWRv4Tso$HM$ z%sQ>}c-;;h4YI4YmGKq1K$s5GnZh<2#LgBe9jCw(^pXs-vea`+Y&V=Vah~h9o9>@0 zNbP@yr*eB%1~SBEE<$Vg5`4;n}X^#n`Cd90qa>FW`p zI4Z7m2g;QLj&qy?+Y775#D!~4GlN5i$Q3QN=_tjT!%fc%y@>aYW){;q?@>@8UPv(; zIWKa4qdQhC|L}=d3mLrVy&;yy2q)(M3*#s2r?9S13*A}-&2xo1wv z_Vyk}OL{GxKeCEP@fT(_3c%t^I(9B|UvDu$tcI%DciS^}yE|Li0R_cju{mV9E74vV>)14#&OzyfgHU`&2vQqy^&k)v~dP>T=o5V}57h61l@xjt{9r<{_bu?^D#*;F>z{Rfn4ZEWta zY5LErDRvWyF&+gask$b|7Q7LW9o;rW^ueS}Z-#gk?0fDa(BZC(U{Nqx?Wd-RZwR@C z|G>c_6EJ=-zO7wzZF}SmO#&HS5avj>F%D%MhKMdc9p=eKt4)z_bFDs!W$E%$>W%ia z#T^aO$t>7gRtqqOd?rR;{de!tUFvl0`A*C2q-))-7d1ZeHlL{}DI5d?R+mH@ycdTR zA9oH98m_a}ZKW9v$Krnd4yR%`>J$2sxh9cjq_LvZ-$9l8JEE?P&G1ufnxEG|EwB~L z#N8G>SBg%lvbUW~SbHb655~gKebxG8UH{$PFJY%7cL^WPl{BK-Yf9}hq;}eSeYB^G zcD48G@@c^KQsFnuQ^d(&bT3oXJDVDUe^RH~d0>1cj${bWO|m8~8YxC}=$-G7$6Y!r z9*i2F924eQpRH~V#3Rs#IOGZ5tUxUM+{NpUY@sXEFfF+<(|&p#z*3&~pLdoYMa(Vp zp%n$&Fiy>}J7!if9~F7Zvgqxebat~v^JukFc_b=hH)R_UzpJ+~qKa$WW_7W6@C$!U zC}jj=GE(W0dCSW=LdeRlS;q8@jG$T{TSc#`KIaieI`>|6B#3ufnt;bJtPpOzWU*U6 zUhdUyKb!Jx7Qn=$NMJh$r7YwoXGDt=Vu3Jc9>Xa4B|$g|)+u72udeInq)vvWMgFx$ z_WyqO?ROK`aoiX2ApK&yaO~>4YY(Dz!~A~BB`38nu(UY;Hkb@oNeAmoc+9dQv#L9!S&<{5@)Frx002IPzrZqCqh0JGBmH`OCjfV-Rg6c2@zWJ%qrW-Xdd90 zFwgq+Oa8%w2x%bClTWNyh$Su=F=#ZlD|R(QemLjj?Xlc0-KK123f@l?QIR~vS$0{- zEnE`wN~8%Tz^>(^^}&Qi2}uY*JzTn*8%sQxJX|K*`up$QCi-R_!MyjZt+ zKy*B^!C`EO4?|bupvv_b`cz`wAij?^KPL`kx|OkBlMd|+kl^9N4H-2wwa2yja|j|k zyea(*@li;v*@f_$x?JYtT57~L7ezsir~%Vd(YJ%5du}w9`Of;-8sqPuj|y?R$v<&H zG19x7n`Iic`DDy*7ImLwPQ*;}t4|ZRkr{q-+&?!VE{n4)O?*`5(CN3<{WIn+!zA8I zbV9eWui9{CV~p+Ne1Us#u&=pK|8o~L)-~^YRB0_>rEQW)XUv|Rg!47#slL;p_Rt#z zz)_WABJ3+ui;JsvXTvE;fXcQw!-dJ_J{69B|B|4kfMu&mUxNi-cQ_m`wmKtVe8ED1Zd~$`h43^ z;IL)M3-+mq3tmo%O#;h0HwM9Hmk;hst2KmKb9&$N+r`k>*;j_Za#-=bEX?1sEA%Lv z&c_;DG@rnFbu)i7aidoM@1&jel0d~_d@05iN33P`|KI)8yyMTk*e_1c&r2y{fuiCJ z62&@UPY#Jb#~O2|W!pFS_{`IaTU*2xzhi4M=UAUtK)&5Pt$knl5r=;s#AS^)%d9P) z@l3}hBi3-hO#_M|zGCuE4?yWErvM8YL;04E%<;9@ui!yzSQgVt z(U?cV08td&>RnhYdr|G-rxF^&vwM6>c<5z(O87VUQNNd*a_o7B*VIcbrUGR$qZan3 z{a&gd%98XHT(&R!(wImh>1EEZ0!4Z$(FL4g+AJjqVJN)C&8r{b+_8;JNiE zEA)yh^X`3^=~P+==PT_vG6QiB2K2kHe03}|vUrOThOs!-X0I8a%7kx2Lphvl zMd?VsRudmwjPOFP^5HbrdAgnR%*JLY24e~yR?K@0=xR388CHW%URBl*3@>&ir0FXg zTdz5{z>Jofr0_8sVup3%A3|2o51ZmA4Wg@qPnso$pzZiUSjT^cQe}4vU zucx-_%XrrB%Vwj)9@wty<0Z@an$r*X;r1i<`SEisW&NIdwJ!#vnj=#tW4~t3S+EJr z)l6zO$V&Ky`9ea~kJ4}Euw{z>3Jv+~i-U_A_8d8iKkV$E>gKce9+J*JY!1wQHum{( zhisj7I<-hK3Yb<=>XhoU!&N7 zr%oaA_4j)+KK7trear5h-vb=CWxXO*MyfplgVs(^_B_Xb9>R>tkJ%w^rON!o#>HX1 z#}dS(XoQ2WBp{=7nGguU{(@F5&Tg?a=tZRN++OLRUL4&rJLy*W`#I+(SU#HZyjtX~ z8!mNXi-m*m6#W0-J%W5lh$nVh(0Wo1SRY(wxM?1I^hX!L z>5tIt zb1%&x4v9E;r3IPO%`AuY7UZ>{hP|Sj7Xo{TDciI?Vd^=8Q@!dr+{oRW_2nZ?bF;<^ zw`=*B5hI5&#Qv<#*t=)t<{Rs&6!js86PM3@P?&&W@w-c3c=Ha|P4424C3o!D=`^&? z0bue8XCSG)6Md6qIDP@G#p!4(h2U5{Bu_eYzZI8X3u05*O!aZi1#>yp^AB;XPE&xPQ%ETL3`urm4KtMYzU=udzZ;otFl!I;}xG3?9&7Z zdgK9Get8Iv{p{17Pe03x!Ex&p0hPT|KwAzy)<%#Ai_a_81f}eZ7}$r5$j8!lFkpw% z*%>NIn&WUoiL;FMKfl?wbog7BXB7!KC~=bwLCm#R#BevBwQ)%%T4;^A)6nd%^{em< z{Ts$3HZ~MyOC;F;#(i2hCSu?oJsL-!Y6y5(Yt|$5Ek{cA{t}U}Un`L~6muFu9Nt)7 zLQ!iLL;L2Hq5>zirX^NBX@y8lnFRJ25`rPzJ!PX<9Sa%zJgW}8w)_%Jeb&5Q6DG@uH;NJ00Kwld4|X9Y0))ha7$;!H143$o(Ac|My3#EG z&$R)im5uja6-jQGd2yZEfDq))Vc~2WvP&YAd%ZnX4W}SDNurF1ZR*nlSSq&gRvV&` zrwO4dM(S19EJ2WrRZkoSTOHv|Ey!j*)nsTLTT1|>!&>X`F5dB?gnh%yr*-Ezm}Lt3 z@!dJp>%8IK@Q&iR9`6(*Ttlp1Y%vR+JKFfuwm_=w!xR)mRw#XzZXv}>Cn6I6pE09k zRs*aQY-8;$tc6}!3$a*i5sECH782#Q`_rVt_U;gtM4_W1lrzht(0x1wOXw)Q?Sum zPyKZ@7H%byyjN@&EZ}I`lGQ@)m5pfP)5^7_cLR%ImV7U{_t`J%p>WiHJgM_(oZ3S z$Saj^6l_we*;8M@cxU$Y4v2>axqSiy;-j=Xio=eV((X70W`0_FDGDS2Ppyma1;SS; zCwCMuJ9+fJ4{V}!_Q8%WwpLSzjO(&T8P|n8+7m5R!HcL z^{~%s9bP2yzGq!&BQbH#2{PjxBia<}wBjREZZGFSvu(9g^ntA_20VvU=D#{G-1FAx zQvyK5r#2xY!huZJ15MsN8&*0*eE}q~4ll&CdZv>%&bm^fN!MIy5}Gj#8CUf?{C8pZ zp+kozEjC}>K&MMBBjaUF7vG#DRff0;$q`RA@<8*YI^V5x4pV;EPNyvG>-y!M5y4!_ zQx=7&c=>_bgV*)hmd@gwq0kx0CYKi{TOXoF27IHAs3v8p%JU$eSAS8NHHqpI&o&&H zG{jJJb#?=Z?K#y&6o!b4+TjenmKKR{;{PG4JYBOef4!C69ijtXC*7jl$6~$t!7mop zghdy9wd3|wGSM?HbllB|@rAtqfD9#tR|i4=#OHQYj8(BZ$jdVK=$$6;F+4p*jZJtu zMd4q0ma5WQb<1M+PdP{VuR5k!kJU7{xyeiS&CX}=L%zvfF_whLU_abHBVHK8*<^?g z=9>z;fr02#4G01GV2VXO1w+kXG5>5ECNz%nhnJuIq_|Q1>dsrAan`3?Msi3HLY}}u z?q*XXj<6?(OlfUkqP}ynp|1-OYeE#PBkcdOA~k`_>+Wm;kTDnvb1~>7IP-dZcI!+g zE(E7MSPMC@S-LyIYQP_by``wY-7gMK2T}7C1Ebh8e)NsQohwm>So;t?GEE=n05PAa zr4YI7Y=FjO^A?}*%6@To_a(7GoEmiPb+h}Ky>50sLoL`wCmnXmg{z-B=mW=XxA*c! z8E^hq;>*XUS{1odo!z&mds#c`WsY560M+HcMNxzR zsueI^qE%k3>D`Koh9G+$!;}cwBV&|P8ycSVubl5+?b!HFi)Xz|#+<-01so)YBGDM( zDw{kdC1~-7PBqxh=`71@4-NC>{AoJ|d&G`0P*wUIX?TA*LMf#K7dICk(PzU-zE9`u4L2w%)A6 zN<4bj$AxEfRhKEbn(aN_4Q<|=yf^=cAcr+LStrk$S`l?lTn9cR*=x9wlv?}ZU?LVa zSd(-Bfh<;|jbnXmOXKMjD$Go;6#$U;=-W@F?w6B*-U-P^S5SWMH>;vF`*T%};zcKZy8-`;8RN&w`U7GvhNWt8RGba>p6KXiA+q>n4FCs zGoQTSSc5rL1ja%P;ENRyjB+zHAr1`I?y>1CZlvUWOjD6aWV$x3Q<~|m&>q5^@rUg^ zeof@R;tfLMR&Y^&Xerser?Q-bvf+9D`!CzQu&Y4SX5?!!3AH zsz1?xnS7F9lH@@D^LESUp2vAJv3v`@wd*Dqc_3SisM%CvQ^!u;A_~DttFJA>4$@OkFnIm6) z_M5N&Pvi%0#({|(*)|QoI^TKyPMk;KaS4xrP51ld?*Z$8J%%@{Zf=%zkXEj%jO*2i zT4dAk8ESEZQ#uwSRao8}NM;+Yfl4`JlOv|1r!X@qR*DPxhGjPwfh?0Os@3YD_ zN=Y#6h>Ly=om_{aX|xg8oEjqvkUK$n<~7n1M&}DLg-S_U>>CKBaHqXRo00^qn$!jX zlV8kxBZla+Ukq0D3qUczI|&3TOT#c+{qqezsWBW^|NIh^)EJhl|C~y2fYG4=?0^t0 z$S8jV()g?B1f;Qx^L9Q?0P!Hyyqp0EUW(_6zgpcT;`a$;2^Iz4ijA?BNMSrMGYCrH z+OhE%DfDF!q%iw=sDF^ykuc4wZ#Kk6f@8Sg5+sGP&kz4c;cqVDk|g`d3hto?cMo#o zA|R7he&ew~iRi1RXDV6GYNT<0gYTe`p5Yhy49OdBNdd^pxA2&De54M94FSXK_2AfF0dgLYi%90?2lPun zo`Ick!Vdk8T%FQu*dD`rF7M%e^NVxrX+R94K)nk_6T~JgK}6bFO(9r3WvoQ z(6RSH=0MoSB5iu|L?IX9JL3n(hkr8tMHI)8&u5X#5uM|iDm)itdxUrMt(V)J zj;)>ofEhRxz;Py6froiR^4g7(Pd~@YFmfftp$>}d7FMFO`C4vrs`U4d9}`veF%cm) z93foYQjW~yLgn1QdE;(oi$qzYVWzSF^YWXoDah;o>*Gm4Zvk}i_$&~<(7VRW_}r5D zpnKIW)rCx!joMlqDu~OfEbh&nerTS@igC>+esGQN{`d6T>=g|aJfdW0w=_;D4Ll~! zaLM^DNS4BWdLaMwO2A5RSM1+}B(0}~nQ#~}yDa?K%omx;nnPxqvK6eYoG9>2obC{D z_QP(W1+7Rcb62m3j)`0okm>aZT`!9a7w!XJS^%x`FO3UsAD>+lxKI_;be&I_w<$3` z=l@rj=$$z^#yXBY^bRYq!ntvm=kCBn{^~$G;OyFC^a8w;DAAx?{AGicp|Gli=kx%< zlJ0vy2m9R-t0^jJ5Qn8ob#*)dJwU?0&UUh|YdL1Q1<~XMlcTuvs@(Y9c6N zhykz(_nj|bGNSvPc0NkX{Q{$N*vm=b9RQNyZ<~f3Fwa8=)@a}S?O+~?F9i3KZvM&O zdm4&+>t2Z?3zY=(QO?VZjF_+H=1Jx1CYo|6nJH6uL4pGrS(TM&3?fYffJ@BpF!C@E zy~ZO!92I=pCX7xjGBKc$;cpm6TtWPl+9IvY?Z+~=4FsUUnZ^R>0!uY0X(DT1?TOO-Z`W?i7$qm9;fF8o1JG-> z6O#>(r?JUQvU>C~edD^E41KI-^WZJ&Q#GZYgtV~WL0H*4v(RtAVb z3Qt-J?W!Zricr`W0Y$6J!pCt@d<7xajEgZhLfQwween)YW6I~Sw>$C_i)OpOzq&j- zJ-fW>RYaR9*@XN?03o5!fN+#BPo8e1`I%DDVl-)u4%*%Ecme91Zu_7dnT%NePCU6u zu}re0kvFU7S+_P z^d(N*de!e0d0zDTRlDxQ*CpqJX4Tq4r8RX_;`8CmFTD{?JQ9`XDs_8}zk3VMO$z4i zvF33zVK4ICZav#J)Wu#YzVf-xlPpln6X_PWjN#h+hVp#$_vw^; z+eQIKf68w4(erLRv1#IbdQOR7hIAM7v6apFMp6iF>N`1xOR7U@VF@ed6U-H*n=+Ry zT=2Dsb-{Jr8Bb3%&Py885iDFpOZ?-!6B(#ox=|agcE8=~%%N@pU@5WJM@ElShdIh> zE0hvXg>)00P|jGnFbZ<6Xv|Se$Crk@@Al*$JFzq;8>2R?d3nL0L;!9ir z1G(sT{e*!cp1Z3NR`pW1Qh;hp4SvH&SRMPO8YYGV-EtK&J4bvTggVp+{6ApcZlk-g z8vXcBH2)bSwK|Xq6bj=|)ihly42DVW`k=AC6ipw2J@o80;y5apsJy^{(@xXBqZ?Q4 z0%9o&V>$&-kfWhL_T-e4MfTNyDa3`;a!Yo!PSEFEvF18P5ov$o>K(to&%S23`1 z+_ZH<4_~P_p?;c1LkJ9>&YVxhCmfUR$GJB=Q7&l#XEAh91mPj5b0XxH_6)K_$37O) zW;b;;6(>n3=}eWVel?9MlhS6zM_JG7OG}vNpkG2V^zwGE%0wy;+5gvsTE9?F({May7e0F4MYZqM zqMzY&{71lX$!v?xvbo2&=kaHD{*tmg!;$1atIvpgqVx<3#(@oTvdt9Yu9b-)<>Ku< ziLIK^1poxAi(kmWW*6(<%`XBGtaUSQnaeH(uJ~BW@)NOV3EiG z0zlUh2!Iu%JEQIu!TpVR@A^d>z zz!#j8vs^NxMI7__BPKkfngW9%2?jAJQNWfUGRbkJMySGd5cP(?;OzW4q#>ta8Or|0 znuR*{J7lv1J!aD5hzO{XA<$*gcTN~EKt)xyMADg`TO7wJlEiQR^>td7>#58M8sM=4 zAZH&^Q5H|sOVwN=G_NL~?eM7nS=e4P%zvs803raq$V5$mpzodJ;@k zqVp40!Mix9tp%Ba4`P02+u==wE!#B5J%xad{83{k0$)*)G3&oY$k=)?O_p&%$96-IA20kvh3WFY6{KI)&$(eZKc1Yr)?4rT(%JL5;G4XE zbDD{I|4tmd1vZ`0EX!3AChki`%_gqUf7aAGruuWc;=M5Y@w!lk6MH{3t;Z3wR`2x*npBJlgQhQs!gPTIi5A=e|t+r znIrN;d{{rvBo^s9=6*xRTnw2!&>+LlId~9DD)fbwY0D;MOCuaByae5Ox|uXely;HS zBZHEjpRQW7iUA>+ZE~h>8~H;xvFC>aoY;m*>|m!K1}e(73x2A$LkM2_h+C@=0EQC6 zD}39>+UDsh*@<}nJJnRx8=de>6=RH0Np)pO8+z2l5!01g*mfmU6@6FMLR~gH2N{)F zcmS=4W-20^@A)r0^eKFt&xwcT50|tgVIX9`P)zjGr9DRxSu76mAfLe2n$dlZj0BUA zaOn@#cFZZS!LYaT253cw%u1_g_}2bIHDUXK?@VXY z@rV5+>3>*o^)R>F@*hLzL)7nVzTNSI85B`&9*_0BZ>akK!sc-G76VU@JQP@Q=ob#u z`^iYf5sq{b+U7U5MAlhqquvuAHD^tQP;wrCRRbT7rB-EhgLQxGRtI}{=b^$%_e2np z_f$&dVwDIvar+|yV{o3Ql&8GR@BEMTR`Ro|xngNP@RLO!p*n+!YRf{VW0!_w&e4}VPor4vV zGcD_8QZEFoLH{XB*Ko!Cs$Zvhtp?!G^!PJf(S`=lPuFg~XgAU%NgM4V{d+I!GF1g0 z45;CU=Qp+C=z#t+M~L=Y-Q|qaQMLiRbtR5^ODWOE)ct3T0R4?x*syZl!@(?3ql!<9 z{+1R0?z0b6`q@|iOI=GcfI|os`fHi59r1aVVoX`?#osd&0#1o^1xBBMXp{uO<8Xrm zG-8LWvB!{51b!X7%J1L`=WExpedvh%+-KE471nY1{qs%DGxE;yi=%iim{tKC#1^>2%!s&eS#vn%hAQy3fEZ%|1jKc^qRJ&4}N{2L?0 zG_1UHK2B4*jpPfTQo=K{j12O$+5jIr-6dqpdBYbAeGY__t0mfo-t0kf*{d-RybqHJ zJn=8|+Lwj&-Gf@jV_E$;Ked8g^!gHOYahMfJyfdyb^Pye(R zCu6Sy!KozwH{Vt_>E`P-*PE1W^w#%vhVpu4^xSbCXhP+=|E6P=hXP>z)%D&L&9d~m z+1Sx_IC{;hqi|+b8mSFb$slS)6*a?@6#d$N=*+wz@Te2bB2`nqNuV5Y{_IiHRupeOt-*8&}_MHRKNLcQKlXtnv<)D zqeI=4&OQvKkd?!^ys~&5Pl+B6VP{UET&8I1Fi*SW;UAnUw9rFD6!0pWbTxQ8-;D2H zuj}54dh^bHGz0MJgN8_3`PpHHi+CJ#xSTC6vI+LWc{&PGeGs+SKKq}45PpGd!49V` z{hg3R+A9MZ7@~Kh2qJOmX_tg^D15&KDQ59P)C+y<IVwJzYU)`h?HEtqH z)E|BC`}V2Qxw2vyC3fPo{`-Mv`iDn~6472~$(ZKkHzews1W-dpn&{rRck~}pO2{(G zfq|M4h6kcd<=6yw=Ed2rtbo?$-g~!WKR^TG!Cy!=WB>N!p;htsL*mq_<~PYK-LzS! z9qwpK4LD11gphIA*7cLM2Ef4)!4Wm#;IFSXe+z>Miwjz!ztCTtg;T`{gCPiP%^%1m zlF>bUI;M~357%fp6G0T4K8vW*R;iEp-9}Vf@6~k_Db>(A0>FJkJEJjK4^U7L=mFiLR>p*2=wHfmsM7W zBA%()h{}zkS!c$&GkyHHEcKIDU7B6F2x%39VlU!MAoyNK4Q(AR#_}a4_jenQ9vz4J z!F~C_|M#BCh~(&bqq7$;?lrV`2AXs1P+6GT-dGZXLxIB1*^t*;ty_78SFoe5tL#fc zyr$(AkJs$YRg)^Hg4pt-tLw2HB2c%{TFF3TT?gOo?9GtYeltiY>HLKdn7;shbG%Sa zF(8HamRnz6>jw47WQzkTW!O@3OJ}8JyPNg?bmw6G2b;QI^tx=zO&RN;mPqN+fwEQY zuKT?|(>+A){S-eN=dPdAWNC8@wb6h(3S*%$|J<%m0je=UuK1XG6{zlC zto}`}*gY@H)6xVz3;fCH_~fyK67_w@Tz|GrTsOWgX0+CR`)T$5HC(><SuQ&-Fe@J*hE zkaNA(1B)UCqTOXnW0T+%iOwz>7-PzELv&)Dq|14e+!(mxDO z4(l>1!jrZQRZ+OZ>?17Pw}QAR(_{uv4S}thb_`6FivULra|{naz3Ly*^}>@na76Bk zkFVt+j%97Ltj1SWPH?j&YuhPKBXlMc#u~OhkFEj&iQ)y?X_>(>*h;KRCABk&6EOLw z9W1W<>D2X%AW@8c`j!Vh`M3zP=Er{Z^-=Us81Wm8-U@FUGvA)u4eFC{MguAVrL1>j zDTXwPj0>pJ`*Gy1&ue|LFWgWLv%%H)r0N2&P7^`(UL@sPsp-ugyh_!b_pVG?~Dth>Hr~KRZwYx)$H0k{Z1c523e-E`_lD^^m zf{MsGwx5Vrz2>(Kl<@QO^Y2RHZ((dd%bMh~z});ee!{OZ|4;JS-?*Tw(TBgM{5rVr z5|a8$&C91Tci~b9u^d8m{0SDY{k~QnRtqKUeJ+SCCS@GMSnYS2lbP^7=|$ciN3+NGb)|QcuS)HptYUK4+zS(*H{}g$Ww!R) zS1gvYL2QZwL=+vle>b!#>vm6*ddv6yvij9jWoeBttz!d49ScgSxVsCv9xX2RAC-mh)G$rdh9=lp>g ze*RG^)cmxw`{U_fKj2T`1YXOi-Y;h;%%w8bU-7Idb{J>F#dAV>`24pHM5a%sbmqbzMY-3iB~f{Civ7OSNR)#uH@z*R#lwCdV8g z$scQ8-oXl)>5U0YGR33xz|T!!lBv82^1kVD98h`Y-i-i@ z#pPv2KH6>SLy=`}s9e@R55MX!5QCz8Vg&f6!OKO$`KYI>1*QA@P{5kdhDgB&$WH-k4@&Yf%e<@L*mVIGhErWqUpCAK zp6!%Iwf^&21J7xhk^@ZI-jrHtEiO$U*mTo$8(@8HQoSCe-3^pvjGJTvlSVehe^mO% zuWgfR`5>7}MtbMhCJ@o$AkbSt+d{>PEVbSizBfC&hWG^dl-Od6mDXF#$EOmXN_^6s z?#Gt)e0=bIF`ODfd#&fnSg0^f7QS%t(g4KfY#x+@Xo+udgNIkuDSQRthUd1YD7V;R&za0?AP_-m)oR^zzi|?JFW)X z`YEN+M@RCRl=P>_k=r7kGKyz+(-J(e1=+*i^yHL(_?%4pr7c4!5q#Id6Do!^Cbio? z<=#_lv^XYI7Bk(CWdD?VkK>sumFs<8)$V9OaYV>6sMq*ES#VhgH{k-Ur3nwgO;B4?6F_hi zNduEC^05-@&Z7G!IKagvpDQ1@?6T1=ht0K%iz`34^22F3R|({2{>)(qpNuK&Kh)dw z{?8l%TJ0}RU&-rDh=oI_I`b!WWgcUG0k&ze!8su(Rn+i{#!x}MEb?|tq_oCz=OQuh ztGp^T;$0Cnh7K0a7gKM=V0ozMGQKbD zrCA2Xh%ea-`UQ?;zl3IPWj?p0k-cm4D2qc$3MBzulw_u87~uv>^tC)mM|O{X=D_?H z&zP6Fen>b(eLGG%2?m&CB>(yH+yFyn;#qOX2S)uS=l2#aMgc227UR zD{mjb#DsH?u2;4s&$-Vak2{YoamX?zl)S`6VLaU_RwLk zi||uZk0`1X7vV1bbUQPWzi|vcV_!Y-o6&+wPwB zSmtnZg<%msM=q*MDLSN@_W(sL%U7WFwTpQExD!F0op79O@>yT~dGW@FGmOWI$63bP zBg8UeH_m32Uqq3D^SIVMH}t>U*o|AR_T|VO-RIlHa!rh;3PSR;3V;Y=!-lt5YBfi&aUs zmX#8N{PiViF(l(u3S5$XtfZ<(t!cSL4Wqe2kMv!7IV3IK=25Da@{*a6$P-}pR zhMqtspp<5(&7B_6dOLMZA$z8c`z_74JN;cPc&^B(1Ni2PhU;44^; zZhQwVnwh-f_ow7swucqi3;sA>+J7In$X~_D>TmxYE|92|=T;)$0utYnZpY^9G#HQn z>-=9l?tenzDoBAb`b>Yt9_spEKl+p&tdl$G%Tw<>_$TIEwiNP5Zkq;W)oD&=V&-K~ zt-EyIJH2qKF1i*B8aVPc&hTBfp#$SElMFQ{mt`y;-xl9DAFCmrf|xM<#=034*#XR8F_ z9g+3LH))-Kj3K9Kvy#g*HJlf_F<5t!7AE3UKC3N%Kdbtp(Z<}N@V9*Xso3G7paqfS z{^8??5Bw8F78IyB^EcHy7N3^wz~xAfKS_7HUHJ1tAdZ1|r;D-Y+4}Tqaj{;mzgK+G zh#9xg9>d2o)i0*eQEHyXFNx_z>5tHVLEU6)2z%+G?tD)9tA`+@@1Mw-lBu?4{dtzv zrERQvL`F$VOKxYnm2E@X?&(g+y>f2aj!0czViRen*Mu2A%&+J{yzz~RpVP|PyY+YJ zjLwsPbwapv(%Y8@!7l*iq->^1t^2SHuw@b)wkEl+x1R=*u!yWH@(UrN5F@aG%`Uae%6Q^Un z&&*6+)lAv7fOMPew9M+2NZ=Iu@v8 zJDL_}6Eq6mIyceG@zW*=r_c93t#h64y7mfrQ3+;|W1fHKAlG(g*!@8>dsBFT#W4Tv z7`?ifZKJU&fdP+i81TVPryo98@s#u`QB5h%Q)7uYqAj;sE;!^xH{3z1+qXnNN1*d^ zi@B5ZfDxy8%gQ$8f3UEx1yx}58J95m$WMxxN_w1=xB#71zVHTr3TzPI0G{(&$H8C%aMLCff4NxLmESV7`BeF14Q}2^m8lFTKJ#!xW?>iC3 zJxMtu6`SG1DWAJwq+j{v035smef=F+>t9CUe-fSeA15%z!PiHKOaheLVxkR=)1j$Kw+_n>tx0b{xa*3`tQW-;L8f$-D6@? z6XQKsDd6b3`IHj}@vpvlBwN>oDp1$rroa5+zIlH06Ao|A!O+;lJUJkw2Cs^i!`!jL zLr{fmu%d}OMru%zDC9U2p8=pmMsFQR!5T8AT)A#tbZA&;1V}js z@-ah$BFTBPL25w;SJGF;B@+0v%9>j)t2j61Fh<9w-Ba9EU<%pM+I?o>nhZw zZD_e}#54)*isZf}R*e)oN3X@8AbOL@gDe$$BuXzGl>;r&wBfmjCu&c)OWNPUvP$$>MB zi&+N66p(`6**Bb+j#1QfEsGngg2YJZAnk-aJ+O*{ghe zBgP9peYR8$-{15pYjVc%(e%90Xp}giVx?R}-oKS86O$PVidWef!PGZ280VWR%dP+L zXaUonfQ)z1pB1@1l@b@-l#r*x)~D8xg|23Y>bd&~3kN9N>REMZZT?xDLy2>lM>N|| zl0pbmP}=b#rx@ZqMBGzU>{$|5c8*nBEmA#7O)Wamh5Gu+{Lg_Z*Jzvv&Gb59`w{VqtNSm)-HwG6+3qrdBui2{FePAR1}y|=ELa1&vCMv&QO^L4pCUtzvCo`hsM7`z%GbDcfH zhPztnT54*G64n3T8*u)ly8fskNNl^YO)=;h5rKg*p>w|g)Hk~~8@saDlwj&Q_n@?! zba5yju2)>NJe4@7AL>M$L;VdMCqdMt9|i=oqUrPYiYbr9`c4eu1N9fvKd!Ue*y)aY ztzAaz!*Oa2epFc+aU)b{Kel0O=OnhXS!OYA!cE|TRd%SyI``AgPEfQo=|hK_Z*Ofcn8Fm33i69%#7n85A=5R_dbaoE3$=rbHS(67tm-U=`|whsAW z)<|{FD*IT~6?dCl#e_4$hzi#%*H3aid4lnx?jP>Ho9~9+#`9gTBtc^DX@|^G6R^c} zt9iRUa;>OO5o@JS1IHYTyl+e>!>a{!&PQ?2#{P|JR8L9BwiCkOb;RvpaNTu-G&p@H zc4?ZgGCsfz*7toN)X$VFkSFD3U%KX@_wfK@eyFD_^EWEfg}MDOe7OCN(l@ol)`d?i z*}NH67!qa!AMqKw3%*^uhC{4E+kOt7B9GM*u5z1z#LcPaEcm+;{4K8fl?{-^maFE` zd<*({nCF{?*X^~w2up+x_j+QRL#~K%qK-J6+sOg+%&v-!;XHUm+Kl{g;dwra6ORtj#sq)H4(v1nL$W4kz z{|-zDnjY8e35`{j>I(&F0hQo9Vn@wgRCrt~BT*~kKywoLGFbM3%2_E?5FHk;s`LtRyd z)UOAg^oX%MA4SXcpwD6Hd-(^WHY3p%{jOLqVo8`rFVch)#5j%&o{M9 z+R?)~52emJBZy%PI4)TfxN&Nt>XY$y>MsZafu)X4z?bA*{0~D81ba}ElX_!RAL;oX zns``9er8736O|uff=nA+IWzJ(-kal$=lkK)kBF)Qqc_6JckMW!?hPP)>(@KQIKK?{ zWux+!k~~l1I~)8-#HfD;GqF(BNBI5!j5rr_m84N=z^bV90t0*A4lRH2cs)~GqvFz!a4)Bre z9hJT41O(WwhVO$VDh~U^q;NghfvA81d3k>1q!m?&|x zshAvVrUbxoZ9)fQa^IeSxOO^gS1Q}VJ?zyt8JM|II0x!-jyAh8nDwp2M=augNWLok z`nM`Ekw#MhfT8cK#sFF+h3(+pI^|6nFkVCHP>2;9Tu>UzZd#Pu+8ALY5V0FBqoj%S z07w#~b48&c1T5a9pDt5n2#hNr$xX811_30-n0Ox8hQN9PbR)UJaJX&&fUgX!XMSb-H#0>#6|bR$3Jk41-qkV zw)hi|{13*LqR;0f6BK3z4wUxbE0V5bVb`QAD15&*dhx3NNM&riU(UU}ce7d;DwIxh z-Gizo1;oZ@HJWiLw0}GZN*iZAKKOL6TU)o^bWp~XgxjY(pku@LJ4BGe!tD;I>&0!G zO%;!~{N+|zV$`7zANQ8|IlfNE)o_nLM!$P|G!%6WmH@F-_rR&q8m^gwqM(PcI=ZG)Jz%e?aAE$o}t*$#}WLJOXRUm zqwQOnl{mf6xrduzJW6etE51=_JBSv%wCcs07*aN&Nh6EpW`ZY$qSolWn^6~97^F#gdDnr_zz%xWX7P#XOsnNnrxr4^*=mGV6XTVbRCVvtQCnk_6?3J} zx>EKllilY)vDAE%O_HtgBvcZnY43TwlV{RN6n#BQH$IJrAi!go$?SJ(YdywxBUktB ze#3;|ow4)Cp*CLB>#1ZLjOnz%{DTDU!DC5bpcG#D^?^;$TP{MO(7 z{Js^gg$VH!g%CO6I3%)ia+Cp0d->1bN&rtsCn83NDV+D z1q?S}FB(3B(C?6kP0lvvB>qeruDP8t-tWk|f3P^8#8ba*-^7WDSSq3hRqVUipL*zy zf7QUYX&{uk>^^n$dv2^LB#0b25C{oCl{GSO>#aQ`fB_{g9!WmA=}b#fz3ZuBqDriG zr6E7uLSb)pdm21*Ok(4U2HqtN8hlvwjV0OryQ{dl#(74OfZZZ$PQS)OUf1VK9$eY8 z<`}y(bx@0}h)MJeSa&C4D#ZGm1&tpN72CQ-OX>Wd$cAJ2yLbS)E}=-&Mcn|Mvn7#q z;FIkchH5(5z4wr~#HgcHphGi(me2Uiv6mcNtirMwr+gYoO=Rv?A=YyZh#i(XOt6U% ziP%yxk8%bRi5Q%ETLQEfD{392MyUYoJeg@9P_zeuDKmFML}9ea_5lG8+Vsla0YOV` z1)zhvM2mz7B-#e{XhVX8IAJmIoV2s~Hu)UCLoGNLLbUdwfXu-4-GW@mdW1X8rbl%q z?8fhO1)`NR?7$B0Z1IbHR<4J54{f!kz{GyXhE!nNd%S)~7b&&bhS<9}-PgC>6baf> zs!3Qs%qktDK<)b%0JOashiuel&9e<#oswFyB2C1Nk}1ntH)Y;ddCC*BH=J$;e3K5_ z?3`QbN~&4lDB(Q(FB)Hgfv& z4~P)LG&Hj%H66E}wQaG1Cr)Xd;T|W15ZZKzA%H8gyT&9(){`{nb%Ify*>SqpxJQa1tDCHc{{Tmhv#tb8=VLe+M zv7qK#i6C$5Jnu}=KhC^we7|k4f}rLv35mN|%SEwJ$HIU{nNba55ZZaVhb0bxgB0j!xvGL!NuZOvo&mTpclA_1)5>?@765lD<-A3+{2mgPWtzx5cI2{$6nhGPuXV zGXGnw|9mGQn3Isv$(qS@Pm-tEwysshh|ciwy!k{w@pG|cs?{ej%Jd@LE((acMqJ{3 zrehS#MIun|n8Ah!zeWH=sdXBD?#3Y^887_GDv84U;a^4YMBOc{lt<|t-tUQ1GWFr=V zSj<*MWv3@y4Uvt-32LAiH0y~s1~l!-!t6o;R+L4J04*y<{bu5dJ{VQms^w(c18dH1 zaWrZep8AA)`WWKr|1SYphUeN9l{}1P+eQeQQz!a#cs@DN2p9|__UJU&-STnAr%?tS z_lN~ABAq7oZlDf273uJilAnPA&X*RUC$3&B6Qu_vNuq)Az=6)9_A%Fj{u37giTg#m zkkcfHnVgk-S7awP3D}(R9oShH>~%rP%gM}{2$9Gb2IMo1Qnr zs=VHrv?ezF&nElHV+AIdot7b*@?mtrnZSN0daMtUAqa7>Y+Lu$F9U(%VZ&3+A7;`0 z|AT`MOSsBkAcFjyKZwsg=hf7}_J^6)NHu>nU_%i0Y$KC{?iPm1gU0fa&t#I{J_P%l zDf;tYaDJr6+F`F_=h(uiEaG7;c&ybQIt<8B7PnKL_B7d51L?8mif9plU-EYPfxyJ3oYj9j4jJ{T-)Kz1_n7|E) zd`@-1vJH;2J#OfYCq3%E5*#soU(C)*pDOwszhkboG1T_R4z>#q*!>~|+{+N&sy}&@ z6u()}{`t{%izTBB^COuXX%#?E+U+QE4xuC8fENY#)FwouM*!E=9{Nc(7%LxfUlV+^ zSg+ez2RTop?%*H_Cez?p&s%$%Y?sFG~Q3MUMw8b2nk;3J(%FP3#SY52G<1)07(9=BpjlYhFHc-a*R zhZj-Vp9^5@<)zh5^k6q^5RH#`-?5t2L8@#LL%a%TSb{T300NzhR(DZ{A8(YOIG;iz z8&$rE;~GqXnzGIAj?TGI#wTyJif9y{#E<6|kna6aztZfZ^9m$%2lQL*sds*#g?=i~ z)lL4jyAi?8>ecP5^$)WXuag|#rk}ov2>;L>ci{(EttVF)nEoX?_7T6}qgu_XH*0|e za`6Aq?IvA4A<-1Z)GIKz9!6j4CsPD{lVh?>WSWQpCZRl!#7cI!dcu^$?pca2*~K8$ zaP-3m*v}X)ct$<|gzbGTDP~zr1S~EyM?4nD&S#14#LE6OCYcl3NUN%V^aBAekY!oY zjZ6$4kP8%EaOP-QWL?=?h#S)IOVC_{(q#-iWtU{B*dbm2gMlyILxvZ zQhGnvE+}~lLzq4QZcYlw&b}({W-EA*Oq$@&4yW8UaUo55i6h^Qz2CeX;wVW;L@~5# ze)u-jA$Xzw((F0IJPR>~tojkok~wzfQa1dqP!-TLqL^BY{1WZ-JMS~=`~vWA-U?{< z6nYTCD28CyZ-71KM+~s;3e400gYZRWll;zGsmW{N1u`_Da_!veD1a>G9eX?FeEufz zAKVJuUC3|#XM7_kCnO#^{ZK#R$yi zy*JL~N=PoX))r&N%s8UzIp6q-3DfybPZTp&Eh|E1yOnd!%|lrf3JjHEXVW@jAr*z0 zV7a^{0zBIEEl$`}Dl*+v-bNF|{v3)zrUKV860Zxv0*gO7k7ENdan zlWOTKm=LKn9(8{#q`Y@bp3wQAps4X;YNS+ggE7Y;>t(u~+308Vk7lJ9W|NtWvzWE+ zTIkG-e;T;?JmpXcLp`xBhtWn_A3DbJF^VcofA@(px58H+EMwC(V^6?Ygjg$YnyrKP zyH(}5scEULZFWu9EIhCE8S^P9RjRtYyfC3WO{U3^xsoQ!uVxBJ)Hu(%D&sETS6woL z%X1jNX)ImG`4@bv^Sr+krvTBY#2OXL((xNOZ^Qb&>h6G~;#tjsAg{U~&4Aq52@%jm zBD}|K=fb(H+5uLo`KqrW_F6B_LkLZ{MQcL{V#lO;1O z6Zi7c{B6E`|9}JSW-w^fwsUgW*pO3cwR*_yEgR;5Qk{<7>}Tg}z=2T7ES*z)XP{s^ z6}vj(s5S;et`|b2^Dp5B;VR`UBGZ5Jb>d<~8Stz@^{qndid6&jmHH0XBiE@iJu6QV zp)K@Eu{FnT>(e%~@w{T)S8n`IZUU4aifb-x$%G!s{Z^+PUmS=5Q+ai&$0Bp)A&|B| z3M+4a3$a5pljAcS&@icAfh3yxdaWm?nUDd$=^ksV4V9hal&CkO!T2W{yJ$)|$ME%C z1XUaZ9J6c#Eg4Y{Aylk|8#>7BDc%Tz#DiKVyoPyEzqUD@C`!n2 z$VNb&I!y-#iMK=&bgyk<=AzgGOZ>!)FX-neG3S_^I~B-AFdG-^Mze}|&}tWN*!LY+ zJ^ZZJm17cj(vfkDE}V!ewbp7ocz}2>EQFIF$*H4RVr*V^HS91atm&9IzMT3b5mu%l z=xST;h+ap2X3?g`=1qn0G-)7X*`0lYIw$kGJo6;t?3K!$pLpwr6g8JTjVVyq=7lv( z2SPXmLyW5%n0BMm?Lqx4Lb8^LS33(vKQ`;n1BJ}Hc067$brnzJn1;yMK|O^X(PuWb z_IsHRc}EP#jj~!FgLf1Atza5;)k{PGu^5-~FshzKQn@Qn8~}4bjK3Ix5bs)hy;F&f zjI_wWs-hw_Pgv&%c?FB)38*tCADg`3%ZHrIOGLhMB@q;6d6|)z>0#6*R&_EOtE42C zd2%XEc3Pb8rz;WIR14oW*y6KKdpxFvY9tU14p=Q5Z}41HiZ54CL&5M zo5Bph9T?do9YOjaMDl6r+ip>WwUdhK$~LugAB4l$C+B@>Oz@G9UaaTeALl|?d$ zR@g&DU4}4xasK;1P^YxkK>W9fEGqzh3%=F_uQXBi<#mJp&I~wQ9k&7P2NrJ&NvWJv%78H(PdwLAuSao+J_PN~8sFN+%=wT-&sGgv%Rnlr zD@#1xx*F@yi?wC}W#^)9so1oM`E(Rg$lN*(1B!AF&b%zE+FfR@^Pj!yQC=MG1iV@=Gq>11RigKc)|7<1I?;tcCEMeua~a_DBR>16Nc!(ae02csV8d@uwiJ3 z8-SIE)(aq?fXms&AI&MvB){wjgeJ6zun}lX!)C(}z|zZl4lZXm{_U*b?f;kodrJM9 zp(t9XWug^UX`VMJX{m5*HA^3jJC16zNA;!5Yy zGNZP(T6(2MUm+%Ti`vfg5|gxgS;}w!`CnH`g}(PXwajIX9f&%pulCuMTY;R7^P2E8 zlRIjKZ*ZE$>!2Bq?#6TJM=h+s+W$O`_a7e@w+>!xcL96$BuKBmN!UsJ5+YTiONK8= z>Xf!Ss8;r?WPGYrHQyjwb0THxI)*Lk5nsaI#c#4?>cpgNdOv2yVjvoHIp$k{mvjlv zu+{(vc+z?%b#nZ}yii_wsH~J21$qdg=KOIe4(Qf5B?pV&)lFu45wBuSF?1Mrp7N*!|RiK(NJ`Hx@(I2&Desn zPH=p0+X#gRliY(Njl1{zk&(??sAW`~7QTSTD-i9>)J{E-0Xka0Em{xt!Z~@JRQZmu zg?Gd*^TGVMi7o*lyKSB!sJq0uWiV7x0N#~4XxmJ;X{&QEjeztBQKeU#Ob43qvhS+c zL$?JSaaS!sU3UEQIQ!!7ZfFQ2aZWWcaH&)U3zwUg+B%ZJNH~1!r8VsPDUH#N+j|W% zhC>KzXMDQINvaWOB-InR`zX+%)A-La0EpTIZoXAlaP$}|-c*)RI$F0f`$VR0z6BDC zf;W$Ma*9qmTC+EsmO@`L&0?Dvd{d}k-nJVvVQc1qtJ#~ox+Tr)dN=HBzx#htj(3+@ zDiv}tWVI6vw$tf0h}G3^8bH0G=>j%+wmrl6MKBLD6`Tqc2=@l4?jfA0ta7|z1{;I7 zVuo@kG)+#C@;#k=+wTe@b}dOR{D#@luhdPMFwT>QF^fPvVVmp0>Y?$uONb4N!9n)@ zpJXw*Jh?#UjE;I#*F!YCCK}NuQ-v)qmo#h%M=v0wo764;`<02Jzg|`G90Vz{F97-$ zl=ZBEA7Dm|73BXWrfxY!PGLf29*>WL-@e0}QA`{Xh)vvb^l-9hXA2eAf;C+yalldI z926BM#@N`+LnF5)4N#%Djy3_%-QgKeyREMLFmc`sov-e6?H)`NOfx^{_c&|d%j#+8 zBH?OJ@`L~oc6PbknRg3O7wmTD(XG+-Ftq;2uxo{@Wb8u>c*@+7&fJ+KDzv^b=2kjl zzm$k^OgORHvx!2R<#JbryX~n_k!3xxM}<@fR};w-X(0fcSz*}w2{hbWo(V)e+wJJ) ze>XM%^E7no&!@Ux9kRP%QHNG{_%K;>Cb)m}9{uHX==5LCa;HaryWPxd1PfP$Or@{V zkSe(dSTv-#xMC!(PNrnA11-(z5%XIGFNB4Kx6UM<+bn1{)_wa@ELMWc;am-TX>l`vXs@h z`k{yFh5=#}4v~vdi#ri|Kin$=F(r$P_(J|Y_3K{vs3Y`cIH=Ub*c0=UPYz4#9s40H zo0dQu9DmeF_{}gglV&?8ys<{aiEoCYM8d$1s?%1MWs%BBrn9Zgw8OO+VYuz-&|c{u zG}zX`p2=TvP4DndQqA&Gr9|GZm73ux=w{i)l3RW-MU0id;HNQj)jV?wy8g;pcYhjrlNl3Rx!wm*SXp_Weq#>=g-<9}es>4N6`Q01tz%gq#Md&$IxASx9&?gR%x|y^ z*3fz)ZjxlWf3Vglr5AwO_Kdp2M@A&8#qtC67M|LRsB~XN@a!B9BUEz56hl)EG|za!fJ$1i>R&I5x=(W z-+U)ulqcs;z7E;|wVInCLdOyNd~a($#`0W&iU?Nf#-1B%^#*0}5hQAVW=f-r{lDIi zcJlRE{>?+g>#=RE&WsMQ92&_@wr(&$dVuc8O7`Ew`o~Al4&Q&4my=3Mx@9w?@)xKL z&vp+`gW(DGP^+c|Cg)o$GA zJHUFCuXGq3dmK;s@N+yL<)1W+TBXEY>w-QI~K!z?6g2 z=Qq@bJm#Ge@v0kv5#Vf4+!-y#!;>$_U!6Uo-;1ft0m2_A0IVFjx2BlV7 z(kl$*WYf;;%FT*`2S6^|UIciItx&0-vSazR&DmKaDhJ}8cQMyue7K7~!(&wsI|!?F zw5lKe8Qv<9RvjxED+?YvdEyf>I6s+DtxqyD?VI@rG$qu;fT(<0YwCreM~N03a5p9- z_^dZPMF}+vO_LH4*hWAAr%0_&%+27~-)<;Qo&Fj7aacoF*hUQyJe zha9f<=bTGt$}#*6UHv`e<*x)dgVPmAydU9Ot)4?fXE>`kWOv>u77<0+b!#cI zo@|>gdyK8)MtY+PRX|C_%H@zf_B-T?qm`*h#VV4P0seWVgR{9qZn;qIkAEMfT3zOK z(n)Ub>()Q}6!n<))NlU8$L?Dg##(=J&JThBKMv#JT9~J7+a{{%&E&Q1_fgy*^M~y% zCFUFvKKt1E%H2&l@4==fJ8LN+c=_wriloyik6%SICRx3wW4mO5k*EfZk4IMgH-#y5 zqug;)rEEs8YGKZ79@M~eZmbL3brQwdZGvaOH24rhij0OAxTo(~(h1su=4FLDm6VH7 z6A4JRDG9~g$gVxq4 zf?fnDMcCW8m<6%)ZHGvcoxb@2^h%Jsd83i18l*2~q$d6g610L@U7La#c(Y0xtJQ%Z z56)H@P2;;CC}i8wQ9WLr-N4mA+GV8wvJSz@q?}1PTV6!Al$l8?Or(;>^w!6Zw2Tg2 zDa1zN^Yhx=ZQ<$rlzQgWZ+lu#o3xvI++(O(>Z`y!6iKFT(yhwyc||>61c6VfS)EHi zeArx)E;g{oljo??FX{Og*+i+4FKHR z-P0V5pfl{aervooViQ|%yw!Z~GFUdu%qwkPUVqoTyt4Iz#G+r@EE5N_of^omt2jx4C+XSD#`Dy zvTKt1RgwDyU+}55chn%z>Sd{x8X%lB15SRkn=q$xQ=~zG!f;xs4t4e+ma6N@0b=gTsOpY!f@llF-Da<+O(R##g* z>F+zq4%xi?OcIEypXweJ`{|$o&vzfh9Yn(`o+-XDKzy=}$W4tEMjj62ElJ|nRW3go zXY`HC(_3lbS|XhB_3j!VZG%CW{*j~Q0o=)ZG$=x=oHvRf{?iabo_AIgqL2D#+881I z6$k2FUVrqbWg^!i53vmI^pl9fJN)cRMERiIjQshfH!e$G9VUk)-c}Lh0nC@|C+Pi< zes@oHW1LS^b0Gv%5o{66)I>yp5+xX^WSwBD#hs|_!xl@ zuwbvaR6fEaUS_x7N(sTh#J5S| z6=3ie)3NV16}p87zq7aFh$S{kyvYJb9Ck5DGRWK!?dqd6X26n5_6VEXS%7&#gf?9D z;OEY2n8k;_mn*Zr17=d3DDR~ET`gSWtMkYq z7H^7gwAMODq`$y5`PdelG4k)}l0)IffutVb2``HaYElIK(nsf;cvX(3GPdRpnoF+# z?(QUqU=2u;@LVCo!IM+|C7Q~}AUWl#mEeZHOFR(rdwD}|bZIyu{_8Iy`?;3g6(&d%2T zKP?bN6pcOh4mKp9;ONSk(dcJ}Z#?%oaaCj&KCq3mo#2E^^&5IwSeGrF<>F$uOAFt! zCnkY7h&C+mtL8Q)+I6v9yshf2tU1#h-j?J%W0L~j@Sc*rn1yV6i@CZ@n8cawjyu<= zWZ{Y0603^v1jIC7YHjr*#%xmsJjIoMXwYAGis;2uuzZK!-9YHVZRb64;-v|KCQIJD zniaGu?AudV6Ik*z#tz z_rAiEg;3-{?*~A*5VWcpr@--D)RX(bw;NG*=iv4KNy$SUxJmKXf(fa3qD(lMdz@@z z8|1}sz~UMe=k_{Pj)M)Gq4m=gsB?UaC}%?8jdfXbPk$>2U8bw?x1OxI7Wf;_II#S+ z|4i@pr#pKYVHSiwH-{Xeg=W^J&LaVUi&xtqLY_Oce-cDiH>>2&qg52n*T zfBh!s$LsZT;B~*&dnXUk)SXNS3E|Jb2ysEoc6rJ9^$LBAb)r}c>Jj_n)kl4RZEJuU z9WjGW+p~J9UR=(u_3r5S=ycLdLpR991<9JD&8?El!KSWAQT9?c7GJ&y;tu+9QC;J&Uz*Z%bFKMPb8#IgD%X7 z)w4k@HPbG0fe8>No|!LK6fQi6Z5f}jcX!NM`^X8KE|Ebp$uTUXf!dmqi79)CF!#j2 zwF+;JORc)UpPHma@)(Ze+i}YaRoz};rkCZ`YdLSNontBeYe)eC25XYFM>%_8Ptg}SNve28G6-nUT&gY#yGD;3+Y%@B!Br~=<|I{g4A+WiN9 zmDi;bK|O@>UYS4d^J^5ZSBa4O>qzdm|7!gJ)GBY@PlLquotQSVCDVs#9EUuV6pT*$ zo@=DJOik4y)3kT7UuU?n{S(eyN#eW>I`uKglg2&6qn|AM-KmPtm)PZg++kuuKp3)( zF;Z$rU&QRV)4UTfC>6lk_Tq6`57j&eqeg+TDM^ObC%bU-_#rE@9u)cFuz7Z++Zgt? zvra)rvsq%wT|6iHjl@nM2r2kswj%@mUAh=*p?{Jf$P$Ao1k*RDfEiFV$(&4OHG{%*l?-J;(q(YA&0O^u&>RKCE9`70 zqsF|&(Nn?@rs65f4OhQ&c``hdYHepuDaKCe7Vq7}A;%nEF6AqCOyN}b{KSP?ySQ;m zP^h^vp{wo#E_&@8Prfi3j|MXB$v#S(*!Y?;UYAOfk*c#TSvt-JNecy~r;vazfURSw zLLR+`Gah&@Vha^N!DP!ehj;8~akYK1X9uQX#dw7g`Xbz7TfR@c!v?aZ#_n z;*~BrXMtNk?(6>z{?}py>0l7*YUc}fNt!hW9BF20Ldv1Hf`DDv-r;)j=?EEi*d+H^ z{(rRt$OrR`GP$Z?`~Oim8zRiEcd35u)HzL^q=!;9dMuzw6KU`93hgZ|NFoFD|0A{j zOnXy0W}r5nD5&tFsG?0~!{bN`2Xo6=PKPE;jk!V3Y@v*dyZ*lq7 z7eo`fNQ<2Hd-15{{IC|H4QCupe~A$|sny>cbaC4KU%$G2F`l{Xd$;Eh)$(~iBlD9X zp!m`IX@F4Gre_eKOx`c3%z}+k;1}f3qc7fOUWhC8*(Wk52Fa#;w^G7@6M2Ti%657i zyfb+_GZQ8>Gb3>!r7WfMfQ53P@YZY=Iz!X}ATI|hMqf<)6bDN8e^%Ln$gHn}eu|h6%2NP= zG@SLo^l`>m><2*)svcxyt0I{W=ZyAz5$OS?#B#1TYTzN4xhb3r6{UXYD@nv_$JLTxPLnDRY=`}=ij6r+$|Ki4@F0D4(VYBkZnBKJnfo{n< z7PCi=%({rhE*Afx`TGPAw3q^55fTp+wKJLU2N}M}_sQ=e8&l?~B0G~065$FD|DKaK zK@Ev&c&=?YjoZUF1LlNzsBYp*v4sMaA-N>Y$I<|f5-ChGmB1C{bIKWACs3G?kLYjE6w{MZ=Eq431xPlS96~P4H z`)Qq4x8X}yB>H^nLh=Dj?Z($xoaM@$CHu>6DWJn>p=g&c^rq`q{z#uG693&pKa)|B=%gEmv`0Eeh>8 z_h)LQ_k~pf^5e|VvtfrmY97V^b4y^|l@ethF}QKpyz1>aULXKR!kF? zz!GmtJoS@6jl{d;y%QnFO}%SAbux4=4uQv-aU>Z+Pkwzr5r56m0jBqJ z^3P&Xr>gI=-D_X@cg2dq(R#p8hr*opdk*p3(YcsAM?-bm?>WlSqOs9!o|5}tL@4>R z9y!wAufh-ZEr(hi8P%+>%(Tn(qA@WKfyy;~l-{RDGdnQTg=YsN)w%-dk{>A)Nbl{A zU)WsDSqE}$6}Drhwj0`Q+pN0$gytH8RKgVD3jPXzK{x|VDri*Hem}w`NZz6x>N0Z# zT-^eWBxg)dTr10~7Fwo!*pLlShu!afFc}@6G6;l^%WFPyVKGAQb|@j0B$;HdJU74^ zI#Sq>_90i2M(H;oX*9^Y;P*^?Wt1Ep=Uj-hiu)oE9;2)~nI%yv>=pU1P?(#>)K*qy z7@S*|543`nAm5nZulDqU>0~l|^8Y80$a`VPNgWYGw;1}KCOTku6bw_0nKyDRGw1Zb zSIJCVnk89Q1ls&Ty00uUqTWXf8S-z)Y%;W`&MfNYSJ}%(xfDsHxFrN*&V`b>AZS$K zET-9wvilBRLaY!cL=X_JrqD3%i#(U-!u{~r7;}+HQ^`#p4DZ)0rLSmIkk{TKi^0T% zdd?s=jZzRoZQzc926G;n0y&B7S*sA0I<1f5$t9cpZqg{rW+{U+O_Ro>&e`tP$K227 zt0NkfTgI%9rR2v9v>^R?Z|EGhuV$;O3yy(8+yEjxAKYw6?J1S5b4K;_E+L-C8pNL3 zZyjF<)}!op+A^T*>Jf>N@uEL+2M&9a6vFW(U6BC|V_0ak9wyH&5Tb`u4>%lKEBhi0arEK!ki3l=W>% za3lWJ{{kA?Q)Rs`@95~^k3|ZiBbi0?YBob+LzSd!{vtV?Z9yOQCH^0-Lu|5BqU>$i zqIZC3u|zvY9mC1{@sgCu~!_KoOKPiahvjRPR4uJB) z*E$^Ho5(H#nitifG$^8i(f1UAx@@96&vhAo zvdvXmT{ya`karU3Y0V_m4Qvr!mvjvfoSN!pt<=;EaX8vN>LC2y1_AA8$H76bm?aK? zmC-Sg8S&K|m4LF~M!PJKC#YsehAE#x&-1I^*G0C48;Ikix~^t&iZSKnAqdvYpqYqK zLW(LR43gJ_DGw<$P_vH_n2lKEKPikr$|LAqg-q)Zi-=xp(lojmBA75X7a^>so{cHS zSwaBF(V@bz(>ZQPK+OKG;pXSjT1EUOoGYj zcn{cnX`z;2z86bYoD%8Kf=2U(^qY-3kICTXc42MwInrg>XCf+DR^?7ZMw9?LID|Y7 zF?tX!sN^KN0vfe^Iv|Kx5znVbMG!=J7Ou{b^D!Rb1G3Rd46_GjZ<5k(#a$g<S~zqex^JCV8No<M2+(R%yFA#bBMsb+@=BSlYL^fk)^Xad=korjU#KHf?iG;xLTU zF=d;RBy2{G9=u~@3(uczs;hIyWqDcV-XZYSayAL&d{;~`UwA}Ao`fhR zlydI-Y@Q>Uc6JncOewQ+LAlQ`e^kgpNTu0?K7`yDFUDOqE1{0 z*%haiRE`R}l-61~&7`wZ*{;s7RpE%-SrVYXT8oQwe_rf}2+87Q%7m=+8LaeE6}i9q zO+KH6AsslNSd}M>W*_>Wo*fPZDMF8luppwph@Bpowk^0}d#aztC4_lSKy71mZQMY= z>0Hj{d>xsXk&eQde`C=hW#YUuKDaen85>~|BEkvO8m&!NXBN?i;Dgf|Gj`)XHtmBD zfL0qqN>t)(#2JZm-}zbzA$3e4_R@Eh&n=O>V#u#alNza|P$oXw=3XWYBM}zVy666+ z&1PNcK~a=gH(|a-aALZ9C54d6lP&QpYssrVvU}z#6rw7gv3U%IkrkM-yJ{vh1K$K0 zp70_8OiY86cLX{*YFVGLyM{)zR_#bd`J<3qmjLIB3g?;0s>l_eq{&r$mStXyw{n_f zS0KQ}jC1N?!(NPL5L(1+Rs8Gu9-O&O|EkyPUG?3W$8jFC>O2>GGJeM=K&`C)E!Li3 zRfJoQS{yL%l?%5l)#$Wd1UT|+uj;RL%&nN+$LQ_Itzw-;A+^>$jR^`jsNpJ@*ZG9K zaVaDX`)`d>#gkjbk=_%P&r1;VJa-_9xn`<2+8p@!G_)Xl1AjSMUEJ+7Uzte6!S#yZ zc}$2!E{oM^h2$0q8JZnZvsSQd!CEgrUG%Qn{2{xnQuA`!qjL_8MI+}rzF6`8xQp+a zp`xKOx9-MnL0gRR+GuZUgZ5TRD_vbfia8j7G(R6iJWhMXuj$|(Ct9Mt^oKh(&!8#w z-pWKIIux;FsD`;Q50{uScd7FkjLjiZoJ_@PRm|IO;F_ZQI<)Tv+J=ef;eZ~*#zkB| zh}I^~NTP9)f~FY>;DDj2;%fF_v5?Pp)Z+)VSB@Z;mUB+BSqW*#OMJMI-O!7q0%6Pw z`75`KS1-tDnclLwO%rnn4_^60B(s;Smp@r$M5kH&QdXxYb8<#Mi_Y#bUkk~UcUx)J zvKdB7kGE(ErQU=jTcSdlUm3{+oH(xh(I@m!g3V@G$NsTnLg30?1J`0rK;s1tUlB_k-zB=%9a8TISgju!Y=IL%tGTP zEI8Escqi~Z5`JLQjn3=b_S5Fhg5fH}WaFZ-rw%>@Bp60?qLnE^J&FWs?#1T;-v(4c z!0LYLBkLf^pY4$2klBb)ixC=33n@607H()wN>5erv>}|P5Nu9J(^%Xv76;+b$^PDacf_H^MGz*K=(WXtYhI7W4 z4s|hEfJcdG!yK__jp6a3qE6rZW`iA`T*mgmd%~mLXm@V}*`}Ci{&`NbhQ0b$K027o&^) z=^@NG%2h0!k(1G*ISiqXLI}vXEH@oVYbg}=fjkOs28ohIEiXc5X6LEE^4hRuEvE3D zW7=pD2pFVtBv}KcFP^F)1ainI=0e(;x16*u1E`@61;D7a z*8v6_EM#dy;q@_&#YCXCC_R}aX(o>&SO=U&WU^OOC8iA(G1_QBxPycCDz#_M|Xy6K1j z6(+2qknl7Bn+fXNZ$JlILuy@x^`1h^dB!M}UaM(~n*R@w269Q)cd}H?BtcW0d&aQR z?Fxa;N)j{WL9Z|cUU#NQNdX48_GF#(6z}Y!S;T=xh!&QTnmo^v7Gz-Gb0x)zoUl2Nqg(W)GQc1};r?in(w;=m88^|Fm@=Td< zGE$r?Ly3!vn%ng6g+!wmH$VV$ePEvu&wYb8+@hkl+q*`+#kZuq2GUIAS>8j*ikX_` z?OVo2l_=kC8TZRLgjL!Gc@*H6mkxzyvF>>Am1swm)7y8jzjb%!gtg1HBhROq8=NM} z=yHbd{zYQ;fiRY0A|oO3U~Rai_l1c}LXJY&V$97tytPgE@Tr;iB2%g`ZE{jyqLJhl7M=pxI&gRnYJLg)Vib}l&);q` zju*i)_hrUVJC)w(bv?KGW{&-!A{npjG} zl%nVcVKLGS`O}O>o}qOwi(D4xLjijSj+dWvbE@FOYbX(t0Xh{B>1k* zI7;le>SK)>a0)u3+||4o*<8etFpVa$dY|yE&W(&UPU5gAGuIiM;^tUU`VQ7&xrsYS zUv{LMF!0y;Zknaion2rLXVNG+ElvI|gHD}|LRsqR4_++2J@zduM&f)mgEP8&U4xG#B>q`RcvKbpo*XszWcE-iW)x*AI~-Yw#w4>5XGM37569Mm7oXM8W*IQeOXpo*jab7i z%9#>?MMh@?6q2K}kY=n(^_*Q&OO%N^X=};jh#)873Q+NxMYf@d%`)o^nz!#hLdA?T z$Q1c2qL&eIUKTM$^wQX!PzgSX)Jaj}1Up68xzXe$(vl~-J8d}c25(XmQd~H?C__>W zyO2j85K=9A3Z?h3N=!jAwf6pd>f$5X?GCb1CnQ|a&s?hiq*t{RTXKxF=bY7X$IMHc>bRy0srvClU( zir)DWgW9_m+>HdY%UvLUjbWKvE*g)OI^cYyQTnALALcIxoa(-V(=#^Ue=&sq+6&&hEP zR8kw7^bS_`rQ4cW|9)D$|KroS*M9-DuseX;I(yKZZSlxP>O4L5u>=me7Yuu8o6;4ht7(r}$&6i>i9{x#A{NIXEK2s0!~MiAyPLR= z-3_~2$Rn=s6S@Zd(FkZy#n$>heSle891&4-^$3#pgQsHwuI zcd&mQ&j@xF!Lf~IbP#HF*(DTt`T@u5@Iys>h@JqQengm#mTD)gJS<9;90U^>!7AHf zTIFs&G>K090ZE^uTBLi&?zI?N3>HniLBnQ(V|+bEXW;Ea08hQ6_(W%&%2z3fQWiZ+ zT#FcjY(|frvY0vz7>XTJvS6AU)*w5MA|Y~(5mhJpu4V@PQq9s%DzC`^b@IbwwY427 zff8M3m7VeEGxU*6*HPmR<~j)Jbz`^W7?=RrOpuG+u-t{<B&io14i4K!7yJYE>y;5kbh# zSud!ERdPyF#ic}(SN9HHBL4k{Adn?Dcjx}YHX`zmS1I^sR~@z6?G6yw?DUJ25fe5$ z)j}$s4#6LjBu4x8wlcUqnt^7nNP5V6Mq#0N>n|0!>H;v^S1<1H2&6Z?gO&LuUsY8| z|N7z)KCffU<#M}gp!l-H^Jzi(D4l3#?>v-_eU!b#RZYe}s*@icLu=WQ5-iEOnCl=)4Uw@UL>Ysu5Cof8KpIOdzWX1DhY;Ho%nFAS%ZOtSQm9*Jf=5vj! z{_B&*VhnA9?o=xSPc&=oLrKgBsZoPQKe_cKuK)>Ui&yCL>cPKRhNS zUXcCGCJ+tV%`}TPVVYTc!a|7-Vnc3deO( z!$KV?Drp4PR6~#^LO_)lPgVh_^Nz=W&I9%*US(Ws89=#6t%az^e>yAc?Bk#$$8q2X zh)XHbMP8P9e0Q`9)yekGzFt3t&3ynxuUXQe=%!M?u4yMnE!$frG-ocUZ))so|1Onq zy@Ld<6?{Ig=fzybr=vJ;=CN>thRt(#FmQt>nPOzeonslmhasv8mEEgtqMFn_m*IQ} zH$%z`8uBlK@Vv}D6I7eh7HZv{wct`IHkPllxaM4{93I_cNY_w}C_;@l0~NV&F7%_c z+x!2$A(w66`cmZRZQa?K#)BJGgeEKcpQ%#J!C@aeY zrbKcaykaCv)k|?ZPL^(Jcq$dVu!k*oStdhfNFQ5$FkddBpmo1Y7eZVrR0TtI8Cv+v zVLcn$KZ_%G_|+f1|IRz_fA#&L8%6qFtrdqqqH_ZTrHTj3KJws67in z?i!BAtxqnpgF~8SU8NN~Vxzb~t-}f;>EPmCHvj;+n2+}-)3Nn*ppcZA8}-=t-g_Md zoX`OB#HgoPz>dlAi#F*xN7QrA5@bWng-`KW$iqbVPBkdsEq6H&0!4l{loncsMs#Te zuBmC}oir791~ES+#9G1HlO_MQSBIii;WeGm@T3sF|g zbH*hA#E_Uk2!HTiB_HVLsZO(wpcIP6j>Jw)4pq9Pi0I7^6GW5Y=UOucFuei_-L9l* z`czyNo$-KH*^GBe?0GB85JypTsQV|RrMDq^$45b_P$>qi=RD%9-2&JasBRlEsYYzV zuwU{hIIoB_94azAyP9cRg>^(;OpPD$;go&Mx$kzSivw~l#G0&Pxzf6jimMFiIy+|d z^;-?e9;9@nK$j=@TVnMAZ8QLB9Dt}Nv4s(*Oh(c&MBu)J6Tfdt#ixqwZ%g6~{{OMs zpClg~widw!pAsRO6f^X1Y!sPw#@+LoCKEAK#C=Lt*Z9LYDI!zZ;c52J`H;Ls0njNyEI1bd2D~pA7X^D|~=C=jNwMsq29Q_lbwlyQ z5uksr>)x2oqo?z937faGqLFfHh?{54vLHv;ZLzw!CO8WA%MkLO$*Qm!M~F_HErSkv$Ni&-j$h*D?45r5*O?VqkSgf*~_nhABj}RcgH~x|~l8QTn=`^4VmMY3o8zeF({(G>DkM}vGM}nH3FxnD1 z?yR~+hN$~J9oe%;kX4#Uml-0ac2LlT7G5K32&UjMW}Lm~ie_zzBPqGj_eJZUpkO*P z6}}`8RkavX5<%QV;lk2>K8Hvu^%x~25PfPZyAE;mGn1>Q?l0nCu+G)R%KjbYe%9RNw?)X#b9A@2WRm z3b19Wmh2Pqw)_^VqtT*%uDkmn*q4)9m|1Es)=J}MlQemmOQ4?6>LiKN^fY|HH74C) zG^-eBy_N!7-zXJzNOtfABbL3Jt}n>gcM*pb(9NCh5-uZ%Vcqh7GfG(ImG}G(6Z$d7 zm-*fn2wSaSNo6$Ni2F#0?#=4R_K_cln;&d#Nu8)gnTTE=8*Fi@mmU==3BWvt56F)5 z&~+g!ZF;qG#V5meumNFDAftNFWbZ5 zi>tG;DMnq4eKpc!RDd&F7fQYPp z&m!}ym+#e>Wc40&{&I&vErIhVfad>AUAsgGy9CPbb(a8Tv?(r7FVbg;^4kY;b|>yl z)@p||)@nI0)FYU`IX*#njFL7^VSr-9&xmW*c#t_{vttp4!oxXDuBoWaXfVGNIt7p) zr06Hg8E``2N2$2fa;kh9a^_A3>T?iQP%$}FkndfA>gueekz zP`VpulHo&k%2_y_n3ptM`Jd2J+6P!`0{^+bjblmP#qERRy1YrLhz&C}Jd3 zsuUI`<2zf_uFO}bMwMfPWUfLFX7+VQ8x@O)I8TA*S!HRjV)srrPLpCd~Tc5a%n?1%yK601)nd`8Q zJEO_0I1uQ0V93p}mcL%?@->@V#--$BICEG9e>+%YVbO_38}| z(|mINmoyBhE@P&@6QNx0gOGK%;NiKv1(p!~YlQ^~ZwLr__ghz%O%5eKt zIa-61N!Z7N*Nc%<3@m!Ni(#pbJ0A)t6zZMN##A|xF!a)-CxgPkhmm*g37`t@N27cb z86T@#z197yaxluG(i;ftNRWA1Z9Vl<_+*>%G;3T~rRn?HXVDuPDs$RmF5w~i>jjPS zF`guBWWF=kgGrC>$~5G-sLuD!kDhn!i0UPCP?n6dQG<-whvpg~UHvjLB0%SJ)e)v3 zEoW|ch>W)p+<<-RlK-c1@t2i0&I5Hmc%Or2jkZ@i(6|p>`o9xUNNua+kP#A6a%r=% zGVe?#L1)qDAtd@c>f}rl#>|WFa&C)Z!iKq&a++fn>;anMJCc!&rMXW9qgPr9P#*gq_9qr)qHb+PE_p^%@|ngJ>GP>LT%q*52SI zTc0*}qiQ$l!g1DTfG(T~XnSSn5+QmWl<%d0Oj+}bQq1JA?c5?lGN0#isFPDsDq@w6 zlyr2I73Ug2RxC5xL0gw4Nz?QIO^vM5%u?8Pz^+hz3fSM;8q70nE%1`k5P-w0;R47y z1U>orTS(k{Fa-mcvHcc{Lep0X(V0U9BN!x#$oyiG8tiX284l+_YZA~D7WAj^$f@mh zpI4l-Po~`8bC^qaNO~#@(N%gOo1ptlCk~#t4^!Vxvh?as5nCoxEKaeK*gvbGgqmGM z(i@(Wx~+xA8L{x>lR>P=0yPy4hUDYGt-Xls^!-z7ZOjmh0S2h6uDS*opoaklsH-KBwFLnzRbo!*}6&MNJ1)X`jqg?U(oyOjsguWP$uR90^qDczQ zny2QhwthczkXqu5$e98fRadmZv#5E9(~PM3-daJ>?7Lf~b$y87(q?F0bvS(Q+?@Ch zL4bLu7j3}vl8zoG?ppyUaR?!d!=b)x|Esx$2?$N5 zwZK9u5*f)!97j=SS|wJq(#ThIHIzXO0G(5Yk6RMLM-9Z0NwU#fdcDL4FH0wTj*H^fi3nU<6Wqgm5HS7pN3BjpnbFkYMNsl4!E~?pG zWBr8Z%ZJ=P_^1Cs$xi?D+yA_$ewi;Hoc@HAkTDB_o`Y}_mIUMdy#R`!L?39rtapcmOP1 z>ctS8r-hhenehuJUmv3;mk~(37aE<5g$Cuph8L)7X8DZjM)8$aiLjnOFJbE8~nEOV?%d%pOKQS4ZlvU?Bg9395(HGBQ1$CNDXfR=WPTVka zo0_Wmtln80tKG=?8#1#y1Wp=XP2glSk|=Bnw=l>!(y|h}Sy9I)ZZw>jS5uL0z`T~@ zBM6oDG_VZO;nJ7~!bux>DPrjxrSyebGVR1F<*=vhB{@-Y*m5Cnzewd>F;_aw+$zn8 zw(%n9u%h}J^LDi|w(Pye7LhsEPz*N|`V2370_A9W&~pMpSdLh&ny0iik?$J$i41w( z7UVKgenlB)IlqIfXcOR0Ejo#$&j=3lr2$nuQ<)3bri{pEoU64Nk?B!oJsyPgdJ(JZ zn;6ubcK`rC-Xl0J>Vkv6i+2#JRs0v!Tkb)ptxDLa*%*BPD~q`u{{Cn;s&ok?KtUHF8EJ4<~Se%6g| zWzBp3+`(tA)q0b#8dYe3HcqHbY>n|t&WjI&E_|lf^Y584j3d2#y!+-u^Eq#JQ8#m( zE1W{~On;r(QSU#0&T5qNi|w?pOTE+AUe~*aT`|X-PN#Ed0;p!15IJMq;$G=s91{iN zu5#pRdOLh(sc%O`KNSS+v!BEYT}Jt+UV7O@m;U3gf8Nwm<<*D|9UtCRMlYs+7>(rotR8@3-+!z!|!E20w>ON++vL8L9{5!#0AQ8KW z3!#mTQKf%$0#Kq4J(3uhAgELC<9+QutZi+bIp@5yqoM|lbQpGsWa`)cvI$6A94b+? zE6Z%S+A1q*$HO^t)sC|Q$7_xP^U-s;ZnusWX%i?$Z>qS(KR7_+N#2Vmw2qvS3LwtdW2VU+Yn$WRiIR1Wq^;HBd~9vZ(r+VfYg#CiibSemfw73w#FSSf*oANCVd3kVWhuBdC9}wiK zWlAgMLk`gSV3y(Kq6fFjlixbfG)w|uwM=Q6EX;`n$Up}o5&Z%JZUI3x8jRBf+31+R zLSW6O@v>4aPEc=2SN&eE)x!QjcX!oOz1BAJ$zGQ_?Y$d{#|B9WSGi=hrlwFz&-+&I z{Cr^lbhfI-2RLhkq`wL_hg&c#rcv>$X0925nu@J}I$6BK61)7X1gddXmWU;MMOky< zB|>CTwij#m%tX`Z2@B&J>2t(RbRXwsQ$$@f$$sC8Zunf6tHyHP6$>efNQxXHZsq7~ z9vQjY6sAQA4##3$(!5_1MpVm`CdkVj%7viOf-!Xm{{HpPDgRYoO%NX_Iaj)`tU=bb z6wf0-SrZ5s=)5eXv!Kub_iZgxnjqieki=CwEt7}I>jd~NYnjpn8IliqqR<1XH2>Dl z1OvoXSWEYDAcGxkCgukQBl|Tw>Ar<>^w*?8k}woMTMgXt_#O}YS>AKSC{QGvs~Yp? zq_$2q5CT@qlvc{Obacl3iW_v04_wSuU`CN}7? z-LLDKz=+sx;vDQJi~o?%bJm5tMdUH7XABtwB|h|rq~-jABo@0ijMydDe~~b@TBfv8 z9_i?w(~g$vzIM5=E%z36Rn_*g>q@8`4B^XB2d7+ey?;At;C5 z7_p?`Tv^k&6VuufUGl_pkP@2W>(d;Si9BZG#Xx|nCHoxMm>WNgtVBsMj~6rZl9a|f zL9Es6thP4PL)_JIjJif?Ez-)hsDLaQL8CYmK#E2i{8@UV?R%=xi@whYl@5@v#vdP$ z_UWFS@|d+18r}1ioqf+N_3k}ZeDR8l=+PB@WGD%eFF9q@ygEc+`ZSgSctylR)3A{T z$3n2P5v1+=#G*2WtpRgYIEoqMwMc{rR0m)-vdA9ORj^xtp!g`3#&ZM&7%KjL2c04m;AOZEN*e|09a|l(Xrny4f@(qq*@gYd{^Sl} zy2DiN5VhXMk{_CRArcnzzEss{ql{~>ZIsb!=OA{ESsZdu5Z20XDk^O+owU1n33-U< z2UcdGAM4<)D1!`wVwbbx%x*AO2Th}o>Vds47sA;Haz;EWXE?V33hG3>paO5|Eqv1K zQ3Vma*g=K6$#2lwqWU!xC7A+Y`<4NM^hPcDKfZ6Z#q-oIH*>&rywbroO%0xVjQTmu-<$OqFjYC`GmQ8C zJ-e^6cWds4gE$=w(p1#@*_?!>&iVI)c|M$+!HKc6?tY!PfQ$9X9xl>hc!TV@NX~gfvCG+K5_bQw#>w}0G zy3Iu3yM7Rf8Z&oNbeUO10d%dISo^qR-%So}DJ*r~sY&X*QRw?$eAP%RVpVGU z!K{vlxXha6KF3`;jf1_~-wp@-jheg) zxEWnXlSl&^z{pr@3`}!}D$0GxQB7$87mXADWoibbo7hyeO8}IG1gE zhy@#H{XN&R(;>kc4bP%Bhd4w;3j)cjAdV$B^}u&#k`Q$cq`R&~T;Iw(sO3Y=7o#h> zbg3(Zu+ctm_hmjw>+84>;VlH4KVsib?d>GBT zeyW$Z%UMC#^fbm}q41u?fpm?>RIk%HoM>fXReK;b&h4G?i`vmgE}U@*jl)g2x7@AjBgUpAs(?GI{!r7RZV9&#k>V`pnW}@x zm&`d4Fy@)Ak*bwml(W~}4O1r%>QQ$a1ST2!Uc<~JK1s{HRNvT{#hg8kmRZtR#vwS2 zqwcwMu||cOMLLokSrF|XbJqASZy2bbS}@_py_VY9lEhB#PR6S8CbSaz(1*!_+N#j>Td7^V?vj__B4G-xnA`-akI)Pu!9F z7DKW7 zoZkJ`Jz)bfd@m5#)kvEpxg!**rdR`CDm;iCow_AIQsXFAFdDs5+*PDFVJ4`ld-V{K z5Ht^d0CA-byB3fN+O72bB_sPLceF`Ni*Q78DWY1HG{R$G531RS+B{7^+5$VxC>Hs# z&{ENe8jZvfOfRH6+*KVC;60Yf5^({j%##@j80}2MH-+->%PW}^9ylNFJS~~N4=AD* zA7KY`&M(DKM<*PJs{{rXrWQupzhrFow>ye__cwpUt)vU{VqFnP_CY#OQO%d!_==id zX~EAKj0=+<`82R9{Wnhe?KV%$0!l%y^rMZT&_2jTQHWgXz0NaaSdpDhCHz%Q@J+fX)+@Nd6c)_m!bw;A z?RTZLoBW+5wV`Epn!nWLU2Opsl|AiX@CAt$r}iZqr`4>S^{({o5C2|5Pz;!)N+B^V z2Y-!rAfyx3b|C*8kIFgu!|QO8&3^kGe00vgo&2FB;!Acb%5p)mJM-}7H31ZoO(H-l zeH270~lbbc8s*j|_+H4c}1)g9Ld} zW%kqkO}pd(OYNCMl&z1tZH?g~vDsvOGr`GG9>eFhUMeFiF5Lp89h`|DQ}|v!7)DaS zH4PPna(3eFZ_ftViRW;!OB)!E4jmjp@cd8cZ=_U*dyR5YrHLv&%q*UdGw3JzlFG9$ zf&h`#7Gvhymq^e=ajqz1r0oFP(J1xfZJOg^nQA=oc-XNYv~_^WCmTvS>EGQd2z zz^9^N?rTM4xGF?NMPC)v$=E8xH_4(n;N_Zg%CjP=z8eoq1+Ad% zhi`JjX@7nhCrKW6cIl_k>VWl*Hm8M6em5CHNvYtm??Z9N-u2L40dJ~{dbk?=97nvm z=>H`mi^ZW3f8u=U04X`fz;1L#Yj4jfA`S=KZYKllAa?+rM}7|wln)ZM%O?Sl8*6BB3 zv!k}1X9@^aCmESItF-B{&bYNwi76#gk~l)UiEDEu9j*yC2}o@=3)k@6Glq~?|QYMPin=5UhF?min$hOK0TH}Ou5yw9tMSu;gT=8IWK^y#^OqTHc6ieZ5 zaT41qJU~yZZMN46)L6WN6({II=bO9EO%xJBT%yZMLm^`U6#{6UGEu{3Z<^Ey2lAXV z#(9hd3X1}%!Z=PIgVl-CJv*g*Jfk^Vn_(n(AkXv)H!~SB0X%I>Fc$B2N$54~2c%haop5z9rMq;Og>f za5(qbTP>|tN?XZRzX-Mp!>GuO-Cuhf#@h%pAG{)rCP5em-lX5Zx+HWpns9FlPS5)T z2kwOJi8~R7L))DZnKAVC;=iDO8vI;f$ z)l_DqJk~U^ipwvxQj;`)YBx3wU2)TAHMc@hFKrt9^u7CkU7wxan2`DSa}Rj@lpDKQ z@Pjp#kmwleeX*arZjpBs$!|dv&zsZMhv4z7-|n~{J_NvADJHJb*{%W7uYQbU@uD}G z{tk7nT4hlo_p8r7_0*R?d)d7hmJVE4`#PUqS|_t>tn*8^k;2B@$0at(<+WkuWKmt1 zoc?OM_@QOVSq{{!oT}>D>MFRI865nz|KDFAkIRh?X2nWaA)#Smp&=|uJS!Ly8%t-4 zm)O{aD2@qft2);?Hl%3Q^tu01ZO;Tvi6B45)kcuHOX?jvfRiABGBp$Q_W9nX&yTK6 zQ?CwNGp@Pd#O*j-PVlxmH!lzT04zTTaS+viRmM+Cy56sU7=O7o_B0{PDK&YN@Sn;U zZ0Sj@us%N_{GodKm%#rhWyWP~9N2Pn(#7bh1!!!I@nbeaTuXG!5;_J3uM^->=kD{J2Z`1m>gTd5+aO2x_rmt4# z^E4O#>)P4>c#Zw?zUv9^#4mKybU(VKS84fb2IE(&&z}VNj{$zOoEkA9pSzRbc$;|x zWX`s+g@+xhX-y!QZ!UD4)vSX&ThKO#QHd7&(-{kcESb`g@Jlz@%qYn%oGAqEM?Dq9 zz4JkfPoryV)IzScwM%?$l=^l>IGX^15NUl#tW9u_Al&7(#{lE8?o}_1j5EThpv5e@2pljX2f}35~5V( z?G2#D7!aVq%+zobL)h%*(j;Z)%^^)W(sM2vDX}*-UC~|lQg)j5HqAyFw0+y(Q-Rs*5Iw+dqQ*Ld=rc4$N5}i z`JK^bZi1~XYx}bj?bYfH03VoZo~>L-=dD<-Ms!LFHV6?j8K6%rzg0pHU0gX&27H$bncUA%3cCEBf#c(jrdpvPj-Jg^}WP@ z@I2&qH6v+J4u#og9^YIG?XWt6$r}7|4p;-P8d#x$0i3LAk#&>Hp64|xOde+H;Tasb zH7Oz?uHa$P=k2Rh?XXXs`d!iC}>p_H=d+VN)h{~mn6Yc@SkmvdpP{3INwVV~I< zNxAcX_@hW~oMVyG2VYgzyn>r8V8olxt5RfX)@3{%xzYJz31EJqe?O>k-N(hH>7d(Z zecdkPQ@w-N5C2r_lw-`&7ROBJD)fK#s)Wc7qe2GK(jw$W~$Q0o_I5 zVz#iC99EnLhzPnBBJhtE)aXm-2cR>X+jnw^&^DS;Q__T#lks%de;p4=%aU*(-DV@qt>270)a$H=Vy#cb{50V-}f#2+CJjxk2=$S zRX)uUDnsp-&<}{nL@vIUN-OC~>T@qp(WoN))a^x)?V8rdO#E1mHpZ=S!GG3EOz@`P zk$ahhvuG#b*cZOEQi}7PUT#poe0K{ybFCqXiWap=Vvxqw=IGc}A?<@et?s)F4f{j) z=t}35e1$t4g?1QWqIaRn*v=sjP~~v)xwRKyp)}j-E66bM2O@QEube=&V-x`2bUS*JG4QH37MvsaQ09H#h8NEFhFcqC73F-&TW;M<(Cy&n#&mK=o zKhwUmi!a{v`OQJP+*bo(LuTLaFAKn6z#n6Z=odfg@3@lmj_NqS<5~akjt|@Xh;jl_ zx}<PJn(XM_NJ^`%2od+7 zmznjkX31o$(!@g{@OfT)IHRS0$KHyHhBW6vN7VG2cY!08o?_beyl*sARy&*zVsC1u zk{c}t74{H_ay%S-6205>Ry2DBV#$VL=dZdg_h=fbVS6a3J;)w@Y5IqG@UARzC5sKQ z9#1w&8%J+-B5}lH&}`KoR|mMYV#QImT=G`N@(~#D@zHp8tq0NDRP#nAIZETOm+2l;ZQGF7DB#IRvZaPLzNtlk?hoknYY z&^}}Y!6xB5$si?#^%3oO1}LczwVwT0paH2(UTu}UM)G2nL6}rEi(L|2bbmmDlf3)Hvw;+ceSy>Id~Ar zOVq7$D#XOo@SoeC`*SxN3qJ~|6Sw+i8e~i>3e8Pk3Hh!Y?EyD#b7KXVyiffQiw8h%NgT{d{dF9 zYsI+^nPh2-L_b-CaphUOkGy4k^aXmlY&&77*o_ek^1D$0WSui~Uqplul2u*dIqOP^Ei0qcEzudR?dmKu&`AkT zS|3k&t{+8|Uc}Qd%NI+feyZrb%QGN%#OASCJUjKB_2Km^?^AGo<{X5SH->ITYt~Or zM%cOX^@;Si^(M8PHq9um=E%KQ`Z}41;o~r-y_>K`1ZZtfk9gviIKthBAfU8=+jVlj zGNkt%q)8n+e~K_!ckS4`1|}&);YOy)c9EpaWb=4v!^BP=Jv7$Q4$91(ChAPgY8LL? z#ux}SJ=du=ujX-&c0@T;226=R=2kjAbUFPe5K=!px5823TsK7$+@7T(O3Efo&&T2%NePv_&B;OFFyD+6^UF-h>L4Gbp`)IoOHlz?4l#Rs}O`>FsaPDm%(~{l~ z#v~aoZSvJVt+=o6B>;UT3(m}fPqchZInqe7PQY^oE$Ij(vWH0#@&D2@qHo|boJncj z-%}PcN>d*N$LZ(|#bGo>BA-b~e{c}88S+Bm2y?(Dyj=Z=um^!WP#2f3S8euON)Eg@ z88!1=3e+1oJ=D*1VLb6ozhGp-%H*5P!;b64PeC2I&t3#k_*prKpj^X;h0*#Pf2v}a zP4DHY%{rZcB6HETk=P7UF<#oH1)t)3Nsh zqtx`==c~$=%G|6KMY&EaCKw_-koIPk%M?7yXqgJr6E#aI@MCk51y5%KmXkFGH-<8s z`|PgTWo=N%YbvcyB4lJizjmh?gmB2m-KH|rCd?MT@9Bdza#*U@r%f%GkR|L8iM|k$ zbn=)B*-oef7z)0F`ppn_KCBs%i+|xHQc>;Eoi*cZe3h7Y`IZgTIqW%#!!UeK1i?DxxgQK!@ zC4pDTSVMoTsoKN@UBu#psHt<68oXS~h_P^-JH7r;RewKBtI~xR89&e7idT@YyxZ@O z#1Gd4M218prFX;hy8qxE`Tfg;Ek&I`TNdl|Oft3Sd)Z%M`l+fw>+`d)gJ zFFTozjr(J>3NYuHZFZ1THw$U+dhK9vb^S|Wl@d%SE;x4{I?WlA%Zi|=4=2&9-mF7Y zscIBiBQN?{k`fAiWeNkRgPK|_HQ6SAsr@V=gILF2X5*ia{=obVuehHEcGa)nfMl@! z$2r71C>G6jvS{DO+)=cZ9mLx z2@eOglxF`z`fqBI%p#5zWg9yAXQ+fZg^Qo@1+PN4KhC*TONJVrd^9_A-ZAcXyP5G{ zx;?Ho#Nt;c4FuWuxsu(3y5ELi?kDUySu;M;kJV5e=@PdluB~CO{|o} zBrU51IEFvo%snq^>aV2{Fd0N4GIWB-T9M?fAIb%edV)7I_7@cZ)1jZ?FiXi|mcwW$ zgWct;;8R3@to<`PoQx~D-gq+1gnOi0P=k9M92^}^1||P8)Ze z_qp>onMM4Dw3A0{CZ*bzuEB%>7vp zJ)D#?S!&)kZE?KaJFkS#+@qnq?BR|))BF$Z27}FKF>$|Y+!X~_woR%(e|Uw-mD@jO z;`Wtesv*~~oppOe@KosSU3%XwrZs-f9()jYAX^VwOaC&dC3JWqh$R;l#RG7};|P(Z z-6J-FBA4gRpo}zdI1^c^M4F}6OsV3-q+l;T!>EU!zX#S0(cyA!YXMRp; zXU81m*hse5>SeOm7LKRv&gPmRm`4A$0ldG#+`xg~ZcPyWEgia*C(L>8wiG7#+wJ({ z*L+`9$F_~>s)vjFa=BpH5m6%?a%0eaBGKhno)^yVK(Kh+R4UQ1JM!Sgr_<(jy8bZvxtDf=T& zf}n>j+^r}bFF_qX_xg|(@RV!3%o(4qHJu4ZQE$>f=O*WOzMaEg3SHi$=+|1Gcw?Sr zN%ODOW=12osPS|^rpmV~;U~rp@Y=9=Di>auP zup3y#@i;5&3;NDeot171hJYo`m%58MO&od%<20p|#__Hq?QjX);0vTL4G3ni26wdxVwT$Oizj*C-aHDx60mDEzIkTvBn7BX9wi zPaG64o#vqPl{sh3p5%eK^S8QbX?xUC)l7ZB)n037r9a)hXk_Yfnr_eG&!#nPer1f+K7=C_!F@A6GJ}>q@@9V8W|Wa{LuZsgg`sXlySFd^Q>~Eqjb7fb@;@1BcSa0}*Uc-d2$Wa@(2PyJB39 z#ZC5LzFQQt9sqZSc!_Vq+^qHLt7x9#*VW7MXsjUmdni3E>MNF8JIK}~Z5xmLcMix8 znm>0T+*WMoxZd7e`Mj{7wveDbcK3n=m`@t@{D)Hz?*IrtV-$FmgNcMH@v6=Q-*@26 z2MG|-!8_U$ZE04Yq$2hI_k61 z!$}K(?0&hBtEwp4{@lbxu^>9gNXrfjXY7BCFVWA~JczUYBLbxYRH_3`gA~20zu+?l za^8l71!CexEmQy3L_lFZS8A;6#phYgj*~?IWM7uHF6-=l^JuESlm%dXStWVK^l~~Q zr2Bem@2bfMuT?&r)yHCxR)W};fUv-^lahTu_^iR*G4+B0)xlf_>)lQ=y_{BOe%P3w z{bQ7>t$E*Ig6EX3p>0am!o3`^S-ANI$CiAIG2x#G#ptZ5Q&%8m(D$daeRtafc^)UC z4@;2nl_EhENwVf7T`m;*U~pa~{C}zAxMQHcZZtjVcqq;@<0S7SV+Lliwvkfd%@0Kk zj*QRu)fQG8cwmYMbFqRnMz`_^^-Q88C$>;gLpydo`$=nW-%n-Kx?Vb(-A~GA5VW2+ z(<;Y-LP7QU5U^_sY~)qNj0@n#400N={9M!^PT_zmMV$;hF|7Jk6~Qzf;+(2NjVS4S zWmC`F@?kKN*CEw!#Xlj-T*M09={Di;R?-_*Uqd>Rxu5HNPUnNsj1HBWStL_1apwIM zyM2b%kNup6Q-%X&!k0q1&L*S(U+oz1j4a80x5Vmx5tF1iMmUY4CZCIM)*%Btv`AO` zCz&~L%t1CmNK;w?`k8E=ViJi&N&?a^sTrtCsuZrm-0*df|nhKf^|_q z;|KD{+U*eSP5kZ{HSC%#9M8DTU_|>IiD-W(zGQ@N-=X93JOWzHmyRV)81rUv6lLHR z4MjZD_k9GEuc8$;$D4z>X~4}R>+U?$0bw4`sO%=emz7NEUhxv%65Cg@Vr=94*hM*> z@=(RiD%WZzuGE7Pi!z_UDq6D<-nF0T`~HO&HO~a}t%T{iD_nP33EVAiu*E zwPGHWd^TvS`XlnpWM&OblgMw+iev$b(d5`R3?(n2&D-CC%ir$~CaAp11H#;5T$t`6 z?@jL9n$joKzu)Di7cJ*5RNywVak5;**0n5Uu6REC zndtDG74LWFmcT(vhaNv3n+Vghvca%Ue60zEe*F5+RZv4?>=)VJ^ln75Q zhSO7-Kc1})InVxC#F1nlLk=I^nf0(y-}^w9(_zza;4!hQG{{jg+Zx9{=gVZ{oS9$> zD$`Hfpzz^sdMooALxrh^_;?W?mqMFqtY;z%j^M5-lP) z3PkJyd&(fyH3_o1M@eA(Y)oW|qW4CQwFoL?TRZ$=dqH?CR8!C2>KC@I_cG;ds=!#;Y75FBL{a)dj;Bm19qi>ysFk0js^*Q+tIzeeAoF=*b28L zAyRT7IK?GwYz;&B@xdSmskqjOizv=3#Rt&{riNrZV@$^<8IIaj_4td)GK#x_;Ku;K zBPS(aOs}q{UdjAdzZvp-{k%0Cw(^9af-V@zK9lSX33cG@_evuWrMrAtUv7WnZ};Fq zrTTWHiJ&k?BJ?7UNa=|r0mIa=%m$c#qJZeDo{e=5|(F$o#jwbvUy2GZ+td4e|_-4{}kE z&4GF*v37I`)3-eBl^QC%U9GPI|7cFkcG-dv)xTQ5ld+QiGG}bJpS^#CEJBa*mA)M zV3$E8Y`Nfh3|I@1uyqcclXW2h^)KJp8Hj`}2lk4$8CMrGwGi5bZ9ME-&)bi(@Z}INSH} zjB3`qQ)P7Tev-)IFu0MYrwj%PIRqHV@-QAQW^XSJo7g+Ms3J99Lo7L#ZP)~lqWjTy zWO~Pdc=Cmu!Xcbt3>Rk`2Rq@w?eLtn<$TfOB+~ssW)|;{Gp-&M>~2MQfgru3S*V7n z_+|YW3z!@3oJ8GQS@V-f^bq1elzu3#sD${^Mu$2|2_1o0w&&_$fvBcG5-&shZ|FxC zjA(9If@p~?7hVy7orXx*azP5fIpDE}@@EV{Fx~7$fP^1i@TC8_5&>N>aG-CZyQql% zVZZFR-+HG^7R&Q!hA_5^5L|M|s4;`avIzng1TId%5$@=gUvMJPnk%FsHzJr~d_SCntTcyXC!;{ORGp6>u-IwDvr*JvtTa}3_6B~)1X`bwj zL_0xoPk36 zsH2w+`g>_Qp#gb^Y@#)riXg8#-&Xw08%+th;)(WM^E|SAi^BF|ic^fiU!mx+Wt#Tn z{Rd{g983w@o(>$dkMpl?Q_uHa|KvuJS$7p5?sYFAN)obRe7-r#y-X=-Cz(hpsI79^@gU`;7&37;w159jsP2Dz%eDyhGMNP>&fKNxNgOJ{kiPLph(| zC;9$#D(8y~!*{hNvGj~fyU9wyV|L|@P#q)e52Vy2v*+}9J3O`iVom5fW1AA+9RXO$ zlkagvPd!rlf{B!ObOK@c(%G}=B<5?o^i<3ls!fse4(A}KH8!Y#QpTFE`}$>0^ZoE# z4SLTjLKyE+&t^19HHf!op=a~AwSf(6zW6?0a4>tx7Y)(Tm#<=Q#YC_}rNBhISgdP< zjjb78a!YpSkieNej2A)8_LQB~Y#P&StA>v8$_Iz+R zw;QsvKkSUU%z&irC108;dmQk!UdAq=oAt+EG(Tp~#|ajhq#K+P=_VfzO}mVHjm}S2 zHH;pj86bL>pm~yKI&1Qs%kAk5fA%v28Ezl=BxqIB^GC;>hEH)W-3oBDt9$(D{EOZ< z^qZ5RmI|+glXBkI8A5Acb&OJ^L&1%&)W5O?m6(BkjF7@lD zWp`Zih1(ms)g{-JmAS}t=giY~SoMKae}PIsbVR)$cj?q-gq!!we+C`-?nS=4YWK_L zEAsy~UHgdpP5-*PUOz_abK^g7uKm~+IQ6WX=&{ohYpXZsGHckaEPB_^BK`7s?QpNz zBVkhhO~fdlQ&?4KCio%j#5C|{hO3B9#mFq8HE@_oyx7Rt&eGxB5tUl8m396d1>}YCxg#*aUc&Gz8R>LTVmhn2fC z(zmtq!26Z9!t;JQzTY)q23G2{zeq|Wliaj_OXS7QI59V~uy{JUuXb`>M{r&DCD3|r&NbV!n{8=R zaYV>KqtU;EzX=6%C~cD6eq z;12sD$aJS^sI})1yp@a+OezYRYs^ENFk`gttVGafX4gp<861aiWGeQQ^i!H$27{yc z9&_?T5&X#@oL1IFyuh`7r4d)f6|Zfj;v1om;-kPa8YS4cpJyiYQ3uS$RLmHAD_7@y z*RRugN}$~8#LNjNUIs?g?$XY?oXa!W`vfiC?uvGY#~*k49{MVMKvD4pIg%g642+Yq z)MaQq=Z9A#hXw?5ru26|;(dd5hIaW5 ztAOJj`ExNNhrh)8R(u;iEWnHEi#D7bMn1z~A@R?KQ-Hp{|0zIM$~g*s}b} z=nS9bOjM8E#phEl0GpiiwKgDje(yY46VuTP3B4xxpw-rV^oc+gQbmi_V=sLiX2g$V zR;l>sd}>e;mUC)#!n4RhgQ!7_i|<%Gt6O4u98eT~9iq{Qq1TLY5tyXNlB~+g_SK5k zh^^KrWGun;ZOdVTKsD`RB;SAoC@w$=*B4hL(TkHJD@>Fn=30AmSVh&)+eHtHUXj{)pSegHt=oF_8m z)NS|q_M+uylyQ-wC{chrDe;nJtK|4o3Fvc?f{b>uvrqs)K)=5xNZshkT01VjtYgi}|zjfAX)8rTB zeAqjA^6*Ewj6@JC9FC^)=SX(L9)E9rB_kTZU{dsS)77KTA8B%Rd zPhx)x+6-c-+yh|g?+*E`G<9X5d^E#r^2i9GP#)z=9_88($JzAQLyQC-ju6-4Jn%hY zhYaop{vv+Z>4CJCOze>snrR{|CCn1EQD#rjY?s0m3bW}Rhyz*rD+`xO2ev5+tHAdDn1 z%~SwsJKLqs!pl(gOabRcS;Yjc<{&P&1lP5Roo{qw&^zlrF%XgNtIon-CE}n*%GADm z8m4!mFHZpeq95dAU{RZOAoIbqe;VbG*`)bav9z=%?@kM*Bo5p%rTQ4e-Jr3m`iSkc z3PEsrQFF6&(tzZjOnp|Ax5UsZ>)AF@0wIhh&@=!6o9G_QD)+&Z@onA{-E9i$$*GNg z>()FgBc3O=Ma}ngv9Lv_#@&zBvPGDkNGj@HiY1E3moBQ+0@3r3GqAp<{=6y(okh<& zM{J%v3GFlzNv~DK1yf?swyif_qAWea*spd=*l5%`fIR0o5lwSJF%w}k=U;bu?G`iw zF);Nsxm0p>Vy`Ar=iePcvO)6M-g;-^zv{KIO>91b>*4R70P3dTFp@Yttzg}b=6pwe zz*X6MCPFDZH(_&;I4E5!4XH$Bcqy`r6&8kpK`Q-NZB2T@EbJfJge?x?IX2gr%a{%- z9o$7Tr9y->2NrpKMuLSh=U`5FVLyd;hcS=HVfjRa3&>gxiAH4e0O4STis>!$$voWb`gv6Q*|FOT{V?eJdj?n+@0GEBwMI9MzC(J=M zD9k*w4rt7Tf~!nuU_CbHir0HWjrooM9TgAIhGtYa>y1%jy1TyUErCcA!zPf^Sb{mC zr}3D%nsJUvUxExXo(n5wJWO2zYRCbNLdZ^Z|9uodo)2b( zFaxpgcqoLol@L^+)vffxT=?Ax>&g}jr5Q{_B5IAN=U(Rkd6z@vW}6_EVC zC{rs&Y}FD^Q}e0Jm7F)fjzQb@v)pI4R!6kPGBxePz|0}_aD+ly~~@dtgNh`TA-l+Adi)xMf~+9*p2~psb-<44caL9o`$99qy(O8KOWC89eUPcDHVB7&;rtwFoz^1Eox_B( zphzc*zRf<)j!5qGWlP?BA{*k5lEu4)Zl@rKM4))LICgO2Z@>>7wAfmhwF9-<&+`RS zDFiPZ0)Yu<62*PzJ8%-&KcQ;5UU5)1$BOx}>8uO)FAEOMKmYN-LI8lJ008R&B>hd! zZix$a0g+ZIJ9#ss9K!uQdFvghB}K}9!maZ>{)HOHTRV!1l#u`AH#7M-Qy`s%ulQY! zQzQ%yHjw9YL4q>Z#P9BTzTKU(4U>M-XQ^8p272f(AR4*xc0wPzb111jAk_+F@FZpJjheQ|y=uv%0Pso`o+az!9`M$iPve$SG+Wx#=PV`8Cr9lnl`a?O` zj@oD++au{a4)1Q=(dSrbxq~^pJn5JGuq+T|yzq|?ma4?+2sJ4WlXN0bD@k1M@59hJ z7+HC27*5JMx-WhGR@r|5{w9Kz1i=1=NE!%n$OQtMwQACF4k0xYRUnuK5q5M;YCqO% zzG|bi zO2v?iW|e6|TaF>N0}}?Ds7%&m6Qdh8{}K7Q?JEp==W(a@%)tZ##1u9b#I5Es+^{pH zv>(|)eA!#m=@FvG&}-IQ&#;tIda*z1>%`Q)+A(^4Qfq=hB7jH@v_-XKV9%xXu6psd zK`Nvwn~E@I`9pQn7RUy7vN_krRWaJe?|2?~_@L5&OAev#fONl*VK}Admv7z{G7$Xo z4$6;W3py*+TXD4q!<~ zUVHR|%H|amOopO3o3TI8E=T-Pcsof+wkc_wqbx3FQ5Zj;mI`i%qm&P0)iXPRvW)fzn7*l{wiqvpj4 zaUM$e&?J&7)$z>As{FAHZ|Uo|EGqFhOa=mgMJx1d@+1!Sv&Ysa7~z zP5F3gMmt=m!G!gelJY_YH#s;lOps^wm_orivt(lP$^!1v4hiaWGfnl2wv$M71il|w z2|0TntaHoUa8RWkUu&p6=xI~BWwDh~7T}T?fNg0tqTpNmN(RanEZ|h`Ti4PS;shZ? z=(Taqn-?gj^88h<)B0)d2r^0(wH^W$2M&^@pukl**(pQ2wW&ZkZQ$N7lzu0e92nY6 zFP+HV^KChscpK^_lK#j{20h{UF=wnQmU%lZv_I3YZ2+maZiqwG+2XmY1HFmCr6_m9NTzv`?&UcsPN^| zFO(xDk_dj^jR9>YAyo5$u(wJOT7bmSP}BiwsnivTkAS3E996spGHBz!F8^jkTZ+U< zvp5>sA|#GmEAnJ(mfs_4g3ZbnSy6orA0$T&xwLYfI0I&$Qg%VCdzbW*91$2pZ7W;s z8XuAl)E+>iKIJC}`DAgeG@K7jH?K6+Miu?b$AU~W0|JXZi!^)n{QTgoIKNR2dTjaTwJ?2R4Rd|wfe0rz7 z!=vQcBlueYT8>nLFiE+59;TTgeMrKvy^J6KCKXq+T_8UzU~|iu`Eg(TlIz?T>27E8 z+POm{^_SZ8zI*g+NBGGPO}@$3!*|?|3SrU4MlzO~Ry;1}^|>}$4Wh?oU^vLi`vahz z0C7bczBU|+otheb?|bn;11Is0ve5TF4np@lQbW`@zNQITIr`>sG3>(rzG?h*$s_aV z(PFhDm23Roi9xJi!!&KZ+s*uu*+sMB=boNgZv>YI)BlW>t>4m2KD&exoMj^&(yU~g zL{*-Xx)g#F$YBn0;N2jNU`Wgf1xMm&7)?hSF+3*i4JOU-zqkc5Xyd;s|7Jvm;B3+? zjz+Ku38?l}3Kk;gBN>(@+$PO9zL!6N)udIR1WDtRXnq2&roU_JgsYid<|Ib$0Xx8I zpQe_Jx70A$@Q`){XN2b=Nn!(#J2BW^K|FtH>qiB-oqBWK64Fo$J0Yh!XNy`BLO@G zXn5WzGj)6mA#F9_vIO1|0{X?JX4<35!a&bFUbGxXJ-ZHr{tGMQoC7lF+c&iLZ@!j6Wc; zr}I@ea`{(5a0la;42Z9}Y)?B7e^q*ZW$kwMJgZJucQAhLGJf0FPxqo&HW|5Z`fhy2 zTaXfq78*%xnphl;yY3pS1^31!f(%9u-|tc*+Op*kHtawj2#dA&t6kWv1|}*6YO&|( zTW{Fn!$^rRr{}a_b3+UFQ!2bvA0gy`vZbkm-WG8Y`9y@4mYPFhT38qia#AnY*hW6X zv_8|vJAil(p%St@oQF-CQGghXs8BQ%h*AlADoU8`da+k63=i!$XNSzAc`Kg8yV*Va!1*{?X|P{FZiK{zt0kmv!H3_q25k;^R1I z8pko|Fpe&G?vnZ}3@Mzx9x5;k<6quEq~tZH2^Ue{>qmy-BNj zn#?JRqe>49V>?Td?0Jc_R6{wVpAQ-EYg-*2gO1pt3*~=9K}qGtk%zZNOrs#cFuMNK zfTIY-c{u|naUq-WKY98e9#m`Z*duqa)=Er00YSf4nhXvjgb+^vmQ;OFf#=)^rDX+v z_*XX;H{9MOFf^RcW64s}Q&W`>H>3sF8-|p*y?+QF>c=4gpoJg5zD`Rud1Neyr!~ZhJ7U!7f_P{ALLMM# zDHvHd>?3C0r1R^iffbvPS;!O%fs!{DrZ08Aj}y1BJHMxJtLbonHtgz9Hw3XjEa~Dt zjo{J3u0aCUh*0o+t0;f&bQgDHMhLS&Th~)k);kcZUcq}VM8_j5+nz@u2s16v)cAXW4dXov}TAyi>wM2I{jnBt|3Se7|@gV&_7 zA9le4do^4=H|7qn@?I)lYpU4$Xmwk60f-9B@62_yq*JIHV(JzHPMgPst#pCX&N(h) z@%zH-^I(SNfCS7m2qLzcC3zUL%pD+!CMCh}*(=91J9*%uD;J#ma|*J#;Fhr|_}yDN ztufAG%s|MPn^%_RF`uJoZpEo7h}`GcLb2+Xbw2wMumonPr_7(ZK8r>>ReZcFN~eR9 z6~)>e&`EzR@?97bQTlsP9C+rcCLEJdR)xGE%cWW13sY30*H23ntFf(Z_J1L)X`Bx+Ur}nR=)DhFZacP}42I*$bUbnh z=Tc8XDk>+p;RIZgmk+^~b^&OAQ|0>poPx4zcaS}mKegfg}a-kGY=mN7QuiZcaF zz#~Q!jB9gN#^8O}xe#NTR{0&57?MnG zj5*FbhC}!cRd`7r@xn!kGbrePo7LL=$x5Znt5(uFfW3`YPqG7cvAU-*aGH?`KTg+&wDLL z(}$1d)TSa7(1|MUtPR8oCsd}9_@R-jKU$U&+RPnrQcOEw= z3{qPv3p_;}%&7#))>C$(CKD54WYC$8_2N0+csLwS{qUpFc-U{w>m0klY+)fi19Zs^ zh&OB^9d8iM3Xjg`x5FTq?J2LNr7A`N9PJYOPH6nwsBEJpr*NXJHb9W zBLJe|4mCHsN^o`9X!VEV@$jp_nb;$XTjGRB_QJW;14`WWm;eE>WMx*Sj4`n;&RrE! zArh)YUTUE9Xu%)5qemkO1@+pX@OG6RAv(I{ftT6_b3|u_P+fFd%+MGxSYZlc1Lt&# zXG83sqb4+$dw9nQ?|W|*a928PVZ<~$3#WjY5ZTgk3AljZC8ddyVaYQ#tm}T>pT&*U z-C#!-Vm@r<_=RJ4un{?-ViX(AcQ|1wcZL2a9@V1I3O)CP>U6ge)}ntq4F(KuFAB_9+H3 zGXl3mWenXdYEWSW5D$UDIt#D~(;R`gaj!YoC^46D+Vk=|AcC9ao}jx)H|t%s4%g=0 zi)d84nSP}(;G^(O0kC(W$9WckoGQL^tgov^w|$$LD&JAh>Mf+;UB+9TTDc3ZLP_Yw@wmoYEQkQN-YS4Yk2K<9S;IA0P zshcH>u7UuPk{GO`1aX_`8dWjbib@8{n)6j2Qxw83D{hzxB;rVT4%wirjF^u(6^_h% zX&miaP@A+aVz{G|5WJk%RzosZSUQ_6w3&~Q%H%66>N)$rE1TFQtP}vqDc|>2_b00+ zUk-#YCSzehEn6XCA-01txMAlGqla-w25y+fGVOfnnNWLeq6(@m^uKoGX6pR)|D`p! zaT?83Oc83?-pe_-n3D(t@f_8@KZ;bfR$oLyu!*WLk(rZJA_QO$VG&RwVj?l~P=TSh z){#V*RaHby2uJG=C!#M{gHy|nQ8N1i7-oLdEx%kQgp`$v?ukG)Xrab^ww>347@vWx z`^XU0WLed~hmn|4g0!+Co~Wa9CMSLr8u#t7nyik*lujYytbN>?4yy_*roy?gNHycx zaZA2L+_>|7Kt6o^*s(<>TENz6ty)-Xy+Z3KZk<{zqk4LCqq8gj8th8W#3++k%<7^P zL@^_@$ZEn?NTJOo-3JyaU_jv^s`QUKGhyacw?qMN*^xGwHR~KyO7HV_wp|T;c+#RB zAJ~M5!pulgslF)IoLi6f|H;SpG(q$&LnF2^Aq3PDn5kJh6l6|6W}u^W3z>7gM-Gsl zR_G9vjf6Gq=N;eE#9Az+w*(_$v9TDtdRt@3UfcuEP12suH5oIX)z@e9ATlE_CF;ad zr^R=742m>pdrfNMS5}h#8uMy!#h_C^^KeX_*;1D;O77?;XW>}o@y5|^>rJ229%A^mMGw|ZJ%(>IqgJ0bC3 zKgSp>=3z*n%4P7jLR<;Lv6Ye#uyrNP-!_MMh4FM*fg8Zc=5;G{=>r8p_9T?ikH-)q za)+&BKwKM7R5`62Wx;o+(;aoBy?9;~H6R2g_NjrJYJ&jC^KHZA8TiT}FfHZX{2Tx{ zHT|>`SVlC`PGhaIP{9$XQ>xDOPq(#Ks(}&4U<4L(f3VTs>V^* z-~V=b>!ZB4cc|?%r^ZcN#hQOLs|rE@`6|Gzt18>lR7w;PF(h-mi(nOIFy|)e$G1$? z%{}N?w(O#6$TllXRXRXiCrK2!S*19CPueUh0a(~naH+*0_!CzFFAf2cw~W4VJ|o0& z${ANXm9htBql{w?j`>tz`TCad5u{INzjFceYkukR(s-(5%{4IlFAWsNET_tlN*PC~ zI*nt=`Lfc>0Mi&#UN$ckTsWQy^8T~9@i(@9OrDM#gw83*a9*+vR6U5C#yb5vrc57O zL9y*sIR>C1QiW9o>T4pX2Y{E30QsMfmfJ4Wvjlq5Mid0BG?gXwv-u*tVztG{r@mP6R|!fP_H2>X}pa4JvyS zWi{ER_9~3Et7p&E9i9+{GBeN*4`It{|o-Lazcu3c$2f&%l7)Rr*<}k~=HxU8e zC=zO|tX4EVLGqN8#5BlVC5QjcB;Yaf$-`nsxHx+q{pAYcF9P2r8en(!;U&Sbs79qf z84ZV1XKLHy(QR;2?yIm%C^52ne_k2LJ)pd|TM#V) z7@@Zzn;32ny$h|qx+K0xhXvB1@wn>%E zC9}#SL1Sf@o}aB(+dQn}MnR4J2xpPn$c|B`1}w|z$f>`$?D$(>t1_%3n=h_rP|feX z(WW&1rgB8&?66_7W&3-?>M`6lorpL;-y+Sc9S{+)P_&5QPpCzJl3OKZ79iSRx>VI* zGf^hS$ag-*8l(0mIwP|9PadBnadxK^R0nOOZunbwd2y6UNp#vk6*N79SRB0yi8B?l zQ))%N&5j$yWiaIQ6~1n+Lycve>_T=1oF`lvt}!HlEfz7Kp_-#Ig(509xi!>WE6y1h z#oo2OljoNtPYsO>rFD9pcl8cU4fl+Xjj+Mkc+c?kaBmkMi~hvm+4kacwRL`a?ugRw zo*kUOIGa9y^;(;}d@+9e;mv1*+0xj#IJs2dIXL#a8jIkP1}6!Xc9+{A5(&199{IvN zZT|m~aNLB4u3z|)+)Emm8Xzp**4K7-ff`S{x*d94k2eGTP?Xgf5Mf(+$v8Uv$6F^}%^Ey@K zPnCvmQ$4LZ9yNvhr&;OQYYJ~Ca4?eqwNJv3$SAc)fk`VtEo7=X@l_w76$_F5iJSD= zF+uKVWRKi6Eh^#&P{~Gv>6v!7(`iUQaIYet34Gaz=XKkSeVazjqk&l!#oyKO^de;Bc}nS42*g@emxYN{D!-m?o*5pXFi#V;@My7*c0k-$XcKIt_f<-no!X z5!pFY4=v~X`YA%}v6LohJWwu7N5n;4#Vl2}K%^>QYtC^U9nKtgUlCK0UxXv6d6Es$ z1VO!m#23$9Ct=I?8qG2#TZx|Nl{8C;Eke#ovZoP*9Tdp0PRnM-i~9OLw${2cQzBAV ztsTxP@mjmuyG!R|jNVN%Z+iw4)DivUniMD<8Ne{IkO_PP?|O@-?WAHeH_3`pCgc?Z zoylZ+PXu{tKyJj(E!p?m?Pg33NqMD0H;J3Y&2_T%h8<0+Ik;JB=Be+0?>*Cr;&n+1 z#)vZNRd2*}e{g(a=ZXYMwMm*z`T8pF1ffj3MNWwj<&HkPhhg4voMQr6W|{WzW2J}K z;sH^#Nv6jKR>nO%tKfrq(pV55KvqC@bk#+fK}UQWAYS{dx5r@$?cKDSF@ibY)kkF? zKvR!z#i46}5+ad9VFNg>hXOD|tr<}t0W&vB??MT5M*@>qCFCH*nNv^v;_-a5AuVsI zI3!*#C1_nT?dN)bAs)NuHji;AQ$=<_j9+eb^ioc*w&r`&B7|pdesK$+B=4KN!6(dHx zp{g1%fM}|Ofhqjqq99IFAjM)hb)jz(vhrQo5a=-)00E$+#{@1QdP=qwxlY^;Zqb53 zYn2vKAVi~cgF1NhhGA=s35%$~X)-8nljuni=r$;_NDzna4AC#E{4Lu1*<&(^F@$Sw z^%=C8CPaTE&C}UM^YFUvrF5h*5T8V%i=sg-dMSsMT45{i$Iq2;6YbO^6Gt4%ye0tJ z!YskT%tG^d+DcfW?|$#*>q3+l~0mrEg3-9MEK|;*@YmsMFI^j2nMoy@51FQ>S zOub0uS2psw&wzQ}=AOXUMv2f5M!n!`X;m(10hfBrr%^DD+SiSzpUz&!e?tK;#AG%@ zt~}V6zNm3s7|vS{h3&7^eDOfN z9mp!dvD|J1dlOP1lp3=oam;R0GzpHfno!uM(^=EkQOF?t{qm+E;}ZR zDJ@iANs~5|s3`g@OSLb@@CwuI{Zn(=xyB~D!|Uk96&)?tH(=$&qt=P-JIzJf?y|gy zx>J`NJvER8^DOWhUXEY6?}qP#+)k;CcuG~dw{2}OSKGSr0(#ygn)0->5yVIG4(I5g z1R{bhUH*c#Z>=Va2MUbMEyhdO2QVVo(%z}-`Dhbn2YV;&Cc7W56*5ZehyDS{jRA%H zh$@#eZGJ?+19!GvNhw%zA)He)Y}jkdxz$b$)xw;ycydpvs8MVW_!fB!L8G8rN!%2< zq^V~z|H@FR18^o5h;Kkhaf8{udvaL}x51}zRt!gm3f^6p$qv~Q64p3^eS(TtUo=1g zFyP-(6Wt`L1q{F@ui>|8$Zcbjk?yg915CfY4Ip7RKPO+@!4E-?agVVELPY^zM8*t& z9L*Ey+$%y?wErhf^MEi9O!LUV7Rn$KpeaaPb;x%Ut{M4V`8QDR3naL$SvuM&)iYcs0s26bH>HfCG2BgMDbsF$M2tU~RNs9EXS* zQ{A$nE_vpO!5a4>7Jzk*Mn?|;n{(~m)N7h#urLgaN<$rY;{+~A4Xp*p5Ns@FVs#$Q zFy_#$*b-rHqCBva-s!OuaZqZ9Rxj3~S#KH{3Q4FC4tz>9GF!7*n0m|(`q~0alBgS- ziMa5FYObo+0=#E)rVw@^s8z zTHAh_B}*lKPrLr(c6snI4%jI;zQhni9dvR!WAi)@%*1=**~4(}h;So$F$4l@t<8a| z`|n)P`yTG5Qr@_5OB!@bz|(5LZrkm>P*#URRhZxs>=9eXb>w0#$c#!We-5p9QBnfi~I89 z2&n#;tBcrV60rVkrCRU`xtJAtGgaRa$`Xy|><30gP_vYcYI?JrxI@0DU%UDUuibSd zgz8#b7|h2Nzjn8Yi!88wnn^eVw1XBs-yFChD5#*}lOW3Fb|EzNHdIw)-lshJzum6c zpX?Ue;lZ0@Z#x}!-Ry&F7<0@IIU#4=|Cq5go;1THL%_$>YJSVbX}?KhGo$8iR8^Z@ zYtGrBijZpV0J94d-*o#kS6M-biz*E^jUzA8tz(I&HrvnAA?K!*NO!VBt#&qNwPBFi zW+SXE^&iCU-NAG^Na5yrzuWBxMNxBZZ4aC;j}_0r2PN`U$ZD*BO`pABuK~-tfK=t3 z93T+#m1_sc&OJLuAE2pff2V#}K$m!WhLbbVH;6&A0uiHziVNJ2O04plv3i?4z;|%Y z&1g+9{Cp|U>K1b|YRwPwcgJAg*_c@+1?swV0HG zB{M68uPbIijs>=V@et1J-(djzR+(>vD@c3S1T{kpj8l%5T5NyQ{#JLn-}4AC^E?9R zkE?F2d@Di>JO-b&`fW4bPlV7GHX~vG(c4;?cJFp@P6w8n7qFKSY8=(?fHo4q&SPKvV z7&(ie9+1C}Bo=C_$a8Ik95y!THp@*egz}ZSyvZ%-0u*<$EMV68e(vz?V_wlILigk+ zG$yny`^uVOR5a_xwOd``J4>r|1KkU(dPOq@w64Z-?5tlgeL@lsaFPxbb^zLHY#4Jq zR9Lu?)nR4y@|j zueu1K257#MWf1NIrH3ToyT9Dw$^>-IYtH>#%G4te*!1}E3v9lXN#eo6wamkuEOSbE zG8l615YD1>0ox~rZZzB^*jW7j2Bzv_Nh`RfOa%lZ=oxG>yuGi>$OT+ui!lZTns(KA zOU-h+7SvuA*GWDeFlg+%&m9f%$~$I;qS#IS0)fAuJtOnu(ocjHrmS&#|1CQJ8L-rX zRF(ejA`@Tq3@#E>mVK>Ki%WYXhAySLV5QKH8SH;vW+@{Ts3$9gCgfm}^<408bn~cU zWCY4;<7L_FXAa!wLu{4$!{ z)F?`|sworHntDz^iZ!Xb?`Wz7NUy1S6Of=`edo5gu(CpX_A?}ttjLS427Wh;z<5=h z*jrI5*aW1~S7HyU^eCLQ+=cLp{{f0m zpdNn?D(lV<*^voxMIPZ7;PS!2yrR6HK*gM$&vM!) z+$`@}CL|y&d#{sjf~S3mQekq~WiDwmB&7Vr<{@}qaib(ixZHZW`p3;Z#t1tD4Xy^2 z3P?aY)1$Jlc&xCaQ6JL}RW*b@i4{w{?I%#WBk5(Ay1*l7)l3dl<8atak*=FnOlxmk`>W} zjTI=;?XcbRpui1K7Nx1Joo?KXVo&O3JePzOB?40R^^H;1+65zs(4LuIN0N@nfFBz~ zJ@oN2aH*HD9~!$`0)uBV2WEYJU^MKbOwh&>WCFy`(A>I|&diq}z220`qTrm9hHMHu(Q|~I zv#`z3)*MBX&(38sUg=iAlYw_+^m8taAWcYsi9wi<;V>P`{zn}U6$Ylq#Ny@aaRtO8ov>GJf749`R+pQmy%lYo~ zep+b}*JMBWo3~`+MNi`8*Nq7Ot#LhdJ9ukRYL+zsGQct30rAZOEl$;{No4uF!)P(p|Z585}|^|??QkRNzZ{t$(N8}y>N z;iVm9khYHBZXOnyqtT5ZqjkLgCh>+aXYoCJGoe|QlDdA~ZY>q)WDQVC4i*_1C*#v= z<2CV{2k;PYV6HO^Z|pegu_JZ+IAVR0iB-CbUU~>ws+VuMk`fjhh(PEb?9@a`=}#9h zA(iyh>jR*6f6x%q1GU$pZL#tU^hJ1Lk{UBMzigCSsP5RNtd=VNenGxO@#HZMK^?AZNU0?OM0ugE z<7-dt67T7yTyp*_LwPH?5L{7zXGo6VwCR}tpTm-S%rH?uhz@9m`o4g3!M?8JCTdVM zbU!?;Cdsp!f)ZiGwW2RVm7*{0vfz~!e~Ju_UHTA9*$`!NmpQY+$I-3d9Mdq4rKGXM zMKxuN2)cv{h~t>3Q`2bWX+z^gSfH#AMJk19cw%isTwg~RHz7p47%w4*bpv-_#@kFa znPkSu8aQ0Pfjl!R{q5fK9{#aw4s*47`8V2{8~T+;qQ>2TgJ3he-bLdC__E!0Ca?nf zq8bk5b1pCL7Uh`(`&N5y(*QM*`oQ2RBG_@=vZp7stq!{ICg}(##N$o8ZXOCVZObhU z;KscZLaMBv^uS(ufrqyfE{4|dtq}i5dN$Ec(#=L$!rX&DU6al%s5jkuqyV=u| zDXg-Hot>3)SfR_xde#n+J*YoYzhpnjeKfC>uhi zKAE4}GCFyr6bhW8>06Q#-@^>XkKa_(S8TYC8EH`-1IigYln@RG zL9*TcN6Cdmd*1zcY7hIpL9aiwr*12i3p-0$w!n$O>^_-YPA_M0$H6aGQwXP5=P%nP zicPD3t&*<2n`&?)Pk$a#YP?DyfmrUAzQ2Gwp&{meb1d49JL5dW@FM11Rb>c5L&(Ey zs|sjzrQTWE2Dq`dzHp`ZUKuos8j<}Kk>cje8c*l=Yf1KY5(#X;zo*t+MfAtF1M!7MP(qkrRsryBApA`CCT* zIhmdupFKW1?!WSrP(?b7Td`2_@a=Qyr?`{f9}d8Zm*0#={4@H+W>i$BRDA5ld=9P- z%Q6-gH!W@U5!e+{+5kSKAnjC_qwCk~qbuBLEq_vMr_Ri{<->*XavZ*AI_(rMFV8%Kvc1^ zZIveztjnNcfkTWTNKl0b!%8Wfn2SoCMx$ve<@@8q<2Ov+awxal&rL>iV8B2B&!03Pq z&QdY~uic2#c`9h7PIPqX8NeXEOyt`pBw{9h;VZ9M9no2gz|A8V)C{Tsr2WKi)ThRNXh`wS zjG9cSIp~Q1*RP#w^jI9Br|~+QjTp7iAY$c`1MP2#(PvgomU;AiU>Qni<*-|^EMDbtIAy5egC+nmF(Dzk z1W`#6CP&jV%MEbcvmDG8Ct9F4?36iB8ZOk-#ry*o41x#U{+QF0;7-!vw61z z0cqRyA0D_k--Zh?YfJaue+f)EOjyQWm#jG)zHe`e;PW;J!=X^?i;5#Xc1vs7NKmiI zm+fs}x(#xANH_0u`$d**7<&j}=VB#h%|#f5RC z?V$BS{HF4ojKL|RW$<-tz6i~KK7_nIE1jFv`zqvFDzwy~U>PvD%4_(+1K>mJ$c8QO zAJ&jlRlqzlbk?C>DQu# zXNne1l0*tStNg9^VicmB)NE_`am%@K;d4dz#eRzr<$E)?o9!p#=QDd~@nj6z#-?FS z_RMbdpImQHHyW2-%zq**$8tx7KcK7Exw_;TkIgc(&I~%s?LoD6@J);FUu|pPGM@*t zf1clL_p`w=wry3Zy0a(8*Q)Rpk-ALEc#o?GEB1V~UEjqAyN2*y*2!=hbjmY@HCzKl z=0B)f(b?4WP;>^31=#9(INx0<8^M5DTV+@-vl!>s{lc89+VaPHW{Q5-6Cbj;IYW^( zh`Uzv#renuGA&G3ysCnFX+zk{$N{E!ewo_Sy5_I@C48v#__ckO#{`ZC0ece!r!bvE zC2vdn^UhC5+~;BQIc;=8=2&Md>5`bSX(yy1K>3upMvj^>Vd7ovh9sMn`xv9oB z&Fd5OD3^7k%UfS4E4|}iO(t$@wou*^@n2liZ(cwhpP1~CfAS!! zCGO#y=|`H{VT^o!<>(KW@Vja|of0Cz(?GNR$9z^w*oapc7jS0h!>TI4qu93L$51`b zO9`KJ&`t1W)_l}~C-gPx7wozD_9xu!k{Lkx$?g=qecg=#x|#Z0sEp*Y?0vwxfJ*q!`ebUom4~vF*75>vCD?(W7Xe?)z-3)KxB4WJg)F*{0A^q^UnkRNng4p4=HJ|I;*EmlxUb8 zYU(P(IHt4?N_7g#+h7Kf@FWI$7>}G8;h8r4N?3?9PTonzpWTyl+fYd~JVjtY><$xk zTVRpSwPSX{|Lo|VY-&tyPF@{Ds<<;q7<6E_NGeX#(aYa%AU}2x`QWoS)5&rs3G%EU zS}2nH%{?rw)ZDuEBnxRy>PK-?qn=-v7R4`Z@!SSKm44mXLU(FsqaQrCM-Iba(YM2} zvh;o5Q=4|g;d2`#Q#8Ib{KZFZ@>f292HFcrytaW?Klsqy80Py%3UTxsYl0PWR(d#J z1bTwiC0BisV8s1Y#BQZ~S^lZ*&g5}~*A0K$k+DmgXttf){;v|o(6wHw)zOHiX}k)- zN*~^{?3j(th31FAS?&$ff*lf1dKcpki+XCpVvUO*+6o2!2T%maos1kIY?2ECuwS(D4cZ_M-l_~@KX zMo?$9bnFPzas7gYqO*G$+FXFvF{apwPymo)13ckQwP?5NV7^vq$u3m`jLWxiYP@s#!BnR$Helg&e8&XQe6=F6sxC z>c<2v#bFrBG`ge%W44Kfl7>?GLM`s0%0%&jfxgi53%w4caP$JX1ia@f{*MOmv?V7f z=W)977}P$Gu|2g?QZiY(i@e>GSgxeh9(yQC8;Xn&v(Q-`r2aaM#pLYu>(lYbp12-P^cHB1r=J|A?HjdkpC2Dyj58}gIqjZa+Lvzun^?0^ zYh%=rWwF)$^QryU$J4c$ zQz<6HKpJsDr@s%hRRI~*N2>tA>7xKIlp$d z@`!yWTmR~2d7O8~W9{8eF7axU{=tUS?JTV8GIB3RBwC>~A-}ksX%0XP!-PHR7L0B2 z9Vu)$B?hgT<4;^1w`eWqj!J?+DeAF#&3rpXzb5Qkwk z?zp&P3;6>v%R%C2SzaV3SDKT9y;BB{4V(z5Qfs5vTH3&sl=ME>f>qWMdJ>}bblM=c zjBkKarq>O{u9qfDH-JpQZ&JtiB==N2tT`n%)DdunaZE5*^g1F9` zSDGIf%Er>~c^)33nVF|?7>AfrFlGc(RmJMbrVwI`QK=*8Oc^*gt+lZJpf|fAzT~Yr zQ{ogEVVt;0nuppIkn{D=zuSg$CYKxSyxccry>MY{SEi~9K}0(#Ebi{Yge0gQcBqs# zJz`qo#7Rpt5}xA*a0J8}dDY+)|9&l~u*dG^@^6YDZc4bj?X$RsZYY+?uZ@lpM`&=J7Y&=MV}(TxWK=XGw*ZI|-XGhqU92}d1q zpn$ry6Mwq$W^+i*vP(p<5KosQT^v(c*ww%JD+q7J{a^>Tfz8v}Wpce>{lA&~r~$;G zS@7mdVoaVy%f(3(B?kutz@hpMT-99T?0M4{V34*C`I~^pixB>9!I^y=W+5^sH5x&2 z{T;zjYWf&lcs=Jh0#NF3L_pS8A_m*~Uc`Z}zp=p1+#HD@)!i)pH&gVo6o67@N|6t^ zszoXgjS^`E^FIbd7K!BqxhmSPn9;2 z4olU7^R}L$QmwOw3rW;9Hn`}Z`&pSfIyuUcJ=VHXqm*VH4|74*HLH0JR1RI*3bt4x z)6&eQtM1h8H2A>gN@=3*%8D_r@^+b061R1NIEGhRjukDy3z2fwMK@QVxm;g$QYNX* z@}+N4O2FV4>L#`a?_Cm`Nkt7EnJJy{1tpqWmCThTcwjnsU(nncewX|Yl=t|d@EHIA E0HDf5w*UYD diff --git a/frontend/app/src/global.scss b/frontend/app/src/global.scss index 77be0de7..af853d92 100644 --- a/frontend/app/src/global.scss +++ b/frontend/app/src/global.scss @@ -26,6 +26,8 @@ @import '~@ionic/angular/css/flex-utils.css'; @import '~@ionic/angular/css/display.css'; +@import '~maplibre-gl/dist/maplibre-gl.css'; + @import 'swiper/scss'; @import 'swiper/scss/controller'; @import 'swiper/scss/navigation'; diff --git a/frontend/app/src/theme/common/_ion-content-parallax.scss b/frontend/app/src/theme/common/_ion-content-parallax.scss index 3b0aff70..5bca3750 100644 --- a/frontend/app/src/theme/common/_ion-content-parallax.scss +++ b/frontend/app/src/theme/common/_ion-content-parallax.scss @@ -24,6 +24,11 @@ ion-content::part(parallax-scroll) { ion-content::part(parallax-parent) { position: relative; transform-style: preserve-3d; + + display: flex; + flex-direction: column; + + height: 100%; } ion-content::part(parallax) { diff --git a/frontend/app/src/theme/common/_leaflet-tile.scss b/frontend/app/src/theme/common/_leaflet-tile.scss deleted file mode 100644 index ec083aac..00000000 --- a/frontend/app/src/theme/common/_leaflet-tile.scss +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * Copyright (C) 2023 StApps - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ -@import '../util/dark'; - -@include dark-only { - .leaflet-tile-pane { - filter: invert(1); - } -} - -.map-container.leaflet-container { - background: var(--ion-background-color); -} diff --git a/frontend/app/src/theme/common/_maplibre.scss b/frontend/app/src/theme/common/_maplibre.scss index 7d79b0dc..0a4b1149 100644 --- a/frontend/app/src/theme/common/_maplibre.scss +++ b/frontend/app/src/theme/common/_maplibre.scss @@ -9,10 +9,9 @@ font-size: 12px; font-weight: bold; - color: var(--ion-text-color); + color: var(--ion-color-dark); background: none; - filter: drop-shadow(0 0 2px rgba(0 0 0 / 60%)); border: none; &::after { diff --git a/frontend/app/src/theme/variables.scss b/frontend/app/src/theme/variables.scss index 7741f1cd..f8c4c644 100644 --- a/frontend/app/src/theme/variables.scss +++ b/frontend/app/src/theme/variables.scss @@ -16,21 +16,6 @@ // http://ionicframework.com/docs/theming/ @import './colors'; @import './fonts'; -@import './common/typo'; -@import './common/helper'; -@import './common/ion-button'; -@import './common/ion-header'; -@import './common/ion-input'; -@import './common/ion-modal'; -@import './common/ion-popover'; -@import './common/ion-refresher'; -@import './common/ion-toolbar'; -@import './common/ion-menu'; -@import './common/swiper'; -@import './common/typography'; -@import './common/leaflet-tile'; -@import './common/ion-searchbar'; -@import './components/image-dark'; :root { // Fonts diff --git a/frontend/app/tsconfig.json b/frontend/app/tsconfig.json index 99603852..6e06e031 100644 --- a/frontend/app/tsconfig.json +++ b/frontend/app/tsconfig.json @@ -5,7 +5,6 @@ "baseUrl": "./", "outDir": "./dist/out-tsc", "declaration": false, - "skipLibCheck": false, "isolatedModules": false, "checkJs": false, "allowJs": false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 08880060..c284639e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -719,12 +719,6 @@ importers: '@angular/router': specifier: 17.3.0 version: 17.3.0(@angular/common@17.3.0)(@angular/core@17.3.0)(@angular/platform-browser@17.3.0)(rxjs@7.8.1) - '@asymmetrik/ngx-leaflet': - specifier: 17.0.0 - version: 17.0.0(@angular/common@17.3.0)(@angular/core@17.3.0)(leaflet@1.9.4) - '@asymmetrik/ngx-leaflet-markercluster': - specifier: 17.0.0 - version: 17.0.0(@angular/common@17.3.0)(@angular/core@17.3.0)(@asymmetrik/ngx-leaflet@17.0.0)(leaflet.markercluster@1.5.3)(leaflet@1.9.4) '@awesome-cordova-plugins/calendar': specifier: 6.6.0 version: 6.6.0(@awesome-cordova-plugins/core@6.6.0)(rxjs@7.8.1) @@ -785,6 +779,9 @@ importers: '@ionic/storage-angular': specifier: 4.0.0 version: 4.0.0(@angular/core@17.3.0)(rxjs@7.8.1) + '@maplibre/ngx-maplibre-gl': + specifier: 17.4.1 + version: 17.4.1(@angular/common@17.3.0)(@angular/core@17.3.0)(maplibre-gl@4.0.2)(rxjs@7.8.1) '@ngx-translate/core': specifier: 15.0.0 version: 15.0.0(@angular/common@17.3.0)(@angular/core@17.3.0)(rxjs@7.8.1) @@ -833,15 +830,12 @@ importers: jsonpath-plus: specifier: 6.0.1 version: 6.0.1 - leaflet: - specifier: 1.9.4 - version: 1.9.4 - leaflet.markercluster: - specifier: 1.5.3 - version: 1.5.3(leaflet@1.9.4) + maplibre-gl: + specifier: 4.0.2 + version: 4.0.2 material-symbols: - specifier: 0.17.0 - version: 0.17.0 + specifier: 0.17.1 + version: 0.17.1 moment: specifier: 2.30.1 version: 2.30.1 @@ -860,6 +854,9 @@ importers: opening_hours: specifier: 3.8.0 version: 3.8.0 + pmtiles: + specifier: 3.0.3 + version: 3.0.3 rxjs: specifier: 7.8.1 version: 7.8.1 @@ -978,12 +975,6 @@ importers: '@types/karma-jasmine': specifier: 4.0.5 version: 4.0.5 - '@types/leaflet': - specifier: 1.9.8 - version: 1.9.8 - '@types/leaflet.markercluster': - specifier: 1.5.4 - version: 1.5.4 '@types/node': specifier: 18.15.3 version: 18.15.3 @@ -1066,20 +1057,20 @@ importers: specifier: 3.1.1 version: 3.1.1 stylelint: - specifier: 16.2.1 - version: 16.2.1(typescript@5.4.2) + specifier: 16.3.1 + version: 16.3.1(typescript@5.4.2) stylelint-config-clean-order: specifier: 5.4.1 - version: 5.4.1(stylelint@16.2.1) + version: 5.4.1(stylelint@16.3.1) stylelint-config-prettier-scss: specifier: 1.0.0 - version: 1.0.0(stylelint@16.2.1) + version: 1.0.0(stylelint@16.3.1) stylelint-config-recommended-scss: specifier: 14.0.0 - version: 14.0.0(postcss@8.4.35)(stylelint@16.2.1) + version: 14.0.0(postcss@8.4.38)(stylelint@16.3.1) stylelint-config-standard-scss: specifier: 13.0.0 - version: 13.0.0(postcss@8.4.35)(stylelint@16.2.1) + version: 13.0.0(postcss@8.4.38)(stylelint@16.3.1) surge: specifier: 0.23.1 version: 0.23.1 @@ -2584,36 +2575,6 @@ packages: tslib: 2.6.2 dev: false - /@asymmetrik/ngx-leaflet-markercluster@17.0.0(@angular/common@17.3.0)(@angular/core@17.3.0)(@asymmetrik/ngx-leaflet@17.0.0)(leaflet.markercluster@1.5.3)(leaflet@1.9.4): - resolution: {integrity: sha512-lYp4B3bCBPlYbs8Kz82VFJJ50c2xzF6yL7+sX1bgtY6x094kb5EZvzZLuwczFQ0v1N8nRDfeokKQfZfQ7s47mw==} - peerDependencies: - '@angular/common': '17' - '@angular/core': '17' - '@asymmetrik/ngx-leaflet': '17' - leaflet: '1' - leaflet.markercluster: '1' - dependencies: - '@angular/common': 17.3.0(@angular/core@17.3.0)(rxjs@7.8.1) - '@angular/core': 17.3.0(rxjs@7.8.1)(zone.js@0.14.4) - '@asymmetrik/ngx-leaflet': 17.0.0(@angular/common@17.3.0)(@angular/core@17.3.0)(leaflet@1.9.4) - leaflet: 1.9.4 - leaflet.markercluster: 1.5.3(leaflet@1.9.4) - tslib: 2.6.2 - dev: false - - /@asymmetrik/ngx-leaflet@17.0.0(@angular/common@17.3.0)(@angular/core@17.3.0)(leaflet@1.9.4): - resolution: {integrity: sha512-Tg09780yg1pPRR7k9Z0B0Fb3Mr4SMXYfi+hii8S0McHiqiUqkB+ZhhB4hJq83v4cuvcYgZjtkz+p06lCJY/z+w==} - peerDependencies: - '@angular/common': '17' - '@angular/core': '17' - leaflet: '1' - dependencies: - '@angular/common': 17.3.0(@angular/core@17.3.0)(rxjs@7.8.1) - '@angular/core': 17.3.0(rxjs@7.8.1)(zone.js@0.14.4) - leaflet: 1.9.4 - tslib: 2.6.2 - dev: false - /@awesome-cordova-plugins/calendar@6.6.0(@awesome-cordova-plugins/core@6.6.0)(rxjs@7.8.1): resolution: {integrity: sha512-NobAl4xvmq2zBeOnLI+pqRVpC66p7OpCwd3jzrQ26h8kqhr0o5wqaNcWN6WBjmgD+/AInVnLUzsziL2QpcmD7g==} peerDependencies: @@ -4286,7 +4247,7 @@ packages: /@changesets/apply-release-plan@6.1.4: resolution: {integrity: sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/config': 2.3.1 '@changesets/get-version-range-type': 0.3.2 '@changesets/git': 2.0.0 @@ -4304,7 +4265,7 @@ packages: /@changesets/assemble-release-plan@5.2.4: resolution: {integrity: sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/errors': 0.1.4 '@changesets/get-dependents-graph': 1.3.6 '@changesets/types': 5.2.1 @@ -4388,7 +4349,7 @@ packages: /@changesets/get-release-plan@3.0.17: resolution: {integrity: sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/assemble-release-plan': 5.2.4 '@changesets/config': 2.3.1 '@changesets/pre': 1.0.14 @@ -4404,7 +4365,7 @@ packages: /@changesets/git@2.0.0: resolution: {integrity: sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/errors': 0.1.4 '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 @@ -4429,7 +4390,7 @@ packages: /@changesets/pre@1.0.14: resolution: {integrity: sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/errors': 0.1.4 '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 @@ -4439,7 +4400,7 @@ packages: /@changesets/read@0.5.9: resolution: {integrity: sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/git': 2.0.0 '@changesets/logger': 0.0.5 '@changesets/parse': 0.3.16 @@ -4460,7 +4421,7 @@ packages: /@changesets/write@0.2.3: resolution: {integrity: sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/types': 5.2.1 fs-extra: 7.0.1 human-id: 1.0.2 @@ -4658,6 +4619,10 @@ packages: engines: {node: '>=10.0.0'} dev: true + /@dual-bundle/import-meta-resolve@4.0.0: + resolution: {integrity: sha512-ZKXyJeFAzcpKM2kk8ipoGIPUqx9BX52omTGnfwjJvxOCaZTM2wtDK7zN0aIgPRbT9XYAlha0HtmZ+XKteuh0Gw==} + dev: true + /@effect/schema@0.56.1(effect@2.0.0-next.62)(fast-check@3.15.0): resolution: {integrity: sha512-cfEyHLXPdzSKzJU/yYrPjFd0iVHPydh+NT0sgTe4bzXbcvOsKZuvQ86cAAwXN7lxY0N5cPes9ACxUxTdkEaNlw==} peerDependencies: @@ -5926,7 +5891,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.23.2 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -5934,6 +5899,69 @@ packages: read-yaml-file: 1.1.0 dev: true + /@mapbox/geojson-rewind@0.5.2: + resolution: {integrity: sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA==} + hasBin: true + dependencies: + get-stream: 6.0.1 + minimist: 1.2.8 + dev: false + + /@mapbox/jsonlint-lines-primitives@2.0.2: + resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} + engines: {node: '>= 0.6'} + dev: false + + /@mapbox/point-geometry@0.1.0: + resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} + dev: false + + /@mapbox/tiny-sdf@2.0.6: + resolution: {integrity: sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==} + dev: false + + /@mapbox/unitbezier@0.0.1: + resolution: {integrity: sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==} + dev: false + + /@mapbox/vector-tile@1.3.1: + resolution: {integrity: sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==} + dependencies: + '@mapbox/point-geometry': 0.1.0 + dev: false + + /@mapbox/whoots-js@3.1.0: + resolution: {integrity: sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==} + engines: {node: '>=6.0.0'} + dev: false + + /@maplibre/maplibre-gl-style-spec@20.1.1: + resolution: {integrity: sha512-z85ARNPCBI2Cs5cPOS3DSbraTN+ue8zrcYVoSWBuNrD/mA+2SKAJ+hIzI22uN7gac6jBMnCdpPKRxS/V0KSZVQ==} + hasBin: true + dependencies: + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/unitbezier': 0.0.1 + json-stringify-pretty-compact: 4.0.0 + minimist: 1.2.8 + rw: 1.3.3 + sort-object: 3.0.3 + dev: false + + /@maplibre/ngx-maplibre-gl@17.4.1(@angular/common@17.3.0)(@angular/core@17.3.0)(maplibre-gl@4.0.2)(rxjs@7.8.1): + resolution: {integrity: sha512-FpMph7i03ZHMtZ7yOyUFuFcU/0T0bcTQrHFu9M6vm6DxxsB45Zk/slSwQmuP/c28ntVzuJBzlKf/ivltYNYyoA==} + peerDependencies: + '@angular/common': '>= 17.0.0' + '@angular/core': '>= 17.0.0' + maplibre-gl: '>= 3.6.0' + rxjs: '>= 7.8.1' + dependencies: + '@angular/common': 17.3.0(@angular/core@17.3.0)(rxjs@7.8.1) + '@angular/core': 17.3.0(rxjs@7.8.1)(zone.js@0.14.4) + maplibre-gl: 4.0.2 + rxjs: 7.8.1 + tslib: 2.6.2 + dev: false + /@ngtools/webpack@17.3.0(@angular/compiler-cli@17.3.0)(typescript@5.4.2)(webpack@5.90.3): resolution: {integrity: sha512-wNTCDPPEtjP4mxYerLVLCMwOCTEOD2HqZMVXD8pJbarrGPMuoyglUZuqNSIS5KVqR+fFez6JEUnMvC3QSqf58w==} engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} @@ -6843,9 +6871,19 @@ packages: dependencies: '@types/node': 18.15.3 + /@types/geojson-vt@3.2.5: + resolution: {integrity: sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==} + dependencies: + '@types/geojson': 1.0.6 + dev: false + /@types/geojson@1.0.6: resolution: {integrity: sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==} + /@types/geojson@7946.0.14: + resolution: {integrity: sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==} + dev: false + /@types/glob@8.1.0: resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==} dependencies: @@ -6951,17 +6989,23 @@ packages: - supports-color dev: true - /@types/leaflet.markercluster@1.5.4: - resolution: {integrity: sha512-tfMP8J62+wfsVLDLGh5Zh1JZxijCaBmVsMAX78MkLPwvPitmZZtSin5aWOVRhZrCS+pEOZwNzexbfWXlY+7yjg==} - dependencies: - '@types/leaflet': 1.9.8 - dev: true - /@types/leaflet@1.9.8: resolution: {integrity: sha512-EXdsL4EhoUtGm2GC2ZYtXn+Fzc6pluVgagvo2VC1RHWToLGlTRwVYoDpqS/7QXa01rmDyBjJk3Catpf60VMkwg==} dependencies: '@types/geojson': 1.0.6 - dev: true + dev: false + + /@types/mapbox__point-geometry@0.1.4: + resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==} + dev: false + + /@types/mapbox__vector-tile@1.3.4: + resolution: {integrity: sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==} + dependencies: + '@types/geojson': 1.0.6 + '@types/mapbox__point-geometry': 0.1.4 + '@types/pbf': 3.0.5 + dev: false /@types/mdast@3.0.15: resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} @@ -7035,6 +7079,10 @@ packages: /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + /@types/pbf@3.0.5: + resolution: {integrity: sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==} + dev: false + /@types/promise-queue@2.2.0: resolution: {integrity: sha512-9QLtid6GxEWqpF+QImxBRG6bSVOHtpAm2kXuIyEvZBbSOupLvqhhJv8uaHbS8kUL8FDjzH3RWcSyC/52WOVtGw==} dev: false @@ -7168,6 +7216,12 @@ packages: '@types/node': 18.15.3 dev: true + /@types/supercluster@7.1.3: + resolution: {integrity: sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==} + dependencies: + '@types/geojson': 1.0.6 + dev: false + /@types/supertest@2.0.12: resolution: {integrity: sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ==} dependencies: @@ -7926,6 +7980,11 @@ packages: dequal: 2.0.3 dev: true + /arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + dev: false + /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: @@ -7990,6 +8049,11 @@ packages: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} dev: true + /assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + dev: false + /ast-transform@0.0.0: resolution: {integrity: sha512-e/JfLiSoakfmL4wmTGPjv0HpTICVmxwXgYOB8x+mzozHL8v+dSfCbrJ8J8hJ0YBP0XcYu1aLZ6b/3TnxNK3P2A==} dependencies: @@ -8488,6 +8552,19 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + /bytewise-core@1.2.3: + resolution: {integrity: sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==} + dependencies: + typewise-core: 1.2.0 + dev: false + + /bytewise@1.1.0: + resolution: {integrity: sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ==} + dependencies: + bytewise-core: 1.2.3 + typewise: 1.0.3 + dev: false + /c8@7.14.0: resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} engines: {node: '>=10.12.0'} @@ -10533,6 +10610,10 @@ packages: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: true + /earcut@2.2.4: + resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} + dev: false + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -11345,6 +11426,21 @@ packages: type: 2.7.2 dev: true + /extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + dependencies: + is-extendable: 0.1.1 + dev: false + + /extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + dependencies: + assign-symbols: 1.0.0 + is-extendable: 1.0.1 + dev: false + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} dev: true @@ -11460,6 +11556,10 @@ packages: pend: 1.2.0 dev: true + /fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + dev: false + /figures@2.0.0: resolution: {integrity: sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==} engines: {node: '>=4'} @@ -11866,6 +11966,10 @@ packages: engines: {node: '>=6.9.0'} dev: true + /geojson-vt@3.2.1: + resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} + dev: false + /geojson@0.5.0: resolution: {integrity: sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==} engines: {node: '>= 0.10'} @@ -11955,6 +12059,11 @@ packages: - supports-color dev: true + /get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + dev: false + /getos@3.2.1: resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} dependencies: @@ -12006,6 +12115,10 @@ packages: resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} dev: true + /gl-matrix@3.4.3: + resolution: {integrity: sha512-wcCp8vu8FT22BnvKVPjXa/ICBWRq/zjFfdofZy1WSpQZpphblv12/bOQLBC1rMM7SGOFS9ltVmKOHil5+Ml7gA==} + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -12107,7 +12220,6 @@ packages: ini: 1.3.8 kind-of: 6.0.3 which: 1.3.1 - dev: true /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -12728,7 +12840,6 @@ packages: /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /ini@2.0.0: resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} @@ -12983,6 +13094,18 @@ packages: resolution: {integrity: sha512-SpMppC2XR3YdxSzczXReBjqs2zGscWQpBIKqwXYBFic0ERaxNVgwLCHwOLZeESfdJQjX0RDvrJ1lBXX2ij+G1Q==} dev: false + /is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + dev: false + + /is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + dependencies: + is-plain-object: 2.0.4 + dev: false + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -13067,7 +13190,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: isobject: 3.0.1 - dev: true /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} @@ -13203,7 +13325,6 @@ packages: /isobject@3.0.1: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} - dev: true /isstream@0.1.2: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} @@ -13435,6 +13556,10 @@ packages: /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + /json-stringify-pretty-compact@4.0.0: + resolution: {integrity: sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==} + dev: false + /json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -13629,6 +13754,10 @@ packages: dev: false optional: true + /kdbush@4.0.2: + resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} + dev: false + /keycharm@0.2.0: resolution: {integrity: sha512-i/XBRTiLqRConPKioy2oq45vbv04e8x59b0mnsIRQM+7Ec/8BC7UcL5pnC4FMeGb8KwG7q4wOMw7CtNZf5tiIg==} dev: true @@ -13653,7 +13782,6 @@ packages: /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - dev: true /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -13673,6 +13801,10 @@ packages: resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==} dev: true + /known-css-properties@0.30.0: + resolution: {integrity: sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==} + dev: true + /launch-editor@2.6.1: resolution: {integrity: sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==} dependencies: @@ -13691,18 +13823,6 @@ packages: engines: {node: '> 0.8'} dev: true - /leaflet.markercluster@1.5.3(leaflet@1.9.4): - resolution: {integrity: sha512-vPTw/Bndq7eQHjLBVlWpnGeLa3t+3zGiuM7fJwCkiMFq+nmRuG3RI3f7f4N4TDX7T4NpbAXpR2+NTRSEGfCSeA==} - peerDependencies: - leaflet: ^1.3.1 - dependencies: - leaflet: 1.9.4 - dev: false - - /leaflet@1.9.4: - resolution: {integrity: sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==} - dev: false - /leek@0.0.24: resolution: {integrity: sha512-6PVFIYXxlYF0o6hrAsHtGpTmi06otkwNrMcmQ0K96SeSRHPREPa9J3nJZ1frliVH7XT0XFswoJFQoXsDukzGNQ==} dependencies: @@ -13790,8 +13910,6 @@ packages: peerDependenciesMeta: webpack: optional: true - webpack-sources: - optional: true dependencies: webpack: 5.90.3(esbuild@0.20.1) webpack-sources: 3.2.3 @@ -14212,6 +14330,38 @@ packages: resolution: {integrity: sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==} dev: true + /maplibre-gl@4.0.2: + resolution: {integrity: sha512-1HlJJyfPIbAwK1OlNzKDyuNf1NKlEwsjZZhPYpazX4yoP6ud1aC7DNct62fMSkn+hd6mRekIqzYEzIfOCC31QQ==} + engines: {node: '>=16.14.0', npm: '>=8.1.0'} + dependencies: + '@mapbox/geojson-rewind': 0.5.2 + '@mapbox/jsonlint-lines-primitives': 2.0.2 + '@mapbox/point-geometry': 0.1.0 + '@mapbox/tiny-sdf': 2.0.6 + '@mapbox/unitbezier': 0.0.1 + '@mapbox/vector-tile': 1.3.1 + '@mapbox/whoots-js': 3.1.0 + '@maplibre/maplibre-gl-style-spec': 20.1.1 + '@types/geojson': 7946.0.14 + '@types/geojson-vt': 3.2.5 + '@types/mapbox__point-geometry': 0.1.4 + '@types/mapbox__vector-tile': 1.3.4 + '@types/pbf': 3.0.5 + '@types/supercluster': 7.1.3 + earcut: 2.2.4 + geojson-vt: 3.2.1 + gl-matrix: 3.4.3 + global-prefix: 3.0.0 + kdbush: 4.0.2 + murmurhash-js: 1.0.0 + pbf: 3.2.1 + potpack: 2.0.0 + quickselect: 2.0.0 + supercluster: 8.0.1 + tinyqueue: 2.0.3 + vt-pbf: 3.1.3 + dev: false + /marked@1.2.9: resolution: {integrity: sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==} engines: {node: '>= 8.16.2'} @@ -14236,8 +14386,8 @@ packages: hasBin: true dev: false - /material-symbols@0.17.0: - resolution: {integrity: sha512-CwDddz58cIH/svt8/wjAegQTp9bfNNIkIPjkkr0MAmA1oMlmUkG+C2ss2/yR22mlDzUX4DnXIq5MrgcpKTXoyA==} + /material-symbols@0.17.1: + resolution: {integrity: sha512-1kJan8t3U3Fmuu/YPu2MVsL/ODSja71o+J7ODROQfMaCzzal0izY4SATafEKgXUXU+jL0zIiBQdyzsno7vXBvA==} dev: false /mathml-tag-names@2.1.3: @@ -14957,6 +15107,10 @@ packages: thunky: 1.1.0 dev: true + /murmurhash-js@1.0.0: + resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} + dev: false + /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true @@ -16039,6 +16193,14 @@ packages: through: 2.3.8 dev: true + /pbf@3.2.1: + resolution: {integrity: sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==} + hasBin: true + dependencies: + ieee754: 1.2.1 + resolve-protobuf-schema: 2.1.0 + dev: false + /pdfjs-dist@2.12.313: resolution: {integrity: sha512-1x6iXO4Qnv6Eb+YFdN5JdUzt4pAkxSp3aLAYPX93eQCyg/m7QFzXVWJHJVtoW48CI8HCXju4dSkhQZwoheL5mA==} peerDependencies: @@ -16135,6 +16297,13 @@ packages: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} + /pmtiles@3.0.3: + resolution: {integrity: sha512-tj4l3HHJd6/qf9VefzlPK2eYEQgbf+4uXPzNlrj3k7hHvLtibYSxfp51TF6ALt4YezM8MCdiOminnHvdAyqyGg==} + dependencies: + '@types/leaflet': 1.9.8 + fflate: 0.8.2 + dev: false + /png-js@1.0.0: resolution: {integrity: sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==} dev: true @@ -16238,22 +16407,22 @@ packages: resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==} dev: true - /postcss-safe-parser@7.0.0(postcss@8.4.35): + /postcss-safe-parser@7.0.0(postcss@8.4.38): resolution: {integrity: sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==} engines: {node: '>=18.0'} peerDependencies: postcss: ^8.4.31 dependencies: - postcss: 8.4.35 + postcss: 8.4.38 dev: true - /postcss-scss@4.0.9(postcss@8.4.35): + /postcss-scss@4.0.9(postcss@8.4.38): resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.4.29 dependencies: - postcss: 8.4.35 + postcss: 8.4.38 dev: true /postcss-selector-parser@6.0.13: @@ -16293,6 +16462,19 @@ packages: source-map-js: 1.0.2 dev: true + /postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.2.0 + dev: true + + /potpack@2.0.0: + resolution: {integrity: sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==} + dev: false + /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} engines: {node: '>=10'} @@ -16439,6 +16621,10 @@ packages: hammerjs: 2.0.8 dev: true + /protocol-buffers-schema@3.6.0: + resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + dev: false + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -16563,6 +16749,10 @@ packages: engines: {node: '>=10'} dev: false + /quickselect@2.0.0: + resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} + dev: false + /quote-stream@1.0.2: resolution: {integrity: sha512-kKr2uQ2AokadPjvTyKJQad9xELbZwYzWlNfI3Uz2j/ib5u6H9lDP7fUUR//rMycd0gv4Z5P1qXMfXR8YpIxrjQ==} hasBin: true @@ -16769,7 +16959,7 @@ packages: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} dependencies: - resolve: 1.22.2 + resolve: 1.22.8 dev: false /redent@3.0.0: @@ -16936,6 +17126,12 @@ packages: engines: {node: '>=8'} dev: true + /resolve-protobuf-schema@2.1.0: + resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} + dependencies: + protocol-buffers-schema: 3.6.0 + dev: false + /resolve-url-loader@5.0.0: resolution: {integrity: sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==} engines: {node: '>=12'} @@ -16966,7 +17162,6 @@ packages: is-core-module: 2.13.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true /responselike@3.0.0: resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} @@ -17101,7 +17296,6 @@ packages: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} requiresBuild: true dev: false - optional: true /rxjs@6.6.7: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} @@ -17355,6 +17549,16 @@ packages: has-property-descriptors: 1.0.2 dev: true + /set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 2.0.1 + is-extendable: 0.1.1 + is-plain-object: 2.0.4 + split-string: 3.1.0 + dev: false + /setprototypeof@1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} dev: true @@ -17672,11 +17876,38 @@ packages: ip: 2.0.0 smart-buffer: 4.2.0 + /sort-asc@0.2.0: + resolution: {integrity: sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==} + engines: {node: '>=0.10.0'} + dev: false + + /sort-desc@0.2.0: + resolution: {integrity: sha512-NqZqyvL4VPW+RAxxXnB8gvE1kyikh8+pR+T+CXLksVRN9eiQqkQlPwqWYU0mF9Jm7UnctShlxLyAt1CaBOTL1w==} + engines: {node: '>=0.10.0'} + dev: false + + /sort-object@3.0.3: + resolution: {integrity: sha512-nK7WOY8jik6zaG9CRwZTaD5O7ETWDLZYMM12pqY8htll+7dYeqGfEUPcUBHOpSJg2vJOrvFIY2Dl5cX2ih1hAQ==} + engines: {node: '>=0.10.0'} + dependencies: + bytewise: 1.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + sort-asc: 0.2.0 + sort-desc: 0.2.0 + union-value: 1.0.1 + dev: false + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} dev: true + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + dev: true + /source-map-loader@5.0.0(webpack@5.90.3): resolution: {integrity: sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==} engines: {node: '>= 18.12.0'} @@ -17811,6 +18042,13 @@ packages: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} dev: false + /split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + dependencies: + extend-shallow: 3.0.2 + dev: false + /split2@3.2.2: resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} dependencies: @@ -18087,26 +18325,26 @@ packages: through: 2.3.8 dev: true - /stylelint-config-clean-order@5.4.1(stylelint@16.2.1): + /stylelint-config-clean-order@5.4.1(stylelint@16.3.1): resolution: {integrity: sha512-C9E94vFk7QKqPshXik3iNU5cYz7vm0Up4/wu1biRjThWLWJ3gYRdXfyV/1fFU7u4ThfSIf2/ijNhk0pf0ErPWQ==} peerDependencies: stylelint: '>=14' dependencies: - stylelint: 16.2.1(typescript@5.4.2) - stylelint-order: 6.0.4(stylelint@16.2.1) + stylelint: 16.3.1(typescript@5.4.2) + stylelint-order: 6.0.4(stylelint@16.3.1) dev: true - /stylelint-config-prettier-scss@1.0.0(stylelint@16.2.1): + /stylelint-config-prettier-scss@1.0.0(stylelint@16.3.1): resolution: {integrity: sha512-Gr2qLiyvJGKeDk0E/+awNTrZB/UtNVPLqCDOr07na/sLekZwm26Br6yYIeBYz3ulsEcQgs5j+2IIMXCC+wsaQA==} engines: {node: 14.* || 16.* || >= 18} hasBin: true peerDependencies: stylelint: '>=15.0.0' dependencies: - stylelint: 16.2.1(typescript@5.4.2) + stylelint: 16.3.1(typescript@5.4.2) dev: true - /stylelint-config-recommended-scss@14.0.0(postcss@8.4.35)(stylelint@16.2.1): + /stylelint-config-recommended-scss@14.0.0(postcss@8.4.38)(stylelint@16.3.1): resolution: {integrity: sha512-HDvpoOAQ1RpF+sPbDOT2Q2/YrBDEJDnUymmVmZ7mMCeNiFSdhRdyGEimBkz06wsN+HaFwUh249gDR+I9JR7Onw==} engines: {node: '>=18.12.0'} peerDependencies: @@ -18116,23 +18354,23 @@ packages: postcss: optional: true dependencies: - postcss: 8.4.35 - postcss-scss: 4.0.9(postcss@8.4.35) - stylelint: 16.2.1(typescript@5.4.2) - stylelint-config-recommended: 14.0.0(stylelint@16.2.1) - stylelint-scss: 6.2.1(stylelint@16.2.1) + postcss: 8.4.38 + postcss-scss: 4.0.9(postcss@8.4.38) + stylelint: 16.3.1(typescript@5.4.2) + stylelint-config-recommended: 14.0.0(stylelint@16.3.1) + stylelint-scss: 6.2.1(stylelint@16.3.1) dev: true - /stylelint-config-recommended@14.0.0(stylelint@16.2.1): + /stylelint-config-recommended@14.0.0(stylelint@16.3.1): resolution: {integrity: sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==} engines: {node: '>=18.12.0'} peerDependencies: stylelint: ^16.0.0 dependencies: - stylelint: 16.2.1(typescript@5.4.2) + stylelint: 16.3.1(typescript@5.4.2) dev: true - /stylelint-config-standard-scss@13.0.0(postcss@8.4.35)(stylelint@16.2.1): + /stylelint-config-standard-scss@13.0.0(postcss@8.4.38)(stylelint@16.3.1): resolution: {integrity: sha512-WaLvkP689qSYUpJQPCo30TFJSSc3VzvvoWnrgp+7PpVby5o8fRUY1cZcP0sePZfjrFl9T8caGhcKg0GO34VDiQ==} engines: {node: '>=18.12.0'} peerDependencies: @@ -18142,33 +18380,33 @@ packages: postcss: optional: true dependencies: - postcss: 8.4.35 - stylelint: 16.2.1(typescript@5.4.2) - stylelint-config-recommended-scss: 14.0.0(postcss@8.4.35)(stylelint@16.2.1) - stylelint-config-standard: 36.0.0(stylelint@16.2.1) + postcss: 8.4.38 + stylelint: 16.3.1(typescript@5.4.2) + stylelint-config-recommended-scss: 14.0.0(postcss@8.4.38)(stylelint@16.3.1) + stylelint-config-standard: 36.0.0(stylelint@16.3.1) dev: true - /stylelint-config-standard@36.0.0(stylelint@16.2.1): + /stylelint-config-standard@36.0.0(stylelint@16.3.1): resolution: {integrity: sha512-3Kjyq4d62bYFp/Aq8PMKDwlgUyPU4nacXsjDLWJdNPRUgpuxALu1KnlAHIj36cdtxViVhXexZij65yM0uNIHug==} engines: {node: '>=18.12.0'} peerDependencies: stylelint: ^16.1.0 dependencies: - stylelint: 16.2.1(typescript@5.4.2) - stylelint-config-recommended: 14.0.0(stylelint@16.2.1) + stylelint: 16.3.1(typescript@5.4.2) + stylelint-config-recommended: 14.0.0(stylelint@16.3.1) dev: true - /stylelint-order@6.0.4(stylelint@16.2.1): + /stylelint-order@6.0.4(stylelint@16.3.1): resolution: {integrity: sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==} peerDependencies: stylelint: ^14.0.0 || ^15.0.0 || ^16.0.1 dependencies: postcss: 8.4.35 postcss-sorting: 8.0.2(postcss@8.4.35) - stylelint: 16.2.1(typescript@5.4.2) + stylelint: 16.3.1(typescript@5.4.2) dev: true - /stylelint-scss@6.2.1(stylelint@16.2.1): + /stylelint-scss@6.2.1(stylelint@16.3.1): resolution: {integrity: sha512-ZoGLbVb1keZYRVGQlhB8G6sZOoNqw61whzzzGFWp05N12ErqLFfBv3JPrXiMLZaW98sBS7K/vUQhRnvUj4vwdw==} engines: {node: '>=18.12.0'} peerDependencies: @@ -18179,11 +18417,11 @@ packages: postcss-resolve-nested-selector: 0.1.1 postcss-selector-parser: 6.0.16 postcss-value-parser: 4.2.0 - stylelint: 16.2.1(typescript@5.4.2) + stylelint: 16.3.1(typescript@5.4.2) dev: true - /stylelint@16.2.1(typescript@5.4.2): - resolution: {integrity: sha512-SfIMGFK+4n7XVAyv50CpVfcGYWG4v41y6xG7PqOgQSY8M/PgdK0SQbjWFblxjJZlN9jNq879mB4BCZHJRIJ1hA==} + /stylelint@16.3.1(typescript@5.4.2): + resolution: {integrity: sha512-/JOwQnBvxEKOT2RtNgGpBVXnCSMBgKOL2k7w0K52htwCyJls4+cHvc4YZgXlVoAZS9QJd2DgYAiRnja96pTgxw==} engines: {node: '>=18.12.0'} hasBin: true dependencies: @@ -18191,6 +18429,7 @@ packages: '@csstools/css-tokenizer': 2.2.4 '@csstools/media-query-list-parser': 2.1.9(@csstools/css-parser-algorithms@2.6.1)(@csstools/css-tokenizer@2.2.4) '@csstools/selector-specificity': 3.0.2(postcss-selector-parser@6.0.16) + '@dual-bundle/import-meta-resolve': 4.0.0 balanced-match: 2.0.0 colord: 2.9.3 cosmiconfig: 9.0.0(typescript@5.4.2) @@ -18207,15 +18446,15 @@ packages: ignore: 5.3.1 imurmurhash: 0.1.4 is-plain-object: 5.0.0 - known-css-properties: 0.29.0 + known-css-properties: 0.30.0 mathml-tag-names: 2.1.3 meow: 13.2.0 micromatch: 4.0.5 normalize-path: 3.0.0 picocolors: 1.0.0 - postcss: 8.4.35 + postcss: 8.4.38 postcss-resolve-nested-selector: 0.1.1 - postcss-safe-parser: 7.0.0(postcss@8.4.35) + postcss-safe-parser: 7.0.0(postcss@8.4.38) postcss-selector-parser: 6.0.16 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 @@ -18290,6 +18529,12 @@ packages: - supports-color dev: true + /supercluster@8.0.1: + resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==} + dependencies: + kdbush: 4.0.2 + dev: false + /supertest@6.3.3: resolution: {integrity: sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==} engines: {node: '>=6.4.0'} @@ -18642,6 +18887,10 @@ packages: resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} dev: true + /tinyqueue@2.0.3: + resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} + dev: false + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -19170,6 +19419,16 @@ packages: engines: {node: '>=14.17'} hasBin: true + /typewise-core@1.2.0: + resolution: {integrity: sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg==} + dev: false + + /typewise@1.0.3: + resolution: {integrity: sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==} + dependencies: + typewise-core: 1.2.0 + dev: false + /ua-parser-js@0.7.36: resolution: {integrity: sha512-CPPLoCts2p7D8VbybttE3P2ylv0OBZEAy7a12DsulIEcAiMtWJy+PBgMXgWDI80D5UwqE8oQPHYnk13tm38M2Q==} dev: true @@ -19242,6 +19501,16 @@ packages: tiny-inflate: 1.0.3 dev: true + /union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + dependencies: + arr-union: 3.1.0 + get-value: 2.0.6 + is-extendable: 0.1.1 + set-value: 2.0.1 + dev: false + /union@0.5.0: resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==} engines: {node: '>= 0.8.0'} @@ -19546,6 +19815,14 @@ packages: resolution: {integrity: sha512-eOpPHogvorZRobNqJGhapa0JdwaxpjVvyBp0QIUMRMSf8ZAlqOdEquKuRmw9Qwu0qXtJIWqFtMkmvJjUZmMjVA==} dev: true + /vt-pbf@3.1.3: + resolution: {integrity: sha512-2LzDFzt0mZKZ9IpVF2r69G9bXaP2Q2sArJCmcCgvfTdCCZzSyz4aCLoQyUilu37Ll56tCblIZrXFIjNUpGIlmA==} + dependencies: + '@mapbox/point-geometry': 0.1.0 + '@mapbox/vector-tile': 1.3.1 + pbf: 3.2.1 + dev: false + /wait-on@6.0.1: resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} engines: {node: '>=10.0.0'} @@ -19842,7 +20119,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: true /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}