From 641d2b39a337bb9590938235cf2dd2b2fdf7d115 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 25 Oct 2024 20:46:57 +0100 Subject: [PATCH 01/44] feat: wip forecast page updates --- .../src/app/pages/forecast/forecast.page.html | 27 +++++--------- .../src/app/pages/forecast/forecast.page.scss | 22 ------------ .../src/app/pages/forecast/forecast.page.ts | 36 ++++++++++++++++--- 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index 716c5c0cf..ab82a74d9 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -7,22 +7,13 @@ } -
- - -
{{'Annual Forecast' | translate}}
-
- - assessment - -
- - -
{{'Downscaled Forecast' | translate}}
-
- - map - -
-
+

{{'Seasonal Forecast' | translate}}

+ @for(forecast of seasonalForecasts(); track forecast.id){ + + } + +

{{'Downscaled Forecasts' | translate}}

+ @for(forecast of downscaledForecasts(); track forecast.id){ + {{forecast.title}} + } diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss index d9d420b71..c5f086962 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss @@ -1,25 +1,3 @@ -.card-container { - display: flex; - flex-direction: row; - justify-content: center; - gap: 48px; - flex-wrap: wrap; -} - -.mat-card { - min-width: 200px; - display: flex; - cursor: pointer; - justify-content: center; - align-items: center; -} -.card-content { - display: flex; - padding: 1rem; - width: 100%; - align-items: center; - justify-content: center; -} .pdf-container { position: fixed; z-index: 2; diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index fc0a0fe8c..ca3a499e4 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -1,8 +1,12 @@ import { CommonModule } from '@angular/common'; -import { Component } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { Component, effect, signal } from '@angular/core'; +import { ConfigurationService } from '@picsa/configuration'; +import { ICountryCode } from '@picsa/data'; +import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; +import { IResourceFile } from '@picsa/resources/src/app/schemas'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; +import { SupabaseStorageService } from '@picsa/shared/services/core/supabase/services/supabase-storage.service'; import { ClimateToolComponentsModule } from '../../components/climate-tool-components.module'; @@ -11,13 +15,37 @@ import { ClimateToolComponentsModule } from '../../components/climate-tool-compo templateUrl: './forecast.page.html', styleUrls: ['./forecast.page.scss'], standalone: true, - imports: [CommonModule, ClimateToolComponentsModule, PicsaTranslateModule, PdfViewerComponent], + imports: [ + CommonModule, + ClimateToolComponentsModule, + PicsaTranslateModule, + PdfViewerComponent, + ResourcesComponentsModule, + ], }) export class ClimateForecastComponent { forecastTypes = ['Annual', 'Downscaled']; public page = 1; public pdfSrc?: string; - constructor(private route: ActivatedRoute) {} + + public seasonalForecasts = signal([]); + + public downscaledForecasts = signal([]); + + constructor(private configurationService: ConfigurationService, private storageService: SupabaseStorageService) { + effect( + () => { + const { country_code } = this.configurationService.deploymentSettings(); + this.loadForecasts(country_code); + }, + { allowSignalWrites: true } + ); + } + + private loadForecasts(country_code: ICountryCode) { + // TODO + } + // ngOnInit() {} openAnnualForeCast() { this.pdfSrc = '/assets/forecast-assets/forecastDoc.pdf'; From 6efe06c2137b1473b21e9ea6bea6c45932343f2f Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 25 Oct 2024 20:47:15 +0100 Subject: [PATCH 02/44] chore: update pre-commit hook --- .husky/pre-commit | 3 --- 1 file changed, 3 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 5a182ef10..372362317 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - yarn lint-staged From 339cbc5f85a64c85d2e553abbaf6947ebaff7302 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 6 Feb 2025 10:23:03 -0800 Subject: [PATCH 03/44] chore: code tidying --- .../src/app/pages/home/home.page.ts | 21 +++++------- .../station-select.component.ts | 3 +- .../module-home/module-home.component.ts | 34 ++++++++----------- .../photo-view/photo-view.component.ts | 29 +++++++--------- 4 files changed, 37 insertions(+), 50 deletions(-) diff --git a/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts b/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts index 7e34d2cfa..4dce2d9e0 100644 --- a/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts +++ b/apps/picsa-apps/extension-app/src/app/pages/home/home.page.ts @@ -15,17 +15,14 @@ export class HomePageComponent { showContent = signal(false); constructor(public configurationService: ConfigurationService, router: Router) { - effect( - () => { - // navigate to /extension or /farmer tool home if configured - const { deployment_id, user_type } = this.configurationService.userSettings(); - if (deployment_id && user_type) { - router.navigate(['/', user_type], { replaceUrl: true }); - } else { - this.showContent.set(true); - } - }, - { allowSignalWrites: true } - ); + effect(() => { + // navigate to /extension or /farmer tool home if configured + const { deployment_id, user_type } = this.configurationService.userSettings(); + if (deployment_id && user_type) { + router.navigate(['/', user_type], { replaceUrl: true }); + } else { + this.showContent.set(true); + } + }); } } diff --git a/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts b/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts index 783623e9e..2b36bc76d 100644 --- a/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts +++ b/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts @@ -57,8 +57,7 @@ export class CropProbabilityStationSelectComponent { if (stationOptions.length > 0) { this.handleStationChange(stationOptions[0].id); } - }, - { allowSignalWrites: true } + } ); } diff --git a/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts b/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts index 5d8aa3a82..59ee91aa0 100644 --- a/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts +++ b/apps/picsa-tools/farmer-content/src/app/pages/module-home/module-home.component.ts @@ -68,27 +68,21 @@ export class FarmerContentModuleHomeComponent implements OnInit, OnDestroy { private tourService: TourService ) { // load content on slug change and fix tour implementation - effect( - (onCleanup) => { - const { slug } = this.params() || {}; - this.loadContentBySlug(slug); - // update the tour service to allow triggering tour from inside mat-tab component - this.tourService.useInMatTab = true; - onCleanup(() => { - this.tourService.useInMatTab = false; - }); - }, - { allowSignalWrites: true } - ); + effect((onCleanup) => { + const { slug } = this.params() || {}; + this.loadContentBySlug(slug); + // update the tour service to allow triggering tour from inside mat-tab component + this.tourService.useInMatTab = true; + onCleanup(() => { + this.tourService.useInMatTab = false; + }); + }); // If tool tab selected handle side-effects (routing and header) - effect( - () => { - const selectedTabIndex = this.selectedIndex(); - const contentBlocks = this.tabs()[selectedTabIndex]; - this.handleContentChangeEffects(contentBlocks); - }, - { allowSignalWrites: true } - ); + effect(() => { + const selectedTabIndex = this.selectedIndex(); + const contentBlocks = this.tabs()[selectedTabIndex]; + this.handleContentChangeEffects(contentBlocks); + }); } ngOnInit() { diff --git a/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts b/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts index 34ad4b1bf..db02296e4 100644 --- a/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts +++ b/libs/shared/src/features/photo/components/photo-view/photo-view.component.ts @@ -26,22 +26,19 @@ export class PhotoViewComponent { @ViewChild('dialogTemplate') dialogTemplate!: TemplateRef; constructor(private service: PhotoService, private dialog: PicsaDialogService, public photoDialog: MatDialog) { - effect( - async (onCleanup) => { - const photo = this.photo; - const uri = await this.service.getPhotoAttachment(photo().id); - if (uri) { - this.uri.set(uri); - } else { - console.error('[Photo] not found', this.photo); - this.errorMsg.set(`Photo not found`); - } - onCleanup(() => { - this.service.revokePhotoAttachment(photo().id); - }); - }, - { allowSignalWrites: true } - ); + effect(async (onCleanup) => { + const photo = this.photo; + const uri = await this.service.getPhotoAttachment(photo().id); + if (uri) { + this.uri.set(uri); + } else { + console.error('[Photo] not found', this.photo); + this.errorMsg.set(`Photo not found`); + } + onCleanup(() => { + this.service.revokePhotoAttachment(photo().id); + }); + }); } openPhotoDialog() { From 782bcbdc4237750555e863c4c8982632a8520e24 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 6 Feb 2025 10:23:32 -0800 Subject: [PATCH 04/44] feat: cliamte forecasts app schema --- .../src/app/pages/forecast/forecast.types.ts | 4 +++ .../src/app/pages/forecast/schemas/index.ts | 6 ++++ .../app/pages/forecast/schemas/schema_v0.ts | 33 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.types.ts create mode 100644 apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts create mode 100644 apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.types.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.types.ts new file mode 100644 index 000000000..3736d70db --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.types.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line @nx/enforce-module-boundaries +import { Database } from '@picsa/server-types'; + +export type IClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts new file mode 100644 index 000000000..f52534f3f --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts @@ -0,0 +1,6 @@ +import * as schema from './schema_v0'; + +// Re-export schema to provide latest version without need to refactor additonal code + +export const CLIMATE_FORECAST_COLLECTION = schema.COLLECTION_V0; +export const CLIMATE_FORECAST_SCHEMA = schema.SCHEMA_V0; diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts new file mode 100644 index 000000000..a57b10178 --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts @@ -0,0 +1,33 @@ +import type { IPicsaCollectionCreator } from '@picsa/shared/services/core/db_v2'; +import { RxJsonSchema } from 'rxdb'; + +import { IClimateForecastRow } from '../forecast.types'; + +const SCHEMA_VERSION = 0; + +export const SCHEMA_V0: RxJsonSchema = { + title: 'climate_forecasts', + version: SCHEMA_VERSION, + keyCompression: false, + type: 'object', + properties: { + country_code: { type: 'string' }, + created_at: { type: 'string' }, + forecast_type: { type: 'string' }, + id: { type: 'string' }, + language_code: { type: 'string' }, + location: { type: 'string' }, + mimetype: { type: 'string' }, + storage_file: { type: 'string' }, + updated_at: { type: 'string' }, + }, + required: ['id'], + primaryKey: 'id', +}; + +export const COLLECTION_V0: IPicsaCollectionCreator = { + schema: SCHEMA_V0, + isUserCollection: false, + migrationStrategies: {}, + attachments: {}, +}; From 19c8ba97d6bbeed1e14506becba97b36aceec5fd Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 6 Feb 2025 14:08:01 -0800 Subject: [PATCH 05/44] feat: forecast storage backend function --- .../supabase/functions/_shared/request.ts | 6 +- ...ecast-update.ts => climate-forecast-db.ts} | 22 ++-- .../dashboard/climate-forecast-storage.ts | 100 ++++++++++++++++++ .../supabase/functions/dashboard/index.ts | 9 +- .../supabase/functions/dashboard/types.ts | 10 ++ ...50127193000_forecast_update_cron copy.sql} | 4 +- 6 files changed, 130 insertions(+), 21 deletions(-) rename apps/picsa-server/supabase/functions/dashboard/{climate-forecast-update.ts => climate-forecast-db.ts} (80%) create mode 100644 apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts create mode 100644 apps/picsa-server/supabase/functions/dashboard/types.ts rename apps/picsa-server/supabase/migrations/{20250127193000_forecast_update_cron.sql => 20250127193000_forecast_update_cron copy.sql} (79%) diff --git a/apps/picsa-server/supabase/functions/_shared/request.ts b/apps/picsa-server/supabase/functions/_shared/request.ts index a4bc5247d..46d2cc367 100644 --- a/apps/picsa-server/supabase/functions/_shared/request.ts +++ b/apps/picsa-server/supabase/functions/_shared/request.ts @@ -9,11 +9,11 @@ export const getFormData = async (req: Request): Promise
=> { return { fields: {}, files: {} }; }; -export const getJsonData = async (req: Request): Promise> => { +export const getJsonData = async >(req: Request): Promise => { if (req.headers.has('content-type') && req.headers.get('content-type')?.startsWith('application/json')) { const json = await req.json(); - return json; + return json as T; } console.error('Request does not contain json body'); - return {}; + return {} as T; }; diff --git a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-update.ts b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts similarity index 80% rename from apps/picsa-server/supabase/functions/dashboard/climate-forecast-update.ts rename to apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts index 0b93b4ceb..16e08eb3f 100644 --- a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-update.ts +++ b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts @@ -1,12 +1,9 @@ -import type { Database } from '../../types/index.ts'; -import type { - paths as climateApiPaths, - components as climateApiComponents, -} from '../../../../picsa-apps/dashboard/src/app/modules/climate/types/api.d.ts'; import { getClient } from '../_shared/client.ts'; import { getJsonData } from '../_shared/request.ts'; import { JSONResponse } from '../_shared/response.ts'; +import type { climateApiPaths, IApiClimateForecast, IDBClimateForecastInsert } from './types.ts'; + /** * Read the endpoint from env. Note, if running climate api in local docker container update `.env` to: * ```env @@ -14,20 +11,17 @@ import { JSONResponse } from '../_shared/response.ts'; * ``` * https://github.com/orgs/supabase/discussions/9837 */ -const CLIMATE_API_ENDPOINT = Deno.env.get('CLIMATE_API_ENDPOINT') || 'https://api.epicsa.idems.international'; -const COUNTRY_CODES = ['mw', 'zm']; +export const CLIMATE_API_ENDPOINT = Deno.env.get('CLIMATE_API_ENDPOINT') || 'https://api.epicsa.idems.international'; +export const COUNTRY_CODES = ['mw', 'zm']; // Create typed fetch client from open-api definition exported by climate api import createClient from 'openapi-fetch'; -const apiClient = createClient({ baseUrl: CLIMATE_API_ENDPOINT, mode: 'cors' }); - -type IDBClimateForecast = Database['public']['Tables']['climate_forecasts']['Insert']; -type IApiClimateForecast = climateApiComponents['schemas']['DocumentMetadata']; +export const apiClient = createClient({ baseUrl: CLIMATE_API_ENDPOINT, mode: 'cors' }); /** - * Update + * Update cliamte forecast db rows */ -export const climateForecastUpdate = async (req: Request) => { +export const climateForecastDB = async (req: Request) => { // Validate body formData // TODO - Improve validators and feedback let { country_codes = COUNTRY_CODES, query_prefix } = await getJsonData(req); @@ -100,7 +94,7 @@ async function getDBForecasts(query: { country_code: string; query_prefix: strin return data; } -function mapApiForecastToDb(apiForecasts: IApiClimateForecast[], country_code: string): IDBClimateForecast[] { +function mapApiForecastToDb(apiForecasts: IApiClimateForecast[], country_code: string): IDBClimateForecastInsert[] { return apiForecasts.map((v) => ({ country_code, id: v.name, diff --git a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts new file mode 100644 index 000000000..bcb2e3962 --- /dev/null +++ b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts @@ -0,0 +1,100 @@ +import { getClient } from '../_shared/client.ts'; +import { getJsonData } from '../_shared/request.ts'; +import { JSONResponse } from '../_shared/response.ts'; +import { apiClient } from './climate-forecast-db.ts'; +import { IDBClimateForecastRow } from './types.ts'; + +interface IReqParams { + /** + * Max number of documents to retrieve. As requests are run in parallel smaller number + * reduces server workload. Default 5 + */ + limit?: number; +} + +/** + * Handle downloading forecast files from api and populating to supabase storage entry + * Checks DB for any entries without storage files and attempts to update + */ +export const climateForecastStorage = async (req: Request) => { + // ensure api up and running before sending batched requests + await apiClient.GET('/v1/status/'); + const params = await getJsonData(req); + const res = await new ClimateForecastStorageUpdate().populateStorageFiles(params); + return JSONResponse(res); +}; + +class ClimateForecastStorageUpdate { + supabaseClient = getClient(); + + private get table() { + return this.supabaseClient.from('climate_forecasts'); + } + + async populateStorageFiles(params: IReqParams) { + const { limit = 5 } = params; + const pending = await this.listPendingFiles(limit); + + const updates: IDBClimateForecastRow[] = []; + const errors: any[] = []; + // TODO - make parallel and allow failure + for (const { country_code, id } of pending) { + const { data, error } = await this.storeForecast(country_code, id); + if (error) { + errors.push(error); + } + if (data) { + updates.push(data); + } + } + return { data: updates, error: errors }; + } + + /** Check all climate forecast db entries for any that are missing corresponding storage files */ + private async listPendingFiles(limit = 5) { + const query = this.table.select('*').is('storage_file', null).order('id', { ascending: false }).limit(limit); + const { data, error } = await query; + if (error) { + throw error; + } + return data; + } + + /** Retrieve forecast data from API, store to supabase storage and update DB */ + private async storeForecast( + country_code: string, + id: string + ): Promise<{ data?: IDBClimateForecastRow; error?: any }> { + const supabaseClient = getClient(); + // download from api + const req = apiClient.GET('/v1/documents/{country}/{filepath}', { + params: { path: { country: country_code as any, filepath: id } }, + parseAs: 'blob', + }); + const { data: fileData, response: apiResponse, error: apiError } = await req; + if (apiError) { + return { error: apiError }; + } + if (fileData) { + // upload to supabase storage + const contentType = apiResponse.headers.get('content-type') as string; + const { data: uploadData, error: uploadError } = await supabaseClient.storage + .from(country_code) + .upload(`climate/forecasts/${id}`, fileData, { contentType, upsert: true }); + if (uploadError) { + return { error: uploadError }; + } + // update db entry + const { data: updateData, error: updateError } = await this.updateForecastDBStorageEntry(id, uploadData.fullPath); + if (updateError) { + return { error: updateError }; + } + return { data: updateData?.[0] }; + } + return { error: `No filedata found for ${id}` }; + } + + private updateForecastDBStorageEntry(id: string, storage_file: string) { + return this.table.update({ storage_file }).eq('id', id).select(); + } +} diff --git a/apps/picsa-server/supabase/functions/dashboard/index.ts b/apps/picsa-server/supabase/functions/dashboard/index.ts index a321407ff..952ff99a8 100644 --- a/apps/picsa-server/supabase/functions/dashboard/index.ts +++ b/apps/picsa-server/supabase/functions/dashboard/index.ts @@ -3,7 +3,8 @@ // This enables autocomplete, go to definition, etc. import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; -import { climateForecastUpdate } from './climate-forecast-update.ts'; +import { climateForecastStorage } from './climate-forecast-storage.ts'; +import { climateForecastDB } from './climate-forecast-db.ts'; import { corsHeaders } from '../_shared/cors.ts'; serve((req) => { @@ -18,8 +19,10 @@ serve((req) => { const endpoint = req.url.split('/').pop(); switch (endpoint) { - case 'climate-forecast-update': - return climateForecastUpdate(req); + case 'climate-forecast-db': + return climateForecastDB(req); + case 'climate-forecast-storage': + return climateForecastStorage(req); default: return new Response(`Invalid endpoint: ${endpoint}`, { diff --git a/apps/picsa-server/supabase/functions/dashboard/types.ts b/apps/picsa-server/supabase/functions/dashboard/types.ts new file mode 100644 index 000000000..f34b8a9ec --- /dev/null +++ b/apps/picsa-server/supabase/functions/dashboard/types.ts @@ -0,0 +1,10 @@ +import type { Database } from '../../types/index.ts'; +import type { paths, components } from '../../../../picsa-apps/dashboard/src/app/modules/climate/types/api.d.ts'; + +export type climateApiPaths = paths; +export type climateApiComponents = components; + +export type IDBClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; +export type IDBClimateForecastInsert = Database['public']['Tables']['climate_forecasts']['Insert']; + +export type IApiClimateForecast = climateApiComponents['schemas']['DocumentMetadata']; diff --git a/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron.sql b/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql similarity index 79% rename from apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron.sql rename to apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql index 4b614c71a..d03d972ae 100644 --- a/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron.sql +++ b/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql @@ -7,7 +7,9 @@ grant all privileges on all tables in schema cron to postgres; -- Trigger backend edge function every 30 minutes -- Adapted from https://supabase.com/docs/guides/functions/schedule-functions -select cron.schedule('climate_forecasts_update', '30 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-update','{}'::jsonb); $$); +select cron.schedule('climate_forecasts_db', '30 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-db','{}'::jsonb); $$); + +select cron.schedule('climate_forecasts_storage', '35 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-storage','{}'::jsonb); $$); -- Alt implementation (intermediate function created to structure more complex requests, kept for future reference) From 5f5d2d240fe7bc014aca7dfcd0456ebc0a8cb72a Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 6 Feb 2025 14:08:34 -0800 Subject: [PATCH 06/44] chore: code tidying --- .../pages/forecast/forecast.component.ts | 2 +- .../extension-app/src/app/app.component.ts | 5 ++- .../src/app/components/layout.ts | 31 +++++++-------- .../src/app/pages/site-view/site-view.page.ts | 39 +++++++++---------- 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts index c11faa0b6..7e21fa17a 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts @@ -121,7 +121,7 @@ export class ClimateForecastPageComponent { formData.append('country_code', country_code); formData.append('query_prefix', this.apiQueryPrefix()); const { data, error } = await this.supabase.functions - .invoke('dashboard/climate-forecast-update', { + .invoke('dashboard/climate-forecast-db', { method: 'POST', body: formData, }) diff --git a/apps/picsa-apps/extension-app/src/app/app.component.ts b/apps/picsa-apps/extension-app/src/app/app.component.ts index 73233a3d3..90fa35342 100644 --- a/apps/picsa-apps/extension-app/src/app/app.component.ts +++ b/apps/picsa-apps/extension-app/src/app/app.component.ts @@ -1,6 +1,7 @@ /* eslint-disable @nx/enforce-module-boundaries */ import { AfterViewInit, Component, Injector, OnInit, signal } from '@angular/core'; import { Router } from '@angular/router'; +import { Capacitor } from '@capacitor/core'; import { ENVIRONMENT } from '@picsa/environments'; import { PicsaMigrationService } from '@picsa/migrations'; import { MonitoringToolService } from '@picsa/monitoring/src/app/services/monitoring-tool.service'; @@ -50,7 +51,9 @@ export class AppComponent implements OnInit, AfterViewInit { this.monitoringService.ready(); // delay push notification as will prompt for permissions setTimeout(() => { - this.pushNotificationService.initializePushNotifications(); + if (Capacitor.isNativePlatform()) { + this.pushNotificationService.initializePushNotifications(); + } }, 1000); } diff --git a/apps/picsa-apps/extension-app/src/app/components/layout.ts b/apps/picsa-apps/extension-app/src/app/components/layout.ts index cb3c05397..c27d36155 100644 --- a/apps/picsa-apps/extension-app/src/app/components/layout.ts +++ b/apps/picsa-apps/extension-app/src/app/components/layout.ts @@ -53,24 +53,21 @@ export class AppLayoutComponent { componentService: PicsaCommonComponentsService, viewContainer: ViewContainerRef ) { - effect( - () => { - // Inject menu button into global header when on farmer or extension home - const { cdkPortalStart } = componentService.headerOptions(); - if (this.showMenuButton()) { - if (!cdkPortalStart) { - componentService.patchHeader({ - cdkPortalStart: new TemplatePortal(this.menuButtonTemplate(), viewContainer), - }); - } - } else { - if (cdkPortalStart) { - componentService.patchHeader({ cdkPortalStart: undefined }); - } + effect(() => { + // Inject menu button into global header when on farmer or extension home + const { cdkPortalStart } = componentService.headerOptions(); + if (this.showMenuButton()) { + if (!cdkPortalStart) { + componentService.patchHeader({ + cdkPortalStart: new TemplatePortal(this.menuButtonTemplate(), viewContainer), + }); } - }, - { allowSignalWrites: true } - ); + } else { + if (cdkPortalStart) { + componentService.patchHeader({ cdkPortalStart: undefined }); + } + } + }); } public toggleUserType() { diff --git a/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts index dd949c956..0c6ce4c19 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/site-view/site-view.page.ts @@ -65,29 +65,26 @@ export class ClimateSiteViewComponent implements OnDestroy, AfterViewInit { private viewContainer: ViewContainerRef, private cdr: ChangeDetectorRef ) { - effect( - async () => { - const viewId = this.viewId(); - const siteId = this.siteId(); - if (siteId && viewId) { - // same site, just view changed - if (siteId === this._siteId) { - await this.loadView(viewId); - } - // site changed - else { - this._siteId = siteId; - await this.chartService.setStation(siteId); - await this.loadView(viewId); - await _wait(50); - this.checkOrientation(); - } + effect(async () => { + const viewId = this.viewId(); + const siteId = this.siteId(); + if (siteId && viewId) { + // same site, just view changed + if (siteId === this._siteId) { + await this.loadView(viewId); } + // site changed + else { + this._siteId = siteId; + await this.chartService.setStation(siteId); + await this.loadView(viewId); + await _wait(50); + this.checkOrientation(); + } + } - this.cdr.markForCheck(); - }, - { allowSignalWrites: true } - ); + this.cdr.markForCheck(); + }); } ngAfterViewInit() { From af4da4cb64dd70fbf7ac5da508534059d5995744 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 11:42:11 -0800 Subject: [PATCH 07/44] feat: add supabase-storage-download component --- .../supabase-storage-download.component.html | 1 + .../supabase-storage-download.component.scss | 0 ...upabase-storage-download.component.spec.ts | 22 +++++ .../supabase-storage-download.component.ts | 91 +++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.html create mode 100644 libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.scss create mode 100644 libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.spec.ts create mode 100644 libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts diff --git a/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.html b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.html new file mode 100644 index 000000000..6dbc74306 --- /dev/null +++ b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.html @@ -0,0 +1 @@ + diff --git a/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.scss b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.spec.ts b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.spec.ts new file mode 100644 index 000000000..31740c5b1 --- /dev/null +++ b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SupabaseStorageDownloadComponent } from './supabase-storage-download.component'; + +describe('SupabaseStorageDownloadComponent', () => { + let component: SupabaseStorageDownloadComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SupabaseStorageDownloadComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(SupabaseStorageDownloadComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts new file mode 100644 index 000000000..867486870 --- /dev/null +++ b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts @@ -0,0 +1,91 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectionStrategy, Component, input, output, signal } from '@angular/core'; +import ky, { KyResponse } from 'ky'; +import { BehaviorSubject, filter, firstValueFrom, map } from 'rxjs'; + +import { SupabaseService } from '../../supabase.service'; + +/** + * Component to handle downloading of a file from supabase storage + * NOTE - it does not render any UI elements itself, but can access + * download `progress()` signal to display custom UI + * + * @example + * ```html + * + * Progress: {{progress()}} + * + * ``` + */ +@Component({ + selector: 'picsa-supabase-storage-download', + imports: [CommonModule], + templateUrl: './supabase-storage-download.component.html', + styleUrl: './supabase-storage-download.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SupabaseStorageDownloadComponent { + /** Storage file path */ + storage_path = input.required(); + + /** Signal of download progress */ + public progress = signal(undefined); + + /** Promise that resolves when download is complete */ + public completed = () => + firstValueFrom( + this.completed$.pipe( + filter((v) => v === true), + map(() => ({ error: this.error, data: this.data })) + ) + ); + + // Internals + private controller: AbortController; + private error: any; + private completed$: BehaviorSubject; + private data: Blob | Record; + + constructor(private service: SupabaseService) {} + + public async start() { + this.progress.set(0); + this.completed$ = new BehaviorSubject(false); + + await this.service.ready(); + const [bucketId, ...pathSegments] = this.storage_path().split('/'); + const url = this.service.storage.getPublicLink(bucketId, pathSegments.join('/')); + const controller = new AbortController(); + return ky(url, { + signal: controller.signal, + onDownloadProgress: (progress) => { + this.progress.set(progress.percent); + }, + }).then( + async (res) => { + this.data = await this.getResData(res); + this.completed$.next(true); + }, + (err) => { + console.error(err); + this.error = err; + this.completed$.next(true); + } + ); + } + + public stop() { + if (this.controller) { + this.controller.abort(); + } + } + + private async getResData(res: KyResponse) { + const contentType = res.headers.get('content-type'); + // TODO - support more content types (possibly via input) + if (contentType === 'application/json') { + return res.json() as Record; + } + return res.blob(); + } +} From a229de831ad0340fa545fa637b700b7231a335ab Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 11:42:47 -0800 Subject: [PATCH 08/44] feat: add ky lib --- .../shared/src/services/core/supabase/components/index.ts | 1 + package.json | 1 + yarn.lock | 8 ++++++++ 3 files changed, 10 insertions(+) diff --git a/libs/shared/src/services/core/supabase/components/index.ts b/libs/shared/src/services/core/supabase/components/index.ts index 8ad6b3ecd..97cd00bb1 100644 --- a/libs/shared/src/services/core/supabase/components/index.ts +++ b/libs/shared/src/services/core/supabase/components/index.ts @@ -1,2 +1,3 @@ +export * from './storage-download/supabase-storage-download.component'; export * from './storage-file-picker/storage-file-picker.component'; export * from './upload/supabase-upload.component'; diff --git a/package.json b/package.json index c624d7ac0..966015b7a 100644 --- a/package.json +++ b/package.json @@ -105,6 +105,7 @@ "html2canvas": "^1.4.1", "intro.js": "^7.2.0", "jwt-decode": "^4.0.0", + "ky": "^1.7.4", "leaflet": "^1.9.4", "lottie-web": "^5.12.2", "mobx": "^6.13.5", diff --git a/yarn.lock b/yarn.lock index e17a948ac..aff7ef00f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16315,6 +16315,13 @@ __metadata: languageName: node linkType: hard +"ky@npm:^1.7.4": + version: 1.7.4 + resolution: "ky@npm:1.7.4" + checksum: 10c0/8b28b85cbee6d3e073ff796b92661f4bf155ec9b9a131411de1c34fb2f89f8507e67ff3df369e3c6d18714134774e8735e88cba72b19d005a09112b800d14474 + languageName: node + linkType: hard + "launch-editor@npm:^2.6.1": version: 2.9.1 resolution: "launch-editor@npm:2.9.1" @@ -19110,6 +19117,7 @@ __metadata: jsonc-eslint-parser: "npm:^2.4.0" jszip: "npm:^3.10.1" jwt-decode: "npm:^4.0.0" + ky: "npm:^1.7.4" leaflet: "npm:^1.9.4" lint-staged: "npm:^13.2.1" lottie-web: "npm:^5.12.2" From 67b774709262d1984bbb717df3237f8daf80f62d Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 11:44:03 -0800 Subject: [PATCH 09/44] feat: wip forecast page --- .../src/app/pages/forecast/forecast.page.html | 25 ++++- .../src/app/pages/forecast/forecast.page.ts | 95 ++++++++++++++----- 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index ab82a74d9..59830c6ee 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -1,12 +1,33 @@
@if(pdfSrc){ - - + + }
+

{{'Daily Forecast' | translate}}

+
+ @for(forecast of dailyForecasts(); track forecast.id){ +
+ @if(!forecast.downloaded && forecast.storage_file){ + +
progress: {{downloader.progress()}}
+
+ } + +
{{forecast.label}}
+
+ } +
+

{{'Seasonal Forecast' | translate}}

@for(forecast of seasonalForecasts(); track forecast.id){ diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index 85d05bd41..b52343b61 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -1,14 +1,24 @@ import { CommonModule } from '@angular/common'; -import { Component, effect, signal } from '@angular/core'; +import { Component, computed, effect, OnDestroy, signal, viewChildren } from '@angular/core'; import { ConfigurationService } from '@picsa/configuration'; -import { ICountryCode } from '@picsa/data'; import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; import { IResourceFile } from '@picsa/resources/src/app/schemas'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; -import { SupabaseStorageService } from '@picsa/shared/services/core/supabase/services/supabase-storage.service'; +import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; +import { RxDocument } from 'rxdb'; import { ClimateToolComponentsModule } from '../../components/climate-tool-components.module'; +import { ClimateForecastService } from './forecast.service'; +import { IClimateForecastRow } from './forecast.types'; + +interface IForecastSummary { + _doc: RxDocument; + id: string; + label: string; + downloaded: boolean; + storage_file: string | null; +} @Component({ selector: 'climate-forecast', @@ -20,39 +30,80 @@ import { ClimateToolComponentsModule } from '../../components/climate-tool-compo PicsaTranslateModule, PdfViewerComponent, ResourcesComponentsModule, + SupabaseStorageDownloadComponent, ], }) -export class ClimateForecastComponent { +export class ClimateForecastComponent implements OnDestroy { forecastTypes = ['Annual', 'Downscaled']; - public page = 1; public pdfSrc?: string; + private downloaders = viewChildren(SupabaseStorageDownloadComponent); + + public dailyForecasts = computed(() => + this.service.dailyForecastDocs().map((doc): IForecastSummary => { + const { id, storage_file } = doc; + const label = this.generateForecastLabel(id); + const summary: IForecastSummary = { _doc: doc, id, label, storage_file, downloaded: false }; + if (storage_file) { + summary.downloaded = doc.getAttachment(storage_file) ? true : false; + } + return summary; + }) + ); + public seasonalForecasts = signal([]); public downscaledForecasts = signal([]); - constructor(private configurationService: ConfigurationService, private storageService: SupabaseStorageService) { - effect( - () => { - const { country_code } = this.configurationService.deploymentSettings(); - this.loadForecasts(country_code); - }, - { allowSignalWrites: true } - ); + constructor(private service: ClimateForecastService, private configurationService: ConfigurationService) { + effect(() => { + const { country_code } = this.configurationService.deploymentSettings(); + if (country_code) { + this.service.loadDailyForecasts(country_code); + } + }); } - private loadForecasts(country_code: ICountryCode) { - // TODO + ngOnDestroy() { + this.closeForecast(); } - // ngOnInit() {} - openAnnualForeCast() { - this.pdfSrc = '/assets/forecast-assets/forecastDoc.pdf'; - } - openDownscaledForeCast() { - this.pdfSrc = '/assets/forecast-assets/forecastDoc.pdf'; + public async handleForecastClick(forecast: IForecastSummary) { + if (forecast.downloaded) { + this.openForecast(forecast); + } else { + const downloader = this.downloaders().find((d) => d.storage_path() === forecast.storage_file); + if (downloader) { + forecast._doc = await this.service.downloadForecastFile(forecast._doc, downloader); + await this.openForecast(forecast); + } + } } - clearPdf() { + + public closeForecast() { + if (this.pdfSrc) { + URL.revokeObjectURL(this.pdfSrc); + } this.pdfSrc = undefined; } + + private async openForecast(forecast: IForecastSummary) { + const attachment = forecast._doc.getAttachment(forecast.storage_file as string); + if (!attachment) { + throw new Error('Forecast file not found'); + } + const blob = await attachment.getData(); + // TODO - handle html (maybe general file-viewer component) + const uri = URL.createObjectURL(blob); + this.pdfSrc = uri; + } + + private generateForecastLabel(id: string) { + const [timestamp, filename] = id.split('/'); + if (filename) { + const [basename, extension] = filename.split('.'); + return basename.replace(/-/g, ' '); + } + return id; + } } From 8aedca7ddf3a07f4ed2fc2b1e3d237aa61ba25d2 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 11:44:18 -0800 Subject: [PATCH 10/44] feat: wip forecasts service --- .../app/pages/forecast/forecast.service.ts | 99 +++++++++++++++++++ .../app/pages/forecast/schemas/schema_v0.ts | 5 +- .../core/db_v2/db-attachment.service.ts | 8 ++ libs/utils/object.utils.ts | 53 ++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts create mode 100644 libs/utils/object.utils.ts diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts new file mode 100644 index 000000000..742dbd0a2 --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -0,0 +1,99 @@ +import { Injectable, signal } from '@angular/core'; +import { ICountryCode } from '@picsa/data'; +import { PicsaDatabase_V2_Service } from '@picsa/shared/services/core/db_v2'; +import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; +import { isEqual } from '@picsa/utils/object.utils'; +import { RxCollection, RxDocument } from 'rxdb'; + +import { IClimateForecastRow } from './forecast.types'; +import { CLIMATE_FORECAST_COLLECTION } from './schemas'; + +/** + * TODOs + * - include forecast_type in all requests and make generic for daily, seasonal and downscaled + * - storage file download/open (convert to resource) + * - UI improvements (re-use existing collection?) + * - Improved downscaled forecast filters + */ + +@Injectable({ providedIn: 'root' }) +export class ClimateForecastService { + public dailyForecastDocs = signal[]>([], { equal: isEqual }); + + private get table() { + return this.supabaseService.db.table('climate_forecasts'); + } + private get dbCollection() { + return this.dbService.db.collections['climate_forecasts'] as RxCollection; + } + + constructor(private supabaseService: SupabaseService, private dbService: PicsaDatabase_V2_Service) {} + + public async loadDailyForecasts(country_code: ICountryCode) { + if (country_code) { + await this.dbService.ensureCollections({ + climate_forecasts: CLIMATE_FORECAST_COLLECTION, + }); + // populate any forecasts that are in the cache + const cachedForecasts = await this.loadCachedForecasts(country_code); + this.dailyForecastDocs.set(cachedForecasts); + // load new forecasts from the server + const serverForecasts = await this.loadServerForecasts(country_code, cachedForecasts[0]); + if (serverForecasts.length > 0) { + const saved = await this.saveForecasts(serverForecasts); + this.dailyForecastDocs.update((v) => [...saved, ...v]); + } + } + } + + public async downloadForecastFile( + doc: RxDocument, + downloaderUI: SupabaseStorageDownloadComponent + ) { + await downloaderUI.start(); + const { error, data } = await downloaderUI.completed(); + if (error) { + // TODO - handle + console.error(error); + throw new Error(`Download failed: ${error.message}`); + } + if (data && data instanceof Blob) { + const attachmentId = downloaderUI.storage_path(); + doc.putAttachment({ id: attachmentId, data, type: data.type }); + } + return doc; + } + + private async loadCachedForecasts(country_code: string) { + // only filter if non-global country used + const selector = country_code === 'global' ? {} : { country_code }; + const cached = await this.dbCollection.find({ selector, sort: [{ id: 'desc' }], limit: 5 }).exec(); + return cached; + } + + private async saveForecasts(forecasts: IClimateForecastRow[]) { + const saved = await this.dbCollection.bulkUpsert(forecasts); + return saved; + } + + private async loadServerForecasts(country_code: string, latest?: IClimateForecastRow) { + await this.supabaseService.ready(); + // only retrieve forecasts that have storage files stored + // NOTE - these are populated on a separate cron schedule to forecast db entries + const query = this.table.select('*').neq('storage_file', null); + if (country_code !== 'global') { + query.eq('country_code', country_code); + } + if (latest) { + query.gt('id', latest.id); + } + const { data, error } = await query.order('id', { ascending: false }).limit(5); + console.log('server latest', latest?.id, data); + if (error) { + console.error(error); + // TODO - handle error + throw error; + } + return data; + } +} diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts index a57b10178..703faa535 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts @@ -23,11 +23,14 @@ export const SCHEMA_V0: RxJsonSchema = { }, required: ['id'], primaryKey: 'id', + attachments: { + encrypted: false, + compression: undefined, + }, }; export const COLLECTION_V0: IPicsaCollectionCreator = { schema: SCHEMA_V0, isUserCollection: false, migrationStrategies: {}, - attachments: {}, }; diff --git a/libs/shared/src/services/core/db_v2/db-attachment.service.ts b/libs/shared/src/services/core/db_v2/db-attachment.service.ts index 8fbdd23f7..ada644fd0 100644 --- a/libs/shared/src/services/core/db_v2/db-attachment.service.ts +++ b/libs/shared/src/services/core/db_v2/db-attachment.service.ts @@ -9,6 +9,13 @@ import { PicsaDatabase_V2_Service } from './db.service'; import { ATTACHMENTS_COLLECTION, IAttachment } from './schemas/attachments'; /********************************************************************************************* + * @deprecated v3.50.0 + * The attachment system was creating primarily to store single resource file attachments + * in a separate collection due to limitations in rxdb/dexie attachment handling. + * + * Recent upgrades handle better so reccomend using doc `putAttachment` method directly + * on source documents + * * DB Attachments * Ordinarily RXDB handles attachments within the storage provider, however dexie is not * currently supported. So manual workaround to persist attachment files to separate collection @@ -74,6 +81,7 @@ export class PicsaDatabaseAttachmentService extends PicsaAsyncService { } return null; } + /** * Release a file attachment URI when no longer required * @param attachmentNames specific resource attachmentNames to revoke diff --git a/libs/utils/object.utils.ts b/libs/utils/object.utils.ts new file mode 100644 index 000000000..b1bd5071e --- /dev/null +++ b/libs/utils/object.utils.ts @@ -0,0 +1,53 @@ +/** + * Determine whether a value is a literal object type (`{}`) + * Adapted from discussion https://stackoverflow.com/q/1173549 + */ +export function isObjectLiteral(v: any) { + return v ? v.constructor === {}.constructor : false; +} + +/** Check if an object is either empty or contains only empty child */ +export function isEmptyObjectDeep(v: any) { + return isObjectLiteral(v) && Object.values(v).every((x) => isEmptyObjectDeep(x)); +} + +/** Minimal deep equality checker, loosely based on lodash _isEqual but for simple primitives only */ +export function isEqual(a: any, b: any) { + // handle simple string, boolean, number, undefined, null or same object reference + if (a === b) return true; + // handle different object types + if (typeof a !== typeof b) return false; + // handle deep comparison for arrays + if (Array.isArray(a) && Array.isArray(b)) { + if (a.length !== b.length) return false; + // find the first element index where there is a mismatch + // if all elements are the same `findIndex` returns value -1 + const differentIndex = a.findIndex((v, i) => !isEqual(v, b[i])); + return differentIndex === -1; + } + // handle deep comparison for literal objects + if (isObjectLiteral(a) && isObjectLiteral(b)) { + // assert if equal if same properties but in different order + const aSorted = sortJsonKeys(a); + const bSorted = sortJsonKeys(b); + if (!isEqual(Object.keys(aSorted), Object.keys(bSorted))) return false; + return isEqual(Object.values(aSorted), Object.values(bSorted)); + } + // NOTE - does not compare symbols, date objects, functions, buffers etc. + return false; +} + +/** Order a nested json object literal in alphabetical key order */ +export const sortJsonKeys = >(json: T): T => { + // return non json-type data as-is + if (!isObjectLiteral(json)) { + return json; + } + // recursively sort any nested json by key + return Object.keys(json) + .sort() + .reduce((obj, key) => { + obj[key] = sortJsonKeys(json[key]); + return obj; + }, {}) as T; +}; From 852f38ea95c4e24437869ab365248a0bb06128da Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 12:37:44 -0800 Subject: [PATCH 11/44] chore: pin capacitor-video-player version fixes issue due to invalid regex when detecting extension. PR open to fix https://github.com/harmonwood/capacitor-video-player/pull/179 --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 966015b7a..d742cac53 100644 --- a/package.json +++ b/package.json @@ -87,7 +87,7 @@ "@uppy/tus": "^3.4.0", "c3": "^0.7.20", "capacitor-blob-writer": "^1.1.16", - "capacitor-video-player": "^6.0.2", + "capacitor-video-player": "6.0.0", "cordova-plugin-file": "^8.1.3", "cordova-plugin-file-opener2": "^4.0.0", "cordova-plugin-x-socialsharing": "^6.0.4", diff --git a/yarn.lock b/yarn.lock index aff7ef00f..f95bc4dae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10035,13 +10035,13 @@ __metadata: languageName: node linkType: hard -"capacitor-video-player@npm:^6.0.2": - version: 6.0.2 - resolution: "capacitor-video-player@npm:6.0.2" +"capacitor-video-player@npm:6.0.0": + version: 6.0.0 + resolution: "capacitor-video-player@npm:6.0.0" peerDependencies: "@capacitor/core": ^6.0.0 hls.js: ^1.4.0 - checksum: 10c0/0473def80440d5391d22b52554dead468612b69847422ab4f86914cd028157af94cf433bf3cca3cdeedde8aee97caa51d11942f106b94f4c9a02ae64d2108c92 + checksum: 10c0/b7abc6cc5e6cdf967ae0f2754107b6d7f04b628c5ac119f9156cd26a6b60fe24eea83e98a60badd82a7b277930c5f0fdd583ad67084901a94480f468cdec57dc languageName: node linkType: hard @@ -19079,7 +19079,7 @@ __metadata: autoprefixer: "npm:^10.4.20" c3: "npm:^0.7.20" capacitor-blob-writer: "npm:^1.1.16" - capacitor-video-player: "npm:^6.0.2" + capacitor-video-player: "npm:6.0.0" cordova-plugin-file: "npm:^8.1.3" cordova-plugin-file-opener2: "npm:^4.0.0" cordova-plugin-x-socialsharing: "npm:^6.0.4" From 78e3243f2b4bbc8433e1fe4e8a1df9b6b726b6a5 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 14:35:04 -0800 Subject: [PATCH 12/44] chore: rxdb16 update --- .../climate-tool/src/app/pages/forecast/forecast.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts index 742dbd0a2..9b2eafb30 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -40,8 +40,8 @@ export class ClimateForecastService { // load new forecasts from the server const serverForecasts = await this.loadServerForecasts(country_code, cachedForecasts[0]); if (serverForecasts.length > 0) { - const saved = await this.saveForecasts(serverForecasts); - this.dailyForecastDocs.update((v) => [...saved, ...v]); + const { success, error } = await this.saveForecasts(serverForecasts); + this.dailyForecastDocs.update((v) => [...success, ...v]); } } } From da257fc2fd4d4d81ccbc92a3daccd4372f125b3f Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 13 Feb 2025 19:30:46 -0800 Subject: [PATCH 13/44] feat: pdf forecast download and view --- .../src/app/pages/forecast/forecast.page.ts | 18 +++++++++++++++--- .../src/app/pages/forecast/forecast.service.ts | 9 +++++++-- .../app/pages/forecast/schemas/schema_v0.ts | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index b52343b61..e788e7b20 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -69,13 +69,20 @@ export class ClimateForecastComponent implements OnDestroy { } public async handleForecastClick(forecast: IForecastSummary) { + // open downloaded forecast if (forecast.downloaded) { this.openForecast(forecast); - } else { + } + // download and open new forecast + else { const downloader = this.downloaders().find((d) => d.storage_path() === forecast.storage_file); if (downloader) { - forecast._doc = await this.service.downloadForecastFile(forecast._doc, downloader); - await this.openForecast(forecast); + await this.service.downloadForecastFile(forecast._doc, downloader); + await this.refreshForecastData(); + const updated = this.dailyForecasts().find(({ id }) => id === forecast.id); + if (updated?.downloaded) { + this.openForecast(updated); + } } } } @@ -87,6 +94,11 @@ export class ClimateForecastComponent implements OnDestroy { this.pdfSrc = undefined; } + private refreshForecastData() { + const { country_code } = this.configurationService.deploymentSettings(); + return this.service.loadDailyForecasts(country_code); + } + private async openForecast(forecast: IForecastSummary) { const attachment = forecast._doc.getAttachment(forecast.storage_file as string); if (!attachment) { diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts index 9b2eafb30..2e4f1aa4b 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -41,6 +41,10 @@ export class ClimateForecastService { const serverForecasts = await this.loadServerForecasts(country_code, cachedForecasts[0]); if (serverForecasts.length > 0) { const { success, error } = await this.saveForecasts(serverForecasts); + if (error.length > 0) { + console.error(error); + throw new Error(`[Forecast] failed to load daily forecasts`); + } this.dailyForecastDocs.update((v) => [...success, ...v]); } } @@ -49,7 +53,7 @@ export class ClimateForecastService { public async downloadForecastFile( doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent - ) { + ): Promise> { await downloaderUI.start(); const { error, data } = await downloaderUI.completed(); if (error) { @@ -59,7 +63,8 @@ export class ClimateForecastService { } if (data && data instanceof Blob) { const attachmentId = downloaderUI.storage_path(); - doc.putAttachment({ id: attachmentId, data, type: data.type }); + const { doc: updatedDoc } = await doc.putAttachment({ id: attachmentId, data, type: data.type }); + return updatedDoc; } return doc; } diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts index 703faa535..23a7dc866 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts @@ -16,7 +16,7 @@ export const SCHEMA_V0: RxJsonSchema = { forecast_type: { type: 'string' }, id: { type: 'string' }, language_code: { type: 'string' }, - location: { type: 'string' }, + location: { type: 'array' }, mimetype: { type: 'string' }, storage_file: { type: 'string' }, updated_at: { type: 'string' }, From 3e0dabc9c49a150487f4aa6a90484c93b0c88e65 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 14 Feb 2025 19:52:42 -0800 Subject: [PATCH 14/44] feat: wip forecast page improvements --- .../src/app/pages/forecast/forecast.page.html | 77 +++++++++++++------ .../src/app/pages/forecast/forecast.page.scss | 11 +++ .../src/app/pages/forecast/forecast.page.ts | 36 ++++++--- .../app/pages/forecast/forecast.service.ts | 75 +++++++++++------- .../src/app/pages/forecast/schemas/index.ts | 3 + .../app/pages/forecast/schemas/schema_v0.ts | 34 ++++++-- .../supabase-storage-download.component.ts | 4 +- 7 files changed, 173 insertions(+), 67 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index 59830c6ee..8ed769636 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -9,32 +9,63 @@ }
-

{{'Daily Forecast' | translate}}

-
- @for(forecast of dailyForecasts(); track forecast.id){ -
- @if(!forecast.downloaded && forecast.storage_file){ - -
progress: {{downloader.progress()}}
-
+ +
+

{{'Daily' | translate}}

+
+ @if(dailyForecasts().length===0){ +
+ +
} - -
{{forecast.label}}
+
+ @for(forecast of dailyForecasts(); track forecast.id){ +
+
{{forecast.label}}
+
+ @if(!forecast.downloaded){ + + @if(downloader.progress()===undefined){ + download + } @else{ + + } + + } @else{ + task_alt + } +
+
+ } +
- }
-

{{'Seasonal Forecast' | translate}}

- @for(forecast of seasonalForecasts(); track forecast.id){ - - } + +
+

{{'Seasonal' | translate}}

+
+
...
+
+
-

{{'Downscaled Forecasts' | translate}}

- @for(forecast of downscaledForecasts(); track forecast.id){ - {{forecast.title}} - } + +
+

{{'Downscaled' | translate}}

+
+
+ @if(downscaledForecasts(); as collection){ + + } + +
+
+
diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss index c5f086962..f9d560b7d 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss @@ -1,3 +1,7 @@ +.forecast-container { + @apply border-solid capitalize p-2; +} + .pdf-container { position: fixed; z-index: 2; @@ -14,3 +18,10 @@ .slide-in.active { transform: translateY(0); } + +h2.forecast-heading { + @apply w-full sm:mb-8 sm:w-32 sm:text-left overflow-hidden text-ellipsis; +} +div.forecast-content { + @apply flex-1 overflow-x-auto mx-4 sm:mx-0; +} diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index e788e7b20..3ab2b4433 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -1,8 +1,9 @@ import { CommonModule } from '@angular/common'; import { Component, computed, effect, OnDestroy, signal, viewChildren } from '@angular/core'; +import { MatIcon } from '@angular/material/icon'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; import { ConfigurationService } from '@picsa/configuration'; import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; -import { IResourceFile } from '@picsa/resources/src/app/schemas'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; @@ -10,14 +11,14 @@ import { RxDocument } from 'rxdb'; import { ClimateToolComponentsModule } from '../../components/climate-tool-components.module'; import { ClimateForecastService } from './forecast.service'; -import { IClimateForecastRow } from './forecast.types'; +import { IClimateForecast } from './schemas'; interface IForecastSummary { - _doc: RxDocument; + _doc: RxDocument; id: string; label: string; + storage_file: string; downloaded: boolean; - storage_file: string | null; } @Component({ @@ -27,6 +28,8 @@ interface IForecastSummary { imports: [ CommonModule, ClimateToolComponentsModule, + MatIcon, + MatProgressBarModule, PicsaTranslateModule, PdfViewerComponent, ResourcesComponentsModule, @@ -34,7 +37,6 @@ interface IForecastSummary { ], }) export class ClimateForecastComponent implements OnDestroy { - forecastTypes = ['Annual', 'Downscaled']; public pdfSrc?: string; private downloaders = viewChildren(SupabaseStorageDownloadComponent); @@ -43,7 +45,13 @@ export class ClimateForecastComponent implements OnDestroy { this.service.dailyForecastDocs().map((doc): IForecastSummary => { const { id, storage_file } = doc; const label = this.generateForecastLabel(id); - const summary: IForecastSummary = { _doc: doc, id, label, storage_file, downloaded: false }; + const summary: IForecastSummary = { + _doc: doc, + id, + label, + storage_file: storage_file as string, + downloaded: false, + }; if (storage_file) { summary.downloaded = doc.getAttachment(storage_file) ? true : false; } @@ -51,15 +59,22 @@ export class ClimateForecastComponent implements OnDestroy { }) ); - public seasonalForecasts = signal([]); + public downscaledForecasts = computed(() => { + const collection = this.service.downscaledForecastsCollection(); + if (collection) { + return collection._data; + } + return undefined; + }); - public downscaledForecasts = signal([]); + // HACK - use resources collection for downscaled forecasts + public downscaledForecastsCollection = {}; constructor(private service: ClimateForecastService, private configurationService: ConfigurationService) { effect(() => { const { country_code } = this.configurationService.deploymentSettings(); if (country_code) { - this.service.loadDailyForecasts(country_code); + this.service.loadForecasts(country_code); } }); } @@ -78,6 +93,7 @@ export class ClimateForecastComponent implements OnDestroy { const downloader = this.downloaders().find((d) => d.storage_path() === forecast.storage_file); if (downloader) { await this.service.downloadForecastFile(forecast._doc, downloader); + // refresh data to populated downloads await this.refreshForecastData(); const updated = this.dailyForecasts().find(({ id }) => id === forecast.id); if (updated?.downloaded) { @@ -96,7 +112,7 @@ export class ClimateForecastComponent implements OnDestroy { private refreshForecastData() { const { country_code } = this.configurationService.deploymentSettings(); - return this.service.loadDailyForecasts(country_code); + return this.service.loadForecasts(country_code); } private async openForecast(forecast: IForecastSummary) { diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts index 2e4f1aa4b..676e30c7c 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -1,12 +1,14 @@ import { Injectable, signal } from '@angular/core'; import { ICountryCode } from '@picsa/data'; +import { IResourceCollection } from '@picsa/resources/src/app/schemas'; +import { ResourcesToolService } from '@picsa/resources/src/app/services/resources-tool.service'; import { PicsaDatabase_V2_Service } from '@picsa/shared/services/core/db_v2'; import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { isEqual } from '@picsa/utils/object.utils'; import { RxCollection, RxDocument } from 'rxdb'; import { IClimateForecastRow } from './forecast.types'; -import { CLIMATE_FORECAST_COLLECTION } from './schemas'; +import { CLIMATE_FORECAST_COLLECTION, IClimateForecast, SERVER_DB_MAPPING } from './schemas'; /** * TODOs @@ -18,42 +20,61 @@ import { CLIMATE_FORECAST_COLLECTION } from './schemas'; @Injectable({ providedIn: 'root' }) export class ClimateForecastService { - public dailyForecastDocs = signal[]>([], { equal: isEqual }); + public dailyForecastDocs = signal[]>([], { equal: isEqual }); + + public downscaledForecastsCollection = signal | null>(null); private get table() { return this.supabaseService.db.table('climate_forecasts'); } private get dbCollection() { - return this.dbService.db.collections['climate_forecasts'] as RxCollection; + return this.dbService.db.collections['climate_forecasts'] as RxCollection; } - constructor(private supabaseService: SupabaseService, private dbService: PicsaDatabase_V2_Service) {} + constructor( + private supabaseService: SupabaseService, + private dbService: PicsaDatabase_V2_Service, + private resourcesService: ResourcesToolService + ) {} - public async loadDailyForecasts(country_code: ICountryCode) { + public async loadForecasts(country_code: ICountryCode) { if (country_code) { - await this.dbService.ensureCollections({ - climate_forecasts: CLIMATE_FORECAST_COLLECTION, - }); - // populate any forecasts that are in the cache - const cachedForecasts = await this.loadCachedForecasts(country_code); - this.dailyForecastDocs.set(cachedForecasts); - // load new forecasts from the server - const serverForecasts = await this.loadServerForecasts(country_code, cachedForecasts[0]); - if (serverForecasts.length > 0) { - const { success, error } = await this.saveForecasts(serverForecasts); - if (error.length > 0) { - console.error(error); - throw new Error(`[Forecast] failed to load daily forecasts`); - } - this.dailyForecastDocs.update((v) => [...success, ...v]); + this.loadDailyForecasts(country_code); + this.loadDownscaledForecasts(); + } + } + + private async loadDailyForecasts(country_code: ICountryCode) { + await this.dbService.ensureCollections({ + climate_forecasts: CLIMATE_FORECAST_COLLECTION, + }); + // populate any forecasts that are in the cache + const cachedForecasts = await this.loadCachedForecasts(country_code); + this.dailyForecastDocs.set(cachedForecasts); + // load new forecasts from the server + const serverForecasts = await this.loadServerForecasts(country_code, cachedForecasts[0]); + if (serverForecasts.length > 0) { + const { success, error } = await this.saveForecasts(serverForecasts); + if (error.length > 0) { + console.error(error); + throw new Error(`[Forecast] failed to load daily forecasts`); } + this.dailyForecastDocs.update((v) => [...success, ...v].slice(0, 5)); } } + private async loadDownscaledForecasts() { + // TODO - load hardcoded into service schema instead of resources (?) + // TODO - or integrate into DB (might be better) + await this.resourcesService.ready(); + const downscaled = await this.resourcesService.dbCollections.findOne('forecasts_downscaled').exec(); + this.downscaledForecastsCollection.set(downscaled); + } + public async downloadForecastFile( - doc: RxDocument, + doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent - ): Promise> { + ): Promise> { await downloaderUI.start(); const { error, data } = await downloaderUI.completed(); if (error) { @@ -76,29 +97,29 @@ export class ClimateForecastService { return cached; } - private async saveForecasts(forecasts: IClimateForecastRow[]) { + private async saveForecasts(forecasts: IClimateForecast[]) { const saved = await this.dbCollection.bulkUpsert(forecasts); return saved; } - private async loadServerForecasts(country_code: string, latest?: IClimateForecastRow) { + private async loadServerForecasts(country_code: string, latest?: IClimateForecast): Promise { await this.supabaseService.ready(); // only retrieve forecasts that have storage files stored // NOTE - these are populated on a separate cron schedule to forecast db entries - const query = this.table.select('*').neq('storage_file', null); + const query = this.table.select<'*', IClimateForecastRow>('*').neq('storage_file', null); if (country_code !== 'global') { query.eq('country_code', country_code); } if (latest) { query.gt('id', latest.id); } - const { data, error } = await query.order('id', { ascending: false }).limit(5); + const { data = [], error } = await query.order('id', { ascending: false }).limit(5); console.log('server latest', latest?.id, data); if (error) { console.error(error); // TODO - handle error throw error; } - return data; + return (data || []).map((el) => SERVER_DB_MAPPING(el)); } } diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts index f52534f3f..606f860e6 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts @@ -4,3 +4,6 @@ import * as schema from './schema_v0'; export const CLIMATE_FORECAST_COLLECTION = schema.COLLECTION_V0; export const CLIMATE_FORECAST_SCHEMA = schema.SCHEMA_V0; +export const SERVER_DB_MAPPING = schema.SERVER_DB_MAPPING_V0; + +export type IClimateForecast = schema.IClimateForecast_V0; diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts index 23a7dc866..6ec0ed3dd 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts @@ -1,3 +1,4 @@ +import type { Database } from '@picsa/server-types'; import type { IPicsaCollectionCreator } from '@picsa/shared/services/core/db_v2'; import { RxJsonSchema } from 'rxdb'; @@ -5,23 +6,32 @@ import { IClimateForecastRow } from '../forecast.types'; const SCHEMA_VERSION = 0; -export const SCHEMA_V0: RxJsonSchema = { +// interface adapted from server types +export interface IClimateForecast_V0 { + country_code: string; + forecast_type: Database['public']['Enums']['forecast_type'] | null; + id: string; + language_code: string | null; + location: string[] | null; + mimetype: string | null; + storage_file: string; +} + +export const SCHEMA_V0: RxJsonSchema = { title: 'climate_forecasts', version: SCHEMA_VERSION, keyCompression: false, type: 'object', properties: { country_code: { type: 'string' }, - created_at: { type: 'string' }, forecast_type: { type: 'string' }, id: { type: 'string' }, language_code: { type: 'string' }, location: { type: 'array' }, mimetype: { type: 'string' }, storage_file: { type: 'string' }, - updated_at: { type: 'string' }, }, - required: ['id'], + required: ['id', 'country_code', 'storage_file'], primaryKey: 'id', attachments: { encrypted: false, @@ -29,8 +39,22 @@ export const SCHEMA_V0: RxJsonSchema = { }, }; -export const COLLECTION_V0: IPicsaCollectionCreator = { +export const COLLECTION_V0: IPicsaCollectionCreator = { schema: SCHEMA_V0, isUserCollection: false, migrationStrategies: {}, }; + +export const SERVER_DB_MAPPING_V0 = (row: IClimateForecastRow): IClimateForecast_V0 => { + const { country_code, forecast_type, id, language_code, location, mimetype, storage_file } = row; + return { + country_code, + forecast_type, + id, + language_code, + location, + mimetype, + // null storage files filtered during db query + storage_file: storage_file as string, + }; +}; diff --git a/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts index 867486870..cad713a7a 100644 --- a/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts +++ b/libs/shared/src/services/core/supabase/components/storage-download/supabase-storage-download.component.ts @@ -28,7 +28,7 @@ export class SupabaseStorageDownloadComponent { /** Storage file path */ storage_path = input.required(); - /** Signal of download progress */ + /** Signal of download progress, integer value from 0 to 100 */ public progress = signal(undefined); /** Promise that resolves when download is complete */ @@ -59,7 +59,7 @@ export class SupabaseStorageDownloadComponent { return ky(url, { signal: controller.signal, onDownloadProgress: (progress) => { - this.progress.set(progress.percent); + this.progress.set(Math.round(progress.percent * 100)); }, }).then( async (res) => { From 25ecd8d8bac8ad2418fb01a7166dbab9e44256bb Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 19 Feb 2025 10:21:03 -0800 Subject: [PATCH 15/44] Merge branch 'main' of https://github.com/e-picsa/picsa-apps into feat/forecasts-page From d230eb007dae7f460df6cba5d365212748b43c0c Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 19 Feb 2025 11:25:04 -0800 Subject: [PATCH 16/44] chore: photo save improvements --- .vscode/settings.json | 3 +- .../src/features/photo/photo.service.ts | 33 ++++++++++--------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9439716aa..b65d66ac8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,5 +13,6 @@ "deno.unstable": true, "deno.config": "apps/picsa-server/supabase/functions/deno.jsonc", "angular.enable-strict-mode-prompt": false, - "css.customData": [".vscode/tailwind.json"] + "css.customData": [".vscode/tailwind.json"], + "typescript.tsdk": "node_modules\\typescript\\lib" } diff --git a/libs/shared/src/features/photo/photo.service.ts b/libs/shared/src/features/photo/photo.service.ts index c7207a745..100188610 100644 --- a/libs/shared/src/features/photo/photo.service.ts +++ b/libs/shared/src/features/photo/photo.service.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Injectable, signal } from '@angular/core'; +import { isEqual } from '@picsa/utils/object.utils'; import { RxCollection } from 'rxdb'; import { PicsaAsyncService } from '../../services/asyncService.service'; @@ -13,7 +14,7 @@ export class PhotoService extends PicsaAsyncService { public collection: RxCollection; /** List of all stored photos, exposed as signal */ - public photos = signal([]); + public photos = signal([], { equal: isEqual }); constructor(private dbService: PicsaDatabase_V2_Service, private attachmentService: PicsaDatabaseAttachmentService) { super(); @@ -32,7 +33,7 @@ export class PhotoService extends PicsaAsyncService { public async getPhotoAttachment(id: string) { const doc = await this.collection.findOne(id).exec(); if (doc) { - return this.attachmentService.getFileAttachmentURI(doc, true); + return this.attachmentService.getFileAttachmentURI(doc, id, true); } return undefined; } @@ -43,31 +44,33 @@ export class PhotoService extends PicsaAsyncService { /** Subscribe to all photos and store list within angular signal */ private subscribeToPhotos() { this.collection.find().$.subscribe((docs) => { - this.photos.set(docs.map((d) => d._data)); + const photos = docs.map((d) => d._data); + // as photo docs are updated before attachment stored filter to only include those that have + // had attachment added + const photosWithAttachments = photos.filter((p) => (p._attachments[p.id] ? true : false)); + this.photos.set(photosWithAttachments); }); } // this method will save the photo to the database. async savePhoto(entry: Schema.IPhotoEntry, data: Blob) { try { - const doc = await this.collection.insert(entry); - await this.attachmentService.putAttachment(doc, entry.id, data); + // create new doc in photos + const photoDoc = await this.collection.insert(entry); + // update the doc with reference to stored attachment + const updatedDoc = await this.attachmentService.putAttachment(photoDoc, entry.id, data); + return updatedDoc; } catch (error) { console.error('Failed to save photo:', error); + return; } } // this method will delete a photo from the database. async deletePhoto(id: string) { - let doc = await this.collection.findOne(id).exec(); - if (doc) { - await this.attachmentService.removeAttachment(doc, id); - // HACK - fetch the doc again as revision will have changed following - // attachment removal - doc = await this.collection.findOne(id).exec(); - if (doc) { - await doc.remove(); - } - } + const photoDoc = await this.collection.findOne(id).exec(); + if (!photoDoc) return; + const updatedDoc = await this.attachmentService.removeAttachment(photoDoc, id); + return updatedDoc; } } From 6162ae9205c6d4e97e66624acf0c21b8db2a1e4a Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 19 Feb 2025 12:50:00 -0800 Subject: [PATCH 17/44] refactor: forecast attachment handling --- .../src/app/pages/forecast/forecast.page.html | 16 +++++------ .../src/app/pages/forecast/forecast.page.ts | 27 +++++++++---------- .../app/pages/forecast/forecast.service.ts | 13 +++++---- .../src/services/core/db_v2/db.types.ts | 1 + 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index 8ed769636..73cee81df 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -48,14 +48,6 @@

{{'Daily' | translate}}

- -
-

{{'Seasonal' | translate}}

-
-
...
-
-
-

{{'Downscaled' | translate}}

@@ -68,4 +60,12 @@

{{'Downscaled' | translate}}

+ + +
+

{{'Seasonal' | translate}}

+
+
...
+
+
diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index 3ab2b4433..6de41d0f5 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -6,6 +6,7 @@ import { ConfigurationService } from '@picsa/configuration'; import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; +import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { RxDocument } from 'rxdb'; @@ -70,7 +71,11 @@ export class ClimateForecastComponent implements OnDestroy { // HACK - use resources collection for downscaled forecasts public downscaledForecastsCollection = {}; - constructor(private service: ClimateForecastService, private configurationService: ConfigurationService) { + constructor( + private service: ClimateForecastService, + private configurationService: ConfigurationService, + private dbAttachmentService: PicsaDatabaseAttachmentService + ) { effect(() => { const { country_code } = this.configurationService.deploymentSettings(); if (country_code) { @@ -93,11 +98,11 @@ export class ClimateForecastComponent implements OnDestroy { const downloader = this.downloaders().find((d) => d.storage_path() === forecast.storage_file); if (downloader) { await this.service.downloadForecastFile(forecast._doc, downloader); - // refresh data to populated downloads - await this.refreshForecastData(); - const updated = this.dailyForecasts().find(({ id }) => id === forecast.id); - if (updated?.downloaded) { - this.openForecast(updated); + forecast._doc = forecast._doc.getLatest(); + if (forecast._doc.getAttachment(forecast.storage_file)) { + this.openForecast(forecast); + // refresh data to populated downloads + this.refreshForecastData(); } } } @@ -116,14 +121,8 @@ export class ClimateForecastComponent implements OnDestroy { } private async openForecast(forecast: IForecastSummary) { - const attachment = forecast._doc.getAttachment(forecast.storage_file as string); - if (!attachment) { - throw new Error('Forecast file not found'); - } - const blob = await attachment.getData(); - // TODO - handle html (maybe general file-viewer component) - const uri = URL.createObjectURL(blob); - this.pdfSrc = uri; + const uri = await this.dbAttachmentService.getFileAttachmentURI(forecast._doc, forecast.storage_file as string); + this.pdfSrc = uri || undefined; } private generateForecastLabel(id: string) { diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts index 676e30c7c..f06e7a30a 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -2,7 +2,7 @@ import { Injectable, signal } from '@angular/core'; import { ICountryCode } from '@picsa/data'; import { IResourceCollection } from '@picsa/resources/src/app/schemas'; import { ResourcesToolService } from '@picsa/resources/src/app/services/resources-tool.service'; -import { PicsaDatabase_V2_Service } from '@picsa/shared/services/core/db_v2'; +import { PicsaDatabase_V2_Service, PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { isEqual } from '@picsa/utils/object.utils'; import { RxCollection, RxDocument } from 'rxdb'; @@ -34,7 +34,8 @@ export class ClimateForecastService { constructor( private supabaseService: SupabaseService, private dbService: PicsaDatabase_V2_Service, - private resourcesService: ResourcesToolService + private resourcesService: ResourcesToolService, + private dbAttachmentService: PicsaDatabaseAttachmentService ) {} public async loadForecasts(country_code: ICountryCode) { @@ -71,10 +72,7 @@ export class ClimateForecastService { this.downscaledForecastsCollection.set(downscaled); } - public async downloadForecastFile( - doc: RxDocument, - downloaderUI: SupabaseStorageDownloadComponent - ): Promise> { + public async downloadForecastFile(doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent) { await downloaderUI.start(); const { error, data } = await downloaderUI.completed(); if (error) { @@ -84,7 +82,8 @@ export class ClimateForecastService { } if (data && data instanceof Blob) { const attachmentId = downloaderUI.storage_path(); - const { doc: updatedDoc } = await doc.putAttachment({ id: attachmentId, data, type: data.type }); + await this.dbAttachmentService.ready(); + const updatedDoc = await this.dbAttachmentService.putAttachment(doc, attachmentId, data); return updatedDoc; } return doc; diff --git a/libs/shared/src/services/core/db_v2/db.types.ts b/libs/shared/src/services/core/db_v2/db.types.ts index 9e77a6d16..63e15b61f 100644 --- a/libs/shared/src/services/core/db_v2/db.types.ts +++ b/libs/shared/src/services/core/db_v2/db.types.ts @@ -5,6 +5,7 @@ const DB_COLLECTION_NAMES = [ 'attachments', 'budget_cards', + 'climate_forecasts', 'monitoring_tool_forms', 'monitoring_tool_submissions', 'options_tool', From fb99047b4f47336d08ad4ad81b47c979ccd1d557 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 19 Feb 2025 13:26:53 -0800 Subject: [PATCH 18/44] refactor: attachment uri handling --- .../src/app/pages/forecast/forecast.page.scss | 2 +- .../src/app/pages/home/home.component.ts | 2 +- .../app/services/resources-tool.service.ts | 5 +- .../src/features/photo/photo.service.ts | 2 +- .../core/db_v2/db-attachment.service.ts | 55 +++++++++---------- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss index f9d560b7d..54fa22492 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss @@ -20,7 +20,7 @@ } h2.forecast-heading { - @apply w-full sm:mb-8 sm:w-32 sm:text-left overflow-hidden text-ellipsis; + @apply w-full sm:mb-8 sm:w-40 sm:text-left overflow-hidden text-ellipsis; } div.forecast-content { @apply flex-1 overflow-x-auto mx-4 sm:mx-0; diff --git a/apps/picsa-tools/manual-tool/src/app/pages/home/home.component.ts b/apps/picsa-tools/manual-tool/src/app/pages/home/home.component.ts index 135315a01..c999a87e6 100644 --- a/apps/picsa-tools/manual-tool/src/app/pages/home/home.component.ts +++ b/apps/picsa-tools/manual-tool/src/app/pages/home/home.component.ts @@ -106,7 +106,7 @@ export class HomeComponent implements OnDestroy, AfterViewInit { const manualDoc = await this.resourcesService.dbFiles.findOne(manualResource.id).exec(); if (manualDoc) { this.resourceDocs[version] = manualDoc; - const uri = await this.resourcesService.getFileAttachmentURI(manualDoc, true); + const uri = await this.resourcesService.getFileAttachmentURI(manualDoc); if (uri) { this.downloadPrompt.show = false; this.pdfSrc = uri; diff --git a/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts b/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts index ec60690c3..4625d5929 100644 --- a/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts +++ b/apps/picsa-tools/resources-tool/src/app/services/resources-tool.service.ts @@ -109,8 +109,9 @@ export class ResourcesToolService extends PicsaAsyncService { * NOTE - on web this will create an objectURL in the document which should be revoked when no longer required * @param convertNativeSrc - Convert to src usable within web content (e.g as image or pdf src) **/ - public async getFileAttachmentURI(doc: RxDocument, convertNativeSrc = false) { - return this.dbAttachmentService.getFileAttachmentURI(doc, convertNativeSrc); + public async getFileAttachmentURI(doc: RxDocument) { + const filename = doc.filename || doc.id; + return this.dbAttachmentService.getFileAttachmentURI(doc, filename); } /** * Release a file attachment URI when no longer required diff --git a/libs/shared/src/features/photo/photo.service.ts b/libs/shared/src/features/photo/photo.service.ts index 100188610..9280e781b 100644 --- a/libs/shared/src/features/photo/photo.service.ts +++ b/libs/shared/src/features/photo/photo.service.ts @@ -33,7 +33,7 @@ export class PhotoService extends PicsaAsyncService { public async getPhotoAttachment(id: string) { const doc = await this.collection.findOne(id).exec(); if (doc) { - return this.attachmentService.getFileAttachmentURI(doc, id, true); + return this.attachmentService.getFileAttachmentURI(doc, id); } return undefined; } diff --git a/libs/shared/src/services/core/db_v2/db-attachment.service.ts b/libs/shared/src/services/core/db_v2/db-attachment.service.ts index 9feb43077..708643a3f 100644 --- a/libs/shared/src/services/core/db_v2/db-attachment.service.ts +++ b/libs/shared/src/services/core/db_v2/db-attachment.service.ts @@ -9,19 +9,17 @@ import { PicsaDatabase_V2_Service } from './db.service'; import { ATTACHMENTS_COLLECTION, IAttachment } from './schemas/attachments'; /********************************************************************************************* - * @deprecated v3.50.0 - * The attachment system was creating primarily to store single resource file attachments - * in a separate collection due to limitations in rxdb/dexie attachment handling. + * If storing attachments using regular `putAttachment` method all attachment data is converted + * to base64 string and stored directly within an `attachments` objectStore on the collection + * indexeddb. This results in very large indexeddbs which may be slow to use and difficult to migrate * - * Recent upgrades handle better so reccomend using doc `putAttachment` method directly - * on source documents + * The PicsaDatabaseAttachmentService instead uses local file storage on native devices, providing + * URIs to files on disk instead of raw data. It includes methods to convert these URIs to + * other data types as required * - * DB Attachments - * Ordinarily RXDB handles attachments within the storage provider, however dexie is not - * currently supported. So manual workaround to persist attachment files to separate collection - * instead and retrieve on demand. - * Additionally writes to disk on native + * On web the service still uses indexeddb * + * TODO - add support for opfs storage on web * TODO - may want hooks system to ensure attachments removed on doc delete * TODO - change all md5checksum for sha256 * TODO - add db service hooks to also remove files on doc remove @@ -55,28 +53,25 @@ export class PicsaDatabaseAttachmentService extends PicsaAsyncService { /** * Retrieve a doc attachment and convert to URI for use within components * NOTE - on web this will create an objectURL in the document which should be revoked when no longer required - * @param convertNativeSrc - Convert to src usable within web content (e.g as image or pdf src) **/ - public async getFileAttachmentURI(doc: RxDocument, convertNativeSrc = false) { - const attachmentName = doc.filename || doc.id; - if (!attachmentName) { + public async getFileAttachmentURI(doc: RxDocument, filename: string) { + if (!filename) { console.error(doc); throw new Error(`No attachment name provided`); } - const attachment = await this.getAttachment(doc, attachmentName); + const attachment = await this.getAttachment(doc, filename); if (!attachment) return null; if (attachment) { if (Capacitor.isNativePlatform()) { const { uri } = attachment; - return convertNativeSrc ? Capacitor.convertFileSrc(uri as string) : uri; - } - // On native URI already stored as path to file stored locally - if (attachment.uri) return attachment.uri; - // On web data stored as base64 string, convert to blob and generate object url - if (attachment.data) { - const blob = await base64ToBlob(attachment.data, attachment.type); - this.objectURLs[attachmentName] = URL.createObjectURL(blob); - return this.objectURLs[attachmentName]; + return Capacitor.convertFileSrc(uri as string); + } else { + // On web data stored as base64 string, convert to blob and generate object url + if (attachment.data) { + const blob = await base64ToBlob(attachment.data, attachment.type); + this.objectURLs[filename] = URL.createObjectURL(blob); + return this.objectURLs[filename]; + } } } return null; @@ -106,8 +101,10 @@ export class PicsaDatabaseAttachmentService extends PicsaAsyncService { * @param prefix additional prefix to provide to filename to ensure globally unique * @param index doc file entry number in case of multiple files */ - public async putAttachment(doc: RxDocument, filename: string, data: Blob) { - if (!data) return; + public async putAttachment(doc: RxDocument, filename: string, data: Blob) { + if (!data) { + throw new Error('Cannot put attachment, no data: ' + filename); + } // prefer to use downloaded blob data directly instead of doc expected const { type, size } = data; const id = this.generateAttachmentID(doc, filename); @@ -136,11 +133,12 @@ export class PicsaDatabaseAttachmentService extends PicsaAsyncService { type, data: new Blob([JSON.stringify(attachmentDoc._data)], { type: 'application/json' }), }); - // await attachmentDoc.patch({ digest }); + // refresh doc and return + return doc.getLatest(); } /** Remove attachments populated to a specific collection doc */ - public async removeAttachment(doc: RxDocument, filename: string) { + public async removeAttachment(doc: RxDocument, filename: string) { const id = this.generateAttachmentID(doc, filename); const ref = await this.collection.findOne(id).exec(); if (ref) { @@ -157,6 +155,7 @@ export class PicsaDatabaseAttachmentService extends PicsaAsyncService { if (docRef) { await docRef.remove(); } + return doc.getLatest(); } /** From 3e4e82ca3a94c4b3fc802b63832dac087e90fb1a Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 20 Feb 2025 16:32:14 -0800 Subject: [PATCH 19/44] feat: wip geojson updates --- libs/data/geoLocation/.gitignore | 1 + libs/data/geoLocation/README.md | 81 + .../geoLocation/mw/admin-0.boundaries.json | 522 +++ .../geoLocation/mw/admin-1.boundaries.json | 1821 ++++++++++ libs/data/geoLocation/types.ts | 21 + libs/data/geoLocation/utils.ts | 82 + .../geoLocation/zm/admin-0.boundaries.json | 930 +++++ .../geoLocation/zm/admin-1.boundaries.json | 3156 +++++++++++++++++ 8 files changed, 6614 insertions(+) create mode 100644 libs/data/geoLocation/.gitignore create mode 100644 libs/data/geoLocation/README.md create mode 100644 libs/data/geoLocation/mw/admin-0.boundaries.json create mode 100644 libs/data/geoLocation/mw/admin-1.boundaries.json create mode 100644 libs/data/geoLocation/types.ts create mode 100644 libs/data/geoLocation/utils.ts create mode 100644 libs/data/geoLocation/zm/admin-0.boundaries.json create mode 100644 libs/data/geoLocation/zm/admin-1.boundaries.json diff --git a/libs/data/geoLocation/.gitignore b/libs/data/geoLocation/.gitignore new file mode 100644 index 000000000..85213e54e --- /dev/null +++ b/libs/data/geoLocation/.gitignore @@ -0,0 +1 @@ +*.geojson \ No newline at end of file diff --git a/libs/data/geoLocation/README.md b/libs/data/geoLocation/README.md new file mode 100644 index 000000000..92c737337 --- /dev/null +++ b/libs/data/geoLocation/README.md @@ -0,0 +1,81 @@ +# GeoLocation Data + +## TODO + +- [ ] Export all data from OSM instead of natural earth +- [ ] Setup admin levels to match OSM +- [ ] +- [ ] Migrate optimisation scripts +- [ ] Migrate legacy data +- [ ] Add custom select +- [ ] Decide how best to handle intermediate admin boundaries (e.g. mw region) + +## Generating Boundary Data (OSM) + +https://overpass-turbo.eu/index.html + +**Country Boundaries** + +``` +[out:json][timeout:25]; +// gather results +nwr["admin_level"="2"]["boundary"="administrative"]["name"="Malawi"]; +// print results +out geom; +``` + +Example data exploration +https://www.openstreetmap.org/relation/195290 + +**District/Province Boundaries** + +``` +[out:json][timeout:25]; +// gather results +nwr["admin_level"="4"]["boundary"="administrative"]["ISO3166-2"~"^MW-"]; +// print results +out geom; +``` + +https://overpass-turbo.eu/s/1Z83 + +Export as GeoJSON + +## Generating Boundary Data (QGIS) + +1. Import admin_1 boundary data into QGIS + +This can be downloaded from: +https://www.naturalearthdata.com/downloads/10m-cultural-vectors/ + +2. Filter for country + Right-click on the feature layer and use the `Filter` dialog to specify country, e.g. + +``` +"admin" = 'Malawi' +``` + +3. Export data + Right-click on the feature layer and use the `Export -> Save Features As...` dialog to create an output geoJson file + +Deselect all fields for export and only check the `name` field +Export to a local file + +4. Optimise + Use the scripts in this workspace to convert geoJson to boundaries to retain only minimal information required for use in the app + +## Troubleshooting + +### Duplicate entries + +There may be some cases where the data exported from QGIS includes errors, which can result in duplicate entries (e.g. malawi data incorrectly marks the karonga district as chipita). + +Review the exported data and cross-check external sources, e.g. + +https://en.wikipedia.org/wiki/List_of_administrative_divisions_by_country + +https://data.humdata.org/dataset/?dataseries_name=COD+-+Subnational+Administrative+Boundaries + +## Additional Notes + +Consider further reductions with https://mapshaper.org/ diff --git a/libs/data/geoLocation/mw/admin-0.boundaries.json b/libs/data/geoLocation/mw/admin-0.boundaries.json new file mode 100644 index 000000000..65ceeb0bc --- /dev/null +++ b/libs/data/geoLocation/mw/admin-0.boundaries.json @@ -0,0 +1,522 @@ +{ + "Malawi": [ + [34.96, -11.57], + [34.62, -11.58], + [34.61, -11.59], + [34.6, -11.73], + [34.56, -11.83], + [34.49, -11.94], + [34.38, -12.1], + [34.36, -12.15], + [34.35, -12.2], + [34.38, -12.29], + [34.44, -12.5], + [34.49, -12.69], + [34.51, -12.8], + [34.52, -12.94], + [34.54, -13.06], + [34.55, -13.16], + [34.54, -13.24], + [34.55, -13.33], + [34.58, -13.4], + [34.6, -13.42], + [34.61, -13.44], + [34.63, -13.47], + [34.64, -13.48], + [34.65, -13.5], + [34.86, -13.52], + [34.89, -13.53], + [35, -13.63], + [35.08, -13.7], + [35.17, -13.81], + [35.28, -13.93], + [35.37, -14.04], + [35.46, -14.14], + [35.52, -14.26], + [35.61, -14.37], + [35.71, -14.5], + [35.75, -14.54], + [35.79, -14.59], + [35.84, -14.64], + [35.85, -14.65], + [35.86, -14.88], + [35.87, -14.89], + [35.84, -15.04], + [35.79, -15.15], + [35.78, -15.17], + [35.79, -15.21], + [35.81, -15.3], + [35.84, -15.42], + [35.83, -15.54], + [35.82, -15.66], + [35.81, -15.9], + [35.8, -15.93], + [35.79, -15.96], + [35.8, -16], + [35.79, -16.02], + [35.77, -16.06], + [35.7, -16.11], + [35.55, -16.14], + [35.52, -16.15], + [35.51, -16.17], + [35.49, -16.16], + [35.47, -16.14], + [35.46, -16.13], + [35.44, -16.12], + [35.39, -16.13], + [35.37, -16.14], + [35.3, -16.2], + [35.28, -16.23], + [35.26, -16.27], + [35.25, -16.32], + [35.27, -16.36], + [35.26, -16.37], + [35.24, -16.39], + [35.23, -16.41], + [35.21, -16.48], + [35.14, -16.53], + [35.13, -16.54], + [35.15, -16.58], + [35.16, -16.61], + [35.17, -16.62], + [35.19, -16.63], + [35.22, -16.64], + [35.23, -16.65], + [35.24, -16.66], + [35.25, -16.67], + [35.28, -16.7], + [35.29, -16.79], + [35.31, -16.83], + [35.29, -16.87], + [35.28, -16.89], + [35.29, -16.93], + [35.28, -16.94], + [35.27, -16.95], + [35.28, -16.96], + [35.31, -16.97], + [35.3, -17.01], + [35.31, -17.07], + [35.3, -17.1], + [35.29, -17.13], + [35.23, -17.14], + [35.13, -17.13], + [35.08, -17.12], + [35.07, -17.11], + [35.04, -17.04], + [35.07, -16.99], + [35.09, -16.98], + [35.11, -16.96], + [35.13, -16.93], + [35.12, -16.83], + [35.1, -16.82], + [35, -16.81], + [34.98, -16.79], + [34.96, -16.77], + [34.95, -16.76], + [34.93, -16.75], + [34.91, -16.74], + [34.9, -16.73], + [34.89, -16.71], + [34.88, -16.69], + [34.84, -16.68], + [34.83, -16.66], + [34.82, -16.63], + [34.77, -16.59], + [34.76, -16.58], + [34.74, -16.54], + [34.73, -16.53], + [34.67, -16.5], + [34.66, -16.49], + [34.64, -16.46], + [34.63, -16.44], + [34.6, -16.42], + [34.59, -16.41], + [34.58, -16.39], + [34.55, -16.32], + [34.52, -16.3], + [34.48, -16.29], + [34.43, -16.27], + [34.39, -16.19], + [34.41, -16.09], + [34.4, -16.06], + [34.39, -16.04], + [34.3, -15.95], + [34.29, -15.94], + [34.26, -15.93], + [34.24, -15.92], + [34.23, -15.89], + [34.24, -15.82], + [34.25, -15.79], + [34.28, -15.76], + [34.29, -15.75], + [34.31, -15.74], + [34.34, -15.73], + [34.4, -15.65], + [34.42, -15.62], + [34.41, -15.51], + [34.42, -15.46], + [34.46, -15.42], + [34.48, -15.41], + [34.49, -15.4], + [34.5, -15.36], + [34.51, -15.35], + [34.52, -15.34], + [34.53, -15.33], + [34.55, -15.32], + [34.57, -15.3], + [34.56, -15.2], + [34.55, -15.12], + [34.56, -15.1], + [34.55, -15.07], + [34.57, -15.02], + [34.58, -15], + [34.57, -14.95], + [34.56, -14.94], + [34.55, -14.92], + [34.54, -14.8], + [34.53, -14.77], + [34.52, -14.73], + [34.51, -14.7], + [34.52, -14.64], + [34.5, -14.58], + [34.45, -14.53], + [34.43, -14.5], + [34.39, -14.43], + [34.38, -14.41], + [34.37, -14.4], + [34.34, -14.39], + [34.32, -14.4], + [34.3, -14.41], + [34.29, -14.4], + [34.18, -14.44], + [34.08, -14.45], + [34.07, -14.46], + [34.06, -14.49], + [34.05, -14.5], + [33.95, -14.48], + [33.89, -14.49], + [33.83, -14.52], + [33.8, -14.53], + [33.72, -14.49], + [33.7, -14.5], + [33.68, -14.52], + [33.67, -14.6], + [33.66, -14.61], + [33.64, -14.6], + [33.63, -14.59], + [33.62, -14.58], + [33.6, -14.52], + [33.58, -14.5], + [33.56, -14.49], + [33.55, -14.48], + [33.54, -14.47], + [33.53, -14.46], + [33.51, -14.43], + [33.47, -14.41], + [33.46, -14.4], + [33.44, -14.38], + [33.39, -14.28], + [33.37, -14.26], + [33.36, -14.23], + [33.35, -14.22], + [33.32, -14.21], + [33.29, -14.16], + [33.28, -14.06], + [33.26, -14.04], + [33.2, -14.01], + [33.19, -13.99], + [33.15, -13.94], + [33.14, -13.92], + [33.13, -13.93], + [33.12, -13.96], + [33.08, -13.97], + [33.06, -13.98], + [33.05, -14], + [33.02, -14.05], + [32.98, -14.02], + [32.97, -14.01], + [32.98, -13.95], + [32.97, -13.94], + [32.96, -13.93], + [32.93, -13.91], + [32.92, -13.88], + [32.87, -13.82], + [32.86, -13.81], + [32.83, -13.8], + [32.79, -13.79], + [32.76, -13.78], + [32.77, -13.74], + [32.8, -13.72], + [32.81, -13.71], + [32.77, -13.65], + [32.74, -13.64], + [32.68, -13.63], + [32.66, -13.6], + [32.67, -13.58], + [32.68, -13.57], + [32.71, -13.58], + [32.72, -13.57], + [32.75, -13.55], + [32.76, -13.54], + [32.81, -13.53], + [32.82, -13.51], + [32.83, -13.46], + [32.87, -13.44], + [32.89, -13.4], + [32.91, -13.35], + [32.92, -13.29], + [32.94, -13.26], + [32.96, -13.22], + [33, -13.2], + [32.98, -13.17], + [32.97, -13.15], + [32.98, -13.01], + [33.01, -12.95], + [32.98, -12.87], + [32.95, -12.85], + [32.94, -12.77], + [32.96, -12.73], + [32.99, -12.67], + [33.02, -12.61], + [33.04, -12.6], + [33.05, -12.59], + [33.06, -12.58], + [33.07, -12.59], + [33.08, -12.6], + [33.1, -12.59], + [33.12, -12.58], + [33.14, -12.59], + [33.16, -12.62], + [33.18, -12.61], + [33.19, -12.6], + [33.2, -12.59], + [33.23, -12.58], + [33.24, -12.54], + [33.26, -12.53], + [33.29, -12.52], + [33.3, -12.53], + [33.32, -12.54], + [33.35, -12.53], + [33.37, -12.52], + [33.39, -12.5], + [33.41, -12.48], + [33.42, -12.46], + [33.45, -12.45], + [33.46, -12.44], + [33.47, -12.41], + [33.49, -12.39], + [33.51, -12.37], + [33.53, -12.36], + [33.51, -12.33], + [33.46, -12.32], + [33.38, -12.34], + [33.35, -12.33], + [33.33, -12.3], + [33.31, -12.23], + [33.3, -12.2], + [33.29, -12.18], + [33.26, -12.16], + [33.25, -12.14], + [33.29, -11.98], + [33.3, -11.93], + [33.31, -11.91], + [33.3, -11.86], + [33.31, -11.81], + [33.3, -11.61], + [33.28, -11.58], + [33.22, -11.57], + [33.21, -11.56], + [33.23, -11.53], + [33.24, -11.4], + [33.27, -11.42], + [33.28, -11.36], + [33.3, -11.35], + [33.37, -11.22], + [33.38, -11.19], + [33.39, -11.16], + [33.36, -11.11], + [33.34, -11.09], + [33.32, -11.06], + [33.3, -11.03], + [33.29, -11], + [33.28, -10.91], + [33.27, -10.9], + [33.23, -10.88], + [33.24, -10.87], + [33.25, -10.86], + [33.26, -10.87], + [33.29, -10.86], + [33.31, -10.83], + [33.32, -10.82], + [33.33, -10.81], + [33.37, -10.8], + [33.42, -10.81], + [33.45, -10.8], + [33.47, -10.78], + [33.5, -10.77], + [33.51, -10.75], + [33.53, -10.71], + [33.58, -10.66], + [33.59, -10.65], + [33.6, -10.64], + [33.64, -10.62], + [33.66, -10.6], + [33.67, -10.58], + [33.64, -10.51], + [33.62, -10.49], + [33.6, -10.45], + [33.57, -10.42], + [33.56, -10.4], + [33.53, -10.34], + [33.54, -10.26], + [33.53, -10.23], + [33.52, -10.21], + [33.5, -10.2], + [33.48, -10.18], + [33.45, -10.17], + [33.44, -10.15], + [33.42, -10.14], + [33.4, -10.12], + [33.32, -10.08], + [33.3, -10.06], + [33.31, -10.01], + [33.33, -9.97], + [33.36, -9.92], + [33.37, -9.9], + [33.36, -9.87], + [33.34, -9.83], + [33.3, -9.81], + [33.29, -9.8], + [33.28, -9.79], + [33.27, -9.78], + [33.25, -9.75], + [33.24, -9.74], + [33.22, -9.73], + [33.21, -9.71], + [33.2, -9.7], + [33.21, -9.69], + [33.22, -9.67], + [33.21, -9.65], + [33.2, -9.62], + [33.18, -9.6], + [33.1, -9.59], + [33.09, -9.61], + [33.08, -9.66], + [33.06, -9.65], + [33.05, -9.64], + [33.04, -9.62], + [33.01, -9.63], + [32.97, -9.6], + [32.99, -9.53], + [32.98, -9.5], + [32.97, -9.48], + [32.94, -9.49], + [32.93, -9.48], + [32.92, -9.47], + [32.94, -9.39], + [32.96, -9.38], + [32.99, -9.39], + [33.04, -9.44], + [33.1, -9.49], + [33.14, -9.5], + [33.17, -9.51], + [33.2, -9.5], + [33.22, -9.49], + [33.24, -9.5], + [33.27, -9.49], + [33.36, -9.53], + [33.37, -9.55], + [33.39, -9.59], + [33.4, -9.6], + [33.42, -9.62], + [33.54, -9.6], + [33.56, -9.59], + [33.59, -9.6], + [33.62, -9.61], + [33.7, -9.59], + [33.73, -9.58], + [33.76, -9.6], + [33.79, -9.63], + [33.81, -9.64], + [33.84, -9.65], + [33.87, -9.67], + [33.89, -9.69], + [33.9, -9.71], + [33.91, -9.72], + [33.93, -9.7], + [33.94, -9.68], + [33.95, -9.67], + [33.96, -9.64], + [33.95, -9.55], + [33.96, -9.52], + [33.98, -9.51], + [34, -9.49], + [34.01, -9.48], + [34.05, -9.49], + [34.08, -9.51], + [34.09, -9.52], + [34.1, -9.53], + [34.14, -9.57], + [34.16, -9.59], + [34.19, -9.61], + [34.29, -9.71], + [34.32, -9.72], + [34.33, -9.75], + [34.34, -9.78], + [34.36, -9.8], + [34.38, -9.82], + [34.48, -9.95], + [34.49, -9.97], + [34.52, -10.01], + [34.54, -10.04], + [34.53, -10.08], + [34.52, -10.09], + [34.53, -10.13], + [34.57, -10.2], + [34.58, -10.26], + [34.59, -10.29], + [34.57, -10.41], + [34.59, -10.46], + [34.58, -10.51], + [34.59, -10.55], + [34.6, -10.58], + [34.63, -10.6], + [34.65, -10.65], + [34.66, -10.67], + [34.65, -10.71], + [34.66, -10.72], + [34.67, -10.73], + [34.68, -10.75], + [34.66, -10.76], + [34.65, -10.86], + [34.63, -10.95], + [34.62, -10.97], + [34.6, -10.99], + [34.59, -11.02], + [34.6, -11.04], + [34.61, -11.08], + [34.62, -11.12], + [34.67, -11.16], + [34.68, -11.18], + [34.7, -11.19], + [34.71, -11.2], + [34.72, -11.21], + [34.73, -11.25], + [34.74, -11.27], + [34.76, -11.28], + [34.75, -11.29], + [34.74, -11.3], + [34.76, -11.34], + [34.77, -11.35], + [34.78, -11.33], + [34.84, -11.35], + [34.87, -11.36], + [34.89, -11.38], + [34.9, -11.4], + [34.92, -11.42], + [34.93, -11.45], + [34.94, -11.46], + [34.95, -11.47], + [34.96, -11.49] + ] +} diff --git a/libs/data/geoLocation/mw/admin-1.boundaries.json b/libs/data/geoLocation/mw/admin-1.boundaries.json new file mode 100644 index 000000000..da69c40c1 --- /dev/null +++ b/libs/data/geoLocation/mw/admin-1.boundaries.json @@ -0,0 +1,1821 @@ +{ + "Chitipa": [ + [34.01, -9.48], + [34.05, -9.49], + [34.08, -9.51], + [34.09, -9.52], + [34.1, -9.53], + [34.14, -9.57], + [34.16, -9.59], + [34.19, -9.61], + [34.29, -9.71], + [34.32, -9.72], + [34.33, -9.75], + [34.34, -9.78], + [34.36, -9.8], + [34.38, -9.82], + [34.48, -9.95], + [34.49, -9.97], + [34.52, -10.01], + [34.54, -10.04], + [34.53, -10.08], + [34.52, -10.09], + [34.53, -10.13], + [34.57, -10.2], + [34.58, -10.26], + [34.59, -10.29], + [34.57, -10.41], + [34.59, -10.46], + [34.58, -10.51], + [34.59, -10.55], + [34.6, -10.58], + [34.09, -10.57], + [33.95, -10.45], + [33.72, -10.1], + [33.71, -10.08], + [33.7, -10.07], + [33.69, -10.06], + [33.66, -10.07], + [33.61, -10.06], + [33.58, -10.03], + [33.57, -10.02], + [33.53, -10.01], + [33.52, -10], + [33.51, -9.99], + [33.5, -9.98], + [33.49, -9.97], + [33.48, -9.96], + [33.49, -9.94], + [33.51, -9.93], + [33.56, -9.9], + [33.57, -9.89], + [33.59, -9.88], + [33.61, -9.87], + [33.62, -9.86], + [33.63, -9.83], + [33.64, -9.82], + [33.66, -9.8], + [33.67, -9.79], + [33.7, -9.78], + [33.69, -9.75], + [33.68, -9.72], + [33.67, -9.7], + [33.68, -9.67], + [33.67, -9.65], + [33.65, -9.61], + [33.7, -9.59], + [33.73, -9.58], + [33.76, -9.6], + [33.79, -9.63], + [33.81, -9.64], + [33.84, -9.65], + [33.87, -9.67], + [33.89, -9.69], + [33.9, -9.71], + [33.91, -9.72], + [33.93, -9.7], + [33.94, -9.68], + [33.95, -9.67], + [33.96, -9.64], + [33.95, -9.55], + [33.96, -9.52], + [33.98, -9.51], + [34, -9.49], + [34.01, -9.48] + ], + "Rumphi": [ + [34.62, -10.58], + [34.63, -10.6], + [34.65, -10.65], + [34.66, -10.67], + [34.65, -10.71], + [34.66, -10.72], + [34.67, -10.73], + [34.68, -10.75], + [34.66, -10.76], + [34.65, -10.86], + [34.63, -10.95], + [34.62, -10.97], + [34.19, -11], + [34.06, -11.08], + [34.04, -11.05], + [34.03, -11.03], + [34.02, -11.02], + [33.95, -10.97], + [33.94, -10.96], + [33.93, -11.02], + [33.92, -11.03], + [33.82, -11.01], + [33.78, -11.02], + [33.75, -11.03], + [33.74, -11.04], + [33.75, -11.05], + [33.74, -11.08], + [33.72, -11.09], + [33.7, -11.08], + [33.69, -11.07], + [33.68, -11.05], + [33.63, -11.06], + [33.61, -11.05], + [33.59, -11.04], + [33.58, -11.03], + [33.57, -11.02], + [33.53, -11.03], + [33.52, -11.05], + [33.51, -11.06], + [33.5, -11.08], + [33.48, -11.09], + [33.46, -11.11], + [33.44, -11.1], + [33.45, -11.07], + [33.44, -11.04], + [33.43, -11.01], + [33.36, -11], + [33.31, -10.98], + [33.29, -10.94], + [33.28, -10.91], + [33.27, -10.9], + [33.23, -10.88], + [33.24, -10.87], + [33.25, -10.86], + [33.26, -10.87], + [33.29, -10.86], + [33.31, -10.83], + [33.32, -10.82], + [33.33, -10.81], + [33.37, -10.8], + [33.42, -10.81], + [33.45, -10.8], + [33.47, -10.78], + [33.5, -10.77], + [33.51, -10.75], + [33.53, -10.71], + [33.58, -10.66], + [33.59, -10.65], + [33.6, -10.64], + [33.64, -10.62], + [33.66, -10.6], + [33.67, -10.58], + [33.7, -10.56], + [33.95, -10.45], + [34.09, -10.57], + [34.11, -10.58] + ], + "Nkhata Bay": [ + [34.62, -10.97], + [34.6, -10.99], + [34.59, -11.02], + [34.6, -11.04], + [34.61, -11.08], + [34.62, -11.12], + [34.67, -11.16], + [34.68, -11.18], + [34.7, -11.19], + [34.71, -11.2], + [34.72, -11.21], + [34.73, -11.25], + [34.74, -11.27], + [34.76, -11.28], + [34.75, -11.29], + [34.74, -11.3], + [34.76, -11.34], + [34.77, -11.35], + [34.78, -11.33], + [34.84, -11.35], + [34.87, -11.36], + [34.89, -11.38], + [34.9, -11.4], + [34.92, -11.42], + [34.93, -11.45], + [34.94, -11.46], + [34.95, -11.47], + [34.96, -11.49], + [34.65, -11.57], + [34.62, -11.58], + [34.61, -11.59], + [34.6, -11.73], + [34.56, -11.83], + [34.49, -11.94], + [34.38, -12.1], + [34.36, -12.15], + [34.35, -12.2], + [33.96, -12.19], + [33.91, -12.17], + [33.9, -12.16], + [33.88, -12.14], + [33.76, -12.13], + [33.75, -12.12], + [33.73, -12.11], + [33.72, -12.1], + [33.73, -12.07], + [33.74, -12.06], + [33.75, -12.05], + [33.77, -12.04], + [33.8, -12.03], + [33.82, -12], + [33.81, -11.97], + [33.8, -11.89], + [33.81, -11.85], + [33.82, -11.83], + [33.81, -11.78], + [33.8, -11.77], + [33.79, -11.75], + [33.78, -11.74], + [33.77, -11.72], + [33.78, -11.62], + [33.79, -11.6], + [33.81, -11.58], + [33.82, -11.57], + [33.83, -11.56], + [33.86, -11.54], + [33.87, -11.53], + [33.93, -11.54], + [33.96, -11.53], + [33.97, -11.52], + [33.98, -11.51], + [33.99, -11.48], + [34, -11.47], + [34.01, -11.46], + [34.05, -11.47], + [34.07, -11.46], + [34.1, -11.45], + [34.09, -11.39], + [34.08, -11.38], + [34.07, -11.37], + [34.05, -11.28], + [34.04, -11.27], + [34.02, -11.26], + [34.05, -11.15], + [34.06, -11.08], + [34.19, -11], + [34.23, -10.97] + ], + "Likoma": [ + [34.69, -12], + [34.74, -12.01], + [34.75, -12.02], + [34.76, -12.04], + [34.75, -12.09], + [34.73, -12.11], + [34.71, -12.12], + [34.66, -12.1], + [34.68, -12.01], + [34.69, -12] + ], + "Karonga": [ + [32.94, -9.49], + [32.93, -9.48], + [32.92, -9.47], + [32.94, -9.39], + [32.96, -9.38], + [32.99, -9.39], + [33.04, -9.44], + [33.1, -9.49], + [33.14, -9.5], + [33.17, -9.51], + [33.2, -9.5], + [33.22, -9.49], + [33.24, -9.5], + [33.27, -9.49], + [33.36, -9.53], + [33.37, -9.55], + [33.39, -9.59], + [33.4, -9.6], + [33.42, -9.62], + [33.54, -9.6], + [33.56, -9.59], + [33.59, -9.6], + [33.62, -9.61], + [33.67, -9.65], + [33.68, -9.66], + [33.67, -9.69], + [33.68, -9.7], + [33.69, -9.73], + [33.7, -9.77], + [33.69, -9.79], + [33.66, -9.8], + [33.64, -9.82], + [33.63, -9.83], + [33.62, -9.85], + [33.61, -9.87], + [33.59, -9.88], + [33.57, -9.89], + [33.56, -9.9], + [33.51, -9.93], + [33.49, -9.94], + [33.48, -9.96], + [33.49, -9.97], + [33.5, -9.98], + [33.51, -9.99], + [33.52, -10], + [33.53, -10.01], + [33.54, -10.02], + [33.58, -10.03], + [33.61, -10.06], + [33.63, -10.07], + [33.69, -10.06], + [33.7, -10.07], + [33.71, -10.08], + [33.72, -10.1], + [33.95, -10.45], + [33.7, -10.56], + [33.67, -10.57], + [33.64, -10.51], + [33.62, -10.49], + [33.6, -10.45], + [33.57, -10.42], + [33.56, -10.4], + [33.53, -10.34], + [33.54, -10.26], + [33.53, -10.23], + [33.52, -10.21], + [33.5, -10.2], + [33.48, -10.18], + [33.45, -10.17], + [33.44, -10.15], + [33.42, -10.14], + [33.4, -10.12], + [33.32, -10.08], + [33.3, -10.06], + [33.31, -10.01], + [33.33, -9.97], + [33.36, -9.92], + [33.37, -9.9], + [33.36, -9.87], + [33.34, -9.83], + [33.3, -9.81], + [33.29, -9.8], + [33.28, -9.79], + [33.27, -9.78], + [33.25, -9.75], + [33.24, -9.74], + [33.22, -9.73], + [33.21, -9.71], + [33.2, -9.7], + [33.21, -9.69], + [33.22, -9.67], + [33.21, -9.65], + [33.2, -9.62], + [33.18, -9.6], + [33.1, -9.59], + [33.09, -9.61], + [33.08, -9.66], + [33.06, -9.65], + [33.05, -9.64], + [33.04, -9.62], + [33.01, -9.63], + [32.97, -9.6], + [32.99, -9.53], + [32.98, -9.5], + [32.97, -9.48], + [32.94, -9.49] + ], + "Mzimba": [ + [33.27, -11.42], + [33.28, -11.36], + [33.3, -11.35], + [33.37, -11.22], + [33.38, -11.19], + [33.39, -11.16], + [33.36, -11.11], + [33.34, -11.09], + [33.32, -11.06], + [33.3, -11.03], + [33.29, -11], + [33.31, -10.98], + [33.36, -11], + [33.39, -11.01], + [33.44, -11.02], + [33.45, -11.05], + [33.44, -11.08], + [33.45, -11.11], + [33.48, -11.09], + [33.5, -11.08], + [33.51, -11.06], + [33.52, -11.05], + [33.53, -11.03], + [33.54, -11.02], + [33.58, -11.03], + [33.59, -11.04], + [33.6, -11.05], + [33.62, -11.06], + [33.67, -11.05], + [33.69, -11.06], + [33.7, -11.08], + [33.71, -11.09], + [33.72, -11.08], + [33.75, -11.07], + [33.74, -11.04], + [33.75, -11.03], + [33.78, -11.02], + [33.82, -11.01], + [33.91, -11.03], + [33.93, -11.02], + [33.94, -10.98], + [33.95, -10.97], + [34.02, -11.02], + [34.03, -11.03], + [34.04, -11.05], + [34.06, -11.08], + [34.05, -11.15], + [34.02, -11.23], + [34.04, -11.27], + [34.05, -11.28], + [34.07, -11.37], + [34.08, -11.38], + [34.09, -11.39], + [34.1, -11.43], + [34.09, -11.46], + [34.06, -11.47], + [34.04, -11.46], + [34, -11.47], + [33.99, -11.48], + [33.98, -11.51], + [33.97, -11.52], + [33.96, -11.53], + [33.95, -11.54], + [33.89, -11.53], + [33.86, -11.54], + [33.84, -11.56], + [33.82, -11.57], + [33.81, -11.58], + [33.79, -11.59], + [33.78, -11.62], + [33.77, -11.67], + [33.78, -11.73], + [33.79, -11.75], + [33.8, -11.76], + [33.81, -11.78], + [33.82, -11.79], + [33.81, -11.85], + [33.8, -11.87], + [33.81, -11.91], + [33.82, -11.98], + [33.8, -12.03], + [33.79, -12.04], + [33.76, -12.05], + [33.74, -12.06], + [33.73, -12.07], + [33.72, -12.08], + [33.73, -12.11], + [33.75, -12.12], + [33.76, -12.13], + [33.77, -12.14], + [33.78, -12.2], + [33.76, -12.22], + [33.77, -12.27], + [33.78, -12.28], + [33.79, -12.29], + [33.83, -12.3], + [33.85, -12.31], + [33.86, -12.34], + [33.87, -12.35], + [33.89, -12.38], + [33.9, -12.41], + [33.91, -12.44], + [33.92, -12.45], + [33.93, -12.46], + [33.97, -12.47], + [34.01, -12.48], + [34.02, -12.49], + [34.08, -12.48], + [34.1, -12.49], + [34.11, -12.5], + [34.09, -12.52], + [34.08, -12.53], + [34.07, -12.55], + [34.06, -12.56], + [34.04, -12.57], + [34, -12.58], + [33.98, -12.59], + [33.97, -12.6], + [33.94, -12.61], + [33.91, -12.62], + [33.89, -12.63], + [33.86, -12.68], + [33.84, -12.71], + [33.82, -12.72], + [33.78, -12.7], + [33.77, -12.69], + [33.74, -12.7], + [33.73, -12.71], + [33.65, -12.7], + [33.64, -12.69], + [33.62, -12.66], + [33.61, -12.65], + [33.57, -12.64], + [33.58, -12.58], + [33.59, -12.57], + [33.58, -12.56], + [33.56, -12.53], + [33.57, -12.44], + [33.58, -12.42], + [33.59, -12.4], + [33.58, -12.39], + [33.53, -12.38], + [33.51, -12.37], + [33.53, -12.36], + [33.51, -12.33], + [33.46, -12.32], + [33.38, -12.34], + [33.35, -12.33], + [33.33, -12.3], + [33.31, -12.23], + [33.3, -12.2], + [33.29, -12.18], + [33.26, -12.16], + [33.25, -12.14], + [33.29, -11.98], + [33.3, -11.93], + [33.31, -11.91], + [33.3, -11.86], + [33.31, -11.81], + [33.3, -11.61], + [33.28, -11.58], + [33.22, -11.57], + [33.21, -11.56], + [33.23, -11.53], + [33.24, -11.4], + [33.27, -11.42] + ], + "Kasungu": [ + [33.33, -12.54], + [33.35, -12.53], + [33.37, -12.52], + [33.39, -12.5], + [33.41, -12.48], + [33.42, -12.46], + [33.45, -12.45], + [33.46, -12.44], + [33.47, -12.41], + [33.49, -12.39], + [33.51, -12.37], + [33.53, -12.38], + [33.57, -12.39], + [33.59, -12.4], + [33.58, -12.41], + [33.57, -12.43], + [33.56, -12.44], + [33.58, -12.54], + [33.59, -12.57], + [33.58, -12.58], + [33.57, -12.59], + [33.58, -12.65], + [33.62, -12.66], + [33.64, -12.69], + [33.65, -12.7], + [33.66, -12.71], + [33.73, -12.7], + [33.75, -12.69], + [33.78, -12.7], + [33.8, -12.72], + [33.83, -12.71], + [33.82, -12.79], + [33.83, -12.84], + [33.84, -12.85], + [33.9, -12.84], + [33.93, -12.85], + [33.95, -12.87], + [33.96, -12.88], + [34, -12.92], + [33.99, -12.95], + [33.95, -12.98], + [33.94, -12.99], + [33.93, -13.01], + [33.92, -13.02], + [33.85, -13.06], + [33.83, -13.07], + [33.82, -13.09], + [33.81, -13.1], + [33.79, -13.11], + [33.78, -13.12], + [33.77, -13.13], + [33.76, -13.15], + [33.74, -13.17], + [33.73, -13.18], + [33.72, -13.19], + [33.71, -13.2], + [33.7, -13.21], + [33.66, -13.22], + [33.65, -13.23], + [33.6, -13.25], + [33.59, -13.27], + [33.58, -13.29], + [33.56, -13.3], + [33.55, -13.32], + [33.54, -13.33], + [33.53, -13.34], + [33.49, -13.33], + [33.48, -13.32], + [33.46, -13.33], + [33.47, -13.35], + [33.46, -13.4], + [33.45, -13.42], + [33.44, -13.45], + [33.42, -13.48], + [33.41, -13.49], + [33.4, -13.5], + [33.38, -13.52], + [33.39, -13.54], + [33.38, -13.58], + [33.35, -13.61], + [33.33, -13.63], + [33.29, -13.58], + [33.27, -13.57], + [33.26, -13.56], + [33.24, -13.54], + [33.21, -13.51], + [33.19, -13.49], + [33.18, -13.48], + [33.17, -13.45], + [33.16, -13.42], + [33.15, -13.4], + [33.16, -13.37], + [33.15, -13.35], + [33.14, -13.34], + [32.92, -13.35], + [32.94, -13.26], + [32.96, -13.22], + [33, -13.2], + [32.98, -13.17], + [32.97, -13.15], + [32.98, -13.01], + [33.01, -12.95], + [32.98, -12.87], + [32.95, -12.85], + [32.94, -12.77], + [32.96, -12.73], + [32.99, -12.67], + [33.02, -12.61], + [33.04, -12.6], + [33.05, -12.59], + [33.06, -12.58], + [33.07, -12.59], + [33.08, -12.6], + [33.1, -12.59], + [33.12, -12.58], + [33.14, -12.59], + [33.16, -12.62], + [33.18, -12.61], + [33.19, -12.6], + [33.2, -12.59], + [33.23, -12.58], + [33.24, -12.54], + [33.26, -12.53], + [33.29, -12.52], + [33.3, -12.53], + [33.32, -12.54] + ], + "Mchinji": [ + [32.71, -13.58], + [32.72, -13.57], + [32.75, -13.55], + [32.76, -13.54], + [32.81, -13.53], + [32.82, -13.51], + [32.83, -13.46], + [32.87, -13.44], + [32.89, -13.4], + [32.91, -13.35], + [33.14, -13.34], + [33.15, -13.35], + [33.16, -13.36], + [33.15, -13.39], + [33.16, -13.42], + [33.17, -13.45], + [33.18, -13.48], + [33.19, -13.49], + [33.21, -13.51], + [33.24, -13.54], + [33.26, -13.56], + [33.27, -13.57], + [33.29, -13.58], + [33.33, -13.63], + [33.32, -13.65], + [33.31, -13.66], + [33.3, -13.68], + [33.29, -13.7], + [33.28, -13.71], + [33.29, -13.73], + [33.28, -13.75], + [33.27, -13.77], + [33.26, -13.81], + [33.25, -13.83], + [33.26, -13.86], + [33.27, -13.87], + [33.28, -13.88], + [33.29, -13.89], + [33.3, -13.9], + [33.32, -13.94], + [33.33, -13.97], + [33.34, -13.98], + [33.33, -14.02], + [33.34, -14.03], + [33.33, -14.1], + [33.35, -14.16], + [33.36, -14.21], + [33.35, -14.23], + [33.34, -14.22], + [33.32, -14.21], + [33.29, -14.16], + [33.28, -14.06], + [33.26, -14.04], + [33.2, -14.01], + [33.19, -13.99], + [33.15, -13.94], + [33.14, -13.92], + [33.13, -13.93], + [33.12, -13.96], + [33.08, -13.97], + [33.06, -13.98], + [33.05, -14], + [33.02, -14.05], + [32.98, -14.02], + [32.97, -14.01], + [32.98, -13.95], + [32.97, -13.94], + [32.96, -13.93], + [32.93, -13.91], + [32.92, -13.88], + [32.87, -13.82], + [32.86, -13.81], + [32.83, -13.8], + [32.79, -13.79], + [32.76, -13.78], + [32.77, -13.74], + [32.8, -13.72], + [32.81, -13.71], + [32.77, -13.65], + [32.74, -13.64], + [32.68, -13.63], + [32.66, -13.6], + [32.67, -13.58], + [32.68, -13.57], + [32.71, -13.58] + ], + "Nkhotakota": [ + [34.36, -12.2], + [34.38, -12.29], + [34.44, -12.5], + [34.49, -12.69], + [34.51, -12.8], + [34.52, -12.94], + [34.54, -13.06], + [34.55, -13.16], + [34.54, -13.24], + [34.55, -13.33], + [34.58, -13.4], + [34.24, -13.45], + [34.2, -13.47], + [34.16, -13.48], + [34.13, -13.49], + [34.12, -13.36], + [34.1, -13.28], + [34.11, -13.27], + [34.1, -13.17], + [34.09, -13.16], + [34.06, -13.15], + [34.02, -13.12], + [34.01, -13.13], + [34, -13.15], + [33.99, -13.16], + [33.98, -13.17], + [33.96, -13.16], + [33.95, -13.15], + [33.94, -13.1], + [33.93, -13.09], + [33.92, -13.07], + [33.93, -13.01], + [33.94, -12.99], + [33.95, -12.98], + [33.99, -12.95], + [34, -12.94], + [33.96, -12.88], + [33.95, -12.87], + [33.94, -12.85], + [33.92, -12.84], + [33.85, -12.85], + [33.83, -12.84], + [33.82, -12.83], + [33.84, -12.71], + [33.86, -12.68], + [33.88, -12.63], + [33.9, -12.62], + [33.94, -12.61], + [33.97, -12.6], + [33.98, -12.59], + [34, -12.58], + [34.01, -12.57], + [34.06, -12.56], + [34.07, -12.55], + [34.08, -12.53], + [34.09, -12.52], + [34.1, -12.5], + [34.09, -12.48], + [34.06, -12.49], + [34.01, -12.48], + [33.97, -12.47], + [33.96, -12.46], + [33.92, -12.45], + [33.91, -12.44], + [33.9, -12.43], + [33.89, -12.39], + [33.87, -12.35], + [33.86, -12.34], + [33.85, -12.31], + [33.83, -12.3], + [33.82, -12.29], + [33.78, -12.28], + [33.77, -12.27], + [33.76, -12.26], + [33.78, -12.2], + [33.84, -12.14], + [33.9, -12.16], + [33.91, -12.17], + [33.96, -12.19], + [34.03, -12.2] + ], + "Salima": [ + [34.58, -13.4], + [34.6, -13.42], + [34.61, -13.44], + [34.63, -13.47], + [34.64, -13.48], + [34.65, -13.5], + [34.86, -13.52], + [34.74, -14.08], + [34.55, -14.07], + [34.54, -14.08], + [34.53, -14.09], + [34.51, -14.11], + [34.47, -14.09], + [34.44, -14.05], + [34.4, -13.99], + [34.39, -13.97], + [34.33, -13.91], + [34.28, -13.85], + [34.21, -13.87], + [34.18, -13.86], + [34.19, -13.85], + [34.2, -13.84], + [34.21, -13.83], + [34.24, -13.82], + [34.25, -13.81], + [34.26, -13.77], + [34.29, -13.76], + [34.3, -13.75], + [34.31, -13.74], + [34.3, -13.73], + [34.29, -13.72], + [34.28, -13.71], + [34.29, -13.7], + [34.28, -13.68], + [34.27, -13.67], + [34.23, -13.69], + [34.19, -13.68], + [34.14, -13.64], + [34.13, -13.63], + [34.12, -13.62], + [34.13, -13.61], + [34.12, -13.5], + [34.13, -13.49], + [34.16, -13.48], + [34.18, -13.47], + [34.24, -13.45], + [34.33, -13.4] + ], + "Mangochi": [ + [34.86, -13.52], + [34.89, -13.53], + [35, -13.63], + [35.08, -13.7], + [35.17, -13.81], + [35.28, -13.93], + [35.37, -14.04], + [35.46, -14.14], + [35.52, -14.26], + [35.61, -14.37], + [35.71, -14.5], + [35.75, -14.54], + [35.72, -14.57], + [35.65, -14.58], + [35.6, -14.59], + [35.58, -14.6], + [35.56, -14.61], + [35.55, -14.62], + [35.54, -14.63], + [35.55, -14.67], + [35.54, -14.69], + [35.53, -14.71], + [35.51, -14.72], + [35.5, -14.73], + [35.47, -14.75], + [35.46, -14.76], + [35.37, -14.74], + [35.35, -14.73], + [35.34, -14.71], + [35.33, -14.7], + [35.31, -14.69], + [35.3, -14.68], + [35.28, -14.69], + [35.27, -14.71], + [35.28, -14.75], + [35, -14.76], + [34.96, -14.73], + [34.93, -14.72], + [34.91, -14.71], + [34.8, -14.55], + [34.77, -14.47], + [34.75, -14.4], + [34.74, -14.08], + [34.86, -13.52] + ], + "Machinga": [ + [35.75, -14.54], + [35.79, -14.59], + [35.84, -14.64], + [35.85, -14.65], + [35.86, -14.88], + [35.87, -14.89], + [35.84, -15.04], + [35.79, -15.15], + [35.78, -15.17], + [35.79, -15.21], + [35.51, -15.22], + [35.5, -15.23], + [35.47, -15.24], + [35.37, -15.22], + [35.35, -15.21], + [35.33, -15.22], + [35.31, -15.24], + [35.3, -15.25], + [35.27, -15.24], + [35.24, -15.23], + [35.23, -15.24], + [35.21, -15.25], + [35.2, -15.26], + [35.19, -15.25], + [35.17, -15.23], + [35.18, -15.22], + [35.19, -15.21], + [35.21, -15.15], + [35.23, -15.09], + [35.24, -15.05], + [35.27, -14.99], + [35.29, -14.98], + [35.3, -14.97], + [35.31, -14.95], + [35.32, -14.87], + [35.31, -14.83], + [35.3, -14.78], + [35.28, -14.76], + [35.27, -14.73], + [35.28, -14.7], + [35.29, -14.68], + [35.31, -14.69], + [35.33, -14.7], + [35.34, -14.71], + [35.35, -14.73], + [35.36, -14.74], + [35.43, -14.76], + [35.47, -14.75], + [35.5, -14.73], + [35.51, -14.72], + [35.52, -14.71], + [35.54, -14.69], + [35.55, -14.68], + [35.54, -14.63], + [35.55, -14.62], + [35.56, -14.61], + [35.58, -14.6], + [35.6, -14.59], + [35.65, -14.58], + [35.67, -14.57], + [35.75, -14.54] + ], + "Dedza": [ + [33.66, -14.61], + [33.64, -14.6], + [33.63, -14.59], + [33.62, -14.58], + [33.64, -14.55], + [33.65, -14.53], + [33.69, -14.49], + [33.7, -14.42], + [33.71, -14.4], + [33.72, -14.39], + [33.73, -14.38], + [33.8, -14.35], + [33.81, -14.34], + [33.82, -14.33], + [33.84, -14.31], + [33.91, -14.3], + [33.92, -14.29], + [33.94, -14.28], + [33.95, -14.27], + [33.96, -14.21], + [33.98, -14.19], + [34.02, -14.18], + [34.04, -14.17], + [34.05, -14.16], + [34.06, -14.14], + [34.08, -14.13], + [34.09, -14.11], + [34.1, -14.08], + [34.11, -14.07], + [34.12, -14.06], + [34.13, -14.04], + [34.15, -14.03], + [34.16, -14.01], + [34.17, -14], + [34.2, -13.95], + [34.21, -13.92], + [34.22, -13.91], + [34.25, -13.9], + [34.27, -13.88], + [34.28, -13.85], + [34.33, -13.91], + [34.39, -13.97], + [34.4, -13.99], + [34.44, -14.05], + [34.47, -14.09], + [34.48, -14.11], + [34.53, -14.09], + [34.54, -14.08], + [34.55, -14.07], + [34.74, -14.08], + [34.75, -14.26], + [34.67, -14.35], + [34.59, -14.41], + [34.54, -14.43], + [34.5, -14.42], + [34.48, -14.41], + [34.46, -14.4], + [34.41, -14.39], + [34.4, -14.4], + [34.38, -14.41], + [34.37, -14.4], + [34.34, -14.39], + [34.32, -14.4], + [34.3, -14.41], + [34.29, -14.4], + [34.18, -14.44], + [34.08, -14.45], + [34.07, -14.46], + [34.06, -14.49], + [34.05, -14.5], + [33.95, -14.48], + [33.89, -14.49], + [33.83, -14.52], + [33.8, -14.53], + [33.72, -14.49], + [33.7, -14.5], + [33.68, -14.52], + [33.67, -14.6], + [33.66, -14.61] + ], + "Lilongwe": [ + [33.62, -14.56], + [33.6, -14.52], + [33.58, -14.5], + [33.56, -14.49], + [33.55, -14.48], + [33.54, -14.47], + [33.53, -14.46], + [33.51, -14.43], + [33.47, -14.41], + [33.46, -14.4], + [33.44, -14.38], + [33.39, -14.28], + [33.37, -14.26], + [33.36, -14.23], + [33.35, -14.16], + [33.33, -14.12], + [33.34, -14.07], + [33.33, -14.02], + [33.34, -14.01], + [33.33, -13.97], + [33.32, -13.94], + [33.3, -13.9], + [33.29, -13.89], + [33.28, -13.88], + [33.27, -13.87], + [33.26, -13.86], + [33.25, -13.84], + [33.26, -13.82], + [33.27, -13.8], + [33.28, -13.76], + [33.29, -13.73], + [33.28, -13.72], + [33.29, -13.7], + [33.3, -13.69], + [33.31, -13.67], + [33.32, -13.65], + [33.33, -13.64], + [33.35, -13.61], + [33.38, -13.58], + [33.39, -13.57], + [33.38, -13.53], + [33.39, -13.5], + [33.41, -13.49], + [33.42, -13.48], + [33.44, -13.49], + [33.45, -13.5], + [33.44, -13.55], + [33.46, -13.64], + [33.47, -13.67], + [33.48, -13.68], + [33.52, -13.7], + [33.74, -13.66], + [33.76, -13.67], + [33.77, -13.71], + [33.79, -13.76], + [33.97, -13.77], + [33.99, -13.78], + [34.01, -13.79], + [34.02, -13.8], + [34.03, -13.81], + [34.05, -13.82], + [34.12, -13.81], + [34.15, -13.8], + [34.16, -13.79], + [34.21, -13.8], + [34.25, -13.78], + [34.24, -13.82], + [34.21, -13.83], + [34.2, -13.84], + [34.19, -13.85], + [34.18, -13.86], + [34.19, -13.87], + [34.25, -13.85], + [34.27, -13.88], + [34.25, -13.9], + [34.22, -13.91], + [34.21, -13.92], + [34.2, -13.93], + [34.17, -14], + [34.16, -14.01], + [34.15, -14.03], + [34.13, -14.04], + [34.12, -14.06], + [34.11, -14.07], + [34.1, -14.08], + [34.09, -14.11], + [34.08, -14.13], + [34.06, -14.14], + [34.05, -14.16], + [34.04, -14.17], + [34.03, -14.18], + [33.98, -14.19], + [33.96, -14.2], + [33.95, -14.22], + [33.94, -14.28], + [33.93, -14.29], + [33.91, -14.3], + [33.88, -14.31], + [33.82, -14.33], + [33.81, -14.34], + [33.8, -14.35], + [33.73, -14.38], + [33.72, -14.39], + [33.71, -14.4], + [33.7, -14.41], + [33.69, -14.44], + [33.66, -14.53], + [33.64, -14.54], + [33.62, -14.56] + ], + "Nsanje": [ + [35.03, -16.82], + [35, -16.81], + [34.98, -16.79], + [34.96, -16.77], + [34.95, -16.76], + [34.93, -16.75], + [34.91, -16.74], + [34.9, -16.73], + [34.89, -16.71], + [34.92, -16.66], + [34.93, -16.64], + [34.95, -16.63], + [34.97, -16.62], + [34.98, -16.57], + [35.03, -16.51], + [35.05, -16.49], + [35.06, -16.48], + [35.1, -16.33], + [35.15, -16.39], + [35.17, -16.4], + [35.19, -16.38], + [35.24, -16.4], + [35.23, -16.41], + [35.21, -16.48], + [35.14, -16.53], + [35.13, -16.54], + [35.15, -16.58], + [35.16, -16.61], + [35.17, -16.62], + [35.19, -16.63], + [35.22, -16.64], + [35.23, -16.65], + [35.24, -16.66], + [35.25, -16.67], + [35.28, -16.7], + [35.29, -16.79], + [35.31, -16.83], + [35.29, -16.87], + [35.28, -16.89], + [35.29, -16.93], + [35.28, -16.94], + [35.27, -16.95], + [35.28, -16.96], + [35.31, -16.97], + [35.3, -17.01], + [35.31, -17.07], + [35.3, -17.1], + [35.29, -17.13], + [35.23, -17.14], + [35.13, -17.13], + [35.08, -17.12], + [35.07, -17.11], + [35.04, -17.04], + [35.07, -16.99], + [35.09, -16.98], + [35.11, -16.96], + [35.13, -16.93], + [35.12, -16.83], + [35.1, -16.82] + ], + "Chikwawa": [ + [34.89, -16.7], + [34.88, -16.69], + [34.84, -16.68], + [34.83, -16.66], + [34.82, -16.63], + [34.77, -16.59], + [34.76, -16.58], + [34.74, -16.54], + [34.73, -16.53], + [34.67, -16.5], + [34.66, -16.49], + [34.64, -16.46], + [34.63, -16.44], + [34.6, -16.42], + [34.59, -16.41], + [34.58, -16.39], + [34.55, -16.32], + [34.52, -16.3], + [34.48, -16.29], + [34.43, -16.27], + [34.39, -16.19], + [34.41, -16.09], + [34.4, -16.06], + [34.39, -16.04], + [34.3, -15.95], + [34.29, -15.94], + [34.26, -15.93], + [34.24, -15.92], + [34.23, -15.89], + [34.24, -15.82], + [34.25, -15.79], + [34.28, -15.76], + [34.29, -15.75], + [34.31, -15.74], + [34.34, -15.73], + [34.36, -15.74], + [34.5, -15.79], + [34.54, -15.81], + [34.85, -15.82], + [34.87, -15.83], + [34.88, -15.85], + [34.86, -15.89], + [34.85, -15.96], + [34.86, -15.97], + [34.88, -15.98], + [34.89, -16.03], + [34.95, -16.12], + [35.08, -16.26], + [35.1, -16.33], + [35.06, -16.48], + [35.05, -16.49], + [35.03, -16.51], + [34.98, -16.57], + [34.97, -16.58], + [34.96, -16.63], + [34.93, -16.64], + [34.92, -16.66], + [34.89, -16.69] + ], + "Mwanza": [ + [34.34, -15.73], + [34.4, -15.65], + [34.42, -15.62], + [34.54, -15.59], + [34.66, -15.6], + [34.76, -15.61], + [34.77, -15.67], + [34.76, -15.68], + [34.75, -15.69], + [34.74, -15.7], + [34.75, -15.81], + [34.5, -15.79], + [34.36, -15.74], + [34.34, -15.73] + ], + "Neno": [ + [34.42, -15.58], + [34.41, -15.51], + [34.42, -15.46], + [34.46, -15.42], + [34.48, -15.41], + [34.49, -15.4], + [34.5, -15.36], + [34.51, -15.35], + [34.52, -15.34], + [34.53, -15.33], + [34.55, -15.32], + [34.57, -15.3], + [34.56, -15.2], + [34.62, -15.21], + [34.68, -15.23], + [34.77, -15.24], + [34.78, -15.25], + [34.81, -15.26], + [34.82, -15.28], + [34.83, -15.33], + [34.84, -15.31], + [35.05, -15.32], + [35.01, -15.35], + [34.99, -15.36], + [34.95, -15.37], + [34.92, -15.39], + [34.89, -15.42], + [34.86, -15.52], + [34.84, -15.55], + [34.78, -15.58], + [34.77, -15.59], + [34.76, -15.61], + [34.66, -15.6], + [34.54, -15.59], + [34.42, -15.58] + ], + "Ntcheu": [ + [34.56, -15.2], + [34.55, -15.12], + [34.56, -15.1], + [34.55, -15.07], + [34.57, -15.02], + [34.58, -15], + [34.57, -14.95], + [34.56, -14.94], + [34.55, -14.92], + [34.54, -14.8], + [34.53, -14.77], + [34.52, -14.73], + [34.51, -14.7], + [34.52, -14.64], + [34.5, -14.58], + [34.45, -14.53], + [34.43, -14.5], + [34.39, -14.43], + [34.38, -14.41], + [34.39, -14.4], + [34.41, -14.39], + [34.44, -14.4], + [34.47, -14.41], + [34.5, -14.42], + [34.51, -14.43], + [34.59, -14.41], + [34.67, -14.35], + [34.75, -14.3], + [34.77, -14.47], + [34.8, -14.55], + [34.91, -14.71], + [34.93, -14.72], + [34.96, -14.73], + [34.99, -14.76], + [34.97, -14.88], + [34.92, -14.96], + [34.91, -14.97], + [34.92, -14.98], + [34.84, -15.31], + [34.83, -15.33], + [34.82, -15.32], + [34.81, -15.27], + [34.8, -15.25], + [34.77, -15.24], + [34.73, -15.23], + [34.62, -15.21], + [34.57, -15.2] + ], + "Zomba": [ + [35.79, -15.21], + [35.81, -15.3], + [35.84, -15.42], + [35.72, -15.46], + [35.69, -15.47], + [35.66, -15.49], + [35.65, -15.5], + [35.62, -15.52], + [35.57, -15.56], + [35.55, -15.57], + [35.54, -15.58], + [35.53, -15.61], + [35.5, -15.62], + [35.49, -15.63], + [35.47, -15.66], + [35.46, -15.67], + [35.38, -15.68], + [35.3, -15.67], + [35.28, -15.66], + [35.27, -15.65], + [35.26, -15.63], + [35.25, -15.62], + [35.24, -15.6], + [35.23, -15.58], + [35.21, -15.57], + [35.19, -15.56], + [35.18, -15.53], + [35.16, -15.54], + [35.12, -15.53], + [35.11, -15.52], + [35.12, -15.51], + [35.14, -15.49], + [35.13, -15.47], + [35.09, -15.45], + [35.05, -15.41], + [35.03, -15.39], + [35.01, -15.35], + [35.05, -15.32], + [35.09, -15.31], + [35.11, -15.3], + [35.13, -15.27], + [35.17, -15.23], + [35.18, -15.25], + [35.19, -15.26], + [35.21, -15.25], + [35.22, -15.24], + [35.24, -15.23], + [35.26, -15.24], + [35.29, -15.25], + [35.31, -15.24], + [35.32, -15.22], + [35.34, -15.21], + [35.37, -15.22], + [35.42, -15.24], + [35.49, -15.23], + [35.51, -15.22], + [35.52, -15.21] + ], + "Phalombe": [ + [35.84, -15.46], + [35.83, -15.54], + [35.82, -15.66], + [35.81, -15.9], + [35.8, -15.93], + [35.76, -15.94], + [35.72, -15.93], + [35.7, -15.92], + [35.68, -15.9], + [35.67, -15.89], + [35.64, -15.9], + [35.6, -15.94], + [35.57, -15.85], + [35.55, -15.84], + [35.54, -15.83], + [35.52, -15.81], + [35.51, -15.7], + [35.5, -15.69], + [35.51, -15.66], + [35.52, -15.65], + [35.53, -15.64], + [35.54, -15.62], + [35.53, -15.61], + [35.54, -15.58], + [35.55, -15.57], + [35.56, -15.56], + [35.62, -15.52], + [35.65, -15.5], + [35.66, -15.49], + [35.69, -15.47], + [35.72, -15.46] + ], + "Mulanje": [ + [35.8, -15.93], + [35.79, -15.96], + [35.8, -16], + [35.79, -16.02], + [35.77, -16.06], + [35.7, -16.11], + [35.55, -16.14], + [35.52, -16.15], + [35.51, -16.17], + [35.49, -16.16], + [35.47, -16.14], + [35.46, -16.13], + [35.44, -16.12], + [35.39, -16.13], + [35.37, -16.14], + [35.3, -16.2], + [35.28, -16.19], + [35.29, -16.16], + [35.3, -16.15], + [35.31, -16.13], + [35.32, -16.1], + [35.31, -16.01], + [35.32, -15.97], + [35.33, -15.96], + [35.32, -15.78], + [35.34, -15.68], + [35.39, -15.67], + [35.47, -15.66], + [35.49, -15.63], + [35.5, -15.62], + [35.53, -15.61], + [35.54, -15.62], + [35.53, -15.63], + [35.52, -15.64], + [35.51, -15.66], + [35.5, -15.68], + [35.51, -15.69], + [35.52, -15.79], + [35.53, -15.83], + [35.54, -15.84], + [35.55, -15.85], + [35.6, -15.93], + [35.64, -15.9], + [35.67, -15.89], + [35.68, -15.9], + [35.7, -15.92], + [35.71, -15.93], + [35.73, -15.94], + [35.76, -15.93] + ], + "Thyolo": [ + [35.3, -16.21], + [35.28, -16.23], + [35.26, -16.27], + [35.25, -16.32], + [35.27, -16.36], + [35.26, -16.37], + [35.24, -16.39], + [35.19, -16.38], + [35.17, -16.39], + [35.1, -16.33], + [35.08, -16.29], + [34.95, -16.12], + [34.89, -16.03], + [34.92, -16.02], + [34.93, -16.01], + [34.95, -15.99], + [34.96, -15.98], + [34.98, -15.95], + [34.99, -15.94], + [35, -15.93], + [35.04, -15.92], + [35.15, -15.86], + [35.2, -15.87], + [35.21, -15.88], + [35.25, -15.92], + [35.26, -15.93], + [35.27, -15.96], + [35.28, -15.98], + [35.29, -15.99], + [35.31, -16.01], + [35.32, -16.1], + [35.31, -16.13], + [35.3, -16.14], + [35.29, -16.16], + [35.28, -16.17], + [35.29, -16.2], + [35.3, -16.21] + ], + "Dowa": [ + [34.12, -13.5], + [34.13, -13.58], + [34.12, -13.61], + [34.13, -13.63], + [34.14, -13.64], + [34.19, -13.68], + [34.2, -13.69], + [34.26, -13.67], + [34.28, -13.68], + [34.29, -13.69], + [34.28, -13.71], + [34.29, -13.72], + [34.3, -13.73], + [34.31, -13.74], + [34.3, -13.75], + [34.29, -13.76], + [34.28, -13.77], + [34.25, -13.78], + [34.22, -13.8], + [34.18, -13.79], + [34.15, -13.8], + [34.14, -13.81], + [34.1, -13.82], + [34.03, -13.81], + [34.02, -13.8], + [34.01, -13.79], + [34, -13.78], + [33.97, -13.77], + [33.94, -13.76], + [33.77, -13.75], + [33.76, -13.69], + [33.75, -13.66], + [33.58, -13.7], + [33.48, -13.68], + [33.47, -13.67], + [33.46, -13.65], + [33.44, -13.56], + [33.45, -13.51], + [33.44, -13.49], + [33.42, -13.48], + [33.44, -13.45], + [33.45, -13.42], + [33.46, -13.4], + [33.47, -13.37], + [33.46, -13.35], + [33.47, -13.32], + [33.48, -13.33], + [33.5, -13.34], + [33.54, -13.33], + [33.55, -13.32], + [33.56, -13.3], + [33.58, -13.29], + [33.59, -13.28], + [33.6, -13.25], + [33.62, -13.23], + [33.63, -13.27], + [33.64, -13.28], + [33.65, -13.29], + [33.67, -13.3], + [33.69, -13.32], + [33.71, -13.34], + [33.72, -13.36], + [33.74, -13.42], + [33.75, -13.49], + [33.76, -13.5], + [33.77, -13.51], + [33.87, -13.49], + [33.94, -13.5], + [34.05, -13.52], + [34.11, -13.51], + [34.12, -13.5] + ], + "Balaka": [ + [35.17, -15.23], + [35.13, -15.27], + [35.11, -15.3], + [35.09, -15.31], + [35.05, -15.32], + [34.84, -15.31], + [34.92, -14.99], + [34.91, -14.97], + [34.92, -14.96], + [34.97, -14.89], + [34.99, -14.82], + [35, -14.76], + [35.3, -14.78], + [35.31, -14.83], + [35.32, -14.87], + [35.31, -14.95], + [35.3, -14.97], + [35.29, -14.98], + [35.27, -14.99], + [35.24, -15.04], + [35.23, -15.06], + [35.21, -15.12], + [35.19, -15.19], + [35.18, -15.22], + [35.17, -15.23] + ], + "Chiradzulu": [ + [35.19, -15.52], + [35.2, -15.57], + [35.23, -15.58], + [35.24, -15.59], + [35.25, -15.62], + [35.26, -15.63], + [35.27, -15.65], + [35.28, -15.66], + [35.3, -15.67], + [35.34, -15.68], + [35.32, -15.74], + [35.33, -15.94], + [35.32, -15.97], + [35.31, -16.01], + [35.29, -15.99], + [35.28, -15.98], + [35.27, -15.97], + [35.26, -15.94], + [35.25, -15.92], + [35.21, -15.89], + [35.2, -15.87], + [35.19, -15.86], + [35.12, -15.82], + [35.11, -15.64], + [35.1, -15.62], + [35.14, -15.54], + [35.16, -15.53], + [35.19, -15.52] + ], + "Blantyre": [ + [35.14, -15.54], + [35.1, -15.6], + [35.11, -15.63], + [35.12, -15.66], + [35.15, -15.86], + [35.04, -15.92], + [35.03, -15.93], + [34.99, -15.94], + [34.98, -15.95], + [34.96, -15.98], + [34.95, -15.99], + [34.93, -16.01], + [34.92, -16.02], + [34.89, -16.03], + [34.88, -16.02], + [34.87, -15.97], + [34.85, -15.96], + [34.86, -15.93], + [34.88, -15.87], + [34.87, -15.83], + [34.86, -15.82], + [34.75, -15.81], + [34.74, -15.74], + [34.75, -15.69], + [34.76, -15.68], + [34.77, -15.67], + [34.76, -15.61], + [34.77, -15.59], + [34.78, -15.58], + [34.83, -15.55], + [34.86, -15.52], + [34.89, -15.42], + [34.91, -15.39], + [34.95, -15.37], + [34.96, -15.36], + [35.01, -15.35], + [35.03, -15.39], + [35.05, -15.41], + [35.09, -15.45], + [35.1, -15.47], + [35.14, -15.48], + [35.12, -15.51], + [35.11, -15.52], + [35.12, -15.53], + [35.13, -15.54] + ], + "Ntchisi": [ + [33.92, -13.02], + [33.93, -13.09], + [33.94, -13.1], + [33.95, -13.12], + [33.96, -13.16], + [33.97, -13.17], + [33.99, -13.16], + [34, -13.15], + [34.01, -13.13], + [34.02, -13.12], + [34.06, -13.11], + [34.07, -13.16], + [34.1, -13.17], + [34.11, -13.18], + [34.1, -13.28], + [34.12, -13.36], + [34.13, -13.49], + [34.12, -13.5], + [34.11, -13.51], + [34.08, -13.52], + [34, -13.5], + [33.91, -13.49], + [33.82, -13.51], + [33.76, -13.5], + [33.75, -13.49], + [33.74, -13.48], + [33.72, -13.36], + [33.71, -13.34], + [33.69, -13.32], + [33.67, -13.3], + [33.65, -13.29], + [33.64, -13.28], + [33.63, -13.27], + [33.62, -13.23], + [33.66, -13.22], + [33.68, -13.21], + [33.71, -13.2], + [33.72, -13.19], + [33.73, -13.18], + [33.74, -13.17], + [33.76, -13.15], + [33.77, -13.13], + [33.78, -13.12], + [33.79, -13.11], + [33.81, -13.1], + [33.82, -13.09], + [33.83, -13.08], + [33.84, -13.06], + [33.92, -13.02] + ] +} diff --git a/libs/data/geoLocation/types.ts b/libs/data/geoLocation/types.ts new file mode 100644 index 000000000..6b5c6a47f --- /dev/null +++ b/libs/data/geoLocation/types.ts @@ -0,0 +1,21 @@ +export interface IGelocationData { + admin_1: { + label: string; + data: () => Promise; + }; +} + +export interface IGeoJsonData> { + type: string; + crs: { type: string; properties: { name: string } }; + features: { + type: string; + properties: T; + geometry: { + type: string; + coordinates: [number, number][][][]; + }; + }[]; +} + +export type IBoundaryData = Record; diff --git a/libs/data/geoLocation/utils.ts b/libs/data/geoLocation/utils.ts new file mode 100644 index 000000000..2e68e7fca --- /dev/null +++ b/libs/data/geoLocation/utils.ts @@ -0,0 +1,82 @@ +import { IBoundaryData, IGeoJsonData } from './types'; + +/** + * Take input geoJson feature collection data and extract coordinates into a a more simple + * coordinate lookup table + * @param propertyKeyField name of field within feature properties to use to index output + * @param precision number or decimal places used to round coordinate values and omit duplicates + * + * NOTE - this is not a fully reversible process. Additional metadata fields CRS and geometry + * types are dropped in the process and should be repopulated from hardcoded data + **/ +export function geoJsonToBoundaries(data: IGeoJsonData, propertyKeyField: keyof T, precision = 2) { + const boundaries: IBoundaryData = {}; + + for (const feature of data.features) { + const key = feature.properties[propertyKeyField] as string; + if (!key) { + const allKeys = Object.keys(feature.properties as any).join(','); + const errMsg = `[${propertyKeyField as any}] not found\nAvailable keys: [${allKeys}]`; + throw new Error(errMsg); + } + if (boundaries[key]) { + throw new Error(`duplicate key found for: ${key}`); + } + + const coordinates: [number, number][] = []; + let x1 = -1; + let y1 = -1; + const allCoordinates = flattenCoordinates(feature.geometry.coordinates); + for (const [x, y] of allCoordinates) { + // round x and y values to number of decimal places provided by precision + const sf = 10 ** precision; + const xRounded = Math.round(x * sf) / sf; + const yRounded = Math.round(y * sf) / sf; + // include coordinates only if different from previous (after rounding) + if (x1 !== xRounded && y1 !== yRounded) { + coordinates.push([xRounded, yRounded]); + x1 = xRounded; + y1 = yRounded; + } + } + + boundaries[key as any] = coordinates; + } + return boundaries; +} + +/** + * Geojson includes coordinates that can be nested various levels deep, + * e.g. [[x1,y1],[x2,y2]], [[[x1,y1],[x2,y2]],[[x3,x4]]], etc. + * Take any arbitrary level of nesting and extract to single coordinate array + */ +function flattenCoordinates(data: any[] = []): number[][] { + if (Array.isArray(data)) { + const [el] = data; + if (Array.isArray(el)) { + const [inner] = el; + if (Array.isArray(inner)) { + const flattened = [].concat(...(data as any)); + return flattenCoordinates(flattened); + } + } + } + return data; +} + +/** Take summary boundary data and convert back to GeoJson */ +export function boundariesToGeoJson(data: IBoundaryData, propertyKeyField: string) { + const geoJson: IGeoJsonData = { + type: 'FeatureCollection', + crs: { type: 'name', properties: { name: 'urn:ogc:def:crs:OGC:1.3:CRS84' } }, + features: [], + }; + for (const [key, coordinates] of Object.entries(data)) { + geoJson.features.push({ + type: 'Feature', + properties: { [propertyKeyField]: key }, + geometry: { type: 'MultiPolygon', coordinates: [[coordinates as any]] }, + }); + } + return geoJson; +} diff --git a/libs/data/geoLocation/zm/admin-0.boundaries.json b/libs/data/geoLocation/zm/admin-0.boundaries.json new file mode 100644 index 000000000..54ec92be2 --- /dev/null +++ b/libs/data/geoLocation/zm/admin-0.boundaries.json @@ -0,0 +1,930 @@ +{ + "Zambia": [ + [32.92, -9.41], + [32.93, -9.48], + [32.94, -9.49], + [32.95, -9.48], + [32.98, -9.5], + [32.99, -9.53], + [32.97, -9.6], + [32.99, -9.63], + [33.02, -9.62], + [33.05, -9.63], + [33.06, -9.65], + [33.08, -9.66], + [33.09, -9.64], + [33.1, -9.59], + [33.12, -9.6], + [33.2, -9.62], + [33.21, -9.64], + [33.22, -9.67], + [33.21, -9.68], + [33.2, -9.7], + [33.21, -9.71], + [33.22, -9.73], + [33.24, -9.74], + [33.25, -9.75], + [33.27, -9.78], + [33.28, -9.79], + [33.29, -9.8], + [33.3, -9.81], + [33.34, -9.82], + [33.36, -9.87], + [33.37, -9.9], + [33.36, -9.92], + [33.33, -9.97], + [33.31, -10.01], + [33.3, -10.04], + [33.32, -10.08], + [33.4, -10.12], + [33.42, -10.14], + [33.44, -10.15], + [33.45, -10.17], + [33.48, -10.18], + [33.5, -10.2], + [33.52, -10.21], + [33.53, -10.23], + [33.54, -10.26], + [33.53, -10.32], + [33.56, -10.4], + [33.57, -10.42], + [33.6, -10.44], + [33.62, -10.49], + [33.64, -10.51], + [33.67, -10.52], + [33.66, -10.6], + [33.64, -10.62], + [33.6, -10.64], + [33.59, -10.65], + [33.58, -10.66], + [33.53, -10.71], + [33.51, -10.75], + [33.5, -10.77], + [33.48, -10.78], + [33.45, -10.8], + [33.43, -10.81], + [33.39, -10.8], + [33.36, -10.81], + [33.32, -10.82], + [33.31, -10.83], + [33.29, -10.86], + [33.27, -10.87], + [33.25, -10.86], + [33.24, -10.87], + [33.23, -10.88], + [33.24, -10.9], + [33.28, -10.91], + [33.29, -10.94], + [33.3, -11.03], + [33.32, -11.06], + [33.34, -11.09], + [33.36, -11.11], + [33.39, -11.16], + [33.38, -11.19], + [33.37, -11.22], + [33.3, -11.33], + [33.29, -11.36], + [33.27, -11.37], + [33.24, -11.4], + [33.23, -11.42], + [33.21, -11.56], + [33.22, -11.57], + [33.23, -11.58], + [33.3, -11.59], + [33.31, -11.77], + [33.3, -11.85], + [33.31, -11.88], + [33.3, -11.93], + [33.29, -11.98], + [33.25, -12.07], + [33.26, -12.16], + [33.29, -12.18], + [33.3, -12.2], + [33.31, -12.23], + [33.33, -12.3], + [33.35, -12.33], + [33.38, -12.34], + [33.46, -12.32], + [33.5, -12.33], + [33.53, -12.34], + [33.52, -12.37], + [33.49, -12.39], + [33.48, -12.41], + [33.46, -12.42], + [33.45, -12.45], + [33.42, -12.46], + [33.41, -12.48], + [33.39, -12.5], + [33.37, -12.52], + [33.35, -12.53], + [33.33, -12.54], + [33.31, -12.53], + [33.29, -12.52], + [33.26, -12.53], + [33.24, -12.54], + [33.23, -12.58], + [33.21, -12.59], + [33.2, -12.6], + [33.18, -12.61], + [33.17, -12.62], + [33.15, -12.59], + [33.13, -12.58], + [33.11, -12.59], + [33.09, -12.6], + [33.07, -12.59], + [33.06, -12.58], + [33.05, -12.59], + [33.04, -12.6], + [33.02, -12.61], + [32.99, -12.67], + [32.96, -12.73], + [32.94, -12.75], + [32.95, -12.84], + [32.98, -12.87], + [33.01, -12.89], + [32.98, -13.01], + [32.97, -13.12], + [32.98, -13.17], + [33, -13.19], + [32.99, -13.22], + [32.94, -13.26], + [32.92, -13.29], + [32.91, -13.35], + [32.89, -13.4], + [32.87, -13.44], + [32.85, -13.46], + [32.82, -13.47], + [32.81, -13.53], + [32.8, -13.54], + [32.75, -13.55], + [32.72, -13.57], + [32.71, -13.58], + [32.69, -13.57], + [32.67, -13.58], + [32.66, -13.6], + [32.68, -13.63], + [32.71, -13.64], + [32.77, -13.65], + [32.81, -13.7], + [32.8, -13.72], + [32.77, -13.74], + [32.76, -13.75], + [32.79, -13.79], + [32.83, -13.8], + [32.86, -13.81], + [32.87, -13.82], + [32.92, -13.88], + [32.93, -13.9], + [32.94, -13.93], + [32.97, -13.94], + [32.98, -13.95], + [32.97, -13.96], + [32.98, -14.02], + [33, -14.05], + [33.05, -14], + [33.06, -13.98], + [33.08, -13.97], + [33.11, -13.96], + [33.13, -13.93], + [33.14, -13.92], + [33.15, -13.94], + [33.19, -13.99], + [33.2, -14.01], + [33.13, -14.04], + [33.04, -14.07], + [32.92, -14.11], + [32.74, -14.17], + [32.58, -14.22], + [32.43, -14.27], + [32.32, -14.31], + [32.23, -14.34], + [32.15, -14.35], + [32.11, -14.36], + [32.03, -14.4], + [31.93, -14.43], + [31.8, -14.47], + [31.66, -14.52], + [31.59, -14.55], + [31.5, -14.6], + [31.41, -14.63], + [31.31, -14.66], + [31.18, -14.69], + [31.07, -14.71], + [30.92, -14.75], + [30.82, -14.77], + [30.68, -14.82], + [30.59, -14.85], + [30.49, -14.89], + [30.39, -14.93], + [30.32, -14.97], + [30.23, -14.98], + [30.21, -14.99], + [30.22, -15.02], + [30.23, -15.11], + [30.26, -15.23], + [30.29, -15.28], + [30.32, -15.3], + [30.35, -15.32], + [30.36, -15.34], + [30.37, -15.37], + [30.39, -15.47], + [30.37, -15.53], + [30.4, -15.59], + [30.41, -15.63], + [30.4, -15.64], + [30.36, -15.65], + [30.3, -15.64], + [30.28, -15.63], + [30.23, -15.64], + [30.22, -15.65], + [30.17, -15.63], + [30.13, -15.62], + [30.09, -15.63], + [30.05, -15.64], + [30.01, -15.65], + [29.97, -15.64], + [29.88, -15.62], + [29.84, -15.61], + [29.81, -15.62], + [29.77, -15.64], + [29.67, -15.66], + [29.65, -15.67], + [29.63, -15.66], + [29.53, -15.69], + [29.51, -15.7], + [29.42, -15.71], + [29.19, -15.81], + [29.15, -15.85], + [29.12, -15.86], + [29.1, -15.87], + [29.09, -15.88], + [29.08, -15.9], + [29.06, -15.93], + [29.04, -15.95], + [28.95, -15.96], + [28.9, -16], + [28.88, -16.02], + [28.87, -16.03], + [28.86, -16.05], + [28.87, -16.08], + [28.85, -16.16], + [28.86, -16.23], + [28.84, -16.28], + [28.86, -16.37], + [28.83, -16.43], + [28.82, -16.47], + [28.81, -16.49], + [28.77, -16.52], + [28.76, -16.53], + [28.74, -16.55], + [28.73, -16.56], + [28.64, -16.57], + [28.28, -16.71], + [28.21, -16.75], + [28.11, -16.83], + [28.02, -16.87], + [27.87, -16.93], + [27.82, -16.96], + [27.78, -17], + [27.64, -17.2], + [27.62, -17.23], + [27.6, -17.31], + [27.58, -17.36], + [27.52, -17.42], + [27.42, -17.5], + [27.16, -17.77], + [27.15, -17.78], + [27.12, -17.88], + [27.08, -17.92], + [27.05, -17.94], + [27.02, -17.96], + [26.95, -17.97], + [26.91, -17.99], + [26.89, -17.98], + [26.79, -18.03], + [26.74, -18.04], + [26.71, -18.07], + [26.63, -18.05], + [26.61, -18.04], + [26.6, -18.03], + [26.58, -18.01], + [26.57, -18], + [26.53, -17.99], + [26.49, -17.98], + [26.41, -17.94], + [26.36, -17.93], + [26.33, -17.94], + [26.32, -17.93], + [26.3, -17.92], + [26.25, -17.91], + [26.23, -17.9], + [26.22, -17.89], + [26.21, -17.88], + [26.2, -17.89], + [26.17, -17.91], + [26.16, -17.92], + [26.12, -17.93], + [26.1, -17.94], + [26.08, -17.96], + [26.05, -17.97], + [26.04, -17.98], + [26.03, -17.97], + [25.98, -18], + [25.86, -17.97], + [25.85, -17.96], + [25.86, -17.92], + [25.85, -17.91], + [25.8, -17.89], + [25.79, -17.87], + [25.77, -17.85], + [25.74, -17.84], + [25.71, -17.83], + [25.69, -17.82], + [25.68, -17.81], + [25.6, -17.84], + [25.54, -17.85], + [25.52, -17.86], + [25.5, -17.85], + [25.38, -17.84], + [25.32, -17.83], + [25.29, -17.81], + [25.27, -17.8], + [25.26, -17.79], + [25.25, -17.78], + [25.24, -17.77], + [25.23, -17.76], + [25.18, -17.74], + [25.16, -17.73], + [25.15, -17.7], + [25.14, -17.69], + [25.12, -17.7], + [25.11, -17.68], + [25.1, -17.67], + [25.09, -17.64], + [25.07, -17.63], + [25.06, -17.62], + [25.03, -17.61], + [25.04, -17.58], + [25.01, -17.59], + [24.98, -17.58], + [24.97, -17.56], + [24.96, -17.55], + [24.94, -17.56], + [24.92, -17.54], + [24.9, -17.53], + [24.83, -17.52], + [24.78, -17.51], + [24.68, -17.49], + [24.63, -17.5], + [24.62, -17.51], + [24.61, -17.52], + [24.59, -17.53], + [24.54, -17.52], + [24.53, -17.51], + [24.5, -17.5], + [24.48, -17.49], + [24.41, -17.47], + [24.33, -17.49], + [24.31, -17.48], + [24.19, -17.49], + [24.11, -17.5], + [24.06, -17.51], + [24.02, -17.52], + [23.98, -17.53], + [23.93, -17.54], + [23.85, -17.55], + [23.81, -17.56], + [23.76, -17.57], + [23.72, -17.58], + [23.68, -17.59], + [23.63, -17.6], + [23.55, -17.61], + [23.51, -17.62], + [23.48, -17.63], + [23.38, -17.64], + [23.36, -17.58], + [23.34, -17.56], + [23.32, -17.55], + [23.31, -17.54], + [23.26, -17.53], + [23.24, -17.54], + [23.18, -17.52], + [23.17, -17.47], + [23.12, -17.45], + [23.1, -17.43], + [23.07, -17.41], + [23.05, -17.38], + [23.04, -17.34], + [23, -17.29], + [22.94, -17.27], + [22.88, -17.25], + [22.85, -17.23], + [22.81, -17.2], + [22.78, -17.18], + [22.77, -17.17], + [22.76, -17.15], + [22.74, -17.11], + [22.73, -17.08], + [22.71, -17.06], + [22.67, -17.01], + [22.65, -17], + [22.59, -16.98], + [22.57, -16.97], + [22.55, -16.92], + [22.52, -16.91], + [22.5, -16.89], + [22.49, -16.87], + [22.42, -16.75], + [22.4, -16.74], + [22.38, -16.73], + [22.37, -16.72], + [22.35, -16.7], + [22.34, -16.68], + [22.33, -16.67], + [22.3, -16.66], + [22.26, -16.67], + [22.15, -16.6], + [22.14, -16.57], + [22.13, -16.55], + [22.11, -16.54], + [22.1, -16.5], + [22.08, -16.47], + [22.09, -16.42], + [22.1, -16.39], + [22.11, -16.38], + [22.09, -16.37], + [22.06, -16.36], + [22.05, -16.34], + [22.04, -16.31], + [22.03, -16.29], + [22.02, -16.27], + [22.01, -16.25], + [21.98, -16.17], + [22.1, -13], + [23.99, -12.97], + [23.97, -12.93], + [23.95, -12.9], + [23.9, -12.85], + [23.87, -12.82], + [23.89, -12.71], + [23.91, -12.63], + [23.93, -12.56], + [23.94, -12.53], + [23.99, -12.47], + [24.02, -12.42], + [24.03, -12.4], + [24.02, -12.34], + [24.01, -12.25], + [23.98, -12.23], + [23.96, -12.2], + [23.95, -12.15], + [23.96, -12.01], + [23.97, -11.88], + [23.99, -11.83], + [23.98, -11.72], + [23.97, -11.7], + [23.96, -11.68], + [23.95, -11.66], + [23.96, -11.62], + [23.98, -11.58], + [24.01, -11.54], + [24.02, -11.44], + [24.05, -11.42], + [24.06, -11.41], + [24.02, -11.3], + [24.01, -11.27], + [24.02, -11.13], + [23.99, -11.11], + [24, -11], + [23.98, -10.94], + [23.97, -10.92], + [24, -10.87], + [24.05, -10.88], + [24.09, -10.9], + [24.11, -10.92], + [24.12, -10.99], + [24.14, -11.04], + [24.16, -11.03], + [24.22, -11.05], + [24.32, -11.06], + [24.35, -11.08], + [24.37, -11.1], + [24.38, -11.12], + [24.37, -11.14], + [24.36, -11.15], + [24.37, -11.18], + [24.38, -11.19], + [24.39, -11.2], + [24.4, -11.22], + [24.39, -11.28], + [24.38, -11.3], + [24.35, -11.35], + [24.34, -11.36], + [24.3, -11.37], + [24.29, -11.38], + [24.31, -11.41], + [24.39, -11.42], + [24.43, -11.45], + [24.45, -11.46], + [24.47, -11.47], + [24.49, -11.46], + [24.53, -11.45], + [24.56, -11.44], + [24.57, -11.43], + [24.58, -11.42], + [24.59, -11.4], + [24.62, -11.39], + [24.65, -11.38], + [24.66, -11.35], + [24.67, -11.34], + [24.71, -11.33], + [24.83, -11.32], + [24.9, -11.28], + [24.94, -11.27], + [25.12, -11.26], + [25.18, -11.25], + [25.28, -11.2], + [25.31, -11.19], + [25.32, -11.21], + [25.33, -11.27], + [25.32, -11.28], + [25.3, -11.3], + [25.28, -11.31], + [25.29, -11.32], + [25.31, -11.33], + [25.3, -11.35], + [25.29, -11.36], + [25.28, -11.37], + [25.29, -11.42], + [25.31, -11.46], + [25.32, -11.47], + [25.3, -11.5], + [25.33, -11.62], + [25.34, -11.63], + [25.35, -11.65], + [25.39, -11.66], + [25.41, -11.67], + [25.46, -11.7], + [25.48, -11.72], + [25.47, -11.76], + [25.48, -11.77], + [25.5, -11.78], + [25.52, -11.77], + [25.53, -11.76], + [25.56, -11.75], + [25.57, -11.73], + [25.66, -11.75], + [25.69, -11.78], + [25.73, -11.8], + [25.83, -11.79], + [25.86, -11.8], + [25.91, -11.85], + [25.95, -11.86], + [25.96, -11.9], + [26.19, -11.91], + [26.21, -11.92], + [26.23, -11.93], + [26.29, -11.94], + [26.33, -11.92], + [26.38, -11.91], + [26.44, -11.92], + [26.46, -11.93], + [26.47, -11.95], + [26.49, -11.96], + [26.52, -11.97], + [26.61, -11.98], + [26.64, -11.99], + [26.66, -12], + [26.68, -12.01], + [26.7, -12.02], + [26.72, -12.01], + [26.73, -12], + [26.74, -11.98], + [26.76, -11.97], + [26.87, -11.96], + [26.91, -11.94], + [26.95, -11.91], + [26.97, -11.87], + [26.98, -11.75], + [27, -11.73], + [27.01, -11.71], + [27.02, -11.7], + [27.01, -11.63], + [27.02, -11.6], + [27.03, -11.59], + [27.05, -11.6], + [27.1, -11.58], + [27.17, -11.57], + [27.2, -11.59], + [27.21, -11.64], + [27.23, -11.81], + [27.42, -11.92], + [27.47, -12], + [27.52, -12.18], + [27.54, -12.2], + [27.59, -12.24], + [27.6, -12.25], + [27.64, -12.29], + [27.67, -12.3], + [27.71, -12.31], + [27.76, -12.3], + [27.81, -12.28], + [27.82, -12.27], + [27.83, -12.26], + [27.88, -12.27], + [27.93, -12.3], + [27.95, -12.32], + [27.96, -12.37], + [28.09, -12.38], + [28.1, -12.39], + [28.11, -12.41], + [28.13, -12.43], + [28.15, -12.42], + [28.16, -12.41], + [28.19, -12.4], + [28.2, -12.41], + [28.22, -12.43], + [28.24, -12.44], + [28.28, -12.43], + [28.3, -12.44], + [28.34, -12.45], + [28.42, -12.52], + [28.44, -12.54], + [28.46, -12.59], + [28.47, -12.61], + [28.5, -12.65], + [28.51, -12.67], + [28.5, -12.71], + [28.48, -12.72], + [28.47, -12.74], + [28.48, -12.76], + [28.5, -12.79], + [28.52, -12.81], + [28.54, -12.83], + [28.55, -12.89], + [28.57, -12.9], + [28.58, -12.89], + [28.59, -12.88], + [28.61, -12.85], + [28.62, -12.84], + [28.67, -12.85], + [28.71, -12.89], + [28.78, -12.98], + [28.79, -12.99], + [28.8, -13], + [28.81, -13.04], + [28.83, -13.05], + [28.82, -13.09], + [28.83, -13.1], + [28.85, -13.14], + [28.89, -13.15], + [28.9, -13.16], + [28.93, -13.31], + [28.95, -13.35], + [28.98, -13.38], + [28.99, -13.4], + [29.05, -13.39], + [29.1, -13.38], + [29.14, -13.39], + [29.15, -13.41], + [29.16, -13.42], + [29.17, -13.43], + [29.18, -13.44], + [29.19, -13.43], + [29.21, -13.41], + [29.23, -13.4], + [29.25, -13.39], + [29.31, -13.35], + [29.45, -13.3], + [29.47, -13.29], + [29.53, -13.23], + [29.55, -13.22], + [29.57, -13.23], + [29.59, -13.24], + [29.61, -13.25], + [29.63, -13.26], + [29.67, -13.27], + [29.66, -13.3], + [29.65, -13.31], + [29.63, -13.32], + [29.62, -13.37], + [29.6, -13.39], + [29.61, -13.4], + [29.62, -13.42], + [29.63, -13.43], + [29.64, -13.44], + [29.66, -13.45], + [29.7, -13.46], + [29.8, -13.42], + [29.76, -12.16], + [29.7, -12.19], + [29.65, -12.21], + [29.63, -12.22], + [29.62, -12.21], + [29.6, -12.19], + [29.55, -12.21], + [29.53, -12.22], + [29.49, -12.23], + [29.47, -12.24], + [29.46, -12.29], + [29.45, -12.32], + [29.48, -12.38], + [29.5, -12.39], + [29.53, -12.41], + [29.52, -12.43], + [29.51, -12.44], + [29.5, -12.45], + [29.47, -12.44], + [29.41, -12.43], + [29.36, -12.41], + [29.3, -12.4], + [29.28, -12.39], + [29.27, -12.37], + [29.13, -12.38], + [29.11, -12.39], + [29.1, -12.37], + [29.08, -12.38], + [29.03, -12.36], + [28.94, -12.21], + [28.92, -12.17], + [28.86, -12.14], + [28.85, -12.13], + [28.84, -12.09], + [28.82, -12.08], + [28.81, -12.06], + [28.77, -12.05], + [28.76, -12.04], + [28.75, -12.02], + [28.74, -11.98], + [28.71, -11.99], + [28.69, -11.98], + [28.64, -11.96], + [28.62, -11.95], + [28.61, -11.91], + [28.59, -11.9], + [28.57, -11.91], + [28.55, -11.89], + [28.54, -11.87], + [28.5, -11.86], + [28.49, -11.81], + [28.48, -11.8], + [28.46, -11.79], + [28.45, -11.78], + [28.44, -11.71], + [28.43, -11.69], + [28.42, -11.68], + [28.41, -11.61], + [28.4, -11.6], + [28.38, -11.58], + [28.37, -11.54], + [28.36, -11.53], + [28.35, -11.46], + [28.36, -11.45], + [28.41, -11.37], + [28.43, -11.35], + [28.44, -11.29], + [28.45, -11.27], + [28.46, -11.26], + [28.47, -11.23], + [28.48, -11.18], + [28.49, -11.15], + [28.48, -11.09], + [28.49, -11.06], + [28.5, -11.03], + [28.51, -11.02], + [28.53, -10.96], + [28.54, -10.94], + [28.55, -10.91], + [28.56, -10.81], + [28.58, -10.79], + [28.59, -10.77], + [28.6, -10.76], + [28.61, -10.74], + [28.62, -10.72], + [28.63, -10.71], + [28.67, -10.7], + [28.68, -10.68], + [28.69, -10.66], + [28.7, -10.64], + [28.67, -10.62], + [28.65, -10.54], + [28.63, -10.52], + [28.64, -10.5], + [28.63, -10.48], + [28.64, -10.46], + [28.65, -10.44], + [28.64, -10.43], + [28.63, -10.39], + [28.62, -10.37], + [28.63, -10.31], + [28.62, -10.28], + [28.61, -10.27], + [28.6, -10.25], + [28.57, -10.22], + [28.58, -10.2], + [28.6, -10.17], + [28.62, -10.14], + [28.63, -10.1], + [28.62, -9.95], + [28.63, -9.93], + [28.66, -9.86], + [28.67, -9.82], + [28.68, -9.8], + [28.7, -9.79], + [28.67, -9.77], + [28.66, -9.75], + [28.65, -9.74], + [28.63, -9.72], + [28.62, -9.65], + [28.61, -9.62], + [28.59, -9.57], + [28.58, -9.56], + [28.61, -9.55], + [28.62, -9.54], + [28.57, -9.53], + [28.56, -9.48], + [28.53, -9.46], + [28.52, -9.45], + [28.51, -9.43], + [28.52, -9.42], + [28.5, -9.35], + [28.46, -9.34], + [28.41, -9.32], + [28.37, -9.31], + [28.35, -9.27], + [28.37, -9.24], + [28.42, -9.21], + [28.51, -9.16], + [28.6, -9.1], + [28.77, -8.93], + [28.89, -8.77], + [28.93, -8.68], + [28.94, -8.59], + [28.89, -8.5], + [28.92, -8.47], + [29.04, -8.45], + [29.21, -8.43], + [29.37, -8.4], + [29.58, -8.37], + [29.86, -8.33], + [30.12, -8.29], + [30.32, -8.26], + [30.58, -8.22], + [30.75, -8.19], + [30.78, -8.29], + [30.83, -8.39], + [30.89, -8.48], + [30.96, -8.55], + [30.99, -8.58], + [31.03, -8.6], + [31.08, -8.62], + [31.14, -8.61], + [31.16, -8.59], + [31.18, -8.58], + [31.22, -8.59], + [31.24, -8.61], + [31.25, -8.62], + [31.33, -8.6], + [31.35, -8.59], + [31.37, -8.6], + [31.39, -8.63], + [31.44, -8.64], + [31.46, -8.67], + [31.48, -8.68], + [31.52, -8.69], + [31.54, -8.7], + [31.55, -8.73], + [31.58, -8.84], + [31.67, -8.91], + [31.69, -8.92], + [31.73, -8.91], + [31.76, -8.89], + [31.94, -8.93], + [31.92, -8.97], + [31.94, -9.06], + [31.98, -9.07], + [32, -9.06], + [32.02, -9.05], + [32.09, -9.07], + [32.13, -9.06], + [32.15, -9.07], + [32.19, -9.11], + [32.21, -9.13], + [32.25, -9.14], + [32.38, -9.13], + [32.42, -9.14], + [32.46, -9.17], + [32.47, -9.18], + [32.49, -9.23], + [32.5, -9.25], + [32.52, -9.26], + [32.64, -9.28], + [32.71, -9.29], + [32.74, -9.31], + [32.75, -9.33], + [32.76, -9.34], + [32.83, -9.37], + [32.91, -9.4], + [32.92, -9.41] + ] +} diff --git a/libs/data/geoLocation/zm/admin-1.boundaries.json b/libs/data/geoLocation/zm/admin-1.boundaries.json new file mode 100644 index 000000000..baad2dddc --- /dev/null +++ b/libs/data/geoLocation/zm/admin-1.boundaries.json @@ -0,0 +1,3156 @@ +{ + "Muchinga": [ + [32.92, -9.41], + [32.93, -9.48], + [32.94, -9.49], + [32.95, -9.48], + [32.98, -9.5], + [32.99, -9.53], + [32.97, -9.6], + [32.99, -9.63], + [33.02, -9.62], + [33.05, -9.63], + [33.06, -9.65], + [33.08, -9.66], + [33.09, -9.64], + [33.1, -9.59], + [33.12, -9.6], + [33.2, -9.62], + [33.21, -9.64], + [33.22, -9.67], + [33.21, -9.68], + [33.2, -9.7], + [33.21, -9.71], + [33.22, -9.73], + [33.24, -9.74], + [33.25, -9.75], + [33.27, -9.78], + [33.28, -9.79], + [33.29, -9.8], + [33.3, -9.81], + [33.34, -9.82], + [33.36, -9.87], + [33.37, -9.9], + [33.36, -9.92], + [33.33, -9.97], + [33.31, -10.01], + [33.3, -10.04], + [33.32, -10.08], + [33.4, -10.12], + [33.42, -10.14], + [33.44, -10.15], + [33.45, -10.17], + [33.48, -10.18], + [33.5, -10.2], + [33.52, -10.21], + [33.53, -10.23], + [33.54, -10.26], + [33.53, -10.32], + [33.56, -10.4], + [33.57, -10.42], + [33.6, -10.44], + [33.62, -10.49], + [33.64, -10.51], + [33.67, -10.52], + [33.66, -10.6], + [33.64, -10.62], + [33.6, -10.64], + [33.59, -10.65], + [33.58, -10.66], + [33.53, -10.71], + [33.51, -10.75], + [33.5, -10.77], + [33.48, -10.78], + [33.45, -10.8], + [33.43, -10.81], + [33.39, -10.8], + [33.36, -10.81], + [33.32, -10.82], + [33.31, -10.83], + [33.29, -10.86], + [33.27, -10.87], + [33.25, -10.86], + [33.24, -10.87], + [33.23, -10.88], + [33.24, -10.9], + [33.28, -10.91], + [33.29, -10.94], + [33.3, -11.03], + [33.32, -11.06], + [33.34, -11.09], + [33.36, -11.11], + [33.39, -11.16], + [33.38, -11.19], + [33.37, -11.22], + [33.3, -11.33], + [33.29, -11.36], + [33.27, -11.37], + [33.24, -11.4], + [33.23, -11.42], + [33.21, -11.56], + [33.22, -11.57], + [33.23, -11.58], + [33.3, -11.59], + [33.31, -11.64], + [33.26, -11.66], + [33.22, -11.67], + [33.2, -11.7], + [33.13, -11.86], + [33.09, -11.95], + [32.95, -11.99], + [32.73, -12.06], + [32.6, -12.07], + [32.5, -12.11], + [32.48, -12.17], + [32.43, -12.22], + [32.29, -12.2], + [32.28, -12.24], + [32.26, -12.29], + [32.21, -12.33], + [32.19, -12.35], + [32.18, -12.38], + [32.17, -12.39], + [32.16, -12.4], + [32.15, -12.41], + [32.14, -12.44], + [32.12, -12.59], + [32.11, -12.6], + [32.1, -12.63], + [32.09, -12.64], + [32.08, -12.72], + [32.07, -12.76], + [32.06, -12.79], + [32.04, -12.8], + [32.03, -12.81], + [32.02, -12.86], + [32.01, -12.89], + [31.97, -12.9], + [31.95, -12.91], + [31.93, -12.93], + [31.91, -12.94], + [31.9, -13.03], + [31.89, -13.04], + [31.87, -13.05], + [31.86, -13.06], + [31.82, -13.08], + [31.81, -13.09], + [31.79, -13.1], + [31.77, -13.11], + [31.76, -13.1], + [31.75, -13.12], + [31.74, -13.13], + [31.72, -13.14], + [31.71, -13.17], + [31.7, -13.19], + [31.68, -13.2], + [31.66, -13.26], + [31.65, -13.3], + [31.64, -13.34], + [31.61, -13.37], + [31.53, -13.43], + [31.48, -13.42], + [31.44, -13.43], + [31.43, -13.44], + [31.41, -13.31], + [31.39, -13.28], + [31.37, -13.25], + [31.36, -13.23], + [31.35, -13.01], + [31.34, -12.98], + [31.33, -12.97], + [31.29, -12.95], + [31.19, -12.96], + [31.18, -12.97], + [31.17, -13.02], + [31.16, -13.03], + [31.15, -13.04], + [31.11, -13.03], + [31.03, -12.96], + [31.02, -12.95], + [30.97, -12.94], + [30.91, -12.93], + [30.83, -12.92], + [30.81, -12.91], + [30.75, -12.87], + [30.74, -12.86], + [30.73, -12.77], + [30.74, -12.73], + [30.75, -12.71], + [30.76, -12.7], + [30.77, -12.69], + [30.76, -12.67], + [30.75, -12.66], + [30.73, -12.65], + [30.72, -12.64], + [30.71, -12.63], + [30.7, -12.6], + [30.69, -12.59], + [30.66, -12.61], + [30.65, -12.62], + [30.63, -12.63], + [30.62, -12.62], + [30.58, -12.59], + [30.57, -12.58], + [30.56, -12.57], + [30.57, -12.54], + [30.56, -12.5], + [30.55, -12.49], + [30.52, -12.48], + [30.51, -12.47], + [30.5, -12.46], + [30.51, -12.4], + [30.5, -12.31], + [30.48, -12.3], + [30.47, -12.31], + [30.44, -12.3], + [30.43, -12.29], + [30.42, -12.28], + [30.41, -12.27], + [30.38, -12.28], + [30.37, -12.27], + [30.35, -12.26], + [30.3, -12.25], + [30.28, -12.24], + [30.23, -12.23], + [30.22, -12.22], + [30.2, -12.21], + [30.16, -12.2], + [30.15, -12.18], + [30.14, -12.17], + [30.11, -12.16], + [30.09, -12.15], + [30.08, -12.14], + [30.07, -12.13], + [30.06, -12.11], + [30.05, -12.1], + [30.03, -12.03], + [30.01, -12.01], + [30, -12], + [29.95, -12.01], + [29.87, -12.04], + [29.86, -12.05], + [29.85, -12.06], + [29.84, -12.12], + [29.83, -12.15], + [29.82, -12.16], + [29.8, -12.15], + [29.81, -12.14], + [29.82, -12.13], + [29.81, -12.12], + [29.82, -12.1], + [29.81, -12.07], + [29.79, -12.05], + [29.78, -12.04], + [29.77, -11.94], + [29.78, -11.91], + [29.79, -11.9], + [29.82, -11.89], + [30.25, -11.83], + [30.26, -11.82], + [30.28, -11.81], + [30.45, -11.59], + [30.44, -11.58], + [30.45, -11.53], + [30.46, -11.5], + [30.48, -11.49], + [30.5, -11.48], + [30.52, -11.46], + [30.53, -11.44], + [30.54, -11.42], + [30.55, -11.4], + [30.57, -11.39], + [30.59, -11.38], + [30.6, -11.37], + [30.61, -11.34], + [30.62, -11.33], + [30.68, -11.31], + [30.71, -11.29], + [30.72, -11.26], + [30.74, -11.21], + [30.82, -11.11], + [30.84, -11.08], + [30.85, -11.06], + [30.86, -11.05], + [30.87, -11.04], + [30.88, -11.06], + [30.9, -11.05], + [30.88, -11.03], + [30.91, -11.02], + [30.93, -11.01], + [30.96, -11], + [30.98, -10.98], + [30.99, -10.94], + [31, -10.92], + [31.01, -10.93], + [31.02, -10.94], + [31.04, -10.95], + [31.05, -10.94], + [31.06, -10.91], + [31.07, -10.92], + [31.08, -10.93], + [31.07, -10.95], + [31.06, -10.96], + [31.15, -10.92], + [31.16, -10.89], + [31.17, -10.88], + [31.15, -10.85], + [31.14, -10.84], + [31.15, -10.82], + [31.2, -10.81], + [31.19, -10.78], + [31.18, -10.79], + [31.15, -10.78], + [31.13, -10.76], + [31.17, -10.72], + [31.19, -10.71], + [31.26, -10.72], + [31.28, -10.73], + [31.3, -10.71], + [31.31, -10.7], + [31.32, -10.64], + [31.34, -10.63], + [31.33, -10.62], + [31.35, -10.61], + [31.39, -10.6], + [31.42, -10.58], + [31.44, -10.57], + [31.45, -10.56], + [31.46, -10.55], + [31.48, -10.56], + [31.49, -10.57], + [31.55, -10.56], + [31.52, -10.28], + [31.42, -10.23], + [31.34, -10.18], + [31.31, -10.07], + [31.26, -9.96], + [31.19, -9.83], + [31.11, -9.76], + [31.18, -9.67], + [31.21, -9.61], + [31.26, -9.59], + [31.32, -9.54], + [31.37, -9.5], + [31.43, -9.55], + [31.51, -9.54], + [31.57, -9.57], + [31.6, -9.5], + [31.68, -9.53], + [31.75, -9.52], + [31.82, -9.48], + [31.9, -9.44], + [32.02, -9.42], + [32.12, -9.43], + [32.22, -9.45], + [32.33, -9.46], + [32.32, -9.36], + [32.27, -9.25], + [32.23, -9.13], + [32.25, -9.14], + [32.38, -9.13], + [32.42, -9.14], + [32.46, -9.17], + [32.47, -9.18], + [32.49, -9.23], + [32.5, -9.25], + [32.52, -9.26], + [32.64, -9.28], + [32.71, -9.29], + [32.74, -9.31], + [32.75, -9.33], + [32.76, -9.34], + [32.83, -9.37], + [32.91, -9.4], + [32.92, -9.41] + ], + "Eastern": [ + [33.31, -11.64], + [33.3, -11.85], + [33.31, -11.88], + [33.3, -11.93], + [33.29, -11.98], + [33.25, -12.07], + [33.26, -12.16], + [33.29, -12.18], + [33.3, -12.2], + [33.31, -12.23], + [33.33, -12.3], + [33.35, -12.33], + [33.38, -12.34], + [33.46, -12.32], + [33.5, -12.33], + [33.53, -12.34], + [33.52, -12.37], + [33.49, -12.39], + [33.48, -12.41], + [33.46, -12.42], + [33.45, -12.45], + [33.42, -12.46], + [33.41, -12.48], + [33.39, -12.5], + [33.37, -12.52], + [33.35, -12.53], + [33.33, -12.54], + [33.31, -12.53], + [33.29, -12.52], + [33.26, -12.53], + [33.24, -12.54], + [33.23, -12.58], + [33.21, -12.59], + [33.2, -12.6], + [33.18, -12.61], + [33.17, -12.62], + [33.15, -12.59], + [33.13, -12.58], + [33.11, -12.59], + [33.09, -12.6], + [33.07, -12.59], + [33.06, -12.58], + [33.05, -12.59], + [33.04, -12.6], + [33.02, -12.61], + [32.99, -12.67], + [32.96, -12.73], + [32.94, -12.75], + [32.95, -12.84], + [32.98, -12.87], + [33.01, -12.89], + [32.98, -13.01], + [32.97, -13.12], + [32.98, -13.17], + [33, -13.19], + [32.99, -13.22], + [32.94, -13.26], + [32.92, -13.29], + [32.91, -13.35], + [32.89, -13.4], + [32.87, -13.44], + [32.85, -13.46], + [32.82, -13.47], + [32.81, -13.53], + [32.8, -13.54], + [32.75, -13.55], + [32.72, -13.57], + [32.71, -13.58], + [32.69, -13.57], + [32.67, -13.58], + [32.66, -13.6], + [32.68, -13.63], + [32.71, -13.64], + [32.77, -13.65], + [32.81, -13.7], + [32.8, -13.72], + [32.77, -13.74], + [32.76, -13.75], + [32.79, -13.79], + [32.83, -13.8], + [32.86, -13.81], + [32.87, -13.82], + [32.92, -13.88], + [32.93, -13.9], + [32.94, -13.93], + [32.97, -13.94], + [32.98, -13.95], + [32.97, -13.96], + [32.98, -14.02], + [33, -14.05], + [33.05, -14], + [33.06, -13.98], + [33.08, -13.97], + [33.11, -13.96], + [33.13, -13.93], + [33.14, -13.92], + [33.15, -13.94], + [33.19, -13.99], + [33.2, -14.01], + [33.13, -14.04], + [33.04, -14.07], + [32.92, -14.11], + [32.74, -14.17], + [32.58, -14.22], + [32.43, -14.27], + [32.32, -14.31], + [32.23, -14.34], + [32.15, -14.35], + [32.11, -14.36], + [32.03, -14.4], + [31.93, -14.43], + [31.8, -14.47], + [31.66, -14.52], + [31.59, -14.55], + [31.5, -14.6], + [31.41, -14.63], + [31.31, -14.66], + [31.18, -14.69], + [31.07, -14.71], + [30.92, -14.75], + [30.82, -14.77], + [30.68, -14.82], + [30.59, -14.85], + [30.49, -14.89], + [30.39, -14.93], + [30.32, -14.97], + [30.23, -14.98], + [30.21, -14.86], + [30.2, -14.83], + [30.19, -14.82], + [30.18, -14.8], + [30.17, -14.79], + [30.15, -14.78], + [30.14, -14.77], + [30.1, -14.72], + [30.09, -14.71], + [30.07, -14.7], + [30.06, -14.69], + [30.05, -14.68], + [30.02, -14.64], + [30, -14.62], + [29.99, -14.61], + [30, -14.56], + [30.01, -14.52], + [30.02, -14.5], + [30.03, -14.48], + [30.05, -14.43], + [30.06, -14.42], + [30.07, -14.41], + [30.08, -14.39], + [30.09, -14.38], + [30.12, -14.37], + [30.13, -14.36], + [30.17, -14.31], + [30.2, -14.29], + [30.21, -14.28], + [30.22, -14.26], + [30.23, -14.25], + [30.25, -14.23], + [30.28, -14.22], + [30.29, -14.21], + [30.3, -14.2], + [30.31, -14.18], + [30.32, -14.16], + [30.31, -14.11], + [30.3, -14.1], + [30.29, -14.09], + [30.28, -14.08], + [30.26, -14.07], + [30.22, -14.06], + [30.19, -14.05], + [30.18, -14.04], + [30.15, -13.96], + [30.14, -13.95], + [30.12, -13.94], + [30.1, -13.93], + [30.89, -13.92], + [30.9, -13.91], + [30.92, -13.89], + [30.94, -13.86], + [30.96, -13.85], + [30.97, -13.81], + [31.01, -13.79], + [31.02, -13.78], + [31.06, -13.77], + [31.07, -13.74], + [31.1, -13.71], + [31.11, -13.7], + [31.12, -13.63], + [31.14, -13.61], + [31.16, -13.6], + [31.17, -13.58], + [31.23, -13.56], + [31.25, -13.53], + [31.26, -13.52], + [31.27, -13.51], + [31.28, -13.52], + [31.29, -13.51], + [31.3, -13.5], + [31.34, -13.47], + [31.36, -13.46], + [31.41, -13.45], + [31.43, -13.44], + [31.44, -13.43], + [31.46, -13.42], + [31.5, -13.43], + [31.61, -13.37], + [31.64, -13.34], + [31.65, -13.3], + [31.66, -13.26], + [31.68, -13.2], + [31.7, -13.19], + [31.71, -13.18], + [31.72, -13.16], + [31.74, -13.13], + [31.75, -13.12], + [31.76, -13.09], + [31.77, -13.1], + [31.81, -13.09], + [31.82, -13.08], + [31.83, -13.06], + [31.86, -13.05], + [31.87, -13.04], + [31.9, -13.03], + [31.91, -13.01], + [31.92, -12.93], + [31.95, -12.92], + [31.97, -12.9], + [31.99, -12.89], + [32.02, -12.88], + [32.03, -12.81], + [32.04, -12.8], + [32.05, -12.79], + [32.07, -12.78], + [32.08, -12.74], + [32.09, -12.69], + [32.1, -12.64], + [32.11, -12.6], + [32.12, -12.59], + [32.14, -12.5], + [32.15, -12.43], + [32.16, -12.4], + [32.17, -12.39], + [32.18, -12.38], + [32.19, -12.35], + [32.21, -12.33], + [32.26, -12.29], + [32.28, -12.26], + [32.29, -12.22], + [32.48, -12.17], + [32.5, -12.11], + [32.54, -12.07], + [32.73, -12.06], + [32.95, -11.99], + [33.09, -11.95], + [33.13, -11.86], + [33.2, -11.75], + [33.22, -11.67], + [33.26, -11.66], + [33.31, -11.64] + ], + "Northern": [ + [30.75, -8.19], + [30.78, -8.29], + [30.83, -8.39], + [30.89, -8.48], + [30.96, -8.55], + [30.99, -8.58], + [31.03, -8.6], + [31.08, -8.62], + [31.14, -8.61], + [31.16, -8.59], + [31.18, -8.58], + [31.22, -8.59], + [31.24, -8.61], + [31.25, -8.62], + [31.33, -8.6], + [31.35, -8.59], + [31.37, -8.6], + [31.39, -8.63], + [31.44, -8.64], + [31.46, -8.67], + [31.48, -8.68], + [31.52, -8.69], + [31.54, -8.7], + [31.55, -8.73], + [31.58, -8.84], + [31.67, -8.91], + [31.69, -8.92], + [31.73, -8.91], + [31.76, -8.89], + [31.94, -8.93], + [31.92, -8.97], + [31.94, -9.06], + [31.98, -9.07], + [32, -9.06], + [32.02, -9.05], + [32.09, -9.07], + [32.13, -9.06], + [32.15, -9.07], + [32.19, -9.11], + [32.21, -9.13], + [32.27, -9.25], + [32.32, -9.36], + [32.33, -9.46], + [32.22, -9.45], + [32.12, -9.43], + [32.02, -9.42], + [31.9, -9.44], + [31.82, -9.48], + [31.75, -9.52], + [31.68, -9.53], + [31.6, -9.5], + [31.57, -9.57], + [31.51, -9.54], + [31.43, -9.55], + [31.37, -9.5], + [31.32, -9.54], + [31.26, -9.59], + [31.21, -9.61], + [31.18, -9.67], + [31.11, -9.76], + [31.19, -9.83], + [31.26, -9.96], + [31.31, -10.07], + [31.34, -10.18], + [31.42, -10.23], + [31.52, -10.28], + [31.55, -10.31], + [31.49, -10.57], + [31.48, -10.56], + [31.47, -10.55], + [31.45, -10.56], + [31.44, -10.57], + [31.42, -10.58], + [31.39, -10.6], + [31.37, -10.61], + [31.33, -10.62], + [31.34, -10.63], + [31.33, -10.64], + [31.31, -10.65], + [31.3, -10.71], + [31.28, -10.72], + [31.24, -10.71], + [31.17, -10.72], + [31.13, -10.75], + [31.15, -10.77], + [31.16, -10.79], + [31.18, -10.78], + [31.2, -10.79], + [31.19, -10.82], + [31.14, -10.83], + [31.15, -10.85], + [31.17, -10.87], + [31.16, -10.89], + [31.15, -10.9], + [31.1, -10.96], + [31.07, -10.95], + [31.08, -10.94], + [31.07, -10.92], + [31.06, -10.91], + [31.05, -10.92], + [31.04, -10.95], + [31.02, -10.94], + [31.01, -10.93], + [31.02, -10.92], + [30.99, -10.94], + [30.98, -10.98], + [30.97, -11], + [30.93, -11.01], + [30.92, -11.02], + [30.89, -11.03], + [30.9, -11.05], + [30.89, -11.06], + [30.87, -11.04], + [30.86, -11.05], + [30.85, -11.06], + [30.84, -11.07], + [30.82, -11.11], + [30.74, -11.21], + [30.72, -11.26], + [30.71, -11.28], + [30.68, -11.31], + [30.67, -11.33], + [30.61, -11.34], + [30.6, -11.35], + [30.59, -11.38], + [30.58, -11.39], + [30.55, -11.4], + [30.54, -11.42], + [30.53, -11.44], + [30.52, -11.46], + [30.5, -11.48], + [30.48, -11.49], + [30.46, -11.5], + [30.45, -11.48], + [30.14, -11.25], + [30.1, -11.24], + [29.96, -11.25], + [29.95, -11.28], + [29.94, -11.29], + [29.9, -11.31], + [29.89, -11.33], + [29.88, -11.35], + [29.85, -11.37], + [29.84, -11.39], + [29.83, -11.4], + [29.89, -11.02], + [29.88, -10.94], + [29.86, -10.9], + [29.85, -10.89], + [29.82, -10.87], + [29.81, -10.86], + [29.79, -10.81], + [29.78, -10.8], + [29.76, -10.79], + [29.75, -10.78], + [29.71, -10.77], + [29.68, -10.75], + [29.66, -10.74], + [29.37, -10.88], + [29.35, -10.9], + [29.34, -10.91], + [29.36, -10.95], + [29.37, -11], + [29.38, -11.02], + [29.39, -11.03], + [29.4, -11.04], + [29.39, -11.08], + [29.38, -11.12], + [29.32, -11.09], + [29.18, -11], + [29.17, -10.99], + [29.09, -10.97], + [29.08, -10.96], + [29.09, -10.95], + [29.11, -10.92], + [29.16, -10.88], + [29.17, -10.74], + [29.29, -10.66], + [29.3, -10.65], + [29.31, -10.64], + [29.36, -10.63], + [29.37, -10.59], + [29.41, -10.54], + [29.4, -10.51], + [29.41, -10.45], + [29.42, -10.44], + [29.43, -10.43], + [29.44, -10.39], + [29.45, -10.38], + [29.47, -10.36], + [29.49, -10.34], + [29.5, -10.33], + [29.52, -10.32], + [29.59, -10.3], + [29.61, -10.29], + [29.62, -10.28], + [29.65, -10.25], + [29.67, -10.24], + [29.68, -10.23], + [29.7, -10.22], + [29.79, -10.23], + [29.82, -10.24], + [29.84, -10.23], + [29.87, -10.22], + [29.88, -10.21], + [29.9, -10.13], + [29.91, -10.1], + [29.92, -10.09], + [29.93, -10.08], + [29.94, -10.07], + [29.93, -10.05], + [29.91, -10.01], + [29.93, -9.91], + [29.94, -9.89], + [29.92, -9.85], + [29.91, -9.83], + [29.89, -9.82], + [29.87, -9.81], + [29.86, -9.79], + [29.84, -9.77], + [29.83, -9.75], + [29.82, -9.74], + [29.81, -9.72], + [29.8, -9.71], + [29.73, -9.7], + [29.7, -9.69], + [29.67, -9.68], + [29.65, -9.67], + [29.6, -9.66], + [29.56, -9.65], + [29.53, -9.64], + [29.52, -9.63], + [29.5, -9.62], + [29.49, -9.61], + [29.48, -9.6], + [29.47, -9.59], + [29.46, -9.56], + [29.44, -9.55], + [29.43, -9.54], + [29.4, -9.55], + [29.37, -9.54], + [29.36, -9.53], + [29.34, -9.47], + [29.33, -9.45], + [29.32, -9.43], + [29.33, -9.4], + [29.34, -9.39], + [29.35, -9.38], + [29.36, -9.37], + [29.34, -9.3], + [29.35, -9.26], + [29.34, -9.25], + [29.33, -9.22], + [29.31, -9.21], + [29.29, -9.2], + [29.27, -9.19], + [29.26, -9.18], + [29.25, -9.16], + [29.24, -9.15], + [29.21, -9.16], + [29.19, -9.15], + [29.18, -9.14], + [29.17, -9.13], + [29.15, -9.12], + [29.12, -9.11], + [29.11, -9.1], + [29.12, -9.05], + [29.13, -9.04], + [29.17, -8.96], + [29.18, -8.95], + [29.19, -8.94], + [29.22, -8.93], + [29.25, -8.91], + [29.28, -8.82], + [29.31, -8.72], + [29.34, -8.64], + [29.35, -8.63], + [29.36, -8.61], + [29.39, -8.55], + [29.41, -8.53], + [29.42, -8.52], + [29.47, -8.5], + [29.5, -8.49], + [29.52, -8.47], + [29.54, -8.45], + [29.57, -8.39], + [29.58, -8.37], + [29.86, -8.33], + [30.12, -8.29], + [30.32, -8.26], + [30.58, -8.22], + [30.75, -8.19] + ], + "Lusaka": [ + [30.01, -15.65], + [29.97, -15.64], + [29.88, -15.62], + [29.84, -15.61], + [29.81, -15.62], + [29.77, -15.64], + [29.67, -15.66], + [29.65, -15.67], + [29.63, -15.66], + [29.53, -15.69], + [29.51, -15.7], + [29.42, -15.71], + [29.19, -15.81], + [29.15, -15.85], + [29.12, -15.86], + [29.1, -15.87], + [29.09, -15.88], + [29.08, -15.9], + [29.06, -15.93], + [29.04, -15.95], + [28.95, -15.96], + [28.93, -15.94], + [28.91, -15.93], + [28.87, -15.94], + [28.84, -15.95], + [28.82, -15.94], + [28.81, -15.95], + [28.8, -15.96], + [28.78, -15.95], + [28.68, -15.9], + [28.66, -15.89], + [28.57, -15.88], + [28.52, -15.84], + [28.51, -15.82], + [28.45, -15.81], + [28.42, -15.8], + [28.41, -15.79], + [28.39, -15.78], + [28.29, -15.79], + [28.28, -15.8], + [28.25, -15.82], + [28.23, -15.81], + [28.2, -15.79], + [28.18, -15.78], + [28.08, -15.74], + [28.04, -15.73], + [28.03, -15.72], + [28.02, -15.7], + [28.01, -15.68], + [27.97, -15.67], + [27.93, -15.66], + [27.89, -15.67], + [27.86, -15.69], + [27.85, -15.68], + [27.84, -15.67], + [27.82, -15.65], + [27.8, -15.56], + [27.91, -15.53], + [27.92, -15.52], + [27.93, -15.51], + [27.92, -15.42], + [27.89, -15.37], + [27.88, -15.36], + [27.81, -15.35], + [27.79, -15.34], + [27.77, -15.33], + [27.78, -15.3], + [27.83, -15.27], + [27.84, -15.26], + [28.03, -15.29], + [28.2, -15.34], + [28.26, -15.35], + [28.29, -15.34], + [28.32, -15.3], + [28.34, -15.22], + [28.38, -15.16], + [28.4, -15.15], + [28.57, -15.19], + [28.74, -15.18], + [28.82, -15.15], + [28.95, -15.04], + [29, -15.02], + [29.05, -15.01], + [29.23, -14.96], + [29.31, -14.98], + [29.46, -14.96], + [29.49, -14.91], + [29.5, -14.87], + [29.51, -14.84], + [29.52, -14.82], + [29.53, -14.81], + [29.59, -14.8], + [29.65, -14.77], + [29.66, -14.76], + [29.67, -14.75], + [29.75, -14.72], + [29.81, -14.7], + [29.88, -14.69], + [29.89, -14.68], + [29.9, -14.66], + [29.91, -14.65], + [29.92, -14.66], + [29.95, -14.65], + [29.99, -14.66], + [30, -14.67], + [30.05, -14.68], + [30.06, -14.69], + [30.07, -14.7], + [30.09, -14.71], + [30.1, -14.72], + [30.14, -14.77], + [30.15, -14.78], + [30.17, -14.79], + [30.18, -14.8], + [30.19, -14.82], + [30.2, -14.83], + [30.21, -14.86], + [30.22, -15.02], + [30.23, -15.11], + [30.26, -15.23], + [30.29, -15.28], + [30.32, -15.3], + [30.35, -15.32], + [30.36, -15.34], + [30.37, -15.37], + [30.39, -15.47], + [30.37, -15.53], + [30.4, -15.59], + [30.41, -15.63], + [30.4, -15.64], + [30.36, -15.65], + [30.3, -15.64], + [30.28, -15.63], + [30.23, -15.64], + [30.22, -15.65], + [30.17, -15.63], + [30.13, -15.62], + [30.09, -15.63], + [30.05, -15.64], + [30.01, -15.65] + ], + "Southern": [ + [28.95, -15.96], + [28.9, -16], + [28.88, -16.02], + [28.87, -16.03], + [28.86, -16.05], + [28.87, -16.08], + [28.85, -16.16], + [28.86, -16.23], + [28.84, -16.28], + [28.86, -16.37], + [28.83, -16.43], + [28.82, -16.47], + [28.81, -16.49], + [28.77, -16.52], + [28.76, -16.53], + [28.74, -16.55], + [28.73, -16.56], + [28.64, -16.57], + [28.28, -16.71], + [28.21, -16.75], + [28.11, -16.83], + [28.02, -16.87], + [27.87, -16.93], + [27.82, -16.96], + [27.78, -17], + [27.64, -17.2], + [27.62, -17.23], + [27.6, -17.31], + [27.58, -17.36], + [27.52, -17.42], + [27.42, -17.5], + [27.16, -17.77], + [27.15, -17.78], + [27.12, -17.88], + [27.08, -17.92], + [27.05, -17.94], + [27.02, -17.96], + [26.95, -17.97], + [26.91, -17.99], + [26.89, -17.98], + [26.79, -18.03], + [26.74, -18.04], + [26.71, -18.07], + [26.63, -18.05], + [26.61, -18.04], + [26.6, -18.03], + [26.58, -18.01], + [26.57, -18], + [26.53, -17.99], + [26.49, -17.98], + [26.41, -17.94], + [26.36, -17.93], + [26.33, -17.94], + [26.32, -17.93], + [26.3, -17.92], + [26.25, -17.91], + [26.23, -17.9], + [26.22, -17.89], + [26.21, -17.88], + [26.2, -17.89], + [26.17, -17.91], + [26.16, -17.92], + [26.12, -17.93], + [26.1, -17.94], + [26.08, -17.96], + [26.05, -17.97], + [26.04, -17.98], + [26.03, -17.97], + [25.98, -18], + [25.86, -17.97], + [25.85, -17.96], + [25.86, -17.92], + [25.85, -17.91], + [25.8, -17.89], + [25.79, -17.87], + [25.77, -17.85], + [25.74, -17.84], + [25.71, -17.83], + [25.69, -17.82], + [25.68, -17.81], + [25.6, -17.84], + [25.54, -17.85], + [25.52, -17.86], + [25.5, -17.85], + [25.38, -17.84], + [25.32, -17.83], + [25.29, -17.81], + [25.27, -17.8], + [25.26, -17.79], + [25.25, -17.78], + [25.24, -17.77], + [25.23, -17.76], + [25.18, -17.74], + [25.16, -17.73], + [25.15, -17.7], + [25.14, -17.69], + [25.12, -17.7], + [25.11, -17.68], + [25.1, -17.67], + [25.09, -17.64], + [25.07, -17.63], + [25.06, -17.62], + [25.03, -17.61], + [25.04, -17.58], + [25.01, -17.59], + [24.98, -17.58], + [24.97, -17.56], + [24.98, -17.49], + [24.99, -17.47], + [25, -17.46], + [25.01, -17.44], + [25.02, -17.43], + [25.03, -17.42], + [25.02, -17.4], + [25.03, -17.32], + [25.05, -17.3], + [25.07, -17.27], + [25.08, -17.25], + [25.1, -17.22], + [25.09, -17.2], + [25.08, -17.18], + [25.09, -17.15], + [25.1, -17.13], + [25.13, -17.11], + [25.14, -17.1], + [25.16, -17.08], + [25.17, -17.01], + [25.18, -17], + [25.24, -16.98], + [25.25, -16.97], + [25.27, -16.93], + [25.28, -16.92], + [25.25, -16.81], + [25.24, -16.8], + [25.25, -16.73], + [25.24, -16.7], + [25.23, -16.69], + [25.11, -16.67], + [25.08, -16.64], + [25.07, -16.61], + [25.03, -16.58], + [25.01, -16.56], + [25, -16.55], + [25.02, -16.52], + [25.04, -16.51], + [25.14, -16.38], + [25.15, -16.37], + [25.17, -16.36], + [25.19, -16.35], + [25.2, -16.34], + [25.23, -16.33], + [25.24, -16.32], + [25.25, -16.31], + [25.26, -16.3], + [25.29, -16.29], + [25.3, -16.27], + [25.33, -16.22], + [25.34, -16.2], + [25.35, -16.17], + [25.36, -16.16], + [25.37, -16.15], + [25.38, -16.14], + [25.39, -16.13], + [25.4, -16.12], + [25.41, -16.11], + [25.42, -16.1], + [25.43, -16.09], + [25.42, -16.08], + [25.39, -16.07], + [25.37, -16.06], + [25.35, -16.04], + [25.34, -16.03], + [25.33, -16.01], + [25.34, -15.99], + [25.35, -15.98], + [25.36, -15.97], + [25.35, -15.96], + [25.36, -15.92], + [25.37, -15.9], + [25.38, -15.88], + [25.4, -15.77], + [25.39, -15.75], + [25.38, -15.73], + [25.37, -15.72], + [25.36, -15.73], + [25.35, -15.74], + [25.34, -15.75], + [25.33, -15.76], + [25.28, -15.75], + [25.27, -15.74], + [25.26, -15.72], + [25.25, -15.71], + [25.26, -15.69], + [25.27, -15.68], + [25.28, -15.67], + [25.27, -15.64], + [25.26, -15.63], + [25.23, -15.61], + [25.22, -15.59], + [25.23, -15.58], + [25.26, -15.56], + [25.27, -15.54], + [25.26, -15.52], + [25.25, -15.5], + [25.24, -15.49], + [25.25, -15.48], + [25.27, -15.47], + [25.31, -15.44], + [25.32, -15.42], + [25.33, -15.37], + [25.34, -15.36], + [25.35, -15.35], + [25.34, -15.33], + [25.33, -15.31], + [25.32, -15.3], + [26.75, -15.34], + [26.84, -15.35], + [26.98, -15.43], + [26.99, -15.44], + [26.96, -15.46], + [26.97, -15.47], + [27.2, -15.48], + [27.23, -15.5], + [27.28, -15.71], + [27.29, -15.73], + [27.3, -15.74], + [27.32, -15.73], + [27.4, -15.58], + [27.41, -15.57], + [27.45, -15.58], + [27.46, -15.57], + [27.47, -15.56], + [27.49, -15.55], + [27.5, -15.54], + [27.51, -15.53], + [27.52, -15.51], + [27.53, -15.5], + [27.54, -15.48], + [27.57, -15.49], + [27.58, -15.5], + [27.63, -15.52], + [27.64, -15.54], + [27.66, -15.55], + [27.67, -15.6], + [27.66, -15.61], + [27.65, -15.62], + [27.67, -15.64], + [27.68, -15.65], + [27.69, -15.66], + [27.75, -15.65], + [27.84, -15.66], + [27.85, -15.68], + [27.86, -15.69], + [27.89, -15.67], + [27.93, -15.66], + [27.97, -15.67], + [28.01, -15.68], + [28.02, -15.7], + [28.03, -15.72], + [28.04, -15.73], + [28.06, -15.74], + [28.18, -15.78], + [28.2, -15.79], + [28.23, -15.81], + [28.24, -15.82], + [28.28, -15.8], + [28.29, -15.79], + [28.39, -15.78], + [28.41, -15.79], + [28.42, -15.8], + [28.44, -15.81], + [28.49, -15.82], + [28.52, -15.84], + [28.57, -15.88], + [28.58, -15.89], + [28.68, -15.9], + [28.74, -15.95], + [28.8, -15.96], + [28.81, -15.95], + [28.82, -15.94], + [28.84, -15.95], + [28.85, -15.94], + [28.89, -15.93], + [28.93, -15.94], + [28.95, -15.96] + ], + "Western": [ + [22.02, -16.25], + [22.01, -16.2], + [21.98, -16.17], + [22, -13.7], + [22.03, -13.71], + [22.04, -13.72], + [22.07, -13.74], + [22.08, -13.76], + [22.16, -13.75], + [22.17, -13.74], + [22.18, -13.73], + [22.2, -13.71], + [22.21, -13.69], + [22.22, -13.68], + [22.25, -13.69], + [22.28, -13.7], + [22.29, -13.71], + [22.43, -13.83], + [22.5, -13.87], + [22.51, -13.89], + [22.54, -13.91], + [22.58, -13.92], + [22.61, -13.93], + [22.62, -13.94], + [22.63, -13.95], + [22.64, -13.97], + [22.68, -13.98], + [22.7, -13.99], + [22.73, -13.98], + [22.74, -13.91], + [22.75, -13.9], + [22.83, -13.87], + [22.88, -13.88], + [22.96, -13.94], + [22.98, -13.95], + [22.99, -13.97], + [23, -13.99], + [23.05, -13.98], + [23.09, -13.99], + [23.1, -14], + [23.11, -14.04], + [23.12, -14.05], + [23.13, -14.06], + [23.22, -14.07], + [23.23, -14.08], + [23.22, -14.09], + [23.21, -14.1], + [23.19, -14.13], + [23.18, -14.15], + [23.22, -14.14], + [23.23, -14.15], + [23.22, -14.17], + [23.28, -14.16], + [23.31, -14.14], + [23.32, -14.13], + [23.34, -14.14], + [23.37, -14.13], + [23.41, -14.1], + [23.44, -14.09], + [23.54, -14.06], + [23.56, -14.05], + [23.59, -14.02], + [23.63, -14.01], + [23.67, -13.99], + [23.7, -14], + [23.72, -14.01], + [23.77, -13.99], + [23.8, -13.98], + [23.82, -13.96], + [23.83, -13.98], + [23.84, -13.99], + [23.9, -14], + [23.93, -13.99], + [23.97, -14], + [24.02, -13.99], + [24.03, -13.98], + [24.04, -13.97], + [24.06, -13.98], + [24.07, -13.97], + [24.08, -13.96], + [24.09, -13.95], + [24.11, -13.96], + [24.13, -13.95], + [24.15, -13.94], + [24.16, -13.93], + [24.19, -13.92], + [24.21, -13.91], + [24.25, -13.92], + [24.27, -13.93], + [24.29, -13.94], + [24.3, -13.93], + [24.29, -13.92], + [24.3, -13.91], + [24.31, -13.89], + [24.32, -13.91], + [24.33, -13.92], + [24.34, -13.95], + [24.38, -13.96], + [24.4, -13.95], + [24.41, -13.96], + [24.43, -13.95], + [24.47, -13.94], + [24.48, -13.93], + [24.49, -13.92], + [24.51, -13.94], + [24.52, -13.95], + [24.53, -13.96], + [24.55, -13.97], + [24.57, -13.98], + [24.58, -13.99], + [24.59, -13.98], + [24.6, -13.96], + [24.62, -13.97], + [24.61, -13.99], + [24.62, -14], + [24.63, -13.98], + [24.64, -13.97], + [24.65, -13.96], + [24.69, -13.99], + [24.71, -14], + [24.72, -14.02], + [24.73, -14.05], + [24.74, -14.11], + [24.75, -14.12], + [24.8, -14.14], + [24.85, -14.15], + [24.88, -14.16], + [24.99, -14.21], + [25.01, -14.22], + [25.06, -14.21], + [25.07, -14.22], + [25.08, -14.23], + [25.09, -14.24], + [25.08, -14.3], + [25.07, -14.33], + [25.06, -14.34], + [25.05, -14.37], + [25.04, -14.44], + [25.03, -14.45], + [25, -14.46], + [24.98, -14.47], + [24.97, -14.48], + [24.96, -14.49], + [24.97, -14.52], + [24.96, -14.55], + [24.97, -14.57], + [24.98, -14.59], + [25, -14.62], + [25.02, -14.63], + [25.04, -14.64], + [25.06, -14.63], + [25.19, -14.62], + [25.21, -14.61], + [25.24, -14.6], + [25.28, -14.59], + [25.31, -14.58], + [25.41, -14.59], + [25.43, -14.6], + [25.51, -14.59], + [25.52, -14.58], + [25.55, -14.59], + [25.53, -14.6], + [25.51, -14.63], + [25.5, -14.64], + [25.49, -14.67], + [25.48, -14.68], + [25.47, -14.79], + [25.46, -14.8], + [25.45, -14.81], + [25.44, -14.83], + [25.43, -14.86], + [25.42, -14.88], + [25.43, -14.91], + [25.45, -14.97], + [25.46, -14.98], + [25.45, -15.03], + [25.43, -15.06], + [25.42, -15.08], + [25.41, -15.09], + [25.42, -15.12], + [25.41, -15.13], + [25.4, -15.14], + [25.38, -15.13], + [25.37, -15.14], + [25.36, -15.15], + [25.33, -15.18], + [25.32, -15.19], + [25.33, -15.23], + [25.32, -15.3], + [25.33, -15.31], + [25.34, -15.33], + [25.35, -15.34], + [25.34, -15.35], + [25.33, -15.37], + [25.32, -15.38], + [25.31, -15.43], + [25.3, -15.47], + [25.25, -15.48], + [25.24, -15.49], + [25.25, -15.5], + [25.26, -15.52], + [25.27, -15.53], + [25.26, -15.55], + [25.23, -15.58], + [25.22, -15.59], + [25.23, -15.6], + [25.25, -15.63], + [25.27, -15.64], + [25.28, -15.65], + [25.27, -15.67], + [25.26, -15.69], + [25.25, -15.7], + [25.26, -15.72], + [25.27, -15.74], + [25.28, -15.75], + [25.29, -15.76], + [25.34, -15.75], + [25.35, -15.74], + [25.36, -15.73], + [25.37, -15.72], + [25.38, -15.73], + [25.39, -15.74], + [25.4, -15.75], + [25.38, -15.88], + [25.37, -15.9], + [25.36, -15.91], + [25.35, -15.92], + [25.36, -15.97], + [25.35, -15.98], + [25.34, -15.99], + [25.33, -16], + [25.34, -16.02], + [25.35, -16.04], + [25.37, -16.06], + [25.38, -16.07], + [25.39, -16.08], + [25.43, -16.09], + [25.42, -16.1], + [25.41, -16.11], + [25.4, -16.12], + [25.39, -16.13], + [25.38, -16.14], + [25.37, -16.15], + [25.36, -16.16], + [25.35, -16.17], + [25.34, -16.2], + [25.33, -16.21], + [25.3, -16.27], + [25.29, -16.29], + [25.28, -16.3], + [25.25, -16.31], + [25.24, -16.32], + [25.23, -16.33], + [25.21, -16.34], + [25.19, -16.35], + [25.17, -16.36], + [25.15, -16.37], + [25.14, -16.38], + [25.04, -16.51], + [25.03, -16.52], + [25, -16.53], + [25.01, -16.56], + [25.03, -16.58], + [25.07, -16.6], + [25.08, -16.61], + [25.1, -16.67], + [25.21, -16.69], + [25.24, -16.7], + [25.25, -16.71], + [25.24, -16.77], + [25.25, -16.81], + [25.28, -16.91], + [25.27, -16.93], + [25.25, -16.96], + [25.24, -16.98], + [25.19, -17], + [25.17, -17.01], + [25.16, -17.03], + [25.14, -17.1], + [25.13, -17.11], + [25.1, -17.12], + [25.09, -17.14], + [25.08, -17.18], + [25.09, -17.19], + [25.1, -17.21], + [25.08, -17.25], + [25.07, -17.27], + [25.05, -17.29], + [25.03, -17.31], + [25.02, -17.32], + [25.03, -17.41], + [25.02, -17.43], + [25.01, -17.44], + [25, -17.45], + [24.99, -17.47], + [24.98, -17.49], + [24.97, -17.56], + [24.96, -17.55], + [24.94, -17.56], + [24.92, -17.54], + [24.9, -17.53], + [24.83, -17.52], + [24.78, -17.51], + [24.68, -17.49], + [24.63, -17.5], + [24.62, -17.51], + [24.61, -17.52], + [24.59, -17.53], + [24.54, -17.52], + [24.53, -17.51], + [24.5, -17.5], + [24.48, -17.49], + [24.41, -17.47], + [24.33, -17.49], + [24.31, -17.48], + [24.19, -17.49], + [24.11, -17.5], + [24.06, -17.51], + [24.02, -17.52], + [23.98, -17.53], + [23.93, -17.54], + [23.85, -17.55], + [23.81, -17.56], + [23.76, -17.57], + [23.72, -17.58], + [23.68, -17.59], + [23.63, -17.6], + [23.55, -17.61], + [23.51, -17.62], + [23.48, -17.63], + [23.38, -17.64], + [23.36, -17.58], + [23.34, -17.56], + [23.32, -17.55], + [23.31, -17.54], + [23.26, -17.53], + [23.24, -17.54], + [23.18, -17.52], + [23.17, -17.47], + [23.12, -17.45], + [23.1, -17.43], + [23.07, -17.41], + [23.05, -17.38], + [23.04, -17.34], + [23, -17.29], + [22.94, -17.27], + [22.88, -17.25], + [22.85, -17.23], + [22.81, -17.2], + [22.78, -17.18], + [22.77, -17.17], + [22.76, -17.15], + [22.74, -17.11], + [22.73, -17.08], + [22.71, -17.06], + [22.67, -17.01], + [22.65, -17], + [22.59, -16.98], + [22.57, -16.97], + [22.55, -16.92], + [22.52, -16.91], + [22.5, -16.89], + [22.49, -16.87], + [22.42, -16.75], + [22.4, -16.74], + [22.38, -16.73], + [22.37, -16.72], + [22.35, -16.7], + [22.34, -16.68], + [22.33, -16.67], + [22.3, -16.66], + [22.26, -16.67], + [22.15, -16.6], + [22.14, -16.57], + [22.13, -16.55], + [22.11, -16.54], + [22.1, -16.5], + [22.08, -16.47], + [22.09, -16.42], + [22.1, -16.39], + [22.11, -16.38], + [22.09, -16.37], + [22.06, -16.36], + [22.05, -16.34], + [22.04, -16.31], + [22.03, -16.29], + [22.02, -16.27], + [22.01, -16.25] + ], + "North-Western": [ + [21.98, -13.69], + [22.1, -13], + [23.99, -12.97], + [23.97, -12.93], + [23.95, -12.9], + [23.9, -12.85], + [23.87, -12.82], + [23.89, -12.71], + [23.91, -12.63], + [23.93, -12.56], + [23.94, -12.53], + [23.99, -12.47], + [24.02, -12.42], + [24.03, -12.4], + [24.02, -12.34], + [24.01, -12.25], + [23.98, -12.23], + [23.96, -12.2], + [23.95, -12.15], + [23.96, -12.01], + [23.97, -11.88], + [23.99, -11.83], + [23.98, -11.72], + [23.97, -11.7], + [23.96, -11.68], + [23.95, -11.66], + [23.96, -11.62], + [23.98, -11.58], + [24.01, -11.54], + [24.02, -11.44], + [24.05, -11.42], + [24.06, -11.41], + [24.02, -11.3], + [24.01, -11.27], + [24.02, -11.13], + [23.99, -11.11], + [24, -11], + [23.98, -10.94], + [23.97, -10.92], + [24, -10.87], + [24.05, -10.88], + [24.09, -10.9], + [24.11, -10.92], + [24.12, -10.99], + [24.14, -11.04], + [24.16, -11.03], + [24.22, -11.05], + [24.32, -11.06], + [24.35, -11.08], + [24.37, -11.1], + [24.38, -11.12], + [24.37, -11.14], + [24.36, -11.15], + [24.37, -11.18], + [24.38, -11.19], + [24.39, -11.2], + [24.4, -11.22], + [24.39, -11.28], + [24.38, -11.3], + [24.35, -11.35], + [24.34, -11.36], + [24.3, -11.37], + [24.29, -11.38], + [24.31, -11.41], + [24.39, -11.42], + [24.43, -11.45], + [24.45, -11.46], + [24.47, -11.47], + [24.49, -11.46], + [24.53, -11.45], + [24.56, -11.44], + [24.57, -11.43], + [24.58, -11.42], + [24.59, -11.4], + [24.62, -11.39], + [24.65, -11.38], + [24.66, -11.35], + [24.67, -11.34], + [24.71, -11.33], + [24.83, -11.32], + [24.9, -11.28], + [24.94, -11.27], + [25.12, -11.26], + [25.18, -11.25], + [25.28, -11.2], + [25.31, -11.19], + [25.32, -11.21], + [25.33, -11.27], + [25.32, -11.28], + [25.3, -11.3], + [25.28, -11.31], + [25.29, -11.32], + [25.31, -11.33], + [25.3, -11.35], + [25.29, -11.36], + [25.28, -11.37], + [25.29, -11.42], + [25.31, -11.46], + [25.32, -11.47], + [25.3, -11.5], + [25.33, -11.62], + [25.34, -11.63], + [25.35, -11.65], + [25.39, -11.66], + [25.41, -11.67], + [25.46, -11.7], + [25.48, -11.72], + [25.47, -11.76], + [25.48, -11.77], + [25.5, -11.78], + [25.52, -11.77], + [25.53, -11.76], + [25.56, -11.75], + [25.57, -11.73], + [25.66, -11.75], + [25.69, -11.78], + [25.73, -11.8], + [25.83, -11.79], + [25.86, -11.8], + [25.91, -11.85], + [25.95, -11.86], + [25.96, -11.9], + [26.19, -11.91], + [26.21, -11.92], + [26.23, -11.93], + [26.29, -11.94], + [26.33, -11.92], + [26.38, -11.91], + [26.44, -11.92], + [26.46, -11.93], + [26.47, -11.95], + [26.49, -11.96], + [26.52, -11.97], + [26.61, -11.98], + [26.64, -11.99], + [26.66, -12], + [26.68, -12.01], + [26.7, -12.02], + [26.72, -12.01], + [26.73, -12], + [26.74, -11.98], + [26.76, -11.97], + [26.87, -11.96], + [26.91, -11.94], + [26.95, -11.91], + [26.97, -11.87], + [26.98, -11.75], + [27, -11.73], + [27.01, -11.71], + [27.02, -11.7], + [27.01, -11.63], + [27.02, -11.6], + [27.03, -11.59], + [27.05, -11.6], + [27.1, -11.58], + [27.17, -11.57], + [27.2, -11.59], + [27.21, -11.64], + [27.23, -11.81], + [27.42, -11.92], + [27.47, -12], + [27.52, -12.18], + [27.54, -12.2], + [27.59, -12.24], + [27.54, -12.27], + [27.52, -12.28], + [27.51, -12.3], + [27.5, -12.29], + [27.46, -12.28], + [27.47, -12.27], + [27.45, -12.26], + [27.44, -12.25], + [27.43, -12.24], + [27.41, -12.25], + [27.4, -12.26], + [27.39, -12.27], + [27.37, -12.28], + [27.35, -12.29], + [27.34, -12.3], + [27.32, -12.31], + [27.31, -12.32], + [27.29, -12.34], + [27.28, -12.35], + [27.15, -12.33], + [27.12, -12.34], + [27.06, -12.33], + [27.05, -12.34], + [27.07, -12.38], + [27.06, -12.43], + [27.05, -12.45], + [27.06, -12.47], + [27.07, -12.5], + [27.08, -12.51], + [27.07, -12.52], + [27.03, -12.53], + [27.01, -12.54], + [26.97, -12.58], + [26.96, -12.6], + [26.95, -12.61], + [26.94, -12.62], + [26.93, -12.63], + [26.89, -12.64], + [26.87, -12.66], + [26.86, -12.67], + [26.85, -12.72], + [26.86, -12.76], + [26.87, -12.77], + [26.88, -12.79], + [26.9, -12.81], + [26.91, -12.82], + [26.9, -12.84], + [26.89, -12.86], + [26.88, -12.88], + [26.89, -12.9], + [26.91, -12.91], + [26.92, -12.92], + [26.93, -12.93], + [26.96, -12.94], + [26.97, -12.95], + [27.01, -12.96], + [27.02, -12.97], + [27.03, -12.98], + [27.04, -12.99], + [27.05, -13], + [27.07, -13.12], + [27.06, -13.13], + [27.05, -13.14], + [27.04, -13.15], + [26.98, -13.19], + [26.97, -13.2], + [26.96, -13.22], + [26.98, -13.28], + [26.97, -13.33], + [26.96, -13.35], + [26.95, -13.37], + [26.93, -13.38], + [26.91, -13.41], + [26.9, -13.42], + [26.89, -13.43], + [26.86, -13.44], + [26.85, -13.45], + [26.84, -13.5], + [26.83, -13.52], + [26.81, -13.53], + [26.8, -13.55], + [26.79, -13.58], + [26.8, -13.68], + [26.82, -13.69], + [26.85, -13.72], + [26.87, -13.73], + [26.88, -13.74], + [26.89, -13.75], + [26.9, -13.78], + [26.91, -13.79], + [26.92, -13.8], + [26.95, -13.81], + [26.94, -13.86], + [26.92, -13.89], + [26.91, -13.91], + [26.9, -14.01], + [26.89, -14.02], + [26.87, -14.03], + [26.86, -14.04], + [26.9, -14.07], + [26.91, -14.08], + [26.96, -14.14], + [26.97, -14.15], + [26.98, -14.17], + [26.96, -14.24], + [26.95, -14.25], + [26.96, -14.37], + [26.95, -14.39], + [26.94, -14.4], + [26.93, -14.41], + [26.79, -14.42], + [26.75, -14.44], + [26.74, -14.45], + [26.65, -14.44], + [26.64, -14.45], + [26.63, -14.46], + [26.62, -14.45], + [26.59, -14.44], + [26.56, -14.45], + [26.54, -14.46], + [26.53, -14.47], + [26.49, -14.53], + [26.43, -14.58], + [26.39, -14.63], + [26.38, -14.65], + [26.37, -14.7], + [26.33, -14.71], + [26.32, -14.72], + [26.31, -14.71], + [26.3, -14.7], + [26.29, -14.69], + [26.25, -14.67], + [26.22, -14.66], + [26.2, -14.65], + [26.18, -14.63], + [26.17, -14.62], + [25.62, -14.56], + [25.57, -14.57], + [25.55, -14.59], + [25.52, -14.58], + [25.51, -14.59], + [25.48, -14.6], + [25.42, -14.59], + [25.39, -14.58], + [25.29, -14.59], + [25.24, -14.6], + [25.22, -14.61], + [25.19, -14.62], + [25.15, -14.63], + [25.05, -14.64], + [25.03, -14.63], + [25.01, -14.62], + [24.98, -14.59], + [24.97, -14.58], + [24.96, -14.56], + [24.97, -14.52], + [24.96, -14.49], + [24.97, -14.48], + [24.98, -14.47], + [25, -14.46], + [25.03, -14.45], + [25.04, -14.44], + [25.05, -14.43], + [25.06, -14.35], + [25.07, -14.33], + [25.08, -14.31], + [25.09, -14.29], + [25.08, -14.23], + [25.07, -14.22], + [25.06, -14.21], + [25.02, -14.22], + [24.99, -14.21], + [24.88, -14.16], + [24.87, -14.15], + [24.82, -14.14], + [24.75, -14.12], + [24.74, -14.11], + [24.73, -14.1], + [24.72, -14.03], + [24.71, -14.01], + [24.69, -13.99], + [24.67, -13.96], + [24.65, -13.97], + [24.63, -13.98], + [24.62, -14], + [24.61, -13.99], + [24.62, -13.97], + [24.61, -13.96], + [24.59, -13.97], + [24.58, -13.99], + [24.57, -13.98], + [24.55, -13.97], + [24.54, -13.96], + [24.52, -13.95], + [24.51, -13.94], + [24.49, -13.92], + [24.48, -13.93], + [24.46, -13.94], + [24.47, -13.95], + [24.43, -13.96], + [24.41, -13.95], + [24.39, -13.96], + [24.34, -13.95], + [24.33, -13.94], + [24.32, -13.91], + [24.31, -13.9], + [24.3, -13.89], + [24.29, -13.91], + [24.3, -13.93], + [24.29, -13.94], + [24.27, -13.93], + [24.25, -13.92], + [24.23, -13.91], + [24.2, -13.92], + [24.19, -13.93], + [24.15, -13.94], + [24.14, -13.95], + [24.13, -13.96], + [24.11, -13.95], + [24.08, -13.96], + [24.07, -13.97], + [24.06, -13.98], + [24.05, -13.97], + [24.03, -13.98], + [24.02, -13.99], + [24.01, -14], + [23.96, -13.99], + [23.92, -14], + [23.87, -13.99], + [23.83, -13.98], + [23.82, -13.96], + [23.8, -13.98], + [23.79, -13.99], + [23.73, -14.01], + [23.7, -14], + [23.68, -13.99], + [23.63, -14.01], + [23.59, -14.02], + [23.56, -14.05], + [23.54, -14.06], + [23.44, -14.09], + [23.41, -14.1], + [23.38, -14.13], + [23.35, -14.14], + [23.32, -14.13], + [23.31, -14.14], + [23.28, -14.16], + [23.26, -14.17], + [23.23, -14.16], + [23.22, -14.14], + [23.18, -14.15], + [23.19, -14.13], + [23.21, -14.1], + [23.22, -14.09], + [23.23, -14.08], + [23.22, -14.07], + [23.14, -14.06], + [23.12, -14.05], + [23.11, -14.04], + [23.1, -14.03], + [23.09, -13.99], + [23.08, -13.98], + [23.03, -13.99], + [22.99, -13.98], + [22.98, -13.96], + [22.96, -13.94], + [22.88, -13.88], + [22.85, -13.87], + [22.81, -13.9], + [22.75, -13.91], + [22.73, -13.97], + [22.72, -13.99], + [22.69, -13.98], + [22.67, -13.97], + [22.63, -13.96], + [22.62, -13.94], + [22.61, -13.93], + [22.59, -13.92], + [22.57, -13.91], + [22.52, -13.89], + [22.5, -13.87], + [22.43, -13.83], + [22.29, -13.71], + [22.28, -13.7], + [22.25, -13.69], + [22.24, -13.68], + [22.22, -13.69], + [22.2, -13.71], + [22.18, -13.72], + [22.17, -13.74], + [22.16, -13.75], + [22.14, -13.76], + [22.07, -13.74], + [22.04, -13.72], + [22.03, -13.71], + [22, -13.7], + [21.98, -13.69] + ], + "Luapula": [ + [28.59, -9.54], + [28.57, -9.53], + [28.56, -9.48], + [28.53, -9.46], + [28.52, -9.45], + [28.51, -9.43], + [28.52, -9.42], + [28.5, -9.35], + [28.46, -9.34], + [28.41, -9.32], + [28.37, -9.31], + [28.35, -9.27], + [28.37, -9.24], + [28.42, -9.21], + [28.51, -9.16], + [28.6, -9.1], + [28.77, -8.93], + [28.89, -8.77], + [28.93, -8.68], + [28.94, -8.59], + [28.89, -8.5], + [28.92, -8.47], + [29.04, -8.45], + [29.21, -8.43], + [29.37, -8.4], + [29.58, -8.37], + [29.57, -8.39], + [29.54, -8.45], + [29.53, -8.47], + [29.51, -8.49], + [29.47, -8.5], + [29.43, -8.52], + [29.41, -8.53], + [29.39, -8.55], + [29.36, -8.61], + [29.35, -8.63], + [29.34, -8.64], + [29.31, -8.72], + [29.28, -8.82], + [29.25, -8.9], + [29.23, -8.93], + [29.19, -8.94], + [29.18, -8.95], + [29.17, -8.96], + [29.15, -9.04], + [29.12, -9.05], + [29.11, -9.06], + [29.12, -9.11], + [29.13, -9.12], + [29.16, -9.13], + [29.18, -9.14], + [29.19, -9.15], + [29.2, -9.16], + [29.22, -9.15], + [29.24, -9.16], + [29.26, -9.18], + [29.27, -9.19], + [29.28, -9.2], + [29.3, -9.21], + [29.31, -9.22], + [29.33, -9.21], + [29.34, -9.22], + [29.35, -9.26], + [29.34, -9.28], + [29.36, -9.36], + [29.35, -9.37], + [29.34, -9.39], + [29.33, -9.4], + [29.32, -9.43], + [29.33, -9.44], + [29.34, -9.47], + [29.36, -9.52], + [29.37, -9.54], + [29.38, -9.55], + [29.4, -9.54], + [29.44, -9.55], + [29.45, -9.56], + [29.47, -9.59], + [29.48, -9.6], + [29.49, -9.61], + [29.5, -9.62], + [29.52, -9.63], + [29.53, -9.64], + [29.54, -9.65], + [29.57, -9.66], + [29.62, -9.67], + [29.67, -9.68], + [29.7, -9.69], + [29.72, -9.7], + [29.73, -9.71], + [29.81, -9.72], + [29.82, -9.74], + [29.83, -9.75], + [29.84, -9.77], + [29.86, -9.78], + [29.87, -9.81], + [29.88, -9.82], + [29.9, -9.83], + [29.92, -9.84], + [29.94, -9.88], + [29.93, -9.91], + [29.91, -9.98], + [29.93, -10.05], + [29.94, -10.06], + [29.93, -10.08], + [29.92, -10.09], + [29.91, -10.1], + [29.9, -10.11], + [29.88, -10.2], + [29.87, -10.21], + [29.85, -10.23], + [29.84, -10.24], + [29.81, -10.23], + [29.78, -10.22], + [29.68, -10.23], + [29.67, -10.24], + [29.65, -10.25], + [29.62, -10.28], + [29.61, -10.29], + [29.59, -10.3], + [29.55, -10.32], + [29.51, -10.33], + [29.5, -10.34], + [29.48, -10.36], + [29.45, -10.38], + [29.44, -10.39], + [29.43, -10.42], + [29.42, -10.44], + [29.41, -10.45], + [29.4, -10.48], + [29.41, -10.51], + [29.37, -10.59], + [29.36, -10.6], + [29.35, -10.64], + [29.3, -10.65], + [29.29, -10.66], + [29.17, -10.74], + [29.16, -10.75], + [29.11, -10.92], + [29.09, -10.94], + [29.08, -10.96], + [29.09, -10.97], + [29.17, -10.99], + [29.18, -11], + [29.27, -11.09], + [29.37, -11.12], + [29.39, -11.11], + [29.4, -11.06], + [29.39, -11.03], + [29.38, -11.02], + [29.37, -11.01], + [29.36, -10.99], + [29.34, -10.92], + [29.35, -10.9], + [29.37, -10.88], + [29.64, -10.74], + [29.68, -10.75], + [29.71, -10.77], + [29.75, -10.78], + [29.76, -10.79], + [29.78, -10.8], + [29.79, -10.81], + [29.81, -10.86], + [29.82, -10.87], + [29.84, -10.89], + [29.86, -10.9], + [29.88, -10.94], + [29.89, -10.95], + [29.83, -11.4], + [29.84, -11.39], + [29.85, -11.37], + [29.88, -11.36], + [29.89, -11.34], + [29.9, -11.32], + [29.94, -11.29], + [29.95, -11.28], + [29.96, -11.25], + [29.97, -11.24], + [30.12, -11.25], + [30.45, -11.48], + [30.46, -11.49], + [30.45, -11.51], + [30.44, -11.55], + [30.45, -11.58], + [30.28, -11.81], + [30.26, -11.82], + [30.25, -11.83], + [29.82, -11.89], + [29.79, -11.9], + [29.78, -11.91], + [29.77, -11.92], + [29.78, -11.98], + [29.79, -12.05], + [29.81, -12.07], + [29.82, -12.09], + [29.81, -12.11], + [29.82, -12.13], + [29.81, -12.14], + [29.8, -12.15], + [29.76, -12.16], + [29.7, -12.19], + [29.65, -12.21], + [29.63, -12.22], + [29.62, -12.21], + [29.6, -12.19], + [29.55, -12.21], + [29.53, -12.22], + [29.49, -12.23], + [29.47, -12.24], + [29.46, -12.29], + [29.45, -12.32], + [29.48, -12.38], + [29.5, -12.39], + [29.53, -12.41], + [29.52, -12.43], + [29.51, -12.44], + [29.5, -12.45], + [29.47, -12.44], + [29.41, -12.43], + [29.36, -12.41], + [29.3, -12.4], + [29.28, -12.39], + [29.27, -12.37], + [29.13, -12.38], + [29.11, -12.39], + [29.1, -12.37], + [29.08, -12.38], + [29.03, -12.36], + [28.94, -12.21], + [28.92, -12.17], + [28.86, -12.14], + [28.85, -12.13], + [28.84, -12.09], + [28.82, -12.08], + [28.81, -12.06], + [28.77, -12.05], + [28.76, -12.04], + [28.75, -12.02], + [28.74, -11.98], + [28.71, -11.99], + [28.69, -11.98], + [28.64, -11.96], + [28.62, -11.95], + [28.61, -11.91], + [28.59, -11.9], + [28.57, -11.91], + [28.55, -11.89], + [28.54, -11.87], + [28.5, -11.86], + [28.49, -11.81], + [28.48, -11.8], + [28.46, -11.79], + [28.45, -11.78], + [28.44, -11.71], + [28.43, -11.69], + [28.42, -11.68], + [28.41, -11.61], + [28.4, -11.6], + [28.38, -11.58], + [28.37, -11.54], + [28.36, -11.53], + [28.35, -11.46], + [28.36, -11.45], + [28.41, -11.37], + [28.43, -11.35], + [28.44, -11.29], + [28.45, -11.27], + [28.46, -11.26], + [28.47, -11.23], + [28.48, -11.18], + [28.49, -11.15], + [28.48, -11.09], + [28.49, -11.06], + [28.5, -11.03], + [28.51, -11.02], + [28.53, -10.96], + [28.54, -10.94], + [28.55, -10.91], + [28.56, -10.81], + [28.58, -10.79], + [28.59, -10.77], + [28.6, -10.76], + [28.61, -10.74], + [28.62, -10.72], + [28.63, -10.71], + [28.67, -10.7], + [28.68, -10.68], + [28.69, -10.66], + [28.7, -10.64], + [28.67, -10.62], + [28.65, -10.54], + [28.63, -10.52], + [28.64, -10.5], + [28.63, -10.48], + [28.64, -10.46], + [28.65, -10.44], + [28.64, -10.43], + [28.63, -10.39], + [28.62, -10.37], + [28.63, -10.31], + [28.62, -10.28], + [28.61, -10.27], + [28.6, -10.25], + [28.57, -10.22], + [28.58, -10.2], + [28.6, -10.17], + [28.62, -10.14], + [28.63, -10.1], + [28.62, -9.95], + [28.63, -9.93], + [28.66, -9.86], + [28.67, -9.82], + [28.68, -9.8], + [28.7, -9.79], + [28.67, -9.77], + [28.66, -9.75], + [28.65, -9.74], + [28.63, -9.72], + [28.62, -9.65], + [28.61, -9.62], + [28.59, -9.57], + [28.58, -9.56], + [28.61, -9.55], + [28.62, -9.54] + ], + "Copperbelt": [ + [27.59, -12.24], + [27.6, -12.25], + [27.64, -12.29], + [27.67, -12.3], + [27.71, -12.31], + [27.76, -12.3], + [27.81, -12.28], + [27.82, -12.27], + [27.83, -12.26], + [27.88, -12.27], + [27.93, -12.3], + [27.95, -12.32], + [27.96, -12.37], + [28.09, -12.38], + [28.1, -12.39], + [28.11, -12.41], + [28.13, -12.43], + [28.15, -12.42], + [28.16, -12.41], + [28.19, -12.4], + [28.2, -12.41], + [28.22, -12.43], + [28.24, -12.44], + [28.28, -12.43], + [28.3, -12.44], + [28.34, -12.45], + [28.42, -12.52], + [28.44, -12.54], + [28.46, -12.59], + [28.47, -12.61], + [28.5, -12.65], + [28.51, -12.67], + [28.5, -12.71], + [28.48, -12.72], + [28.47, -12.74], + [28.48, -12.76], + [28.5, -12.79], + [28.52, -12.81], + [28.54, -12.83], + [28.55, -12.89], + [28.57, -12.9], + [28.58, -12.89], + [28.59, -12.88], + [28.61, -12.85], + [28.62, -12.84], + [28.67, -12.85], + [28.71, -12.89], + [28.78, -12.98], + [28.79, -12.99], + [28.8, -13], + [28.81, -13.04], + [28.83, -13.05], + [28.82, -13.09], + [28.83, -13.1], + [28.85, -13.14], + [28.89, -13.15], + [28.9, -13.16], + [28.93, -13.31], + [28.95, -13.35], + [28.98, -13.38], + [28.99, -13.4], + [29.05, -13.39], + [29.06, -13.4], + [29.02, -13.44], + [28.95, -13.52], + [28.91, -13.54], + [28.87, -13.56], + [28.86, -13.57], + [28.84, -13.59], + [28.83, -13.61], + [28.82, -13.62], + [28.67, -13.73], + [28.66, -13.86], + [28.54, -13.87], + [28.52, -13.88], + [28.5, -13.89], + [28.37, -13.88], + [28.36, -13.87], + [28.33, -13.88], + [28.28, -13.89], + [28.27, -13.88], + [28.21, -13.87], + [28.17, -13.88], + [28.15, -13.89], + [28.11, -13.9], + [27.98, -13.91], + [27.96, -13.92], + [27.93, -13.91], + [27.91, -13.9], + [27.9, -13.88], + [27.89, -13.86], + [27.82, -13.7], + [27.81, -13.69], + [27.79, -13.68], + [27.7, -13.67], + [27.68, -13.66], + [27.67, -13.65], + [27.62, -13.66], + [27.63, -13.69], + [27.62, -13.7], + [27.6, -13.71], + [27.59, -13.72], + [27.6, -13.73], + [27.59, -13.75], + [27.55, -13.79], + [27.54, -13.82], + [27.53, -13.81], + [27.52, -13.79], + [27.48, -13.81], + [27.49, -13.82], + [27.48, -13.87], + [27.46, -13.89], + [27.43, -13.91], + [27.42, -13.92], + [27.41, -13.91], + [27.4, -13.9], + [27.39, -13.88], + [27.38, -13.85], + [27.37, -13.82], + [27.36, -13.8], + [27.35, -13.79], + [27.34, -13.77], + [27.35, -13.76], + [27.26, -13.73], + [26.85, -13.72], + [26.82, -13.69], + [26.8, -13.68], + [26.79, -13.67], + [26.8, -13.56], + [26.81, -13.54], + [26.83, -13.52], + [26.84, -13.51], + [26.85, -13.45], + [26.86, -13.44], + [26.87, -13.43], + [26.9, -13.42], + [26.91, -13.41], + [26.92, -13.38], + [26.95, -13.37], + [26.96, -13.36], + [26.97, -13.33], + [26.98, -13.32], + [26.96, -13.26], + [26.97, -13.21], + [26.98, -13.19], + [27.04, -13.16], + [27.05, -13.14], + [27.06, -13.13], + [27.07, -13.12], + [27.09, -13], + [27.04, -12.99], + [27.03, -12.98], + [27.02, -12.97], + [27.01, -12.96], + [27, -12.95], + [26.96, -12.94], + [26.93, -12.93], + [26.92, -12.92], + [26.91, -12.91], + [26.9, -12.9], + [26.88, -12.89], + [26.89, -12.86], + [26.9, -12.84], + [26.91, -12.83], + [26.9, -12.81], + [26.88, -12.79], + [26.87, -12.78], + [26.86, -12.76], + [26.85, -12.75], + [26.86, -12.71], + [26.87, -12.66], + [26.88, -12.64], + [26.9, -12.63], + [26.94, -12.62], + [26.95, -12.61], + [26.96, -12.6], + [26.97, -12.58], + [27.01, -12.54], + [27.02, -12.53], + [27.07, -12.52], + [27.08, -12.51], + [27.07, -12.5], + [27.06, -12.48], + [27.05, -12.46], + [27.06, -12.44], + [27.07, -12.42], + [27.05, -12.35], + [27.06, -12.33], + [27.08, -12.34], + [27.14, -12.33], + [27.28, -12.35], + [27.29, -12.34], + [27.3, -12.32], + [27.32, -12.31], + [27.34, -12.3], + [27.35, -12.29], + [27.36, -12.28], + [27.38, -12.27], + [27.4, -12.26], + [27.41, -12.25], + [27.43, -12.24], + [27.44, -12.25], + [27.45, -12.26], + [27.47, -12.27], + [27.46, -12.28], + [27.47, -12.29], + [27.51, -12.3], + [27.52, -12.28], + [27.54, -12.27], + [27.59, -12.25] + ], + "Central": [ + [29.77, -13.46], + [29.8, -13.42], + [29.82, -12.16], + [29.83, -12.15], + [29.84, -12.13], + [29.85, -12.12], + [29.86, -12.05], + [29.87, -12.04], + [29.95, -12.01], + [29.97, -12], + [30.01, -12.01], + [30.03, -12.03], + [30.05, -12.07], + [30.06, -12.11], + [30.07, -12.13], + [30.08, -12.14], + [30.09, -12.15], + [30.11, -12.16], + [30.12, -12.17], + [30.15, -12.18], + [30.16, -12.2], + [30.18, -12.21], + [30.21, -12.22], + [30.23, -12.23], + [30.25, -12.24], + [30.29, -12.25], + [30.31, -12.26], + [30.36, -12.27], + [30.38, -12.28], + [30.39, -12.27], + [30.42, -12.28], + [30.43, -12.29], + [30.44, -12.3], + [30.45, -12.31], + [30.48, -12.3], + [30.49, -12.31], + [30.51, -12.33], + [30.5, -12.42], + [30.51, -12.47], + [30.52, -12.48], + [30.55, -12.49], + [30.56, -12.5], + [30.57, -12.51], + [30.56, -12.56], + [30.57, -12.58], + [30.58, -12.59], + [30.61, -12.62], + [30.63, -12.63], + [30.65, -12.62], + [30.66, -12.61], + [30.68, -12.59], + [30.7, -12.6], + [30.71, -12.63], + [30.72, -12.64], + [30.73, -12.65], + [30.75, -12.66], + [30.76, -12.67], + [30.77, -12.68], + [30.76, -12.7], + [30.75, -12.71], + [30.74, -12.73], + [30.73, -12.75], + [30.74, -12.82], + [30.75, -12.87], + [30.81, -12.91], + [30.83, -12.92], + [30.84, -12.93], + [30.95, -12.94], + [30.99, -12.95], + [31.03, -12.96], + [31.11, -13.03], + [31.12, -13.04], + [31.16, -13.03], + [31.17, -13.02], + [31.18, -13], + [31.19, -12.96], + [31.2, -12.95], + [31.32, -12.97], + [31.34, -12.98], + [31.35, -12.99], + [31.36, -13.23], + [31.37, -13.25], + [31.39, -13.28], + [31.41, -13.31], + [31.43, -13.32], + [31.41, -13.45], + [31.36, -13.46], + [31.34, -13.47], + [31.3, -13.5], + [31.29, -13.51], + [31.28, -13.52], + [31.27, -13.51], + [31.26, -13.52], + [31.25, -13.53], + [31.23, -13.56], + [31.22, -13.58], + [31.16, -13.6], + [31.14, -13.61], + [31.12, -13.63], + [31.11, -13.7], + [31.1, -13.71], + [31.07, -13.74], + [31.06, -13.76], + [31.05, -13.78], + [31.01, -13.79], + [30.98, -13.81], + [30.96, -13.82], + [30.94, -13.86], + [30.92, -13.89], + [30.9, -13.9], + [30.89, -13.92], + [30.88, -13.93], + [30.1, -13.94], + [30.14, -13.95], + [30.15, -13.96], + [30.18, -14.04], + [30.19, -14.05], + [30.22, -14.06], + [30.26, -14.07], + [30.27, -14.08], + [30.29, -14.09], + [30.3, -14.1], + [30.31, -14.11], + [30.32, -14.12], + [30.31, -14.17], + [30.3, -14.2], + [30.29, -14.21], + [30.28, -14.22], + [30.25, -14.23], + [30.23, -14.25], + [30.22, -14.26], + [30.21, -14.27], + [30.2, -14.29], + [30.17, -14.31], + [30.13, -14.36], + [30.12, -14.37], + [30.11, -14.38], + [30.09, -14.37], + [30.08, -14.38], + [30.07, -14.41], + [30.06, -14.42], + [30.05, -14.43], + [30.03, -14.44], + [30.02, -14.5], + [30.01, -14.51], + [30, -14.56], + [29.99, -14.61], + [30, -14.62], + [30.02, -14.64], + [30.05, -14.66], + [30, -14.67], + [29.99, -14.66], + [29.98, -14.65], + [29.94, -14.66], + [29.91, -14.65], + [29.9, -14.66], + [29.89, -14.68], + [29.88, -14.69], + [29.87, -14.7], + [29.79, -14.72], + [29.67, -14.75], + [29.66, -14.76], + [29.65, -14.77], + [29.59, -14.8], + [29.58, -14.81], + [29.52, -14.82], + [29.51, -14.84], + [29.5, -14.85], + [29.49, -14.91], + [29.46, -14.96], + [29.39, -14.98], + [29.23, -14.96], + [29.05, -15.01], + [29, -15.02], + [28.95, -15.04], + [28.82, -15.15], + [28.74, -15.18], + [28.66, -15.19], + [28.4, -15.15], + [28.38, -15.16], + [28.34, -15.22], + [28.32, -15.3], + [28.29, -15.34], + [28.26, -15.35], + [28.2, -15.34], + [28.03, -15.29], + [27.86, -15.26], + [27.83, -15.27], + [27.78, -15.3], + [27.77, -15.31], + [27.79, -15.34], + [27.81, -15.35], + [27.86, -15.36], + [27.89, -15.37], + [27.92, -15.42], + [27.93, -15.47], + [27.92, -15.52], + [27.91, -15.53], + [27.8, -15.56], + [27.76, -15.65], + [27.75, -15.66], + [27.69, -15.67], + [27.68, -15.65], + [27.67, -15.64], + [27.65, -15.63], + [27.66, -15.61], + [27.67, -15.6], + [27.66, -15.59], + [27.64, -15.55], + [27.63, -15.53], + [27.58, -15.5], + [27.57, -15.49], + [27.56, -15.48], + [27.53, -15.49], + [27.52, -15.51], + [27.51, -15.52], + [27.5, -15.54], + [27.49, -15.55], + [27.48, -15.56], + [27.47, -15.57], + [27.46, -15.58], + [27.43, -15.57], + [27.4, -15.58], + [27.32, -15.73], + [27.3, -15.74], + [27.29, -15.73], + [27.28, -15.71], + [27.23, -15.5], + [27.2, -15.48], + [26.97, -15.47], + [26.96, -15.46], + [26.99, -15.44], + [26.98, -15.43], + [26.84, -15.35], + [26.8, -15.34], + [25.32, -15.3], + [25.33, -15.23], + [25.32, -15.19], + [25.33, -15.18], + [25.36, -15.15], + [25.37, -15.14], + [25.38, -15.13], + [25.39, -15.14], + [25.41, -15.13], + [25.42, -15.12], + [25.41, -15.09], + [25.42, -15.08], + [25.43, -15.06], + [25.45, -15.04], + [25.46, -15.02], + [25.45, -14.97], + [25.43, -14.91], + [25.42, -14.9], + [25.43, -14.87], + [25.44, -14.85], + [25.45, -14.82], + [25.46, -14.8], + [25.47, -14.79], + [25.48, -14.78], + [25.49, -14.67], + [25.5, -14.64], + [25.51, -14.63], + [25.52, -14.6], + [25.53, -14.59], + [25.57, -14.57], + [25.59, -14.56], + [26.17, -14.62], + [26.18, -14.63], + [26.19, -14.65], + [26.21, -14.66], + [26.25, -14.67], + [26.29, -14.69], + [26.3, -14.7], + [26.31, -14.71], + [26.32, -14.72], + [26.33, -14.71], + [26.37, -14.7], + [26.38, -14.65], + [26.39, -14.63], + [26.43, -14.58], + [26.49, -14.53], + [26.53, -14.47], + [26.54, -14.46], + [26.56, -14.45], + [26.57, -14.44], + [26.6, -14.45], + [26.63, -14.46], + [26.64, -14.45], + [26.65, -14.44], + [26.74, -14.45], + [26.75, -14.44], + [26.79, -14.42], + [26.8, -14.41], + [26.94, -14.4], + [26.95, -14.39], + [26.96, -14.37], + [26.95, -14.26], + [26.96, -14.24], + [26.98, -14.21], + [26.97, -14.15], + [26.96, -14.14], + [26.91, -14.08], + [26.9, -14.07], + [26.86, -14.05], + [26.87, -14.03], + [26.89, -14.02], + [26.9, -14.01], + [26.91, -14], + [26.92, -13.89], + [26.94, -13.86], + [26.95, -13.84], + [26.92, -13.8], + [26.91, -13.79], + [26.9, -13.78], + [26.89, -13.77], + [26.88, -13.74], + [26.87, -13.73], + [26.86, -13.72], + [27.26, -13.73], + [27.35, -13.74], + [27.34, -13.76], + [27.35, -13.79], + [27.36, -13.8], + [27.37, -13.81], + [27.38, -13.82], + [27.39, -13.86], + [27.4, -13.9], + [27.41, -13.91], + [27.42, -13.92], + [27.43, -13.91], + [27.46, -13.89], + [27.48, -13.87], + [27.49, -13.84], + [27.48, -13.81], + [27.49, -13.79], + [27.53, -13.81], + [27.54, -13.82], + [27.55, -13.81], + [27.59, -13.75], + [27.6, -13.74], + [27.59, -13.72], + [27.6, -13.71], + [27.61, -13.7], + [27.63, -13.69], + [27.62, -13.68], + [27.64, -13.65], + [27.68, -13.66], + [27.69, -13.67], + [27.79, -13.68], + [27.81, -13.69], + [27.82, -13.7], + [27.89, -13.86], + [27.9, -13.88], + [27.91, -13.9], + [27.93, -13.91], + [27.94, -13.92], + [27.97, -13.91], + [27.99, -13.9], + [28.14, -13.89], + [28.16, -13.88], + [28.17, -13.87], + [28.27, -13.88], + [28.28, -13.89], + [28.29, -13.88], + [28.36, -13.87], + [28.37, -13.88], + [28.42, -13.89], + [28.51, -13.88], + [28.53, -13.87], + [28.58, -13.86], + [28.67, -13.85], + [28.82, -13.62], + [28.83, -13.61], + [28.84, -13.59], + [28.86, -13.57], + [28.87, -13.56], + [28.91, -13.54], + [28.95, -13.53], + [29.02, -13.44], + [29.06, -13.4], + [29.07, -13.39], + [29.1, -13.38], + [29.14, -13.39], + [29.15, -13.41], + [29.16, -13.42], + [29.17, -13.43], + [29.18, -13.44], + [29.19, -13.43], + [29.21, -13.41], + [29.23, -13.4], + [29.25, -13.39], + [29.31, -13.35], + [29.45, -13.3], + [29.47, -13.29], + [29.53, -13.23], + [29.55, -13.22], + [29.57, -13.23], + [29.59, -13.24], + [29.61, -13.25], + [29.63, -13.26], + [29.67, -13.27], + [29.66, -13.3], + [29.65, -13.31], + [29.63, -13.32], + [29.62, -13.37], + [29.6, -13.39], + [29.61, -13.4], + [29.62, -13.42], + [29.63, -13.43], + [29.64, -13.44], + [29.66, -13.45], + [29.7, -13.46] + ] +} From 248b547a6c8e7f62b6d085d3d6e9641871064050 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 20 Feb 2025 16:39:52 -0800 Subject: [PATCH 20/44] chore: update boundaries --- .../geoLocation/mw/admin-1.boundaries.json | 5403 +++++++++++------ 1 file changed, 3663 insertions(+), 1740 deletions(-) diff --git a/libs/data/geoLocation/mw/admin-1.boundaries.json b/libs/data/geoLocation/mw/admin-1.boundaries.json index da69c40c1..5b7e37da1 100644 --- a/libs/data/geoLocation/mw/admin-1.boundaries.json +++ b/libs/data/geoLocation/mw/admin-1.boundaries.json @@ -1,1821 +1,3744 @@ { + "Balaka": [ + [34.84, -15.22], + [34.85, -15.23], + [34.84, -15.24], + [34.83, -15.25], + [34.84, -15.27], + [34.83, -15.28], + [34.82, -15.32], + [34.81, -15.33], + [34.86, -15.32], + [35.07, -15.31], + [35.08, -15.3], + [35.07, -15.31], + [35.08, -15.3], + [35.1, -15.29], + [35.11, -15.28], + [35.12, -15.26], + [35.13, -15.25], + [35.14, -15.24], + [35.15, -15.23], + [35.16, -15.22], + [35.17, -15.2], + [35.18, -15.17], + [35.19, -15.14], + [35.2, -15.12], + [35.21, -15.11], + [35.22, -15.06], + [35.23, -15.03], + [35.24, -15.01], + [35.25, -14.99], + [35.26, -14.98], + [35.27, -14.97], + [35.28, -14.95], + [35.29, -14.93], + [35.3, -14.88], + [35.29, -14.86], + [35.28, -14.81], + [35.22, -14.77], + [34.97, -14.78], + [34.96, -14.81], + [34.95, -14.86], + [34.94, -14.85], + [34.93, -14.86], + [34.91, -14.94], + [34.9, -14.96], + [34.89, -15.02], + [34.86, -15.13], + [34.84, -15.22] + ], + "Blantyre": [ + [35.01, -15.91], + [35.02, -15.92], + [35.03, -15.93], + [35.04, -15.92], + [35.05, -15.91], + [35.07, -15.9], + [35.06, -15.89], + [35.08, -15.88], + [35.09, -15.87], + [35.08, -15.86], + [35.09, -15.85], + [35.11, -15.84], + [35.12, -15.83], + [35.13, -15.82], + [35.12, -15.8], + [35.11, -15.79], + [35.12, -15.75], + [35.11, -15.72], + [35.12, -15.71], + [35.11, -15.69], + [35.12, -15.66], + [35.11, -15.64], + [35.1, -15.63], + [35.11, -15.58], + [35.12, -15.56], + [35.13, -15.55], + [35.12, -15.54], + [35.1, -15.55], + [35.09, -15.54], + [35.13, -15.47], + [35.09, -15.46], + [35.07, -15.44], + [35.06, -15.43], + [35.05, -15.42], + [35.06, -15.41], + [35.05, -15.4], + [35.03, -15.39], + [35.02, -15.38], + [35.01, -15.37], + [35, -15.36], + [34.99, -15.35], + [34.98, -15.36], + [34.97, -15.35], + [34.95, -15.36], + [34.92, -15.37], + [34.91, -15.38], + [34.9, -15.39], + [34.89, -15.4], + [34.88, -15.41], + [34.87, -15.44], + [34.86, -15.45], + [34.87, -15.46], + [34.86, -15.47], + [34.85, -15.49], + [34.84, -15.5], + [34.83, -15.51], + [34.82, -15.53], + [34.81, -15.54], + [34.8, -15.55], + [34.79, -15.56], + [34.77, -15.57], + [34.76, -15.58], + [34.75, -15.59], + [34.76, -15.62], + [34.75, -15.68], + [34.74, -15.69], + [34.72, -15.7], + [34.73, -15.71], + [34.74, -15.74], + [34.73, -15.81], + [34.74, -15.82], + [34.85, -15.83], + [34.87, -15.84], + [34.88, -15.85], + [34.87, -15.87], + [34.86, -15.89], + [34.85, -15.9], + [34.86, -15.91], + [34.87, -15.92], + [34.86, -15.93], + [34.85, -15.95], + [34.86, -15.97], + [34.87, -15.96], + [34.88, -15.97], + [34.89, -15.98], + [34.88, -16], + [34.89, -16.01], + [34.9, -16.02], + [34.91, -16.01], + [34.93, -16], + [34.92, -15.99], + [34.94, -16], + [34.95, -15.99], + [34.96, -15.97], + [34.97, -15.95], + [34.96, -15.94], + [34.97, -15.95], + [34.98, -15.94], + [34.99, -15.93], + [35, -15.92], + [35.01, -15.91] + ], + "Chikwawa": [ + [35.04, -16.51], + [35.05, -16.5], + [35.06, -16.49], + [35.07, -16.43], + [35.08, -16.4], + [35.09, -16.38], + [35.1, -16.35], + [35.09, -16.34], + [35.1, -16.33], + [35.11, -16.32], + [35.12, -16.31], + [35.11, -16.29], + [35.1, -16.28], + [35.09, -16.27], + [35.08, -16.26], + [35.06, -16.25], + [35.05, -16.24], + [35.04, -16.23], + [35.03, -16.21], + [35.02, -16.2], + [34.97, -16.14], + [34.96, -16.13], + [34.95, -16.12], + [34.94, -16.11], + [34.93, -16.09], + [34.92, -16.06], + [34.91, -16.04], + [34.92, -16.03], + [34.91, -16.02], + [34.9, -16.01], + [34.89, -16.02], + [34.88, -16], + [34.89, -15.99], + [34.88, -15.97], + [34.87, -15.96], + [34.86, -15.97], + [34.85, -15.96], + [34.86, -15.95], + [34.87, -15.93], + [34.86, -15.92], + [34.85, -15.9], + [34.86, -15.89], + [34.87, -15.88], + [34.88, -15.87], + [34.87, -15.84], + [34.85, -15.83], + [34.81, -15.82], + [34.71, -15.81], + [34.49, -15.8], + [34.48, -15.79], + [34.43, -15.77], + [34.4, -15.76], + [34.35, -15.74], + [34.32, -15.75], + [34.31, -15.76], + [34.3, -15.77], + [34.29, -15.78], + [34.28, -15.79], + [34.27, -15.8], + [34.26, -15.82], + [34.25, -15.84], + [34.26, -15.86], + [34.25, -15.87], + [34.26, -15.88], + [34.25, -15.89], + [34.26, -15.9], + [34.27, -15.92], + [34.28, -15.93], + [34.31, -15.94], + [34.33, -15.95], + [34.34, -15.96], + [34.36, -15.97], + [34.37, -15.99], + [34.38, -16], + [34.39, -16.02], + [34.4, -16.03], + [34.41, -16.04], + [34.43, -16.05], + [34.44, -16.06], + [34.43, -16.07], + [34.42, -16.08], + [34.41, -16.11], + [34.4, -16.12], + [34.41, -16.13], + [34.4, -16.14], + [34.41, -16.15], + [34.4, -16.16], + [34.41, -16.21], + [34.42, -16.23], + [34.43, -16.26], + [34.44, -16.27], + [34.45, -16.28], + [34.48, -16.29], + [34.49, -16.3], + [34.5, -16.29], + [34.52, -16.28], + [34.53, -16.29], + [34.54, -16.3], + [34.55, -16.31], + [34.57, -16.32], + [34.58, -16.33], + [34.57, -16.34], + [34.58, -16.35], + [34.59, -16.36], + [34.58, -16.39], + [34.59, -16.4], + [34.6, -16.42], + [34.61, -16.43], + [34.62, -16.42], + [34.63, -16.43], + [34.64, -16.44], + [34.65, -16.45], + [34.66, -16.44], + [34.68, -16.45], + [34.69, -16.5], + [34.7, -16.51], + [34.71, -16.5], + [34.73, -16.51], + [34.75, -16.52], + [34.76, -16.53], + [34.77, -16.54], + [34.78, -16.55], + [34.77, -16.58], + [34.78, -16.59], + [34.79, -16.58], + [34.8, -16.59], + [34.81, -16.6], + [34.82, -16.61], + [34.83, -16.6], + [34.84, -16.61], + [34.85, -16.62], + [34.86, -16.66], + [34.87, -16.68], + [34.88, -16.69], + [34.9, -16.68], + [34.91, -16.67], + [34.92, -16.66], + [34.93, -16.65], + [34.94, -16.64], + [34.95, -16.63], + [34.97, -16.62], + [34.98, -16.61], + [34.97, -16.6], + [34.98, -16.59], + [34.97, -16.58], + [34.98, -16.57], + [34.99, -16.56], + [35, -16.55], + [35.01, -16.54], + [35.02, -16.53], + [35.03, -16.52], + [35.04, -16.51] + ], + "Chiradzulu": [ + [35.33, -15.96], + [35.32, -15.91], + [35.31, -15.77], + [35.3, -15.74], + [35.31, -15.71], + [35.33, -15.68], + [35.32, -15.67], + [35.3, -15.66], + [35.27, -15.65], + [35.26, -15.64], + [35.25, -15.63], + [35.24, -15.62], + [35.23, -15.59], + [35.22, -15.57], + [35.19, -15.56], + [35.18, -15.55], + [35.19, -15.53], + [35.17, -15.51], + [35.16, -15.52], + [35.15, -15.54], + [35.14, -15.53], + [35.13, -15.54], + [35.12, -15.55], + [35.11, -15.57], + [35.1, -15.59], + [35.11, -15.63], + [35.12, -15.64], + [35.11, -15.66], + [35.12, -15.69], + [35.11, -15.71], + [35.12, -15.73], + [35.11, -15.75], + [35.12, -15.8], + [35.13, -15.82], + [35.12, -15.83], + [35.11, -15.84], + [35.1, -15.85], + [35.11, -15.86], + [35.13, -15.85], + [35.14, -15.86], + [35.19, -15.85], + [35.2, -15.86], + [35.21, -15.88], + [35.2, -15.89], + [35.23, -15.9], + [35.25, -15.91], + [35.26, -15.92], + [35.27, -15.96], + [35.28, -15.98], + [35.29, -15.99], + [35.3, -16], + [35.31, -15.99], + [35.32, -15.97], + [35.33, -15.96] + ], "Chitipa": [ - [34.01, -9.48], - [34.05, -9.49], - [34.08, -9.51], - [34.09, -9.52], - [34.1, -9.53], - [34.14, -9.57], - [34.16, -9.59], - [34.19, -9.61], - [34.29, -9.71], - [34.32, -9.72], - [34.33, -9.75], - [34.34, -9.78], - [34.36, -9.8], - [34.38, -9.82], - [34.48, -9.95], - [34.49, -9.97], - [34.52, -10.01], - [34.54, -10.04], - [34.53, -10.08], - [34.52, -10.09], - [34.53, -10.13], - [34.57, -10.2], - [34.58, -10.26], - [34.59, -10.29], - [34.57, -10.41], - [34.59, -10.46], - [34.58, -10.51], - [34.59, -10.55], - [34.6, -10.58], - [34.09, -10.57], - [33.95, -10.45], - [33.72, -10.1], - [33.71, -10.08], - [33.7, -10.07], - [33.69, -10.06], + [33.22, -9.5], + [33.21, -9.51], + [33.2, -9.5], + [33.16, -9.49], + [33.13, -9.48], + [33.12, -9.47], + [33.11, -9.46], + [33.1, -9.45], + [33.08, -9.44], + [33.06, -9.43], + [33.05, -9.42], + [33.04, -9.41], + [33.02, -9.4], + [33.01, -9.38], + [33, -9.37], + [32.97, -9.39], + [32.96, -9.4], + [32.95, -9.41], + [32.96, -9.42], + [32.95, -9.43], + [32.97, -9.48], + [32.98, -9.49], + [32.99, -9.5], + [33.01, -9.49], + [33.02, -9.5], + [33.03, -9.51], + [33.02, -9.54], + [33.01, -9.55], + [33, -9.56], + [33.01, -9.59], + [33.02, -9.61], + [33.03, -9.64], + [33.04, -9.63], + [33.07, -9.64], + [33.08, -9.65], + [33.09, -9.66], + [33.1, -9.68], + [33.11, -9.67], + [33.12, -9.64], + [33.11, -9.63], + [33.12, -9.61], + [33.13, -9.6], + [33.14, -9.61], + [33.15, -9.62], + [33.16, -9.61], + [33.19, -9.6], + [33.2, -9.61], + [33.21, -9.62], + [33.22, -9.63], + [33.23, -9.65], + [33.24, -9.75], + [33.25, -9.76], + [33.27, -9.77], + [33.28, -9.78], + [33.29, -9.79], + [33.3, -9.81], + [33.31, -9.82], + [33.32, -9.83], + [33.35, -9.84], + [33.36, -9.85], + [33.37, -9.86], + [33.38, -9.9], + [33.37, -9.92], + [33.36, -9.93], + [33.35, -9.94], + [33.34, -9.98], + [33.33, -10], + [33.32, -10.05], + [33.31, -10.06], + [33.32, -10.07], + [33.33, -10.08], + [33.34, -10.09], + [33.35, -10.1], + [33.37, -10.11], + [33.38, -10.1], + [33.39, -10.11], + [33.4, -10.12], + [33.42, -10.13], + [33.43, -10.14], + [33.44, -10.15], + [33.45, -10.16], + [33.46, -10.17], + [33.48, -10.18], + [33.51, -10.19], + [33.52, -10.2], + [33.53, -10.21], + [33.54, -10.22], + [33.55, -10.23], + [33.56, -10.24], + [33.55, -10.26], + [33.54, -10.3], + [33.55, -10.33], + [33.54, -10.34], + [33.56, -10.35], + [33.55, -10.36], + [33.56, -10.38], + [33.57, -10.39], + [33.56, -10.4], + [33.57, -10.41], + [33.58, -10.44], + [33.6, -10.45], + [33.63, -10.46], + [33.64, -10.47], + [33.63, -10.48], + [33.62, -10.49], + [33.63, -10.5], + [33.64, -10.51], + [33.65, -10.52], + [33.66, -10.53], + [33.67, -10.54], + [33.68, -10.55], + [33.69, -10.58], + [33.7, -10.57], + [33.72, -10.56], + [33.79, -10.53], + [33.89, -10.48], + [33.96, -10.45], + [33.8, -10.21], + [33.77, -10.16], + [33.74, -10.13], + [33.75, -10.12], + [33.74, -10.11], + [33.73, -10.1], + [33.72, -10.08], + [33.71, -10.06], + [33.68, -10.07], + [33.67, -10.06], [33.66, -10.07], - [33.61, -10.06], - [33.58, -10.03], - [33.57, -10.02], - [33.53, -10.01], - [33.52, -10], - [33.51, -9.99], - [33.5, -9.98], - [33.49, -9.97], - [33.48, -9.96], - [33.49, -9.94], - [33.51, -9.93], - [33.56, -9.9], - [33.57, -9.89], + [33.63, -10.06], + [33.61, -10.05], + [33.6, -10.04], + [33.59, -10.03], + [33.58, -10.01], + [33.56, -10.02], + [33.55, -10.01], + [33.54, -10], + [33.53, -9.99], + [33.51, -9.98], + [33.5, -9.97], + [33.49, -9.98], + [33.48, -9.97], + [33.47, -9.96], + [33.48, -9.94], + [33.49, -9.93], + [33.51, -9.92], + [33.53, -9.91], + [33.54, -9.9], + [33.56, -9.89], + [33.57, -9.88], + [33.58, -9.89], [33.59, -9.88], - [33.61, -9.87], - [33.62, -9.86], + [33.6, -9.87], + [33.61, -9.86], + [33.62, -9.84], + [33.63, -9.83], + [33.62, -9.82], [33.63, -9.83], [33.64, -9.82], + [33.65, -9.81], [33.66, -9.8], [33.67, -9.79], [33.7, -9.78], - [33.69, -9.75], - [33.68, -9.72], - [33.67, -9.7], + [33.69, -9.77], + [33.68, -9.75], + [33.67, -9.72], + [33.66, -9.71], + [33.67, -9.69], [33.68, -9.67], - [33.67, -9.65], - [33.65, -9.61], - [33.7, -9.59], - [33.73, -9.58], - [33.76, -9.6], - [33.79, -9.63], - [33.81, -9.64], - [33.84, -9.65], - [33.87, -9.67], - [33.89, -9.69], - [33.9, -9.71], - [33.91, -9.72], - [33.93, -9.7], - [33.94, -9.68], - [33.95, -9.67], - [33.96, -9.64], - [33.95, -9.55], - [33.96, -9.52], - [33.98, -9.51], - [34, -9.49], - [34.01, -9.48] - ], - "Rumphi": [ - [34.62, -10.58], - [34.63, -10.6], - [34.65, -10.65], - [34.66, -10.67], - [34.65, -10.71], - [34.66, -10.72], - [34.67, -10.73], - [34.68, -10.75], - [34.66, -10.76], - [34.65, -10.86], - [34.63, -10.95], - [34.62, -10.97], - [34.19, -11], - [34.06, -11.08], - [34.04, -11.05], - [34.03, -11.03], - [34.02, -11.02], - [33.95, -10.97], - [33.94, -10.96], - [33.93, -11.02], - [33.92, -11.03], - [33.82, -11.01], - [33.78, -11.02], - [33.75, -11.03], - [33.74, -11.04], - [33.75, -11.05], - [33.74, -11.08], - [33.72, -11.09], - [33.7, -11.08], - [33.69, -11.07], - [33.68, -11.05], - [33.63, -11.06], - [33.61, -11.05], - [33.59, -11.04], - [33.58, -11.03], - [33.57, -11.02], - [33.53, -11.03], - [33.52, -11.05], - [33.51, -11.06], - [33.5, -11.08], - [33.48, -11.09], - [33.46, -11.11], - [33.44, -11.1], - [33.45, -11.07], - [33.44, -11.04], - [33.43, -11.01], - [33.36, -11], - [33.31, -10.98], - [33.29, -10.94], - [33.28, -10.91], - [33.27, -10.9], - [33.23, -10.88], - [33.24, -10.87], - [33.25, -10.86], - [33.26, -10.87], - [33.29, -10.86], - [33.31, -10.83], - [33.32, -10.82], - [33.33, -10.81], - [33.37, -10.8], - [33.42, -10.81], - [33.45, -10.8], - [33.47, -10.78], - [33.5, -10.77], - [33.51, -10.75], - [33.53, -10.71], - [33.58, -10.66], - [33.59, -10.65], - [33.6, -10.64], - [33.64, -10.62], - [33.66, -10.6], - [33.67, -10.58], - [33.7, -10.56], - [33.95, -10.45], - [34.09, -10.57], - [34.11, -10.58] + [33.67, -9.66], + [33.66, -9.65], + [33.65, -9.64], + [33.66, -9.63], + [33.65, -9.62], + [33.64, -9.61], + [33.63, -9.6], + [33.61, -9.59], + [33.6, -9.58], + [33.58, -9.59], + [33.55, -9.6], + [33.54, -9.61], + [33.53, -9.62], + [33.51, -9.63], + [33.5, -9.62], + [33.46, -9.61], + [33.45, -9.62], + [33.44, -9.61], + [33.43, -9.6], + [33.42, -9.59], + [33.43, -9.58], + [33.42, -9.57], + [33.41, -9.56], + [33.4, -9.55], + [33.39, -9.54], + [33.38, -9.53], + [33.37, -9.52], + [33.36, -9.53], + [33.35, -9.52], + [33.34, -9.5], + [33.33, -9.49], + [33.31, -9.48], + [33.3, -9.49], + [33.28, -9.5], + [33.26, -9.49], + [33.23, -9.5] ], - "Nkhata Bay": [ - [34.62, -10.97], - [34.6, -10.99], - [34.59, -11.02], - [34.6, -11.04], - [34.61, -11.08], - [34.62, -11.12], - [34.67, -11.16], - [34.68, -11.18], - [34.7, -11.19], - [34.71, -11.2], - [34.72, -11.21], - [34.73, -11.25], - [34.74, -11.27], - [34.76, -11.28], - [34.75, -11.29], - [34.74, -11.3], - [34.76, -11.34], - [34.77, -11.35], - [34.78, -11.33], - [34.84, -11.35], - [34.87, -11.36], - [34.89, -11.38], - [34.9, -11.4], - [34.92, -11.42], - [34.93, -11.45], - [34.94, -11.46], - [34.95, -11.47], - [34.96, -11.49], - [34.65, -11.57], - [34.62, -11.58], - [34.61, -11.59], - [34.6, -11.73], - [34.56, -11.83], - [34.49, -11.94], - [34.38, -12.1], - [34.36, -12.15], - [34.35, -12.2], - [33.96, -12.19], - [33.91, -12.17], - [33.9, -12.16], - [33.88, -12.14], - [33.76, -12.13], - [33.75, -12.12], - [33.73, -12.11], - [33.72, -12.1], - [33.73, -12.07], - [33.74, -12.06], - [33.75, -12.05], - [33.77, -12.04], - [33.8, -12.03], - [33.82, -12], - [33.81, -11.97], - [33.8, -11.89], - [33.81, -11.85], - [33.82, -11.83], - [33.81, -11.78], - [33.8, -11.77], - [33.79, -11.75], - [33.78, -11.74], - [33.77, -11.72], - [33.78, -11.62], - [33.79, -11.6], - [33.81, -11.58], - [33.82, -11.57], - [33.83, -11.56], - [33.86, -11.54], - [33.87, -11.53], - [33.93, -11.54], - [33.96, -11.53], - [33.97, -11.52], - [33.98, -11.51], - [33.99, -11.48], - [34, -11.47], - [34.01, -11.46], - [34.05, -11.47], - [34.07, -11.46], - [34.1, -11.45], - [34.09, -11.39], - [34.08, -11.38], - [34.07, -11.37], - [34.05, -11.28], - [34.04, -11.27], - [34.02, -11.26], - [34.05, -11.15], - [34.06, -11.08], - [34.19, -11], - [34.23, -10.97] + "Dedza": [ + [34.74, -14.28], + [34.72, -14.29], + [34.68, -14.28], + [34.69, -14.27], + [34.68, -14.23], + [34.66, -14.22], + [34.63, -14.21], + [34.62, -14.2], + [34.61, -14.19], + [34.6, -14.18], + [34.61, -14.17], + [34.6, -14.16], + [34.59, -14.15], + [34.58, -14.14], + [34.57, -14.13], + [34.56, -14.12], + [34.55, -14.11], + [34.54, -14.08], + [34.53, -14.09], + [34.52, -14.1], + [34.49, -14.11], + [34.48, -14.1], + [34.47, -14.09], + [34.46, -14.08], + [34.45, -14.07], + [34.44, -14.06], + [34.43, -14.05], + [34.42, -14.04], + [34.41, -14.03], + [34.4, -14.02], + [34.39, -14.01], + [34.38, -13.99], + [34.37, -13.98], + [34.36, -13.96], + [34.35, -13.95], + [34.34, -13.94], + [34.33, -13.93], + [34.32, -13.91], + [34.31, -13.9], + [34.3, -13.87], + [34.29, -13.86], + [34.28, -13.87], + [34.27, -13.88], + [34.26, -13.9], + [34.24, -13.91], + [34.23, -13.92], + [34.22, -13.93], + [34.23, -13.94], + [34.22, -13.93], + [34.2, -13.94], + [34.19, -13.97], + [34.18, -13.98], + [34.17, -14.01], + [34.16, -14.03], + [34.14, -14.04], + [34.13, -14.05], + [34.14, -14.06], + [34.13, -14.07], + [34.12, -14.08], + [34.11, -14.09], + [34.1, -14.1], + [34.09, -14.11], + [34.08, -14.14], + [34.06, -14.15], + [34.05, -14.16], + [34.04, -14.19], + [34.03, -14.2], + [34.01, -14.21], + [34, -14.2], + [33.99, -14.19], + [33.98, -14.2], + [33.97, -14.21], + [33.95, -14.22], + [33.94, -14.26], + [33.95, -14.27], + [33.94, -14.29], + [33.93, -14.31], + [33.89, -14.32], + [33.87, -14.33], + [33.86, -14.32], + [33.85, -14.31], + [33.84, -14.32], + [33.83, -14.33], + [33.82, -14.34], + [33.81, -14.35], + [33.8, -14.36], + [33.78, -14.37], + [33.77, -14.38], + [33.76, -14.39], + [33.71, -14.4], + [33.7, -14.42], + [33.69, -14.44], + [33.68, -14.52], + [33.67, -14.53], + [33.66, -14.54], + [33.67, -14.58], + [33.66, -14.59], + [33.65, -14.6], + [33.67, -14.61], + [33.68, -14.62], + [33.69, -14.61], + [33.7, -14.59], + [33.71, -14.58], + [33.72, -14.57], + [33.71, -14.56], + [33.7, -14.55], + [33.71, -14.54], + [33.72, -14.5], + [33.74, -14.51], + [33.75, -14.52], + [33.77, -14.53], + [33.79, -14.54], + [33.8, -14.55], + [33.83, -14.54], + [33.84, -14.53], + [33.85, -14.52], + [33.86, -14.51], + [33.87, -14.52], + [33.89, -14.51], + [33.88, -14.5], + [33.89, -14.49], + [33.91, -14.48], + [33.93, -14.47], + [33.94, -14.48], + [34.09, -14.49], + [34.08, -14.46], + [34.11, -14.45], + [34.19, -14.44], + [34.22, -14.43], + [34.23, -14.42], + [34.24, -14.43], + [34.27, -14.42], + [34.28, -14.41], + [34.29, -14.4], + [34.31, -14.41], + [34.32, -14.4], + [34.35, -14.39], + [34.38, -14.4], + [34.39, -14.39], + [34.4, -14.41], + [34.42, -14.42], + [34.44, -14.41], + [34.45, -14.42], + [34.47, -14.43], + [34.5, -14.42], + [34.52, -14.43], + [34.53, -14.44], + [34.55, -14.43], + [34.56, -14.44], + [34.59, -14.43], + [34.61, -14.41], + [34.72, -14.33], + [34.73, -14.32], + [34.74, -14.31] ], - "Likoma": [ - [34.69, -12], - [34.74, -12.01], - [34.75, -12.02], - [34.76, -12.04], - [34.75, -12.09], - [34.73, -12.11], - [34.71, -12.12], - [34.66, -12.1], - [34.68, -12.01], - [34.69, -12] + "Dowa": [ + [34.24, -13.8], + [34.25, -13.79], + [34.27, -13.78], + [34.3, -13.77], + [34.29, -13.75], + [34.28, -13.74], + [34.27, -13.68], + [34.26, -13.69], + [34.25, -13.7], + [34.21, -13.71], + [34.2, -13.7], + [34.17, -13.68], + [34.15, -13.67], + [34.12, -13.64], + [34.11, -13.52], + [34.1, -13.53], + [34.08, -13.54], + [34.07, -13.53], + [34.06, -13.54], + [34.05, -13.53], + [34.04, -13.52], + [34.03, -13.53], + [34.04, -13.52], + [34.03, -13.51], + [34.02, -13.5], + [34, -13.51], + [33.97, -13.52], + [33.95, -13.51], + [33.94, -13.5], + [33.93, -13.48], + [33.92, -13.49], + [33.89, -13.5], + [33.84, -13.51], + [33.83, -13.52], + [33.79, -13.51], + [33.78, -13.52], + [33.76, -13.53], + [33.75, -13.52], + [33.74, -13.51], + [33.73, -13.46], + [33.74, -13.45], + [33.73, -13.41], + [33.72, -13.38], + [33.71, -13.36], + [33.7, -13.34], + [33.69, -13.33], + [33.67, -13.32], + [33.66, -13.31], + [33.65, -13.3], + [33.64, -13.29], + [33.62, -13.28], + [33.61, -13.26], + [33.62, -13.25], + [33.61, -13.24], + [33.62, -13.23], + [33.59, -13.24], + [33.58, -13.28], + [33.57, -13.29], + [33.55, -13.28], + [33.54, -13.3], + [33.55, -13.31], + [33.54, -13.32], + [33.53, -13.31], + [33.54, -13.32], + [33.53, -13.34], + [33.52, -13.33], + [33.51, -13.34], + [33.5, -13.33], + [33.48, -13.32], + [33.47, -13.31], + [33.46, -13.32], + [33.45, -13.33], + [33.46, -13.34], + [33.47, -13.37], + [33.45, -13.38], + [33.46, -13.39], + [33.45, -13.4], + [33.44, -13.42], + [33.43, -13.43], + [33.42, -13.46], + [33.41, -13.47], + [33.42, -13.49], + [33.43, -13.5], + [33.45, -13.51], + [33.44, -13.53], + [33.45, -13.59], + [33.46, -13.63], + [33.45, -13.68], + [33.46, -13.69], + [33.5, -13.7], + [33.51, -13.71], + [33.52, -13.72], + [33.55, -13.71], + [33.56, -13.72], + [33.57, -13.73], + [33.59, -13.72], + [33.6, -13.71], + [33.61, -13.7], + [33.68, -13.69], + [33.71, -13.68], + [33.75, -13.67], + [33.76, -13.68], + [33.75, -13.69], + [33.76, -13.71], + [33.77, -13.76], + [33.78, -13.77], + [33.8, -13.78], + [33.81, -13.77], + [33.82, -13.78], + [33.85, -13.77], + [33.87, -13.76], + [33.88, -13.77], + [33.92, -13.78], + [33.93, -13.77], + [33.94, -13.78], + [33.95, -13.77], + [33.96, -13.79], + [33.99, -13.8], + [34.01, -13.81], + [34.02, -13.82], + [34.03, -13.83], + [34.04, -13.84], + [34.05, -13.83], + [34.08, -13.84], + [34.09, -13.83], + [34.1, -13.84], + [34.11, -13.83], + [34.14, -13.82], + [34.15, -13.81], + [34.17, -13.8], + [34.2, -13.81], + [34.21, -13.82], + [34.22, -13.81], + [34.23, -13.8] ], "Karonga": [ - [32.94, -9.49], - [32.93, -9.48], - [32.92, -9.47], - [32.94, -9.39], - [32.96, -9.38], - [32.99, -9.39], - [33.04, -9.44], - [33.1, -9.49], - [33.14, -9.5], - [33.17, -9.51], - [33.2, -9.5], - [33.22, -9.49], - [33.24, -9.5], - [33.27, -9.49], - [33.36, -9.53], - [33.37, -9.55], - [33.39, -9.59], - [33.4, -9.6], - [33.42, -9.62], - [33.54, -9.6], - [33.56, -9.59], - [33.59, -9.6], - [33.62, -9.61], - [33.67, -9.65], - [33.68, -9.66], - [33.67, -9.69], - [33.68, -9.7], - [33.69, -9.73], + [34.26, -10.4], + [33.72, -10.06], + [33.73, -10.08], + [33.74, -10.11], + [33.75, -10.12], + [33.74, -10.13], + [33.77, -10.16], + [33.8, -10.21], + [33.96, -10.45], + [34.08, -10.57], + [34.09, -10.58], + [34.12, -10.59], + [34.13, -10.58], + [34.14, -10.57], + [34.16, -10.58], + [34.18, -10.59], + [34.19, -10.56], + [34.2, -10.55], + [34.21, -10.54], + [34.23, -10.53], + [34.22, -10.52], + [34.21, -10.51], + [34.22, -10.47], + [34.23, -10.46], + [34.24, -10.45], + [34.26, -10.44], + [34.27, -10.45], + [34.28, -10.46], + [34.27, -10.45], + [34.26, -10.44], + [34.25, -10.43], + [34.26, -10.4], + [34.25, -10.39], + [34.24, -10.38], + [34.25, -10.37], + [34.24, -10.36], + [34.23, -10.35], + [34.21, -10.34], + [34.2, -10.33], + [34.19, -10.32], + [34.18, -10.31], + [34.17, -10.28], + [34.16, -10.27], + [34.15, -10.26], + [34.14, -10.25], + [34.13, -10.24], + [34.11, -10.23], + [34.1, -10.22], + [34.09, -10.21], + [34.08, -10.2], + [34.07, -10.19], + [34.06, -10.18], + [34.05, -10.16], + [34.04, -10.15], + [34.03, -10.14], + [34.02, -10.13], + [34.01, -10.12], + [34, -10.11], + [34.01, -10.09], + [34, -10.08], + [34.01, -10.07], + [34, -10.06], + [33.99, -10.05], + [33.98, -10.04], + [33.97, -10.03], + [33.96, -10.02], + [33.95, -9.99], + [33.94, -9.98], + [33.95, -9.94], + [33.94, -9.9], + [33.93, -9.89], + [33.92, -9.88], + [33.91, -9.87], + [33.9, -9.85], + [33.91, -9.83], + [33.9, -9.8], + [33.89, -9.76], + [33.9, -9.77], + [33.89, -9.76], + [33.9, -9.74], + [33.91, -9.73], + [33.92, -9.72], + [33.93, -9.71], + [33.91, -9.7], + [33.9, -9.69], + [33.89, -9.68], + [33.87, -9.67], + [33.86, -9.66], + [33.85, -9.65], + [33.84, -9.64], + [33.82, -9.63], + [33.81, -9.62], + [33.8, -9.61], + [33.79, -9.6], + [33.78, -9.59], + [33.76, -9.58], + [33.75, -9.59], + [33.74, -9.58], + [33.73, -9.59], + [33.72, -9.58], + [33.71, -9.59], + [33.72, -9.6], + [33.71, -9.61], + [33.65, -9.6], + [33.64, -9.61], + [33.65, -9.62], + [33.66, -9.63], + [33.65, -9.64], + [33.66, -9.65], + [33.67, -9.66], + [33.68, -9.67], + [33.67, -9.68], + [33.66, -9.69], + [33.65, -9.71], + [33.67, -9.72], + [33.68, -9.73], + [33.69, -9.75], [33.7, -9.77], [33.69, -9.79], - [33.66, -9.8], + [33.67, -9.8], + [33.65, -9.81], [33.64, -9.82], [33.63, -9.83], - [33.62, -9.85], - [33.61, -9.87], - [33.59, -9.88], + [33.62, -9.82], + [33.63, -9.83], + [33.62, -9.84], + [33.61, -9.85], + [33.6, -9.86], + [33.59, -9.87], + [33.58, -9.88], [33.57, -9.89], [33.56, -9.9], + [33.54, -9.91], + [33.53, -9.92], [33.51, -9.93], [33.49, -9.94], - [33.48, -9.96], - [33.49, -9.97], - [33.5, -9.98], - [33.51, -9.99], - [33.52, -10], - [33.53, -10.01], - [33.54, -10.02], - [33.58, -10.03], - [33.61, -10.06], + [33.47, -9.95], + [33.48, -9.97], + [33.49, -9.98], + [33.5, -9.97], + [33.51, -9.98], + [33.52, -9.99], + [33.54, -10], + [33.55, -10.01], + [33.56, -10.02], + [33.57, -10.01], + [33.59, -10.02], + [33.6, -10.03], + [33.61, -10.04], + [33.62, -10.06], [33.63, -10.07], - [33.69, -10.06], - [33.7, -10.07], - [33.71, -10.08], - [33.72, -10.1], - [33.95, -10.45], - [33.7, -10.56], - [33.67, -10.57], - [33.64, -10.51], - [33.62, -10.49], - [33.6, -10.45], - [33.57, -10.42], - [33.56, -10.4], - [33.53, -10.34], - [33.54, -10.26], - [33.53, -10.23], - [33.52, -10.21], - [33.5, -10.2], - [33.48, -10.18], - [33.45, -10.17], - [33.44, -10.15], - [33.42, -10.14], - [33.4, -10.12], - [33.32, -10.08], - [33.3, -10.06], - [33.31, -10.01], - [33.33, -9.97], - [33.36, -9.92], - [33.37, -9.9], - [33.36, -9.87], - [33.34, -9.83], - [33.3, -9.81], - [33.29, -9.8], - [33.28, -9.79], - [33.27, -9.78], - [33.25, -9.75], - [33.24, -9.74], - [33.22, -9.73], - [33.21, -9.71], - [33.2, -9.7], - [33.21, -9.69], - [33.22, -9.67], - [33.21, -9.65], - [33.2, -9.62], - [33.18, -9.6], - [33.1, -9.59], - [33.09, -9.61], - [33.08, -9.66], - [33.06, -9.65], - [33.05, -9.64], - [33.04, -9.62], - [33.01, -9.63], - [32.97, -9.6], - [32.99, -9.53], - [32.98, -9.5], - [32.97, -9.48], - [32.94, -9.49] + [33.67, -10.06], + [33.68, -10.07], + [33.69, -10.06] ], - "Mzimba": [ - [33.27, -11.42], - [33.28, -11.36], - [33.3, -11.35], - [33.37, -11.22], - [33.38, -11.19], - [33.39, -11.16], - [33.36, -11.11], - [33.34, -11.09], - [33.32, -11.06], - [33.3, -11.03], - [33.29, -11], - [33.31, -10.98], - [33.36, -11], - [33.39, -11.01], - [33.44, -11.02], - [33.45, -11.05], - [33.44, -11.08], - [33.45, -11.11], - [33.48, -11.09], - [33.5, -11.08], - [33.51, -11.06], - [33.52, -11.05], - [33.53, -11.03], - [33.54, -11.02], - [33.58, -11.03], - [33.59, -11.04], - [33.6, -11.05], - [33.62, -11.06], - [33.67, -11.05], - [33.69, -11.06], - [33.7, -11.08], - [33.71, -11.09], - [33.72, -11.08], - [33.75, -11.07], - [33.74, -11.04], - [33.75, -11.03], - [33.78, -11.02], - [33.82, -11.01], - [33.91, -11.03], - [33.93, -11.02], - [33.94, -10.98], - [33.95, -10.97], - [34.02, -11.02], - [34.03, -11.03], - [34.04, -11.05], - [34.06, -11.08], - [34.05, -11.15], - [34.02, -11.23], - [34.04, -11.27], - [34.05, -11.28], - [34.07, -11.37], - [34.08, -11.38], - [34.09, -11.39], - [34.1, -11.43], - [34.09, -11.46], - [34.06, -11.47], - [34.04, -11.46], - [34, -11.47], - [33.99, -11.48], - [33.98, -11.51], - [33.97, -11.52], - [33.96, -11.53], - [33.95, -11.54], - [33.89, -11.53], - [33.86, -11.54], - [33.84, -11.56], - [33.82, -11.57], - [33.81, -11.58], - [33.79, -11.59], - [33.78, -11.62], - [33.77, -11.67], - [33.78, -11.73], - [33.79, -11.75], - [33.8, -11.76], - [33.81, -11.78], - [33.82, -11.79], - [33.81, -11.85], - [33.8, -11.87], - [33.81, -11.91], - [33.82, -11.98], - [33.8, -12.03], - [33.79, -12.04], - [33.76, -12.05], - [33.74, -12.06], - [33.73, -12.07], - [33.72, -12.08], - [33.73, -12.11], - [33.75, -12.12], - [33.76, -12.13], - [33.77, -12.14], - [33.78, -12.2], - [33.76, -12.22], - [33.77, -12.27], - [33.78, -12.28], - [33.79, -12.29], - [33.83, -12.3], - [33.85, -12.31], - [33.86, -12.34], - [33.87, -12.35], - [33.89, -12.38], - [33.9, -12.41], - [33.91, -12.44], - [33.92, -12.45], - [33.93, -12.46], - [33.97, -12.47], - [34.01, -12.48], - [34.02, -12.49], - [34.08, -12.48], - [34.1, -12.49], - [34.11, -12.5], - [34.09, -12.52], - [34.08, -12.53], - [34.07, -12.55], - [34.06, -12.56], - [34.04, -12.57], - [34, -12.58], - [33.98, -12.59], - [33.97, -12.6], - [33.94, -12.61], - [33.91, -12.62], - [33.89, -12.63], - [33.86, -12.68], + "Kasungu": [ + [33.16, -13.35], + [33.15, -13.37], + [33.16, -13.39], + [33.15, -13.4], + [33.16, -13.42], + [33.17, -13.44], + [33.18, -13.46], + [33.19, -13.51], + [33.21, -13.52], + [33.22, -13.53], + [33.23, -13.54], + [33.24, -13.55], + [33.25, -13.56], + [33.26, -13.58], + [33.29, -13.59], + [33.3, -13.6], + [33.31, -13.62], + [33.34, -13.61], + [33.35, -13.6], + [33.36, -13.59], + [33.38, -13.58], + [33.37, -13.54], + [33.38, -13.52], + [33.37, -13.51], + [33.38, -13.5], + [33.39, -13.49], + [33.41, -13.48], + [33.42, -13.47], + [33.43, -13.46], + [33.44, -13.43], + [33.45, -13.42], + [33.46, -13.4], + [33.45, -13.39], + [33.46, -13.38], + [33.45, -13.37], + [33.46, -13.36], + [33.45, -13.34], + [33.46, -13.33], + [33.47, -13.31], + [33.48, -13.32], + [33.49, -13.33], + [33.5, -13.34], + [33.51, -13.33], + [33.53, -13.34], + [33.54, -13.33], + [33.53, -13.31], + [33.54, -13.32], + [33.55, -13.31], + [33.54, -13.3], + [33.55, -13.29], + [33.58, -13.28], + [33.59, -13.27], + [33.58, -13.24], + [33.6, -13.23], + [33.63, -13.24], + [33.64, -13.23], + [33.65, -13.22], + [33.66, -13.21], + [33.68, -13.2], + [33.69, -13.21], + [33.7, -13.2], + [33.71, -13.18], + [33.72, -13.17], + [33.73, -13.16], + [33.75, -13.15], + [33.76, -13.14], + [33.77, -13.12], + [33.78, -13.11], + [33.79, -13.1], + [33.8, -13.09], + [33.81, -13.1], + [33.82, -13.09], + [33.83, -13.08], + [33.82, -13.07], + [33.83, -13.06], + [33.84, -13.05], + [33.87, -13.04], + [33.89, -13.03], + [33.9, -13.02], + [33.92, -13.01], + [33.93, -13], + [33.94, -12.98], + [33.95, -12.97], + [33.96, -12.96], + [33.97, -12.95], + [33.98, -12.96], + [33.99, -12.95], + [34, -12.94], + [33.99, -12.92], + [33.98, -12.91], + [33.97, -12.9], + [33.96, -12.89], + [33.95, -12.88], + [33.94, -12.85], + [33.91, -12.84], + [33.9, -12.85], + [33.89, -12.84], + [33.84, -12.85], + [33.82, -12.84], + [33.81, -12.83], + [33.82, -12.82], + [33.81, -12.81], + [33.82, -12.8], + [33.83, -12.74], + [33.84, -12.73], + [33.83, -12.72], [33.84, -12.71], - [33.82, -12.72], - [33.78, -12.7], - [33.77, -12.69], + [33.8, -12.72], + [33.78, -12.71], + [33.77, -12.7], + [33.76, -12.69], [33.74, -12.7], - [33.73, -12.71], - [33.65, -12.7], - [33.64, -12.69], - [33.62, -12.66], - [33.61, -12.65], - [33.57, -12.64], - [33.58, -12.58], - [33.59, -12.57], + [33.72, -12.71], + [33.71, -12.72], + [33.69, -12.73], + [33.6, -12.69], + [33.59, -12.68], + [33.58, -12.69], + [33.57, -12.68], + [33.56, -12.64], + [33.55, -12.59], [33.58, -12.56], - [33.56, -12.53], - [33.57, -12.44], - [33.58, -12.42], - [33.59, -12.4], - [33.58, -12.39], - [33.53, -12.38], - [33.51, -12.37], - [33.53, -12.36], - [33.51, -12.33], - [33.46, -12.32], - [33.38, -12.34], - [33.35, -12.33], - [33.33, -12.3], - [33.31, -12.23], - [33.3, -12.2], - [33.29, -12.18], - [33.26, -12.16], - [33.25, -12.14], - [33.29, -11.98], - [33.3, -11.93], - [33.31, -11.91], - [33.3, -11.86], - [33.31, -11.81], - [33.3, -11.61], - [33.28, -11.58], - [33.22, -11.57], - [33.21, -11.56], - [33.23, -11.53], - [33.24, -11.4], - [33.27, -11.42] - ], - "Kasungu": [ + [33.57, -12.55], + [33.56, -12.54], + [33.55, -12.53], + [33.54, -12.49], + [33.55, -12.48], + [33.54, -12.47], + [33.53, -12.46], + [33.56, -12.45], + [33.59, -12.43], + [33.61, -12.37], + [33.55, -12.36], + [33.54, -12.38], + [33.53, -12.39], + [33.51, -12.4], + [33.5, -12.41], + [33.49, -12.42], + [33.48, -12.41], + [33.47, -12.42], + [33.48, -12.44], + [33.47, -12.46], + [33.46, -12.47], + [33.44, -12.48], + [33.43, -12.49], + [33.42, -12.5], + [33.41, -12.51], + [33.4, -12.53], + [33.39, -12.54], + [33.38, -12.55], + [33.37, -12.56], + [33.36, -12.55], + [33.35, -12.54], + [33.34, -12.55], [33.33, -12.54], - [33.35, -12.53], - [33.37, -12.52], - [33.39, -12.5], - [33.41, -12.48], - [33.42, -12.46], - [33.45, -12.45], - [33.46, -12.44], - [33.47, -12.41], - [33.49, -12.39], - [33.51, -12.37], - [33.53, -12.38], - [33.57, -12.39], - [33.59, -12.4], - [33.58, -12.41], - [33.57, -12.43], - [33.56, -12.44], - [33.58, -12.54], - [33.59, -12.57], - [33.58, -12.58], - [33.57, -12.59], - [33.58, -12.65], - [33.62, -12.66], - [33.64, -12.69], - [33.65, -12.7], - [33.66, -12.71], - [33.73, -12.7], - [33.75, -12.69], - [33.78, -12.7], - [33.8, -12.72], - [33.83, -12.71], - [33.82, -12.79], - [33.83, -12.84], - [33.84, -12.85], - [33.9, -12.84], - [33.93, -12.85], - [33.95, -12.87], - [33.96, -12.88], - [34, -12.92], - [33.99, -12.95], - [33.95, -12.98], - [33.94, -12.99], - [33.93, -13.01], - [33.92, -13.02], - [33.85, -13.06], - [33.83, -13.07], - [33.82, -13.09], - [33.81, -13.1], - [33.79, -13.11], - [33.78, -13.12], - [33.77, -13.13], - [33.76, -13.15], - [33.74, -13.17], - [33.73, -13.18], - [33.72, -13.19], - [33.71, -13.2], - [33.7, -13.21], - [33.66, -13.22], - [33.65, -13.23], - [33.6, -13.25], - [33.59, -13.27], - [33.58, -13.29], - [33.56, -13.3], - [33.55, -13.32], - [33.54, -13.33], - [33.53, -13.34], - [33.49, -13.33], - [33.48, -13.32], - [33.46, -13.33], - [33.47, -13.35], - [33.46, -13.4], - [33.45, -13.42], - [33.44, -13.45], - [33.42, -13.48], - [33.41, -13.49], - [33.4, -13.5], - [33.38, -13.52], - [33.39, -13.54], - [33.38, -13.58], - [33.35, -13.61], - [33.33, -13.63], - [33.29, -13.58], - [33.27, -13.57], - [33.26, -13.56], - [33.24, -13.54], - [33.21, -13.51], - [33.19, -13.49], - [33.18, -13.48], - [33.17, -13.45], - [33.16, -13.42], - [33.15, -13.4], - [33.16, -13.37], - [33.15, -13.35], - [33.14, -13.34], - [32.92, -13.35], - [32.94, -13.26], - [32.96, -13.22], - [33, -13.2], - [32.98, -13.17], - [32.97, -13.15], - [32.98, -13.01], - [33.01, -12.95], - [32.98, -12.87], - [32.95, -12.85], + [33.32, -12.53], + [33.3, -12.54], + [33.26, -12.55], + [33.27, -12.56], + [33.26, -12.57], + [33.25, -12.58], + [33.24, -12.59], + [33.23, -12.6], + [33.21, -12.61], + [33.2, -12.62], + [33.19, -12.63], + [33.18, -12.64], + [33.17, -12.61], + [33.16, -12.6], + [33.13, -12.61], + [33.1, -12.6], + [33.07, -12.61], + [33.05, -12.62], + [33.04, -12.63], + [33.03, -12.64], + [33.02, -12.65], + [33.01, -12.68], + [32.99, -12.73], + [32.97, -12.74], + [32.96, -12.75], + [32.95, -12.76], [32.94, -12.77], - [32.96, -12.73], - [32.99, -12.67], - [33.02, -12.61], - [33.04, -12.6], - [33.05, -12.59], - [33.06, -12.58], - [33.07, -12.59], - [33.08, -12.6], - [33.1, -12.59], - [33.12, -12.58], - [33.14, -12.59], - [33.16, -12.62], - [33.18, -12.61], - [33.19, -12.6], - [33.2, -12.59], - [33.23, -12.58], - [33.24, -12.54], - [33.26, -12.53], - [33.29, -12.52], - [33.3, -12.53], - [33.32, -12.54] + [32.95, -12.79], + [32.96, -12.83], + [32.95, -12.84], + [32.96, -12.86], + [32.97, -12.87], + [32.98, -12.88], + [32.99, -12.89], + [33.02, -12.9], + [33.03, -12.91], + [33.02, -12.93], + [33.01, -12.97], + [33.02, -12.98], + [33.01, -12.99], + [33, -13], + [32.99, -13.03], + [33, -13.05], + [32.99, -13.06], + [32.98, -13.08], + [32.97, -13.11], + [32.98, -13.12], + [32.99, -13.17], + [33, -13.18], + [33.01, -13.19], + [33.02, -13.21], + [33.01, -13.22], + [32.99, -13.23], + [32.98, -13.24], + [32.97, -13.25], + [32.96, -13.26], + [32.95, -13.27], + [32.94, -13.28], + [32.93, -13.31], + [32.99, -13.36], + [33, -13.37], + [33.02, -13.36], + [33.05, -13.35], + [33.1, -13.34], + [33.12, -13.35] ], - "Mchinji": [ - [32.71, -13.58], - [32.72, -13.57], - [32.75, -13.55], - [32.76, -13.54], - [32.81, -13.53], - [32.82, -13.51], - [32.83, -13.46], - [32.87, -13.44], - [32.89, -13.4], - [32.91, -13.35], - [33.14, -13.34], - [33.15, -13.35], - [33.16, -13.36], - [33.15, -13.39], - [33.16, -13.42], - [33.17, -13.45], - [33.18, -13.48], - [33.19, -13.49], - [33.21, -13.51], - [33.24, -13.54], - [33.26, -13.56], - [33.27, -13.57], - [33.29, -13.58], - [33.33, -13.63], - [33.32, -13.65], - [33.31, -13.66], - [33.3, -13.68], - [33.29, -13.7], - [33.28, -13.71], - [33.29, -13.73], - [33.28, -13.75], + "Likoma": [ + [34.59, -11.98], + [34.58, -11.99], + [34.57, -12], + [34.58, -12.03], + [34.59, -12.07], + [34.6, -12.08], + [34.64, -12.07], + [34.65, -12.06], + [34.66, -12.05], + [34.65, -11.99], + [34.64, -11.98], + [34.62, -11.97], + [34.6, -11.98], + [34.68, -12.09], + [34.69, -12.11], + [34.7, -12.12], + [34.71, -12.14], + [34.73, -12.13], + [34.75, -12.11], + [34.76, -12.1], + [34.77, -12.09], + [34.78, -12.08], + [34.79, -12.07], + [34.78, -12.02], + [34.77, -12.01], + [34.75, -12], + [34.71, -12.01], + [34.7, -12.02], + [34.69, -12.03], + [34.68, -12.06], + [34.67, -12.08], + [34.68, -12.09] + ], + "Lilongwe": [ + [34.09, -14.13], + [34.1, -14.11], + [34.11, -14.09], + [34.12, -14.08], + [34.13, -14.07], + [34.14, -14.06], + [34.13, -14.05], + [34.14, -14.04], + [34.15, -14.03], + [34.17, -14.02], + [34.18, -14], + [34.19, -13.98], + [34.2, -13.97], + [34.21, -13.94], + [34.2, -13.93], + [34.22, -13.94], + [34.23, -13.93], + [34.22, -13.92], + [34.23, -13.91], + [34.24, -13.9], + [34.27, -13.89], + [34.28, -13.88], + [34.27, -13.86], + [34.24, -13.87], + [34.22, -13.88], + [34.21, -13.89], + [34.2, -13.88], + [34.19, -13.87], + [34.2, -13.86], + [34.21, -13.85], + [34.22, -13.84], + [34.23, -13.83], + [34.24, -13.82], + [34.23, -13.8], + [34.22, -13.81], + [34.21, -13.82], + [34.2, -13.81], + [34.19, -13.8], + [34.17, -13.81], + [34.15, -13.82], + [34.14, -13.83], + [34.1, -13.84], + [34.09, -13.83], + [34.08, -13.84], + [34.07, -13.83], + [34.05, -13.84], + [34.04, -13.85], + [34.03, -13.84], + [34.02, -13.83], + [34.03, -13.82], + [34.02, -13.83], + [34.01, -13.81], + [34, -13.8], + [33.99, -13.79], + [33.95, -13.78], + [33.94, -13.77], + [33.93, -13.78], + [33.92, -13.77], + [33.87, -13.76], + [33.86, -13.77], + [33.85, -13.78], + [33.82, -13.77], + [33.81, -13.78], + [33.8, -13.77], + [33.77, -13.76], + [33.76, -13.75], + [33.75, -13.71], + [33.76, -13.69], + [33.75, -13.67], + [33.74, -13.68], + [33.71, -13.69], + [33.67, -13.7], + [33.61, -13.71], + [33.59, -13.72], + [33.58, -13.73], + [33.57, -13.72], + [33.56, -13.71], + [33.55, -13.72], + [33.51, -13.71], + [33.5, -13.7], + [33.49, -13.69], + [33.46, -13.68], + [33.45, -13.63], + [33.44, -13.59], + [33.45, -13.53], + [33.44, -13.5], + [33.42, -13.49], + [33.38, -13.5], + [33.37, -13.51], + [33.38, -13.52], + [33.37, -13.53], + [33.38, -13.54], + [33.37, -13.59], + [33.36, -13.6], + [33.34, -13.61], + [33.33, -13.62], + [33.32, -13.63], + [33.31, -13.64], + [33.3, -13.65], + [33.29, -13.68], + [33.28, -13.69], + [33.27, -13.71], + [33.28, -13.73], [33.27, -13.77], - [33.26, -13.81], - [33.25, -13.83], - [33.26, -13.86], + [33.26, -13.78], + [33.25, -13.82], + [33.26, -13.85], [33.27, -13.87], - [33.28, -13.88], - [33.29, -13.89], + [33.28, -13.89], [33.3, -13.9], + [33.31, -13.91], [33.32, -13.94], - [33.33, -13.97], - [33.34, -13.98], - [33.33, -14.02], - [33.34, -14.03], - [33.33, -14.1], + [33.33, -13.96], + [33.34, -13.97], + [33.35, -13.99], + [33.34, -14.02], + [33.33, -14.03], + [33.34, -14.05], + [33.35, -14.06], + [33.34, -14.1], + [33.33, -14.12], + [33.34, -14.15], [33.35, -14.16], [33.36, -14.21], - [33.35, -14.23], - [33.34, -14.22], - [33.32, -14.21], - [33.29, -14.16], - [33.28, -14.06], - [33.26, -14.04], - [33.2, -14.01], - [33.19, -13.99], - [33.15, -13.94], - [33.14, -13.92], - [33.13, -13.93], - [33.12, -13.96], - [33.08, -13.97], - [33.06, -13.98], - [33.05, -14], - [33.02, -14.05], - [32.98, -14.02], - [32.97, -14.01], - [32.98, -13.95], - [32.97, -13.94], - [32.96, -13.93], - [32.93, -13.91], - [32.92, -13.88], - [32.87, -13.82], - [32.86, -13.81], - [32.83, -13.8], - [32.79, -13.79], - [32.76, -13.78], - [32.77, -13.74], - [32.8, -13.72], - [32.81, -13.71], - [32.77, -13.65], - [32.74, -13.64], - [32.68, -13.63], - [32.66, -13.6], - [32.67, -13.58], - [32.68, -13.57], - [32.71, -13.58] - ], - "Nkhotakota": [ - [34.36, -12.2], - [34.38, -12.29], - [34.44, -12.5], - [34.49, -12.69], - [34.51, -12.8], - [34.52, -12.94], - [34.54, -13.06], - [34.55, -13.16], - [34.54, -13.24], - [34.55, -13.33], - [34.58, -13.4], - [34.24, -13.45], - [34.2, -13.47], - [34.16, -13.48], - [34.13, -13.49], - [34.12, -13.36], - [34.1, -13.28], - [34.11, -13.27], - [34.1, -13.17], - [34.09, -13.16], - [34.06, -13.15], - [34.02, -13.12], - [34.01, -13.13], - [34, -13.15], - [33.99, -13.16], - [33.98, -13.17], - [33.96, -13.16], - [33.95, -13.15], - [33.94, -13.1], - [33.93, -13.09], - [33.92, -13.07], - [33.93, -13.01], - [33.94, -12.99], - [33.95, -12.98], - [33.99, -12.95], - [34, -12.94], - [33.96, -12.88], - [33.95, -12.87], - [33.94, -12.85], - [33.92, -12.84], - [33.85, -12.85], - [33.83, -12.84], - [33.82, -12.83], - [33.84, -12.71], - [33.86, -12.68], - [33.88, -12.63], - [33.9, -12.62], - [33.94, -12.61], - [33.97, -12.6], - [33.98, -12.59], - [34, -12.58], - [34.01, -12.57], - [34.06, -12.56], - [34.07, -12.55], - [34.08, -12.53], - [34.09, -12.52], - [34.1, -12.5], - [34.09, -12.48], - [34.06, -12.49], - [34.01, -12.48], - [33.97, -12.47], - [33.96, -12.46], - [33.92, -12.45], - [33.91, -12.44], - [33.9, -12.43], - [33.89, -12.39], - [33.87, -12.35], - [33.86, -12.34], - [33.85, -12.31], - [33.83, -12.3], - [33.82, -12.29], - [33.78, -12.28], - [33.77, -12.27], - [33.76, -12.26], - [33.78, -12.2], - [33.84, -12.14], - [33.9, -12.16], - [33.91, -12.17], - [33.96, -12.19], - [34.03, -12.2] - ], - "Salima": [ - [34.58, -13.4], - [34.6, -13.42], - [34.61, -13.44], - [34.63, -13.47], - [34.64, -13.48], - [34.65, -13.5], - [34.86, -13.52], - [34.74, -14.08], - [34.55, -14.07], - [34.54, -14.08], - [34.53, -14.09], - [34.51, -14.11], - [34.47, -14.09], - [34.44, -14.05], - [34.4, -13.99], - [34.39, -13.97], - [34.33, -13.91], - [34.28, -13.85], - [34.21, -13.87], - [34.18, -13.86], - [34.19, -13.85], - [34.2, -13.84], - [34.21, -13.83], - [34.24, -13.82], - [34.25, -13.81], - [34.26, -13.77], - [34.29, -13.76], - [34.3, -13.75], - [34.31, -13.74], - [34.3, -13.73], - [34.29, -13.72], - [34.28, -13.71], - [34.29, -13.7], - [34.28, -13.68], - [34.27, -13.67], - [34.23, -13.69], - [34.19, -13.68], - [34.14, -13.64], - [34.13, -13.63], - [34.12, -13.62], - [34.13, -13.61], - [34.12, -13.5], - [34.13, -13.49], - [34.16, -13.48], - [34.18, -13.47], - [34.24, -13.45], - [34.33, -13.4] - ], - "Mangochi": [ - [34.86, -13.52], - [34.89, -13.53], - [35, -13.63], - [35.08, -13.7], - [35.17, -13.81], - [35.28, -13.93], - [35.37, -14.04], - [35.46, -14.14], - [35.52, -14.26], - [35.61, -14.37], - [35.71, -14.5], - [35.75, -14.54], - [35.72, -14.57], - [35.65, -14.58], - [35.6, -14.59], - [35.58, -14.6], - [35.56, -14.61], - [35.55, -14.62], - [35.54, -14.63], - [35.55, -14.67], - [35.54, -14.69], - [35.53, -14.71], - [35.51, -14.72], - [35.5, -14.73], - [35.47, -14.75], - [35.46, -14.76], - [35.37, -14.74], - [35.35, -14.73], - [35.34, -14.71], - [35.33, -14.7], - [35.31, -14.69], - [35.3, -14.68], - [35.28, -14.69], - [35.27, -14.71], - [35.28, -14.75], - [35, -14.76], - [34.96, -14.73], - [34.93, -14.72], - [34.91, -14.71], - [34.8, -14.55], - [34.77, -14.47], - [34.75, -14.4], - [34.74, -14.08], - [34.86, -13.52] + [33.38, -14.22], + [33.39, -14.24], + [33.4, -14.25], + [33.41, -14.27], + [33.42, -14.28], + [33.43, -14.31], + [33.44, -14.32], + [33.45, -14.33], + [33.46, -14.37], + [33.47, -14.38], + [33.48, -14.4], + [33.49, -14.41], + [33.5, -14.42], + [33.53, -14.43], + [33.55, -14.44], + [33.56, -14.46], + [33.57, -14.48], + [33.59, -14.49], + [33.6, -14.48], + [33.61, -14.49], + [33.62, -14.51], + [33.63, -14.53], + [33.62, -14.54], + [33.63, -14.57], + [33.64, -14.59], + [33.65, -14.6], + [33.66, -14.59], + [33.67, -14.58], + [33.66, -14.57], + [33.67, -14.54], + [33.68, -14.52], + [33.69, -14.51], + [33.7, -14.44], + [33.71, -14.42], + [33.72, -14.39], + [33.76, -14.38], + [33.78, -14.37], + [33.79, -14.36], + [33.8, -14.37], + [33.81, -14.34], + [33.82, -14.33], + [33.83, -14.32], + [33.84, -14.31], + [33.85, -14.32], + [33.86, -14.33], + [33.87, -14.32], + [33.89, -14.31], + [33.94, -14.3], + [33.95, -14.29], + [33.94, -14.27], + [33.95, -14.26], + [33.96, -14.22], + [33.95, -14.21], + [33.98, -14.2], + [33.99, -14.19], + [34, -14.2], + [34.01, -14.21], + [34.02, -14.2], + [34.03, -14.19], + [34.05, -14.18], + [34.06, -14.16], + [34.07, -14.14], + [34.09, -14.13] ], "Machinga": [ - [35.75, -14.54], - [35.79, -14.59], - [35.84, -14.64], - [35.85, -14.65], - [35.86, -14.88], - [35.87, -14.89], - [35.84, -15.04], - [35.79, -15.15], - [35.78, -15.17], - [35.79, -15.21], - [35.51, -15.22], [35.5, -15.23], - [35.47, -15.24], - [35.37, -15.22], - [35.35, -15.21], - [35.33, -15.22], - [35.31, -15.24], - [35.3, -15.25], - [35.27, -15.24], - [35.24, -15.23], - [35.23, -15.24], - [35.21, -15.25], - [35.2, -15.26], - [35.19, -15.25], - [35.17, -15.23], - [35.18, -15.22], - [35.19, -15.21], - [35.21, -15.15], - [35.23, -15.09], - [35.24, -15.05], - [35.27, -14.99], - [35.29, -14.98], - [35.3, -14.97], - [35.31, -14.95], - [35.32, -14.87], - [35.31, -14.83], - [35.3, -14.78], - [35.28, -14.76], + [35.51, -15.22], + [35.52, -15.21], + [35.8, -15.2], + [35.79, -15.17], + [35.87, -15], + [35.88, -14.98], + [35.92, -14.9], + [35.87, -14.68], + [35.86, -14.66], + [35.8, -14.6], + [35.77, -14.55], + [35.76, -14.56], + [35.75, -14.57], + [35.74, -14.59], + [35.71, -14.6], + [35.69, -14.59], + [35.66, -14.58], + [35.65, -14.59], + [35.63, -14.6], + [35.61, -14.59], + [35.6, -14.6], + [35.59, -14.61], + [35.57, -14.62], + [35.56, -14.64], + [35.55, -14.65], + [35.56, -14.68], + [35.55, -14.69], + [35.56, -14.7], + [35.55, -14.72], + [35.54, -14.73], + [35.53, -14.74], + [35.52, -14.73], + [35.51, -14.74], + [35.5, -14.75], + [35.49, -14.77], + [35.48, -14.78], + [35.47, -14.79], + [35.46, -14.8], + [35.44, -14.79], + [35.43, -14.78], + [35.41, -14.79], + [35.4, -14.78], + [35.39, -14.77], + [35.36, -14.76], + [35.35, -14.75], + [35.34, -14.74], + [35.33, -14.72], + [35.32, -14.71], + [35.31, -14.7], + [35.29, -14.71], + [35.28, -14.72], [35.27, -14.73], - [35.28, -14.7], - [35.29, -14.68], - [35.31, -14.69], - [35.33, -14.7], - [35.34, -14.71], - [35.35, -14.73], - [35.36, -14.74], - [35.43, -14.76], - [35.47, -14.75], - [35.5, -14.73], - [35.51, -14.72], - [35.52, -14.71], - [35.54, -14.69], - [35.55, -14.68], - [35.54, -14.63], - [35.55, -14.62], - [35.56, -14.61], - [35.58, -14.6], - [35.6, -14.59], - [35.65, -14.58], - [35.67, -14.57], - [35.75, -14.54] + [35.28, -14.74], + [35.29, -14.81], + [35.3, -14.86], + [35.29, -14.88], + [35.28, -14.93], + [35.27, -14.95], + [35.28, -14.97], + [35.26, -14.98], + [35.25, -14.99], + [35.24, -15], + [35.23, -15.01], + [35.22, -15.03], + [35.21, -15.07], + [35.2, -15.12], + [35.19, -15.13], + [35.18, -15.14], + [35.17, -15.17], + [35.16, -15.2], + [35.17, -15.22], + [35.18, -15.23], + [35.19, -15.25], + [35.21, -15.24], + [35.22, -15.23], + [35.23, -15.22], + [35.24, -15.23], + [35.26, -15.24], + [35.3, -15.25], + [35.31, -15.24], + [35.3, -15.23], + [35.31, -15.22], + [35.32, -15.21], + [35.34, -15.2], + [35.42, -15.23], + [35.43, -15.24], + [35.44, -15.23], + [35.45, -15.24], + [35.46, -15.23] ], - "Dedza": [ - [33.66, -14.61], - [33.64, -14.6], - [33.63, -14.59], - [33.62, -14.58], - [33.64, -14.55], - [33.65, -14.53], - [33.69, -14.49], - [33.7, -14.42], - [33.71, -14.4], - [33.72, -14.39], - [33.73, -14.38], - [33.8, -14.35], - [33.81, -14.34], - [33.82, -14.33], - [33.84, -14.31], - [33.91, -14.3], - [33.92, -14.29], - [33.94, -14.28], - [33.95, -14.27], - [33.96, -14.21], - [33.98, -14.19], - [34.02, -14.18], - [34.04, -14.17], - [34.05, -14.16], - [34.06, -14.14], - [34.08, -14.13], - [34.09, -14.11], - [34.1, -14.08], - [34.11, -14.07], - [34.12, -14.06], - [34.13, -14.04], - [34.15, -14.03], - [34.16, -14.01], - [34.17, -14], - [34.2, -13.95], - [34.21, -13.92], - [34.22, -13.91], - [34.25, -13.9], - [34.27, -13.88], - [34.28, -13.85], - [34.33, -13.91], - [34.39, -13.97], - [34.4, -13.99], - [34.44, -14.05], - [34.47, -14.09], - [34.48, -14.11], - [34.53, -14.09], - [34.54, -14.08], - [34.55, -14.07], - [34.74, -14.08], - [34.75, -14.26], - [34.67, -14.35], - [34.59, -14.41], - [34.54, -14.43], - [34.5, -14.42], - [34.48, -14.41], - [34.46, -14.4], - [34.41, -14.39], - [34.4, -14.4], - [34.38, -14.41], - [34.37, -14.4], - [34.34, -14.39], - [34.32, -14.4], - [34.3, -14.41], - [34.29, -14.4], - [34.18, -14.44], - [34.08, -14.45], - [34.07, -14.46], - [34.06, -14.49], - [34.05, -14.5], - [33.95, -14.48], - [33.89, -14.49], - [33.83, -14.52], - [33.8, -14.53], - [33.72, -14.49], - [33.7, -14.5], - [33.68, -14.52], - [33.67, -14.6], - [33.66, -14.61] + "Mangochi": [ + [34.82, -13.97], + [34.83, -13.98], + [34.84, -13.99], + [34.85, -14], + [34.84, -13.99], + [34.83, -13.97], + [34.82, -14.02], + [34.81, -14.01], + [34.82, -14.02], + [35.17, -14.37], + [35.16, -14.34], + [35.15, -14.33], + [35.14, -14.31], + [35.13, -14.3], + [35.11, -14.29], + [35.1, -14.28], + [35.09, -14.27], + [35.08, -14.25], + [35.07, -14.21], + [35.06, -14.2], + [35.04, -14.19], + [35.03, -14.18], + [35.04, -14.19], + [35.03, -14.18], + [35, -14.17], + [34.99, -14.16], + [34.98, -14.17], + [34.95, -14.16], + [34.94, -14.15], + [34.93, -14.14], + [34.92, -14.07], + [34.91, -14.06], + [34.92, -14.05], + [34.91, -14.04], + [34.9, -14.03], + [34.89, -14.02], + [34.88, -14.01], + [34.87, -14], + [34.85, -14.01], + [34.84, -14.02], + [34.83, -14.03], + [34.82, -14.04], + [34.83, -14.05], + [34.84, -14.06], + [34.85, -14.07], + [34.86, -14.09], + [34.87, -14.11], + [34.86, -14.12], + [34.83, -14.13], + [34.82, -14.14], + [34.81, -14.15], + [34.82, -14.19], + [34.81, -14.22], + [34.8, -14.25], + [34.79, -14.26], + [34.78, -14.27], + [34.76, -14.28], + [34.74, -14.29], + [34.73, -14.31], + [34.72, -14.33], + [34.74, -14.37], + [34.75, -14.38], + [34.74, -14.45], + [34.75, -14.47], + [34.76, -14.49], + [34.77, -14.5], + [34.78, -14.51], + [34.8, -14.59], + [34.86, -14.65], + [34.89, -14.68], + [34.93, -14.71], + [34.92, -14.72], + [34.93, -14.74], + [34.96, -14.75], + [34.97, -14.77], + [35.28, -14.78], + [35.27, -14.74], + [35.28, -14.73], + [35.29, -14.72], + [35.3, -14.7], + [35.31, -14.71], + [35.33, -14.72], + [35.34, -14.73], + [35.35, -14.74], + [35.36, -14.75], + [35.37, -14.77], + [35.4, -14.78], + [35.41, -14.79], + [35.42, -14.78], + [35.43, -14.79], + [35.44, -14.8], + [35.46, -14.79], + [35.48, -14.78], + [35.49, -14.77], + [35.5, -14.76], + [35.51, -14.75], + [35.52, -14.74], + [35.53, -14.73], + [35.54, -14.74], + [35.55, -14.73], + [35.56, -14.72], + [35.55, -14.7], + [35.56, -14.69], + [35.55, -14.67], + [35.56, -14.65], + [35.57, -14.64], + [35.58, -14.61], + [35.6, -14.6], + [35.61, -14.59], + [35.62, -14.6], + [35.63, -14.59], + [35.65, -14.58], + [35.66, -14.59], + [35.7, -14.6], + [35.71, -14.59], + [35.75, -14.58], + [35.76, -14.57], + [35.77, -14.56], + [35.71, -14.48], + [35.62, -14.37], + [35.61, -14.36], + [35.52, -14.26], + [35.49, -14.17], + [35.39, -14.06], + [35.36, -14.03], + [35.23, -13.88], + [35.16, -13.79], + [35.09, -13.7], + [35, -13.61], + [34.93, -13.55], + [34.87, -13.48], + [34.86, -13.52], + [34.87, -13.53], + [34.86, -13.54], + [34.85, -13.55], + [34.86, -13.56], + [34.85, -13.57], + [34.86, -13.58], + [34.85, -13.59], + [34.86, -13.62], + [34.85, -13.63], + [34.86, -13.64], + [34.85, -13.65], + [34.86, -13.66], + [34.85, -13.67], + [34.84, -13.68], + [34.85, -13.69], + [34.84, -13.7], + [34.85, -13.71], + [34.86, -13.72], + [34.87, -13.73], + [34.9, -13.74], + [34.91, -13.73], + [35.06, -13.74], + [35.07, -13.75], + [35.08, -13.78], + [35.09, -13.82], + [35.08, -13.83], + [35.09, -13.84], + [35.1, -13.85], + [35.11, -13.86], + [35.12, -13.89], + [35.13, -13.93], + [35.12, -13.95], + [35.11, -13.96], + [35.12, -13.97], + [35.14, -13.98], + [35.15, -14], + [35.16, -14.02], + [35.17, -14.03], + [35.18, -14.04], + [35.19, -14.08], + [35.18, -14.09], + [35.19, -14.13], + [35.2, -14.15], + [35.19, -14.16], + [35.2, -14.17], + [35.21, -14.18], + [35.22, -14.19], + [35.23, -14.21], + [35.22, -14.22], + [35.23, -14.24], + [35.24, -14.26], + [35.25, -14.27], + [35.26, -14.29], + [35.27, -14.31], + [35.28, -14.32], + [35.29, -14.34], + [35.3, -14.35], + [35.29, -14.36], + [35.3, -14.37], + [35.28, -14.38], + [35.27, -14.39], + [35.26, -14.4], + [35.25, -14.41], + [35.24, -14.42], + [35.23, -14.43], + [35.22, -14.41], + [35.23, -14.4], + [35.22, -14.39], + [35.21, -14.38], + [35.2, -14.37] ], - "Lilongwe": [ - [33.62, -14.56], - [33.6, -14.52], - [33.58, -14.5], - [33.56, -14.49], - [33.55, -14.48], - [33.54, -14.47], - [33.53, -14.46], - [33.51, -14.43], - [33.47, -14.41], - [33.46, -14.4], - [33.44, -14.38], - [33.39, -14.28], - [33.37, -14.26], - [33.36, -14.23], - [33.35, -14.16], - [33.33, -14.12], - [33.34, -14.07], - [33.33, -14.02], - [33.34, -14.01], - [33.33, -13.97], - [33.32, -13.94], - [33.3, -13.9], - [33.29, -13.89], - [33.28, -13.88], - [33.27, -13.87], - [33.26, -13.86], + "Mchinji": [ + [33.26, -13.85], [33.25, -13.84], [33.26, -13.82], - [33.27, -13.8], + [33.27, -13.77], [33.28, -13.76], - [33.29, -13.73], - [33.28, -13.72], - [33.29, -13.7], - [33.3, -13.69], - [33.31, -13.67], - [33.32, -13.65], - [33.33, -13.64], - [33.35, -13.61], - [33.38, -13.58], - [33.39, -13.57], - [33.38, -13.53], - [33.39, -13.5], - [33.41, -13.49], - [33.42, -13.48], - [33.44, -13.49], - [33.45, -13.5], - [33.44, -13.55], - [33.46, -13.64], - [33.47, -13.67], - [33.48, -13.68], - [33.52, -13.7], - [33.74, -13.66], - [33.76, -13.67], - [33.77, -13.71], - [33.79, -13.76], - [33.97, -13.77], - [33.99, -13.78], - [34.01, -13.79], - [34.02, -13.8], - [34.03, -13.81], - [34.05, -13.82], - [34.12, -13.81], - [34.15, -13.8], - [34.16, -13.79], - [34.21, -13.8], - [34.25, -13.78], - [34.24, -13.82], - [34.21, -13.83], - [34.2, -13.84], - [34.19, -13.85], - [34.18, -13.86], - [34.19, -13.87], - [34.25, -13.85], - [34.27, -13.88], - [34.25, -13.9], - [34.22, -13.91], - [34.21, -13.92], - [34.2, -13.93], - [34.17, -14], - [34.16, -14.01], - [34.15, -14.03], - [34.13, -14.04], - [34.12, -14.06], - [34.11, -14.07], - [34.1, -14.08], - [34.09, -14.11], - [34.08, -14.13], - [34.06, -14.14], - [34.05, -14.16], - [34.04, -14.17], - [34.03, -14.18], - [33.98, -14.19], - [33.96, -14.2], - [33.95, -14.22], - [33.94, -14.28], - [33.93, -14.29], - [33.91, -14.3], - [33.88, -14.31], - [33.82, -14.33], - [33.81, -14.34], - [33.8, -14.35], - [33.73, -14.38], - [33.72, -14.39], - [33.71, -14.4], - [33.7, -14.41], - [33.69, -14.44], - [33.66, -14.53], - [33.64, -14.54], - [33.62, -14.56] + [33.27, -13.73], + [33.28, -13.71], + [33.29, -13.69], + [33.3, -13.68], + [33.31, -13.65], + [33.32, -13.64], + [33.33, -13.62], + [33.3, -13.61], + [33.29, -13.6], + [33.28, -13.58], + [33.25, -13.57], + [33.24, -13.55], + [33.23, -13.54], + [33.22, -13.53], + [33.21, -13.52], + [33.19, -13.51], + [33.18, -13.5], + [33.17, -13.46], + [33.16, -13.44], + [33.15, -13.41], + [33.16, -13.4], + [33.15, -13.39], + [33.16, -13.36], + [33.15, -13.35], + [33.11, -13.34], + [33.1, -13.35], + [33.05, -13.36], + [33.02, -13.37], + [33, -13.36], + [32.93, -13.38], + [32.92, -13.39], + [32.91, -13.42], + [32.9, -13.43], + [32.89, -13.45], + [32.88, -13.46], + [32.87, -13.47], + [32.86, -13.46], + [32.85, -13.47], + [32.84, -13.5], + [32.85, -13.51], + [32.84, -13.52], + [32.83, -13.53], + [32.82, -13.54], + [32.8, -13.55], + [32.78, -13.56], + [32.76, -13.57], + [32.75, -13.58], + [32.74, -13.59], + [32.73, -13.58], + [32.71, -13.57], + [32.7, -13.58], + [32.68, -13.59], + [32.69, -13.6], + [32.68, -13.61], + [32.67, -13.62], + [32.69, -13.63], + [32.7, -13.64], + [32.72, -13.65], + [32.75, -13.64], + [32.78, -13.65], + [32.8, -13.66], + [32.81, -13.68], + [32.82, -13.69], + [32.83, -13.7], + [32.84, -13.71], + [32.85, -13.72], + [32.84, -13.73], + [32.8, -13.74], + [32.79, -13.75], + [32.78, -13.76], + [32.77, -13.78], + [32.78, -13.79], + [32.79, -13.78], + [32.8, -13.79], + [32.81, -13.8], + [32.82, -13.79], + [32.85, -13.8], + [32.88, -13.81], + [32.89, -13.82], + [32.9, -13.83], + [32.91, -13.86], + [32.92, -13.87], + [32.93, -13.88], + [32.95, -13.89], + [32.94, -13.95], + [32.95, -13.94], + [32.99, -13.95], + [33, -13.96], + [32.99, -14.01], + [33, -14.02], + [33.01, -14.03], + [33.03, -14.04], + [33.04, -14.05], + [33.05, -14.04], + [33.06, -14.03], + [33.07, -13.99], + [33.08, -13.98], + [33.09, -13.97], + [33.1, -13.96], + [33.14, -13.95], + [33.15, -13.94], + [33.16, -13.95], + [33.18, -13.96], + [33.19, -13.97], + [33.2, -13.99], + [33.21, -14], + [33.25, -14.01], + [33.26, -14.02], + [33.27, -14.03], + [33.28, -14.02], + [33.29, -14.03], + [33.3, -14.04], + [33.31, -14.05], + [33.3, -14.06], + [33.31, -14.07], + [33.32, -14.08], + [33.31, -14.09], + [33.3, -14.11], + [33.31, -14.12], + [33.3, -14.13], + [33.31, -14.15], + [33.32, -14.16], + [33.33, -14.18], + [33.34, -14.19], + [33.33, -14.2], + [33.34, -14.21], + [33.35, -14.22], + [33.36, -14.21], + [33.35, -14.2], + [33.34, -14.16], + [33.33, -14.15], + [33.34, -14.12], + [33.35, -14.1], + [33.34, -14.06], + [33.33, -14.04], + [33.34, -14.02], + [33.35, -14.01], + [33.34, -13.99], + [33.33, -13.97], + [33.32, -13.96], + [33.31, -13.94], + [33.3, -13.91], + [33.29, -13.89], + [33.27, -13.88], + [33.26, -13.87] ], - "Nsanje": [ - [35.03, -16.82], - [35, -16.81], - [34.98, -16.79], - [34.96, -16.77], - [34.95, -16.76], - [34.93, -16.75], - [34.91, -16.74], - [34.9, -16.73], - [34.89, -16.71], - [34.92, -16.66], - [34.93, -16.64], - [34.95, -16.63], - [34.97, -16.62], - [34.98, -16.57], - [35.03, -16.51], - [35.05, -16.49], - [35.06, -16.48], - [35.1, -16.33], - [35.15, -16.39], - [35.17, -16.4], - [35.19, -16.38], - [35.24, -16.4], - [35.23, -16.41], - [35.21, -16.48], - [35.14, -16.53], - [35.13, -16.54], - [35.15, -16.58], - [35.16, -16.61], - [35.17, -16.62], - [35.19, -16.63], - [35.22, -16.64], - [35.23, -16.65], - [35.24, -16.66], - [35.25, -16.67], - [35.28, -16.7], - [35.29, -16.79], - [35.31, -16.83], - [35.29, -16.87], - [35.28, -16.89], - [35.29, -16.93], - [35.28, -16.94], - [35.27, -16.95], - [35.28, -16.96], - [35.31, -16.97], - [35.3, -17.01], - [35.31, -17.07], - [35.3, -17.1], - [35.29, -17.13], - [35.23, -17.14], - [35.13, -17.13], - [35.08, -17.12], - [35.07, -17.11], - [35.04, -17.04], - [35.07, -16.99], - [35.09, -16.98], - [35.11, -16.96], - [35.13, -16.93], - [35.12, -16.83], - [35.1, -16.82] + "Mulanje": [ + [35.67, -16.1], + [35.68, -16.11], + [35.69, -16.1], + [35.71, -16.09], + [35.73, -16.08], + [35.75, -16.07], + [35.76, -16.08], + [35.77, -16.07], + [35.78, -16.06], + [35.79, -16.05], + [35.8, -16.04], + [35.81, -16.03], + [35.82, -16.02], + [35.81, -16], + [35.8, -15.93], + [35.76, -15.92], + [35.77, -15.9], + [35.76, -15.89], + [35.74, -15.87], + [35.72, -15.86], + [35.71, -15.85], + [35.69, -15.84], + [35.68, -15.83], + [35.61, -15.85], + [35.65, -15.89], + [35.6, -15.86], + [35.58, -15.88], + [35.57, -15.86], + [35.56, -15.85], + [35.55, -15.84], + [35.54, -15.83], + [35.53, -15.82], + [35.52, -15.81], + [35.51, -15.7], + [35.5, -15.69], + [35.51, -15.67], + [35.52, -15.66], + [35.53, -15.64], + [35.54, -15.62], + [35.53, -15.61], + [35.52, -15.6], + [35.51, -15.61], + [35.49, -15.62], + [35.48, -15.63], + [35.47, -15.65], + [35.46, -15.66], + [35.45, -15.67], + [35.42, -15.68], + [35.41, -15.67], + [35.4, -15.66], + [35.39, -15.67], + [35.38, -15.68], + [35.31, -15.71], + [35.3, -15.74], + [35.31, -15.77], + [35.32, -15.87], + [35.33, -15.96], + [35.32, -15.97], + [35.31, -15.98], + [35.32, -16], + [35.31, -16.02], + [35.32, -16.04], + [35.31, -16.05], + [35.32, -16.06], + [35.33, -16.07], + [35.32, -16.08], + [35.33, -16.1], + [35.32, -16.13], + [35.31, -16.14], + [35.3, -16.15], + [35.29, -16.16], + [35.28, -16.18], + [35.29, -16.19], + [35.3, -16.2], + [35.31, -16.21], + [35.32, -16.2], + [35.33, -16.19], + [35.35, -16.18], + [35.36, -16.17], + [35.37, -16.16], + [35.38, -16.15], + [35.4, -16.14], + [35.41, -16.13], + [35.42, -16.12], + [35.43, -16.11], + [35.44, -16.12], + [35.45, -16.11], + [35.46, -16.12], + [35.49, -16.13], + [35.5, -16.15], + [35.51, -16.16], + [35.52, -16.17], + [35.53, -16.16], + [35.54, -16.15], + [35.55, -16.14], + [35.56, -16.13], + [35.58, -16.12], + [35.59, -16.13], + [35.61, -16.12], + [35.62, -16.13], + [35.63, -16.12], + [35.64, -16.11], + [35.65, -16.1] ], - "Chikwawa": [ - [34.89, -16.7], - [34.88, -16.69], - [34.84, -16.68], - [34.83, -16.66], - [34.82, -16.63], - [34.77, -16.59], - [34.76, -16.58], - [34.74, -16.54], - [34.73, -16.53], - [34.67, -16.5], - [34.66, -16.49], - [34.64, -16.46], - [34.63, -16.44], - [34.6, -16.42], - [34.59, -16.41], - [34.58, -16.39], - [34.55, -16.32], - [34.52, -16.3], - [34.48, -16.29], - [34.43, -16.27], - [34.39, -16.19], - [34.41, -16.09], - [34.4, -16.06], - [34.39, -16.04], - [34.3, -15.95], - [34.29, -15.94], - [34.26, -15.93], - [34.24, -15.92], - [34.23, -15.89], - [34.24, -15.82], - [34.25, -15.79], - [34.28, -15.76], - [34.29, -15.75], - [34.31, -15.74], - [34.34, -15.73], + "Mwanza": [ + [34.51, -15.48], + [34.5, -15.47], + [34.51, -15.46], + [34.5, -15.45], + [34.49, -15.43], + [34.5, -15.42], + [34.49, -15.41], + [34.48, -15.42], + [34.47, -15.43], + [34.45, -15.42], + [34.44, -15.43], + [34.43, -15.47], + [34.44, -15.52], + [34.45, -15.59], + [34.46, -15.61], + [34.44, -15.62], + [34.43, -15.63], + [34.44, -15.66], + [34.42, -15.67], + [34.41, -15.68], + [34.4, -15.69], + [34.39, -15.68], + [34.38, -15.71], + [34.37, -15.73], [34.36, -15.74], - [34.5, -15.79], - [34.54, -15.81], - [34.85, -15.82], - [34.87, -15.83], - [34.88, -15.85], - [34.86, -15.89], - [34.85, -15.96], - [34.86, -15.97], - [34.88, -15.98], - [34.89, -16.03], - [34.95, -16.12], - [35.08, -16.26], - [35.1, -16.33], + [34.4, -15.76], + [34.43, -15.77], + [34.46, -15.79], + [34.49, -15.8], + [34.51, -15.81], + [34.73, -15.82], + [34.72, -15.81], + [34.7, -15.8], + [34.69, -15.79], + [34.68, -15.78], + [34.69, -15.77], + [34.68, -15.76], + [34.67, -15.75], + [34.66, -15.74], + [34.65, -15.73], + [34.64, -15.72], + [34.63, -15.71], + [34.62, -15.7], + [34.61, -15.69], + [34.6, -15.68], + [34.59, -15.66], + [34.58, -15.64], + [34.59, -15.63], + [34.58, -15.62], + [34.57, -15.58], + [34.56, -15.56], + [34.55, -15.55], + [34.54, -15.53], + [34.53, -15.5], + [34.52, -15.49], + [34.51, -15.48] + ], + "Mzimba": [ + [33.93, -11], + [33.92, -11.02], + [33.93, -11.03], + [33.91, -11.04], + [33.9, -11.03], + [33.89, -11.04], + [33.88, -11.03], + [33.87, -11.04], + [33.86, -11.03], + [33.82, -11.02], + [33.8, -11.03], + [33.79, -11.02], + [33.78, -11.03], + [33.74, -11.04], + [33.73, -11.05], + [33.74, -11.06], + [33.73, -11.09], + [33.72, -11.1], + [33.7, -11.11], + [33.69, -11.1], + [33.68, -11.08], + [33.67, -11.07], + [33.66, -11.06], + [33.65, -11.07], + [33.58, -11.06], + [33.57, -11.05], + [33.56, -11.04], + [33.55, -11.03], + [33.53, -11.04], + [33.52, -11.05], + [33.51, -11.06], + [33.5, -11.08], + [33.49, -11.09], + [33.48, -11.1], + [33.47, -11.11], + [33.46, -11.12], + [33.45, -11.13], + [33.43, -11.12], + [33.44, -11.11], + [33.43, -11.07], + [33.44, -11.06], + [33.43, -11.04], + [33.42, -11.03], + [33.4, -11.04], + [33.38, -11.03], + [33.37, -11.02], + [33.34, -11.01], + [33.32, -11], + [33.31, -11.01], + [33.32, -11.03], + [33.33, -11.05], + [33.34, -11.07], + [33.35, -11.08], + [33.36, -11.09], + [33.37, -11.1], + [33.38, -11.12], + [33.39, -11.14], + [33.4, -11.15], + [33.39, -11.18], + [33.38, -11.21], + [33.37, -11.24], + [33.36, -11.25], + [33.35, -11.26], + [33.34, -11.29], + [33.33, -11.31], + [33.32, -11.32], + [33.31, -11.33], + [33.3, -11.37], + [33.29, -11.38], + [33.28, -11.44], + [33.27, -11.43], + [33.26, -11.42], + [33.24, -11.41], + [33.23, -11.42], + [33.24, -11.44], + [33.25, -11.45], + [33.24, -11.46], + [33.23, -11.48], + [33.24, -11.49], + [33.25, -11.5], + [33.24, -11.54], + [33.23, -11.55], + [33.24, -11.59], + [33.25, -11.58], + [33.29, -11.59], + [33.31, -11.6], + [33.32, -11.61], + [33.31, -11.66], + [33.32, -11.69], + [33.31, -11.7], + [33.32, -11.71], + [33.31, -11.72], + [33.32, -11.73], + [33.33, -11.76], + [33.32, -11.77], + [33.33, -11.78], + [33.32, -11.84], + [33.31, -11.85], + [33.32, -11.88], + [33.31, -11.95], + [33.3, -12.02], + [33.29, -12.03], + [33.28, -12.06], + [33.27, -12.07], + [33.26, -12.11], + [33.27, -12.15], + [33.28, -12.16], + [33.29, -12.17], + [33.31, -12.18], + [33.32, -12.26], + [33.33, -12.27], + [33.34, -12.28], + [33.35, -12.3], + [33.36, -12.31], + [33.37, -12.32], + [33.38, -12.35], + [33.39, -12.34], + [33.44, -12.33], + [33.49, -12.34], + [33.54, -12.35], + [33.55, -12.36], + [33.56, -12.37], + [33.59, -12.42], + [33.57, -12.45], + [33.55, -12.46], + [33.53, -12.47], + [33.54, -12.48], + [33.55, -12.49], + [33.56, -12.53], + [33.57, -12.55], + [33.58, -12.56], + [33.55, -12.59], + [33.56, -12.64], + [33.57, -12.68], + [33.58, -12.69], + [33.59, -12.68], + [33.6, -12.69], + [33.66, -12.73], + [33.7, -12.72], + [33.71, -12.71], + [33.72, -12.7], + [33.74, -12.69], + [33.77, -12.68], + [33.78, -12.7], + [33.79, -12.72], + [33.8, -12.71], + [33.85, -12.7], + [33.86, -12.69], + [33.87, -12.67], + [33.88, -12.66], + [33.89, -12.65], + [33.9, -12.64], + [33.91, -12.63], + [33.92, -12.64], + [33.93, -12.63], + [33.92, -12.62], + [33.97, -12.61], + [33.98, -12.6], + [33.99, -12.59], + [34, -12.58], + [34.03, -12.57], + [34.04, -12.58], + [34.06, -12.57], + [34.07, -12.56], + [34.06, -12.57], + [34.07, -12.56], + [34.06, -12.54], + [34.07, -12.53], + [34.08, -12.52], + [34.1, -12.51], + [34.09, -12.5], + [34.08, -12.49], + [34.07, -12.5], + [34.06, -12.51], + [34.04, -12.52], + [34.03, -12.51], + [34.02, -12.52], + [34.01, -12.51], + [33.99, -12.5], + [33.98, -12.49], + [33.97, -12.48], + [33.95, -12.47], + [33.94, -12.48], + [33.93, -12.49], + [33.91, -12.48], + [33.9, -12.47], + [33.89, -12.46], + [33.88, -12.42], + [33.89, -12.4], + [33.88, -12.36], + [33.87, -12.35], + [33.86, -12.34], + [33.87, -12.33], + [33.86, -12.32], + [33.83, -12.31], + [33.79, -12.3], + [33.78, -12.29], + [33.77, -12.3], + [33.76, -12.29], + [33.75, -12.25], + [33.76, -12.24], + [33.75, -12.23], + [33.76, -12.22], + [33.78, -12.21], + [33.79, -12.2], + [33.8, -12.19], + [33.82, -12.18], + [33.83, -12.17], + [33.81, -12.16], + [33.8, -12.17], + [33.78, -12.18], + [33.77, -12.17], + [33.76, -12.16], + [33.75, -12.17], + [33.74, -12.16], + [33.73, -12.15], + [33.72, -12.14], + [33.71, -12.13], + [33.7, -12.12], + [33.69, -12.11], + [33.71, -12.1], + [33.72, -12.09], + [33.73, -12.08], + [33.76, -12.07], + [33.78, -12.06], + [33.79, -12.05], + [33.8, -12.04], + [33.81, -12.03], + [33.83, -12.02], + [33.85, -12.01], + [33.83, -12], + [33.82, -11.99], + [33.8, -11.98], + [33.79, -11.97], + [33.8, -11.96], + [33.81, -11.95], + [33.8, -11.94], + [33.79, -11.92], + [33.78, -11.9], + [33.79, -11.89], + [33.8, -11.88], + [33.81, -11.84], + [33.82, -11.83], + [33.81, -11.81], + [33.8, -11.8], + [33.79, -11.79], + [33.8, -11.77], + [33.79, -11.76], + [33.77, -11.75], + [33.75, -11.74], + [33.76, -11.73], + [33.75, -11.68], + [33.74, -11.67], + [33.75, -11.65], + [33.76, -11.64], + [33.77, -11.63], + [33.78, -11.61], + [33.79, -11.6], + [33.8, -11.59], + [33.81, -11.58], + [33.83, -11.57], + [33.84, -11.56], + [33.85, -11.55], + [33.86, -11.54], + [33.87, -11.53], + [33.88, -11.54], + [33.91, -11.55], + [33.93, -11.56], + [33.94, -11.55], + [33.95, -11.54], + [33.96, -11.53], + [33.97, -11.51], + [33.98, -11.48], + [33.99, -11.47], + [34, -11.46], + [34.02, -11.47], + [34.04, -11.48], + [34.05, -11.47], + [34.06, -11.46], + [34.07, -11.47], + [34.08, -11.46], + [34.09, -11.47], + [34.1, -11.46], + [34.09, -11.44], + [34.08, -11.39], + [34.07, -11.38], + [34.06, -11.39], + [34.05, -11.38], + [34.04, -11.36], + [34.03, -11.27], + [34.02, -11.26], + [34.01, -11.22], + [34.02, -11.21], + [34.03, -11.18], + [34.04, -11.17], + [34.05, -11.15], + [34.06, -11.12], + [34.05, -11.11], + [34.06, -11.1], + [34.05, -11.08], + [34.04, -11.05], + [34.03, -11.04], + [34.02, -11.03], + [34.01, -11.02], + [34, -11.01], + [33.99, -11], + [33.98, -10.99], + [33.97, -10.98], + [33.96, -10.97], + [33.95, -10.96], + [33.94, -10.97], + [33.93, -10.99], + [33.94, -11] + ], + "Nkhata Bay": [ + [34.24, -11.12], + [34.23, -11.11], + [34.22, -11.09], + [34.21, -11.02], + [34.22, -11.01], + [34.21, -10.97], + [34.2, -10.98], + [34.19, -11], + [34.18, -11.01], + [34.16, -11.02], + [34.14, -11.03], + [34.12, -11.04], + [34.11, -11.05], + [34.1, -11.06], + [34.08, -11.07], + [34.07, -11.08], + [34.06, -11.09], + [34.05, -11.1], + [34.06, -11.12], + [34.05, -11.13], + [34.04, -11.15], + [34.03, -11.18], + [34.02, -11.19], + [34.01, -11.21], + [34.02, -11.22], + [34.03, -11.26], + [34.04, -11.27], + [34.05, -11.36], + [34.06, -11.39], + [34.07, -11.38], + [34.08, -11.39], + [34.09, -11.4], + [34.1, -11.44], + [34.09, -11.46], + [34.08, -11.47], + [34.07, -11.46], + [34.06, -11.47], + [34.05, -11.48], + [34.04, -11.47], + [34, -11.46], + [33.99, -11.47], + [33.98, -11.48], + [33.97, -11.49], + [33.96, -11.51], + [33.95, -11.54], + [33.94, -11.55], + [33.93, -11.56], + [33.92, -11.55], + [33.91, -11.54], + [33.87, -11.53], + [33.86, -11.54], + [33.85, -11.55], + [33.84, -11.56], + [33.83, -11.57], + [33.82, -11.58], + [33.8, -11.59], + [33.79, -11.6], + [33.78, -11.61], + [33.77, -11.62], + [33.78, -11.63], + [33.76, -11.64], + [33.75, -11.65], + [33.74, -11.66], + [33.75, -11.67], + [33.76, -11.68], + [33.75, -11.73], + [33.76, -11.75], + [33.77, -11.76], + [33.79, -11.77], + [33.8, -11.8], + [33.81, -11.81], + [33.82, -11.82], + [33.81, -11.83], + [33.8, -11.84], + [33.79, -11.88], + [33.78, -11.89], + [33.79, -11.9], + [33.8, -11.92], + [33.81, -11.95], + [33.8, -11.96], + [33.79, -11.97], + [33.8, -11.98], + [33.81, -11.99], + [33.82, -12], + [33.83, -12.01], + [33.85, -12.02], + [33.83, -12.03], + [33.8, -12.04], + [33.79, -12.05], + [33.78, -12.06], + [33.77, -12.07], + [33.75, -12.08], + [33.73, -12.07], + [33.72, -12.08], + [33.71, -12.1], + [33.7, -12.11], + [33.69, -12.12], + [33.7, -12.13], + [33.72, -12.14], + [33.73, -12.15], + [33.74, -12.16], + [33.75, -12.17], + [33.76, -12.16], + [33.77, -12.17], + [33.78, -12.18], + [33.79, -12.17], + [33.81, -12.16], + [33.82, -12.17], + [33.84, -12.16], + [33.85, -12.17], + [33.86, -12.16], + [33.85, -12.17], + [33.86, -12.16], + [33.87, -12.17], + [33.88, -12.19], + [33.9, -12.2], + [33.91, -12.21], + [33.94, -12.22], + [33.96, -12.23], + [33.97, -12.22], + [33.98, -12.23], + [33.99, -12.22], + [34, -12.23], + [34.01, -12.24], + [34.02, -12.23], + [34.03, -12.19], + [34.04, -12.15], + [34.05, -12.11], + [34.06, -12.1], + [34.05, -12.05], + [34.06, -12.04], + [34.05, -12.03], + [34.06, -12.02], + [34.07, -12.01], + [34.08, -12], + [34.09, -11.98], + [34.1, -11.97], + [34.11, -11.96], + [34.12, -11.95], + [34.14, -11.94], + [34.16, -11.93], + [34.18, -11.92], + [34.17, -11.91], + [34.18, -11.87], + [34.17, -11.86], + [34.18, -11.85], + [34.19, -11.81], + [34.2, -11.8], + [34.22, -11.79], + [34.24, -11.78], + [34.25, -11.77], + [34.26, -11.75], + [34.27, -11.74], + [34.29, -11.73], + [34.3, -11.72], + [34.31, -11.71], + [34.32, -11.7], + [34.33, -11.68], + [34.32, -11.66], + [34.31, -11.65], + [34.3, -11.62], + [34.31, -11.61], + [34.3, -11.6], + [34.29, -11.56], + [34.28, -11.54], + [34.27, -11.52], + [34.28, -11.51], + [34.27, -11.5], + [34.28, -11.49], + [34.27, -11.46], + [34.28, -11.45], + [34.27, -11.44], + [34.28, -11.43], + [34.27, -11.42], + [34.28, -11.4], + [34.27, -11.39], + [34.26, -11.37], + [34.25, -11.32], + [34.24, -11.31], + [34.23, -11.3], + [34.22, -11.29], + [34.23, -11.25], + [34.22, -11.23], + [34.21, -11.22], + [34.22, -11.15], + [34.23, -11.14], + [34.24, -11.13], + [34.23, -11.12] + ], + "Nkhotakota": [ + [34.13, -13.5], + [34.15, -13.49], + [34.19, -13.48], + [34.2, -13.47], + [34.24, -13.46], + [34.25, -13.45], + [34.27, -13.46], + [34.28, -13.45], + [34.29, -13.44], + [34.31, -13.43], + [34.32, -13.42], + [34.31, -13.4], + [34.3, -13.38], + [34.31, -13.37], + [34.3, -13.36], + [34.31, -13.32], + [34.32, -13.31], + [34.33, -13.3], + [34.34, -13.29], + [34.35, -13.27], + [34.34, -13.26], + [34.35, -13.25], + [34.34, -13.24], + [34.35, -13.23], + [34.34, -13.22], + [34.33, -13.19], + [34.34, -13.18], + [34.33, -13.15], + [34.34, -13.14], + [34.33, -13.13], + [34.32, -13.09], + [34.33, -13.08], + [34.32, -13.07], + [34.33, -13.06], + [34.32, -12.99], + [34.31, -12.98], + [34.3, -12.95], + [34.29, -12.87], + [34.28, -12.86], + [34.27, -12.85], + [34.26, -12.84], + [34.27, -12.8], + [34.28, -12.79], + [34.27, -12.78], + [34.28, -12.76], + [34.27, -12.75], + [34.25, -12.74], + [34.24, -12.73], + [34.23, -12.72], + [34.22, -12.71], + [34.21, -12.7], + [34.2, -12.69], + [34.19, -12.68], + [34.18, -12.66], + [34.17, -12.61], + [34.18, -12.57], + [34.19, -12.55], + [34.2, -12.54], + [34.19, -12.51], + [34.2, -12.5], + [34.19, -12.49], + [34.18, -12.48], + [34.17, -12.42], + [34.16, -12.41], + [34.15, -12.4], + [34.11, -12.39], + [34.09, -12.38], + [34.08, -12.37], + [34.07, -12.36], + [34.06, -12.35], + [34.05, -12.34], + [34.04, -12.32], + [34.03, -12.3], + [34.02, -12.27], + [34.01, -12.24], + [34, -12.23], + [33.99, -12.22], + [33.98, -12.23], + [33.97, -12.22], + [33.96, -12.23], + [33.95, -12.22], + [33.94, -12.21], + [33.91, -12.22], + [33.9, -12.2], + [33.89, -12.19], + [33.87, -12.18], + [33.86, -12.16], + [33.85, -12.17], + [33.86, -12.16], + [33.85, -12.17], + [33.84, -12.16], + [33.83, -12.17], + [33.82, -12.18], + [33.81, -12.19], + [33.8, -12.2], + [33.79, -12.21], + [33.77, -12.22], + [33.76, -12.23], + [33.75, -12.24], + [33.76, -12.25], + [33.77, -12.3], + [33.78, -12.29], + [33.79, -12.3], + [33.8, -12.31], + [33.83, -12.32], + [33.86, -12.33], + [33.87, -12.35], + [33.88, -12.36], + [33.89, -12.37], + [33.88, -12.41], + [33.89, -12.42], + [33.9, -12.46], + [33.91, -12.47], + [33.92, -12.48], + [33.91, -12.49], + [33.93, -12.48], + [33.94, -12.47], + [33.95, -12.48], + [33.97, -12.49], + [33.98, -12.5], + [33.99, -12.51], + [34.02, -12.52], + [34.03, -12.51], + [34.04, -12.52], + [34.05, -12.51], + [34.06, -12.5], + [34.07, -12.49], + [34.09, -12.5], + [34.1, -12.51], + [34.09, -12.52], + [34.07, -12.53], + [34.06, -12.54], + [34.07, -12.55], + [34.06, -12.56], + [34.07, -12.57], + [34.06, -12.58], + [34.03, -12.57], + [34.02, -12.58], + [34, -12.59], + [33.98, -12.6], + [33.97, -12.61], + [33.96, -12.62], + [33.93, -12.63], + [33.92, -12.64], + [33.91, -12.63], + [33.9, -12.64], + [33.89, -12.65], + [33.88, -12.66], + [33.87, -12.67], + [33.86, -12.68], + [33.85, -12.69], + [33.84, -12.71], + [33.83, -12.72], + [33.84, -12.73], + [33.83, -12.74], + [33.82, -12.75], + [33.81, -12.8], + [33.82, -12.81], + [33.81, -12.83], + [33.82, -12.84], + [33.83, -12.85], + [33.84, -12.84], + [33.9, -12.85], + [33.91, -12.84], + [33.92, -12.85], + [33.95, -12.86], + [33.96, -12.88], + [33.97, -12.89], + [33.98, -12.9], + [33.99, -12.91], + [33.98, -12.92], + [34, -12.93], + [33.99, -12.95], + [33.98, -12.96], + [33.97, -12.95], + [33.96, -12.96], + [33.95, -12.97], + [33.94, -12.98], + [33.93, -12.99], + [33.92, -13.01], + [33.91, -13.03], + [33.92, -13.07], + [33.93, -13.11], + [33.94, -13.12], + [33.95, -13.13], + [33.96, -13.14], + [33.95, -13.15], + [33.94, -13.17], + [33.95, -13.18], + [33.96, -13.17], + [33.97, -13.18], + [33.98, -13.17], + [33.99, -13.18], + [34, -13.16], + [33.99, -13.15], + [34, -13.14], + [34.01, -13.13], + [34.04, -13.12], + [34.06, -13.13], + [34.05, -13.14], + [34.06, -13.18], + [34.07, -13.17], + [34.08, -13.16], + [34.11, -13.26], + [34.1, -13.27], + [34.09, -13.28], + [34.1, -13.3], + [34.11, -13.34], + [34.12, -13.35], + [34.11, -13.36], + [34.12, -13.42], + [34.13, -13.5] + ], + "Nneno": [ + [34.49, -15.41], + [34.5, -15.42], + [34.49, -15.43], + [34.5, -15.44], + [34.51, -15.46], + [34.5, -15.47], + [34.51, -15.48], + [34.52, -15.49], + [34.53, -15.5], + [34.54, -15.51], + [34.55, -15.53], + [34.56, -15.55], + [34.57, -15.56], + [34.58, -15.58], + [34.59, -15.63], + [34.58, -15.64], + [34.59, -15.65], + [34.6, -15.66], + [34.61, -15.68], + [34.62, -15.69], + [34.63, -15.7], + [34.62, -15.71], + [34.64, -15.72], + [34.65, -15.73], + [34.66, -15.74], + [34.67, -15.75], + [34.68, -15.76], + [34.69, -15.77], + [34.68, -15.78], + [34.69, -15.79], + [34.7, -15.8], + [34.71, -15.81], + [34.73, -15.82], + [34.74, -15.81], + [34.73, -15.74], + [34.72, -15.71], + [34.73, -15.69], + [34.74, -15.68], + [34.76, -15.67], + [34.75, -15.62], + [34.76, -15.58], + [34.77, -15.57], + [34.78, -15.56], + [34.79, -15.55], + [34.8, -15.54], + [34.81, -15.53], + [34.83, -15.52], + [34.84, -15.5], + [34.85, -15.49], + [34.86, -15.48], + [34.87, -15.46], + [34.86, -15.45], + [34.87, -15.44], + [34.88, -15.43], + [34.89, -15.41], + [34.9, -15.39], + [34.91, -15.38], + [34.92, -15.37], + [34.93, -15.36], + [34.95, -15.35], + [34.98, -15.36], + [34.99, -15.35], + [35, -15.34], + [35.01, -15.33], + [35.04, -15.32], + [34.81, -15.33], + [34.8, -15.32], + [34.81, -15.31], + [34.8, -15.29], + [34.79, -15.27], + [34.78, -15.26], + [34.79, -15.25], + [34.78, -15.26], + [34.77, -15.25], + [34.71, -15.24], + [34.69, -15.23], + [34.68, -15.24], + [34.67, -15.23], + [34.64, -15.22], + [34.63, -15.23], + [34.62, -15.22], + [34.61, -15.21], + [34.59, -15.22], + [34.6, -15.23], + [34.59, -15.29], + [34.58, -15.3], + [34.57, -15.31], + [34.58, -15.32], + [34.57, -15.33], + [34.56, -15.34], + [34.55, -15.33], + [34.53, -15.34], + [34.52, -15.35], + [34.51, -15.4], + [34.52, -15.41] + ], + "Nsanje": [ + [35.24, -16.4], + [35.22, -16.39], + [35.21, -16.38], + [35.2, -16.37], + [35.16, -16.36], + [35.15, -16.35], + [35.14, -16.33], + [35.12, -16.32], + [35.11, -16.31], + [35.1, -16.32], + [35.09, -16.34], + [35.1, -16.35], + [35.09, -16.36], + [35.08, -16.4], + [35.07, -16.43], [35.06, -16.48], - [35.05, -16.49], - [35.03, -16.51], + [35.05, -16.5], + [35.04, -16.51], + [35.03, -16.52], + [35.02, -16.53], + [35.01, -16.54], + [35, -16.55], + [34.99, -16.56], [34.98, -16.57], [34.97, -16.58], + [34.98, -16.59], + [34.97, -16.6], + [34.98, -16.61], + [34.97, -16.62], [34.96, -16.63], - [34.93, -16.64], + [34.94, -16.64], + [34.93, -16.65], [34.92, -16.66], - [34.89, -16.69] - ], - "Mwanza": [ - [34.34, -15.73], - [34.4, -15.65], - [34.42, -15.62], - [34.54, -15.59], - [34.66, -15.6], - [34.76, -15.61], - [34.77, -15.67], - [34.76, -15.68], - [34.75, -15.69], - [34.74, -15.7], - [34.75, -15.81], - [34.5, -15.79], - [34.36, -15.74], - [34.34, -15.73] - ], - "Neno": [ - [34.42, -15.58], - [34.41, -15.51], - [34.42, -15.46], - [34.46, -15.42], - [34.48, -15.41], - [34.49, -15.4], - [34.5, -15.36], - [34.51, -15.35], - [34.52, -15.34], - [34.53, -15.33], - [34.55, -15.32], - [34.57, -15.3], - [34.56, -15.2], - [34.62, -15.21], - [34.68, -15.23], - [34.77, -15.24], - [34.78, -15.25], - [34.81, -15.26], - [34.82, -15.28], - [34.83, -15.33], - [34.84, -15.31], - [35.05, -15.32], - [35.01, -15.35], - [34.99, -15.36], - [34.95, -15.37], - [34.92, -15.39], - [34.89, -15.42], - [34.86, -15.52], - [34.84, -15.55], - [34.78, -15.58], - [34.77, -15.59], - [34.76, -15.61], - [34.66, -15.6], - [34.54, -15.59], - [34.42, -15.58] + [34.91, -16.67], + [34.9, -16.68], + [34.89, -16.69], + [34.91, -16.7], + [34.92, -16.72], + [34.93, -16.75], + [34.94, -16.74], + [34.97, -16.75], + [34.99, -16.76], + [35, -16.79], + [35.01, -16.8], + [35.02, -16.81], + [35.04, -16.82], + [35.05, -16.83], + [35.06, -16.84], + [35.07, -16.83], + [35.08, -16.82], + [35.09, -16.83], + [35.1, -16.82], + [35.14, -16.83], + [35.15, -16.84], + [35.16, -16.85], + [35.15, -16.86], + [35.16, -16.89], + [35.17, -16.92], + [35.16, -16.94], + [35.15, -16.95], + [35.14, -16.96], + [35.13, -16.97], + [35.12, -16.98], + [35.1, -16.99], + [35.09, -16.98], + [35.08, -16.99], + [35.06, -17], + [35.05, -17.01], + [35.06, -17.02], + [35.07, -17.05], + [35.08, -17.07], + [35.09, -17.06], + [35.08, -17.07], + [35.09, -17.08], + [35.1, -17.09], + [35.09, -17.1], + [35.08, -17.11], + [35.09, -17.12], + [35.1, -17.13], + [35.31, -17.12], + [35.3, -17.11], + [35.31, -17.1], + [35.3, -17.09], + [35.31, -17.08], + [35.3, -17.06], + [35.29, -17.04], + [35.3, -17.03], + [35.29, -17.01], + [35.3, -17], + [35.31, -16.98], + [35.3, -16.97], + [35.29, -16.96], + [35.28, -16.97], + [35.27, -16.96], + [35.26, -16.95], + [35.27, -16.94], + [35.28, -16.91], + [35.29, -16.9], + [35.27, -16.89], + [35.28, -16.88], + [35.29, -16.87], + [35.3, -16.86], + [35.31, -16.85], + [35.3, -16.84], + [35.31, -16.83], + [35.3, -16.81], + [35.29, -16.8], + [35.3, -16.77], + [35.29, -16.76], + [35.28, -16.75], + [35.29, -16.74], + [35.28, -16.73], + [35.29, -16.72], + [35.28, -16.71], + [35.27, -16.7], + [35.26, -16.69], + [35.25, -16.68], + [35.24, -16.67], + [35.23, -16.66], + [35.22, -16.65], + [35.21, -16.64], + [35.19, -16.63], + [35.18, -16.62], + [35.17, -16.61], + [35.16, -16.6], + [35.15, -16.59], + [35.14, -16.57], + [35.15, -16.56], + [35.16, -16.55], + [35.17, -16.54], + [35.18, -16.53], + [35.19, -16.52], + [35.21, -16.51], + [35.22, -16.5], + [35.23, -16.49], + [35.25, -16.48], + [35.26, -16.47], + [35.27, -16.44], + [35.26, -16.43], + [35.25, -16.41], + [35.24, -16.4] ], "Ntcheu": [ - [34.56, -15.2], - [34.55, -15.12], - [34.56, -15.1], - [34.55, -15.07], - [34.57, -15.02], - [34.58, -15], - [34.57, -14.95], - [34.56, -14.94], - [34.55, -14.92], - [34.54, -14.8], - [34.53, -14.77], - [34.52, -14.73], - [34.51, -14.7], - [34.52, -14.64], - [34.5, -14.58], - [34.45, -14.53], - [34.43, -14.5], - [34.39, -14.43], - [34.38, -14.41], - [34.39, -14.4], - [34.41, -14.39], - [34.44, -14.4], - [34.47, -14.41], - [34.5, -14.42], - [34.51, -14.43], - [34.59, -14.41], - [34.67, -14.35], - [34.75, -14.3], - [34.77, -14.47], - [34.8, -14.55], - [34.91, -14.71], - [34.93, -14.72], - [34.96, -14.73], - [34.99, -14.76], - [34.97, -14.88], - [34.92, -14.96], - [34.91, -14.97], - [34.92, -14.98], - [34.84, -15.31], - [34.83, -15.33], + [34.81, -15.33], [34.82, -15.32], - [34.81, -15.27], - [34.8, -15.25], - [34.77, -15.24], - [34.73, -15.23], - [34.62, -15.21], - [34.57, -15.2] + [34.83, -15.31], + [34.84, -15.28], + [34.83, -15.27], + [34.84, -15.25], + [34.85, -15.23], + [34.84, -15.22], + [34.86, -15.13], + [34.89, -15.02], + [34.9, -15], + [34.91, -14.94], + [34.93, -14.88], + [34.94, -14.85], + [34.95, -14.86], + [34.96, -14.85], + [34.97, -14.81], + [34.96, -14.76], + [34.95, -14.74], + [34.92, -14.73], + [34.93, -14.71], + [34.89, -14.68], + [34.86, -14.65], + [34.8, -14.59], + [34.78, -14.57], + [34.79, -14.51], + [34.78, -14.5], + [34.77, -14.49], + [34.75, -14.47], + [34.74, -14.46], + [34.75, -14.44], + [34.74, -14.37], + [34.72, -14.34], + [34.61, -14.41], + [34.59, -14.43], + [34.58, -14.44], + [34.56, -14.43], + [34.55, -14.44], + [34.52, -14.43], + [34.51, -14.42], + [34.5, -14.43], + [34.47, -14.42], + [34.45, -14.41], + [34.44, -14.42], + [34.42, -14.41], + [34.4, -14.42], + [34.41, -14.43], + [34.42, -14.44], + [34.43, -14.45], + [34.44, -14.46], + [34.45, -14.48], + [34.46, -14.51], + [34.47, -14.52], + [34.48, -14.53], + [34.49, -14.54], + [34.5, -14.55], + [34.52, -14.56], + [34.53, -14.57], + [34.54, -14.59], + [34.55, -14.64], + [34.54, -14.66], + [34.53, -14.68], + [34.52, -14.69], + [34.53, -14.7], + [34.54, -14.72], + [34.55, -14.75], + [34.56, -14.76], + [34.57, -14.77], + [34.58, -14.8], + [34.57, -14.82], + [34.58, -14.84], + [34.57, -14.88], + [34.58, -14.91], + [34.59, -14.93], + [34.6, -14.96], + [34.61, -14.98], + [34.62, -14.99], + [34.61, -15.02], + [34.6, -15.03], + [34.59, -15.05], + [34.58, -15.06], + [34.57, -15.07], + [34.58, -15.09], + [34.59, -15.1], + [34.58, -15.11], + [34.57, -15.12], + [34.58, -15.13], + [34.57, -15.15], + [34.58, -15.16], + [34.59, -15.21], + [34.61, -15.22], + [34.63, -15.23], + [34.64, -15.22], + [34.65, -15.23], + [34.67, -15.24], + [34.68, -15.23], + [34.69, -15.24], + [34.71, -15.25], + [34.78, -15.26], + [34.79, -15.25], + [34.78, -15.26], + [34.79, -15.27], + [34.8, -15.28], + [34.81, -15.29], + [34.8, -15.32], + [34.81, -15.33] ], - "Zomba": [ - [35.79, -15.21], - [35.81, -15.3], - [35.84, -15.42], - [35.72, -15.46], - [35.69, -15.47], - [35.66, -15.49], - [35.65, -15.5], - [35.62, -15.52], - [35.57, -15.56], - [35.55, -15.57], - [35.54, -15.58], - [35.53, -15.61], - [35.5, -15.62], - [35.49, -15.63], - [35.47, -15.66], - [35.46, -15.67], - [35.38, -15.68], - [35.3, -15.67], - [35.28, -15.66], - [35.27, -15.65], - [35.26, -15.63], - [35.25, -15.62], - [35.24, -15.6], - [35.23, -15.58], - [35.21, -15.57], - [35.19, -15.56], - [35.18, -15.53], - [35.16, -15.54], - [35.12, -15.53], - [35.11, -15.52], - [35.12, -15.51], - [35.14, -15.49], - [35.13, -15.47], - [35.09, -15.45], - [35.05, -15.41], - [35.03, -15.39], - [35.01, -15.35], - [35.05, -15.32], - [35.09, -15.31], - [35.11, -15.3], - [35.13, -15.27], - [35.17, -15.23], - [35.18, -15.25], - [35.19, -15.26], - [35.21, -15.25], - [35.22, -15.24], - [35.24, -15.23], - [35.26, -15.24], - [35.29, -15.25], - [35.31, -15.24], - [35.32, -15.22], - [35.34, -15.21], - [35.37, -15.22], - [35.42, -15.24], - [35.49, -15.23], - [35.51, -15.22], - [35.52, -15.21] + "Ntchisi": [ + [33.62, -13.29], + [33.65, -13.3], + [33.66, -13.31], + [33.67, -13.32], + [33.68, -13.33], + [33.7, -13.34], + [33.71, -13.35], + [33.72, -13.36], + [33.73, -13.39], + [33.74, -13.42], + [33.73, -13.45], + [33.74, -13.46], + [33.75, -13.52], + [33.76, -13.53], + [33.77, -13.52], + [33.78, -13.51], + [33.8, -13.52], + [33.83, -13.51], + [33.84, -13.5], + [33.9, -13.49], + [33.93, -13.48], + [33.94, -13.49], + [33.95, -13.51], + [33.96, -13.52], + [33.97, -13.51], + [34, -13.5], + [34.02, -13.51], + [34.03, -13.5], + [34.04, -13.51], + [34.03, -13.52], + [34.04, -13.53], + [34.06, -13.54], + [34.07, -13.53], + [34.08, -13.54], + [34.09, -13.53], + [34.1, -13.52], + [34.11, -13.51], + [34.12, -13.5], + [34.11, -13.37], + [34.12, -13.36], + [34.11, -13.34], + [34.1, -13.32], + [34.09, -13.3], + [34.1, -13.27], + [34.11, -13.26], + [34.09, -13.16], + [34.08, -13.17], + [34.07, -13.18], + [34.05, -13.17], + [34.06, -13.13], + [34.05, -13.12], + [34.04, -13.13], + [34.01, -13.12], + [34, -13.13], + [33.99, -13.15], + [34, -13.16], + [33.99, -13.17], + [33.98, -13.18], + [33.97, -13.17], + [33.95, -13.18], + [33.94, -13.17], + [33.95, -13.16], + [33.96, -13.14], + [33.95, -13.13], + [33.94, -13.12], + [33.93, -13.11], + [33.92, -13.1], + [33.91, -13.07], + [33.92, -13.03], + [33.91, -13.02], + [33.89, -13.03], + [33.88, -13.04], + [33.87, -13.05], + [33.83, -13.06], + [33.82, -13.07], + [33.83, -13.08], + [33.82, -13.09], + [33.81, -13.1], + [33.8, -13.09], + [33.79, -13.1], + [33.78, -13.11], + [33.77, -13.12], + [33.76, -13.13], + [33.75, -13.15], + [33.74, -13.16], + [33.73, -13.17], + [33.72, -13.18], + [33.7, -13.19], + [33.69, -13.21], + [33.68, -13.2], + [33.67, -13.21], + [33.66, -13.22], + [33.64, -13.23], + [33.63, -13.24], + [33.62, -13.23], + [33.61, -13.24], + [33.62, -13.25], + [33.61, -13.26], + [33.62, -13.27] ], "Phalombe": [ - [35.84, -15.46], - [35.83, -15.54], - [35.82, -15.66], - [35.81, -15.9], - [35.8, -15.93], - [35.76, -15.94], - [35.72, -15.93], - [35.7, -15.92], - [35.68, -15.9], - [35.67, -15.89], - [35.64, -15.9], - [35.6, -15.94], - [35.57, -15.85], - [35.55, -15.84], - [35.54, -15.83], - [35.52, -15.81], - [35.51, -15.7], - [35.5, -15.69], - [35.51, -15.66], - [35.52, -15.65], - [35.53, -15.64], - [35.54, -15.62], - [35.53, -15.61], - [35.54, -15.58], - [35.55, -15.57], - [35.56, -15.56], - [35.62, -15.52], - [35.65, -15.5], - [35.66, -15.49], - [35.69, -15.47], - [35.72, -15.46] - ], - "Mulanje": [ - [35.8, -15.93], - [35.79, -15.96], - [35.8, -16], - [35.79, -16.02], - [35.77, -16.06], - [35.7, -16.11], - [35.55, -16.14], - [35.52, -16.15], - [35.51, -16.17], - [35.49, -16.16], - [35.47, -16.14], - [35.46, -16.13], - [35.44, -16.12], - [35.39, -16.13], - [35.37, -16.14], - [35.3, -16.2], - [35.28, -16.19], - [35.29, -16.16], - [35.3, -16.15], - [35.31, -16.13], - [35.32, -16.1], - [35.31, -16.01], - [35.32, -15.97], - [35.33, -15.96], - [35.32, -15.78], - [35.34, -15.68], - [35.39, -15.67], - [35.47, -15.66], - [35.49, -15.63], - [35.5, -15.62], + [35.66, -15.46], + [35.65, -15.47], + [35.64, -15.48], + [35.63, -15.49], + [35.62, -15.5], + [35.61, -15.52], + [35.6, -15.53], + [35.58, -15.54], + [35.56, -15.55], + [35.55, -15.56], + [35.54, -15.55], + [35.53, -15.56], + [35.54, -15.57], + [35.53, -15.58], + [35.52, -15.6], [35.53, -15.61], [35.54, -15.62], [35.53, -15.63], [35.52, -15.64], [35.51, -15.66], - [35.5, -15.68], + [35.5, -15.67], [35.51, -15.69], - [35.52, -15.79], - [35.53, -15.83], - [35.54, -15.84], - [35.55, -15.85], - [35.6, -15.93], - [35.64, -15.9], - [35.67, -15.89], - [35.68, -15.9], - [35.7, -15.92], - [35.71, -15.93], - [35.73, -15.94], - [35.76, -15.93] + [35.52, -15.7], + [35.53, -15.82], + [35.54, -15.83], + [35.55, -15.84], + [35.56, -15.85], + [35.57, -15.86], + [35.58, -15.87], + [35.6, -15.86], + [35.64, -15.89], + [35.61, -15.85], + [35.63, -15.83], + [35.68, -15.84], + [35.69, -15.85], + [35.72, -15.86], + [35.74, -15.87], + [35.75, -15.89], + [35.77, -15.9], + [35.76, -15.91], + [35.77, -15.93], + [35.82, -15.88], + [35.83, -15.73], + [35.84, -15.58], + [35.85, -15.52], + [35.84, -15.45], + [35.66, -15.46] ], - "Thyolo": [ - [35.3, -16.21], - [35.28, -16.23], - [35.26, -16.27], - [35.25, -16.32], - [35.27, -16.36], - [35.26, -16.37], - [35.24, -16.39], - [35.19, -16.38], - [35.17, -16.39], - [35.1, -16.33], - [35.08, -16.29], - [34.95, -16.12], - [34.89, -16.03], - [34.92, -16.02], - [34.93, -16.01], - [34.95, -15.99], - [34.96, -15.98], - [34.98, -15.95], - [34.99, -15.94], - [35, -15.93], - [35.04, -15.92], - [35.15, -15.86], - [35.2, -15.87], - [35.21, -15.88], - [35.25, -15.92], - [35.26, -15.93], - [35.27, -15.96], - [35.28, -15.98], - [35.29, -15.99], - [35.31, -16.01], - [35.32, -16.1], - [35.31, -16.13], - [35.3, -16.14], - [35.29, -16.16], - [35.28, -16.17], - [35.29, -16.2], - [35.3, -16.21] + "Rumphi": [ + [33.71, -10.57], + [33.7, -10.58], + [33.69, -10.59], + [33.68, -10.61], + [33.67, -10.62], + [33.65, -10.63], + [33.64, -10.64], + [33.63, -10.65], + [33.62, -10.66], + [33.61, -10.65], + [33.6, -10.66], + [33.59, -10.67], + [33.58, -10.68], + [33.57, -10.7], + [33.56, -10.71], + [33.55, -10.73], + [33.54, -10.74], + [33.53, -10.75], + [33.52, -10.77], + [33.51, -10.78], + [33.5, -10.79], + [33.48, -10.8], + [33.47, -10.81], + [33.46, -10.82], + [33.42, -10.81], + [33.38, -10.82], + [33.37, -10.83], + [33.34, -10.82], + [33.33, -10.83], + [33.32, -10.85], + [33.31, -10.87], + [33.29, -10.88], + [33.28, -10.87], + [33.26, -10.88], + [33.25, -10.89], + [33.26, -10.91], + [33.27, -10.9], + [33.28, -10.91], + [33.29, -10.92], + [33.3, -10.93], + [33.31, -10.94], + [33.3, -10.99], + [33.29, -10.98], + [33.3, -10.99], + [33.31, -11], + [33.32, -11.01], + [33.34, -11.02], + [33.38, -11.03], + [33.39, -11.04], + [33.4, -11.03], + [33.43, -11.04], + [33.44, -11.05], + [33.43, -11.06], + [33.44, -11.07], + [33.43, -11.12], + [33.44, -11.13], + [33.46, -11.12], + [33.47, -11.11], + [33.48, -11.1], + [33.49, -11.09], + [33.5, -11.08], + [33.51, -11.07], + [33.52, -11.06], + [33.53, -11.04], + [33.54, -11.03], + [33.55, -11.04], + [33.56, -11.05], + [33.57, -11.06], + [33.58, -11.07], + [33.65, -11.06], + [33.67, -11.07], + [33.68, -11.08], + [33.69, -11.09], + [33.7, -11.1], + [33.73, -11.09], + [33.74, -11.08], + [33.73, -11.05], + [33.74, -11.04], + [33.75, -11.03], + [33.78, -11.02], + [33.79, -11.03], + [33.8, -11.02], + [33.82, -11.03], + [33.86, -11.02], + [33.87, -11.03], + [33.88, -11.04], + [33.89, -11.03], + [33.9, -11.04], + [33.91, -11.03], + [33.93, -11.02], + [33.94, -11], + [33.93, -10.99], + [33.94, -10.98], + [33.95, -10.96], + [33.96, -10.97], + [33.97, -10.98], + [33.98, -10.99], + [33.99, -11], + [34, -11.01], + [34.01, -11.02], + [34.02, -11.03], + [34.03, -11.04], + [34.04, -11.05], + [34.05, -11.06], + [34.06, -11.08], + [34.07, -11.07], + [34.08, -11.06], + [34.1, -11.05], + [34.11, -11.04], + [34.12, -11.03], + [34.14, -11.02], + [34.16, -11.01], + [34.18, -11], + [34.2, -10.99], + [34.21, -10.98], + [34.22, -10.97], + [34.21, -10.89], + [34.22, -10.88], + [34.21, -10.87], + [34.2, -10.83], + [34.21, -10.82], + [34.2, -10.81], + [34.21, -10.8], + [34.2, -10.78], + [34.21, -10.77], + [34.22, -10.75], + [34.21, -10.74], + [34.2, -10.73], + [34.19, -10.72], + [34.2, -10.7], + [34.19, -10.68], + [34.2, -10.67], + [34.19, -10.66], + [34.2, -10.65], + [34.19, -10.63], + [34.18, -10.61], + [34.17, -10.6], + [34.18, -10.59], + [34.17, -10.58], + [34.16, -10.57], + [34.14, -10.58], + [34.12, -10.59], + [34.11, -10.58], + [34.09, -10.57], + [33.96, -10.45], + [33.89, -10.48], + [33.79, -10.53], + [33.72, -10.56], + [33.71, -10.57] ], - "Dowa": [ + "Salima": [ + [34.24, -13.8], + [34.23, -13.83], + [34.22, -13.84], + [34.21, -13.85], + [34.2, -13.86], + [34.19, -13.87], + [34.2, -13.88], + [34.21, -13.89], + [34.22, -13.88], + [34.23, -13.87], + [34.25, -13.86], + [34.29, -13.87], + [34.31, -13.88], + [34.32, -13.91], + [34.33, -13.92], + [34.34, -13.94], + [34.35, -13.95], + [34.36, -13.96], + [34.37, -13.97], + [34.38, -13.98], + [34.39, -13.99], + [34.4, -14.02], + [34.41, -14.03], + [34.42, -14.04], + [34.43, -14.05], + [34.44, -14.06], + [34.45, -14.07], + [34.46, -14.08], + [34.47, -14.09], + [34.48, -14.1], + [34.49, -14.11], + [34.5, -14.1], + [34.52, -14.09], + [34.53, -14.08], + [34.55, -14.07], + [34.54, -14.06], + [34.53, -14.05], + [34.52, -14.01], + [34.53, -13.95], + [34.54, -13.94], + [34.55, -13.93], + [34.56, -13.92], + [34.57, -13.91], + [34.58, -13.9], + [34.59, -13.89], + [34.6, -13.88], + [34.59, -13.87], + [34.6, -13.81], + [34.61, -13.79], + [34.62, -13.78], + [34.61, -13.77], + [34.62, -13.74], + [34.63, -13.72], + [34.62, -13.71], + [34.61, -13.7], + [34.6, -13.69], + [34.59, -13.67], + [34.58, -13.66], + [34.57, -13.65], + [34.56, -13.64], + [34.55, -13.63], + [34.54, -13.62], + [34.53, -13.6], + [34.52, -13.58], + [34.53, -13.59], + [34.54, -13.61], + [34.53, -13.6], + [34.51, -13.59], + [34.5, -13.58], + [34.48, -13.59], + [34.47, -13.6], + [34.45, -13.59], + [34.43, -13.58], + [34.42, -13.57], + [34.41, -13.56], + [34.4, -13.55], + [34.39, -13.54], + [34.38, -13.53], + [34.37, -13.5], + [34.36, -13.47], + [34.35, -13.45], + [34.34, -13.44], + [34.33, -13.43], + [34.32, -13.42], + [34.31, -13.43], + [34.3, -13.44], + [34.29, -13.45], + [34.27, -13.46], + [34.26, -13.45], + [34.24, -13.46], + [34.23, -13.47], + [34.2, -13.48], + [34.19, -13.49], + [34.15, -13.5], + [34.13, -13.51], [34.12, -13.5], - [34.13, -13.58], - [34.12, -13.61], - [34.13, -13.63], - [34.14, -13.64], - [34.19, -13.68], - [34.2, -13.69], - [34.26, -13.67], - [34.28, -13.68], - [34.29, -13.69], - [34.28, -13.71], - [34.29, -13.72], - [34.3, -13.73], - [34.31, -13.74], - [34.3, -13.75], - [34.29, -13.76], - [34.28, -13.77], - [34.25, -13.78], - [34.22, -13.8], - [34.18, -13.79], - [34.15, -13.8], - [34.14, -13.81], - [34.1, -13.82], - [34.03, -13.81], - [34.02, -13.8], - [34.01, -13.79], - [34, -13.78], - [33.97, -13.77], - [33.94, -13.76], - [33.77, -13.75], - [33.76, -13.69], - [33.75, -13.66], - [33.58, -13.7], - [33.48, -13.68], - [33.47, -13.67], - [33.46, -13.65], - [33.44, -13.56], - [33.45, -13.51], - [33.44, -13.49], - [33.42, -13.48], - [33.44, -13.45], - [33.45, -13.42], - [33.46, -13.4], - [33.47, -13.37], - [33.46, -13.35], - [33.47, -13.32], - [33.48, -13.33], - [33.5, -13.34], - [33.54, -13.33], - [33.55, -13.32], - [33.56, -13.3], - [33.58, -13.29], - [33.59, -13.28], - [33.6, -13.25], - [33.62, -13.23], - [33.63, -13.27], - [33.64, -13.28], - [33.65, -13.29], - [33.67, -13.3], - [33.69, -13.32], - [33.71, -13.34], - [33.72, -13.36], - [33.74, -13.42], - [33.75, -13.49], - [33.76, -13.5], - [33.77, -13.51], - [33.87, -13.49], - [33.94, -13.5], - [34.05, -13.52], [34.11, -13.51], - [34.12, -13.5] + [34.12, -13.57], + [34.15, -13.67], + [34.17, -13.68], + [34.19, -13.7], + [34.2, -13.71], + [34.21, -13.7], + [34.25, -13.69], + [34.27, -13.68], + [34.28, -13.69], + [34.29, -13.75], + [34.3, -13.76], + [34.29, -13.78], + [34.27, -13.79], + [34.24, -13.8] ], - "Balaka": [ - [35.17, -15.23], - [35.13, -15.27], - [35.11, -15.3], - [35.09, -15.31], - [35.05, -15.32], - [34.84, -15.31], - [34.92, -14.99], - [34.91, -14.97], - [34.92, -14.96], - [34.97, -14.89], - [34.99, -14.82], - [35, -14.76], - [35.3, -14.78], - [35.31, -14.83], - [35.32, -14.87], - [35.31, -14.95], - [35.3, -14.97], - [35.29, -14.98], - [35.27, -14.99], - [35.24, -15.04], - [35.23, -15.06], - [35.21, -15.12], - [35.19, -15.19], - [35.18, -15.22], - [35.17, -15.23] + "Thyolo": [ + [35.26, -16.41], + [35.27, -16.4], + [35.28, -16.38], + [35.29, -16.37], + [35.3, -16.36], + [35.29, -16.34], + [35.28, -16.33], + [35.29, -16.31], + [35.3, -16.27], + [35.29, -16.25], + [35.3, -16.24], + [35.31, -16.23], + [35.3, -16.21], + [35.29, -16.2], + [35.28, -16.19], + [35.29, -16.18], + [35.3, -16.15], + [35.31, -16.14], + [35.32, -16.13], + [35.33, -16.12], + [35.32, -16.1], + [35.33, -16.08], + [35.32, -16.07], + [35.31, -16.05], + [35.32, -16.04], + [35.31, -16.03], + [35.32, -16.02], + [35.31, -16], + [35.29, -15.99], + [35.28, -15.98], + [35.27, -15.97], + [35.26, -15.96], + [35.25, -15.92], + [35.24, -15.9], + [35.23, -15.89], + [35.2, -15.88], + [35.19, -15.86], + [35.14, -15.85], + [35.13, -15.86], + [35.1, -15.85], + [35.08, -15.86], + [35.09, -15.87], + [35.08, -15.88], + [35.07, -15.89], + [35.06, -15.91], + [35.05, -15.92], + [35.04, -15.91], + [35.03, -15.92], + [35.02, -15.93], + [35.01, -15.91], + [35, -15.92], + [34.99, -15.93], + [34.98, -15.94], + [34.97, -15.95], + [34.96, -15.94], + [34.97, -15.95], + [34.96, -15.96], + [34.95, -15.97], + [34.94, -15.99], + [34.92, -16], + [34.93, -16.01], + [34.91, -16.02], + [34.92, -16.03], + [34.91, -16.04], + [34.92, -16.06], + [34.93, -16.07], + [34.94, -16.09], + [34.95, -16.12], + [34.96, -16.13], + [34.97, -16.14], + [35.02, -16.18], + [35.03, -16.2], + [35.04, -16.21], + [35.05, -16.23], + [35.06, -16.25], + [35.07, -16.26], + [35.08, -16.27], + [35.09, -16.28], + [35.11, -16.29], + [35.12, -16.3], + [35.11, -16.31], + [35.12, -16.32], + [35.13, -16.33], + [35.15, -16.34], + [35.16, -16.35], + [35.17, -16.37], + [35.2, -16.38], + [35.21, -16.39], + [35.22, -16.4], + [35.25, -16.41] ], - "Chiradzulu": [ - [35.19, -15.52], + "Zomba": [ + [35.13, -15.53], + [35.15, -15.52], + [35.16, -15.54], + [35.17, -15.52], + [35.19, -15.5], + [35.18, -15.53], + [35.19, -15.55], [35.2, -15.57], [35.23, -15.58], [35.24, -15.59], - [35.25, -15.62], - [35.26, -15.63], + [35.25, -15.63], + [35.26, -15.64], [35.27, -15.65], [35.28, -15.66], [35.3, -15.67], - [35.34, -15.68], - [35.32, -15.74], - [35.33, -15.94], - [35.32, -15.97], - [35.31, -16.01], - [35.29, -15.99], - [35.28, -15.98], - [35.27, -15.97], - [35.26, -15.94], - [35.25, -15.92], - [35.21, -15.89], - [35.2, -15.87], - [35.19, -15.86], - [35.12, -15.82], - [35.11, -15.64], - [35.1, -15.62], - [35.14, -15.54], - [35.16, -15.53], - [35.19, -15.52] - ], - "Blantyre": [ - [35.14, -15.54], - [35.1, -15.6], - [35.11, -15.63], - [35.12, -15.66], - [35.15, -15.86], - [35.04, -15.92], - [35.03, -15.93], - [34.99, -15.94], - [34.98, -15.95], - [34.96, -15.98], - [34.95, -15.99], - [34.93, -16.01], - [34.92, -16.02], - [34.89, -16.03], - [34.88, -16.02], - [34.87, -15.97], - [34.85, -15.96], - [34.86, -15.93], - [34.88, -15.87], - [34.87, -15.83], - [34.86, -15.82], - [34.75, -15.81], - [34.74, -15.74], - [34.75, -15.69], - [34.76, -15.68], - [34.77, -15.67], - [34.76, -15.61], - [34.77, -15.59], - [34.78, -15.58], - [34.83, -15.55], - [34.86, -15.52], - [34.89, -15.42], - [34.91, -15.39], - [34.95, -15.37], - [34.96, -15.36], - [35.01, -15.35], + [35.32, -15.68], + [35.38, -15.67], + [35.39, -15.66], + [35.4, -15.67], + [35.41, -15.68], + [35.42, -15.67], + [35.45, -15.66], + [35.47, -15.65], + [35.48, -15.64], + [35.49, -15.63], + [35.5, -15.61], + [35.51, -15.6], + [35.53, -15.59], + [35.54, -15.58], + [35.53, -15.57], + [35.54, -15.56], + [35.55, -15.55], + [35.56, -15.54], + [35.58, -15.53], + [35.6, -15.52], + [35.61, -15.53], + [35.62, -15.52], + [35.63, -15.5], + [35.64, -15.48], + [35.65, -15.47], + [35.66, -15.46], + [35.67, -15.45], + [35.85, -15.44], + [35.84, -15.37], + [35.8, -15.2], + [35.79, -15.21], + [35.51, -15.22], + [35.5, -15.23], + [35.46, -15.24], + [35.45, -15.23], + [35.44, -15.24], + [35.43, -15.23], + [35.34, -15.2], + [35.33, -15.21], + [35.31, -15.22], + [35.3, -15.23], + [35.31, -15.24], + [35.3, -15.25], + [35.29, -15.24], + [35.26, -15.23], + [35.23, -15.22], + [35.22, -15.23], + [35.21, -15.24], + [35.2, -15.25], + [35.18, -15.24], + [35.17, -15.23], + [35.16, -15.21], + [35.15, -15.22], + [35.14, -15.24], + [35.13, -15.25], + [35.12, -15.26], + [35.11, -15.27], + [35.1, -15.29], + [35.09, -15.3], + [35.08, -15.31], + [35.07, -15.3], + [35.06, -15.32], + [35.04, -15.33], + [35.01, -15.34], + [34.99, -15.35], + [35, -15.36], + [35.01, -15.37], + [35.02, -15.38], [35.03, -15.39], - [35.05, -15.41], - [35.09, -15.45], + [35.04, -15.4], + [35.06, -15.41], + [35.05, -15.42], + [35.06, -15.43], + [35.07, -15.44], + [35.09, -15.46], [35.1, -15.47], - [35.14, -15.48], - [35.12, -15.51], - [35.11, -15.52], - [35.12, -15.53], - [35.13, -15.54] - ], - "Ntchisi": [ - [33.92, -13.02], - [33.93, -13.09], - [33.94, -13.1], - [33.95, -13.12], - [33.96, -13.16], - [33.97, -13.17], - [33.99, -13.16], - [34, -13.15], - [34.01, -13.13], - [34.02, -13.12], - [34.06, -13.11], - [34.07, -13.16], - [34.1, -13.17], - [34.11, -13.18], - [34.1, -13.28], - [34.12, -13.36], - [34.13, -13.49], - [34.12, -13.5], - [34.11, -13.51], - [34.08, -13.52], - [34, -13.5], - [33.91, -13.49], - [33.82, -13.51], - [33.76, -13.5], - [33.75, -13.49], - [33.74, -13.48], - [33.72, -13.36], - [33.71, -13.34], - [33.69, -13.32], - [33.67, -13.3], - [33.65, -13.29], - [33.64, -13.28], - [33.63, -13.27], - [33.62, -13.23], - [33.66, -13.22], - [33.68, -13.21], - [33.71, -13.2], - [33.72, -13.19], - [33.73, -13.18], - [33.74, -13.17], - [33.76, -13.15], - [33.77, -13.13], - [33.78, -13.12], - [33.79, -13.11], - [33.81, -13.1], - [33.82, -13.09], - [33.83, -13.08], - [33.84, -13.06], - [33.92, -13.02] + [35.09, -15.54], + [35.1, -15.55], + [35.12, -15.54], + [35.13, -15.53] ] } From d0a5e87c3ee16f0681d3c93b6bb47e78bbf24444 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 20 Feb 2025 18:29:08 -0800 Subject: [PATCH 21/44] feat: wip forecast page district select --- .../src/app/pages/forecast/forecast.page.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index 73cee81df..2515c54af 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -52,6 +52,15 @@

{{'Daily' | translate}}

{{'Downscaled' | translate}}

+ + + {{'Location' | translate}} + +
@if(downscaledForecasts(); as collection){ From 19081ec6b0f545d325a6349962c30efdcb9fd47b Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 20 Feb 2025 18:34:14 -0800 Subject: [PATCH 22/44] chore: remove boundary json --- .../geoLocation/mw/admin-0.boundaries.json | 522 --- .../geoLocation/mw/admin-1.boundaries.json | 3744 ----------------- .../geoLocation/zm/admin-0.boundaries.json | 930 ---- .../geoLocation/zm/admin-1.boundaries.json | 3156 -------------- 4 files changed, 8352 deletions(-) delete mode 100644 libs/data/geoLocation/mw/admin-0.boundaries.json delete mode 100644 libs/data/geoLocation/mw/admin-1.boundaries.json delete mode 100644 libs/data/geoLocation/zm/admin-0.boundaries.json delete mode 100644 libs/data/geoLocation/zm/admin-1.boundaries.json diff --git a/libs/data/geoLocation/mw/admin-0.boundaries.json b/libs/data/geoLocation/mw/admin-0.boundaries.json deleted file mode 100644 index 65ceeb0bc..000000000 --- a/libs/data/geoLocation/mw/admin-0.boundaries.json +++ /dev/null @@ -1,522 +0,0 @@ -{ - "Malawi": [ - [34.96, -11.57], - [34.62, -11.58], - [34.61, -11.59], - [34.6, -11.73], - [34.56, -11.83], - [34.49, -11.94], - [34.38, -12.1], - [34.36, -12.15], - [34.35, -12.2], - [34.38, -12.29], - [34.44, -12.5], - [34.49, -12.69], - [34.51, -12.8], - [34.52, -12.94], - [34.54, -13.06], - [34.55, -13.16], - [34.54, -13.24], - [34.55, -13.33], - [34.58, -13.4], - [34.6, -13.42], - [34.61, -13.44], - [34.63, -13.47], - [34.64, -13.48], - [34.65, -13.5], - [34.86, -13.52], - [34.89, -13.53], - [35, -13.63], - [35.08, -13.7], - [35.17, -13.81], - [35.28, -13.93], - [35.37, -14.04], - [35.46, -14.14], - [35.52, -14.26], - [35.61, -14.37], - [35.71, -14.5], - [35.75, -14.54], - [35.79, -14.59], - [35.84, -14.64], - [35.85, -14.65], - [35.86, -14.88], - [35.87, -14.89], - [35.84, -15.04], - [35.79, -15.15], - [35.78, -15.17], - [35.79, -15.21], - [35.81, -15.3], - [35.84, -15.42], - [35.83, -15.54], - [35.82, -15.66], - [35.81, -15.9], - [35.8, -15.93], - [35.79, -15.96], - [35.8, -16], - [35.79, -16.02], - [35.77, -16.06], - [35.7, -16.11], - [35.55, -16.14], - [35.52, -16.15], - [35.51, -16.17], - [35.49, -16.16], - [35.47, -16.14], - [35.46, -16.13], - [35.44, -16.12], - [35.39, -16.13], - [35.37, -16.14], - [35.3, -16.2], - [35.28, -16.23], - [35.26, -16.27], - [35.25, -16.32], - [35.27, -16.36], - [35.26, -16.37], - [35.24, -16.39], - [35.23, -16.41], - [35.21, -16.48], - [35.14, -16.53], - [35.13, -16.54], - [35.15, -16.58], - [35.16, -16.61], - [35.17, -16.62], - [35.19, -16.63], - [35.22, -16.64], - [35.23, -16.65], - [35.24, -16.66], - [35.25, -16.67], - [35.28, -16.7], - [35.29, -16.79], - [35.31, -16.83], - [35.29, -16.87], - [35.28, -16.89], - [35.29, -16.93], - [35.28, -16.94], - [35.27, -16.95], - [35.28, -16.96], - [35.31, -16.97], - [35.3, -17.01], - [35.31, -17.07], - [35.3, -17.1], - [35.29, -17.13], - [35.23, -17.14], - [35.13, -17.13], - [35.08, -17.12], - [35.07, -17.11], - [35.04, -17.04], - [35.07, -16.99], - [35.09, -16.98], - [35.11, -16.96], - [35.13, -16.93], - [35.12, -16.83], - [35.1, -16.82], - [35, -16.81], - [34.98, -16.79], - [34.96, -16.77], - [34.95, -16.76], - [34.93, -16.75], - [34.91, -16.74], - [34.9, -16.73], - [34.89, -16.71], - [34.88, -16.69], - [34.84, -16.68], - [34.83, -16.66], - [34.82, -16.63], - [34.77, -16.59], - [34.76, -16.58], - [34.74, -16.54], - [34.73, -16.53], - [34.67, -16.5], - [34.66, -16.49], - [34.64, -16.46], - [34.63, -16.44], - [34.6, -16.42], - [34.59, -16.41], - [34.58, -16.39], - [34.55, -16.32], - [34.52, -16.3], - [34.48, -16.29], - [34.43, -16.27], - [34.39, -16.19], - [34.41, -16.09], - [34.4, -16.06], - [34.39, -16.04], - [34.3, -15.95], - [34.29, -15.94], - [34.26, -15.93], - [34.24, -15.92], - [34.23, -15.89], - [34.24, -15.82], - [34.25, -15.79], - [34.28, -15.76], - [34.29, -15.75], - [34.31, -15.74], - [34.34, -15.73], - [34.4, -15.65], - [34.42, -15.62], - [34.41, -15.51], - [34.42, -15.46], - [34.46, -15.42], - [34.48, -15.41], - [34.49, -15.4], - [34.5, -15.36], - [34.51, -15.35], - [34.52, -15.34], - [34.53, -15.33], - [34.55, -15.32], - [34.57, -15.3], - [34.56, -15.2], - [34.55, -15.12], - [34.56, -15.1], - [34.55, -15.07], - [34.57, -15.02], - [34.58, -15], - [34.57, -14.95], - [34.56, -14.94], - [34.55, -14.92], - [34.54, -14.8], - [34.53, -14.77], - [34.52, -14.73], - [34.51, -14.7], - [34.52, -14.64], - [34.5, -14.58], - [34.45, -14.53], - [34.43, -14.5], - [34.39, -14.43], - [34.38, -14.41], - [34.37, -14.4], - [34.34, -14.39], - [34.32, -14.4], - [34.3, -14.41], - [34.29, -14.4], - [34.18, -14.44], - [34.08, -14.45], - [34.07, -14.46], - [34.06, -14.49], - [34.05, -14.5], - [33.95, -14.48], - [33.89, -14.49], - [33.83, -14.52], - [33.8, -14.53], - [33.72, -14.49], - [33.7, -14.5], - [33.68, -14.52], - [33.67, -14.6], - [33.66, -14.61], - [33.64, -14.6], - [33.63, -14.59], - [33.62, -14.58], - [33.6, -14.52], - [33.58, -14.5], - [33.56, -14.49], - [33.55, -14.48], - [33.54, -14.47], - [33.53, -14.46], - [33.51, -14.43], - [33.47, -14.41], - [33.46, -14.4], - [33.44, -14.38], - [33.39, -14.28], - [33.37, -14.26], - [33.36, -14.23], - [33.35, -14.22], - [33.32, -14.21], - [33.29, -14.16], - [33.28, -14.06], - [33.26, -14.04], - [33.2, -14.01], - [33.19, -13.99], - [33.15, -13.94], - [33.14, -13.92], - [33.13, -13.93], - [33.12, -13.96], - [33.08, -13.97], - [33.06, -13.98], - [33.05, -14], - [33.02, -14.05], - [32.98, -14.02], - [32.97, -14.01], - [32.98, -13.95], - [32.97, -13.94], - [32.96, -13.93], - [32.93, -13.91], - [32.92, -13.88], - [32.87, -13.82], - [32.86, -13.81], - [32.83, -13.8], - [32.79, -13.79], - [32.76, -13.78], - [32.77, -13.74], - [32.8, -13.72], - [32.81, -13.71], - [32.77, -13.65], - [32.74, -13.64], - [32.68, -13.63], - [32.66, -13.6], - [32.67, -13.58], - [32.68, -13.57], - [32.71, -13.58], - [32.72, -13.57], - [32.75, -13.55], - [32.76, -13.54], - [32.81, -13.53], - [32.82, -13.51], - [32.83, -13.46], - [32.87, -13.44], - [32.89, -13.4], - [32.91, -13.35], - [32.92, -13.29], - [32.94, -13.26], - [32.96, -13.22], - [33, -13.2], - [32.98, -13.17], - [32.97, -13.15], - [32.98, -13.01], - [33.01, -12.95], - [32.98, -12.87], - [32.95, -12.85], - [32.94, -12.77], - [32.96, -12.73], - [32.99, -12.67], - [33.02, -12.61], - [33.04, -12.6], - [33.05, -12.59], - [33.06, -12.58], - [33.07, -12.59], - [33.08, -12.6], - [33.1, -12.59], - [33.12, -12.58], - [33.14, -12.59], - [33.16, -12.62], - [33.18, -12.61], - [33.19, -12.6], - [33.2, -12.59], - [33.23, -12.58], - [33.24, -12.54], - [33.26, -12.53], - [33.29, -12.52], - [33.3, -12.53], - [33.32, -12.54], - [33.35, -12.53], - [33.37, -12.52], - [33.39, -12.5], - [33.41, -12.48], - [33.42, -12.46], - [33.45, -12.45], - [33.46, -12.44], - [33.47, -12.41], - [33.49, -12.39], - [33.51, -12.37], - [33.53, -12.36], - [33.51, -12.33], - [33.46, -12.32], - [33.38, -12.34], - [33.35, -12.33], - [33.33, -12.3], - [33.31, -12.23], - [33.3, -12.2], - [33.29, -12.18], - [33.26, -12.16], - [33.25, -12.14], - [33.29, -11.98], - [33.3, -11.93], - [33.31, -11.91], - [33.3, -11.86], - [33.31, -11.81], - [33.3, -11.61], - [33.28, -11.58], - [33.22, -11.57], - [33.21, -11.56], - [33.23, -11.53], - [33.24, -11.4], - [33.27, -11.42], - [33.28, -11.36], - [33.3, -11.35], - [33.37, -11.22], - [33.38, -11.19], - [33.39, -11.16], - [33.36, -11.11], - [33.34, -11.09], - [33.32, -11.06], - [33.3, -11.03], - [33.29, -11], - [33.28, -10.91], - [33.27, -10.9], - [33.23, -10.88], - [33.24, -10.87], - [33.25, -10.86], - [33.26, -10.87], - [33.29, -10.86], - [33.31, -10.83], - [33.32, -10.82], - [33.33, -10.81], - [33.37, -10.8], - [33.42, -10.81], - [33.45, -10.8], - [33.47, -10.78], - [33.5, -10.77], - [33.51, -10.75], - [33.53, -10.71], - [33.58, -10.66], - [33.59, -10.65], - [33.6, -10.64], - [33.64, -10.62], - [33.66, -10.6], - [33.67, -10.58], - [33.64, -10.51], - [33.62, -10.49], - [33.6, -10.45], - [33.57, -10.42], - [33.56, -10.4], - [33.53, -10.34], - [33.54, -10.26], - [33.53, -10.23], - [33.52, -10.21], - [33.5, -10.2], - [33.48, -10.18], - [33.45, -10.17], - [33.44, -10.15], - [33.42, -10.14], - [33.4, -10.12], - [33.32, -10.08], - [33.3, -10.06], - [33.31, -10.01], - [33.33, -9.97], - [33.36, -9.92], - [33.37, -9.9], - [33.36, -9.87], - [33.34, -9.83], - [33.3, -9.81], - [33.29, -9.8], - [33.28, -9.79], - [33.27, -9.78], - [33.25, -9.75], - [33.24, -9.74], - [33.22, -9.73], - [33.21, -9.71], - [33.2, -9.7], - [33.21, -9.69], - [33.22, -9.67], - [33.21, -9.65], - [33.2, -9.62], - [33.18, -9.6], - [33.1, -9.59], - [33.09, -9.61], - [33.08, -9.66], - [33.06, -9.65], - [33.05, -9.64], - [33.04, -9.62], - [33.01, -9.63], - [32.97, -9.6], - [32.99, -9.53], - [32.98, -9.5], - [32.97, -9.48], - [32.94, -9.49], - [32.93, -9.48], - [32.92, -9.47], - [32.94, -9.39], - [32.96, -9.38], - [32.99, -9.39], - [33.04, -9.44], - [33.1, -9.49], - [33.14, -9.5], - [33.17, -9.51], - [33.2, -9.5], - [33.22, -9.49], - [33.24, -9.5], - [33.27, -9.49], - [33.36, -9.53], - [33.37, -9.55], - [33.39, -9.59], - [33.4, -9.6], - [33.42, -9.62], - [33.54, -9.6], - [33.56, -9.59], - [33.59, -9.6], - [33.62, -9.61], - [33.7, -9.59], - [33.73, -9.58], - [33.76, -9.6], - [33.79, -9.63], - [33.81, -9.64], - [33.84, -9.65], - [33.87, -9.67], - [33.89, -9.69], - [33.9, -9.71], - [33.91, -9.72], - [33.93, -9.7], - [33.94, -9.68], - [33.95, -9.67], - [33.96, -9.64], - [33.95, -9.55], - [33.96, -9.52], - [33.98, -9.51], - [34, -9.49], - [34.01, -9.48], - [34.05, -9.49], - [34.08, -9.51], - [34.09, -9.52], - [34.1, -9.53], - [34.14, -9.57], - [34.16, -9.59], - [34.19, -9.61], - [34.29, -9.71], - [34.32, -9.72], - [34.33, -9.75], - [34.34, -9.78], - [34.36, -9.8], - [34.38, -9.82], - [34.48, -9.95], - [34.49, -9.97], - [34.52, -10.01], - [34.54, -10.04], - [34.53, -10.08], - [34.52, -10.09], - [34.53, -10.13], - [34.57, -10.2], - [34.58, -10.26], - [34.59, -10.29], - [34.57, -10.41], - [34.59, -10.46], - [34.58, -10.51], - [34.59, -10.55], - [34.6, -10.58], - [34.63, -10.6], - [34.65, -10.65], - [34.66, -10.67], - [34.65, -10.71], - [34.66, -10.72], - [34.67, -10.73], - [34.68, -10.75], - [34.66, -10.76], - [34.65, -10.86], - [34.63, -10.95], - [34.62, -10.97], - [34.6, -10.99], - [34.59, -11.02], - [34.6, -11.04], - [34.61, -11.08], - [34.62, -11.12], - [34.67, -11.16], - [34.68, -11.18], - [34.7, -11.19], - [34.71, -11.2], - [34.72, -11.21], - [34.73, -11.25], - [34.74, -11.27], - [34.76, -11.28], - [34.75, -11.29], - [34.74, -11.3], - [34.76, -11.34], - [34.77, -11.35], - [34.78, -11.33], - [34.84, -11.35], - [34.87, -11.36], - [34.89, -11.38], - [34.9, -11.4], - [34.92, -11.42], - [34.93, -11.45], - [34.94, -11.46], - [34.95, -11.47], - [34.96, -11.49] - ] -} diff --git a/libs/data/geoLocation/mw/admin-1.boundaries.json b/libs/data/geoLocation/mw/admin-1.boundaries.json deleted file mode 100644 index 5b7e37da1..000000000 --- a/libs/data/geoLocation/mw/admin-1.boundaries.json +++ /dev/null @@ -1,3744 +0,0 @@ -{ - "Balaka": [ - [34.84, -15.22], - [34.85, -15.23], - [34.84, -15.24], - [34.83, -15.25], - [34.84, -15.27], - [34.83, -15.28], - [34.82, -15.32], - [34.81, -15.33], - [34.86, -15.32], - [35.07, -15.31], - [35.08, -15.3], - [35.07, -15.31], - [35.08, -15.3], - [35.1, -15.29], - [35.11, -15.28], - [35.12, -15.26], - [35.13, -15.25], - [35.14, -15.24], - [35.15, -15.23], - [35.16, -15.22], - [35.17, -15.2], - [35.18, -15.17], - [35.19, -15.14], - [35.2, -15.12], - [35.21, -15.11], - [35.22, -15.06], - [35.23, -15.03], - [35.24, -15.01], - [35.25, -14.99], - [35.26, -14.98], - [35.27, -14.97], - [35.28, -14.95], - [35.29, -14.93], - [35.3, -14.88], - [35.29, -14.86], - [35.28, -14.81], - [35.22, -14.77], - [34.97, -14.78], - [34.96, -14.81], - [34.95, -14.86], - [34.94, -14.85], - [34.93, -14.86], - [34.91, -14.94], - [34.9, -14.96], - [34.89, -15.02], - [34.86, -15.13], - [34.84, -15.22] - ], - "Blantyre": [ - [35.01, -15.91], - [35.02, -15.92], - [35.03, -15.93], - [35.04, -15.92], - [35.05, -15.91], - [35.07, -15.9], - [35.06, -15.89], - [35.08, -15.88], - [35.09, -15.87], - [35.08, -15.86], - [35.09, -15.85], - [35.11, -15.84], - [35.12, -15.83], - [35.13, -15.82], - [35.12, -15.8], - [35.11, -15.79], - [35.12, -15.75], - [35.11, -15.72], - [35.12, -15.71], - [35.11, -15.69], - [35.12, -15.66], - [35.11, -15.64], - [35.1, -15.63], - [35.11, -15.58], - [35.12, -15.56], - [35.13, -15.55], - [35.12, -15.54], - [35.1, -15.55], - [35.09, -15.54], - [35.13, -15.47], - [35.09, -15.46], - [35.07, -15.44], - [35.06, -15.43], - [35.05, -15.42], - [35.06, -15.41], - [35.05, -15.4], - [35.03, -15.39], - [35.02, -15.38], - [35.01, -15.37], - [35, -15.36], - [34.99, -15.35], - [34.98, -15.36], - [34.97, -15.35], - [34.95, -15.36], - [34.92, -15.37], - [34.91, -15.38], - [34.9, -15.39], - [34.89, -15.4], - [34.88, -15.41], - [34.87, -15.44], - [34.86, -15.45], - [34.87, -15.46], - [34.86, -15.47], - [34.85, -15.49], - [34.84, -15.5], - [34.83, -15.51], - [34.82, -15.53], - [34.81, -15.54], - [34.8, -15.55], - [34.79, -15.56], - [34.77, -15.57], - [34.76, -15.58], - [34.75, -15.59], - [34.76, -15.62], - [34.75, -15.68], - [34.74, -15.69], - [34.72, -15.7], - [34.73, -15.71], - [34.74, -15.74], - [34.73, -15.81], - [34.74, -15.82], - [34.85, -15.83], - [34.87, -15.84], - [34.88, -15.85], - [34.87, -15.87], - [34.86, -15.89], - [34.85, -15.9], - [34.86, -15.91], - [34.87, -15.92], - [34.86, -15.93], - [34.85, -15.95], - [34.86, -15.97], - [34.87, -15.96], - [34.88, -15.97], - [34.89, -15.98], - [34.88, -16], - [34.89, -16.01], - [34.9, -16.02], - [34.91, -16.01], - [34.93, -16], - [34.92, -15.99], - [34.94, -16], - [34.95, -15.99], - [34.96, -15.97], - [34.97, -15.95], - [34.96, -15.94], - [34.97, -15.95], - [34.98, -15.94], - [34.99, -15.93], - [35, -15.92], - [35.01, -15.91] - ], - "Chikwawa": [ - [35.04, -16.51], - [35.05, -16.5], - [35.06, -16.49], - [35.07, -16.43], - [35.08, -16.4], - [35.09, -16.38], - [35.1, -16.35], - [35.09, -16.34], - [35.1, -16.33], - [35.11, -16.32], - [35.12, -16.31], - [35.11, -16.29], - [35.1, -16.28], - [35.09, -16.27], - [35.08, -16.26], - [35.06, -16.25], - [35.05, -16.24], - [35.04, -16.23], - [35.03, -16.21], - [35.02, -16.2], - [34.97, -16.14], - [34.96, -16.13], - [34.95, -16.12], - [34.94, -16.11], - [34.93, -16.09], - [34.92, -16.06], - [34.91, -16.04], - [34.92, -16.03], - [34.91, -16.02], - [34.9, -16.01], - [34.89, -16.02], - [34.88, -16], - [34.89, -15.99], - [34.88, -15.97], - [34.87, -15.96], - [34.86, -15.97], - [34.85, -15.96], - [34.86, -15.95], - [34.87, -15.93], - [34.86, -15.92], - [34.85, -15.9], - [34.86, -15.89], - [34.87, -15.88], - [34.88, -15.87], - [34.87, -15.84], - [34.85, -15.83], - [34.81, -15.82], - [34.71, -15.81], - [34.49, -15.8], - [34.48, -15.79], - [34.43, -15.77], - [34.4, -15.76], - [34.35, -15.74], - [34.32, -15.75], - [34.31, -15.76], - [34.3, -15.77], - [34.29, -15.78], - [34.28, -15.79], - [34.27, -15.8], - [34.26, -15.82], - [34.25, -15.84], - [34.26, -15.86], - [34.25, -15.87], - [34.26, -15.88], - [34.25, -15.89], - [34.26, -15.9], - [34.27, -15.92], - [34.28, -15.93], - [34.31, -15.94], - [34.33, -15.95], - [34.34, -15.96], - [34.36, -15.97], - [34.37, -15.99], - [34.38, -16], - [34.39, -16.02], - [34.4, -16.03], - [34.41, -16.04], - [34.43, -16.05], - [34.44, -16.06], - [34.43, -16.07], - [34.42, -16.08], - [34.41, -16.11], - [34.4, -16.12], - [34.41, -16.13], - [34.4, -16.14], - [34.41, -16.15], - [34.4, -16.16], - [34.41, -16.21], - [34.42, -16.23], - [34.43, -16.26], - [34.44, -16.27], - [34.45, -16.28], - [34.48, -16.29], - [34.49, -16.3], - [34.5, -16.29], - [34.52, -16.28], - [34.53, -16.29], - [34.54, -16.3], - [34.55, -16.31], - [34.57, -16.32], - [34.58, -16.33], - [34.57, -16.34], - [34.58, -16.35], - [34.59, -16.36], - [34.58, -16.39], - [34.59, -16.4], - [34.6, -16.42], - [34.61, -16.43], - [34.62, -16.42], - [34.63, -16.43], - [34.64, -16.44], - [34.65, -16.45], - [34.66, -16.44], - [34.68, -16.45], - [34.69, -16.5], - [34.7, -16.51], - [34.71, -16.5], - [34.73, -16.51], - [34.75, -16.52], - [34.76, -16.53], - [34.77, -16.54], - [34.78, -16.55], - [34.77, -16.58], - [34.78, -16.59], - [34.79, -16.58], - [34.8, -16.59], - [34.81, -16.6], - [34.82, -16.61], - [34.83, -16.6], - [34.84, -16.61], - [34.85, -16.62], - [34.86, -16.66], - [34.87, -16.68], - [34.88, -16.69], - [34.9, -16.68], - [34.91, -16.67], - [34.92, -16.66], - [34.93, -16.65], - [34.94, -16.64], - [34.95, -16.63], - [34.97, -16.62], - [34.98, -16.61], - [34.97, -16.6], - [34.98, -16.59], - [34.97, -16.58], - [34.98, -16.57], - [34.99, -16.56], - [35, -16.55], - [35.01, -16.54], - [35.02, -16.53], - [35.03, -16.52], - [35.04, -16.51] - ], - "Chiradzulu": [ - [35.33, -15.96], - [35.32, -15.91], - [35.31, -15.77], - [35.3, -15.74], - [35.31, -15.71], - [35.33, -15.68], - [35.32, -15.67], - [35.3, -15.66], - [35.27, -15.65], - [35.26, -15.64], - [35.25, -15.63], - [35.24, -15.62], - [35.23, -15.59], - [35.22, -15.57], - [35.19, -15.56], - [35.18, -15.55], - [35.19, -15.53], - [35.17, -15.51], - [35.16, -15.52], - [35.15, -15.54], - [35.14, -15.53], - [35.13, -15.54], - [35.12, -15.55], - [35.11, -15.57], - [35.1, -15.59], - [35.11, -15.63], - [35.12, -15.64], - [35.11, -15.66], - [35.12, -15.69], - [35.11, -15.71], - [35.12, -15.73], - [35.11, -15.75], - [35.12, -15.8], - [35.13, -15.82], - [35.12, -15.83], - [35.11, -15.84], - [35.1, -15.85], - [35.11, -15.86], - [35.13, -15.85], - [35.14, -15.86], - [35.19, -15.85], - [35.2, -15.86], - [35.21, -15.88], - [35.2, -15.89], - [35.23, -15.9], - [35.25, -15.91], - [35.26, -15.92], - [35.27, -15.96], - [35.28, -15.98], - [35.29, -15.99], - [35.3, -16], - [35.31, -15.99], - [35.32, -15.97], - [35.33, -15.96] - ], - "Chitipa": [ - [33.22, -9.5], - [33.21, -9.51], - [33.2, -9.5], - [33.16, -9.49], - [33.13, -9.48], - [33.12, -9.47], - [33.11, -9.46], - [33.1, -9.45], - [33.08, -9.44], - [33.06, -9.43], - [33.05, -9.42], - [33.04, -9.41], - [33.02, -9.4], - [33.01, -9.38], - [33, -9.37], - [32.97, -9.39], - [32.96, -9.4], - [32.95, -9.41], - [32.96, -9.42], - [32.95, -9.43], - [32.97, -9.48], - [32.98, -9.49], - [32.99, -9.5], - [33.01, -9.49], - [33.02, -9.5], - [33.03, -9.51], - [33.02, -9.54], - [33.01, -9.55], - [33, -9.56], - [33.01, -9.59], - [33.02, -9.61], - [33.03, -9.64], - [33.04, -9.63], - [33.07, -9.64], - [33.08, -9.65], - [33.09, -9.66], - [33.1, -9.68], - [33.11, -9.67], - [33.12, -9.64], - [33.11, -9.63], - [33.12, -9.61], - [33.13, -9.6], - [33.14, -9.61], - [33.15, -9.62], - [33.16, -9.61], - [33.19, -9.6], - [33.2, -9.61], - [33.21, -9.62], - [33.22, -9.63], - [33.23, -9.65], - [33.24, -9.75], - [33.25, -9.76], - [33.27, -9.77], - [33.28, -9.78], - [33.29, -9.79], - [33.3, -9.81], - [33.31, -9.82], - [33.32, -9.83], - [33.35, -9.84], - [33.36, -9.85], - [33.37, -9.86], - [33.38, -9.9], - [33.37, -9.92], - [33.36, -9.93], - [33.35, -9.94], - [33.34, -9.98], - [33.33, -10], - [33.32, -10.05], - [33.31, -10.06], - [33.32, -10.07], - [33.33, -10.08], - [33.34, -10.09], - [33.35, -10.1], - [33.37, -10.11], - [33.38, -10.1], - [33.39, -10.11], - [33.4, -10.12], - [33.42, -10.13], - [33.43, -10.14], - [33.44, -10.15], - [33.45, -10.16], - [33.46, -10.17], - [33.48, -10.18], - [33.51, -10.19], - [33.52, -10.2], - [33.53, -10.21], - [33.54, -10.22], - [33.55, -10.23], - [33.56, -10.24], - [33.55, -10.26], - [33.54, -10.3], - [33.55, -10.33], - [33.54, -10.34], - [33.56, -10.35], - [33.55, -10.36], - [33.56, -10.38], - [33.57, -10.39], - [33.56, -10.4], - [33.57, -10.41], - [33.58, -10.44], - [33.6, -10.45], - [33.63, -10.46], - [33.64, -10.47], - [33.63, -10.48], - [33.62, -10.49], - [33.63, -10.5], - [33.64, -10.51], - [33.65, -10.52], - [33.66, -10.53], - [33.67, -10.54], - [33.68, -10.55], - [33.69, -10.58], - [33.7, -10.57], - [33.72, -10.56], - [33.79, -10.53], - [33.89, -10.48], - [33.96, -10.45], - [33.8, -10.21], - [33.77, -10.16], - [33.74, -10.13], - [33.75, -10.12], - [33.74, -10.11], - [33.73, -10.1], - [33.72, -10.08], - [33.71, -10.06], - [33.68, -10.07], - [33.67, -10.06], - [33.66, -10.07], - [33.63, -10.06], - [33.61, -10.05], - [33.6, -10.04], - [33.59, -10.03], - [33.58, -10.01], - [33.56, -10.02], - [33.55, -10.01], - [33.54, -10], - [33.53, -9.99], - [33.51, -9.98], - [33.5, -9.97], - [33.49, -9.98], - [33.48, -9.97], - [33.47, -9.96], - [33.48, -9.94], - [33.49, -9.93], - [33.51, -9.92], - [33.53, -9.91], - [33.54, -9.9], - [33.56, -9.89], - [33.57, -9.88], - [33.58, -9.89], - [33.59, -9.88], - [33.6, -9.87], - [33.61, -9.86], - [33.62, -9.84], - [33.63, -9.83], - [33.62, -9.82], - [33.63, -9.83], - [33.64, -9.82], - [33.65, -9.81], - [33.66, -9.8], - [33.67, -9.79], - [33.7, -9.78], - [33.69, -9.77], - [33.68, -9.75], - [33.67, -9.72], - [33.66, -9.71], - [33.67, -9.69], - [33.68, -9.67], - [33.67, -9.66], - [33.66, -9.65], - [33.65, -9.64], - [33.66, -9.63], - [33.65, -9.62], - [33.64, -9.61], - [33.63, -9.6], - [33.61, -9.59], - [33.6, -9.58], - [33.58, -9.59], - [33.55, -9.6], - [33.54, -9.61], - [33.53, -9.62], - [33.51, -9.63], - [33.5, -9.62], - [33.46, -9.61], - [33.45, -9.62], - [33.44, -9.61], - [33.43, -9.6], - [33.42, -9.59], - [33.43, -9.58], - [33.42, -9.57], - [33.41, -9.56], - [33.4, -9.55], - [33.39, -9.54], - [33.38, -9.53], - [33.37, -9.52], - [33.36, -9.53], - [33.35, -9.52], - [33.34, -9.5], - [33.33, -9.49], - [33.31, -9.48], - [33.3, -9.49], - [33.28, -9.5], - [33.26, -9.49], - [33.23, -9.5] - ], - "Dedza": [ - [34.74, -14.28], - [34.72, -14.29], - [34.68, -14.28], - [34.69, -14.27], - [34.68, -14.23], - [34.66, -14.22], - [34.63, -14.21], - [34.62, -14.2], - [34.61, -14.19], - [34.6, -14.18], - [34.61, -14.17], - [34.6, -14.16], - [34.59, -14.15], - [34.58, -14.14], - [34.57, -14.13], - [34.56, -14.12], - [34.55, -14.11], - [34.54, -14.08], - [34.53, -14.09], - [34.52, -14.1], - [34.49, -14.11], - [34.48, -14.1], - [34.47, -14.09], - [34.46, -14.08], - [34.45, -14.07], - [34.44, -14.06], - [34.43, -14.05], - [34.42, -14.04], - [34.41, -14.03], - [34.4, -14.02], - [34.39, -14.01], - [34.38, -13.99], - [34.37, -13.98], - [34.36, -13.96], - [34.35, -13.95], - [34.34, -13.94], - [34.33, -13.93], - [34.32, -13.91], - [34.31, -13.9], - [34.3, -13.87], - [34.29, -13.86], - [34.28, -13.87], - [34.27, -13.88], - [34.26, -13.9], - [34.24, -13.91], - [34.23, -13.92], - [34.22, -13.93], - [34.23, -13.94], - [34.22, -13.93], - [34.2, -13.94], - [34.19, -13.97], - [34.18, -13.98], - [34.17, -14.01], - [34.16, -14.03], - [34.14, -14.04], - [34.13, -14.05], - [34.14, -14.06], - [34.13, -14.07], - [34.12, -14.08], - [34.11, -14.09], - [34.1, -14.1], - [34.09, -14.11], - [34.08, -14.14], - [34.06, -14.15], - [34.05, -14.16], - [34.04, -14.19], - [34.03, -14.2], - [34.01, -14.21], - [34, -14.2], - [33.99, -14.19], - [33.98, -14.2], - [33.97, -14.21], - [33.95, -14.22], - [33.94, -14.26], - [33.95, -14.27], - [33.94, -14.29], - [33.93, -14.31], - [33.89, -14.32], - [33.87, -14.33], - [33.86, -14.32], - [33.85, -14.31], - [33.84, -14.32], - [33.83, -14.33], - [33.82, -14.34], - [33.81, -14.35], - [33.8, -14.36], - [33.78, -14.37], - [33.77, -14.38], - [33.76, -14.39], - [33.71, -14.4], - [33.7, -14.42], - [33.69, -14.44], - [33.68, -14.52], - [33.67, -14.53], - [33.66, -14.54], - [33.67, -14.58], - [33.66, -14.59], - [33.65, -14.6], - [33.67, -14.61], - [33.68, -14.62], - [33.69, -14.61], - [33.7, -14.59], - [33.71, -14.58], - [33.72, -14.57], - [33.71, -14.56], - [33.7, -14.55], - [33.71, -14.54], - [33.72, -14.5], - [33.74, -14.51], - [33.75, -14.52], - [33.77, -14.53], - [33.79, -14.54], - [33.8, -14.55], - [33.83, -14.54], - [33.84, -14.53], - [33.85, -14.52], - [33.86, -14.51], - [33.87, -14.52], - [33.89, -14.51], - [33.88, -14.5], - [33.89, -14.49], - [33.91, -14.48], - [33.93, -14.47], - [33.94, -14.48], - [34.09, -14.49], - [34.08, -14.46], - [34.11, -14.45], - [34.19, -14.44], - [34.22, -14.43], - [34.23, -14.42], - [34.24, -14.43], - [34.27, -14.42], - [34.28, -14.41], - [34.29, -14.4], - [34.31, -14.41], - [34.32, -14.4], - [34.35, -14.39], - [34.38, -14.4], - [34.39, -14.39], - [34.4, -14.41], - [34.42, -14.42], - [34.44, -14.41], - [34.45, -14.42], - [34.47, -14.43], - [34.5, -14.42], - [34.52, -14.43], - [34.53, -14.44], - [34.55, -14.43], - [34.56, -14.44], - [34.59, -14.43], - [34.61, -14.41], - [34.72, -14.33], - [34.73, -14.32], - [34.74, -14.31] - ], - "Dowa": [ - [34.24, -13.8], - [34.25, -13.79], - [34.27, -13.78], - [34.3, -13.77], - [34.29, -13.75], - [34.28, -13.74], - [34.27, -13.68], - [34.26, -13.69], - [34.25, -13.7], - [34.21, -13.71], - [34.2, -13.7], - [34.17, -13.68], - [34.15, -13.67], - [34.12, -13.64], - [34.11, -13.52], - [34.1, -13.53], - [34.08, -13.54], - [34.07, -13.53], - [34.06, -13.54], - [34.05, -13.53], - [34.04, -13.52], - [34.03, -13.53], - [34.04, -13.52], - [34.03, -13.51], - [34.02, -13.5], - [34, -13.51], - [33.97, -13.52], - [33.95, -13.51], - [33.94, -13.5], - [33.93, -13.48], - [33.92, -13.49], - [33.89, -13.5], - [33.84, -13.51], - [33.83, -13.52], - [33.79, -13.51], - [33.78, -13.52], - [33.76, -13.53], - [33.75, -13.52], - [33.74, -13.51], - [33.73, -13.46], - [33.74, -13.45], - [33.73, -13.41], - [33.72, -13.38], - [33.71, -13.36], - [33.7, -13.34], - [33.69, -13.33], - [33.67, -13.32], - [33.66, -13.31], - [33.65, -13.3], - [33.64, -13.29], - [33.62, -13.28], - [33.61, -13.26], - [33.62, -13.25], - [33.61, -13.24], - [33.62, -13.23], - [33.59, -13.24], - [33.58, -13.28], - [33.57, -13.29], - [33.55, -13.28], - [33.54, -13.3], - [33.55, -13.31], - [33.54, -13.32], - [33.53, -13.31], - [33.54, -13.32], - [33.53, -13.34], - [33.52, -13.33], - [33.51, -13.34], - [33.5, -13.33], - [33.48, -13.32], - [33.47, -13.31], - [33.46, -13.32], - [33.45, -13.33], - [33.46, -13.34], - [33.47, -13.37], - [33.45, -13.38], - [33.46, -13.39], - [33.45, -13.4], - [33.44, -13.42], - [33.43, -13.43], - [33.42, -13.46], - [33.41, -13.47], - [33.42, -13.49], - [33.43, -13.5], - [33.45, -13.51], - [33.44, -13.53], - [33.45, -13.59], - [33.46, -13.63], - [33.45, -13.68], - [33.46, -13.69], - [33.5, -13.7], - [33.51, -13.71], - [33.52, -13.72], - [33.55, -13.71], - [33.56, -13.72], - [33.57, -13.73], - [33.59, -13.72], - [33.6, -13.71], - [33.61, -13.7], - [33.68, -13.69], - [33.71, -13.68], - [33.75, -13.67], - [33.76, -13.68], - [33.75, -13.69], - [33.76, -13.71], - [33.77, -13.76], - [33.78, -13.77], - [33.8, -13.78], - [33.81, -13.77], - [33.82, -13.78], - [33.85, -13.77], - [33.87, -13.76], - [33.88, -13.77], - [33.92, -13.78], - [33.93, -13.77], - [33.94, -13.78], - [33.95, -13.77], - [33.96, -13.79], - [33.99, -13.8], - [34.01, -13.81], - [34.02, -13.82], - [34.03, -13.83], - [34.04, -13.84], - [34.05, -13.83], - [34.08, -13.84], - [34.09, -13.83], - [34.1, -13.84], - [34.11, -13.83], - [34.14, -13.82], - [34.15, -13.81], - [34.17, -13.8], - [34.2, -13.81], - [34.21, -13.82], - [34.22, -13.81], - [34.23, -13.8] - ], - "Karonga": [ - [34.26, -10.4], - [33.72, -10.06], - [33.73, -10.08], - [33.74, -10.11], - [33.75, -10.12], - [33.74, -10.13], - [33.77, -10.16], - [33.8, -10.21], - [33.96, -10.45], - [34.08, -10.57], - [34.09, -10.58], - [34.12, -10.59], - [34.13, -10.58], - [34.14, -10.57], - [34.16, -10.58], - [34.18, -10.59], - [34.19, -10.56], - [34.2, -10.55], - [34.21, -10.54], - [34.23, -10.53], - [34.22, -10.52], - [34.21, -10.51], - [34.22, -10.47], - [34.23, -10.46], - [34.24, -10.45], - [34.26, -10.44], - [34.27, -10.45], - [34.28, -10.46], - [34.27, -10.45], - [34.26, -10.44], - [34.25, -10.43], - [34.26, -10.4], - [34.25, -10.39], - [34.24, -10.38], - [34.25, -10.37], - [34.24, -10.36], - [34.23, -10.35], - [34.21, -10.34], - [34.2, -10.33], - [34.19, -10.32], - [34.18, -10.31], - [34.17, -10.28], - [34.16, -10.27], - [34.15, -10.26], - [34.14, -10.25], - [34.13, -10.24], - [34.11, -10.23], - [34.1, -10.22], - [34.09, -10.21], - [34.08, -10.2], - [34.07, -10.19], - [34.06, -10.18], - [34.05, -10.16], - [34.04, -10.15], - [34.03, -10.14], - [34.02, -10.13], - [34.01, -10.12], - [34, -10.11], - [34.01, -10.09], - [34, -10.08], - [34.01, -10.07], - [34, -10.06], - [33.99, -10.05], - [33.98, -10.04], - [33.97, -10.03], - [33.96, -10.02], - [33.95, -9.99], - [33.94, -9.98], - [33.95, -9.94], - [33.94, -9.9], - [33.93, -9.89], - [33.92, -9.88], - [33.91, -9.87], - [33.9, -9.85], - [33.91, -9.83], - [33.9, -9.8], - [33.89, -9.76], - [33.9, -9.77], - [33.89, -9.76], - [33.9, -9.74], - [33.91, -9.73], - [33.92, -9.72], - [33.93, -9.71], - [33.91, -9.7], - [33.9, -9.69], - [33.89, -9.68], - [33.87, -9.67], - [33.86, -9.66], - [33.85, -9.65], - [33.84, -9.64], - [33.82, -9.63], - [33.81, -9.62], - [33.8, -9.61], - [33.79, -9.6], - [33.78, -9.59], - [33.76, -9.58], - [33.75, -9.59], - [33.74, -9.58], - [33.73, -9.59], - [33.72, -9.58], - [33.71, -9.59], - [33.72, -9.6], - [33.71, -9.61], - [33.65, -9.6], - [33.64, -9.61], - [33.65, -9.62], - [33.66, -9.63], - [33.65, -9.64], - [33.66, -9.65], - [33.67, -9.66], - [33.68, -9.67], - [33.67, -9.68], - [33.66, -9.69], - [33.65, -9.71], - [33.67, -9.72], - [33.68, -9.73], - [33.69, -9.75], - [33.7, -9.77], - [33.69, -9.79], - [33.67, -9.8], - [33.65, -9.81], - [33.64, -9.82], - [33.63, -9.83], - [33.62, -9.82], - [33.63, -9.83], - [33.62, -9.84], - [33.61, -9.85], - [33.6, -9.86], - [33.59, -9.87], - [33.58, -9.88], - [33.57, -9.89], - [33.56, -9.9], - [33.54, -9.91], - [33.53, -9.92], - [33.51, -9.93], - [33.49, -9.94], - [33.47, -9.95], - [33.48, -9.97], - [33.49, -9.98], - [33.5, -9.97], - [33.51, -9.98], - [33.52, -9.99], - [33.54, -10], - [33.55, -10.01], - [33.56, -10.02], - [33.57, -10.01], - [33.59, -10.02], - [33.6, -10.03], - [33.61, -10.04], - [33.62, -10.06], - [33.63, -10.07], - [33.67, -10.06], - [33.68, -10.07], - [33.69, -10.06] - ], - "Kasungu": [ - [33.16, -13.35], - [33.15, -13.37], - [33.16, -13.39], - [33.15, -13.4], - [33.16, -13.42], - [33.17, -13.44], - [33.18, -13.46], - [33.19, -13.51], - [33.21, -13.52], - [33.22, -13.53], - [33.23, -13.54], - [33.24, -13.55], - [33.25, -13.56], - [33.26, -13.58], - [33.29, -13.59], - [33.3, -13.6], - [33.31, -13.62], - [33.34, -13.61], - [33.35, -13.6], - [33.36, -13.59], - [33.38, -13.58], - [33.37, -13.54], - [33.38, -13.52], - [33.37, -13.51], - [33.38, -13.5], - [33.39, -13.49], - [33.41, -13.48], - [33.42, -13.47], - [33.43, -13.46], - [33.44, -13.43], - [33.45, -13.42], - [33.46, -13.4], - [33.45, -13.39], - [33.46, -13.38], - [33.45, -13.37], - [33.46, -13.36], - [33.45, -13.34], - [33.46, -13.33], - [33.47, -13.31], - [33.48, -13.32], - [33.49, -13.33], - [33.5, -13.34], - [33.51, -13.33], - [33.53, -13.34], - [33.54, -13.33], - [33.53, -13.31], - [33.54, -13.32], - [33.55, -13.31], - [33.54, -13.3], - [33.55, -13.29], - [33.58, -13.28], - [33.59, -13.27], - [33.58, -13.24], - [33.6, -13.23], - [33.63, -13.24], - [33.64, -13.23], - [33.65, -13.22], - [33.66, -13.21], - [33.68, -13.2], - [33.69, -13.21], - [33.7, -13.2], - [33.71, -13.18], - [33.72, -13.17], - [33.73, -13.16], - [33.75, -13.15], - [33.76, -13.14], - [33.77, -13.12], - [33.78, -13.11], - [33.79, -13.1], - [33.8, -13.09], - [33.81, -13.1], - [33.82, -13.09], - [33.83, -13.08], - [33.82, -13.07], - [33.83, -13.06], - [33.84, -13.05], - [33.87, -13.04], - [33.89, -13.03], - [33.9, -13.02], - [33.92, -13.01], - [33.93, -13], - [33.94, -12.98], - [33.95, -12.97], - [33.96, -12.96], - [33.97, -12.95], - [33.98, -12.96], - [33.99, -12.95], - [34, -12.94], - [33.99, -12.92], - [33.98, -12.91], - [33.97, -12.9], - [33.96, -12.89], - [33.95, -12.88], - [33.94, -12.85], - [33.91, -12.84], - [33.9, -12.85], - [33.89, -12.84], - [33.84, -12.85], - [33.82, -12.84], - [33.81, -12.83], - [33.82, -12.82], - [33.81, -12.81], - [33.82, -12.8], - [33.83, -12.74], - [33.84, -12.73], - [33.83, -12.72], - [33.84, -12.71], - [33.8, -12.72], - [33.78, -12.71], - [33.77, -12.7], - [33.76, -12.69], - [33.74, -12.7], - [33.72, -12.71], - [33.71, -12.72], - [33.69, -12.73], - [33.6, -12.69], - [33.59, -12.68], - [33.58, -12.69], - [33.57, -12.68], - [33.56, -12.64], - [33.55, -12.59], - [33.58, -12.56], - [33.57, -12.55], - [33.56, -12.54], - [33.55, -12.53], - [33.54, -12.49], - [33.55, -12.48], - [33.54, -12.47], - [33.53, -12.46], - [33.56, -12.45], - [33.59, -12.43], - [33.61, -12.37], - [33.55, -12.36], - [33.54, -12.38], - [33.53, -12.39], - [33.51, -12.4], - [33.5, -12.41], - [33.49, -12.42], - [33.48, -12.41], - [33.47, -12.42], - [33.48, -12.44], - [33.47, -12.46], - [33.46, -12.47], - [33.44, -12.48], - [33.43, -12.49], - [33.42, -12.5], - [33.41, -12.51], - [33.4, -12.53], - [33.39, -12.54], - [33.38, -12.55], - [33.37, -12.56], - [33.36, -12.55], - [33.35, -12.54], - [33.34, -12.55], - [33.33, -12.54], - [33.32, -12.53], - [33.3, -12.54], - [33.26, -12.55], - [33.27, -12.56], - [33.26, -12.57], - [33.25, -12.58], - [33.24, -12.59], - [33.23, -12.6], - [33.21, -12.61], - [33.2, -12.62], - [33.19, -12.63], - [33.18, -12.64], - [33.17, -12.61], - [33.16, -12.6], - [33.13, -12.61], - [33.1, -12.6], - [33.07, -12.61], - [33.05, -12.62], - [33.04, -12.63], - [33.03, -12.64], - [33.02, -12.65], - [33.01, -12.68], - [32.99, -12.73], - [32.97, -12.74], - [32.96, -12.75], - [32.95, -12.76], - [32.94, -12.77], - [32.95, -12.79], - [32.96, -12.83], - [32.95, -12.84], - [32.96, -12.86], - [32.97, -12.87], - [32.98, -12.88], - [32.99, -12.89], - [33.02, -12.9], - [33.03, -12.91], - [33.02, -12.93], - [33.01, -12.97], - [33.02, -12.98], - [33.01, -12.99], - [33, -13], - [32.99, -13.03], - [33, -13.05], - [32.99, -13.06], - [32.98, -13.08], - [32.97, -13.11], - [32.98, -13.12], - [32.99, -13.17], - [33, -13.18], - [33.01, -13.19], - [33.02, -13.21], - [33.01, -13.22], - [32.99, -13.23], - [32.98, -13.24], - [32.97, -13.25], - [32.96, -13.26], - [32.95, -13.27], - [32.94, -13.28], - [32.93, -13.31], - [32.99, -13.36], - [33, -13.37], - [33.02, -13.36], - [33.05, -13.35], - [33.1, -13.34], - [33.12, -13.35] - ], - "Likoma": [ - [34.59, -11.98], - [34.58, -11.99], - [34.57, -12], - [34.58, -12.03], - [34.59, -12.07], - [34.6, -12.08], - [34.64, -12.07], - [34.65, -12.06], - [34.66, -12.05], - [34.65, -11.99], - [34.64, -11.98], - [34.62, -11.97], - [34.6, -11.98], - [34.68, -12.09], - [34.69, -12.11], - [34.7, -12.12], - [34.71, -12.14], - [34.73, -12.13], - [34.75, -12.11], - [34.76, -12.1], - [34.77, -12.09], - [34.78, -12.08], - [34.79, -12.07], - [34.78, -12.02], - [34.77, -12.01], - [34.75, -12], - [34.71, -12.01], - [34.7, -12.02], - [34.69, -12.03], - [34.68, -12.06], - [34.67, -12.08], - [34.68, -12.09] - ], - "Lilongwe": [ - [34.09, -14.13], - [34.1, -14.11], - [34.11, -14.09], - [34.12, -14.08], - [34.13, -14.07], - [34.14, -14.06], - [34.13, -14.05], - [34.14, -14.04], - [34.15, -14.03], - [34.17, -14.02], - [34.18, -14], - [34.19, -13.98], - [34.2, -13.97], - [34.21, -13.94], - [34.2, -13.93], - [34.22, -13.94], - [34.23, -13.93], - [34.22, -13.92], - [34.23, -13.91], - [34.24, -13.9], - [34.27, -13.89], - [34.28, -13.88], - [34.27, -13.86], - [34.24, -13.87], - [34.22, -13.88], - [34.21, -13.89], - [34.2, -13.88], - [34.19, -13.87], - [34.2, -13.86], - [34.21, -13.85], - [34.22, -13.84], - [34.23, -13.83], - [34.24, -13.82], - [34.23, -13.8], - [34.22, -13.81], - [34.21, -13.82], - [34.2, -13.81], - [34.19, -13.8], - [34.17, -13.81], - [34.15, -13.82], - [34.14, -13.83], - [34.1, -13.84], - [34.09, -13.83], - [34.08, -13.84], - [34.07, -13.83], - [34.05, -13.84], - [34.04, -13.85], - [34.03, -13.84], - [34.02, -13.83], - [34.03, -13.82], - [34.02, -13.83], - [34.01, -13.81], - [34, -13.8], - [33.99, -13.79], - [33.95, -13.78], - [33.94, -13.77], - [33.93, -13.78], - [33.92, -13.77], - [33.87, -13.76], - [33.86, -13.77], - [33.85, -13.78], - [33.82, -13.77], - [33.81, -13.78], - [33.8, -13.77], - [33.77, -13.76], - [33.76, -13.75], - [33.75, -13.71], - [33.76, -13.69], - [33.75, -13.67], - [33.74, -13.68], - [33.71, -13.69], - [33.67, -13.7], - [33.61, -13.71], - [33.59, -13.72], - [33.58, -13.73], - [33.57, -13.72], - [33.56, -13.71], - [33.55, -13.72], - [33.51, -13.71], - [33.5, -13.7], - [33.49, -13.69], - [33.46, -13.68], - [33.45, -13.63], - [33.44, -13.59], - [33.45, -13.53], - [33.44, -13.5], - [33.42, -13.49], - [33.38, -13.5], - [33.37, -13.51], - [33.38, -13.52], - [33.37, -13.53], - [33.38, -13.54], - [33.37, -13.59], - [33.36, -13.6], - [33.34, -13.61], - [33.33, -13.62], - [33.32, -13.63], - [33.31, -13.64], - [33.3, -13.65], - [33.29, -13.68], - [33.28, -13.69], - [33.27, -13.71], - [33.28, -13.73], - [33.27, -13.77], - [33.26, -13.78], - [33.25, -13.82], - [33.26, -13.85], - [33.27, -13.87], - [33.28, -13.89], - [33.3, -13.9], - [33.31, -13.91], - [33.32, -13.94], - [33.33, -13.96], - [33.34, -13.97], - [33.35, -13.99], - [33.34, -14.02], - [33.33, -14.03], - [33.34, -14.05], - [33.35, -14.06], - [33.34, -14.1], - [33.33, -14.12], - [33.34, -14.15], - [33.35, -14.16], - [33.36, -14.21], - [33.38, -14.22], - [33.39, -14.24], - [33.4, -14.25], - [33.41, -14.27], - [33.42, -14.28], - [33.43, -14.31], - [33.44, -14.32], - [33.45, -14.33], - [33.46, -14.37], - [33.47, -14.38], - [33.48, -14.4], - [33.49, -14.41], - [33.5, -14.42], - [33.53, -14.43], - [33.55, -14.44], - [33.56, -14.46], - [33.57, -14.48], - [33.59, -14.49], - [33.6, -14.48], - [33.61, -14.49], - [33.62, -14.51], - [33.63, -14.53], - [33.62, -14.54], - [33.63, -14.57], - [33.64, -14.59], - [33.65, -14.6], - [33.66, -14.59], - [33.67, -14.58], - [33.66, -14.57], - [33.67, -14.54], - [33.68, -14.52], - [33.69, -14.51], - [33.7, -14.44], - [33.71, -14.42], - [33.72, -14.39], - [33.76, -14.38], - [33.78, -14.37], - [33.79, -14.36], - [33.8, -14.37], - [33.81, -14.34], - [33.82, -14.33], - [33.83, -14.32], - [33.84, -14.31], - [33.85, -14.32], - [33.86, -14.33], - [33.87, -14.32], - [33.89, -14.31], - [33.94, -14.3], - [33.95, -14.29], - [33.94, -14.27], - [33.95, -14.26], - [33.96, -14.22], - [33.95, -14.21], - [33.98, -14.2], - [33.99, -14.19], - [34, -14.2], - [34.01, -14.21], - [34.02, -14.2], - [34.03, -14.19], - [34.05, -14.18], - [34.06, -14.16], - [34.07, -14.14], - [34.09, -14.13] - ], - "Machinga": [ - [35.5, -15.23], - [35.51, -15.22], - [35.52, -15.21], - [35.8, -15.2], - [35.79, -15.17], - [35.87, -15], - [35.88, -14.98], - [35.92, -14.9], - [35.87, -14.68], - [35.86, -14.66], - [35.8, -14.6], - [35.77, -14.55], - [35.76, -14.56], - [35.75, -14.57], - [35.74, -14.59], - [35.71, -14.6], - [35.69, -14.59], - [35.66, -14.58], - [35.65, -14.59], - [35.63, -14.6], - [35.61, -14.59], - [35.6, -14.6], - [35.59, -14.61], - [35.57, -14.62], - [35.56, -14.64], - [35.55, -14.65], - [35.56, -14.68], - [35.55, -14.69], - [35.56, -14.7], - [35.55, -14.72], - [35.54, -14.73], - [35.53, -14.74], - [35.52, -14.73], - [35.51, -14.74], - [35.5, -14.75], - [35.49, -14.77], - [35.48, -14.78], - [35.47, -14.79], - [35.46, -14.8], - [35.44, -14.79], - [35.43, -14.78], - [35.41, -14.79], - [35.4, -14.78], - [35.39, -14.77], - [35.36, -14.76], - [35.35, -14.75], - [35.34, -14.74], - [35.33, -14.72], - [35.32, -14.71], - [35.31, -14.7], - [35.29, -14.71], - [35.28, -14.72], - [35.27, -14.73], - [35.28, -14.74], - [35.29, -14.81], - [35.3, -14.86], - [35.29, -14.88], - [35.28, -14.93], - [35.27, -14.95], - [35.28, -14.97], - [35.26, -14.98], - [35.25, -14.99], - [35.24, -15], - [35.23, -15.01], - [35.22, -15.03], - [35.21, -15.07], - [35.2, -15.12], - [35.19, -15.13], - [35.18, -15.14], - [35.17, -15.17], - [35.16, -15.2], - [35.17, -15.22], - [35.18, -15.23], - [35.19, -15.25], - [35.21, -15.24], - [35.22, -15.23], - [35.23, -15.22], - [35.24, -15.23], - [35.26, -15.24], - [35.3, -15.25], - [35.31, -15.24], - [35.3, -15.23], - [35.31, -15.22], - [35.32, -15.21], - [35.34, -15.2], - [35.42, -15.23], - [35.43, -15.24], - [35.44, -15.23], - [35.45, -15.24], - [35.46, -15.23] - ], - "Mangochi": [ - [34.82, -13.97], - [34.83, -13.98], - [34.84, -13.99], - [34.85, -14], - [34.84, -13.99], - [34.83, -13.97], - [34.82, -14.02], - [34.81, -14.01], - [34.82, -14.02], - [35.17, -14.37], - [35.16, -14.34], - [35.15, -14.33], - [35.14, -14.31], - [35.13, -14.3], - [35.11, -14.29], - [35.1, -14.28], - [35.09, -14.27], - [35.08, -14.25], - [35.07, -14.21], - [35.06, -14.2], - [35.04, -14.19], - [35.03, -14.18], - [35.04, -14.19], - [35.03, -14.18], - [35, -14.17], - [34.99, -14.16], - [34.98, -14.17], - [34.95, -14.16], - [34.94, -14.15], - [34.93, -14.14], - [34.92, -14.07], - [34.91, -14.06], - [34.92, -14.05], - [34.91, -14.04], - [34.9, -14.03], - [34.89, -14.02], - [34.88, -14.01], - [34.87, -14], - [34.85, -14.01], - [34.84, -14.02], - [34.83, -14.03], - [34.82, -14.04], - [34.83, -14.05], - [34.84, -14.06], - [34.85, -14.07], - [34.86, -14.09], - [34.87, -14.11], - [34.86, -14.12], - [34.83, -14.13], - [34.82, -14.14], - [34.81, -14.15], - [34.82, -14.19], - [34.81, -14.22], - [34.8, -14.25], - [34.79, -14.26], - [34.78, -14.27], - [34.76, -14.28], - [34.74, -14.29], - [34.73, -14.31], - [34.72, -14.33], - [34.74, -14.37], - [34.75, -14.38], - [34.74, -14.45], - [34.75, -14.47], - [34.76, -14.49], - [34.77, -14.5], - [34.78, -14.51], - [34.8, -14.59], - [34.86, -14.65], - [34.89, -14.68], - [34.93, -14.71], - [34.92, -14.72], - [34.93, -14.74], - [34.96, -14.75], - [34.97, -14.77], - [35.28, -14.78], - [35.27, -14.74], - [35.28, -14.73], - [35.29, -14.72], - [35.3, -14.7], - [35.31, -14.71], - [35.33, -14.72], - [35.34, -14.73], - [35.35, -14.74], - [35.36, -14.75], - [35.37, -14.77], - [35.4, -14.78], - [35.41, -14.79], - [35.42, -14.78], - [35.43, -14.79], - [35.44, -14.8], - [35.46, -14.79], - [35.48, -14.78], - [35.49, -14.77], - [35.5, -14.76], - [35.51, -14.75], - [35.52, -14.74], - [35.53, -14.73], - [35.54, -14.74], - [35.55, -14.73], - [35.56, -14.72], - [35.55, -14.7], - [35.56, -14.69], - [35.55, -14.67], - [35.56, -14.65], - [35.57, -14.64], - [35.58, -14.61], - [35.6, -14.6], - [35.61, -14.59], - [35.62, -14.6], - [35.63, -14.59], - [35.65, -14.58], - [35.66, -14.59], - [35.7, -14.6], - [35.71, -14.59], - [35.75, -14.58], - [35.76, -14.57], - [35.77, -14.56], - [35.71, -14.48], - [35.62, -14.37], - [35.61, -14.36], - [35.52, -14.26], - [35.49, -14.17], - [35.39, -14.06], - [35.36, -14.03], - [35.23, -13.88], - [35.16, -13.79], - [35.09, -13.7], - [35, -13.61], - [34.93, -13.55], - [34.87, -13.48], - [34.86, -13.52], - [34.87, -13.53], - [34.86, -13.54], - [34.85, -13.55], - [34.86, -13.56], - [34.85, -13.57], - [34.86, -13.58], - [34.85, -13.59], - [34.86, -13.62], - [34.85, -13.63], - [34.86, -13.64], - [34.85, -13.65], - [34.86, -13.66], - [34.85, -13.67], - [34.84, -13.68], - [34.85, -13.69], - [34.84, -13.7], - [34.85, -13.71], - [34.86, -13.72], - [34.87, -13.73], - [34.9, -13.74], - [34.91, -13.73], - [35.06, -13.74], - [35.07, -13.75], - [35.08, -13.78], - [35.09, -13.82], - [35.08, -13.83], - [35.09, -13.84], - [35.1, -13.85], - [35.11, -13.86], - [35.12, -13.89], - [35.13, -13.93], - [35.12, -13.95], - [35.11, -13.96], - [35.12, -13.97], - [35.14, -13.98], - [35.15, -14], - [35.16, -14.02], - [35.17, -14.03], - [35.18, -14.04], - [35.19, -14.08], - [35.18, -14.09], - [35.19, -14.13], - [35.2, -14.15], - [35.19, -14.16], - [35.2, -14.17], - [35.21, -14.18], - [35.22, -14.19], - [35.23, -14.21], - [35.22, -14.22], - [35.23, -14.24], - [35.24, -14.26], - [35.25, -14.27], - [35.26, -14.29], - [35.27, -14.31], - [35.28, -14.32], - [35.29, -14.34], - [35.3, -14.35], - [35.29, -14.36], - [35.3, -14.37], - [35.28, -14.38], - [35.27, -14.39], - [35.26, -14.4], - [35.25, -14.41], - [35.24, -14.42], - [35.23, -14.43], - [35.22, -14.41], - [35.23, -14.4], - [35.22, -14.39], - [35.21, -14.38], - [35.2, -14.37] - ], - "Mchinji": [ - [33.26, -13.85], - [33.25, -13.84], - [33.26, -13.82], - [33.27, -13.77], - [33.28, -13.76], - [33.27, -13.73], - [33.28, -13.71], - [33.29, -13.69], - [33.3, -13.68], - [33.31, -13.65], - [33.32, -13.64], - [33.33, -13.62], - [33.3, -13.61], - [33.29, -13.6], - [33.28, -13.58], - [33.25, -13.57], - [33.24, -13.55], - [33.23, -13.54], - [33.22, -13.53], - [33.21, -13.52], - [33.19, -13.51], - [33.18, -13.5], - [33.17, -13.46], - [33.16, -13.44], - [33.15, -13.41], - [33.16, -13.4], - [33.15, -13.39], - [33.16, -13.36], - [33.15, -13.35], - [33.11, -13.34], - [33.1, -13.35], - [33.05, -13.36], - [33.02, -13.37], - [33, -13.36], - [32.93, -13.38], - [32.92, -13.39], - [32.91, -13.42], - [32.9, -13.43], - [32.89, -13.45], - [32.88, -13.46], - [32.87, -13.47], - [32.86, -13.46], - [32.85, -13.47], - [32.84, -13.5], - [32.85, -13.51], - [32.84, -13.52], - [32.83, -13.53], - [32.82, -13.54], - [32.8, -13.55], - [32.78, -13.56], - [32.76, -13.57], - [32.75, -13.58], - [32.74, -13.59], - [32.73, -13.58], - [32.71, -13.57], - [32.7, -13.58], - [32.68, -13.59], - [32.69, -13.6], - [32.68, -13.61], - [32.67, -13.62], - [32.69, -13.63], - [32.7, -13.64], - [32.72, -13.65], - [32.75, -13.64], - [32.78, -13.65], - [32.8, -13.66], - [32.81, -13.68], - [32.82, -13.69], - [32.83, -13.7], - [32.84, -13.71], - [32.85, -13.72], - [32.84, -13.73], - [32.8, -13.74], - [32.79, -13.75], - [32.78, -13.76], - [32.77, -13.78], - [32.78, -13.79], - [32.79, -13.78], - [32.8, -13.79], - [32.81, -13.8], - [32.82, -13.79], - [32.85, -13.8], - [32.88, -13.81], - [32.89, -13.82], - [32.9, -13.83], - [32.91, -13.86], - [32.92, -13.87], - [32.93, -13.88], - [32.95, -13.89], - [32.94, -13.95], - [32.95, -13.94], - [32.99, -13.95], - [33, -13.96], - [32.99, -14.01], - [33, -14.02], - [33.01, -14.03], - [33.03, -14.04], - [33.04, -14.05], - [33.05, -14.04], - [33.06, -14.03], - [33.07, -13.99], - [33.08, -13.98], - [33.09, -13.97], - [33.1, -13.96], - [33.14, -13.95], - [33.15, -13.94], - [33.16, -13.95], - [33.18, -13.96], - [33.19, -13.97], - [33.2, -13.99], - [33.21, -14], - [33.25, -14.01], - [33.26, -14.02], - [33.27, -14.03], - [33.28, -14.02], - [33.29, -14.03], - [33.3, -14.04], - [33.31, -14.05], - [33.3, -14.06], - [33.31, -14.07], - [33.32, -14.08], - [33.31, -14.09], - [33.3, -14.11], - [33.31, -14.12], - [33.3, -14.13], - [33.31, -14.15], - [33.32, -14.16], - [33.33, -14.18], - [33.34, -14.19], - [33.33, -14.2], - [33.34, -14.21], - [33.35, -14.22], - [33.36, -14.21], - [33.35, -14.2], - [33.34, -14.16], - [33.33, -14.15], - [33.34, -14.12], - [33.35, -14.1], - [33.34, -14.06], - [33.33, -14.04], - [33.34, -14.02], - [33.35, -14.01], - [33.34, -13.99], - [33.33, -13.97], - [33.32, -13.96], - [33.31, -13.94], - [33.3, -13.91], - [33.29, -13.89], - [33.27, -13.88], - [33.26, -13.87] - ], - "Mulanje": [ - [35.67, -16.1], - [35.68, -16.11], - [35.69, -16.1], - [35.71, -16.09], - [35.73, -16.08], - [35.75, -16.07], - [35.76, -16.08], - [35.77, -16.07], - [35.78, -16.06], - [35.79, -16.05], - [35.8, -16.04], - [35.81, -16.03], - [35.82, -16.02], - [35.81, -16], - [35.8, -15.93], - [35.76, -15.92], - [35.77, -15.9], - [35.76, -15.89], - [35.74, -15.87], - [35.72, -15.86], - [35.71, -15.85], - [35.69, -15.84], - [35.68, -15.83], - [35.61, -15.85], - [35.65, -15.89], - [35.6, -15.86], - [35.58, -15.88], - [35.57, -15.86], - [35.56, -15.85], - [35.55, -15.84], - [35.54, -15.83], - [35.53, -15.82], - [35.52, -15.81], - [35.51, -15.7], - [35.5, -15.69], - [35.51, -15.67], - [35.52, -15.66], - [35.53, -15.64], - [35.54, -15.62], - [35.53, -15.61], - [35.52, -15.6], - [35.51, -15.61], - [35.49, -15.62], - [35.48, -15.63], - [35.47, -15.65], - [35.46, -15.66], - [35.45, -15.67], - [35.42, -15.68], - [35.41, -15.67], - [35.4, -15.66], - [35.39, -15.67], - [35.38, -15.68], - [35.31, -15.71], - [35.3, -15.74], - [35.31, -15.77], - [35.32, -15.87], - [35.33, -15.96], - [35.32, -15.97], - [35.31, -15.98], - [35.32, -16], - [35.31, -16.02], - [35.32, -16.04], - [35.31, -16.05], - [35.32, -16.06], - [35.33, -16.07], - [35.32, -16.08], - [35.33, -16.1], - [35.32, -16.13], - [35.31, -16.14], - [35.3, -16.15], - [35.29, -16.16], - [35.28, -16.18], - [35.29, -16.19], - [35.3, -16.2], - [35.31, -16.21], - [35.32, -16.2], - [35.33, -16.19], - [35.35, -16.18], - [35.36, -16.17], - [35.37, -16.16], - [35.38, -16.15], - [35.4, -16.14], - [35.41, -16.13], - [35.42, -16.12], - [35.43, -16.11], - [35.44, -16.12], - [35.45, -16.11], - [35.46, -16.12], - [35.49, -16.13], - [35.5, -16.15], - [35.51, -16.16], - [35.52, -16.17], - [35.53, -16.16], - [35.54, -16.15], - [35.55, -16.14], - [35.56, -16.13], - [35.58, -16.12], - [35.59, -16.13], - [35.61, -16.12], - [35.62, -16.13], - [35.63, -16.12], - [35.64, -16.11], - [35.65, -16.1] - ], - "Mwanza": [ - [34.51, -15.48], - [34.5, -15.47], - [34.51, -15.46], - [34.5, -15.45], - [34.49, -15.43], - [34.5, -15.42], - [34.49, -15.41], - [34.48, -15.42], - [34.47, -15.43], - [34.45, -15.42], - [34.44, -15.43], - [34.43, -15.47], - [34.44, -15.52], - [34.45, -15.59], - [34.46, -15.61], - [34.44, -15.62], - [34.43, -15.63], - [34.44, -15.66], - [34.42, -15.67], - [34.41, -15.68], - [34.4, -15.69], - [34.39, -15.68], - [34.38, -15.71], - [34.37, -15.73], - [34.36, -15.74], - [34.4, -15.76], - [34.43, -15.77], - [34.46, -15.79], - [34.49, -15.8], - [34.51, -15.81], - [34.73, -15.82], - [34.72, -15.81], - [34.7, -15.8], - [34.69, -15.79], - [34.68, -15.78], - [34.69, -15.77], - [34.68, -15.76], - [34.67, -15.75], - [34.66, -15.74], - [34.65, -15.73], - [34.64, -15.72], - [34.63, -15.71], - [34.62, -15.7], - [34.61, -15.69], - [34.6, -15.68], - [34.59, -15.66], - [34.58, -15.64], - [34.59, -15.63], - [34.58, -15.62], - [34.57, -15.58], - [34.56, -15.56], - [34.55, -15.55], - [34.54, -15.53], - [34.53, -15.5], - [34.52, -15.49], - [34.51, -15.48] - ], - "Mzimba": [ - [33.93, -11], - [33.92, -11.02], - [33.93, -11.03], - [33.91, -11.04], - [33.9, -11.03], - [33.89, -11.04], - [33.88, -11.03], - [33.87, -11.04], - [33.86, -11.03], - [33.82, -11.02], - [33.8, -11.03], - [33.79, -11.02], - [33.78, -11.03], - [33.74, -11.04], - [33.73, -11.05], - [33.74, -11.06], - [33.73, -11.09], - [33.72, -11.1], - [33.7, -11.11], - [33.69, -11.1], - [33.68, -11.08], - [33.67, -11.07], - [33.66, -11.06], - [33.65, -11.07], - [33.58, -11.06], - [33.57, -11.05], - [33.56, -11.04], - [33.55, -11.03], - [33.53, -11.04], - [33.52, -11.05], - [33.51, -11.06], - [33.5, -11.08], - [33.49, -11.09], - [33.48, -11.1], - [33.47, -11.11], - [33.46, -11.12], - [33.45, -11.13], - [33.43, -11.12], - [33.44, -11.11], - [33.43, -11.07], - [33.44, -11.06], - [33.43, -11.04], - [33.42, -11.03], - [33.4, -11.04], - [33.38, -11.03], - [33.37, -11.02], - [33.34, -11.01], - [33.32, -11], - [33.31, -11.01], - [33.32, -11.03], - [33.33, -11.05], - [33.34, -11.07], - [33.35, -11.08], - [33.36, -11.09], - [33.37, -11.1], - [33.38, -11.12], - [33.39, -11.14], - [33.4, -11.15], - [33.39, -11.18], - [33.38, -11.21], - [33.37, -11.24], - [33.36, -11.25], - [33.35, -11.26], - [33.34, -11.29], - [33.33, -11.31], - [33.32, -11.32], - [33.31, -11.33], - [33.3, -11.37], - [33.29, -11.38], - [33.28, -11.44], - [33.27, -11.43], - [33.26, -11.42], - [33.24, -11.41], - [33.23, -11.42], - [33.24, -11.44], - [33.25, -11.45], - [33.24, -11.46], - [33.23, -11.48], - [33.24, -11.49], - [33.25, -11.5], - [33.24, -11.54], - [33.23, -11.55], - [33.24, -11.59], - [33.25, -11.58], - [33.29, -11.59], - [33.31, -11.6], - [33.32, -11.61], - [33.31, -11.66], - [33.32, -11.69], - [33.31, -11.7], - [33.32, -11.71], - [33.31, -11.72], - [33.32, -11.73], - [33.33, -11.76], - [33.32, -11.77], - [33.33, -11.78], - [33.32, -11.84], - [33.31, -11.85], - [33.32, -11.88], - [33.31, -11.95], - [33.3, -12.02], - [33.29, -12.03], - [33.28, -12.06], - [33.27, -12.07], - [33.26, -12.11], - [33.27, -12.15], - [33.28, -12.16], - [33.29, -12.17], - [33.31, -12.18], - [33.32, -12.26], - [33.33, -12.27], - [33.34, -12.28], - [33.35, -12.3], - [33.36, -12.31], - [33.37, -12.32], - [33.38, -12.35], - [33.39, -12.34], - [33.44, -12.33], - [33.49, -12.34], - [33.54, -12.35], - [33.55, -12.36], - [33.56, -12.37], - [33.59, -12.42], - [33.57, -12.45], - [33.55, -12.46], - [33.53, -12.47], - [33.54, -12.48], - [33.55, -12.49], - [33.56, -12.53], - [33.57, -12.55], - [33.58, -12.56], - [33.55, -12.59], - [33.56, -12.64], - [33.57, -12.68], - [33.58, -12.69], - [33.59, -12.68], - [33.6, -12.69], - [33.66, -12.73], - [33.7, -12.72], - [33.71, -12.71], - [33.72, -12.7], - [33.74, -12.69], - [33.77, -12.68], - [33.78, -12.7], - [33.79, -12.72], - [33.8, -12.71], - [33.85, -12.7], - [33.86, -12.69], - [33.87, -12.67], - [33.88, -12.66], - [33.89, -12.65], - [33.9, -12.64], - [33.91, -12.63], - [33.92, -12.64], - [33.93, -12.63], - [33.92, -12.62], - [33.97, -12.61], - [33.98, -12.6], - [33.99, -12.59], - [34, -12.58], - [34.03, -12.57], - [34.04, -12.58], - [34.06, -12.57], - [34.07, -12.56], - [34.06, -12.57], - [34.07, -12.56], - [34.06, -12.54], - [34.07, -12.53], - [34.08, -12.52], - [34.1, -12.51], - [34.09, -12.5], - [34.08, -12.49], - [34.07, -12.5], - [34.06, -12.51], - [34.04, -12.52], - [34.03, -12.51], - [34.02, -12.52], - [34.01, -12.51], - [33.99, -12.5], - [33.98, -12.49], - [33.97, -12.48], - [33.95, -12.47], - [33.94, -12.48], - [33.93, -12.49], - [33.91, -12.48], - [33.9, -12.47], - [33.89, -12.46], - [33.88, -12.42], - [33.89, -12.4], - [33.88, -12.36], - [33.87, -12.35], - [33.86, -12.34], - [33.87, -12.33], - [33.86, -12.32], - [33.83, -12.31], - [33.79, -12.3], - [33.78, -12.29], - [33.77, -12.3], - [33.76, -12.29], - [33.75, -12.25], - [33.76, -12.24], - [33.75, -12.23], - [33.76, -12.22], - [33.78, -12.21], - [33.79, -12.2], - [33.8, -12.19], - [33.82, -12.18], - [33.83, -12.17], - [33.81, -12.16], - [33.8, -12.17], - [33.78, -12.18], - [33.77, -12.17], - [33.76, -12.16], - [33.75, -12.17], - [33.74, -12.16], - [33.73, -12.15], - [33.72, -12.14], - [33.71, -12.13], - [33.7, -12.12], - [33.69, -12.11], - [33.71, -12.1], - [33.72, -12.09], - [33.73, -12.08], - [33.76, -12.07], - [33.78, -12.06], - [33.79, -12.05], - [33.8, -12.04], - [33.81, -12.03], - [33.83, -12.02], - [33.85, -12.01], - [33.83, -12], - [33.82, -11.99], - [33.8, -11.98], - [33.79, -11.97], - [33.8, -11.96], - [33.81, -11.95], - [33.8, -11.94], - [33.79, -11.92], - [33.78, -11.9], - [33.79, -11.89], - [33.8, -11.88], - [33.81, -11.84], - [33.82, -11.83], - [33.81, -11.81], - [33.8, -11.8], - [33.79, -11.79], - [33.8, -11.77], - [33.79, -11.76], - [33.77, -11.75], - [33.75, -11.74], - [33.76, -11.73], - [33.75, -11.68], - [33.74, -11.67], - [33.75, -11.65], - [33.76, -11.64], - [33.77, -11.63], - [33.78, -11.61], - [33.79, -11.6], - [33.8, -11.59], - [33.81, -11.58], - [33.83, -11.57], - [33.84, -11.56], - [33.85, -11.55], - [33.86, -11.54], - [33.87, -11.53], - [33.88, -11.54], - [33.91, -11.55], - [33.93, -11.56], - [33.94, -11.55], - [33.95, -11.54], - [33.96, -11.53], - [33.97, -11.51], - [33.98, -11.48], - [33.99, -11.47], - [34, -11.46], - [34.02, -11.47], - [34.04, -11.48], - [34.05, -11.47], - [34.06, -11.46], - [34.07, -11.47], - [34.08, -11.46], - [34.09, -11.47], - [34.1, -11.46], - [34.09, -11.44], - [34.08, -11.39], - [34.07, -11.38], - [34.06, -11.39], - [34.05, -11.38], - [34.04, -11.36], - [34.03, -11.27], - [34.02, -11.26], - [34.01, -11.22], - [34.02, -11.21], - [34.03, -11.18], - [34.04, -11.17], - [34.05, -11.15], - [34.06, -11.12], - [34.05, -11.11], - [34.06, -11.1], - [34.05, -11.08], - [34.04, -11.05], - [34.03, -11.04], - [34.02, -11.03], - [34.01, -11.02], - [34, -11.01], - [33.99, -11], - [33.98, -10.99], - [33.97, -10.98], - [33.96, -10.97], - [33.95, -10.96], - [33.94, -10.97], - [33.93, -10.99], - [33.94, -11] - ], - "Nkhata Bay": [ - [34.24, -11.12], - [34.23, -11.11], - [34.22, -11.09], - [34.21, -11.02], - [34.22, -11.01], - [34.21, -10.97], - [34.2, -10.98], - [34.19, -11], - [34.18, -11.01], - [34.16, -11.02], - [34.14, -11.03], - [34.12, -11.04], - [34.11, -11.05], - [34.1, -11.06], - [34.08, -11.07], - [34.07, -11.08], - [34.06, -11.09], - [34.05, -11.1], - [34.06, -11.12], - [34.05, -11.13], - [34.04, -11.15], - [34.03, -11.18], - [34.02, -11.19], - [34.01, -11.21], - [34.02, -11.22], - [34.03, -11.26], - [34.04, -11.27], - [34.05, -11.36], - [34.06, -11.39], - [34.07, -11.38], - [34.08, -11.39], - [34.09, -11.4], - [34.1, -11.44], - [34.09, -11.46], - [34.08, -11.47], - [34.07, -11.46], - [34.06, -11.47], - [34.05, -11.48], - [34.04, -11.47], - [34, -11.46], - [33.99, -11.47], - [33.98, -11.48], - [33.97, -11.49], - [33.96, -11.51], - [33.95, -11.54], - [33.94, -11.55], - [33.93, -11.56], - [33.92, -11.55], - [33.91, -11.54], - [33.87, -11.53], - [33.86, -11.54], - [33.85, -11.55], - [33.84, -11.56], - [33.83, -11.57], - [33.82, -11.58], - [33.8, -11.59], - [33.79, -11.6], - [33.78, -11.61], - [33.77, -11.62], - [33.78, -11.63], - [33.76, -11.64], - [33.75, -11.65], - [33.74, -11.66], - [33.75, -11.67], - [33.76, -11.68], - [33.75, -11.73], - [33.76, -11.75], - [33.77, -11.76], - [33.79, -11.77], - [33.8, -11.8], - [33.81, -11.81], - [33.82, -11.82], - [33.81, -11.83], - [33.8, -11.84], - [33.79, -11.88], - [33.78, -11.89], - [33.79, -11.9], - [33.8, -11.92], - [33.81, -11.95], - [33.8, -11.96], - [33.79, -11.97], - [33.8, -11.98], - [33.81, -11.99], - [33.82, -12], - [33.83, -12.01], - [33.85, -12.02], - [33.83, -12.03], - [33.8, -12.04], - [33.79, -12.05], - [33.78, -12.06], - [33.77, -12.07], - [33.75, -12.08], - [33.73, -12.07], - [33.72, -12.08], - [33.71, -12.1], - [33.7, -12.11], - [33.69, -12.12], - [33.7, -12.13], - [33.72, -12.14], - [33.73, -12.15], - [33.74, -12.16], - [33.75, -12.17], - [33.76, -12.16], - [33.77, -12.17], - [33.78, -12.18], - [33.79, -12.17], - [33.81, -12.16], - [33.82, -12.17], - [33.84, -12.16], - [33.85, -12.17], - [33.86, -12.16], - [33.85, -12.17], - [33.86, -12.16], - [33.87, -12.17], - [33.88, -12.19], - [33.9, -12.2], - [33.91, -12.21], - [33.94, -12.22], - [33.96, -12.23], - [33.97, -12.22], - [33.98, -12.23], - [33.99, -12.22], - [34, -12.23], - [34.01, -12.24], - [34.02, -12.23], - [34.03, -12.19], - [34.04, -12.15], - [34.05, -12.11], - [34.06, -12.1], - [34.05, -12.05], - [34.06, -12.04], - [34.05, -12.03], - [34.06, -12.02], - [34.07, -12.01], - [34.08, -12], - [34.09, -11.98], - [34.1, -11.97], - [34.11, -11.96], - [34.12, -11.95], - [34.14, -11.94], - [34.16, -11.93], - [34.18, -11.92], - [34.17, -11.91], - [34.18, -11.87], - [34.17, -11.86], - [34.18, -11.85], - [34.19, -11.81], - [34.2, -11.8], - [34.22, -11.79], - [34.24, -11.78], - [34.25, -11.77], - [34.26, -11.75], - [34.27, -11.74], - [34.29, -11.73], - [34.3, -11.72], - [34.31, -11.71], - [34.32, -11.7], - [34.33, -11.68], - [34.32, -11.66], - [34.31, -11.65], - [34.3, -11.62], - [34.31, -11.61], - [34.3, -11.6], - [34.29, -11.56], - [34.28, -11.54], - [34.27, -11.52], - [34.28, -11.51], - [34.27, -11.5], - [34.28, -11.49], - [34.27, -11.46], - [34.28, -11.45], - [34.27, -11.44], - [34.28, -11.43], - [34.27, -11.42], - [34.28, -11.4], - [34.27, -11.39], - [34.26, -11.37], - [34.25, -11.32], - [34.24, -11.31], - [34.23, -11.3], - [34.22, -11.29], - [34.23, -11.25], - [34.22, -11.23], - [34.21, -11.22], - [34.22, -11.15], - [34.23, -11.14], - [34.24, -11.13], - [34.23, -11.12] - ], - "Nkhotakota": [ - [34.13, -13.5], - [34.15, -13.49], - [34.19, -13.48], - [34.2, -13.47], - [34.24, -13.46], - [34.25, -13.45], - [34.27, -13.46], - [34.28, -13.45], - [34.29, -13.44], - [34.31, -13.43], - [34.32, -13.42], - [34.31, -13.4], - [34.3, -13.38], - [34.31, -13.37], - [34.3, -13.36], - [34.31, -13.32], - [34.32, -13.31], - [34.33, -13.3], - [34.34, -13.29], - [34.35, -13.27], - [34.34, -13.26], - [34.35, -13.25], - [34.34, -13.24], - [34.35, -13.23], - [34.34, -13.22], - [34.33, -13.19], - [34.34, -13.18], - [34.33, -13.15], - [34.34, -13.14], - [34.33, -13.13], - [34.32, -13.09], - [34.33, -13.08], - [34.32, -13.07], - [34.33, -13.06], - [34.32, -12.99], - [34.31, -12.98], - [34.3, -12.95], - [34.29, -12.87], - [34.28, -12.86], - [34.27, -12.85], - [34.26, -12.84], - [34.27, -12.8], - [34.28, -12.79], - [34.27, -12.78], - [34.28, -12.76], - [34.27, -12.75], - [34.25, -12.74], - [34.24, -12.73], - [34.23, -12.72], - [34.22, -12.71], - [34.21, -12.7], - [34.2, -12.69], - [34.19, -12.68], - [34.18, -12.66], - [34.17, -12.61], - [34.18, -12.57], - [34.19, -12.55], - [34.2, -12.54], - [34.19, -12.51], - [34.2, -12.5], - [34.19, -12.49], - [34.18, -12.48], - [34.17, -12.42], - [34.16, -12.41], - [34.15, -12.4], - [34.11, -12.39], - [34.09, -12.38], - [34.08, -12.37], - [34.07, -12.36], - [34.06, -12.35], - [34.05, -12.34], - [34.04, -12.32], - [34.03, -12.3], - [34.02, -12.27], - [34.01, -12.24], - [34, -12.23], - [33.99, -12.22], - [33.98, -12.23], - [33.97, -12.22], - [33.96, -12.23], - [33.95, -12.22], - [33.94, -12.21], - [33.91, -12.22], - [33.9, -12.2], - [33.89, -12.19], - [33.87, -12.18], - [33.86, -12.16], - [33.85, -12.17], - [33.86, -12.16], - [33.85, -12.17], - [33.84, -12.16], - [33.83, -12.17], - [33.82, -12.18], - [33.81, -12.19], - [33.8, -12.2], - [33.79, -12.21], - [33.77, -12.22], - [33.76, -12.23], - [33.75, -12.24], - [33.76, -12.25], - [33.77, -12.3], - [33.78, -12.29], - [33.79, -12.3], - [33.8, -12.31], - [33.83, -12.32], - [33.86, -12.33], - [33.87, -12.35], - [33.88, -12.36], - [33.89, -12.37], - [33.88, -12.41], - [33.89, -12.42], - [33.9, -12.46], - [33.91, -12.47], - [33.92, -12.48], - [33.91, -12.49], - [33.93, -12.48], - [33.94, -12.47], - [33.95, -12.48], - [33.97, -12.49], - [33.98, -12.5], - [33.99, -12.51], - [34.02, -12.52], - [34.03, -12.51], - [34.04, -12.52], - [34.05, -12.51], - [34.06, -12.5], - [34.07, -12.49], - [34.09, -12.5], - [34.1, -12.51], - [34.09, -12.52], - [34.07, -12.53], - [34.06, -12.54], - [34.07, -12.55], - [34.06, -12.56], - [34.07, -12.57], - [34.06, -12.58], - [34.03, -12.57], - [34.02, -12.58], - [34, -12.59], - [33.98, -12.6], - [33.97, -12.61], - [33.96, -12.62], - [33.93, -12.63], - [33.92, -12.64], - [33.91, -12.63], - [33.9, -12.64], - [33.89, -12.65], - [33.88, -12.66], - [33.87, -12.67], - [33.86, -12.68], - [33.85, -12.69], - [33.84, -12.71], - [33.83, -12.72], - [33.84, -12.73], - [33.83, -12.74], - [33.82, -12.75], - [33.81, -12.8], - [33.82, -12.81], - [33.81, -12.83], - [33.82, -12.84], - [33.83, -12.85], - [33.84, -12.84], - [33.9, -12.85], - [33.91, -12.84], - [33.92, -12.85], - [33.95, -12.86], - [33.96, -12.88], - [33.97, -12.89], - [33.98, -12.9], - [33.99, -12.91], - [33.98, -12.92], - [34, -12.93], - [33.99, -12.95], - [33.98, -12.96], - [33.97, -12.95], - [33.96, -12.96], - [33.95, -12.97], - [33.94, -12.98], - [33.93, -12.99], - [33.92, -13.01], - [33.91, -13.03], - [33.92, -13.07], - [33.93, -13.11], - [33.94, -13.12], - [33.95, -13.13], - [33.96, -13.14], - [33.95, -13.15], - [33.94, -13.17], - [33.95, -13.18], - [33.96, -13.17], - [33.97, -13.18], - [33.98, -13.17], - [33.99, -13.18], - [34, -13.16], - [33.99, -13.15], - [34, -13.14], - [34.01, -13.13], - [34.04, -13.12], - [34.06, -13.13], - [34.05, -13.14], - [34.06, -13.18], - [34.07, -13.17], - [34.08, -13.16], - [34.11, -13.26], - [34.1, -13.27], - [34.09, -13.28], - [34.1, -13.3], - [34.11, -13.34], - [34.12, -13.35], - [34.11, -13.36], - [34.12, -13.42], - [34.13, -13.5] - ], - "Nneno": [ - [34.49, -15.41], - [34.5, -15.42], - [34.49, -15.43], - [34.5, -15.44], - [34.51, -15.46], - [34.5, -15.47], - [34.51, -15.48], - [34.52, -15.49], - [34.53, -15.5], - [34.54, -15.51], - [34.55, -15.53], - [34.56, -15.55], - [34.57, -15.56], - [34.58, -15.58], - [34.59, -15.63], - [34.58, -15.64], - [34.59, -15.65], - [34.6, -15.66], - [34.61, -15.68], - [34.62, -15.69], - [34.63, -15.7], - [34.62, -15.71], - [34.64, -15.72], - [34.65, -15.73], - [34.66, -15.74], - [34.67, -15.75], - [34.68, -15.76], - [34.69, -15.77], - [34.68, -15.78], - [34.69, -15.79], - [34.7, -15.8], - [34.71, -15.81], - [34.73, -15.82], - [34.74, -15.81], - [34.73, -15.74], - [34.72, -15.71], - [34.73, -15.69], - [34.74, -15.68], - [34.76, -15.67], - [34.75, -15.62], - [34.76, -15.58], - [34.77, -15.57], - [34.78, -15.56], - [34.79, -15.55], - [34.8, -15.54], - [34.81, -15.53], - [34.83, -15.52], - [34.84, -15.5], - [34.85, -15.49], - [34.86, -15.48], - [34.87, -15.46], - [34.86, -15.45], - [34.87, -15.44], - [34.88, -15.43], - [34.89, -15.41], - [34.9, -15.39], - [34.91, -15.38], - [34.92, -15.37], - [34.93, -15.36], - [34.95, -15.35], - [34.98, -15.36], - [34.99, -15.35], - [35, -15.34], - [35.01, -15.33], - [35.04, -15.32], - [34.81, -15.33], - [34.8, -15.32], - [34.81, -15.31], - [34.8, -15.29], - [34.79, -15.27], - [34.78, -15.26], - [34.79, -15.25], - [34.78, -15.26], - [34.77, -15.25], - [34.71, -15.24], - [34.69, -15.23], - [34.68, -15.24], - [34.67, -15.23], - [34.64, -15.22], - [34.63, -15.23], - [34.62, -15.22], - [34.61, -15.21], - [34.59, -15.22], - [34.6, -15.23], - [34.59, -15.29], - [34.58, -15.3], - [34.57, -15.31], - [34.58, -15.32], - [34.57, -15.33], - [34.56, -15.34], - [34.55, -15.33], - [34.53, -15.34], - [34.52, -15.35], - [34.51, -15.4], - [34.52, -15.41] - ], - "Nsanje": [ - [35.24, -16.4], - [35.22, -16.39], - [35.21, -16.38], - [35.2, -16.37], - [35.16, -16.36], - [35.15, -16.35], - [35.14, -16.33], - [35.12, -16.32], - [35.11, -16.31], - [35.1, -16.32], - [35.09, -16.34], - [35.1, -16.35], - [35.09, -16.36], - [35.08, -16.4], - [35.07, -16.43], - [35.06, -16.48], - [35.05, -16.5], - [35.04, -16.51], - [35.03, -16.52], - [35.02, -16.53], - [35.01, -16.54], - [35, -16.55], - [34.99, -16.56], - [34.98, -16.57], - [34.97, -16.58], - [34.98, -16.59], - [34.97, -16.6], - [34.98, -16.61], - [34.97, -16.62], - [34.96, -16.63], - [34.94, -16.64], - [34.93, -16.65], - [34.92, -16.66], - [34.91, -16.67], - [34.9, -16.68], - [34.89, -16.69], - [34.91, -16.7], - [34.92, -16.72], - [34.93, -16.75], - [34.94, -16.74], - [34.97, -16.75], - [34.99, -16.76], - [35, -16.79], - [35.01, -16.8], - [35.02, -16.81], - [35.04, -16.82], - [35.05, -16.83], - [35.06, -16.84], - [35.07, -16.83], - [35.08, -16.82], - [35.09, -16.83], - [35.1, -16.82], - [35.14, -16.83], - [35.15, -16.84], - [35.16, -16.85], - [35.15, -16.86], - [35.16, -16.89], - [35.17, -16.92], - [35.16, -16.94], - [35.15, -16.95], - [35.14, -16.96], - [35.13, -16.97], - [35.12, -16.98], - [35.1, -16.99], - [35.09, -16.98], - [35.08, -16.99], - [35.06, -17], - [35.05, -17.01], - [35.06, -17.02], - [35.07, -17.05], - [35.08, -17.07], - [35.09, -17.06], - [35.08, -17.07], - [35.09, -17.08], - [35.1, -17.09], - [35.09, -17.1], - [35.08, -17.11], - [35.09, -17.12], - [35.1, -17.13], - [35.31, -17.12], - [35.3, -17.11], - [35.31, -17.1], - [35.3, -17.09], - [35.31, -17.08], - [35.3, -17.06], - [35.29, -17.04], - [35.3, -17.03], - [35.29, -17.01], - [35.3, -17], - [35.31, -16.98], - [35.3, -16.97], - [35.29, -16.96], - [35.28, -16.97], - [35.27, -16.96], - [35.26, -16.95], - [35.27, -16.94], - [35.28, -16.91], - [35.29, -16.9], - [35.27, -16.89], - [35.28, -16.88], - [35.29, -16.87], - [35.3, -16.86], - [35.31, -16.85], - [35.3, -16.84], - [35.31, -16.83], - [35.3, -16.81], - [35.29, -16.8], - [35.3, -16.77], - [35.29, -16.76], - [35.28, -16.75], - [35.29, -16.74], - [35.28, -16.73], - [35.29, -16.72], - [35.28, -16.71], - [35.27, -16.7], - [35.26, -16.69], - [35.25, -16.68], - [35.24, -16.67], - [35.23, -16.66], - [35.22, -16.65], - [35.21, -16.64], - [35.19, -16.63], - [35.18, -16.62], - [35.17, -16.61], - [35.16, -16.6], - [35.15, -16.59], - [35.14, -16.57], - [35.15, -16.56], - [35.16, -16.55], - [35.17, -16.54], - [35.18, -16.53], - [35.19, -16.52], - [35.21, -16.51], - [35.22, -16.5], - [35.23, -16.49], - [35.25, -16.48], - [35.26, -16.47], - [35.27, -16.44], - [35.26, -16.43], - [35.25, -16.41], - [35.24, -16.4] - ], - "Ntcheu": [ - [34.81, -15.33], - [34.82, -15.32], - [34.83, -15.31], - [34.84, -15.28], - [34.83, -15.27], - [34.84, -15.25], - [34.85, -15.23], - [34.84, -15.22], - [34.86, -15.13], - [34.89, -15.02], - [34.9, -15], - [34.91, -14.94], - [34.93, -14.88], - [34.94, -14.85], - [34.95, -14.86], - [34.96, -14.85], - [34.97, -14.81], - [34.96, -14.76], - [34.95, -14.74], - [34.92, -14.73], - [34.93, -14.71], - [34.89, -14.68], - [34.86, -14.65], - [34.8, -14.59], - [34.78, -14.57], - [34.79, -14.51], - [34.78, -14.5], - [34.77, -14.49], - [34.75, -14.47], - [34.74, -14.46], - [34.75, -14.44], - [34.74, -14.37], - [34.72, -14.34], - [34.61, -14.41], - [34.59, -14.43], - [34.58, -14.44], - [34.56, -14.43], - [34.55, -14.44], - [34.52, -14.43], - [34.51, -14.42], - [34.5, -14.43], - [34.47, -14.42], - [34.45, -14.41], - [34.44, -14.42], - [34.42, -14.41], - [34.4, -14.42], - [34.41, -14.43], - [34.42, -14.44], - [34.43, -14.45], - [34.44, -14.46], - [34.45, -14.48], - [34.46, -14.51], - [34.47, -14.52], - [34.48, -14.53], - [34.49, -14.54], - [34.5, -14.55], - [34.52, -14.56], - [34.53, -14.57], - [34.54, -14.59], - [34.55, -14.64], - [34.54, -14.66], - [34.53, -14.68], - [34.52, -14.69], - [34.53, -14.7], - [34.54, -14.72], - [34.55, -14.75], - [34.56, -14.76], - [34.57, -14.77], - [34.58, -14.8], - [34.57, -14.82], - [34.58, -14.84], - [34.57, -14.88], - [34.58, -14.91], - [34.59, -14.93], - [34.6, -14.96], - [34.61, -14.98], - [34.62, -14.99], - [34.61, -15.02], - [34.6, -15.03], - [34.59, -15.05], - [34.58, -15.06], - [34.57, -15.07], - [34.58, -15.09], - [34.59, -15.1], - [34.58, -15.11], - [34.57, -15.12], - [34.58, -15.13], - [34.57, -15.15], - [34.58, -15.16], - [34.59, -15.21], - [34.61, -15.22], - [34.63, -15.23], - [34.64, -15.22], - [34.65, -15.23], - [34.67, -15.24], - [34.68, -15.23], - [34.69, -15.24], - [34.71, -15.25], - [34.78, -15.26], - [34.79, -15.25], - [34.78, -15.26], - [34.79, -15.27], - [34.8, -15.28], - [34.81, -15.29], - [34.8, -15.32], - [34.81, -15.33] - ], - "Ntchisi": [ - [33.62, -13.29], - [33.65, -13.3], - [33.66, -13.31], - [33.67, -13.32], - [33.68, -13.33], - [33.7, -13.34], - [33.71, -13.35], - [33.72, -13.36], - [33.73, -13.39], - [33.74, -13.42], - [33.73, -13.45], - [33.74, -13.46], - [33.75, -13.52], - [33.76, -13.53], - [33.77, -13.52], - [33.78, -13.51], - [33.8, -13.52], - [33.83, -13.51], - [33.84, -13.5], - [33.9, -13.49], - [33.93, -13.48], - [33.94, -13.49], - [33.95, -13.51], - [33.96, -13.52], - [33.97, -13.51], - [34, -13.5], - [34.02, -13.51], - [34.03, -13.5], - [34.04, -13.51], - [34.03, -13.52], - [34.04, -13.53], - [34.06, -13.54], - [34.07, -13.53], - [34.08, -13.54], - [34.09, -13.53], - [34.1, -13.52], - [34.11, -13.51], - [34.12, -13.5], - [34.11, -13.37], - [34.12, -13.36], - [34.11, -13.34], - [34.1, -13.32], - [34.09, -13.3], - [34.1, -13.27], - [34.11, -13.26], - [34.09, -13.16], - [34.08, -13.17], - [34.07, -13.18], - [34.05, -13.17], - [34.06, -13.13], - [34.05, -13.12], - [34.04, -13.13], - [34.01, -13.12], - [34, -13.13], - [33.99, -13.15], - [34, -13.16], - [33.99, -13.17], - [33.98, -13.18], - [33.97, -13.17], - [33.95, -13.18], - [33.94, -13.17], - [33.95, -13.16], - [33.96, -13.14], - [33.95, -13.13], - [33.94, -13.12], - [33.93, -13.11], - [33.92, -13.1], - [33.91, -13.07], - [33.92, -13.03], - [33.91, -13.02], - [33.89, -13.03], - [33.88, -13.04], - [33.87, -13.05], - [33.83, -13.06], - [33.82, -13.07], - [33.83, -13.08], - [33.82, -13.09], - [33.81, -13.1], - [33.8, -13.09], - [33.79, -13.1], - [33.78, -13.11], - [33.77, -13.12], - [33.76, -13.13], - [33.75, -13.15], - [33.74, -13.16], - [33.73, -13.17], - [33.72, -13.18], - [33.7, -13.19], - [33.69, -13.21], - [33.68, -13.2], - [33.67, -13.21], - [33.66, -13.22], - [33.64, -13.23], - [33.63, -13.24], - [33.62, -13.23], - [33.61, -13.24], - [33.62, -13.25], - [33.61, -13.26], - [33.62, -13.27] - ], - "Phalombe": [ - [35.66, -15.46], - [35.65, -15.47], - [35.64, -15.48], - [35.63, -15.49], - [35.62, -15.5], - [35.61, -15.52], - [35.6, -15.53], - [35.58, -15.54], - [35.56, -15.55], - [35.55, -15.56], - [35.54, -15.55], - [35.53, -15.56], - [35.54, -15.57], - [35.53, -15.58], - [35.52, -15.6], - [35.53, -15.61], - [35.54, -15.62], - [35.53, -15.63], - [35.52, -15.64], - [35.51, -15.66], - [35.5, -15.67], - [35.51, -15.69], - [35.52, -15.7], - [35.53, -15.82], - [35.54, -15.83], - [35.55, -15.84], - [35.56, -15.85], - [35.57, -15.86], - [35.58, -15.87], - [35.6, -15.86], - [35.64, -15.89], - [35.61, -15.85], - [35.63, -15.83], - [35.68, -15.84], - [35.69, -15.85], - [35.72, -15.86], - [35.74, -15.87], - [35.75, -15.89], - [35.77, -15.9], - [35.76, -15.91], - [35.77, -15.93], - [35.82, -15.88], - [35.83, -15.73], - [35.84, -15.58], - [35.85, -15.52], - [35.84, -15.45], - [35.66, -15.46] - ], - "Rumphi": [ - [33.71, -10.57], - [33.7, -10.58], - [33.69, -10.59], - [33.68, -10.61], - [33.67, -10.62], - [33.65, -10.63], - [33.64, -10.64], - [33.63, -10.65], - [33.62, -10.66], - [33.61, -10.65], - [33.6, -10.66], - [33.59, -10.67], - [33.58, -10.68], - [33.57, -10.7], - [33.56, -10.71], - [33.55, -10.73], - [33.54, -10.74], - [33.53, -10.75], - [33.52, -10.77], - [33.51, -10.78], - [33.5, -10.79], - [33.48, -10.8], - [33.47, -10.81], - [33.46, -10.82], - [33.42, -10.81], - [33.38, -10.82], - [33.37, -10.83], - [33.34, -10.82], - [33.33, -10.83], - [33.32, -10.85], - [33.31, -10.87], - [33.29, -10.88], - [33.28, -10.87], - [33.26, -10.88], - [33.25, -10.89], - [33.26, -10.91], - [33.27, -10.9], - [33.28, -10.91], - [33.29, -10.92], - [33.3, -10.93], - [33.31, -10.94], - [33.3, -10.99], - [33.29, -10.98], - [33.3, -10.99], - [33.31, -11], - [33.32, -11.01], - [33.34, -11.02], - [33.38, -11.03], - [33.39, -11.04], - [33.4, -11.03], - [33.43, -11.04], - [33.44, -11.05], - [33.43, -11.06], - [33.44, -11.07], - [33.43, -11.12], - [33.44, -11.13], - [33.46, -11.12], - [33.47, -11.11], - [33.48, -11.1], - [33.49, -11.09], - [33.5, -11.08], - [33.51, -11.07], - [33.52, -11.06], - [33.53, -11.04], - [33.54, -11.03], - [33.55, -11.04], - [33.56, -11.05], - [33.57, -11.06], - [33.58, -11.07], - [33.65, -11.06], - [33.67, -11.07], - [33.68, -11.08], - [33.69, -11.09], - [33.7, -11.1], - [33.73, -11.09], - [33.74, -11.08], - [33.73, -11.05], - [33.74, -11.04], - [33.75, -11.03], - [33.78, -11.02], - [33.79, -11.03], - [33.8, -11.02], - [33.82, -11.03], - [33.86, -11.02], - [33.87, -11.03], - [33.88, -11.04], - [33.89, -11.03], - [33.9, -11.04], - [33.91, -11.03], - [33.93, -11.02], - [33.94, -11], - [33.93, -10.99], - [33.94, -10.98], - [33.95, -10.96], - [33.96, -10.97], - [33.97, -10.98], - [33.98, -10.99], - [33.99, -11], - [34, -11.01], - [34.01, -11.02], - [34.02, -11.03], - [34.03, -11.04], - [34.04, -11.05], - [34.05, -11.06], - [34.06, -11.08], - [34.07, -11.07], - [34.08, -11.06], - [34.1, -11.05], - [34.11, -11.04], - [34.12, -11.03], - [34.14, -11.02], - [34.16, -11.01], - [34.18, -11], - [34.2, -10.99], - [34.21, -10.98], - [34.22, -10.97], - [34.21, -10.89], - [34.22, -10.88], - [34.21, -10.87], - [34.2, -10.83], - [34.21, -10.82], - [34.2, -10.81], - [34.21, -10.8], - [34.2, -10.78], - [34.21, -10.77], - [34.22, -10.75], - [34.21, -10.74], - [34.2, -10.73], - [34.19, -10.72], - [34.2, -10.7], - [34.19, -10.68], - [34.2, -10.67], - [34.19, -10.66], - [34.2, -10.65], - [34.19, -10.63], - [34.18, -10.61], - [34.17, -10.6], - [34.18, -10.59], - [34.17, -10.58], - [34.16, -10.57], - [34.14, -10.58], - [34.12, -10.59], - [34.11, -10.58], - [34.09, -10.57], - [33.96, -10.45], - [33.89, -10.48], - [33.79, -10.53], - [33.72, -10.56], - [33.71, -10.57] - ], - "Salima": [ - [34.24, -13.8], - [34.23, -13.83], - [34.22, -13.84], - [34.21, -13.85], - [34.2, -13.86], - [34.19, -13.87], - [34.2, -13.88], - [34.21, -13.89], - [34.22, -13.88], - [34.23, -13.87], - [34.25, -13.86], - [34.29, -13.87], - [34.31, -13.88], - [34.32, -13.91], - [34.33, -13.92], - [34.34, -13.94], - [34.35, -13.95], - [34.36, -13.96], - [34.37, -13.97], - [34.38, -13.98], - [34.39, -13.99], - [34.4, -14.02], - [34.41, -14.03], - [34.42, -14.04], - [34.43, -14.05], - [34.44, -14.06], - [34.45, -14.07], - [34.46, -14.08], - [34.47, -14.09], - [34.48, -14.1], - [34.49, -14.11], - [34.5, -14.1], - [34.52, -14.09], - [34.53, -14.08], - [34.55, -14.07], - [34.54, -14.06], - [34.53, -14.05], - [34.52, -14.01], - [34.53, -13.95], - [34.54, -13.94], - [34.55, -13.93], - [34.56, -13.92], - [34.57, -13.91], - [34.58, -13.9], - [34.59, -13.89], - [34.6, -13.88], - [34.59, -13.87], - [34.6, -13.81], - [34.61, -13.79], - [34.62, -13.78], - [34.61, -13.77], - [34.62, -13.74], - [34.63, -13.72], - [34.62, -13.71], - [34.61, -13.7], - [34.6, -13.69], - [34.59, -13.67], - [34.58, -13.66], - [34.57, -13.65], - [34.56, -13.64], - [34.55, -13.63], - [34.54, -13.62], - [34.53, -13.6], - [34.52, -13.58], - [34.53, -13.59], - [34.54, -13.61], - [34.53, -13.6], - [34.51, -13.59], - [34.5, -13.58], - [34.48, -13.59], - [34.47, -13.6], - [34.45, -13.59], - [34.43, -13.58], - [34.42, -13.57], - [34.41, -13.56], - [34.4, -13.55], - [34.39, -13.54], - [34.38, -13.53], - [34.37, -13.5], - [34.36, -13.47], - [34.35, -13.45], - [34.34, -13.44], - [34.33, -13.43], - [34.32, -13.42], - [34.31, -13.43], - [34.3, -13.44], - [34.29, -13.45], - [34.27, -13.46], - [34.26, -13.45], - [34.24, -13.46], - [34.23, -13.47], - [34.2, -13.48], - [34.19, -13.49], - [34.15, -13.5], - [34.13, -13.51], - [34.12, -13.5], - [34.11, -13.51], - [34.12, -13.57], - [34.15, -13.67], - [34.17, -13.68], - [34.19, -13.7], - [34.2, -13.71], - [34.21, -13.7], - [34.25, -13.69], - [34.27, -13.68], - [34.28, -13.69], - [34.29, -13.75], - [34.3, -13.76], - [34.29, -13.78], - [34.27, -13.79], - [34.24, -13.8] - ], - "Thyolo": [ - [35.26, -16.41], - [35.27, -16.4], - [35.28, -16.38], - [35.29, -16.37], - [35.3, -16.36], - [35.29, -16.34], - [35.28, -16.33], - [35.29, -16.31], - [35.3, -16.27], - [35.29, -16.25], - [35.3, -16.24], - [35.31, -16.23], - [35.3, -16.21], - [35.29, -16.2], - [35.28, -16.19], - [35.29, -16.18], - [35.3, -16.15], - [35.31, -16.14], - [35.32, -16.13], - [35.33, -16.12], - [35.32, -16.1], - [35.33, -16.08], - [35.32, -16.07], - [35.31, -16.05], - [35.32, -16.04], - [35.31, -16.03], - [35.32, -16.02], - [35.31, -16], - [35.29, -15.99], - [35.28, -15.98], - [35.27, -15.97], - [35.26, -15.96], - [35.25, -15.92], - [35.24, -15.9], - [35.23, -15.89], - [35.2, -15.88], - [35.19, -15.86], - [35.14, -15.85], - [35.13, -15.86], - [35.1, -15.85], - [35.08, -15.86], - [35.09, -15.87], - [35.08, -15.88], - [35.07, -15.89], - [35.06, -15.91], - [35.05, -15.92], - [35.04, -15.91], - [35.03, -15.92], - [35.02, -15.93], - [35.01, -15.91], - [35, -15.92], - [34.99, -15.93], - [34.98, -15.94], - [34.97, -15.95], - [34.96, -15.94], - [34.97, -15.95], - [34.96, -15.96], - [34.95, -15.97], - [34.94, -15.99], - [34.92, -16], - [34.93, -16.01], - [34.91, -16.02], - [34.92, -16.03], - [34.91, -16.04], - [34.92, -16.06], - [34.93, -16.07], - [34.94, -16.09], - [34.95, -16.12], - [34.96, -16.13], - [34.97, -16.14], - [35.02, -16.18], - [35.03, -16.2], - [35.04, -16.21], - [35.05, -16.23], - [35.06, -16.25], - [35.07, -16.26], - [35.08, -16.27], - [35.09, -16.28], - [35.11, -16.29], - [35.12, -16.3], - [35.11, -16.31], - [35.12, -16.32], - [35.13, -16.33], - [35.15, -16.34], - [35.16, -16.35], - [35.17, -16.37], - [35.2, -16.38], - [35.21, -16.39], - [35.22, -16.4], - [35.25, -16.41] - ], - "Zomba": [ - [35.13, -15.53], - [35.15, -15.52], - [35.16, -15.54], - [35.17, -15.52], - [35.19, -15.5], - [35.18, -15.53], - [35.19, -15.55], - [35.2, -15.57], - [35.23, -15.58], - [35.24, -15.59], - [35.25, -15.63], - [35.26, -15.64], - [35.27, -15.65], - [35.28, -15.66], - [35.3, -15.67], - [35.32, -15.68], - [35.38, -15.67], - [35.39, -15.66], - [35.4, -15.67], - [35.41, -15.68], - [35.42, -15.67], - [35.45, -15.66], - [35.47, -15.65], - [35.48, -15.64], - [35.49, -15.63], - [35.5, -15.61], - [35.51, -15.6], - [35.53, -15.59], - [35.54, -15.58], - [35.53, -15.57], - [35.54, -15.56], - [35.55, -15.55], - [35.56, -15.54], - [35.58, -15.53], - [35.6, -15.52], - [35.61, -15.53], - [35.62, -15.52], - [35.63, -15.5], - [35.64, -15.48], - [35.65, -15.47], - [35.66, -15.46], - [35.67, -15.45], - [35.85, -15.44], - [35.84, -15.37], - [35.8, -15.2], - [35.79, -15.21], - [35.51, -15.22], - [35.5, -15.23], - [35.46, -15.24], - [35.45, -15.23], - [35.44, -15.24], - [35.43, -15.23], - [35.34, -15.2], - [35.33, -15.21], - [35.31, -15.22], - [35.3, -15.23], - [35.31, -15.24], - [35.3, -15.25], - [35.29, -15.24], - [35.26, -15.23], - [35.23, -15.22], - [35.22, -15.23], - [35.21, -15.24], - [35.2, -15.25], - [35.18, -15.24], - [35.17, -15.23], - [35.16, -15.21], - [35.15, -15.22], - [35.14, -15.24], - [35.13, -15.25], - [35.12, -15.26], - [35.11, -15.27], - [35.1, -15.29], - [35.09, -15.3], - [35.08, -15.31], - [35.07, -15.3], - [35.06, -15.32], - [35.04, -15.33], - [35.01, -15.34], - [34.99, -15.35], - [35, -15.36], - [35.01, -15.37], - [35.02, -15.38], - [35.03, -15.39], - [35.04, -15.4], - [35.06, -15.41], - [35.05, -15.42], - [35.06, -15.43], - [35.07, -15.44], - [35.09, -15.46], - [35.1, -15.47], - [35.09, -15.54], - [35.1, -15.55], - [35.12, -15.54], - [35.13, -15.53] - ] -} diff --git a/libs/data/geoLocation/zm/admin-0.boundaries.json b/libs/data/geoLocation/zm/admin-0.boundaries.json deleted file mode 100644 index 54ec92be2..000000000 --- a/libs/data/geoLocation/zm/admin-0.boundaries.json +++ /dev/null @@ -1,930 +0,0 @@ -{ - "Zambia": [ - [32.92, -9.41], - [32.93, -9.48], - [32.94, -9.49], - [32.95, -9.48], - [32.98, -9.5], - [32.99, -9.53], - [32.97, -9.6], - [32.99, -9.63], - [33.02, -9.62], - [33.05, -9.63], - [33.06, -9.65], - [33.08, -9.66], - [33.09, -9.64], - [33.1, -9.59], - [33.12, -9.6], - [33.2, -9.62], - [33.21, -9.64], - [33.22, -9.67], - [33.21, -9.68], - [33.2, -9.7], - [33.21, -9.71], - [33.22, -9.73], - [33.24, -9.74], - [33.25, -9.75], - [33.27, -9.78], - [33.28, -9.79], - [33.29, -9.8], - [33.3, -9.81], - [33.34, -9.82], - [33.36, -9.87], - [33.37, -9.9], - [33.36, -9.92], - [33.33, -9.97], - [33.31, -10.01], - [33.3, -10.04], - [33.32, -10.08], - [33.4, -10.12], - [33.42, -10.14], - [33.44, -10.15], - [33.45, -10.17], - [33.48, -10.18], - [33.5, -10.2], - [33.52, -10.21], - [33.53, -10.23], - [33.54, -10.26], - [33.53, -10.32], - [33.56, -10.4], - [33.57, -10.42], - [33.6, -10.44], - [33.62, -10.49], - [33.64, -10.51], - [33.67, -10.52], - [33.66, -10.6], - [33.64, -10.62], - [33.6, -10.64], - [33.59, -10.65], - [33.58, -10.66], - [33.53, -10.71], - [33.51, -10.75], - [33.5, -10.77], - [33.48, -10.78], - [33.45, -10.8], - [33.43, -10.81], - [33.39, -10.8], - [33.36, -10.81], - [33.32, -10.82], - [33.31, -10.83], - [33.29, -10.86], - [33.27, -10.87], - [33.25, -10.86], - [33.24, -10.87], - [33.23, -10.88], - [33.24, -10.9], - [33.28, -10.91], - [33.29, -10.94], - [33.3, -11.03], - [33.32, -11.06], - [33.34, -11.09], - [33.36, -11.11], - [33.39, -11.16], - [33.38, -11.19], - [33.37, -11.22], - [33.3, -11.33], - [33.29, -11.36], - [33.27, -11.37], - [33.24, -11.4], - [33.23, -11.42], - [33.21, -11.56], - [33.22, -11.57], - [33.23, -11.58], - [33.3, -11.59], - [33.31, -11.77], - [33.3, -11.85], - [33.31, -11.88], - [33.3, -11.93], - [33.29, -11.98], - [33.25, -12.07], - [33.26, -12.16], - [33.29, -12.18], - [33.3, -12.2], - [33.31, -12.23], - [33.33, -12.3], - [33.35, -12.33], - [33.38, -12.34], - [33.46, -12.32], - [33.5, -12.33], - [33.53, -12.34], - [33.52, -12.37], - [33.49, -12.39], - [33.48, -12.41], - [33.46, -12.42], - [33.45, -12.45], - [33.42, -12.46], - [33.41, -12.48], - [33.39, -12.5], - [33.37, -12.52], - [33.35, -12.53], - [33.33, -12.54], - [33.31, -12.53], - [33.29, -12.52], - [33.26, -12.53], - [33.24, -12.54], - [33.23, -12.58], - [33.21, -12.59], - [33.2, -12.6], - [33.18, -12.61], - [33.17, -12.62], - [33.15, -12.59], - [33.13, -12.58], - [33.11, -12.59], - [33.09, -12.6], - [33.07, -12.59], - [33.06, -12.58], - [33.05, -12.59], - [33.04, -12.6], - [33.02, -12.61], - [32.99, -12.67], - [32.96, -12.73], - [32.94, -12.75], - [32.95, -12.84], - [32.98, -12.87], - [33.01, -12.89], - [32.98, -13.01], - [32.97, -13.12], - [32.98, -13.17], - [33, -13.19], - [32.99, -13.22], - [32.94, -13.26], - [32.92, -13.29], - [32.91, -13.35], - [32.89, -13.4], - [32.87, -13.44], - [32.85, -13.46], - [32.82, -13.47], - [32.81, -13.53], - [32.8, -13.54], - [32.75, -13.55], - [32.72, -13.57], - [32.71, -13.58], - [32.69, -13.57], - [32.67, -13.58], - [32.66, -13.6], - [32.68, -13.63], - [32.71, -13.64], - [32.77, -13.65], - [32.81, -13.7], - [32.8, -13.72], - [32.77, -13.74], - [32.76, -13.75], - [32.79, -13.79], - [32.83, -13.8], - [32.86, -13.81], - [32.87, -13.82], - [32.92, -13.88], - [32.93, -13.9], - [32.94, -13.93], - [32.97, -13.94], - [32.98, -13.95], - [32.97, -13.96], - [32.98, -14.02], - [33, -14.05], - [33.05, -14], - [33.06, -13.98], - [33.08, -13.97], - [33.11, -13.96], - [33.13, -13.93], - [33.14, -13.92], - [33.15, -13.94], - [33.19, -13.99], - [33.2, -14.01], - [33.13, -14.04], - [33.04, -14.07], - [32.92, -14.11], - [32.74, -14.17], - [32.58, -14.22], - [32.43, -14.27], - [32.32, -14.31], - [32.23, -14.34], - [32.15, -14.35], - [32.11, -14.36], - [32.03, -14.4], - [31.93, -14.43], - [31.8, -14.47], - [31.66, -14.52], - [31.59, -14.55], - [31.5, -14.6], - [31.41, -14.63], - [31.31, -14.66], - [31.18, -14.69], - [31.07, -14.71], - [30.92, -14.75], - [30.82, -14.77], - [30.68, -14.82], - [30.59, -14.85], - [30.49, -14.89], - [30.39, -14.93], - [30.32, -14.97], - [30.23, -14.98], - [30.21, -14.99], - [30.22, -15.02], - [30.23, -15.11], - [30.26, -15.23], - [30.29, -15.28], - [30.32, -15.3], - [30.35, -15.32], - [30.36, -15.34], - [30.37, -15.37], - [30.39, -15.47], - [30.37, -15.53], - [30.4, -15.59], - [30.41, -15.63], - [30.4, -15.64], - [30.36, -15.65], - [30.3, -15.64], - [30.28, -15.63], - [30.23, -15.64], - [30.22, -15.65], - [30.17, -15.63], - [30.13, -15.62], - [30.09, -15.63], - [30.05, -15.64], - [30.01, -15.65], - [29.97, -15.64], - [29.88, -15.62], - [29.84, -15.61], - [29.81, -15.62], - [29.77, -15.64], - [29.67, -15.66], - [29.65, -15.67], - [29.63, -15.66], - [29.53, -15.69], - [29.51, -15.7], - [29.42, -15.71], - [29.19, -15.81], - [29.15, -15.85], - [29.12, -15.86], - [29.1, -15.87], - [29.09, -15.88], - [29.08, -15.9], - [29.06, -15.93], - [29.04, -15.95], - [28.95, -15.96], - [28.9, -16], - [28.88, -16.02], - [28.87, -16.03], - [28.86, -16.05], - [28.87, -16.08], - [28.85, -16.16], - [28.86, -16.23], - [28.84, -16.28], - [28.86, -16.37], - [28.83, -16.43], - [28.82, -16.47], - [28.81, -16.49], - [28.77, -16.52], - [28.76, -16.53], - [28.74, -16.55], - [28.73, -16.56], - [28.64, -16.57], - [28.28, -16.71], - [28.21, -16.75], - [28.11, -16.83], - [28.02, -16.87], - [27.87, -16.93], - [27.82, -16.96], - [27.78, -17], - [27.64, -17.2], - [27.62, -17.23], - [27.6, -17.31], - [27.58, -17.36], - [27.52, -17.42], - [27.42, -17.5], - [27.16, -17.77], - [27.15, -17.78], - [27.12, -17.88], - [27.08, -17.92], - [27.05, -17.94], - [27.02, -17.96], - [26.95, -17.97], - [26.91, -17.99], - [26.89, -17.98], - [26.79, -18.03], - [26.74, -18.04], - [26.71, -18.07], - [26.63, -18.05], - [26.61, -18.04], - [26.6, -18.03], - [26.58, -18.01], - [26.57, -18], - [26.53, -17.99], - [26.49, -17.98], - [26.41, -17.94], - [26.36, -17.93], - [26.33, -17.94], - [26.32, -17.93], - [26.3, -17.92], - [26.25, -17.91], - [26.23, -17.9], - [26.22, -17.89], - [26.21, -17.88], - [26.2, -17.89], - [26.17, -17.91], - [26.16, -17.92], - [26.12, -17.93], - [26.1, -17.94], - [26.08, -17.96], - [26.05, -17.97], - [26.04, -17.98], - [26.03, -17.97], - [25.98, -18], - [25.86, -17.97], - [25.85, -17.96], - [25.86, -17.92], - [25.85, -17.91], - [25.8, -17.89], - [25.79, -17.87], - [25.77, -17.85], - [25.74, -17.84], - [25.71, -17.83], - [25.69, -17.82], - [25.68, -17.81], - [25.6, -17.84], - [25.54, -17.85], - [25.52, -17.86], - [25.5, -17.85], - [25.38, -17.84], - [25.32, -17.83], - [25.29, -17.81], - [25.27, -17.8], - [25.26, -17.79], - [25.25, -17.78], - [25.24, -17.77], - [25.23, -17.76], - [25.18, -17.74], - [25.16, -17.73], - [25.15, -17.7], - [25.14, -17.69], - [25.12, -17.7], - [25.11, -17.68], - [25.1, -17.67], - [25.09, -17.64], - [25.07, -17.63], - [25.06, -17.62], - [25.03, -17.61], - [25.04, -17.58], - [25.01, -17.59], - [24.98, -17.58], - [24.97, -17.56], - [24.96, -17.55], - [24.94, -17.56], - [24.92, -17.54], - [24.9, -17.53], - [24.83, -17.52], - [24.78, -17.51], - [24.68, -17.49], - [24.63, -17.5], - [24.62, -17.51], - [24.61, -17.52], - [24.59, -17.53], - [24.54, -17.52], - [24.53, -17.51], - [24.5, -17.5], - [24.48, -17.49], - [24.41, -17.47], - [24.33, -17.49], - [24.31, -17.48], - [24.19, -17.49], - [24.11, -17.5], - [24.06, -17.51], - [24.02, -17.52], - [23.98, -17.53], - [23.93, -17.54], - [23.85, -17.55], - [23.81, -17.56], - [23.76, -17.57], - [23.72, -17.58], - [23.68, -17.59], - [23.63, -17.6], - [23.55, -17.61], - [23.51, -17.62], - [23.48, -17.63], - [23.38, -17.64], - [23.36, -17.58], - [23.34, -17.56], - [23.32, -17.55], - [23.31, -17.54], - [23.26, -17.53], - [23.24, -17.54], - [23.18, -17.52], - [23.17, -17.47], - [23.12, -17.45], - [23.1, -17.43], - [23.07, -17.41], - [23.05, -17.38], - [23.04, -17.34], - [23, -17.29], - [22.94, -17.27], - [22.88, -17.25], - [22.85, -17.23], - [22.81, -17.2], - [22.78, -17.18], - [22.77, -17.17], - [22.76, -17.15], - [22.74, -17.11], - [22.73, -17.08], - [22.71, -17.06], - [22.67, -17.01], - [22.65, -17], - [22.59, -16.98], - [22.57, -16.97], - [22.55, -16.92], - [22.52, -16.91], - [22.5, -16.89], - [22.49, -16.87], - [22.42, -16.75], - [22.4, -16.74], - [22.38, -16.73], - [22.37, -16.72], - [22.35, -16.7], - [22.34, -16.68], - [22.33, -16.67], - [22.3, -16.66], - [22.26, -16.67], - [22.15, -16.6], - [22.14, -16.57], - [22.13, -16.55], - [22.11, -16.54], - [22.1, -16.5], - [22.08, -16.47], - [22.09, -16.42], - [22.1, -16.39], - [22.11, -16.38], - [22.09, -16.37], - [22.06, -16.36], - [22.05, -16.34], - [22.04, -16.31], - [22.03, -16.29], - [22.02, -16.27], - [22.01, -16.25], - [21.98, -16.17], - [22.1, -13], - [23.99, -12.97], - [23.97, -12.93], - [23.95, -12.9], - [23.9, -12.85], - [23.87, -12.82], - [23.89, -12.71], - [23.91, -12.63], - [23.93, -12.56], - [23.94, -12.53], - [23.99, -12.47], - [24.02, -12.42], - [24.03, -12.4], - [24.02, -12.34], - [24.01, -12.25], - [23.98, -12.23], - [23.96, -12.2], - [23.95, -12.15], - [23.96, -12.01], - [23.97, -11.88], - [23.99, -11.83], - [23.98, -11.72], - [23.97, -11.7], - [23.96, -11.68], - [23.95, -11.66], - [23.96, -11.62], - [23.98, -11.58], - [24.01, -11.54], - [24.02, -11.44], - [24.05, -11.42], - [24.06, -11.41], - [24.02, -11.3], - [24.01, -11.27], - [24.02, -11.13], - [23.99, -11.11], - [24, -11], - [23.98, -10.94], - [23.97, -10.92], - [24, -10.87], - [24.05, -10.88], - [24.09, -10.9], - [24.11, -10.92], - [24.12, -10.99], - [24.14, -11.04], - [24.16, -11.03], - [24.22, -11.05], - [24.32, -11.06], - [24.35, -11.08], - [24.37, -11.1], - [24.38, -11.12], - [24.37, -11.14], - [24.36, -11.15], - [24.37, -11.18], - [24.38, -11.19], - [24.39, -11.2], - [24.4, -11.22], - [24.39, -11.28], - [24.38, -11.3], - [24.35, -11.35], - [24.34, -11.36], - [24.3, -11.37], - [24.29, -11.38], - [24.31, -11.41], - [24.39, -11.42], - [24.43, -11.45], - [24.45, -11.46], - [24.47, -11.47], - [24.49, -11.46], - [24.53, -11.45], - [24.56, -11.44], - [24.57, -11.43], - [24.58, -11.42], - [24.59, -11.4], - [24.62, -11.39], - [24.65, -11.38], - [24.66, -11.35], - [24.67, -11.34], - [24.71, -11.33], - [24.83, -11.32], - [24.9, -11.28], - [24.94, -11.27], - [25.12, -11.26], - [25.18, -11.25], - [25.28, -11.2], - [25.31, -11.19], - [25.32, -11.21], - [25.33, -11.27], - [25.32, -11.28], - [25.3, -11.3], - [25.28, -11.31], - [25.29, -11.32], - [25.31, -11.33], - [25.3, -11.35], - [25.29, -11.36], - [25.28, -11.37], - [25.29, -11.42], - [25.31, -11.46], - [25.32, -11.47], - [25.3, -11.5], - [25.33, -11.62], - [25.34, -11.63], - [25.35, -11.65], - [25.39, -11.66], - [25.41, -11.67], - [25.46, -11.7], - [25.48, -11.72], - [25.47, -11.76], - [25.48, -11.77], - [25.5, -11.78], - [25.52, -11.77], - [25.53, -11.76], - [25.56, -11.75], - [25.57, -11.73], - [25.66, -11.75], - [25.69, -11.78], - [25.73, -11.8], - [25.83, -11.79], - [25.86, -11.8], - [25.91, -11.85], - [25.95, -11.86], - [25.96, -11.9], - [26.19, -11.91], - [26.21, -11.92], - [26.23, -11.93], - [26.29, -11.94], - [26.33, -11.92], - [26.38, -11.91], - [26.44, -11.92], - [26.46, -11.93], - [26.47, -11.95], - [26.49, -11.96], - [26.52, -11.97], - [26.61, -11.98], - [26.64, -11.99], - [26.66, -12], - [26.68, -12.01], - [26.7, -12.02], - [26.72, -12.01], - [26.73, -12], - [26.74, -11.98], - [26.76, -11.97], - [26.87, -11.96], - [26.91, -11.94], - [26.95, -11.91], - [26.97, -11.87], - [26.98, -11.75], - [27, -11.73], - [27.01, -11.71], - [27.02, -11.7], - [27.01, -11.63], - [27.02, -11.6], - [27.03, -11.59], - [27.05, -11.6], - [27.1, -11.58], - [27.17, -11.57], - [27.2, -11.59], - [27.21, -11.64], - [27.23, -11.81], - [27.42, -11.92], - [27.47, -12], - [27.52, -12.18], - [27.54, -12.2], - [27.59, -12.24], - [27.6, -12.25], - [27.64, -12.29], - [27.67, -12.3], - [27.71, -12.31], - [27.76, -12.3], - [27.81, -12.28], - [27.82, -12.27], - [27.83, -12.26], - [27.88, -12.27], - [27.93, -12.3], - [27.95, -12.32], - [27.96, -12.37], - [28.09, -12.38], - [28.1, -12.39], - [28.11, -12.41], - [28.13, -12.43], - [28.15, -12.42], - [28.16, -12.41], - [28.19, -12.4], - [28.2, -12.41], - [28.22, -12.43], - [28.24, -12.44], - [28.28, -12.43], - [28.3, -12.44], - [28.34, -12.45], - [28.42, -12.52], - [28.44, -12.54], - [28.46, -12.59], - [28.47, -12.61], - [28.5, -12.65], - [28.51, -12.67], - [28.5, -12.71], - [28.48, -12.72], - [28.47, -12.74], - [28.48, -12.76], - [28.5, -12.79], - [28.52, -12.81], - [28.54, -12.83], - [28.55, -12.89], - [28.57, -12.9], - [28.58, -12.89], - [28.59, -12.88], - [28.61, -12.85], - [28.62, -12.84], - [28.67, -12.85], - [28.71, -12.89], - [28.78, -12.98], - [28.79, -12.99], - [28.8, -13], - [28.81, -13.04], - [28.83, -13.05], - [28.82, -13.09], - [28.83, -13.1], - [28.85, -13.14], - [28.89, -13.15], - [28.9, -13.16], - [28.93, -13.31], - [28.95, -13.35], - [28.98, -13.38], - [28.99, -13.4], - [29.05, -13.39], - [29.1, -13.38], - [29.14, -13.39], - [29.15, -13.41], - [29.16, -13.42], - [29.17, -13.43], - [29.18, -13.44], - [29.19, -13.43], - [29.21, -13.41], - [29.23, -13.4], - [29.25, -13.39], - [29.31, -13.35], - [29.45, -13.3], - [29.47, -13.29], - [29.53, -13.23], - [29.55, -13.22], - [29.57, -13.23], - [29.59, -13.24], - [29.61, -13.25], - [29.63, -13.26], - [29.67, -13.27], - [29.66, -13.3], - [29.65, -13.31], - [29.63, -13.32], - [29.62, -13.37], - [29.6, -13.39], - [29.61, -13.4], - [29.62, -13.42], - [29.63, -13.43], - [29.64, -13.44], - [29.66, -13.45], - [29.7, -13.46], - [29.8, -13.42], - [29.76, -12.16], - [29.7, -12.19], - [29.65, -12.21], - [29.63, -12.22], - [29.62, -12.21], - [29.6, -12.19], - [29.55, -12.21], - [29.53, -12.22], - [29.49, -12.23], - [29.47, -12.24], - [29.46, -12.29], - [29.45, -12.32], - [29.48, -12.38], - [29.5, -12.39], - [29.53, -12.41], - [29.52, -12.43], - [29.51, -12.44], - [29.5, -12.45], - [29.47, -12.44], - [29.41, -12.43], - [29.36, -12.41], - [29.3, -12.4], - [29.28, -12.39], - [29.27, -12.37], - [29.13, -12.38], - [29.11, -12.39], - [29.1, -12.37], - [29.08, -12.38], - [29.03, -12.36], - [28.94, -12.21], - [28.92, -12.17], - [28.86, -12.14], - [28.85, -12.13], - [28.84, -12.09], - [28.82, -12.08], - [28.81, -12.06], - [28.77, -12.05], - [28.76, -12.04], - [28.75, -12.02], - [28.74, -11.98], - [28.71, -11.99], - [28.69, -11.98], - [28.64, -11.96], - [28.62, -11.95], - [28.61, -11.91], - [28.59, -11.9], - [28.57, -11.91], - [28.55, -11.89], - [28.54, -11.87], - [28.5, -11.86], - [28.49, -11.81], - [28.48, -11.8], - [28.46, -11.79], - [28.45, -11.78], - [28.44, -11.71], - [28.43, -11.69], - [28.42, -11.68], - [28.41, -11.61], - [28.4, -11.6], - [28.38, -11.58], - [28.37, -11.54], - [28.36, -11.53], - [28.35, -11.46], - [28.36, -11.45], - [28.41, -11.37], - [28.43, -11.35], - [28.44, -11.29], - [28.45, -11.27], - [28.46, -11.26], - [28.47, -11.23], - [28.48, -11.18], - [28.49, -11.15], - [28.48, -11.09], - [28.49, -11.06], - [28.5, -11.03], - [28.51, -11.02], - [28.53, -10.96], - [28.54, -10.94], - [28.55, -10.91], - [28.56, -10.81], - [28.58, -10.79], - [28.59, -10.77], - [28.6, -10.76], - [28.61, -10.74], - [28.62, -10.72], - [28.63, -10.71], - [28.67, -10.7], - [28.68, -10.68], - [28.69, -10.66], - [28.7, -10.64], - [28.67, -10.62], - [28.65, -10.54], - [28.63, -10.52], - [28.64, -10.5], - [28.63, -10.48], - [28.64, -10.46], - [28.65, -10.44], - [28.64, -10.43], - [28.63, -10.39], - [28.62, -10.37], - [28.63, -10.31], - [28.62, -10.28], - [28.61, -10.27], - [28.6, -10.25], - [28.57, -10.22], - [28.58, -10.2], - [28.6, -10.17], - [28.62, -10.14], - [28.63, -10.1], - [28.62, -9.95], - [28.63, -9.93], - [28.66, -9.86], - [28.67, -9.82], - [28.68, -9.8], - [28.7, -9.79], - [28.67, -9.77], - [28.66, -9.75], - [28.65, -9.74], - [28.63, -9.72], - [28.62, -9.65], - [28.61, -9.62], - [28.59, -9.57], - [28.58, -9.56], - [28.61, -9.55], - [28.62, -9.54], - [28.57, -9.53], - [28.56, -9.48], - [28.53, -9.46], - [28.52, -9.45], - [28.51, -9.43], - [28.52, -9.42], - [28.5, -9.35], - [28.46, -9.34], - [28.41, -9.32], - [28.37, -9.31], - [28.35, -9.27], - [28.37, -9.24], - [28.42, -9.21], - [28.51, -9.16], - [28.6, -9.1], - [28.77, -8.93], - [28.89, -8.77], - [28.93, -8.68], - [28.94, -8.59], - [28.89, -8.5], - [28.92, -8.47], - [29.04, -8.45], - [29.21, -8.43], - [29.37, -8.4], - [29.58, -8.37], - [29.86, -8.33], - [30.12, -8.29], - [30.32, -8.26], - [30.58, -8.22], - [30.75, -8.19], - [30.78, -8.29], - [30.83, -8.39], - [30.89, -8.48], - [30.96, -8.55], - [30.99, -8.58], - [31.03, -8.6], - [31.08, -8.62], - [31.14, -8.61], - [31.16, -8.59], - [31.18, -8.58], - [31.22, -8.59], - [31.24, -8.61], - [31.25, -8.62], - [31.33, -8.6], - [31.35, -8.59], - [31.37, -8.6], - [31.39, -8.63], - [31.44, -8.64], - [31.46, -8.67], - [31.48, -8.68], - [31.52, -8.69], - [31.54, -8.7], - [31.55, -8.73], - [31.58, -8.84], - [31.67, -8.91], - [31.69, -8.92], - [31.73, -8.91], - [31.76, -8.89], - [31.94, -8.93], - [31.92, -8.97], - [31.94, -9.06], - [31.98, -9.07], - [32, -9.06], - [32.02, -9.05], - [32.09, -9.07], - [32.13, -9.06], - [32.15, -9.07], - [32.19, -9.11], - [32.21, -9.13], - [32.25, -9.14], - [32.38, -9.13], - [32.42, -9.14], - [32.46, -9.17], - [32.47, -9.18], - [32.49, -9.23], - [32.5, -9.25], - [32.52, -9.26], - [32.64, -9.28], - [32.71, -9.29], - [32.74, -9.31], - [32.75, -9.33], - [32.76, -9.34], - [32.83, -9.37], - [32.91, -9.4], - [32.92, -9.41] - ] -} diff --git a/libs/data/geoLocation/zm/admin-1.boundaries.json b/libs/data/geoLocation/zm/admin-1.boundaries.json deleted file mode 100644 index baad2dddc..000000000 --- a/libs/data/geoLocation/zm/admin-1.boundaries.json +++ /dev/null @@ -1,3156 +0,0 @@ -{ - "Muchinga": [ - [32.92, -9.41], - [32.93, -9.48], - [32.94, -9.49], - [32.95, -9.48], - [32.98, -9.5], - [32.99, -9.53], - [32.97, -9.6], - [32.99, -9.63], - [33.02, -9.62], - [33.05, -9.63], - [33.06, -9.65], - [33.08, -9.66], - [33.09, -9.64], - [33.1, -9.59], - [33.12, -9.6], - [33.2, -9.62], - [33.21, -9.64], - [33.22, -9.67], - [33.21, -9.68], - [33.2, -9.7], - [33.21, -9.71], - [33.22, -9.73], - [33.24, -9.74], - [33.25, -9.75], - [33.27, -9.78], - [33.28, -9.79], - [33.29, -9.8], - [33.3, -9.81], - [33.34, -9.82], - [33.36, -9.87], - [33.37, -9.9], - [33.36, -9.92], - [33.33, -9.97], - [33.31, -10.01], - [33.3, -10.04], - [33.32, -10.08], - [33.4, -10.12], - [33.42, -10.14], - [33.44, -10.15], - [33.45, -10.17], - [33.48, -10.18], - [33.5, -10.2], - [33.52, -10.21], - [33.53, -10.23], - [33.54, -10.26], - [33.53, -10.32], - [33.56, -10.4], - [33.57, -10.42], - [33.6, -10.44], - [33.62, -10.49], - [33.64, -10.51], - [33.67, -10.52], - [33.66, -10.6], - [33.64, -10.62], - [33.6, -10.64], - [33.59, -10.65], - [33.58, -10.66], - [33.53, -10.71], - [33.51, -10.75], - [33.5, -10.77], - [33.48, -10.78], - [33.45, -10.8], - [33.43, -10.81], - [33.39, -10.8], - [33.36, -10.81], - [33.32, -10.82], - [33.31, -10.83], - [33.29, -10.86], - [33.27, -10.87], - [33.25, -10.86], - [33.24, -10.87], - [33.23, -10.88], - [33.24, -10.9], - [33.28, -10.91], - [33.29, -10.94], - [33.3, -11.03], - [33.32, -11.06], - [33.34, -11.09], - [33.36, -11.11], - [33.39, -11.16], - [33.38, -11.19], - [33.37, -11.22], - [33.3, -11.33], - [33.29, -11.36], - [33.27, -11.37], - [33.24, -11.4], - [33.23, -11.42], - [33.21, -11.56], - [33.22, -11.57], - [33.23, -11.58], - [33.3, -11.59], - [33.31, -11.64], - [33.26, -11.66], - [33.22, -11.67], - [33.2, -11.7], - [33.13, -11.86], - [33.09, -11.95], - [32.95, -11.99], - [32.73, -12.06], - [32.6, -12.07], - [32.5, -12.11], - [32.48, -12.17], - [32.43, -12.22], - [32.29, -12.2], - [32.28, -12.24], - [32.26, -12.29], - [32.21, -12.33], - [32.19, -12.35], - [32.18, -12.38], - [32.17, -12.39], - [32.16, -12.4], - [32.15, -12.41], - [32.14, -12.44], - [32.12, -12.59], - [32.11, -12.6], - [32.1, -12.63], - [32.09, -12.64], - [32.08, -12.72], - [32.07, -12.76], - [32.06, -12.79], - [32.04, -12.8], - [32.03, -12.81], - [32.02, -12.86], - [32.01, -12.89], - [31.97, -12.9], - [31.95, -12.91], - [31.93, -12.93], - [31.91, -12.94], - [31.9, -13.03], - [31.89, -13.04], - [31.87, -13.05], - [31.86, -13.06], - [31.82, -13.08], - [31.81, -13.09], - [31.79, -13.1], - [31.77, -13.11], - [31.76, -13.1], - [31.75, -13.12], - [31.74, -13.13], - [31.72, -13.14], - [31.71, -13.17], - [31.7, -13.19], - [31.68, -13.2], - [31.66, -13.26], - [31.65, -13.3], - [31.64, -13.34], - [31.61, -13.37], - [31.53, -13.43], - [31.48, -13.42], - [31.44, -13.43], - [31.43, -13.44], - [31.41, -13.31], - [31.39, -13.28], - [31.37, -13.25], - [31.36, -13.23], - [31.35, -13.01], - [31.34, -12.98], - [31.33, -12.97], - [31.29, -12.95], - [31.19, -12.96], - [31.18, -12.97], - [31.17, -13.02], - [31.16, -13.03], - [31.15, -13.04], - [31.11, -13.03], - [31.03, -12.96], - [31.02, -12.95], - [30.97, -12.94], - [30.91, -12.93], - [30.83, -12.92], - [30.81, -12.91], - [30.75, -12.87], - [30.74, -12.86], - [30.73, -12.77], - [30.74, -12.73], - [30.75, -12.71], - [30.76, -12.7], - [30.77, -12.69], - [30.76, -12.67], - [30.75, -12.66], - [30.73, -12.65], - [30.72, -12.64], - [30.71, -12.63], - [30.7, -12.6], - [30.69, -12.59], - [30.66, -12.61], - [30.65, -12.62], - [30.63, -12.63], - [30.62, -12.62], - [30.58, -12.59], - [30.57, -12.58], - [30.56, -12.57], - [30.57, -12.54], - [30.56, -12.5], - [30.55, -12.49], - [30.52, -12.48], - [30.51, -12.47], - [30.5, -12.46], - [30.51, -12.4], - [30.5, -12.31], - [30.48, -12.3], - [30.47, -12.31], - [30.44, -12.3], - [30.43, -12.29], - [30.42, -12.28], - [30.41, -12.27], - [30.38, -12.28], - [30.37, -12.27], - [30.35, -12.26], - [30.3, -12.25], - [30.28, -12.24], - [30.23, -12.23], - [30.22, -12.22], - [30.2, -12.21], - [30.16, -12.2], - [30.15, -12.18], - [30.14, -12.17], - [30.11, -12.16], - [30.09, -12.15], - [30.08, -12.14], - [30.07, -12.13], - [30.06, -12.11], - [30.05, -12.1], - [30.03, -12.03], - [30.01, -12.01], - [30, -12], - [29.95, -12.01], - [29.87, -12.04], - [29.86, -12.05], - [29.85, -12.06], - [29.84, -12.12], - [29.83, -12.15], - [29.82, -12.16], - [29.8, -12.15], - [29.81, -12.14], - [29.82, -12.13], - [29.81, -12.12], - [29.82, -12.1], - [29.81, -12.07], - [29.79, -12.05], - [29.78, -12.04], - [29.77, -11.94], - [29.78, -11.91], - [29.79, -11.9], - [29.82, -11.89], - [30.25, -11.83], - [30.26, -11.82], - [30.28, -11.81], - [30.45, -11.59], - [30.44, -11.58], - [30.45, -11.53], - [30.46, -11.5], - [30.48, -11.49], - [30.5, -11.48], - [30.52, -11.46], - [30.53, -11.44], - [30.54, -11.42], - [30.55, -11.4], - [30.57, -11.39], - [30.59, -11.38], - [30.6, -11.37], - [30.61, -11.34], - [30.62, -11.33], - [30.68, -11.31], - [30.71, -11.29], - [30.72, -11.26], - [30.74, -11.21], - [30.82, -11.11], - [30.84, -11.08], - [30.85, -11.06], - [30.86, -11.05], - [30.87, -11.04], - [30.88, -11.06], - [30.9, -11.05], - [30.88, -11.03], - [30.91, -11.02], - [30.93, -11.01], - [30.96, -11], - [30.98, -10.98], - [30.99, -10.94], - [31, -10.92], - [31.01, -10.93], - [31.02, -10.94], - [31.04, -10.95], - [31.05, -10.94], - [31.06, -10.91], - [31.07, -10.92], - [31.08, -10.93], - [31.07, -10.95], - [31.06, -10.96], - [31.15, -10.92], - [31.16, -10.89], - [31.17, -10.88], - [31.15, -10.85], - [31.14, -10.84], - [31.15, -10.82], - [31.2, -10.81], - [31.19, -10.78], - [31.18, -10.79], - [31.15, -10.78], - [31.13, -10.76], - [31.17, -10.72], - [31.19, -10.71], - [31.26, -10.72], - [31.28, -10.73], - [31.3, -10.71], - [31.31, -10.7], - [31.32, -10.64], - [31.34, -10.63], - [31.33, -10.62], - [31.35, -10.61], - [31.39, -10.6], - [31.42, -10.58], - [31.44, -10.57], - [31.45, -10.56], - [31.46, -10.55], - [31.48, -10.56], - [31.49, -10.57], - [31.55, -10.56], - [31.52, -10.28], - [31.42, -10.23], - [31.34, -10.18], - [31.31, -10.07], - [31.26, -9.96], - [31.19, -9.83], - [31.11, -9.76], - [31.18, -9.67], - [31.21, -9.61], - [31.26, -9.59], - [31.32, -9.54], - [31.37, -9.5], - [31.43, -9.55], - [31.51, -9.54], - [31.57, -9.57], - [31.6, -9.5], - [31.68, -9.53], - [31.75, -9.52], - [31.82, -9.48], - [31.9, -9.44], - [32.02, -9.42], - [32.12, -9.43], - [32.22, -9.45], - [32.33, -9.46], - [32.32, -9.36], - [32.27, -9.25], - [32.23, -9.13], - [32.25, -9.14], - [32.38, -9.13], - [32.42, -9.14], - [32.46, -9.17], - [32.47, -9.18], - [32.49, -9.23], - [32.5, -9.25], - [32.52, -9.26], - [32.64, -9.28], - [32.71, -9.29], - [32.74, -9.31], - [32.75, -9.33], - [32.76, -9.34], - [32.83, -9.37], - [32.91, -9.4], - [32.92, -9.41] - ], - "Eastern": [ - [33.31, -11.64], - [33.3, -11.85], - [33.31, -11.88], - [33.3, -11.93], - [33.29, -11.98], - [33.25, -12.07], - [33.26, -12.16], - [33.29, -12.18], - [33.3, -12.2], - [33.31, -12.23], - [33.33, -12.3], - [33.35, -12.33], - [33.38, -12.34], - [33.46, -12.32], - [33.5, -12.33], - [33.53, -12.34], - [33.52, -12.37], - [33.49, -12.39], - [33.48, -12.41], - [33.46, -12.42], - [33.45, -12.45], - [33.42, -12.46], - [33.41, -12.48], - [33.39, -12.5], - [33.37, -12.52], - [33.35, -12.53], - [33.33, -12.54], - [33.31, -12.53], - [33.29, -12.52], - [33.26, -12.53], - [33.24, -12.54], - [33.23, -12.58], - [33.21, -12.59], - [33.2, -12.6], - [33.18, -12.61], - [33.17, -12.62], - [33.15, -12.59], - [33.13, -12.58], - [33.11, -12.59], - [33.09, -12.6], - [33.07, -12.59], - [33.06, -12.58], - [33.05, -12.59], - [33.04, -12.6], - [33.02, -12.61], - [32.99, -12.67], - [32.96, -12.73], - [32.94, -12.75], - [32.95, -12.84], - [32.98, -12.87], - [33.01, -12.89], - [32.98, -13.01], - [32.97, -13.12], - [32.98, -13.17], - [33, -13.19], - [32.99, -13.22], - [32.94, -13.26], - [32.92, -13.29], - [32.91, -13.35], - [32.89, -13.4], - [32.87, -13.44], - [32.85, -13.46], - [32.82, -13.47], - [32.81, -13.53], - [32.8, -13.54], - [32.75, -13.55], - [32.72, -13.57], - [32.71, -13.58], - [32.69, -13.57], - [32.67, -13.58], - [32.66, -13.6], - [32.68, -13.63], - [32.71, -13.64], - [32.77, -13.65], - [32.81, -13.7], - [32.8, -13.72], - [32.77, -13.74], - [32.76, -13.75], - [32.79, -13.79], - [32.83, -13.8], - [32.86, -13.81], - [32.87, -13.82], - [32.92, -13.88], - [32.93, -13.9], - [32.94, -13.93], - [32.97, -13.94], - [32.98, -13.95], - [32.97, -13.96], - [32.98, -14.02], - [33, -14.05], - [33.05, -14], - [33.06, -13.98], - [33.08, -13.97], - [33.11, -13.96], - [33.13, -13.93], - [33.14, -13.92], - [33.15, -13.94], - [33.19, -13.99], - [33.2, -14.01], - [33.13, -14.04], - [33.04, -14.07], - [32.92, -14.11], - [32.74, -14.17], - [32.58, -14.22], - [32.43, -14.27], - [32.32, -14.31], - [32.23, -14.34], - [32.15, -14.35], - [32.11, -14.36], - [32.03, -14.4], - [31.93, -14.43], - [31.8, -14.47], - [31.66, -14.52], - [31.59, -14.55], - [31.5, -14.6], - [31.41, -14.63], - [31.31, -14.66], - [31.18, -14.69], - [31.07, -14.71], - [30.92, -14.75], - [30.82, -14.77], - [30.68, -14.82], - [30.59, -14.85], - [30.49, -14.89], - [30.39, -14.93], - [30.32, -14.97], - [30.23, -14.98], - [30.21, -14.86], - [30.2, -14.83], - [30.19, -14.82], - [30.18, -14.8], - [30.17, -14.79], - [30.15, -14.78], - [30.14, -14.77], - [30.1, -14.72], - [30.09, -14.71], - [30.07, -14.7], - [30.06, -14.69], - [30.05, -14.68], - [30.02, -14.64], - [30, -14.62], - [29.99, -14.61], - [30, -14.56], - [30.01, -14.52], - [30.02, -14.5], - [30.03, -14.48], - [30.05, -14.43], - [30.06, -14.42], - [30.07, -14.41], - [30.08, -14.39], - [30.09, -14.38], - [30.12, -14.37], - [30.13, -14.36], - [30.17, -14.31], - [30.2, -14.29], - [30.21, -14.28], - [30.22, -14.26], - [30.23, -14.25], - [30.25, -14.23], - [30.28, -14.22], - [30.29, -14.21], - [30.3, -14.2], - [30.31, -14.18], - [30.32, -14.16], - [30.31, -14.11], - [30.3, -14.1], - [30.29, -14.09], - [30.28, -14.08], - [30.26, -14.07], - [30.22, -14.06], - [30.19, -14.05], - [30.18, -14.04], - [30.15, -13.96], - [30.14, -13.95], - [30.12, -13.94], - [30.1, -13.93], - [30.89, -13.92], - [30.9, -13.91], - [30.92, -13.89], - [30.94, -13.86], - [30.96, -13.85], - [30.97, -13.81], - [31.01, -13.79], - [31.02, -13.78], - [31.06, -13.77], - [31.07, -13.74], - [31.1, -13.71], - [31.11, -13.7], - [31.12, -13.63], - [31.14, -13.61], - [31.16, -13.6], - [31.17, -13.58], - [31.23, -13.56], - [31.25, -13.53], - [31.26, -13.52], - [31.27, -13.51], - [31.28, -13.52], - [31.29, -13.51], - [31.3, -13.5], - [31.34, -13.47], - [31.36, -13.46], - [31.41, -13.45], - [31.43, -13.44], - [31.44, -13.43], - [31.46, -13.42], - [31.5, -13.43], - [31.61, -13.37], - [31.64, -13.34], - [31.65, -13.3], - [31.66, -13.26], - [31.68, -13.2], - [31.7, -13.19], - [31.71, -13.18], - [31.72, -13.16], - [31.74, -13.13], - [31.75, -13.12], - [31.76, -13.09], - [31.77, -13.1], - [31.81, -13.09], - [31.82, -13.08], - [31.83, -13.06], - [31.86, -13.05], - [31.87, -13.04], - [31.9, -13.03], - [31.91, -13.01], - [31.92, -12.93], - [31.95, -12.92], - [31.97, -12.9], - [31.99, -12.89], - [32.02, -12.88], - [32.03, -12.81], - [32.04, -12.8], - [32.05, -12.79], - [32.07, -12.78], - [32.08, -12.74], - [32.09, -12.69], - [32.1, -12.64], - [32.11, -12.6], - [32.12, -12.59], - [32.14, -12.5], - [32.15, -12.43], - [32.16, -12.4], - [32.17, -12.39], - [32.18, -12.38], - [32.19, -12.35], - [32.21, -12.33], - [32.26, -12.29], - [32.28, -12.26], - [32.29, -12.22], - [32.48, -12.17], - [32.5, -12.11], - [32.54, -12.07], - [32.73, -12.06], - [32.95, -11.99], - [33.09, -11.95], - [33.13, -11.86], - [33.2, -11.75], - [33.22, -11.67], - [33.26, -11.66], - [33.31, -11.64] - ], - "Northern": [ - [30.75, -8.19], - [30.78, -8.29], - [30.83, -8.39], - [30.89, -8.48], - [30.96, -8.55], - [30.99, -8.58], - [31.03, -8.6], - [31.08, -8.62], - [31.14, -8.61], - [31.16, -8.59], - [31.18, -8.58], - [31.22, -8.59], - [31.24, -8.61], - [31.25, -8.62], - [31.33, -8.6], - [31.35, -8.59], - [31.37, -8.6], - [31.39, -8.63], - [31.44, -8.64], - [31.46, -8.67], - [31.48, -8.68], - [31.52, -8.69], - [31.54, -8.7], - [31.55, -8.73], - [31.58, -8.84], - [31.67, -8.91], - [31.69, -8.92], - [31.73, -8.91], - [31.76, -8.89], - [31.94, -8.93], - [31.92, -8.97], - [31.94, -9.06], - [31.98, -9.07], - [32, -9.06], - [32.02, -9.05], - [32.09, -9.07], - [32.13, -9.06], - [32.15, -9.07], - [32.19, -9.11], - [32.21, -9.13], - [32.27, -9.25], - [32.32, -9.36], - [32.33, -9.46], - [32.22, -9.45], - [32.12, -9.43], - [32.02, -9.42], - [31.9, -9.44], - [31.82, -9.48], - [31.75, -9.52], - [31.68, -9.53], - [31.6, -9.5], - [31.57, -9.57], - [31.51, -9.54], - [31.43, -9.55], - [31.37, -9.5], - [31.32, -9.54], - [31.26, -9.59], - [31.21, -9.61], - [31.18, -9.67], - [31.11, -9.76], - [31.19, -9.83], - [31.26, -9.96], - [31.31, -10.07], - [31.34, -10.18], - [31.42, -10.23], - [31.52, -10.28], - [31.55, -10.31], - [31.49, -10.57], - [31.48, -10.56], - [31.47, -10.55], - [31.45, -10.56], - [31.44, -10.57], - [31.42, -10.58], - [31.39, -10.6], - [31.37, -10.61], - [31.33, -10.62], - [31.34, -10.63], - [31.33, -10.64], - [31.31, -10.65], - [31.3, -10.71], - [31.28, -10.72], - [31.24, -10.71], - [31.17, -10.72], - [31.13, -10.75], - [31.15, -10.77], - [31.16, -10.79], - [31.18, -10.78], - [31.2, -10.79], - [31.19, -10.82], - [31.14, -10.83], - [31.15, -10.85], - [31.17, -10.87], - [31.16, -10.89], - [31.15, -10.9], - [31.1, -10.96], - [31.07, -10.95], - [31.08, -10.94], - [31.07, -10.92], - [31.06, -10.91], - [31.05, -10.92], - [31.04, -10.95], - [31.02, -10.94], - [31.01, -10.93], - [31.02, -10.92], - [30.99, -10.94], - [30.98, -10.98], - [30.97, -11], - [30.93, -11.01], - [30.92, -11.02], - [30.89, -11.03], - [30.9, -11.05], - [30.89, -11.06], - [30.87, -11.04], - [30.86, -11.05], - [30.85, -11.06], - [30.84, -11.07], - [30.82, -11.11], - [30.74, -11.21], - [30.72, -11.26], - [30.71, -11.28], - [30.68, -11.31], - [30.67, -11.33], - [30.61, -11.34], - [30.6, -11.35], - [30.59, -11.38], - [30.58, -11.39], - [30.55, -11.4], - [30.54, -11.42], - [30.53, -11.44], - [30.52, -11.46], - [30.5, -11.48], - [30.48, -11.49], - [30.46, -11.5], - [30.45, -11.48], - [30.14, -11.25], - [30.1, -11.24], - [29.96, -11.25], - [29.95, -11.28], - [29.94, -11.29], - [29.9, -11.31], - [29.89, -11.33], - [29.88, -11.35], - [29.85, -11.37], - [29.84, -11.39], - [29.83, -11.4], - [29.89, -11.02], - [29.88, -10.94], - [29.86, -10.9], - [29.85, -10.89], - [29.82, -10.87], - [29.81, -10.86], - [29.79, -10.81], - [29.78, -10.8], - [29.76, -10.79], - [29.75, -10.78], - [29.71, -10.77], - [29.68, -10.75], - [29.66, -10.74], - [29.37, -10.88], - [29.35, -10.9], - [29.34, -10.91], - [29.36, -10.95], - [29.37, -11], - [29.38, -11.02], - [29.39, -11.03], - [29.4, -11.04], - [29.39, -11.08], - [29.38, -11.12], - [29.32, -11.09], - [29.18, -11], - [29.17, -10.99], - [29.09, -10.97], - [29.08, -10.96], - [29.09, -10.95], - [29.11, -10.92], - [29.16, -10.88], - [29.17, -10.74], - [29.29, -10.66], - [29.3, -10.65], - [29.31, -10.64], - [29.36, -10.63], - [29.37, -10.59], - [29.41, -10.54], - [29.4, -10.51], - [29.41, -10.45], - [29.42, -10.44], - [29.43, -10.43], - [29.44, -10.39], - [29.45, -10.38], - [29.47, -10.36], - [29.49, -10.34], - [29.5, -10.33], - [29.52, -10.32], - [29.59, -10.3], - [29.61, -10.29], - [29.62, -10.28], - [29.65, -10.25], - [29.67, -10.24], - [29.68, -10.23], - [29.7, -10.22], - [29.79, -10.23], - [29.82, -10.24], - [29.84, -10.23], - [29.87, -10.22], - [29.88, -10.21], - [29.9, -10.13], - [29.91, -10.1], - [29.92, -10.09], - [29.93, -10.08], - [29.94, -10.07], - [29.93, -10.05], - [29.91, -10.01], - [29.93, -9.91], - [29.94, -9.89], - [29.92, -9.85], - [29.91, -9.83], - [29.89, -9.82], - [29.87, -9.81], - [29.86, -9.79], - [29.84, -9.77], - [29.83, -9.75], - [29.82, -9.74], - [29.81, -9.72], - [29.8, -9.71], - [29.73, -9.7], - [29.7, -9.69], - [29.67, -9.68], - [29.65, -9.67], - [29.6, -9.66], - [29.56, -9.65], - [29.53, -9.64], - [29.52, -9.63], - [29.5, -9.62], - [29.49, -9.61], - [29.48, -9.6], - [29.47, -9.59], - [29.46, -9.56], - [29.44, -9.55], - [29.43, -9.54], - [29.4, -9.55], - [29.37, -9.54], - [29.36, -9.53], - [29.34, -9.47], - [29.33, -9.45], - [29.32, -9.43], - [29.33, -9.4], - [29.34, -9.39], - [29.35, -9.38], - [29.36, -9.37], - [29.34, -9.3], - [29.35, -9.26], - [29.34, -9.25], - [29.33, -9.22], - [29.31, -9.21], - [29.29, -9.2], - [29.27, -9.19], - [29.26, -9.18], - [29.25, -9.16], - [29.24, -9.15], - [29.21, -9.16], - [29.19, -9.15], - [29.18, -9.14], - [29.17, -9.13], - [29.15, -9.12], - [29.12, -9.11], - [29.11, -9.1], - [29.12, -9.05], - [29.13, -9.04], - [29.17, -8.96], - [29.18, -8.95], - [29.19, -8.94], - [29.22, -8.93], - [29.25, -8.91], - [29.28, -8.82], - [29.31, -8.72], - [29.34, -8.64], - [29.35, -8.63], - [29.36, -8.61], - [29.39, -8.55], - [29.41, -8.53], - [29.42, -8.52], - [29.47, -8.5], - [29.5, -8.49], - [29.52, -8.47], - [29.54, -8.45], - [29.57, -8.39], - [29.58, -8.37], - [29.86, -8.33], - [30.12, -8.29], - [30.32, -8.26], - [30.58, -8.22], - [30.75, -8.19] - ], - "Lusaka": [ - [30.01, -15.65], - [29.97, -15.64], - [29.88, -15.62], - [29.84, -15.61], - [29.81, -15.62], - [29.77, -15.64], - [29.67, -15.66], - [29.65, -15.67], - [29.63, -15.66], - [29.53, -15.69], - [29.51, -15.7], - [29.42, -15.71], - [29.19, -15.81], - [29.15, -15.85], - [29.12, -15.86], - [29.1, -15.87], - [29.09, -15.88], - [29.08, -15.9], - [29.06, -15.93], - [29.04, -15.95], - [28.95, -15.96], - [28.93, -15.94], - [28.91, -15.93], - [28.87, -15.94], - [28.84, -15.95], - [28.82, -15.94], - [28.81, -15.95], - [28.8, -15.96], - [28.78, -15.95], - [28.68, -15.9], - [28.66, -15.89], - [28.57, -15.88], - [28.52, -15.84], - [28.51, -15.82], - [28.45, -15.81], - [28.42, -15.8], - [28.41, -15.79], - [28.39, -15.78], - [28.29, -15.79], - [28.28, -15.8], - [28.25, -15.82], - [28.23, -15.81], - [28.2, -15.79], - [28.18, -15.78], - [28.08, -15.74], - [28.04, -15.73], - [28.03, -15.72], - [28.02, -15.7], - [28.01, -15.68], - [27.97, -15.67], - [27.93, -15.66], - [27.89, -15.67], - [27.86, -15.69], - [27.85, -15.68], - [27.84, -15.67], - [27.82, -15.65], - [27.8, -15.56], - [27.91, -15.53], - [27.92, -15.52], - [27.93, -15.51], - [27.92, -15.42], - [27.89, -15.37], - [27.88, -15.36], - [27.81, -15.35], - [27.79, -15.34], - [27.77, -15.33], - [27.78, -15.3], - [27.83, -15.27], - [27.84, -15.26], - [28.03, -15.29], - [28.2, -15.34], - [28.26, -15.35], - [28.29, -15.34], - [28.32, -15.3], - [28.34, -15.22], - [28.38, -15.16], - [28.4, -15.15], - [28.57, -15.19], - [28.74, -15.18], - [28.82, -15.15], - [28.95, -15.04], - [29, -15.02], - [29.05, -15.01], - [29.23, -14.96], - [29.31, -14.98], - [29.46, -14.96], - [29.49, -14.91], - [29.5, -14.87], - [29.51, -14.84], - [29.52, -14.82], - [29.53, -14.81], - [29.59, -14.8], - [29.65, -14.77], - [29.66, -14.76], - [29.67, -14.75], - [29.75, -14.72], - [29.81, -14.7], - [29.88, -14.69], - [29.89, -14.68], - [29.9, -14.66], - [29.91, -14.65], - [29.92, -14.66], - [29.95, -14.65], - [29.99, -14.66], - [30, -14.67], - [30.05, -14.68], - [30.06, -14.69], - [30.07, -14.7], - [30.09, -14.71], - [30.1, -14.72], - [30.14, -14.77], - [30.15, -14.78], - [30.17, -14.79], - [30.18, -14.8], - [30.19, -14.82], - [30.2, -14.83], - [30.21, -14.86], - [30.22, -15.02], - [30.23, -15.11], - [30.26, -15.23], - [30.29, -15.28], - [30.32, -15.3], - [30.35, -15.32], - [30.36, -15.34], - [30.37, -15.37], - [30.39, -15.47], - [30.37, -15.53], - [30.4, -15.59], - [30.41, -15.63], - [30.4, -15.64], - [30.36, -15.65], - [30.3, -15.64], - [30.28, -15.63], - [30.23, -15.64], - [30.22, -15.65], - [30.17, -15.63], - [30.13, -15.62], - [30.09, -15.63], - [30.05, -15.64], - [30.01, -15.65] - ], - "Southern": [ - [28.95, -15.96], - [28.9, -16], - [28.88, -16.02], - [28.87, -16.03], - [28.86, -16.05], - [28.87, -16.08], - [28.85, -16.16], - [28.86, -16.23], - [28.84, -16.28], - [28.86, -16.37], - [28.83, -16.43], - [28.82, -16.47], - [28.81, -16.49], - [28.77, -16.52], - [28.76, -16.53], - [28.74, -16.55], - [28.73, -16.56], - [28.64, -16.57], - [28.28, -16.71], - [28.21, -16.75], - [28.11, -16.83], - [28.02, -16.87], - [27.87, -16.93], - [27.82, -16.96], - [27.78, -17], - [27.64, -17.2], - [27.62, -17.23], - [27.6, -17.31], - [27.58, -17.36], - [27.52, -17.42], - [27.42, -17.5], - [27.16, -17.77], - [27.15, -17.78], - [27.12, -17.88], - [27.08, -17.92], - [27.05, -17.94], - [27.02, -17.96], - [26.95, -17.97], - [26.91, -17.99], - [26.89, -17.98], - [26.79, -18.03], - [26.74, -18.04], - [26.71, -18.07], - [26.63, -18.05], - [26.61, -18.04], - [26.6, -18.03], - [26.58, -18.01], - [26.57, -18], - [26.53, -17.99], - [26.49, -17.98], - [26.41, -17.94], - [26.36, -17.93], - [26.33, -17.94], - [26.32, -17.93], - [26.3, -17.92], - [26.25, -17.91], - [26.23, -17.9], - [26.22, -17.89], - [26.21, -17.88], - [26.2, -17.89], - [26.17, -17.91], - [26.16, -17.92], - [26.12, -17.93], - [26.1, -17.94], - [26.08, -17.96], - [26.05, -17.97], - [26.04, -17.98], - [26.03, -17.97], - [25.98, -18], - [25.86, -17.97], - [25.85, -17.96], - [25.86, -17.92], - [25.85, -17.91], - [25.8, -17.89], - [25.79, -17.87], - [25.77, -17.85], - [25.74, -17.84], - [25.71, -17.83], - [25.69, -17.82], - [25.68, -17.81], - [25.6, -17.84], - [25.54, -17.85], - [25.52, -17.86], - [25.5, -17.85], - [25.38, -17.84], - [25.32, -17.83], - [25.29, -17.81], - [25.27, -17.8], - [25.26, -17.79], - [25.25, -17.78], - [25.24, -17.77], - [25.23, -17.76], - [25.18, -17.74], - [25.16, -17.73], - [25.15, -17.7], - [25.14, -17.69], - [25.12, -17.7], - [25.11, -17.68], - [25.1, -17.67], - [25.09, -17.64], - [25.07, -17.63], - [25.06, -17.62], - [25.03, -17.61], - [25.04, -17.58], - [25.01, -17.59], - [24.98, -17.58], - [24.97, -17.56], - [24.98, -17.49], - [24.99, -17.47], - [25, -17.46], - [25.01, -17.44], - [25.02, -17.43], - [25.03, -17.42], - [25.02, -17.4], - [25.03, -17.32], - [25.05, -17.3], - [25.07, -17.27], - [25.08, -17.25], - [25.1, -17.22], - [25.09, -17.2], - [25.08, -17.18], - [25.09, -17.15], - [25.1, -17.13], - [25.13, -17.11], - [25.14, -17.1], - [25.16, -17.08], - [25.17, -17.01], - [25.18, -17], - [25.24, -16.98], - [25.25, -16.97], - [25.27, -16.93], - [25.28, -16.92], - [25.25, -16.81], - [25.24, -16.8], - [25.25, -16.73], - [25.24, -16.7], - [25.23, -16.69], - [25.11, -16.67], - [25.08, -16.64], - [25.07, -16.61], - [25.03, -16.58], - [25.01, -16.56], - [25, -16.55], - [25.02, -16.52], - [25.04, -16.51], - [25.14, -16.38], - [25.15, -16.37], - [25.17, -16.36], - [25.19, -16.35], - [25.2, -16.34], - [25.23, -16.33], - [25.24, -16.32], - [25.25, -16.31], - [25.26, -16.3], - [25.29, -16.29], - [25.3, -16.27], - [25.33, -16.22], - [25.34, -16.2], - [25.35, -16.17], - [25.36, -16.16], - [25.37, -16.15], - [25.38, -16.14], - [25.39, -16.13], - [25.4, -16.12], - [25.41, -16.11], - [25.42, -16.1], - [25.43, -16.09], - [25.42, -16.08], - [25.39, -16.07], - [25.37, -16.06], - [25.35, -16.04], - [25.34, -16.03], - [25.33, -16.01], - [25.34, -15.99], - [25.35, -15.98], - [25.36, -15.97], - [25.35, -15.96], - [25.36, -15.92], - [25.37, -15.9], - [25.38, -15.88], - [25.4, -15.77], - [25.39, -15.75], - [25.38, -15.73], - [25.37, -15.72], - [25.36, -15.73], - [25.35, -15.74], - [25.34, -15.75], - [25.33, -15.76], - [25.28, -15.75], - [25.27, -15.74], - [25.26, -15.72], - [25.25, -15.71], - [25.26, -15.69], - [25.27, -15.68], - [25.28, -15.67], - [25.27, -15.64], - [25.26, -15.63], - [25.23, -15.61], - [25.22, -15.59], - [25.23, -15.58], - [25.26, -15.56], - [25.27, -15.54], - [25.26, -15.52], - [25.25, -15.5], - [25.24, -15.49], - [25.25, -15.48], - [25.27, -15.47], - [25.31, -15.44], - [25.32, -15.42], - [25.33, -15.37], - [25.34, -15.36], - [25.35, -15.35], - [25.34, -15.33], - [25.33, -15.31], - [25.32, -15.3], - [26.75, -15.34], - [26.84, -15.35], - [26.98, -15.43], - [26.99, -15.44], - [26.96, -15.46], - [26.97, -15.47], - [27.2, -15.48], - [27.23, -15.5], - [27.28, -15.71], - [27.29, -15.73], - [27.3, -15.74], - [27.32, -15.73], - [27.4, -15.58], - [27.41, -15.57], - [27.45, -15.58], - [27.46, -15.57], - [27.47, -15.56], - [27.49, -15.55], - [27.5, -15.54], - [27.51, -15.53], - [27.52, -15.51], - [27.53, -15.5], - [27.54, -15.48], - [27.57, -15.49], - [27.58, -15.5], - [27.63, -15.52], - [27.64, -15.54], - [27.66, -15.55], - [27.67, -15.6], - [27.66, -15.61], - [27.65, -15.62], - [27.67, -15.64], - [27.68, -15.65], - [27.69, -15.66], - [27.75, -15.65], - [27.84, -15.66], - [27.85, -15.68], - [27.86, -15.69], - [27.89, -15.67], - [27.93, -15.66], - [27.97, -15.67], - [28.01, -15.68], - [28.02, -15.7], - [28.03, -15.72], - [28.04, -15.73], - [28.06, -15.74], - [28.18, -15.78], - [28.2, -15.79], - [28.23, -15.81], - [28.24, -15.82], - [28.28, -15.8], - [28.29, -15.79], - [28.39, -15.78], - [28.41, -15.79], - [28.42, -15.8], - [28.44, -15.81], - [28.49, -15.82], - [28.52, -15.84], - [28.57, -15.88], - [28.58, -15.89], - [28.68, -15.9], - [28.74, -15.95], - [28.8, -15.96], - [28.81, -15.95], - [28.82, -15.94], - [28.84, -15.95], - [28.85, -15.94], - [28.89, -15.93], - [28.93, -15.94], - [28.95, -15.96] - ], - "Western": [ - [22.02, -16.25], - [22.01, -16.2], - [21.98, -16.17], - [22, -13.7], - [22.03, -13.71], - [22.04, -13.72], - [22.07, -13.74], - [22.08, -13.76], - [22.16, -13.75], - [22.17, -13.74], - [22.18, -13.73], - [22.2, -13.71], - [22.21, -13.69], - [22.22, -13.68], - [22.25, -13.69], - [22.28, -13.7], - [22.29, -13.71], - [22.43, -13.83], - [22.5, -13.87], - [22.51, -13.89], - [22.54, -13.91], - [22.58, -13.92], - [22.61, -13.93], - [22.62, -13.94], - [22.63, -13.95], - [22.64, -13.97], - [22.68, -13.98], - [22.7, -13.99], - [22.73, -13.98], - [22.74, -13.91], - [22.75, -13.9], - [22.83, -13.87], - [22.88, -13.88], - [22.96, -13.94], - [22.98, -13.95], - [22.99, -13.97], - [23, -13.99], - [23.05, -13.98], - [23.09, -13.99], - [23.1, -14], - [23.11, -14.04], - [23.12, -14.05], - [23.13, -14.06], - [23.22, -14.07], - [23.23, -14.08], - [23.22, -14.09], - [23.21, -14.1], - [23.19, -14.13], - [23.18, -14.15], - [23.22, -14.14], - [23.23, -14.15], - [23.22, -14.17], - [23.28, -14.16], - [23.31, -14.14], - [23.32, -14.13], - [23.34, -14.14], - [23.37, -14.13], - [23.41, -14.1], - [23.44, -14.09], - [23.54, -14.06], - [23.56, -14.05], - [23.59, -14.02], - [23.63, -14.01], - [23.67, -13.99], - [23.7, -14], - [23.72, -14.01], - [23.77, -13.99], - [23.8, -13.98], - [23.82, -13.96], - [23.83, -13.98], - [23.84, -13.99], - [23.9, -14], - [23.93, -13.99], - [23.97, -14], - [24.02, -13.99], - [24.03, -13.98], - [24.04, -13.97], - [24.06, -13.98], - [24.07, -13.97], - [24.08, -13.96], - [24.09, -13.95], - [24.11, -13.96], - [24.13, -13.95], - [24.15, -13.94], - [24.16, -13.93], - [24.19, -13.92], - [24.21, -13.91], - [24.25, -13.92], - [24.27, -13.93], - [24.29, -13.94], - [24.3, -13.93], - [24.29, -13.92], - [24.3, -13.91], - [24.31, -13.89], - [24.32, -13.91], - [24.33, -13.92], - [24.34, -13.95], - [24.38, -13.96], - [24.4, -13.95], - [24.41, -13.96], - [24.43, -13.95], - [24.47, -13.94], - [24.48, -13.93], - [24.49, -13.92], - [24.51, -13.94], - [24.52, -13.95], - [24.53, -13.96], - [24.55, -13.97], - [24.57, -13.98], - [24.58, -13.99], - [24.59, -13.98], - [24.6, -13.96], - [24.62, -13.97], - [24.61, -13.99], - [24.62, -14], - [24.63, -13.98], - [24.64, -13.97], - [24.65, -13.96], - [24.69, -13.99], - [24.71, -14], - [24.72, -14.02], - [24.73, -14.05], - [24.74, -14.11], - [24.75, -14.12], - [24.8, -14.14], - [24.85, -14.15], - [24.88, -14.16], - [24.99, -14.21], - [25.01, -14.22], - [25.06, -14.21], - [25.07, -14.22], - [25.08, -14.23], - [25.09, -14.24], - [25.08, -14.3], - [25.07, -14.33], - [25.06, -14.34], - [25.05, -14.37], - [25.04, -14.44], - [25.03, -14.45], - [25, -14.46], - [24.98, -14.47], - [24.97, -14.48], - [24.96, -14.49], - [24.97, -14.52], - [24.96, -14.55], - [24.97, -14.57], - [24.98, -14.59], - [25, -14.62], - [25.02, -14.63], - [25.04, -14.64], - [25.06, -14.63], - [25.19, -14.62], - [25.21, -14.61], - [25.24, -14.6], - [25.28, -14.59], - [25.31, -14.58], - [25.41, -14.59], - [25.43, -14.6], - [25.51, -14.59], - [25.52, -14.58], - [25.55, -14.59], - [25.53, -14.6], - [25.51, -14.63], - [25.5, -14.64], - [25.49, -14.67], - [25.48, -14.68], - [25.47, -14.79], - [25.46, -14.8], - [25.45, -14.81], - [25.44, -14.83], - [25.43, -14.86], - [25.42, -14.88], - [25.43, -14.91], - [25.45, -14.97], - [25.46, -14.98], - [25.45, -15.03], - [25.43, -15.06], - [25.42, -15.08], - [25.41, -15.09], - [25.42, -15.12], - [25.41, -15.13], - [25.4, -15.14], - [25.38, -15.13], - [25.37, -15.14], - [25.36, -15.15], - [25.33, -15.18], - [25.32, -15.19], - [25.33, -15.23], - [25.32, -15.3], - [25.33, -15.31], - [25.34, -15.33], - [25.35, -15.34], - [25.34, -15.35], - [25.33, -15.37], - [25.32, -15.38], - [25.31, -15.43], - [25.3, -15.47], - [25.25, -15.48], - [25.24, -15.49], - [25.25, -15.5], - [25.26, -15.52], - [25.27, -15.53], - [25.26, -15.55], - [25.23, -15.58], - [25.22, -15.59], - [25.23, -15.6], - [25.25, -15.63], - [25.27, -15.64], - [25.28, -15.65], - [25.27, -15.67], - [25.26, -15.69], - [25.25, -15.7], - [25.26, -15.72], - [25.27, -15.74], - [25.28, -15.75], - [25.29, -15.76], - [25.34, -15.75], - [25.35, -15.74], - [25.36, -15.73], - [25.37, -15.72], - [25.38, -15.73], - [25.39, -15.74], - [25.4, -15.75], - [25.38, -15.88], - [25.37, -15.9], - [25.36, -15.91], - [25.35, -15.92], - [25.36, -15.97], - [25.35, -15.98], - [25.34, -15.99], - [25.33, -16], - [25.34, -16.02], - [25.35, -16.04], - [25.37, -16.06], - [25.38, -16.07], - [25.39, -16.08], - [25.43, -16.09], - [25.42, -16.1], - [25.41, -16.11], - [25.4, -16.12], - [25.39, -16.13], - [25.38, -16.14], - [25.37, -16.15], - [25.36, -16.16], - [25.35, -16.17], - [25.34, -16.2], - [25.33, -16.21], - [25.3, -16.27], - [25.29, -16.29], - [25.28, -16.3], - [25.25, -16.31], - [25.24, -16.32], - [25.23, -16.33], - [25.21, -16.34], - [25.19, -16.35], - [25.17, -16.36], - [25.15, -16.37], - [25.14, -16.38], - [25.04, -16.51], - [25.03, -16.52], - [25, -16.53], - [25.01, -16.56], - [25.03, -16.58], - [25.07, -16.6], - [25.08, -16.61], - [25.1, -16.67], - [25.21, -16.69], - [25.24, -16.7], - [25.25, -16.71], - [25.24, -16.77], - [25.25, -16.81], - [25.28, -16.91], - [25.27, -16.93], - [25.25, -16.96], - [25.24, -16.98], - [25.19, -17], - [25.17, -17.01], - [25.16, -17.03], - [25.14, -17.1], - [25.13, -17.11], - [25.1, -17.12], - [25.09, -17.14], - [25.08, -17.18], - [25.09, -17.19], - [25.1, -17.21], - [25.08, -17.25], - [25.07, -17.27], - [25.05, -17.29], - [25.03, -17.31], - [25.02, -17.32], - [25.03, -17.41], - [25.02, -17.43], - [25.01, -17.44], - [25, -17.45], - [24.99, -17.47], - [24.98, -17.49], - [24.97, -17.56], - [24.96, -17.55], - [24.94, -17.56], - [24.92, -17.54], - [24.9, -17.53], - [24.83, -17.52], - [24.78, -17.51], - [24.68, -17.49], - [24.63, -17.5], - [24.62, -17.51], - [24.61, -17.52], - [24.59, -17.53], - [24.54, -17.52], - [24.53, -17.51], - [24.5, -17.5], - [24.48, -17.49], - [24.41, -17.47], - [24.33, -17.49], - [24.31, -17.48], - [24.19, -17.49], - [24.11, -17.5], - [24.06, -17.51], - [24.02, -17.52], - [23.98, -17.53], - [23.93, -17.54], - [23.85, -17.55], - [23.81, -17.56], - [23.76, -17.57], - [23.72, -17.58], - [23.68, -17.59], - [23.63, -17.6], - [23.55, -17.61], - [23.51, -17.62], - [23.48, -17.63], - [23.38, -17.64], - [23.36, -17.58], - [23.34, -17.56], - [23.32, -17.55], - [23.31, -17.54], - [23.26, -17.53], - [23.24, -17.54], - [23.18, -17.52], - [23.17, -17.47], - [23.12, -17.45], - [23.1, -17.43], - [23.07, -17.41], - [23.05, -17.38], - [23.04, -17.34], - [23, -17.29], - [22.94, -17.27], - [22.88, -17.25], - [22.85, -17.23], - [22.81, -17.2], - [22.78, -17.18], - [22.77, -17.17], - [22.76, -17.15], - [22.74, -17.11], - [22.73, -17.08], - [22.71, -17.06], - [22.67, -17.01], - [22.65, -17], - [22.59, -16.98], - [22.57, -16.97], - [22.55, -16.92], - [22.52, -16.91], - [22.5, -16.89], - [22.49, -16.87], - [22.42, -16.75], - [22.4, -16.74], - [22.38, -16.73], - [22.37, -16.72], - [22.35, -16.7], - [22.34, -16.68], - [22.33, -16.67], - [22.3, -16.66], - [22.26, -16.67], - [22.15, -16.6], - [22.14, -16.57], - [22.13, -16.55], - [22.11, -16.54], - [22.1, -16.5], - [22.08, -16.47], - [22.09, -16.42], - [22.1, -16.39], - [22.11, -16.38], - [22.09, -16.37], - [22.06, -16.36], - [22.05, -16.34], - [22.04, -16.31], - [22.03, -16.29], - [22.02, -16.27], - [22.01, -16.25] - ], - "North-Western": [ - [21.98, -13.69], - [22.1, -13], - [23.99, -12.97], - [23.97, -12.93], - [23.95, -12.9], - [23.9, -12.85], - [23.87, -12.82], - [23.89, -12.71], - [23.91, -12.63], - [23.93, -12.56], - [23.94, -12.53], - [23.99, -12.47], - [24.02, -12.42], - [24.03, -12.4], - [24.02, -12.34], - [24.01, -12.25], - [23.98, -12.23], - [23.96, -12.2], - [23.95, -12.15], - [23.96, -12.01], - [23.97, -11.88], - [23.99, -11.83], - [23.98, -11.72], - [23.97, -11.7], - [23.96, -11.68], - [23.95, -11.66], - [23.96, -11.62], - [23.98, -11.58], - [24.01, -11.54], - [24.02, -11.44], - [24.05, -11.42], - [24.06, -11.41], - [24.02, -11.3], - [24.01, -11.27], - [24.02, -11.13], - [23.99, -11.11], - [24, -11], - [23.98, -10.94], - [23.97, -10.92], - [24, -10.87], - [24.05, -10.88], - [24.09, -10.9], - [24.11, -10.92], - [24.12, -10.99], - [24.14, -11.04], - [24.16, -11.03], - [24.22, -11.05], - [24.32, -11.06], - [24.35, -11.08], - [24.37, -11.1], - [24.38, -11.12], - [24.37, -11.14], - [24.36, -11.15], - [24.37, -11.18], - [24.38, -11.19], - [24.39, -11.2], - [24.4, -11.22], - [24.39, -11.28], - [24.38, -11.3], - [24.35, -11.35], - [24.34, -11.36], - [24.3, -11.37], - [24.29, -11.38], - [24.31, -11.41], - [24.39, -11.42], - [24.43, -11.45], - [24.45, -11.46], - [24.47, -11.47], - [24.49, -11.46], - [24.53, -11.45], - [24.56, -11.44], - [24.57, -11.43], - [24.58, -11.42], - [24.59, -11.4], - [24.62, -11.39], - [24.65, -11.38], - [24.66, -11.35], - [24.67, -11.34], - [24.71, -11.33], - [24.83, -11.32], - [24.9, -11.28], - [24.94, -11.27], - [25.12, -11.26], - [25.18, -11.25], - [25.28, -11.2], - [25.31, -11.19], - [25.32, -11.21], - [25.33, -11.27], - [25.32, -11.28], - [25.3, -11.3], - [25.28, -11.31], - [25.29, -11.32], - [25.31, -11.33], - [25.3, -11.35], - [25.29, -11.36], - [25.28, -11.37], - [25.29, -11.42], - [25.31, -11.46], - [25.32, -11.47], - [25.3, -11.5], - [25.33, -11.62], - [25.34, -11.63], - [25.35, -11.65], - [25.39, -11.66], - [25.41, -11.67], - [25.46, -11.7], - [25.48, -11.72], - [25.47, -11.76], - [25.48, -11.77], - [25.5, -11.78], - [25.52, -11.77], - [25.53, -11.76], - [25.56, -11.75], - [25.57, -11.73], - [25.66, -11.75], - [25.69, -11.78], - [25.73, -11.8], - [25.83, -11.79], - [25.86, -11.8], - [25.91, -11.85], - [25.95, -11.86], - [25.96, -11.9], - [26.19, -11.91], - [26.21, -11.92], - [26.23, -11.93], - [26.29, -11.94], - [26.33, -11.92], - [26.38, -11.91], - [26.44, -11.92], - [26.46, -11.93], - [26.47, -11.95], - [26.49, -11.96], - [26.52, -11.97], - [26.61, -11.98], - [26.64, -11.99], - [26.66, -12], - [26.68, -12.01], - [26.7, -12.02], - [26.72, -12.01], - [26.73, -12], - [26.74, -11.98], - [26.76, -11.97], - [26.87, -11.96], - [26.91, -11.94], - [26.95, -11.91], - [26.97, -11.87], - [26.98, -11.75], - [27, -11.73], - [27.01, -11.71], - [27.02, -11.7], - [27.01, -11.63], - [27.02, -11.6], - [27.03, -11.59], - [27.05, -11.6], - [27.1, -11.58], - [27.17, -11.57], - [27.2, -11.59], - [27.21, -11.64], - [27.23, -11.81], - [27.42, -11.92], - [27.47, -12], - [27.52, -12.18], - [27.54, -12.2], - [27.59, -12.24], - [27.54, -12.27], - [27.52, -12.28], - [27.51, -12.3], - [27.5, -12.29], - [27.46, -12.28], - [27.47, -12.27], - [27.45, -12.26], - [27.44, -12.25], - [27.43, -12.24], - [27.41, -12.25], - [27.4, -12.26], - [27.39, -12.27], - [27.37, -12.28], - [27.35, -12.29], - [27.34, -12.3], - [27.32, -12.31], - [27.31, -12.32], - [27.29, -12.34], - [27.28, -12.35], - [27.15, -12.33], - [27.12, -12.34], - [27.06, -12.33], - [27.05, -12.34], - [27.07, -12.38], - [27.06, -12.43], - [27.05, -12.45], - [27.06, -12.47], - [27.07, -12.5], - [27.08, -12.51], - [27.07, -12.52], - [27.03, -12.53], - [27.01, -12.54], - [26.97, -12.58], - [26.96, -12.6], - [26.95, -12.61], - [26.94, -12.62], - [26.93, -12.63], - [26.89, -12.64], - [26.87, -12.66], - [26.86, -12.67], - [26.85, -12.72], - [26.86, -12.76], - [26.87, -12.77], - [26.88, -12.79], - [26.9, -12.81], - [26.91, -12.82], - [26.9, -12.84], - [26.89, -12.86], - [26.88, -12.88], - [26.89, -12.9], - [26.91, -12.91], - [26.92, -12.92], - [26.93, -12.93], - [26.96, -12.94], - [26.97, -12.95], - [27.01, -12.96], - [27.02, -12.97], - [27.03, -12.98], - [27.04, -12.99], - [27.05, -13], - [27.07, -13.12], - [27.06, -13.13], - [27.05, -13.14], - [27.04, -13.15], - [26.98, -13.19], - [26.97, -13.2], - [26.96, -13.22], - [26.98, -13.28], - [26.97, -13.33], - [26.96, -13.35], - [26.95, -13.37], - [26.93, -13.38], - [26.91, -13.41], - [26.9, -13.42], - [26.89, -13.43], - [26.86, -13.44], - [26.85, -13.45], - [26.84, -13.5], - [26.83, -13.52], - [26.81, -13.53], - [26.8, -13.55], - [26.79, -13.58], - [26.8, -13.68], - [26.82, -13.69], - [26.85, -13.72], - [26.87, -13.73], - [26.88, -13.74], - [26.89, -13.75], - [26.9, -13.78], - [26.91, -13.79], - [26.92, -13.8], - [26.95, -13.81], - [26.94, -13.86], - [26.92, -13.89], - [26.91, -13.91], - [26.9, -14.01], - [26.89, -14.02], - [26.87, -14.03], - [26.86, -14.04], - [26.9, -14.07], - [26.91, -14.08], - [26.96, -14.14], - [26.97, -14.15], - [26.98, -14.17], - [26.96, -14.24], - [26.95, -14.25], - [26.96, -14.37], - [26.95, -14.39], - [26.94, -14.4], - [26.93, -14.41], - [26.79, -14.42], - [26.75, -14.44], - [26.74, -14.45], - [26.65, -14.44], - [26.64, -14.45], - [26.63, -14.46], - [26.62, -14.45], - [26.59, -14.44], - [26.56, -14.45], - [26.54, -14.46], - [26.53, -14.47], - [26.49, -14.53], - [26.43, -14.58], - [26.39, -14.63], - [26.38, -14.65], - [26.37, -14.7], - [26.33, -14.71], - [26.32, -14.72], - [26.31, -14.71], - [26.3, -14.7], - [26.29, -14.69], - [26.25, -14.67], - [26.22, -14.66], - [26.2, -14.65], - [26.18, -14.63], - [26.17, -14.62], - [25.62, -14.56], - [25.57, -14.57], - [25.55, -14.59], - [25.52, -14.58], - [25.51, -14.59], - [25.48, -14.6], - [25.42, -14.59], - [25.39, -14.58], - [25.29, -14.59], - [25.24, -14.6], - [25.22, -14.61], - [25.19, -14.62], - [25.15, -14.63], - [25.05, -14.64], - [25.03, -14.63], - [25.01, -14.62], - [24.98, -14.59], - [24.97, -14.58], - [24.96, -14.56], - [24.97, -14.52], - [24.96, -14.49], - [24.97, -14.48], - [24.98, -14.47], - [25, -14.46], - [25.03, -14.45], - [25.04, -14.44], - [25.05, -14.43], - [25.06, -14.35], - [25.07, -14.33], - [25.08, -14.31], - [25.09, -14.29], - [25.08, -14.23], - [25.07, -14.22], - [25.06, -14.21], - [25.02, -14.22], - [24.99, -14.21], - [24.88, -14.16], - [24.87, -14.15], - [24.82, -14.14], - [24.75, -14.12], - [24.74, -14.11], - [24.73, -14.1], - [24.72, -14.03], - [24.71, -14.01], - [24.69, -13.99], - [24.67, -13.96], - [24.65, -13.97], - [24.63, -13.98], - [24.62, -14], - [24.61, -13.99], - [24.62, -13.97], - [24.61, -13.96], - [24.59, -13.97], - [24.58, -13.99], - [24.57, -13.98], - [24.55, -13.97], - [24.54, -13.96], - [24.52, -13.95], - [24.51, -13.94], - [24.49, -13.92], - [24.48, -13.93], - [24.46, -13.94], - [24.47, -13.95], - [24.43, -13.96], - [24.41, -13.95], - [24.39, -13.96], - [24.34, -13.95], - [24.33, -13.94], - [24.32, -13.91], - [24.31, -13.9], - [24.3, -13.89], - [24.29, -13.91], - [24.3, -13.93], - [24.29, -13.94], - [24.27, -13.93], - [24.25, -13.92], - [24.23, -13.91], - [24.2, -13.92], - [24.19, -13.93], - [24.15, -13.94], - [24.14, -13.95], - [24.13, -13.96], - [24.11, -13.95], - [24.08, -13.96], - [24.07, -13.97], - [24.06, -13.98], - [24.05, -13.97], - [24.03, -13.98], - [24.02, -13.99], - [24.01, -14], - [23.96, -13.99], - [23.92, -14], - [23.87, -13.99], - [23.83, -13.98], - [23.82, -13.96], - [23.8, -13.98], - [23.79, -13.99], - [23.73, -14.01], - [23.7, -14], - [23.68, -13.99], - [23.63, -14.01], - [23.59, -14.02], - [23.56, -14.05], - [23.54, -14.06], - [23.44, -14.09], - [23.41, -14.1], - [23.38, -14.13], - [23.35, -14.14], - [23.32, -14.13], - [23.31, -14.14], - [23.28, -14.16], - [23.26, -14.17], - [23.23, -14.16], - [23.22, -14.14], - [23.18, -14.15], - [23.19, -14.13], - [23.21, -14.1], - [23.22, -14.09], - [23.23, -14.08], - [23.22, -14.07], - [23.14, -14.06], - [23.12, -14.05], - [23.11, -14.04], - [23.1, -14.03], - [23.09, -13.99], - [23.08, -13.98], - [23.03, -13.99], - [22.99, -13.98], - [22.98, -13.96], - [22.96, -13.94], - [22.88, -13.88], - [22.85, -13.87], - [22.81, -13.9], - [22.75, -13.91], - [22.73, -13.97], - [22.72, -13.99], - [22.69, -13.98], - [22.67, -13.97], - [22.63, -13.96], - [22.62, -13.94], - [22.61, -13.93], - [22.59, -13.92], - [22.57, -13.91], - [22.52, -13.89], - [22.5, -13.87], - [22.43, -13.83], - [22.29, -13.71], - [22.28, -13.7], - [22.25, -13.69], - [22.24, -13.68], - [22.22, -13.69], - [22.2, -13.71], - [22.18, -13.72], - [22.17, -13.74], - [22.16, -13.75], - [22.14, -13.76], - [22.07, -13.74], - [22.04, -13.72], - [22.03, -13.71], - [22, -13.7], - [21.98, -13.69] - ], - "Luapula": [ - [28.59, -9.54], - [28.57, -9.53], - [28.56, -9.48], - [28.53, -9.46], - [28.52, -9.45], - [28.51, -9.43], - [28.52, -9.42], - [28.5, -9.35], - [28.46, -9.34], - [28.41, -9.32], - [28.37, -9.31], - [28.35, -9.27], - [28.37, -9.24], - [28.42, -9.21], - [28.51, -9.16], - [28.6, -9.1], - [28.77, -8.93], - [28.89, -8.77], - [28.93, -8.68], - [28.94, -8.59], - [28.89, -8.5], - [28.92, -8.47], - [29.04, -8.45], - [29.21, -8.43], - [29.37, -8.4], - [29.58, -8.37], - [29.57, -8.39], - [29.54, -8.45], - [29.53, -8.47], - [29.51, -8.49], - [29.47, -8.5], - [29.43, -8.52], - [29.41, -8.53], - [29.39, -8.55], - [29.36, -8.61], - [29.35, -8.63], - [29.34, -8.64], - [29.31, -8.72], - [29.28, -8.82], - [29.25, -8.9], - [29.23, -8.93], - [29.19, -8.94], - [29.18, -8.95], - [29.17, -8.96], - [29.15, -9.04], - [29.12, -9.05], - [29.11, -9.06], - [29.12, -9.11], - [29.13, -9.12], - [29.16, -9.13], - [29.18, -9.14], - [29.19, -9.15], - [29.2, -9.16], - [29.22, -9.15], - [29.24, -9.16], - [29.26, -9.18], - [29.27, -9.19], - [29.28, -9.2], - [29.3, -9.21], - [29.31, -9.22], - [29.33, -9.21], - [29.34, -9.22], - [29.35, -9.26], - [29.34, -9.28], - [29.36, -9.36], - [29.35, -9.37], - [29.34, -9.39], - [29.33, -9.4], - [29.32, -9.43], - [29.33, -9.44], - [29.34, -9.47], - [29.36, -9.52], - [29.37, -9.54], - [29.38, -9.55], - [29.4, -9.54], - [29.44, -9.55], - [29.45, -9.56], - [29.47, -9.59], - [29.48, -9.6], - [29.49, -9.61], - [29.5, -9.62], - [29.52, -9.63], - [29.53, -9.64], - [29.54, -9.65], - [29.57, -9.66], - [29.62, -9.67], - [29.67, -9.68], - [29.7, -9.69], - [29.72, -9.7], - [29.73, -9.71], - [29.81, -9.72], - [29.82, -9.74], - [29.83, -9.75], - [29.84, -9.77], - [29.86, -9.78], - [29.87, -9.81], - [29.88, -9.82], - [29.9, -9.83], - [29.92, -9.84], - [29.94, -9.88], - [29.93, -9.91], - [29.91, -9.98], - [29.93, -10.05], - [29.94, -10.06], - [29.93, -10.08], - [29.92, -10.09], - [29.91, -10.1], - [29.9, -10.11], - [29.88, -10.2], - [29.87, -10.21], - [29.85, -10.23], - [29.84, -10.24], - [29.81, -10.23], - [29.78, -10.22], - [29.68, -10.23], - [29.67, -10.24], - [29.65, -10.25], - [29.62, -10.28], - [29.61, -10.29], - [29.59, -10.3], - [29.55, -10.32], - [29.51, -10.33], - [29.5, -10.34], - [29.48, -10.36], - [29.45, -10.38], - [29.44, -10.39], - [29.43, -10.42], - [29.42, -10.44], - [29.41, -10.45], - [29.4, -10.48], - [29.41, -10.51], - [29.37, -10.59], - [29.36, -10.6], - [29.35, -10.64], - [29.3, -10.65], - [29.29, -10.66], - [29.17, -10.74], - [29.16, -10.75], - [29.11, -10.92], - [29.09, -10.94], - [29.08, -10.96], - [29.09, -10.97], - [29.17, -10.99], - [29.18, -11], - [29.27, -11.09], - [29.37, -11.12], - [29.39, -11.11], - [29.4, -11.06], - [29.39, -11.03], - [29.38, -11.02], - [29.37, -11.01], - [29.36, -10.99], - [29.34, -10.92], - [29.35, -10.9], - [29.37, -10.88], - [29.64, -10.74], - [29.68, -10.75], - [29.71, -10.77], - [29.75, -10.78], - [29.76, -10.79], - [29.78, -10.8], - [29.79, -10.81], - [29.81, -10.86], - [29.82, -10.87], - [29.84, -10.89], - [29.86, -10.9], - [29.88, -10.94], - [29.89, -10.95], - [29.83, -11.4], - [29.84, -11.39], - [29.85, -11.37], - [29.88, -11.36], - [29.89, -11.34], - [29.9, -11.32], - [29.94, -11.29], - [29.95, -11.28], - [29.96, -11.25], - [29.97, -11.24], - [30.12, -11.25], - [30.45, -11.48], - [30.46, -11.49], - [30.45, -11.51], - [30.44, -11.55], - [30.45, -11.58], - [30.28, -11.81], - [30.26, -11.82], - [30.25, -11.83], - [29.82, -11.89], - [29.79, -11.9], - [29.78, -11.91], - [29.77, -11.92], - [29.78, -11.98], - [29.79, -12.05], - [29.81, -12.07], - [29.82, -12.09], - [29.81, -12.11], - [29.82, -12.13], - [29.81, -12.14], - [29.8, -12.15], - [29.76, -12.16], - [29.7, -12.19], - [29.65, -12.21], - [29.63, -12.22], - [29.62, -12.21], - [29.6, -12.19], - [29.55, -12.21], - [29.53, -12.22], - [29.49, -12.23], - [29.47, -12.24], - [29.46, -12.29], - [29.45, -12.32], - [29.48, -12.38], - [29.5, -12.39], - [29.53, -12.41], - [29.52, -12.43], - [29.51, -12.44], - [29.5, -12.45], - [29.47, -12.44], - [29.41, -12.43], - [29.36, -12.41], - [29.3, -12.4], - [29.28, -12.39], - [29.27, -12.37], - [29.13, -12.38], - [29.11, -12.39], - [29.1, -12.37], - [29.08, -12.38], - [29.03, -12.36], - [28.94, -12.21], - [28.92, -12.17], - [28.86, -12.14], - [28.85, -12.13], - [28.84, -12.09], - [28.82, -12.08], - [28.81, -12.06], - [28.77, -12.05], - [28.76, -12.04], - [28.75, -12.02], - [28.74, -11.98], - [28.71, -11.99], - [28.69, -11.98], - [28.64, -11.96], - [28.62, -11.95], - [28.61, -11.91], - [28.59, -11.9], - [28.57, -11.91], - [28.55, -11.89], - [28.54, -11.87], - [28.5, -11.86], - [28.49, -11.81], - [28.48, -11.8], - [28.46, -11.79], - [28.45, -11.78], - [28.44, -11.71], - [28.43, -11.69], - [28.42, -11.68], - [28.41, -11.61], - [28.4, -11.6], - [28.38, -11.58], - [28.37, -11.54], - [28.36, -11.53], - [28.35, -11.46], - [28.36, -11.45], - [28.41, -11.37], - [28.43, -11.35], - [28.44, -11.29], - [28.45, -11.27], - [28.46, -11.26], - [28.47, -11.23], - [28.48, -11.18], - [28.49, -11.15], - [28.48, -11.09], - [28.49, -11.06], - [28.5, -11.03], - [28.51, -11.02], - [28.53, -10.96], - [28.54, -10.94], - [28.55, -10.91], - [28.56, -10.81], - [28.58, -10.79], - [28.59, -10.77], - [28.6, -10.76], - [28.61, -10.74], - [28.62, -10.72], - [28.63, -10.71], - [28.67, -10.7], - [28.68, -10.68], - [28.69, -10.66], - [28.7, -10.64], - [28.67, -10.62], - [28.65, -10.54], - [28.63, -10.52], - [28.64, -10.5], - [28.63, -10.48], - [28.64, -10.46], - [28.65, -10.44], - [28.64, -10.43], - [28.63, -10.39], - [28.62, -10.37], - [28.63, -10.31], - [28.62, -10.28], - [28.61, -10.27], - [28.6, -10.25], - [28.57, -10.22], - [28.58, -10.2], - [28.6, -10.17], - [28.62, -10.14], - [28.63, -10.1], - [28.62, -9.95], - [28.63, -9.93], - [28.66, -9.86], - [28.67, -9.82], - [28.68, -9.8], - [28.7, -9.79], - [28.67, -9.77], - [28.66, -9.75], - [28.65, -9.74], - [28.63, -9.72], - [28.62, -9.65], - [28.61, -9.62], - [28.59, -9.57], - [28.58, -9.56], - [28.61, -9.55], - [28.62, -9.54] - ], - "Copperbelt": [ - [27.59, -12.24], - [27.6, -12.25], - [27.64, -12.29], - [27.67, -12.3], - [27.71, -12.31], - [27.76, -12.3], - [27.81, -12.28], - [27.82, -12.27], - [27.83, -12.26], - [27.88, -12.27], - [27.93, -12.3], - [27.95, -12.32], - [27.96, -12.37], - [28.09, -12.38], - [28.1, -12.39], - [28.11, -12.41], - [28.13, -12.43], - [28.15, -12.42], - [28.16, -12.41], - [28.19, -12.4], - [28.2, -12.41], - [28.22, -12.43], - [28.24, -12.44], - [28.28, -12.43], - [28.3, -12.44], - [28.34, -12.45], - [28.42, -12.52], - [28.44, -12.54], - [28.46, -12.59], - [28.47, -12.61], - [28.5, -12.65], - [28.51, -12.67], - [28.5, -12.71], - [28.48, -12.72], - [28.47, -12.74], - [28.48, -12.76], - [28.5, -12.79], - [28.52, -12.81], - [28.54, -12.83], - [28.55, -12.89], - [28.57, -12.9], - [28.58, -12.89], - [28.59, -12.88], - [28.61, -12.85], - [28.62, -12.84], - [28.67, -12.85], - [28.71, -12.89], - [28.78, -12.98], - [28.79, -12.99], - [28.8, -13], - [28.81, -13.04], - [28.83, -13.05], - [28.82, -13.09], - [28.83, -13.1], - [28.85, -13.14], - [28.89, -13.15], - [28.9, -13.16], - [28.93, -13.31], - [28.95, -13.35], - [28.98, -13.38], - [28.99, -13.4], - [29.05, -13.39], - [29.06, -13.4], - [29.02, -13.44], - [28.95, -13.52], - [28.91, -13.54], - [28.87, -13.56], - [28.86, -13.57], - [28.84, -13.59], - [28.83, -13.61], - [28.82, -13.62], - [28.67, -13.73], - [28.66, -13.86], - [28.54, -13.87], - [28.52, -13.88], - [28.5, -13.89], - [28.37, -13.88], - [28.36, -13.87], - [28.33, -13.88], - [28.28, -13.89], - [28.27, -13.88], - [28.21, -13.87], - [28.17, -13.88], - [28.15, -13.89], - [28.11, -13.9], - [27.98, -13.91], - [27.96, -13.92], - [27.93, -13.91], - [27.91, -13.9], - [27.9, -13.88], - [27.89, -13.86], - [27.82, -13.7], - [27.81, -13.69], - [27.79, -13.68], - [27.7, -13.67], - [27.68, -13.66], - [27.67, -13.65], - [27.62, -13.66], - [27.63, -13.69], - [27.62, -13.7], - [27.6, -13.71], - [27.59, -13.72], - [27.6, -13.73], - [27.59, -13.75], - [27.55, -13.79], - [27.54, -13.82], - [27.53, -13.81], - [27.52, -13.79], - [27.48, -13.81], - [27.49, -13.82], - [27.48, -13.87], - [27.46, -13.89], - [27.43, -13.91], - [27.42, -13.92], - [27.41, -13.91], - [27.4, -13.9], - [27.39, -13.88], - [27.38, -13.85], - [27.37, -13.82], - [27.36, -13.8], - [27.35, -13.79], - [27.34, -13.77], - [27.35, -13.76], - [27.26, -13.73], - [26.85, -13.72], - [26.82, -13.69], - [26.8, -13.68], - [26.79, -13.67], - [26.8, -13.56], - [26.81, -13.54], - [26.83, -13.52], - [26.84, -13.51], - [26.85, -13.45], - [26.86, -13.44], - [26.87, -13.43], - [26.9, -13.42], - [26.91, -13.41], - [26.92, -13.38], - [26.95, -13.37], - [26.96, -13.36], - [26.97, -13.33], - [26.98, -13.32], - [26.96, -13.26], - [26.97, -13.21], - [26.98, -13.19], - [27.04, -13.16], - [27.05, -13.14], - [27.06, -13.13], - [27.07, -13.12], - [27.09, -13], - [27.04, -12.99], - [27.03, -12.98], - [27.02, -12.97], - [27.01, -12.96], - [27, -12.95], - [26.96, -12.94], - [26.93, -12.93], - [26.92, -12.92], - [26.91, -12.91], - [26.9, -12.9], - [26.88, -12.89], - [26.89, -12.86], - [26.9, -12.84], - [26.91, -12.83], - [26.9, -12.81], - [26.88, -12.79], - [26.87, -12.78], - [26.86, -12.76], - [26.85, -12.75], - [26.86, -12.71], - [26.87, -12.66], - [26.88, -12.64], - [26.9, -12.63], - [26.94, -12.62], - [26.95, -12.61], - [26.96, -12.6], - [26.97, -12.58], - [27.01, -12.54], - [27.02, -12.53], - [27.07, -12.52], - [27.08, -12.51], - [27.07, -12.5], - [27.06, -12.48], - [27.05, -12.46], - [27.06, -12.44], - [27.07, -12.42], - [27.05, -12.35], - [27.06, -12.33], - [27.08, -12.34], - [27.14, -12.33], - [27.28, -12.35], - [27.29, -12.34], - [27.3, -12.32], - [27.32, -12.31], - [27.34, -12.3], - [27.35, -12.29], - [27.36, -12.28], - [27.38, -12.27], - [27.4, -12.26], - [27.41, -12.25], - [27.43, -12.24], - [27.44, -12.25], - [27.45, -12.26], - [27.47, -12.27], - [27.46, -12.28], - [27.47, -12.29], - [27.51, -12.3], - [27.52, -12.28], - [27.54, -12.27], - [27.59, -12.25] - ], - "Central": [ - [29.77, -13.46], - [29.8, -13.42], - [29.82, -12.16], - [29.83, -12.15], - [29.84, -12.13], - [29.85, -12.12], - [29.86, -12.05], - [29.87, -12.04], - [29.95, -12.01], - [29.97, -12], - [30.01, -12.01], - [30.03, -12.03], - [30.05, -12.07], - [30.06, -12.11], - [30.07, -12.13], - [30.08, -12.14], - [30.09, -12.15], - [30.11, -12.16], - [30.12, -12.17], - [30.15, -12.18], - [30.16, -12.2], - [30.18, -12.21], - [30.21, -12.22], - [30.23, -12.23], - [30.25, -12.24], - [30.29, -12.25], - [30.31, -12.26], - [30.36, -12.27], - [30.38, -12.28], - [30.39, -12.27], - [30.42, -12.28], - [30.43, -12.29], - [30.44, -12.3], - [30.45, -12.31], - [30.48, -12.3], - [30.49, -12.31], - [30.51, -12.33], - [30.5, -12.42], - [30.51, -12.47], - [30.52, -12.48], - [30.55, -12.49], - [30.56, -12.5], - [30.57, -12.51], - [30.56, -12.56], - [30.57, -12.58], - [30.58, -12.59], - [30.61, -12.62], - [30.63, -12.63], - [30.65, -12.62], - [30.66, -12.61], - [30.68, -12.59], - [30.7, -12.6], - [30.71, -12.63], - [30.72, -12.64], - [30.73, -12.65], - [30.75, -12.66], - [30.76, -12.67], - [30.77, -12.68], - [30.76, -12.7], - [30.75, -12.71], - [30.74, -12.73], - [30.73, -12.75], - [30.74, -12.82], - [30.75, -12.87], - [30.81, -12.91], - [30.83, -12.92], - [30.84, -12.93], - [30.95, -12.94], - [30.99, -12.95], - [31.03, -12.96], - [31.11, -13.03], - [31.12, -13.04], - [31.16, -13.03], - [31.17, -13.02], - [31.18, -13], - [31.19, -12.96], - [31.2, -12.95], - [31.32, -12.97], - [31.34, -12.98], - [31.35, -12.99], - [31.36, -13.23], - [31.37, -13.25], - [31.39, -13.28], - [31.41, -13.31], - [31.43, -13.32], - [31.41, -13.45], - [31.36, -13.46], - [31.34, -13.47], - [31.3, -13.5], - [31.29, -13.51], - [31.28, -13.52], - [31.27, -13.51], - [31.26, -13.52], - [31.25, -13.53], - [31.23, -13.56], - [31.22, -13.58], - [31.16, -13.6], - [31.14, -13.61], - [31.12, -13.63], - [31.11, -13.7], - [31.1, -13.71], - [31.07, -13.74], - [31.06, -13.76], - [31.05, -13.78], - [31.01, -13.79], - [30.98, -13.81], - [30.96, -13.82], - [30.94, -13.86], - [30.92, -13.89], - [30.9, -13.9], - [30.89, -13.92], - [30.88, -13.93], - [30.1, -13.94], - [30.14, -13.95], - [30.15, -13.96], - [30.18, -14.04], - [30.19, -14.05], - [30.22, -14.06], - [30.26, -14.07], - [30.27, -14.08], - [30.29, -14.09], - [30.3, -14.1], - [30.31, -14.11], - [30.32, -14.12], - [30.31, -14.17], - [30.3, -14.2], - [30.29, -14.21], - [30.28, -14.22], - [30.25, -14.23], - [30.23, -14.25], - [30.22, -14.26], - [30.21, -14.27], - [30.2, -14.29], - [30.17, -14.31], - [30.13, -14.36], - [30.12, -14.37], - [30.11, -14.38], - [30.09, -14.37], - [30.08, -14.38], - [30.07, -14.41], - [30.06, -14.42], - [30.05, -14.43], - [30.03, -14.44], - [30.02, -14.5], - [30.01, -14.51], - [30, -14.56], - [29.99, -14.61], - [30, -14.62], - [30.02, -14.64], - [30.05, -14.66], - [30, -14.67], - [29.99, -14.66], - [29.98, -14.65], - [29.94, -14.66], - [29.91, -14.65], - [29.9, -14.66], - [29.89, -14.68], - [29.88, -14.69], - [29.87, -14.7], - [29.79, -14.72], - [29.67, -14.75], - [29.66, -14.76], - [29.65, -14.77], - [29.59, -14.8], - [29.58, -14.81], - [29.52, -14.82], - [29.51, -14.84], - [29.5, -14.85], - [29.49, -14.91], - [29.46, -14.96], - [29.39, -14.98], - [29.23, -14.96], - [29.05, -15.01], - [29, -15.02], - [28.95, -15.04], - [28.82, -15.15], - [28.74, -15.18], - [28.66, -15.19], - [28.4, -15.15], - [28.38, -15.16], - [28.34, -15.22], - [28.32, -15.3], - [28.29, -15.34], - [28.26, -15.35], - [28.2, -15.34], - [28.03, -15.29], - [27.86, -15.26], - [27.83, -15.27], - [27.78, -15.3], - [27.77, -15.31], - [27.79, -15.34], - [27.81, -15.35], - [27.86, -15.36], - [27.89, -15.37], - [27.92, -15.42], - [27.93, -15.47], - [27.92, -15.52], - [27.91, -15.53], - [27.8, -15.56], - [27.76, -15.65], - [27.75, -15.66], - [27.69, -15.67], - [27.68, -15.65], - [27.67, -15.64], - [27.65, -15.63], - [27.66, -15.61], - [27.67, -15.6], - [27.66, -15.59], - [27.64, -15.55], - [27.63, -15.53], - [27.58, -15.5], - [27.57, -15.49], - [27.56, -15.48], - [27.53, -15.49], - [27.52, -15.51], - [27.51, -15.52], - [27.5, -15.54], - [27.49, -15.55], - [27.48, -15.56], - [27.47, -15.57], - [27.46, -15.58], - [27.43, -15.57], - [27.4, -15.58], - [27.32, -15.73], - [27.3, -15.74], - [27.29, -15.73], - [27.28, -15.71], - [27.23, -15.5], - [27.2, -15.48], - [26.97, -15.47], - [26.96, -15.46], - [26.99, -15.44], - [26.98, -15.43], - [26.84, -15.35], - [26.8, -15.34], - [25.32, -15.3], - [25.33, -15.23], - [25.32, -15.19], - [25.33, -15.18], - [25.36, -15.15], - [25.37, -15.14], - [25.38, -15.13], - [25.39, -15.14], - [25.41, -15.13], - [25.42, -15.12], - [25.41, -15.09], - [25.42, -15.08], - [25.43, -15.06], - [25.45, -15.04], - [25.46, -15.02], - [25.45, -14.97], - [25.43, -14.91], - [25.42, -14.9], - [25.43, -14.87], - [25.44, -14.85], - [25.45, -14.82], - [25.46, -14.8], - [25.47, -14.79], - [25.48, -14.78], - [25.49, -14.67], - [25.5, -14.64], - [25.51, -14.63], - [25.52, -14.6], - [25.53, -14.59], - [25.57, -14.57], - [25.59, -14.56], - [26.17, -14.62], - [26.18, -14.63], - [26.19, -14.65], - [26.21, -14.66], - [26.25, -14.67], - [26.29, -14.69], - [26.3, -14.7], - [26.31, -14.71], - [26.32, -14.72], - [26.33, -14.71], - [26.37, -14.7], - [26.38, -14.65], - [26.39, -14.63], - [26.43, -14.58], - [26.49, -14.53], - [26.53, -14.47], - [26.54, -14.46], - [26.56, -14.45], - [26.57, -14.44], - [26.6, -14.45], - [26.63, -14.46], - [26.64, -14.45], - [26.65, -14.44], - [26.74, -14.45], - [26.75, -14.44], - [26.79, -14.42], - [26.8, -14.41], - [26.94, -14.4], - [26.95, -14.39], - [26.96, -14.37], - [26.95, -14.26], - [26.96, -14.24], - [26.98, -14.21], - [26.97, -14.15], - [26.96, -14.14], - [26.91, -14.08], - [26.9, -14.07], - [26.86, -14.05], - [26.87, -14.03], - [26.89, -14.02], - [26.9, -14.01], - [26.91, -14], - [26.92, -13.89], - [26.94, -13.86], - [26.95, -13.84], - [26.92, -13.8], - [26.91, -13.79], - [26.9, -13.78], - [26.89, -13.77], - [26.88, -13.74], - [26.87, -13.73], - [26.86, -13.72], - [27.26, -13.73], - [27.35, -13.74], - [27.34, -13.76], - [27.35, -13.79], - [27.36, -13.8], - [27.37, -13.81], - [27.38, -13.82], - [27.39, -13.86], - [27.4, -13.9], - [27.41, -13.91], - [27.42, -13.92], - [27.43, -13.91], - [27.46, -13.89], - [27.48, -13.87], - [27.49, -13.84], - [27.48, -13.81], - [27.49, -13.79], - [27.53, -13.81], - [27.54, -13.82], - [27.55, -13.81], - [27.59, -13.75], - [27.6, -13.74], - [27.59, -13.72], - [27.6, -13.71], - [27.61, -13.7], - [27.63, -13.69], - [27.62, -13.68], - [27.64, -13.65], - [27.68, -13.66], - [27.69, -13.67], - [27.79, -13.68], - [27.81, -13.69], - [27.82, -13.7], - [27.89, -13.86], - [27.9, -13.88], - [27.91, -13.9], - [27.93, -13.91], - [27.94, -13.92], - [27.97, -13.91], - [27.99, -13.9], - [28.14, -13.89], - [28.16, -13.88], - [28.17, -13.87], - [28.27, -13.88], - [28.28, -13.89], - [28.29, -13.88], - [28.36, -13.87], - [28.37, -13.88], - [28.42, -13.89], - [28.51, -13.88], - [28.53, -13.87], - [28.58, -13.86], - [28.67, -13.85], - [28.82, -13.62], - [28.83, -13.61], - [28.84, -13.59], - [28.86, -13.57], - [28.87, -13.56], - [28.91, -13.54], - [28.95, -13.53], - [29.02, -13.44], - [29.06, -13.4], - [29.07, -13.39], - [29.1, -13.38], - [29.14, -13.39], - [29.15, -13.41], - [29.16, -13.42], - [29.17, -13.43], - [29.18, -13.44], - [29.19, -13.43], - [29.21, -13.41], - [29.23, -13.4], - [29.25, -13.39], - [29.31, -13.35], - [29.45, -13.3], - [29.47, -13.29], - [29.53, -13.23], - [29.55, -13.22], - [29.57, -13.23], - [29.59, -13.24], - [29.61, -13.25], - [29.63, -13.26], - [29.67, -13.27], - [29.66, -13.3], - [29.65, -13.31], - [29.63, -13.32], - [29.62, -13.37], - [29.6, -13.39], - [29.61, -13.4], - [29.62, -13.42], - [29.63, -13.43], - [29.64, -13.44], - [29.66, -13.45], - [29.7, -13.46] - ] -} From b7a84e34e4291598226bf991689f2ab19b7b16dd Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Mon, 24 Feb 2025 19:46:35 -0800 Subject: [PATCH 23/44] refactor: admin_4 locations --- .../src/data/districts.ts | 32 +------------------ libs/data/geoLocation/index.ts | 8 +++-- libs/data/geoLocation/mw/districts.ts | 32 +++++++++++++++++++ libs/data/geoLocation/types.ts | 3 +- libs/data/geoLocation/zm/provinces.ts | 14 ++++++++ 5 files changed, 55 insertions(+), 34 deletions(-) create mode 100644 libs/data/geoLocation/mw/districts.ts create mode 100644 libs/data/geoLocation/zm/provinces.ts diff --git a/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts b/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts index 52da3c19a..090e2733a 100644 --- a/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts +++ b/apps/picsa-server/scripts/crop-probability-parser/src/data/districts.ts @@ -1,35 +1,5 @@ import { arrayToHashmap } from '../../../../../../libs/utils'; - -const MW_DISTRICTS = [ - { id: 'balaka', label: 'Balaka' }, - { id: 'blantyre', label: 'Blantyre' }, - { id: 'chikwawa', label: 'Chikwawa' }, - { id: 'chiradzulu', label: 'Chiradzulu' }, - { id: 'chitipa', label: 'Chitipa' }, - { id: 'dedza', label: 'Dedza' }, - { id: 'dowa', label: 'Dowa' }, - { id: 'karonga', label: 'Karonga' }, - { id: 'kasungu', label: 'Kasungu' }, - { id: 'likoma', label: 'Likoma' }, - { id: 'lilongwe', label: 'Lilongwe' }, - { id: 'machinga', label: 'Machinga' }, - { id: 'mangochi', label: 'Mangochi' }, - { id: 'mchinji', label: 'Mchinji' }, - { id: 'mulanje', label: 'Mulanje' }, - { id: 'mwanza', label: 'Mwanza' }, - { id: 'mzimba', label: 'Mzimba' }, - { id: 'neno', label: 'Neno' }, - { id: 'nkhata_bay', label: 'Nkhata Bay' }, - { id: 'nkhotakota', label: 'Nkhotakota' }, - { id: 'nsanje', label: 'Nsanje' }, - { id: 'ntcheu', label: 'Ntcheu' }, - { id: 'ntchisi', label: 'Ntchisi' }, - { id: 'phalombe', label: 'Phalombe' }, - { id: 'rumphi', label: 'Rumphi' }, - { id: 'salima', label: 'Salima' }, - { id: 'thyolo', label: 'Thyolo' }, - { id: 'zomba', label: 'Zomba' }, -]; +import MW_DISTRICTS from '../../../../../../libs/data/geoLocation/mw/districts'; export const DISTRICTS = { mw: arrayToHashmap(MW_DISTRICTS, 'label'), diff --git a/libs/data/geoLocation/index.ts b/libs/data/geoLocation/index.ts index 32c260ef6..73606e2e6 100644 --- a/libs/data/geoLocation/index.ts +++ b/libs/data/geoLocation/index.ts @@ -1,6 +1,8 @@ import { marker as translateMarker } from '@biesbjerg/ngx-translate-extract-marker'; +import MW_DISTRICTS from './mw/districts'; import { ICountryCode } from '../deployments'; import { IGelocationData } from './types'; +import ZM_PROVINCES from './zm/provinces'; export * from './utils'; export * from './types'; @@ -9,19 +11,21 @@ export const GEO_LOCATION_DATA: { [country_code in ICountryCode]?: IGelocationDa mw: { admin_4: { label: translateMarker('District'), - data: async () => { + topoJson: async () => { const res = await import('./mw/admin-4.osm.topo.json'); return res.default; }, + locations: MW_DISTRICTS, }, }, zm: { admin_4: { label: translateMarker('Province'), - data: async () => { + topoJson: async () => { const res = await import('./zm/admin-4.osm.topo.json'); return res.default; }, + locations: ZM_PROVINCES, }, }, }; diff --git a/libs/data/geoLocation/mw/districts.ts b/libs/data/geoLocation/mw/districts.ts new file mode 100644 index 000000000..816ff3370 --- /dev/null +++ b/libs/data/geoLocation/mw/districts.ts @@ -0,0 +1,32 @@ +const MW_DISTRICTS = [ + { id: 'balaka', label: 'Balaka' }, + { id: 'blantyre', label: 'Blantyre' }, + { id: 'chikwawa', label: 'Chikwawa' }, + { id: 'chiradzulu', label: 'Chiradzulu' }, + { id: 'chitipa', label: 'Chitipa' }, + { id: 'dedza', label: 'Dedza' }, + { id: 'dowa', label: 'Dowa' }, + { id: 'karonga', label: 'Karonga' }, + { id: 'kasungu', label: 'Kasungu' }, + { id: 'likoma', label: 'Likoma' }, + { id: 'lilongwe', label: 'Lilongwe' }, + { id: 'machinga', label: 'Machinga' }, + { id: 'mangochi', label: 'Mangochi' }, + { id: 'mchinji', label: 'Mchinji' }, + { id: 'mulanje', label: 'Mulanje' }, + { id: 'mwanza', label: 'Mwanza' }, + { id: 'mzimba', label: 'Mzimba' }, + { id: 'nkhata_bay', label: 'Nkhata Bay' }, + { id: 'nkhotakota', label: 'Nkhotakota' }, + { id: 'nneno', label: 'Nneno' }, + { id: 'nsanje', label: 'Nsanje' }, + { id: 'ntcheu', label: 'Ntcheu' }, + { id: 'ntchisi', label: 'Ntchisi' }, + { id: 'phalombe', label: 'Phalombe' }, + { id: 'rumphi', label: 'Rumphi' }, + { id: 'salima', label: 'Salima' }, + { id: 'thyolo', label: 'Thyolo' }, + { id: 'zomba', label: 'Zomba' }, +]; + +export default MW_DISTRICTS; diff --git a/libs/data/geoLocation/types.ts b/libs/data/geoLocation/types.ts index 87894387f..249b06465 100644 --- a/libs/data/geoLocation/types.ts +++ b/libs/data/geoLocation/types.ts @@ -5,7 +5,8 @@ export interface IGelocationData { **/ admin_4: { label: string; - data: () => Promise; + topoJson: () => Promise; + locations: { id: string; label: string }[]; }; } diff --git a/libs/data/geoLocation/zm/provinces.ts b/libs/data/geoLocation/zm/provinces.ts new file mode 100644 index 000000000..cf315c525 --- /dev/null +++ b/libs/data/geoLocation/zm/provinces.ts @@ -0,0 +1,14 @@ +const ZM_PROVINCES = [ + { id: 'western', label: 'Western Province' }, + { id: 'north_western', label: 'North-Western Province' }, + { id: 'copperbelt', label: 'Copperbelt Province' }, + { id: 'central', label: 'Central Province' }, + { id: 'northern', label: 'Northern Province' }, + { id: 'southern', label: 'Southern Province' }, + { id: 'lusaka', label: 'Lusaka Province' }, + { id: 'eastern', label: 'Eastern Province' }, + { id: 'luapula', label: 'Luapula Province' }, + { id: 'muchinga', label: 'Muchinga Province' }, +]; + +export default ZM_PROVINCES; From 7d83216d31bd80472540a5fd6a114cbdd86229ff Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Mon, 24 Feb 2025 20:02:36 -0800 Subject: [PATCH 24/44] feat: user profile district and forecasts --- ...0250115161100_climate_forecasts_update.sql | 2 +- apps/picsa-server/supabase/types/index.ts | 2 +- .../src/app/pages/forecast/forecast.page.html | 119 +++++++++--------- .../src/app/pages/forecast/forecast.page.scss | 8 +- .../src/app/pages/forecast/forecast.page.ts | 58 +++++++-- .../app/pages/site-select/site-select.page.ts | 2 +- .../pages/home/extension-home.component.ts | 4 +- libs/environments/src/version.ts | 2 +- 8 files changed, 109 insertions(+), 88 deletions(-) diff --git a/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql b/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql index 9bcec4c08..e31910bb2 100644 --- a/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql +++ b/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql @@ -2,7 +2,7 @@ drop table if exists public.climate_forecasts; -- -- Custom types -create type public.forecast_type as enum ('daily','annual'); +create type public.forecast_type as enum ('daily','seasonal','downscaled'); create table public.climate_forecasts ( diff --git a/apps/picsa-server/supabase/types/index.ts b/apps/picsa-server/supabase/types/index.ts index edb93c72b..195df967d 100644 --- a/apps/picsa-server/supabase/types/index.ts +++ b/apps/picsa-server/supabase/types/index.ts @@ -686,7 +686,7 @@ export type Database = { | "deployments.admin" | "translations.viewer" country_code: "global" | "mw" | "zm" | "tj" - forecast_type: "daily" | "annual" + forecast_type: "daily" | "annual" | 'seasonal'| 'downscaled' locale_code: "global_en" | "mw_ny" | "mw_tum" | "zm_ny" | "tj_tg" resource_link_type: "app" | "social" | "web" } diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index 2515c54af..96fe7eb73 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -9,72 +9,67 @@ }
- -
-

{{'Daily' | translate}}

-
- @if(dailyForecasts().length===0){ -
- -
+ + + {{locationSelectLabel() | translate}} + + @for (option of locationSelectOptions(); track option.id) { + {{option.label}} } -
- @for(forecast of dailyForecasts(); track forecast.id){ -
-
{{forecast.label}}
-
- @if(!forecast.downloaded){ - - @if(downloader.progress()===undefined){ - download - } @else{ - - } - - } @else{ - task_alt - } -
-
- } -
-
-
+ + - -
-

{{'Downscaled' | translate}}

-
- - - {{'Location' | translate}} - - -
- @if(downscaledForecasts(); as collection){ - - } - -
+ +
+ + @if(dailyForecasts().length===0){ +
+
+ } @for(forecast of dailyForecasts(); track forecast.id){ + + } + + + @if(downscaledForecast(); as downscaledForecast){ + + } + + @if(seasonalForecast(); as seasonalForecast){ + + }
- -
-

{{'Seasonal' | translate}}

-
-
...
+ +
+ + + + + @if(toForecastType(value); as forecast){ +
+

{{forecast.type | translate}}

+
{{forecast.label}}
+
+ @if(!forecast.downloaded){ + + @if(downloader.progress()===undefined){ + download + } @else{ + + } + + } @else{ + task_alt + }
-
+ } + diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss index 54fa22492..1490f7975 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss @@ -18,10 +18,6 @@ .slide-in.active { transform: translateY(0); } - -h2.forecast-heading { - @apply w-full sm:mb-8 sm:w-40 sm:text-left overflow-hidden text-ellipsis; -} -div.forecast-content { - @apply flex-1 overflow-x-auto mx-4 sm:mx-0; +.forecast-heading { + @apply border-solid border-0 border-b border-[var(--color-light)] text-center p-2 m-0 capitalize; } diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index 6de41d0f5..08a710f3f 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -3,6 +3,8 @@ import { Component, computed, effect, OnDestroy, signal, viewChildren } from '@a import { MatIcon } from '@angular/material/icon'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { ConfigurationService } from '@picsa/configuration'; +import { ICountryCode } from '@picsa/data'; +import { GEO_LOCATION_DATA } from '@picsa/data/geoLocation'; import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; @@ -20,6 +22,7 @@ interface IForecastSummary { label: string; storage_file: string; downloaded: boolean; + type: string; } @Component({ @@ -40,11 +43,20 @@ interface IForecastSummary { export class ClimateForecastComponent implements OnDestroy { public pdfSrc?: string; - private downloaders = viewChildren(SupabaseStorageDownloadComponent); + /** Options provided to location select (admin_4 district/province level) */ + public locationSelectOptions = signal<{ id: string; label: string }[]>([]); + + /** Label used for location select (admin_4 district/province level) */ + public locationSelectLabel = signal(''); + + /** Location selected as stored to user profile (admin_4 district/province level) */ + public locationSelected = computed( + () => this.configurationService.userSettings().location[4] || this.locationSelectOptions()[0]?.id + ); public dailyForecasts = computed(() => this.service.dailyForecastDocs().map((doc): IForecastSummary => { - const { id, storage_file } = doc; + const { id, storage_file, forecast_type } = doc; const label = this.generateForecastLabel(id); const summary: IForecastSummary = { _doc: doc, @@ -52,6 +64,7 @@ export class ClimateForecastComponent implements OnDestroy { label, storage_file: storage_file as string, downloaded: false, + type: forecast_type || '', }; if (storage_file) { summary.downloaded = doc.getAttachment(storage_file) ? true : false; @@ -60,16 +73,15 @@ export class ClimateForecastComponent implements OnDestroy { }) ); - public downscaledForecasts = computed(() => { - const collection = this.service.downscaledForecastsCollection(); - if (collection) { - return collection._data; - } - return undefined; - }); + public downscaledForecast = signal(undefined); + + public seasonalForecast = signal(undefined); + + // Utility to add type-safety to implicit ng-template data + public toForecastType = (data: any) => data as IForecastSummary; - // HACK - use resources collection for downscaled forecasts - public downscaledForecastsCollection = {}; + /** List of rendered SupabaseStorageDownload components for direct interaction */ + private downloaders = viewChildren(SupabaseStorageDownloadComponent); constructor( private service: ClimateForecastService, @@ -77,9 +89,22 @@ export class ClimateForecastComponent implements OnDestroy { private dbAttachmentService: PicsaDatabaseAttachmentService ) { effect(() => { - const { country_code } = this.configurationService.deploymentSettings(); - if (country_code) { + const { location } = this.configurationService.userSettings(); + console.log('load location data', location); + if (location) { + const country_code = location[2] as ICountryCode; this.service.loadForecasts(country_code); + const geoLocationData = GEO_LOCATION_DATA[country_code]; + this.locationSelectOptions.set(geoLocationData?.admin_4.locations || []); + this.locationSelectLabel.set(geoLocationData?.admin_4.label || ''); + } + }); + + effect(() => { + const location = this.locationSelected(); + if (location) { + console.log('loading downscaled forecast', location); + // TODO - load downscaled forecast for location } }); } @@ -108,6 +133,13 @@ export class ClimateForecastComponent implements OnDestroy { } } + /** When user district/province selected store to user profile location data */ + public handleUserLocationSelect(admin_4_location: string) { + const update = [...this.configurationService.userSettings().location]; + update[4] = admin_4_location; + this.configurationService.updateUserSettings({ location: update }); + } + public closeForecast() { if (this.pdfSrc) { URL.revokeObjectURL(this.pdfSrc); diff --git a/apps/picsa-tools/climate-tool/src/app/pages/site-select/site-select.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/site-select/site-select.page.ts index d07ac409b..1edbb30ab 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/site-select/site-select.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/site-select/site-select.page.ts @@ -82,7 +82,7 @@ export class SiteSelectPage { private async loadCountryAdminBoundaries(map: Map, country_code: string) { const metadata: IGelocationData = GEO_LOCATION_DATA[country_code]; if (!metadata) return; - const topojson = await metadata.admin_4.data(); + const topojson = await metadata.admin_4.topoJson(); const feature = topoJsonToGeoJson(topojson); geoJSON(feature as any) .setStyle({ fill: false, color: 'brown', opacity: 0.5 }) diff --git a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts index f6091e756..d915fb2d2 100644 --- a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts +++ b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts @@ -87,9 +87,7 @@ const ADDITIONAL_LINKS: IPageLink[] = [ { name: translateMarker('Forecasts'), svgIcon: 'extension_app:forecasts_tool', - // HACK - forecasts currently child resource collection - // TODO - move to standalone tool - url: '/resources/collection/weatherResources', + url: '/climate/forecast', tourId: 'forecasts', }, { diff --git a/libs/environments/src/version.ts b/libs/environments/src/version.ts index ac8327088..c1702c978 100644 --- a/libs/environments/src/version.ts +++ b/libs/environments/src/version.ts @@ -1,8 +1,8 @@ // tslint:disable no-var-requires import packageJson from '../../../package.json'; -// e.g. 1.0.1 - even though called a number is stored as a string export const APP_VERSION = { + /** Semver code for current app version, e.g. 3.26.0 (TODO - rename) */ number: packageJson.version, date: '2025-02-15', }; From 505015864d0d5da2fa1a83663ba3b884f927e364 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Tue, 25 Feb 2025 15:15:12 -0800 Subject: [PATCH 25/44] feat: mw downscaled forecast integration --- .../src/app/components/layout.html | 2 +- .../src/app/pages/forecast/forecast.page.html | 12 +- .../src/app/pages/forecast/forecast.page.scss | 9 + .../src/app/pages/forecast/forecast.page.ts | 86 ++--- .../app/pages/forecast/forecast.service.ts | 76 +++-- libs/configuration/src/provider.ts | 14 + libs/data/climate/forecasts/index.ts | 9 + libs/data/climate/forecasts/mw.ts | 317 ++++++++++++++++++ libs/data/climate/forecasts/types.ts | 4 + libs/data/climate/forecasts/zm.ts | 64 ++++ 10 files changed, 517 insertions(+), 76 deletions(-) create mode 100644 libs/data/climate/forecasts/index.ts create mode 100644 libs/data/climate/forecasts/mw.ts create mode 100644 libs/data/climate/forecasts/types.ts create mode 100644 libs/data/climate/forecasts/zm.ts diff --git a/apps/picsa-apps/extension-app/src/app/components/layout.html b/apps/picsa-apps/extension-app/src/app/components/layout.html index 799fd1df2..2ce6be47c 100644 --- a/apps/picsa-apps/extension-app/src/app/components/layout.html +++ b/apps/picsa-apps/extension-app/src/app/components/layout.html @@ -20,7 +20,7 @@
} - +
cloud {{ 'Forecasts' | translate}} diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index 96fe7eb73..e61ad8d51 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -35,16 +35,14 @@ } - @if(downscaledForecast(); as downscaledForecast){ - + @for(forecast of downscaledForecasts(); track forecast.id){ + } - @if(seasonalForecast(); as seasonalForecast){ - + @for(forecast of seasonalForecasts(); track forecast.id){ + }
- -
@@ -57,7 +55,7 @@ >

{{forecast.type | translate}}

{{forecast.label}}
-
+
@if(!forecast.downloaded){ @if(downloader.progress()===undefined){ diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss index 1490f7975..55cb9c345 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss @@ -21,3 +21,12 @@ .forecast-heading { @apply border-solid border-0 border-b border-[var(--color-light)] text-center p-2 m-0 capitalize; } +.download-container { + @apply pt-1 text-center bg-[var(--color-secondary-50)]; +} +.download-container[data-forecast-type='downscaled'] { + filter: hue-rotate(120deg); +} +.download-container[data-forecast-type='seasonal'] { + filter: hue-rotate(240deg); +} diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index 08a710f3f..fe591c212 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -50,32 +50,11 @@ export class ClimateForecastComponent implements OnDestroy { public locationSelectLabel = signal(''); /** Location selected as stored to user profile (admin_4 district/province level) */ - public locationSelected = computed( - () => this.configurationService.userSettings().location[4] || this.locationSelectOptions()[0]?.id - ); + public locationSelected = computed(() => this.configurationService.userSettings().location[4]); - public dailyForecasts = computed(() => - this.service.dailyForecastDocs().map((doc): IForecastSummary => { - const { id, storage_file, forecast_type } = doc; - const label = this.generateForecastLabel(id); - const summary: IForecastSummary = { - _doc: doc, - id, - label, - storage_file: storage_file as string, - downloaded: false, - type: forecast_type || '', - }; - if (storage_file) { - summary.downloaded = doc.getAttachment(storage_file) ? true : false; - } - return summary; - }) - ); - - public downscaledForecast = signal(undefined); - - public seasonalForecast = signal(undefined); + public dailyForecasts = computed(() => this.generateForecastSummary(this.service.dailyForecastDocs())); + public downscaledForecasts = computed(() => this.generateForecastSummary(this.service.downscaledForecastDocs())); + public seasonalForecasts = computed(() => this.generateForecastSummary(this.service.seasonalForecastDocs())); // Utility to add type-safety to implicit ng-template data public toForecastType = (data: any) => data as IForecastSummary; @@ -90,21 +69,24 @@ export class ClimateForecastComponent implements OnDestroy { ) { effect(() => { const { location } = this.configurationService.userSettings(); - console.log('load location data', location); if (location) { const country_code = location[2] as ICountryCode; - this.service.loadForecasts(country_code); + const sublocation = location[4]; const geoLocationData = GEO_LOCATION_DATA[country_code]; - this.locationSelectOptions.set(geoLocationData?.admin_4.locations || []); - this.locationSelectLabel.set(geoLocationData?.admin_4.label || ''); - } - }); + const locationOptions = geoLocationData?.admin_4.locations || []; - effect(() => { - const location = this.locationSelected(); - if (location) { - console.log('loading downscaled forecast', location); - // TODO - load downscaled forecast for location + // HACK - update user profile to select first location if not specified + if (!sublocation && locationOptions.length > 0) { + const updatedLocation = [...location]; + updatedLocation[4] = locationOptions[0].id; + return this.configurationService.updateUserSettings({ location: updatedLocation }); + } + // Load forecasts and configure UI + else { + this.locationSelectOptions.set(locationOptions); + this.locationSelectLabel.set(geoLocationData?.admin_4.label || ''); + this.service.loadForecasts(location); + } } }); } @@ -147,9 +129,29 @@ export class ClimateForecastComponent implements OnDestroy { this.pdfSrc = undefined; } + private generateForecastSummary(docs: RxDocument[]): IForecastSummary[] { + const summaries = docs.map((doc) => { + const { id, storage_file, forecast_type } = doc; + const label = this.generateForecastLabel(storage_file); + const summary: IForecastSummary = { + _doc: doc, + id, + label, + storage_file: storage_file as string, + downloaded: false, + type: forecast_type || '', + }; + if (storage_file) { + summary.downloaded = doc.getAttachment(storage_file) ? true : false; + } + return summary; + }); + return summaries; + } + private refreshForecastData() { - const { country_code } = this.configurationService.deploymentSettings(); - return this.service.loadForecasts(country_code); + const { location } = this.configurationService.userSettings(); + return this.service.loadForecasts(location); } private async openForecast(forecast: IForecastSummary) { @@ -157,12 +159,12 @@ export class ClimateForecastComponent implements OnDestroy { this.pdfSrc = uri || undefined; } - private generateForecastLabel(id: string) { - const [timestamp, filename] = id.split('/'); + private generateForecastLabel(storage_file: string) { + const filename = storage_file.split('/').pop(); if (filename) { const [basename, extension] = filename.split('.'); - return basename.replace(/-/g, ' '); + return basename.replace(/[-_]/g, ' '); } - return id; + return storage_file; } } diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts index f06e7a30a..5c29c4433 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -1,28 +1,25 @@ import { Injectable, signal } from '@angular/core'; +import { IUserSettings } from '@picsa/configuration/src'; import { ICountryCode } from '@picsa/data'; -import { IResourceCollection } from '@picsa/resources/src/app/schemas'; -import { ResourcesToolService } from '@picsa/resources/src/app/services/resources-tool.service'; +import { CLIMATE_FORECASTS_DB } from '@picsa/data/climate/forecasts'; import { PicsaDatabase_V2_Service, PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { isEqual } from '@picsa/utils/object.utils'; -import { RxCollection, RxDocument } from 'rxdb'; +import { MangoQuerySelector, RxCollection, RxDocument, RxQuery } from 'rxdb'; import { IClimateForecastRow } from './forecast.types'; import { CLIMATE_FORECAST_COLLECTION, IClimateForecast, SERVER_DB_MAPPING } from './schemas'; /** * TODOs - * - include forecast_type in all requests and make generic for daily, seasonal and downscaled - * - storage file download/open (convert to resource) - * - UI improvements (re-use existing collection?) - * - Improved downscaled forecast filters + * - HTML Open */ @Injectable({ providedIn: 'root' }) export class ClimateForecastService { public dailyForecastDocs = signal[]>([], { equal: isEqual }); - - public downscaledForecastsCollection = signal | null>(null); + public seasonalForecastDocs = signal[]>([], { equal: isEqual }); + public downscaledForecastDocs = signal[]>([], { equal: isEqual }); private get table() { return this.supabaseService.db.table('climate_forecasts'); @@ -34,21 +31,34 @@ export class ClimateForecastService { constructor( private supabaseService: SupabaseService, private dbService: PicsaDatabase_V2_Service, - private resourcesService: ResourcesToolService, private dbAttachmentService: PicsaDatabaseAttachmentService ) {} - public async loadForecasts(country_code: ICountryCode) { + public async loadForecasts(location: IUserSettings['location'] = []) { + await this.dbService.ensureCollections({ + climate_forecasts: CLIMATE_FORECAST_COLLECTION, + }); + const country_code = location[2] as ICountryCode; + const subLocationCode = location[4]; if (country_code) { this.loadDailyForecasts(country_code); - this.loadDownscaledForecasts(); + this.loadSeasonalForecasts(country_code); + this.loadDownscaledForecasts(country_code, subLocationCode); + } + } + + private async hackStoreHardcodedData(forecasts: IClimateForecastRow[] = []) { + const { error, success } = await this.dbCollection.bulkUpsert( + forecasts.map((forecast) => SERVER_DB_MAPPING(forecast)) + ); + if (error.length > 0) { + console.error('forecast store error', error); + return []; } + return success; } private async loadDailyForecasts(country_code: ICountryCode) { - await this.dbService.ensureCollections({ - climate_forecasts: CLIMATE_FORECAST_COLLECTION, - }); // populate any forecasts that are in the cache const cachedForecasts = await this.loadCachedForecasts(country_code); this.dailyForecastDocs.set(cachedForecasts); @@ -60,16 +70,28 @@ export class ClimateForecastService { console.error(error); throw new Error(`[Forecast] failed to load daily forecasts`); } - this.dailyForecastDocs.update((v) => [...success, ...v].slice(0, 5)); + this.dailyForecastDocs.update((v) => [...success, ...v].slice(0, 3)); } } + private async loadSeasonalForecasts(country_code: ICountryCode) { + const seaonalForecasts = CLIMATE_FORECASTS_DB.filter( + (v) => v.country_code === country_code && v.forecast_type === 'seasonal' + ); + const dbDocs = await this.hackStoreHardcodedData(seaonalForecasts); + this.seasonalForecastDocs.set(dbDocs); + } - private async loadDownscaledForecasts() { - // TODO - load hardcoded into service schema instead of resources (?) - // TODO - or integrate into DB (might be better) - await this.resourcesService.ready(); - const downscaled = await this.resourcesService.dbCollections.findOne('forecasts_downscaled').exec(); - this.downscaledForecastsCollection.set(downscaled); + private async loadDownscaledForecasts(country_code: ICountryCode, subLocationCode: string | null) { + if (!subLocationCode) { + this.downscaledForecastDocs.set([]); + return; + } + const downscaledForecasts = CLIMATE_FORECASTS_DB.filter( + (v) => + v.country_code === country_code && v.forecast_type === 'downscaled' && v.location?.includes(subLocationCode) + ); + const dbDocs = await this.hackStoreHardcodedData(downscaledForecasts); + this.downscaledForecastDocs.set(dbDocs); } public async downloadForecastFile(doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent) { @@ -91,8 +113,11 @@ export class ClimateForecastService { private async loadCachedForecasts(country_code: string) { // only filter if non-global country used - const selector = country_code === 'global' ? {} : { country_code }; - const cached = await this.dbCollection.find({ selector, sort: [{ id: 'desc' }], limit: 5 }).exec(); + const selector: MangoQuerySelector = { forecast_type: 'daily' }; + if (country_code !== 'global') { + selector.country_code = country_code; + } + const cached = await this.dbCollection.find({ selector, sort: [{ id: 'desc' }], limit: 3 }).exec(); return cached; } @@ -112,8 +137,7 @@ export class ClimateForecastService { if (latest) { query.gt('id', latest.id); } - const { data = [], error } = await query.order('id', { ascending: false }).limit(5); - console.log('server latest', latest?.id, data); + const { data = [], error } = await query.order('id', { ascending: false }).limit(3); if (error) { console.error(error); // TODO - handle error diff --git a/libs/configuration/src/provider.ts b/libs/configuration/src/provider.ts index db8973c40..dda120fd8 100644 --- a/libs/configuration/src/provider.ts +++ b/libs/configuration/src/provider.ts @@ -12,6 +12,12 @@ export interface IUserSettings { language_code: ILocaleCode; /** Specify if using farmer or extension app user_type */ user_type: 'farmer' | 'extension'; + /** + * User location, stored as an array to allow for hierarchy by osm admin level, + * https://wiki.openstreetmap.org/wiki/Key:admin_level + * @example [null,null,'malawi','northern','karonga'] + */ + location: (string | null)[]; } const USER_CONFIGURATION_DEFAULT: IUserSettings = { @@ -19,6 +25,7 @@ const USER_CONFIGURATION_DEFAULT: IUserSettings = { deployment_id: null as any, language_code: null as any, user_type: null as any, + location: [], }; @Injectable({ providedIn: 'root' }) @@ -47,6 +54,13 @@ export class ConfigurationService { document.body.dataset['theme'] = 'picsa-default'; } }); + + effect(() => { + // ensure sublocation kept in sync with country selected + const { country_code, location } = this.userSettings(); + if (location[2] === country_code) return; + this.userSettings.update((v) => ({ ...v, location: [null, null, country_code] })); + }); } public resetUserSettings() { diff --git a/libs/data/climate/forecasts/index.ts b/libs/data/climate/forecasts/index.ts new file mode 100644 index 000000000..dbade3706 --- /dev/null +++ b/libs/data/climate/forecasts/index.ts @@ -0,0 +1,9 @@ +import mw from './mw'; +import zm from './zm'; + +// eslint-disable-next-line @nx/enforce-module-boundaries +import { Database } from '@picsa/server-types'; + +export type IClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; + +export const CLIMATE_FORECASTS_DB = [...zm.downscaled, ...zm.seasonal, ...mw.downscaled, ...mw.seasonal]; diff --git a/libs/data/climate/forecasts/mw.ts b/libs/data/climate/forecasts/mw.ts new file mode 100644 index 000000000..0b7363c0f --- /dev/null +++ b/libs/data/climate/forecasts/mw.ts @@ -0,0 +1,317 @@ +import { IClimateForecastRow } from './types'; + +const seasonal: IClimateForecastRow[] = [ + { + id: 'b79ff462-eb50-49bf-89d2-d7e87717af7e', + country_code: 'mw', + forecast_type: 'seasonal', + storage_file: 'mw/forecasts/2024-2025_Seasonal_Rainfall_Forecast_Malawi_11_Sep_2024_Final.pdf', + language_code: 'en', + location: [], + created_at: '2024-10-14 18:12:08.013546+00', + updated_at: '2024-10-14 18:12:08.013546+00', + mimetype: 'application/pdf', + }, +]; + +const downscaled: IClimateForecastRow[] = [ + { + id: 'a4ac39ea-f469-419d-8bd5-99e080e00bcb', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/BALAKA.pdf', + language_code: 'en', + location: ['balaka'], + created_at: '2024-10-14 18:11:23.243079+00', + updated_at: '2024-10-14 18:11:23.243079+00', + mimetype: 'application/pdf', + }, + { + id: '380db05d-7dad-426f-9d17-7381eebce2e5', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/BLANTYRE.pdf', + language_code: 'en', + location: ['blantyre'], + created_at: '2024-10-14 18:11:09.655212+00', + updated_at: '2024-10-14 18:11:09.655212+00', + mimetype: 'application/pdf', + }, + { + id: '3c2dcc8b-b8dd-4326-8637-539aae3c3f8d', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/CHIKWAWA.pdf', + language_code: 'en', + location: ['chikwawa'], + created_at: '2024-10-14 18:11:09.682714+00', + updated_at: '2024-10-14 18:11:09.682714+00', + mimetype: 'application/pdf', + }, + { + id: '907f32a5-6840-478c-a0d1-6edc596fe258', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/CHIRADZULU.pdf', + language_code: 'en', + location: ['chiradzulu'], + created_at: '2024-10-14 18:11:23.207281+00', + updated_at: '2024-10-14 18:11:23.207281+00', + mimetype: 'application/pdf', + }, + { + id: '0eec3606-d263-4c7d-901c-b22bec133e68', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/CHITIPA.pdf', + language_code: 'en', + location: ['chitipa'], + created_at: '2024-10-14 18:11:09.83569+00', + updated_at: '2024-10-14 18:11:09.83569+00', + mimetype: 'application/pdf', + }, + { + id: '8532e10c-4cb9-4920-91bd-71e059a67c77', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/DOWA.pdf', + language_code: 'en', + location: ['dowa'], + created_at: '2024-10-14 18:11:09.409888+00', + updated_at: '2024-10-14 18:11:09.409888+00', + mimetype: 'application/pdf', + }, + { + id: '87b69c91-da9c-4174-8525-3dd75289c987', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/KASUNGU.pdf', + language_code: 'en', + location: ['kasungu'], + created_at: '2024-10-14 18:11:08.448048+00', + updated_at: '2024-10-14 18:11:08.448048+00', + mimetype: 'application/pdf', + }, + { + id: '40fc3ecb-2ae5-40db-afff-14dfe94335e4', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/KIRONGA.pdf', + language_code: 'en', + location: ['kironga'], + created_at: '2024-10-14 18:11:09.567199+00', + updated_at: '2024-10-14 18:11:09.567199+00', + mimetype: 'application/pdf', + }, + { + id: '6fc83453-a84d-4768-814e-8bb01af4a17e', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/LIKOMA.pdf', + language_code: 'en', + location: ['likoma'], + created_at: '2024-10-14 18:11:31.980442+00', + updated_at: '2024-10-14 18:11:31.980442+00', + mimetype: 'application/pdf', + }, + { + id: 'abf3c291-20f8-4582-a9ad-488ce509988d', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/LILONGWE.pdf', + language_code: 'en', + location: ['lilongwe'], + created_at: '2024-10-14 18:11:23.145823+00', + updated_at: '2024-10-14 18:11:23.145823+00', + mimetype: 'application/pdf', + }, + { + id: 'e0b89068-a34f-4f8d-9a5a-6acfc58e22de', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/MACHINGA.pdf', + language_code: 'en', + location: ['machinga'], + created_at: '2024-10-14 18:11:09.79181+00', + updated_at: '2024-10-14 18:11:09.79181+00', + mimetype: 'application/pdf', + }, + { + id: '1ed3458c-b1bd-4524-a0c1-ad52ae6fe8d0', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/MANGOCHI.pdf', + language_code: 'en', + location: ['mangochi'], + created_at: '2024-10-14 18:11:22.692276+00', + updated_at: '2024-10-14 18:11:22.692276+00', + mimetype: 'application/pdf', + }, + { + id: '000f3fd4-c3b4-414e-a004-490b0175d134', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/MCHINJI.pdf', + language_code: 'en', + location: ['mchinji'], + created_at: '2024-10-14 18:11:08.844687+00', + updated_at: '2024-10-14 18:11:08.844687+00', + mimetype: 'application/pdf', + }, + { + id: '687dada2-e368-4035-9219-1a082980c5ed', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/MULANJE.pdf', + language_code: 'en', + location: ['mulanje'], + created_at: '2024-10-14 18:11:23.173087+00', + updated_at: '2024-10-14 18:11:23.173087+00', + mimetype: 'application/pdf', + }, + { + id: 'aa8c69f8-8ed9-46ac-958c-e15b125e9c8e', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/MWANZA.pdf', + language_code: 'en', + location: ['mwanza'], + created_at: '2024-10-14 18:11:32.48908+00', + updated_at: '2024-10-14 18:11:32.48908+00', + mimetype: 'application/pdf', + }, + { + id: '244b069d-d2c5-4e3d-8ceb-3cda1c7957c8', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/MZIMBA.pdf', + language_code: 'en', + location: ['mzimba'], + created_at: '2024-10-14 18:11:09.259207+00', + updated_at: '2024-10-14 18:11:09.259207+00', + mimetype: 'application/pdf', + }, + { + id: '9bf1bf53-3b44-435a-b949-c3ac2576e33d', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/NENO.pdf', + language_code: 'en', + location: ['neno'], + created_at: '2024-10-14 18:11:22.877689+00', + updated_at: '2024-10-14 18:11:22.877689+00', + mimetype: 'application/pdf', + }, + { + id: '39bb7f23-7dee-46e4-b051-e9c37bd4c8a2', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/NKHATA BAY.pdf', + language_code: 'en', + location: ['nkhata_bay'], + created_at: '2024-10-14 18:11:32.547321+00', + updated_at: '2024-10-14 18:11:32.547321+00', + mimetype: 'application/pdf', + }, + { + id: '9352fabe-0586-48ef-9cd8-f2dac5ac9894', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/NKHOTAKOTA.pdf', + language_code: 'en', + location: ['nkhotakota'], + created_at: '2024-10-14 18:11:23.214239+00', + updated_at: '2024-10-14 18:11:23.214239+00', + mimetype: 'application/pdf', + }, + { + id: 'e081519b-19f0-4e59-8f86-474670d6028f', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/NSANJE.pdf', + language_code: 'en', + location: ['nsanje'], + created_at: '2024-10-14 18:11:32.403485+00', + updated_at: '2024-10-14 18:11:32.403485+00', + mimetype: 'application/pdf', + }, + { + id: '763869da-ffa1-467f-b8fe-0373710ca2df', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/NTCHEU.pdf', + language_code: 'en', + location: ['ntcheu'], + created_at: '2024-10-14 18:11:32.389443+00', + updated_at: '2024-10-14 18:11:32.389443+00', + mimetype: 'application/pdf', + }, + { + id: '3f0929de-b75e-4731-bf3f-da4f0d0ad825', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/NTCHISI.pdf', + language_code: 'en', + location: ['ntchisi'], + created_at: '2024-10-14 18:11:08.748628+00', + updated_at: '2024-10-14 18:11:08.748628+00', + mimetype: 'application/pdf', + }, + { + id: 'c3aa2653-ac80-49f1-a899-b50c72ad4898', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/PHALOMBE.pdf', + language_code: 'en', + location: ['phalombe'], + created_at: '2024-10-14 18:11:22.773196+00', + updated_at: '2024-10-14 18:11:22.773196+00', + mimetype: 'application/pdf', + }, + { + id: '64733f68-d958-4dd6-9a04-5dac5ce7fd2a', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/RUMPHI.pdf', + language_code: 'en', + location: ['rumphi'], + created_at: '2024-10-14 18:11:32.507389+00', + updated_at: '2024-10-14 18:11:32.507389+00', + mimetype: 'application/pdf', + }, + { + id: '1c204f75-5d7d-421f-830d-45261b82565a', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/SALIMA.pdf', + language_code: 'en', + location: ['salima'], + created_at: '2024-10-14 18:11:31.637577+00', + updated_at: '2024-10-14 18:11:31.637577+00', + mimetype: 'application/pdf', + }, + { + id: '24f32ab0-20dd-4020-aa72-abf2ab79ef0a', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/THYOLO.pdf', + language_code: 'en', + location: ['thyolo'], + created_at: '2024-10-14 18:11:23.494319+00', + updated_at: '2024-10-14 18:11:23.494319+00', + mimetype: 'application/pdf', + }, + { + id: '9274a223-3568-434f-91ea-40fd0e30084b', + country_code: 'mw', + forecast_type: 'downscaled', + storage_file: 'mw/forecasts/downscaled/ZOMBA.pdf', + language_code: 'en', + location: ['zomba'], + created_at: '2024-10-14 18:11:23.13625+00', + updated_at: '2024-10-14 18:11:23.13625+00', + mimetype: 'application/pdf', + }, +]; + +export default { seasonal, downscaled }; diff --git a/libs/data/climate/forecasts/types.ts b/libs/data/climate/forecasts/types.ts new file mode 100644 index 000000000..3736d70db --- /dev/null +++ b/libs/data/climate/forecasts/types.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line @nx/enforce-module-boundaries +import { Database } from '@picsa/server-types'; + +export type IClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; diff --git a/libs/data/climate/forecasts/zm.ts b/libs/data/climate/forecasts/zm.ts new file mode 100644 index 000000000..6a4647333 --- /dev/null +++ b/libs/data/climate/forecasts/zm.ts @@ -0,0 +1,64 @@ +import { IClimateForecastRow } from './types'; + +const seasonal: IClimateForecastRow[] = [ + { + id: 'c139d571-723c-4013-8246-28b0a291becf', + country_code: 'zm', + forecast_type: 'seasonal', + storage_file: 'zm/forecasts/ZMD Seasonal forecast 2024-25.pdf', + language_code: 'en', + location: [], + mimetype: 'application/pdf', + created_at: '2024-10-14 18:12:29.879524+00', + updated_at: '2024-10-14 18:12:29.879524+00', + }, +]; + +export const downscaled: IClimateForecastRow[] = [ + { + id: '8067b33b-dca9-47cc-9296-fb42b0ec5f54', + country_code: 'zm', + forecast_type: 'downscaled', + language_code: 'zm_ny', + location: ['chipata'], + storage_file: 'zm/forecasts/downscaled/CINYANJA SEASONAL RAINFALL FORECAST YA CHIPATA DISTRICT 2024.pdf', + created_at: '2024-10-25 09:59:27.62489+00', + updated_at: '2024-10-25 09:59:27.62489+00', + mimetype: 'application/pdf', + }, + { + id: '23938706-cea7-4c9e-b199-961d17b4be9a', + country_code: 'zm', + forecast_type: 'downscaled', + language_code: 'zm_ny', + location: ['petauke'], + storage_file: 'zm/forecasts/downscaled/CINYANJA SEASONAL RAINFALL FORECAST YA PETAUKE DISTRICT 2024.pdf', + created_at: '2024-10-25 09:59:30.722051+00', + updated_at: '2024-10-25 09:59:30.722051+00', + mimetype: 'application/pdf', + }, + { + id: '37b86bd1-f8a1-4709-8fd2-d2e6b8dc7294', + country_code: 'zm', + forecast_type: 'downscaled', + language_code: 'en', + location: ['chipata'], + storage_file: 'zm/forecasts/downscaled/SEASONAL RAINFALL FORECAST FOR CHIPATA DISTRICT 2024.pdf', + created_at: '2024-10-25 09:59:15.267263+00', + updated_at: '2024-10-25 09:59:15.267263+00', + mimetype: 'application/pdf', + }, + { + id: '9f4fd23f-d1c8-474f-aacc-f15d5aec4da9', + country_code: 'zm', + forecast_type: 'downscaled', + language_code: 'en', + location: ['petauke'], + storage_file: 'zm/forecasts/downscaled/SEASONAL RAINFALL FORECAST FOR PETAUKE DISTRICT 2024.pdf', + created_at: '2024-10-25 09:59:17.786206+00', + updated_at: '2024-10-25 09:59:17.786206+00', + mimetype: 'application/pdf', + }, +]; + +export default { seasonal, downscaled }; From a46270426024697a74689b51aff99032a9628b2c Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Tue, 25 Feb 2025 22:48:12 -0800 Subject: [PATCH 26/44] feat: zm district select and data --- libs/data/climate/forecasts/zm.ts | 8 +- libs/data/geoLocation/README.md | 41 ++++++++ libs/data/geoLocation/index.ts | 5 + libs/data/geoLocation/types.ts | 4 + libs/data/geoLocation/zm/districts.ts | 130 ++++++++++++++++++++++++++ libs/data/geoLocation/zm/provinces.ts | 12 +-- 6 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 libs/data/geoLocation/zm/districts.ts diff --git a/libs/data/climate/forecasts/zm.ts b/libs/data/climate/forecasts/zm.ts index 6a4647333..1718e881b 100644 --- a/libs/data/climate/forecasts/zm.ts +++ b/libs/data/climate/forecasts/zm.ts @@ -20,7 +20,7 @@ export const downscaled: IClimateForecastRow[] = [ country_code: 'zm', forecast_type: 'downscaled', language_code: 'zm_ny', - location: ['chipata'], + location: ['eastern', 'chipata'], storage_file: 'zm/forecasts/downscaled/CINYANJA SEASONAL RAINFALL FORECAST YA CHIPATA DISTRICT 2024.pdf', created_at: '2024-10-25 09:59:27.62489+00', updated_at: '2024-10-25 09:59:27.62489+00', @@ -31,7 +31,7 @@ export const downscaled: IClimateForecastRow[] = [ country_code: 'zm', forecast_type: 'downscaled', language_code: 'zm_ny', - location: ['petauke'], + location: ['eastern', 'petauke'], storage_file: 'zm/forecasts/downscaled/CINYANJA SEASONAL RAINFALL FORECAST YA PETAUKE DISTRICT 2024.pdf', created_at: '2024-10-25 09:59:30.722051+00', updated_at: '2024-10-25 09:59:30.722051+00', @@ -42,7 +42,7 @@ export const downscaled: IClimateForecastRow[] = [ country_code: 'zm', forecast_type: 'downscaled', language_code: 'en', - location: ['chipata'], + location: ['eastern', 'chipata'], storage_file: 'zm/forecasts/downscaled/SEASONAL RAINFALL FORECAST FOR CHIPATA DISTRICT 2024.pdf', created_at: '2024-10-25 09:59:15.267263+00', updated_at: '2024-10-25 09:59:15.267263+00', @@ -53,7 +53,7 @@ export const downscaled: IClimateForecastRow[] = [ country_code: 'zm', forecast_type: 'downscaled', language_code: 'en', - location: ['petauke'], + location: ['eastern', 'petauke'], storage_file: 'zm/forecasts/downscaled/SEASONAL RAINFALL FORECAST FOR PETAUKE DISTRICT 2024.pdf', created_at: '2024-10-25 09:59:17.786206+00', updated_at: '2024-10-25 09:59:17.786206+00', diff --git a/libs/data/geoLocation/README.md b/libs/data/geoLocation/README.md index 437d3a2ae..1dbc6be43 100644 --- a/libs/data/geoLocation/README.md +++ b/libs/data/geoLocation/README.md @@ -47,6 +47,47 @@ out geom; https://overpass-turbo.eu/s/1Z83 +**Admin_5 - District/Province Boundaries** +OSM does not keep relations between admin_4 and admin_5, so it is not possible to retrieve all admin_5 +boundaries with a single query. + +Instead wiki entries must be used to manually extract one at a time + +In some cases original sources for boundaries are provided, however these have likely undergone several revisions since +first population, and so are unlikely to be representative of current map as viewed in OSM + +It may be possible to try and use common tags found across multiple boundaries, e.g. + +``` +[out:json][timeout:25]; +// gather results +nwr["admin_level"="5"]["boundary"="administrative"]["source"="https://github.com/lightonphiri/data-zambia-shapefiles"]; + +// print results +out geom; +``` + +Otherwise will likely need to create a search limited to country bounding box and filter out results that are not part of country +Use web viewport bounding box via {{bbox}} query, or specify coordinates for custom bounding box + +``` +[out:json][timeout:25]; +// gather results +nwr["admin_level"="5"]["boundary"="administrative"]["type"="boundary"]({{bbox}}); + +// print results +out geom; +``` + +http://bboxfinder.com/#-18.271086,21.379395,-7.863382,34.453125 +21.379395, -18.271086, 34.453125, -7.863382 +West South East North + +Convert WSEN -> SWNE coordinates + +-18.271086, 21.379395, -7.863382, 34.453125 +South West North East + ### Export as GeoJSON Use the export feature in overpass-turbo to export as GeoJson diff --git a/libs/data/geoLocation/index.ts b/libs/data/geoLocation/index.ts index 73606e2e6..b48030b4e 100644 --- a/libs/data/geoLocation/index.ts +++ b/libs/data/geoLocation/index.ts @@ -3,6 +3,7 @@ import MW_DISTRICTS from './mw/districts'; import { ICountryCode } from '../deployments'; import { IGelocationData } from './types'; import ZM_PROVINCES from './zm/provinces'; +import ZM_DISTRICTS from './zm/districts'; export * from './utils'; export * from './types'; @@ -27,5 +28,9 @@ export const GEO_LOCATION_DATA: { [country_code in ICountryCode]?: IGelocationDa }, locations: ZM_PROVINCES, }, + admin_5: { + label: translateMarker('District'), + locations: ZM_DISTRICTS, + }, }, }; diff --git a/libs/data/geoLocation/types.ts b/libs/data/geoLocation/types.ts index 249b06465..e9421ea4e 100644 --- a/libs/data/geoLocation/types.ts +++ b/libs/data/geoLocation/types.ts @@ -8,6 +8,10 @@ export interface IGelocationData { topoJson: () => Promise; locations: { id: string; label: string }[]; }; + admin_5?: { + label: string; + locations: { id: string; label: string; admin_4: string }[]; + }; } export interface IGeoJsonData> { diff --git a/libs/data/geoLocation/zm/districts.ts b/libs/data/geoLocation/zm/districts.ts new file mode 100644 index 000000000..84d5dac96 --- /dev/null +++ b/libs/data/geoLocation/zm/districts.ts @@ -0,0 +1,130 @@ +const ZM_DISTRICTS = [ + // Central - 11 + { id: 'chibombo', label: 'Chibombo', admin_4: 'central' }, + { id: 'chisamba', label: 'Chisamba', admin_4: 'central' }, + { id: 'chitambo', label: 'Chitambo', admin_4: 'central' }, + { id: 'kabwe', label: 'Kabwe', admin_4: 'central' }, + { id: 'kapiri_mposhi', label: 'Kapiri Mposhi', admin_4: 'central' }, + { id: 'luano', label: 'Luano', admin_4: 'central' }, + { id: 'mkushi', label: 'Mkushi', admin_4: 'central' }, + { id: 'mumbwa', label: 'Mumbwa', admin_4: 'central' }, + { id: 'ngabwe', label: 'Ngabwe', admin_4: 'central' }, + { id: 'serenje', label: 'Serenje', admin_4: 'central' }, + { id: 'shibuyunji', label: 'Shibuyunji', admin_4: 'central' }, + // Copperbelt - 10 + { id: 'chililabombwe', label: 'Chililabombwe', admin_4: 'copperbelt' }, + { id: 'chingola', label: 'Chingola', admin_4: 'copperbelt' }, + { id: 'kalulushi', label: 'Kalulushi', admin_4: 'copperbelt' }, + { id: 'kitwe', label: 'Kitwe', admin_4: 'copperbelt' }, + { id: 'luanshya', label: 'Luanshya', admin_4: 'copperbelt' }, + { id: 'lufwanyama', label: 'Lufwanyama', admin_4: 'copperbelt' }, + { id: 'masaiti', label: 'Masaiti', admin_4: 'copperbelt' }, + { id: 'mpongwe', label: 'Mpongwe', admin_4: 'copperbelt' }, + { id: 'mufulira', label: 'Mufulira', admin_4: 'copperbelt' }, + { id: 'ndola', label: 'Ndola', admin_4: 'copperbelt' }, + // Eastern - 15 + { id: 'chadiza', label: 'Chadiza', admin_4: 'eastern' }, + { id: 'chama', label: 'Chama', admin_4: 'eastern' }, + { id: 'chasefu', label: 'Chasefu', admin_4: 'eastern' }, + { id: 'chipangali', label: 'Chipangali', admin_4: 'eastern' }, + { id: 'chipata', label: 'Chipata', admin_4: 'eastern' }, + { id: 'kasenengwa', label: 'Kasenengwa', admin_4: 'eastern' }, + { id: 'katete', label: 'Katete', admin_4: 'eastern' }, + { id: 'lumezi', label: 'Lumezi', admin_4: 'eastern' }, + { id: 'lundazi', label: 'Lundazi', admin_4: 'eastern' }, + { id: 'lusangazi', label: 'Lusangazi', admin_4: 'eastern' }, + { id: 'mambwe', label: 'Mambwe', admin_4: 'eastern' }, + { id: 'nyimba', label: 'Nyimba', admin_4: 'eastern' }, + { id: 'petauke', label: 'Petauke', admin_4: 'eastern' }, + { id: 'sinda', label: 'Sinda', admin_4: 'eastern' }, + { id: 'vubwi', label: 'Vubwi', admin_4: 'eastern' }, + // Luapula - 12 + { id: 'chembe', label: 'Chembe', admin_4: 'luapula' }, + { id: 'chiengi', label: 'Chiengi', admin_4: 'luapula' }, + { id: 'chifunabuli', label: 'Chifunabuli', admin_4: 'luapula' }, + { id: 'chipili', label: 'Chipili', admin_4: 'luapula' }, + { id: 'kawambwa', label: 'Kawambwa', admin_4: 'luapula' }, + { id: 'lunga', label: 'Lunga', admin_4: 'luapula' }, + { id: 'mansa', label: 'Mansa', admin_4: 'luapula' }, + { id: 'milenge', label: 'Milenge', admin_4: 'luapula' }, + { id: 'mwansabombwe', label: 'Mwansabombwe', admin_4: 'luapula' }, + { id: 'mwense', label: 'Mwense', admin_4: 'luapula' }, + { id: 'nchelenge', label: 'Nchelenge', admin_4: 'luapula' }, + { id: 'samfya', label: 'Samfya', admin_4: 'luapula' }, + // Lusaka - 6 + { id: 'chilanga', label: 'Chilanga', admin_4: 'lusaka' }, + { id: 'chongwe', label: 'Chongwe', admin_4: 'lusaka' }, + { id: 'kafue', label: 'Kafue', admin_4: 'lusaka' }, + { id: 'luangwa', label: 'Luangwa', admin_4: 'lusaka' }, + { id: 'lusaka', label: 'Lusaka', admin_4: 'lusaka' }, + { id: 'rufunsa', label: 'Rufunsa', admin_4: 'lusaka' }, + // Muchiga - 8 + { id: 'chinsali', label: 'Chinsali', admin_4: 'muchiga' }, + { id: 'isoka', label: 'Isoka', admin_4: 'muchiga' }, + { id: 'kanchibiya', label: 'Kanchibiya', admin_4: 'muchiga' }, + { id: 'lavushimanda', label: 'Lavushimanda', admin_4: 'muchiga' }, + { id: 'mafinga', label: 'Mafinga', admin_4: 'muchiga' }, + { id: 'mpika', label: 'Mpika', admin_4: 'muchiga' }, + { id: 'nakonde', label: 'Nakonde', admin_4: 'muchiga' }, + { id: 'shiwang_andu', label: "Shiwang'andu", admin_4: 'muchiga' }, + // North-Western - 11 + { id: 'chavuma', label: 'Chavuma', admin_4: 'north_western' }, + { id: 'ikelenge', label: 'Ikelenge', admin_4: 'north_western' }, + { id: 'kabompo', label: 'Kabompo', admin_4: 'north_western' }, + { id: 'kalumbila', label: 'Kalumbila', admin_4: 'north_western' }, + { id: 'kasempa', label: 'Kasempa', admin_4: 'north_western' }, + { id: 'manyinga', label: 'Manyinga', admin_4: 'north_western' }, + { id: 'mufumbwe', label: 'Mufumbwe', admin_4: 'north_western' }, + { id: 'mushindamo', label: 'Mushindamo', admin_4: 'north_western' }, + { id: 'mwinilunga', label: 'Mwinilunga', admin_4: 'north_western' }, + { id: 'solwezi', label: 'Solwezi', admin_4: 'north_western' }, + { id: 'zambezi', label: 'Zambezi', admin_4: 'north_western' }, + // Northern - 12 + { id: 'chilubi', label: 'Chilubi', admin_4: 'northern' }, + { id: 'kaputa', label: 'Kaputa', admin_4: 'northern' }, + { id: 'kasama', label: 'Kasama', admin_4: 'northern' }, + { id: 'lunte', label: 'Lunte', admin_4: 'northern' }, + { id: 'lupososhi', label: 'Lupososhi', admin_4: 'northern' }, + { id: 'luwingu', label: 'Luwingu', admin_4: 'northern' }, + { id: 'mbala', label: 'Mbala', admin_4: 'northern' }, + { id: 'mporokoso', label: 'Mporokoso', admin_4: 'northern' }, + { id: 'mpulungu', label: 'Mpulungu', admin_4: 'northern' }, + { id: 'mungwi', label: 'Mungwi', admin_4: 'northern' }, + { id: 'nsama', label: 'Nsama', admin_4: 'northern' }, + { id: 'senga', label: 'Senga', admin_4: 'northern' }, + + // Southern - 15 + { id: 'chikankata', label: 'Chikankata', admin_4: 'southern' }, + { id: 'chirundu', label: 'Chirundu', admin_4: 'southern' }, + { id: 'choma', label: 'Choma', admin_4: 'southern' }, + { id: 'gwembe', label: 'Gwembe', admin_4: 'southern' }, + { id: 'itezhi_tezhi', label: 'Itezhi-Tezhi', admin_4: 'southern' }, + { id: 'kalomo', label: 'Kalomo', admin_4: 'southern' }, + { id: 'kazungula', label: 'Kazungula', admin_4: 'southern' }, + { id: 'livingstone', label: 'Livingstone', admin_4: 'southern' }, + { id: 'mazabuka', label: 'Mazabuka', admin_4: 'southern' }, + { id: 'monze', label: 'Monze', admin_4: 'southern' }, + { id: 'namwala', label: 'Namwala', admin_4: 'southern' }, + { id: 'pemba', label: 'Pemba', admin_4: 'southern' }, + { id: 'siavonga', label: 'Siavonga', admin_4: 'southern' }, + { id: 'sinazongwe', label: 'Sinazongwe', admin_4: 'southern' }, + { id: 'zimba', label: 'Zimba', admin_4: 'southern' }, + // Western - 16 + { id: 'kalabo', label: 'Kalabo', admin_4: 'western' }, + { id: 'kaoma', label: 'Kaoma', admin_4: 'western' }, + { id: 'limulunga', label: 'Limulunga', admin_4: 'western' }, + { id: 'luampa', label: 'Luampa', admin_4: 'western' }, + { id: 'lukulu', label: 'Lukulu', admin_4: 'western' }, + { id: 'mitete', label: 'Mitete', admin_4: 'western' }, + { id: 'mongu', label: 'Mongu', admin_4: 'western' }, + { id: 'mulobezi', label: 'Mulobezi', admin_4: 'western' }, + { id: 'mwandi', label: 'Mwandi', admin_4: 'western' }, + { id: 'nalolo', label: 'Nalolo', admin_4: 'western' }, + { id: 'nkeyema', label: 'Nkeyema', admin_4: 'western' }, + { id: 'senanga', label: 'Senanga', admin_4: 'western' }, + { id: 'sesheke', label: 'Sesheke', admin_4: 'western' }, + { id: 'shang_ombo', label: "Shang'ombo", admin_4: 'western' }, + { id: 'sikongo', label: 'Sikongo', admin_4: 'western' }, + { id: 'sioma', label: 'Sioma', admin_4: 'western' }, +]; +export default ZM_DISTRICTS; diff --git a/libs/data/geoLocation/zm/provinces.ts b/libs/data/geoLocation/zm/provinces.ts index cf315c525..acbeffa7a 100644 --- a/libs/data/geoLocation/zm/provinces.ts +++ b/libs/data/geoLocation/zm/provinces.ts @@ -1,14 +1,14 @@ const ZM_PROVINCES = [ - { id: 'western', label: 'Western Province' }, - { id: 'north_western', label: 'North-Western Province' }, - { id: 'copperbelt', label: 'Copperbelt Province' }, { id: 'central', label: 'Central Province' }, - { id: 'northern', label: 'Northern Province' }, - { id: 'southern', label: 'Southern Province' }, - { id: 'lusaka', label: 'Lusaka Province' }, + { id: 'copperbelt', label: 'Copperbelt Province' }, { id: 'eastern', label: 'Eastern Province' }, { id: 'luapula', label: 'Luapula Province' }, + { id: 'lusaka', label: 'Lusaka Province' }, { id: 'muchinga', label: 'Muchinga Province' }, + { id: 'north_western', label: 'North-Western Province' }, + { id: 'northern', label: 'Northern Province' }, + { id: 'southern', label: 'Southern Province' }, + { id: 'western', label: 'Western Province' }, ]; export default ZM_PROVINCES; From 8e366326a21d28bc7c76f1d35862b895f2b24d7e Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Tue, 25 Feb 2025 22:52:51 -0800 Subject: [PATCH 27/44] feat: location select component --- .../location-select.component.html | 30 ++++++ .../location-select.component.scss | 3 + .../location-select.component.spec.ts | 22 ++++ .../location-select.component.ts | 100 ++++++++++++++++++ .../src/app/pages/forecast/forecast.page.ts | 59 +---------- 5 files changed, 159 insertions(+), 55 deletions(-) create mode 100644 apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.html create mode 100644 apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.scss create mode 100644 apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.spec.ts create mode 100644 apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.html b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.html new file mode 100644 index 000000000..50aedba16 --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.html @@ -0,0 +1,30 @@ + +
+ + {{ admin4Label() | translate }} + + @for (option of admin4Options(); track option.id) { + {{ option.label }} + } + + + @if(admin5Options().length>0){ + + + {{ admin5Label() | translate }} + + @for (option of admin5Options(); track option.id) { + {{ option.label }} + } + + + } +
diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.scss b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.scss new file mode 100644 index 000000000..5d4e87f30 --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.scss @@ -0,0 +1,3 @@ +:host { + display: block; +} diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.spec.ts b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.spec.ts new file mode 100644 index 000000000..2a7ddc71d --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LocationSelectComponent } from './location-select.component'; + +describe('LocationSelectComponent', () => { + let component: LocationSelectComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [LocationSelectComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(LocationSelectComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts new file mode 100644 index 000000000..134ea6c10 --- /dev/null +++ b/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts @@ -0,0 +1,100 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectionStrategy, Component, computed, effect, signal } from '@angular/core'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatSelectModule } from '@angular/material/select'; +import { ConfigurationService } from '@picsa/configuration/src'; +import { ICountryCode } from '@picsa/data'; +import { GEO_LOCATION_DATA } from '@picsa/data/geoLocation'; +import { PicsaTranslateModule } from '@picsa/shared/modules'; + +/** + * Climate location select displays dropdown selection boxes for administrative level 4 and 5 + * locations within the current user selected country. + * + * This is slightly complicated as different countries use different terminology to describe + * administrative location levels, and not all countries use all levels. + * + * E.g. In Malawi it shows dropdown [4|District] + * E.g. In Zambia is shows dropdowns [4|Province] [5|District] + */ +@Component({ + selector: 'climate-location-select', + imports: [CommonModule, MatFormFieldModule, MatSelectModule, PicsaTranslateModule], + templateUrl: './location-select.component.html', + styleUrl: './location-select.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ClimateLocationSelectComponent { + /** Options provided to location select (admin_4 district/province level) */ + public admin4Options = signal<{ id: string; label: string }[]>([]); + public admin5Options = signal<{ id: string; label: string }[]>([]); + + /** Label used for location select (admin_4 district/province level) */ + public admin4Label = signal(''); + public admin5Label = signal(''); + + /** Location selected as stored to user profile (admin_4 district/province level) */ + public admin4Selected = computed(() => this.configurationService.userSettings().location[4]); + public admin5Selected = computed(() => this.configurationService.userSettings().location[5]); + + private countrySelected = computed(() => this.configurationService.userSettings().location[2] as ICountryCode); + + constructor(private configurationService: ConfigurationService) { + // Generate admin 4 options + effect(() => { + const selected = this.countrySelected(); + if (selected) { + this.generateAdmin4Options(selected); + } + }); + + // Generate admin 5 options + effect(() => { + const selected = this.admin4Selected(); + if (selected) { + this.generateAdmin5Options(this.countrySelected(), selected); + } + }); + + // Set default admin_4 option + effect(() => { + if (!this.admin4Selected() && this.admin4Options().length > 0) { + this.handleUserLocationSelect(this.admin4Options()[0].id, 4); + } + }); + + // Set default admin_5 option + effect(() => { + if (!this.admin5Selected() && this.admin5Options().length > 0) { + this.handleUserLocationSelect(this.admin5Options()[0].id, 5); + } + }); + } + + /** When user district/province selected store to user profile location data */ + public handleUserLocationSelect(id: string, admin_level: 4 | 5) { + const update = [...this.configurationService.userSettings().location]; + update[admin_level] = id; + // clear admin_5 on admin_4 change + if (admin_level === 4) { + update[5] = undefined; + } + console.log('update location', update); + this.configurationService.updateUserSettings({ location: update }); + } + + private generateAdmin4Options(country_code: ICountryCode) { + const geoLocationData = GEO_LOCATION_DATA[country_code]; + const options = geoLocationData?.admin_4.locations || []; + this.admin4Label.set(geoLocationData?.admin_4.label || ''); + this.admin4Options.set(options); + } + + private generateAdmin5Options(country_code: ICountryCode, admin_4: string) { + const geoLocationData = GEO_LOCATION_DATA[country_code]; + const options = geoLocationData?.admin_5?.locations || []; + const filtered = options.filter((v) => v.admin_4 === admin_4); + this.admin5Label.set(geoLocationData?.admin_5?.label || ''); + this.admin5Options.set(filtered); + } +} diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts index fe591c212..fa4ac293b 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts @@ -1,10 +1,7 @@ import { CommonModule } from '@angular/common'; -import { Component, computed, effect, OnDestroy, signal, viewChildren } from '@angular/core'; +import { Component, computed, OnDestroy, viewChildren } from '@angular/core'; import { MatIcon } from '@angular/material/icon'; import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { ConfigurationService } from '@picsa/configuration'; -import { ICountryCode } from '@picsa/data'; -import { GEO_LOCATION_DATA } from '@picsa/data/geoLocation'; import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; @@ -13,6 +10,7 @@ import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/su import { RxDocument } from 'rxdb'; import { ClimateToolComponentsModule } from '../../components/climate-tool-components.module'; +import { ClimateLocationSelectComponent } from '../../components/location-select/location-select.component'; import { ClimateForecastService } from './forecast.service'; import { IClimateForecast } from './schemas'; @@ -32,6 +30,7 @@ interface IForecastSummary { imports: [ CommonModule, ClimateToolComponentsModule, + ClimateLocationSelectComponent, MatIcon, MatProgressBarModule, PicsaTranslateModule, @@ -43,15 +42,6 @@ interface IForecastSummary { export class ClimateForecastComponent implements OnDestroy { public pdfSrc?: string; - /** Options provided to location select (admin_4 district/province level) */ - public locationSelectOptions = signal<{ id: string; label: string }[]>([]); - - /** Label used for location select (admin_4 district/province level) */ - public locationSelectLabel = signal(''); - - /** Location selected as stored to user profile (admin_4 district/province level) */ - public locationSelected = computed(() => this.configurationService.userSettings().location[4]); - public dailyForecasts = computed(() => this.generateForecastSummary(this.service.dailyForecastDocs())); public downscaledForecasts = computed(() => this.generateForecastSummary(this.service.downscaledForecastDocs())); public seasonalForecasts = computed(() => this.generateForecastSummary(this.service.seasonalForecastDocs())); @@ -62,34 +52,7 @@ export class ClimateForecastComponent implements OnDestroy { /** List of rendered SupabaseStorageDownload components for direct interaction */ private downloaders = viewChildren(SupabaseStorageDownloadComponent); - constructor( - private service: ClimateForecastService, - private configurationService: ConfigurationService, - private dbAttachmentService: PicsaDatabaseAttachmentService - ) { - effect(() => { - const { location } = this.configurationService.userSettings(); - if (location) { - const country_code = location[2] as ICountryCode; - const sublocation = location[4]; - const geoLocationData = GEO_LOCATION_DATA[country_code]; - const locationOptions = geoLocationData?.admin_4.locations || []; - - // HACK - update user profile to select first location if not specified - if (!sublocation && locationOptions.length > 0) { - const updatedLocation = [...location]; - updatedLocation[4] = locationOptions[0].id; - return this.configurationService.updateUserSettings({ location: updatedLocation }); - } - // Load forecasts and configure UI - else { - this.locationSelectOptions.set(locationOptions); - this.locationSelectLabel.set(geoLocationData?.admin_4.label || ''); - this.service.loadForecasts(location); - } - } - }); - } + constructor(private service: ClimateForecastService, private dbAttachmentService: PicsaDatabaseAttachmentService) {} ngOnDestroy() { this.closeForecast(); @@ -108,20 +71,11 @@ export class ClimateForecastComponent implements OnDestroy { forecast._doc = forecast._doc.getLatest(); if (forecast._doc.getAttachment(forecast.storage_file)) { this.openForecast(forecast); - // refresh data to populated downloads - this.refreshForecastData(); } } } } - /** When user district/province selected store to user profile location data */ - public handleUserLocationSelect(admin_4_location: string) { - const update = [...this.configurationService.userSettings().location]; - update[4] = admin_4_location; - this.configurationService.updateUserSettings({ location: update }); - } - public closeForecast() { if (this.pdfSrc) { URL.revokeObjectURL(this.pdfSrc); @@ -149,11 +103,6 @@ export class ClimateForecastComponent implements OnDestroy { return summaries; } - private refreshForecastData() { - const { location } = this.configurationService.userSettings(); - return this.service.loadForecasts(location); - } - private async openForecast(forecast: IForecastSummary) { const uri = await this.dbAttachmentService.getFileAttachmentURI(forecast._doc, forecast.storage_file as string); this.pdfSrc = uri || undefined; From ee710fcead5bb1310e9de7c6fee17fcb6f5dd74e Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 08:59:33 -0800 Subject: [PATCH 28/44] chore: code tidying --- .../src/app/pages/forecast/forecast.page.html | 13 +-- .../app/pages/forecast/forecast.service.ts | 81 ++++++++++++------- .../station-select.component.ts | 2 + libs/configuration/src/provider.ts | 4 +- 4 files changed, 55 insertions(+), 45 deletions(-) diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html index e61ad8d51..3cbc788b3 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html @@ -10,18 +10,7 @@
- - {{locationSelectLabel() | translate}} - - @for (option of locationSelectOptions(); track option.id) { - {{option.label}} - } - - +
diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts index 5c29c4433..c6f78220e 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts @@ -1,26 +1,30 @@ -import { Injectable, signal } from '@angular/core'; -import { IUserSettings } from '@picsa/configuration/src'; +import { computed, effect, Injectable, signal } from '@angular/core'; +import { ConfigurationService } from '@picsa/configuration/src'; import { ICountryCode } from '@picsa/data'; import { CLIMATE_FORECASTS_DB } from '@picsa/data/climate/forecasts'; +import { PicsaAsyncService } from '@picsa/shared/services/asyncService.service'; import { PicsaDatabase_V2_Service, PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { isEqual } from '@picsa/utils/object.utils'; -import { MangoQuerySelector, RxCollection, RxDocument, RxQuery } from 'rxdb'; +import { MangoQuerySelector, RxCollection, RxDocument } from 'rxdb'; import { IClimateForecastRow } from './forecast.types'; import { CLIMATE_FORECAST_COLLECTION, IClimateForecast, SERVER_DB_MAPPING } from './schemas'; -/** - * TODOs - * - HTML Open - */ - @Injectable({ providedIn: 'root' }) -export class ClimateForecastService { +export class ClimateForecastService extends PicsaAsyncService { public dailyForecastDocs = signal[]>([], { equal: isEqual }); public seasonalForecastDocs = signal[]>([], { equal: isEqual }); public downscaledForecastDocs = signal[]>([], { equal: isEqual }); + private downscaledLocation = computed( + () => { + const { location } = this.configurationService.userSettings(); + return { country_code: location[2], admin_4: location[4], admin_5: location[5] }; + }, + { equal: isEqual } + ); + private get table() { return this.supabaseService.db.table('climate_forecasts'); } @@ -31,20 +35,48 @@ export class ClimateForecastService { constructor( private supabaseService: SupabaseService, private dbService: PicsaDatabase_V2_Service, - private dbAttachmentService: PicsaDatabaseAttachmentService - ) {} + private dbAttachmentService: PicsaDatabaseAttachmentService, + private configurationService: ConfigurationService + ) { + super(); + effect(async () => { + const { country_code } = this.configurationService.userSettings(); + if (country_code) { + await this.ready(); + this.loadDailyForecasts(country_code); + this.loadSeasonalForecasts(country_code); + } + }); - public async loadForecasts(location: IUserSettings['location'] = []) { + effect(async () => { + const { country_code, admin_4, admin_5 } = this.downscaledLocation(); + if (country_code && admin_4) { + await this.ready(); + this.loadDownscaledForecasts(country_code, admin_4, admin_5); + } else { + this.downscaledForecastDocs.set([]); + } + }); + } + public override async init(...args: any): Promise { await this.dbService.ensureCollections({ climate_forecasts: CLIMATE_FORECAST_COLLECTION, }); - const country_code = location[2] as ICountryCode; - const subLocationCode = location[4]; - if (country_code) { - this.loadDailyForecasts(country_code); - this.loadSeasonalForecasts(country_code); - this.loadDownscaledForecasts(country_code, subLocationCode); + } + + private async loadDownscaledForecasts(country_code: string, admin_4: string, admin_5?: string) { + const filters: ((v: IClimateForecastRow) => boolean)[] = [ + (v) => v.forecast_type === 'downscaled', + (v) => v.country_code === country_code, + (v) => v.location?.[0] === admin_4, + ]; + // optional filter if admin_5 in specifed + if (admin_5) { + filters.push((v) => v.location?.[1] === admin_5); } + const forecasts = CLIMATE_FORECASTS_DB.filter((v) => filters.every((fn) => fn(v))); + const dbDocs = await this.hackStoreHardcodedData(forecasts); + this.downscaledForecastDocs.set(dbDocs); } private async hackStoreHardcodedData(forecasts: IClimateForecastRow[] = []) { @@ -81,19 +113,6 @@ export class ClimateForecastService { this.seasonalForecastDocs.set(dbDocs); } - private async loadDownscaledForecasts(country_code: ICountryCode, subLocationCode: string | null) { - if (!subLocationCode) { - this.downscaledForecastDocs.set([]); - return; - } - const downscaledForecasts = CLIMATE_FORECASTS_DB.filter( - (v) => - v.country_code === country_code && v.forecast_type === 'downscaled' && v.location?.includes(subLocationCode) - ); - const dbDocs = await this.hackStoreHardcodedData(downscaledForecasts); - this.downscaledForecastDocs.set(dbDocs); - } - public async downloadForecastFile(doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent) { await downloaderUI.start(); const { error, data } = await downloaderUI.completed(); diff --git a/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts b/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts index 2b36bc76d..f7b75dce1 100644 --- a/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts +++ b/apps/picsa-tools/crop-probability-tool/src/app/components/station-select/station-select.component.ts @@ -15,6 +15,8 @@ import { IStationRouteQueryParams } from '../../models'; export class CropProbabilityStationSelectComponent { @Input() selectedStationId?: string; + // TODO - refactor to use geoLocation data (similar to forecasts page) + // and show fallback if no data available private stationsByCountry = computed(() => { const { country_code } = this.configurationService.userSettings(); if (country_code) { diff --git a/libs/configuration/src/provider.ts b/libs/configuration/src/provider.ts index dda120fd8..42e7f6f0d 100644 --- a/libs/configuration/src/provider.ts +++ b/libs/configuration/src/provider.ts @@ -17,7 +17,7 @@ export interface IUserSettings { * https://wiki.openstreetmap.org/wiki/Key:admin_level * @example [null,null,'malawi','northern','karonga'] */ - location: (string | null)[]; + location: (string | undefined)[]; } const USER_CONFIGURATION_DEFAULT: IUserSettings = { @@ -59,7 +59,7 @@ export class ConfigurationService { // ensure sublocation kept in sync with country selected const { country_code, location } = this.userSettings(); if (location[2] === country_code) return; - this.userSettings.update((v) => ({ ...v, location: [null, null, country_code] })); + this.userSettings.update((v) => ({ ...v, location: [undefined, undefined, country_code] })); }); } From ac47c04f4a62b0b0620f05b094d60098f366c795 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 09:12:03 -0800 Subject: [PATCH 29/44] refactor: forecasts standalone tool --- .../extension-app/src/app/routes/tool-routes.ts | 4 ++++ .../src/app/pages/home/extension-home.component.ts | 2 +- .../location-select/location-select.component.html | 0 .../location-select/location-select.component.scss | 0 .../location-select.component.spec.ts | 0 .../location-select/location-select.component.ts | 6 +++--- .../src}/pages/forecast/forecast.page.html | 2 +- .../src}/pages/forecast/forecast.page.scss | 0 .../src}/pages/forecast/forecast.page.ts | 13 +++++-------- .../src}/pages/forecast/forecast.service.ts | 2 +- .../src}/pages/forecast/forecast.types.ts | 0 .../src}/pages/forecast/schemas/index.ts | 0 .../src}/pages/forecast/schemas/schema_v0.ts | 0 tsconfig.base.json | 1 + 14 files changed, 16 insertions(+), 14 deletions(-) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/components/location-select/location-select.component.html (100%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/components/location-select/location-select.component.scss (100%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/components/location-select/location-select.component.spec.ts (100%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/components/location-select/location-select.component.ts (95%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/forecast.page.html (97%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/forecast.page.scss (100%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/forecast.page.ts (87%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/forecast.service.ts (99%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/forecast.types.ts (100%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/schemas/index.ts (100%) rename apps/picsa-tools/{climate-tool/src/app => forecasts/src}/pages/forecast/schemas/schema_v0.ts (100%) diff --git a/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts b/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts index e02d8b4bf..a7c8e5c7f 100644 --- a/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts +++ b/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts @@ -16,6 +16,10 @@ export const TOOL_ROUTES: Routes = [ loadChildren: () => import('@picsa/crop-probability/src/app/app.module-embedded').then((mod) => mod.CropProbabilityToolModule), }, + { + path: 'forecast', + loadComponent: () => import('@picsa/forecasts/pages/forecast/forecast.page').then((mod) => mod.ForecastComponent), + }, { path: 'monitoring', loadChildren: () => import('@picsa/monitoring/src/app/app.module-embedded').then((mod) => mod.MonitoringToolModule), diff --git a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts index d915fb2d2..eb016a627 100644 --- a/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts +++ b/apps/picsa-tools/extension-content/src/app/pages/home/extension-home.component.ts @@ -87,7 +87,7 @@ const ADDITIONAL_LINKS: IPageLink[] = [ { name: translateMarker('Forecasts'), svgIcon: 'extension_app:forecasts_tool', - url: '/climate/forecast', + url: '/forecasts', tourId: 'forecasts', }, { diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.html b/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.html similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.html rename to apps/picsa-tools/forecasts/src/components/location-select/location-select.component.html diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.scss b/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.scss similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.scss rename to apps/picsa-tools/forecasts/src/components/location-select/location-select.component.scss diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.spec.ts b/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.spec.ts similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.spec.ts rename to apps/picsa-tools/forecasts/src/components/location-select/location-select.component.spec.ts diff --git a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts b/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.ts similarity index 95% rename from apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts rename to apps/picsa-tools/forecasts/src/components/location-select/location-select.component.ts index 134ea6c10..2d9e5ce78 100644 --- a/apps/picsa-tools/climate-tool/src/app/components/location-select/location-select.component.ts +++ b/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.ts @@ -8,7 +8,7 @@ import { GEO_LOCATION_DATA } from '@picsa/data/geoLocation'; import { PicsaTranslateModule } from '@picsa/shared/modules'; /** - * Climate location select displays dropdown selection boxes for administrative level 4 and 5 + * Forecast location select displays dropdown selection boxes for administrative level 4 and 5 * locations within the current user selected country. * * This is slightly complicated as different countries use different terminology to describe @@ -18,13 +18,13 @@ import { PicsaTranslateModule } from '@picsa/shared/modules'; * E.g. In Zambia is shows dropdowns [4|Province] [5|District] */ @Component({ - selector: 'climate-location-select', + selector: 'forecast-location-select', imports: [CommonModule, MatFormFieldModule, MatSelectModule, PicsaTranslateModule], templateUrl: './location-select.component.html', styleUrl: './location-select.component.scss', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class ClimateLocationSelectComponent { +export class ForecastLocationSelectComponent { /** Options provided to location select (admin_4 district/province level) */ public admin4Options = signal<{ id: string; label: string }[]>([]); public admin5Options = signal<{ id: string; label: string }[]>([]); diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.html similarity index 97% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html rename to apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.html index 3cbc788b3..07772b674 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.html @@ -10,7 +10,7 @@
- +
diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.scss similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.scss rename to apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.scss diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts similarity index 87% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts rename to apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts index fa4ac293b..0c270903b 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts @@ -9,9 +9,8 @@ import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { RxDocument } from 'rxdb'; -import { ClimateToolComponentsModule } from '../../components/climate-tool-components.module'; -import { ClimateLocationSelectComponent } from '../../components/location-select/location-select.component'; -import { ClimateForecastService } from './forecast.service'; +import { ForecastLocationSelectComponent } from '../../components/location-select/location-select.component'; +import { ForecastService } from './forecast.service'; import { IClimateForecast } from './schemas'; interface IForecastSummary { @@ -24,13 +23,11 @@ interface IForecastSummary { } @Component({ - selector: 'climate-forecast', templateUrl: './forecast.page.html', styleUrls: ['./forecast.page.scss'], imports: [ CommonModule, - ClimateToolComponentsModule, - ClimateLocationSelectComponent, + ForecastLocationSelectComponent, MatIcon, MatProgressBarModule, PicsaTranslateModule, @@ -39,7 +36,7 @@ interface IForecastSummary { SupabaseStorageDownloadComponent, ], }) -export class ClimateForecastComponent implements OnDestroy { +export class ForecastComponent implements OnDestroy { public pdfSrc?: string; public dailyForecasts = computed(() => this.generateForecastSummary(this.service.dailyForecastDocs())); @@ -52,7 +49,7 @@ export class ClimateForecastComponent implements OnDestroy { /** List of rendered SupabaseStorageDownload components for direct interaction */ private downloaders = viewChildren(SupabaseStorageDownloadComponent); - constructor(private service: ClimateForecastService, private dbAttachmentService: PicsaDatabaseAttachmentService) {} + constructor(private service: ForecastService, private dbAttachmentService: PicsaDatabaseAttachmentService) {} ngOnDestroy() { this.closeForecast(); diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts similarity index 99% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts rename to apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts index c6f78220e..0a165b8a4 100644 --- a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts @@ -12,7 +12,7 @@ import { IClimateForecastRow } from './forecast.types'; import { CLIMATE_FORECAST_COLLECTION, IClimateForecast, SERVER_DB_MAPPING } from './schemas'; @Injectable({ providedIn: 'root' }) -export class ClimateForecastService extends PicsaAsyncService { +export class ForecastService extends PicsaAsyncService { public dailyForecastDocs = signal[]>([], { equal: isEqual }); public seasonalForecastDocs = signal[]>([], { equal: isEqual }); public downscaledForecastDocs = signal[]>([], { equal: isEqual }); diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.types.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/forecast.types.ts rename to apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts b/apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/index.ts rename to apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts diff --git a/apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts similarity index 100% rename from apps/picsa-tools/climate-tool/src/app/pages/forecast/schemas/schema_v0.ts rename to apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts diff --git a/tsconfig.base.json b/tsconfig.base.json index 88899d6b2..07d32a8bf 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -34,6 +34,7 @@ "@picsa/extension/*": ["apps/picsa-apps/extension-app/*"], "@picsa/farmer-content/*": ["apps/picsa-tools/farmer-content/*"], "@picsa/forms": ["libs/forms"], + "@picsa/forecasts/*": ["apps/picsa-tools/forecasts/src/*"], "@picsa/i18n": ["libs/i18n/src/index.ts"], "@picsa/manual/*": ["apps/picsa-tools/manual-tool/*"], "@picsa/migrations": ["libs/migrations/index.ts"], From 5e763693fd10aeb8d8460e3b66f1fac6df88e72c Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 09:14:10 -0800 Subject: [PATCH 30/44] chore: code tidying --- .../src/pages/forecast/forecast.page.ts | 6 ++-- .../src/pages/forecast/forecast.service.ts | 28 +++++++++---------- .../src/pages/forecast/forecast.types.ts | 2 +- .../src/pages/forecast/schemas/index.ts | 6 ++-- .../src/pages/forecast/schemas/schema_v0.ts | 12 ++++---- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts index 0c270903b..0d05e239b 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts @@ -11,10 +11,10 @@ import { RxDocument } from 'rxdb'; import { ForecastLocationSelectComponent } from '../../components/location-select/location-select.component'; import { ForecastService } from './forecast.service'; -import { IClimateForecast } from './schemas'; +import { IForecast } from './schemas'; interface IForecastSummary { - _doc: RxDocument; + _doc: RxDocument; id: string; label: string; storage_file: string; @@ -80,7 +80,7 @@ export class ForecastComponent implements OnDestroy { this.pdfSrc = undefined; } - private generateForecastSummary(docs: RxDocument[]): IForecastSummary[] { + private generateForecastSummary(docs: RxDocument[]): IForecastSummary[] { const summaries = docs.map((doc) => { const { id, storage_file, forecast_type } = doc; const label = this.generateForecastLabel(storage_file); diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts index 0a165b8a4..bc4783f48 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts @@ -8,14 +8,14 @@ import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared import { isEqual } from '@picsa/utils/object.utils'; import { MangoQuerySelector, RxCollection, RxDocument } from 'rxdb'; -import { IClimateForecastRow } from './forecast.types'; -import { CLIMATE_FORECAST_COLLECTION, IClimateForecast, SERVER_DB_MAPPING } from './schemas'; +import { IForecastRow } from './forecast.types'; +import { FORECAST_COLLECTION, IForecast, SERVER_DB_MAPPING } from './schemas'; @Injectable({ providedIn: 'root' }) export class ForecastService extends PicsaAsyncService { - public dailyForecastDocs = signal[]>([], { equal: isEqual }); - public seasonalForecastDocs = signal[]>([], { equal: isEqual }); - public downscaledForecastDocs = signal[]>([], { equal: isEqual }); + public dailyForecastDocs = signal[]>([], { equal: isEqual }); + public seasonalForecastDocs = signal[]>([], { equal: isEqual }); + public downscaledForecastDocs = signal[]>([], { equal: isEqual }); private downscaledLocation = computed( () => { @@ -29,7 +29,7 @@ export class ForecastService extends PicsaAsyncService { return this.supabaseService.db.table('climate_forecasts'); } private get dbCollection() { - return this.dbService.db.collections['climate_forecasts'] as RxCollection; + return this.dbService.db.collections['climate_forecasts'] as RxCollection; } constructor( @@ -60,12 +60,12 @@ export class ForecastService extends PicsaAsyncService { } public override async init(...args: any): Promise { await this.dbService.ensureCollections({ - climate_forecasts: CLIMATE_FORECAST_COLLECTION, + climate_forecasts: FORECAST_COLLECTION, }); } private async loadDownscaledForecasts(country_code: string, admin_4: string, admin_5?: string) { - const filters: ((v: IClimateForecastRow) => boolean)[] = [ + const filters: ((v: IForecastRow) => boolean)[] = [ (v) => v.forecast_type === 'downscaled', (v) => v.country_code === country_code, (v) => v.location?.[0] === admin_4, @@ -79,7 +79,7 @@ export class ForecastService extends PicsaAsyncService { this.downscaledForecastDocs.set(dbDocs); } - private async hackStoreHardcodedData(forecasts: IClimateForecastRow[] = []) { + private async hackStoreHardcodedData(forecasts: IForecastRow[] = []) { const { error, success } = await this.dbCollection.bulkUpsert( forecasts.map((forecast) => SERVER_DB_MAPPING(forecast)) ); @@ -113,7 +113,7 @@ export class ForecastService extends PicsaAsyncService { this.seasonalForecastDocs.set(dbDocs); } - public async downloadForecastFile(doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent) { + public async downloadForecastFile(doc: RxDocument, downloaderUI: SupabaseStorageDownloadComponent) { await downloaderUI.start(); const { error, data } = await downloaderUI.completed(); if (error) { @@ -132,7 +132,7 @@ export class ForecastService extends PicsaAsyncService { private async loadCachedForecasts(country_code: string) { // only filter if non-global country used - const selector: MangoQuerySelector = { forecast_type: 'daily' }; + const selector: MangoQuerySelector = { forecast_type: 'daily' }; if (country_code !== 'global') { selector.country_code = country_code; } @@ -140,16 +140,16 @@ export class ForecastService extends PicsaAsyncService { return cached; } - private async saveForecasts(forecasts: IClimateForecast[]) { + private async saveForecasts(forecasts: IForecast[]) { const saved = await this.dbCollection.bulkUpsert(forecasts); return saved; } - private async loadServerForecasts(country_code: string, latest?: IClimateForecast): Promise { + private async loadServerForecasts(country_code: string, latest?: IForecast): Promise { await this.supabaseService.ready(); // only retrieve forecasts that have storage files stored // NOTE - these are populated on a separate cron schedule to forecast db entries - const query = this.table.select<'*', IClimateForecastRow>('*').neq('storage_file', null); + const query = this.table.select<'*', IForecastRow>('*').neq('storage_file', null); if (country_code !== 'global') { query.eq('country_code', country_code); } diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts index 3736d70db..651b2462c 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts @@ -1,4 +1,4 @@ // eslint-disable-next-line @nx/enforce-module-boundaries import { Database } from '@picsa/server-types'; -export type IClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; +export type IForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts b/apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts index 606f860e6..f940cbd53 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts @@ -2,8 +2,8 @@ import * as schema from './schema_v0'; // Re-export schema to provide latest version without need to refactor additonal code -export const CLIMATE_FORECAST_COLLECTION = schema.COLLECTION_V0; -export const CLIMATE_FORECAST_SCHEMA = schema.SCHEMA_V0; +export const FORECAST_COLLECTION = schema.COLLECTION_V0; +export const FORECAST_SCHEMA = schema.SCHEMA_V0; export const SERVER_DB_MAPPING = schema.SERVER_DB_MAPPING_V0; -export type IClimateForecast = schema.IClimateForecast_V0; +export type IForecast = schema.IForecast_V0; diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts index 6ec0ed3dd..357b48568 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts @@ -2,12 +2,12 @@ import type { Database } from '@picsa/server-types'; import type { IPicsaCollectionCreator } from '@picsa/shared/services/core/db_v2'; import { RxJsonSchema } from 'rxdb'; -import { IClimateForecastRow } from '../forecast.types'; +import { IForecastRow } from '../forecast.types'; const SCHEMA_VERSION = 0; // interface adapted from server types -export interface IClimateForecast_V0 { +export interface IForecast_V0 { country_code: string; forecast_type: Database['public']['Enums']['forecast_type'] | null; id: string; @@ -17,8 +17,8 @@ export interface IClimateForecast_V0 { storage_file: string; } -export const SCHEMA_V0: RxJsonSchema = { - title: 'climate_forecasts', +export const SCHEMA_V0: RxJsonSchema = { + title: 'forecasts', version: SCHEMA_VERSION, keyCompression: false, type: 'object', @@ -39,13 +39,13 @@ export const SCHEMA_V0: RxJsonSchema = { }, }; -export const COLLECTION_V0: IPicsaCollectionCreator = { +export const COLLECTION_V0: IPicsaCollectionCreator = { schema: SCHEMA_V0, isUserCollection: false, migrationStrategies: {}, }; -export const SERVER_DB_MAPPING_V0 = (row: IClimateForecastRow): IClimateForecast_V0 => { +export const SERVER_DB_MAPPING_V0 = (row: IForecastRow): IForecast_V0 => { const { country_code, forecast_type, id, language_code, location, mimetype, storage_file } = row; return { country_code, From 33f9740813d3d8538215d5c5b2439daf8df0edd0 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 09:22:46 -0800 Subject: [PATCH 31/44] chore: code tidying --- .../modules/climate/climate-api.mapping.ts | 2 +- .../pages/forecast/forecast.component.ts | 2 +- .../src/app/modules/climate/types/db.d.ts | 6 +- .../dashboard/climate-forecast-db.ts | 6 +- .../dashboard/climate-forecast-storage.ts | 8 +- .../supabase/functions/dashboard/index.ts | 8 +- .../supabase/functions/dashboard/types.ts | 4 +- ...0250115161100_climate_forecasts_update.sql | 10 +- ...250127193000_forecast_update_cron copy.sql | 6 +- apps/picsa-server/supabase/types/index.ts | 2 +- .../src/app/app-routing.module.ts | 5 - .../src/pages/forecast/forecast.service.ts | 12 +- .../src/pages/forecast/forecast.types.ts | 2 +- libs/data/climate/forecasts/index.ts | 4 +- libs/data/climate/forecasts/mw.ts | 6 +- libs/data/climate/forecasts/types.ts | 2 +- libs/data/climate/forecasts/zm.ts | 6 +- libs/data/resources/forecasts/mw.ts | 597 ------------------ libs/data/resources/forecasts/zm.ts | 114 ---- .../src/services/core/db_v2/db.types.ts | 2 +- 20 files changed, 44 insertions(+), 760 deletions(-) delete mode 100644 libs/data/resources/forecasts/mw.ts delete mode 100644 libs/data/resources/forecasts/zm.ts diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts index 7105b3e13..560c779d2 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts @@ -116,7 +116,7 @@ export const ApiMapping = ( // TODO - handle error if filename already exists const { error: dbError } = await supabaseService.db - .table('climate_forecasts') + .table('forecasts') .update({ storage_file: fullPath }) .eq('id', row.id); if (dbError) { diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts index 7e21fa17a..2f19b5f90 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts @@ -61,7 +61,7 @@ export class ClimateForecastPageComponent { public activeDownloads = signal>({}); private get db() { - return this.supabase.db.table('climate_forecasts'); + return this.supabase.db.table('forecasts'); } constructor( diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/types/db.d.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/types/db.d.ts index 2b5a758d2..f2b75ac82 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/types/db.d.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/types/db.d.ts @@ -10,9 +10,9 @@ export type IClimateSummaryRainfallRow = Database['public']['Tables']['climate_s }; export type IClimateSummaryRainfallInsert = Database['public']['Tables']['climate_summary_rainfall']['Insert']; -export type IForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; -export type IForecastInsert = Database['public']['Tables']['climate_forecasts']['Insert']; -export type IForecastUpdate = Database['public']['Tables']['climate_forecasts']['Update']; +export type IForecastRow = Database['public']['Tables']['forecasts']['Row']; +export type IForecastInsert = Database['public']['Tables']['forecasts']['Insert']; +export type IForecastUpdate = Database['public']['Tables']['forecasts']['Update']; export type IStationRow = Database['public']['Tables']['climate_stations']['Row']; export type IStationInsert = Database['public']['Tables']['climate_stations']['Insert']; diff --git a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts index 16e08eb3f..59ccff78f 100644 --- a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts +++ b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts @@ -21,7 +21,7 @@ export const apiClient = createClient({ baseUrl: CLIMATE_API_EN /** * Update cliamte forecast db rows */ -export const climateForecastDB = async (req: Request) => { +export const forecastDB = async (req: Request) => { // Validate body formData // TODO - Improve validators and feedback let { country_codes = COUNTRY_CODES, query_prefix } = await getJsonData(req); @@ -59,7 +59,7 @@ async function getCountryUpdates(country_code: string, query_prefix: string) { // map api forecasts to db format and update db const updates = mapApiForecastToDb(newForecasts, country_code); const supabaseClient = getClient(); - const { error } = await supabaseClient.from('climate_forecasts').insert(updates); + const { error } = await supabaseClient.from('forecasts').insert(updates); if (error) { throw error; } @@ -82,7 +82,7 @@ async function getDBForecasts(query: { country_code: string; query_prefix: strin const { country_code, query_prefix } = query; console.log('db query', query_prefix, country_code); const { data, error } = await supabaseClient - .from('climate_forecasts') + .from('forecasts') .select('*') .like('id', `${query_prefix}%`) .eq('country_code', country_code) diff --git a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts index bcb2e3962..4583bd6ff 100644 --- a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts +++ b/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts @@ -16,19 +16,19 @@ interface IReqParams { * Handle downloading forecast files from api and populating to supabase storage entry * Checks DB for any entries without storage files and attempts to update */ -export const climateForecastStorage = async (req: Request) => { +export const forecastStorage = async (req: Request) => { // ensure api up and running before sending batched requests await apiClient.GET('/v1/status/'); const params = await getJsonData(req); - const res = await new ClimateForecastStorageUpdate().populateStorageFiles(params); + const res = await new ForecastStorageUpdate().populateStorageFiles(params); return JSONResponse(res); }; -class ClimateForecastStorageUpdate { +class ForecastStorageUpdate { supabaseClient = getClient(); private get table() { - return this.supabaseClient.from('climate_forecasts'); + return this.supabaseClient.from('forecasts'); } async populateStorageFiles(params: IReqParams) { diff --git a/apps/picsa-server/supabase/functions/dashboard/index.ts b/apps/picsa-server/supabase/functions/dashboard/index.ts index 952ff99a8..d8e850da3 100644 --- a/apps/picsa-server/supabase/functions/dashboard/index.ts +++ b/apps/picsa-server/supabase/functions/dashboard/index.ts @@ -3,8 +3,8 @@ // This enables autocomplete, go to definition, etc. import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; -import { climateForecastStorage } from './climate-forecast-storage.ts'; -import { climateForecastDB } from './climate-forecast-db.ts'; +import { forecastStorage } from './climate-forecast-storage.ts'; +import { forecastDB } from './climate-forecast-db.ts'; import { corsHeaders } from '../_shared/cors.ts'; serve((req) => { @@ -20,9 +20,9 @@ serve((req) => { switch (endpoint) { case 'climate-forecast-db': - return climateForecastDB(req); + return forecastDB(req); case 'climate-forecast-storage': - return climateForecastStorage(req); + return forecastStorage(req); default: return new Response(`Invalid endpoint: ${endpoint}`, { diff --git a/apps/picsa-server/supabase/functions/dashboard/types.ts b/apps/picsa-server/supabase/functions/dashboard/types.ts index f34b8a9ec..133b56d69 100644 --- a/apps/picsa-server/supabase/functions/dashboard/types.ts +++ b/apps/picsa-server/supabase/functions/dashboard/types.ts @@ -4,7 +4,7 @@ import type { paths, components } from '../../../../picsa-apps/dashboard/src/app export type climateApiPaths = paths; export type climateApiComponents = components; -export type IDBClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; -export type IDBClimateForecastInsert = Database['public']['Tables']['climate_forecasts']['Insert']; +export type IDBClimateForecastRow = Database['public']['Tables']['forecasts']['Row']; +export type IDBClimateForecastInsert = Database['public']['Tables']['forecasts']['Insert']; export type IApiClimateForecast = climateApiComponents['schemas']['DocumentMetadata']; diff --git a/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql b/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql index e31910bb2..17ce57358 100644 --- a/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql +++ b/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql @@ -1,11 +1,11 @@ -- recreate table and data -drop table if exists public.climate_forecasts; +drop table if exists public.forecasts; -- -- Custom types create type public.forecast_type as enum ('daily','seasonal','downscaled'); create table - public.climate_forecasts ( + public.forecasts ( id character varying not null, created_at timestamp with time zone DEFAULT "now"() NOT NULL, updated_at timestamp with time zone DEFAULT "now"() NOT NULL, @@ -17,8 +17,8 @@ create table language_code text null, storage_file text null, mimetype text null, - constraint climate_forecasts_pkey primary key (id), - constraint climate_forecasts_storage_file_fkey foreign key (storage_file) references storage.objects (path) on delete cascade + constraint forecasts_pkey primary key (id), + constraint forecasts_storage_file_fkey foreign key (storage_file) references storage.objects (path) on delete cascade ) tablespace pg_default; @@ -27,5 +27,5 @@ create table CREATE EXTENSION IF NOT EXISTS "moddatetime" SCHEMA extensions; -- NOTE - required extensions - allow moddatetime -create trigger handle_updated_at before update on public.climate_forecasts +create trigger handle_updated_at before update on public.forecasts for each row execute procedure moddatetime (updated_at); \ No newline at end of file diff --git a/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql b/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql index d03d972ae..22ecbaff4 100644 --- a/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql +++ b/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql @@ -7,14 +7,14 @@ grant all privileges on all tables in schema cron to postgres; -- Trigger backend edge function every 30 minutes -- Adapted from https://supabase.com/docs/guides/functions/schedule-functions -select cron.schedule('climate_forecasts_db', '30 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-db','{}'::jsonb); $$); +select cron.schedule('forecasts_db', '30 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-db','{}'::jsonb); $$); -select cron.schedule('climate_forecasts_storage', '35 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-storage','{}'::jsonb); $$); +select cron.schedule('forecasts_storage', '35 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-storage','{}'::jsonb); $$); -- Alt implementation (intermediate function created to structure more complex requests, kept for future reference) --- create or replace function public.trigger_climate_forecast_update() +-- create or replace function public.trigger_forecast_update() -- returns void -- language plpgsql -- as $$ diff --git a/apps/picsa-server/supabase/types/index.ts b/apps/picsa-server/supabase/types/index.ts index 195df967d..084a1c0b4 100644 --- a/apps/picsa-server/supabase/types/index.ts +++ b/apps/picsa-server/supabase/types/index.ts @@ -34,7 +34,7 @@ export type Database = { } public: { Tables: { - climate_forecasts: { + forecasts: { Row: { country_code: string created_at: string diff --git a/apps/picsa-tools/climate-tool/src/app/app-routing.module.ts b/apps/picsa-tools/climate-tool/src/app/app-routing.module.ts index dfc85e90e..adca984a1 100644 --- a/apps/picsa-tools/climate-tool/src/app/app-routing.module.ts +++ b/apps/picsa-tools/climate-tool/src/app/app-routing.module.ts @@ -15,11 +15,6 @@ export const ROUTES_COMMON: Routes = [ headerStyle: 'inverted', }, }, - { - path: 'forecast', - loadComponent: () => import('./pages/forecast/forecast.page').then((mod) => mod.ClimateForecastComponent), - title: translateMarker('Forecast'), - }, { path: 'site', redirectTo: '', diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts index bc4783f48..db2999c35 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts @@ -1,7 +1,7 @@ import { computed, effect, Injectable, signal } from '@angular/core'; import { ConfigurationService } from '@picsa/configuration/src'; import { ICountryCode } from '@picsa/data'; -import { CLIMATE_FORECASTS_DB } from '@picsa/data/climate/forecasts'; +import { FORECASTS_DB } from '@picsa/data/climate/forecasts'; import { PicsaAsyncService } from '@picsa/shared/services/asyncService.service'; import { PicsaDatabase_V2_Service, PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; @@ -26,10 +26,10 @@ export class ForecastService extends PicsaAsyncService { ); private get table() { - return this.supabaseService.db.table('climate_forecasts'); + return this.supabaseService.db.table('forecasts'); } private get dbCollection() { - return this.dbService.db.collections['climate_forecasts'] as RxCollection; + return this.dbService.db.collections['forecasts'] as RxCollection; } constructor( @@ -60,7 +60,7 @@ export class ForecastService extends PicsaAsyncService { } public override async init(...args: any): Promise { await this.dbService.ensureCollections({ - climate_forecasts: FORECAST_COLLECTION, + forecasts: FORECAST_COLLECTION, }); } @@ -74,7 +74,7 @@ export class ForecastService extends PicsaAsyncService { if (admin_5) { filters.push((v) => v.location?.[1] === admin_5); } - const forecasts = CLIMATE_FORECASTS_DB.filter((v) => filters.every((fn) => fn(v))); + const forecasts = FORECASTS_DB.filter((v) => filters.every((fn) => fn(v))); const dbDocs = await this.hackStoreHardcodedData(forecasts); this.downscaledForecastDocs.set(dbDocs); } @@ -106,7 +106,7 @@ export class ForecastService extends PicsaAsyncService { } } private async loadSeasonalForecasts(country_code: ICountryCode) { - const seaonalForecasts = CLIMATE_FORECASTS_DB.filter( + const seaonalForecasts = FORECASTS_DB.filter( (v) => v.country_code === country_code && v.forecast_type === 'seasonal' ); const dbDocs = await this.hackStoreHardcodedData(seaonalForecasts); diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts index 651b2462c..c90544835 100644 --- a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts +++ b/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts @@ -1,4 +1,4 @@ // eslint-disable-next-line @nx/enforce-module-boundaries import { Database } from '@picsa/server-types'; -export type IForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; +export type IForecastRow = Database['public']['Tables']['forecasts']['Row']; diff --git a/libs/data/climate/forecasts/index.ts b/libs/data/climate/forecasts/index.ts index dbade3706..723e27636 100644 --- a/libs/data/climate/forecasts/index.ts +++ b/libs/data/climate/forecasts/index.ts @@ -4,6 +4,6 @@ import zm from './zm'; // eslint-disable-next-line @nx/enforce-module-boundaries import { Database } from '@picsa/server-types'; -export type IClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; +export type IForecastRow = Database['public']['Tables']['forecasts']['Row']; -export const CLIMATE_FORECASTS_DB = [...zm.downscaled, ...zm.seasonal, ...mw.downscaled, ...mw.seasonal]; +export const FORECASTS_DB = [...zm.downscaled, ...zm.seasonal, ...mw.downscaled, ...mw.seasonal]; diff --git a/libs/data/climate/forecasts/mw.ts b/libs/data/climate/forecasts/mw.ts index 0b7363c0f..af2712884 100644 --- a/libs/data/climate/forecasts/mw.ts +++ b/libs/data/climate/forecasts/mw.ts @@ -1,6 +1,6 @@ -import { IClimateForecastRow } from './types'; +import { IForecastRow } from './types'; -const seasonal: IClimateForecastRow[] = [ +const seasonal: IForecastRow[] = [ { id: 'b79ff462-eb50-49bf-89d2-d7e87717af7e', country_code: 'mw', @@ -14,7 +14,7 @@ const seasonal: IClimateForecastRow[] = [ }, ]; -const downscaled: IClimateForecastRow[] = [ +const downscaled: IForecastRow[] = [ { id: 'a4ac39ea-f469-419d-8bd5-99e080e00bcb', country_code: 'mw', diff --git a/libs/data/climate/forecasts/types.ts b/libs/data/climate/forecasts/types.ts index 3736d70db..c90544835 100644 --- a/libs/data/climate/forecasts/types.ts +++ b/libs/data/climate/forecasts/types.ts @@ -1,4 +1,4 @@ // eslint-disable-next-line @nx/enforce-module-boundaries import { Database } from '@picsa/server-types'; -export type IClimateForecastRow = Database['public']['Tables']['climate_forecasts']['Row']; +export type IForecastRow = Database['public']['Tables']['forecasts']['Row']; diff --git a/libs/data/climate/forecasts/zm.ts b/libs/data/climate/forecasts/zm.ts index 1718e881b..77b81e27f 100644 --- a/libs/data/climate/forecasts/zm.ts +++ b/libs/data/climate/forecasts/zm.ts @@ -1,6 +1,6 @@ -import { IClimateForecastRow } from './types'; +import { IForecastRow } from './types'; -const seasonal: IClimateForecastRow[] = [ +const seasonal: IForecastRow[] = [ { id: 'c139d571-723c-4013-8246-28b0a291becf', country_code: 'zm', @@ -14,7 +14,7 @@ const seasonal: IClimateForecastRow[] = [ }, ]; -export const downscaled: IClimateForecastRow[] = [ +export const downscaled: IForecastRow[] = [ { id: '8067b33b-dca9-47cc-9296-fb42b0ec5f54', country_code: 'zm', diff --git a/libs/data/resources/forecasts/mw.ts b/libs/data/resources/forecasts/mw.ts deleted file mode 100644 index ad3434931..000000000 --- a/libs/data/resources/forecasts/mw.ts +++ /dev/null @@ -1,597 +0,0 @@ -import { IForecastStorageEntry } from './types'; - -const seasonal: IForecastStorageEntry[] = [ - { - id: 'b79ff462-eb50-49bf-89d2-d7e87717af7e', - bucket_id: 'mw', - name: 'forecasts/2024-2025_Seasonal_Rainfall_Forecast_Malawi_11_Sep_2024_Final.pdf', - owner: '', - created_at: '2024-10-14 18:12:08.013546+00', - updated_at: '2024-10-14 18:12:08.013546+00', - last_accessed_at: '2024-10-14 18:12:08.013546+00', - metadata: { - eTag: '0d83e8fa5956c75dbd7bd40d8d4811de-1', - size: 275194, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:12:08.000Z', - contentLength: 275194, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', '2024-2025_Seasonal_Rainfall_Forecast_Malawi_11_Sep_2024_Final.pdf'], - version: 'fd5bed25-06af-46a3-a727-5fd81ac81eb2', - owner_id: '', - }, -]; - -const downscaled: IForecastStorageEntry[] = [ - { - id: 'a4ac39ea-f469-419d-8bd5-99e080e00bcb', - bucket_id: 'mw', - name: 'forecasts/downscaled/BALAKA.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.243079+00', - updated_at: '2024-10-14 18:11:23.243079+00', - last_accessed_at: '2024-10-14 18:11:23.243079+00', - metadata: { - eTag: '6872bb2af47f4ad30814378bec0fecf7-1', - size: 1863041, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1863041, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'BALAKA.pdf'], - version: '316f4917-c66d-4440-90eb-6512b73990b9', - owner_id: '', - }, - { - id: '380db05d-7dad-426f-9d17-7381eebce2e5', - bucket_id: 'mw', - name: 'forecasts/downscaled/BLANTYRE.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.655212+00', - updated_at: '2024-10-14 18:11:09.655212+00', - last_accessed_at: '2024-10-14 18:11:09.655212+00', - metadata: { - eTag: '9bad7616897d92df2f6ca2ecdd8f0543-1', - size: 2378940, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:10.000Z', - contentLength: 2378940, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'BLANTYRE.pdf'], - version: 'efdf185c-2917-47bb-82e7-b91034a74f7c', - owner_id: '', - }, - { - id: '3c2dcc8b-b8dd-4326-8637-539aae3c3f8d', - bucket_id: 'mw', - name: 'forecasts/downscaled/CHIKWAWA.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.682714+00', - updated_at: '2024-10-14 18:11:09.682714+00', - last_accessed_at: '2024-10-14 18:11:09.682714+00', - metadata: { - eTag: '01d83b1ea204c3df4b6a361bc88cf02f-1', - size: 2356724, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:10.000Z', - contentLength: 2356724, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'CHIKWAWA.pdf'], - version: '46546c7a-e737-4ad7-bdfa-17c06e8ac34c', - owner_id: '', - }, - { - id: '907f32a5-6840-478c-a0d1-6edc596fe258', - bucket_id: 'mw', - name: 'forecasts/downscaled/CHIRADZULU.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.207281+00', - updated_at: '2024-10-14 18:11:23.207281+00', - last_accessed_at: '2024-10-14 18:11:23.207281+00', - metadata: { - eTag: '99edd25c05ef95274232b16b9685e8b3-1', - size: 1864973, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1864973, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'CHIRADZULU.pdf'], - version: '6c672d04-2ffb-48a9-aadd-7b1e5c97c83a', - owner_id: '', - }, - { - id: '0eec3606-d263-4c7d-901c-b22bec133e68', - bucket_id: 'mw', - name: 'forecasts/downscaled/CHITIPA.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.83569+00', - updated_at: '2024-10-14 18:11:09.83569+00', - last_accessed_at: '2024-10-14 18:11:09.83569+00', - metadata: { - eTag: '3bf6ddca442ec9b56a43858581cf965c-1', - size: 2442692, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:10.000Z', - contentLength: 2442692, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'CHITIPA.pdf'], - version: '560b88ef-3ebb-4b65-8d83-3d24b9d5668d', - owner_id: '', - }, - { - id: '8532e10c-4cb9-4920-91bd-71e059a67c77', - bucket_id: 'mw', - name: 'forecasts/downscaled/DOWA.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.409888+00', - updated_at: '2024-10-14 18:11:09.409888+00', - last_accessed_at: '2024-10-14 18:11:09.409888+00', - metadata: { - eTag: '9eff6abe88c0dd86e177b981b6af2d06-1', - size: 2108958, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:09.000Z', - contentLength: 2108958, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'DOWA.pdf'], - version: '9b4fb2de-ead2-4114-8fd4-e24ef115d985', - owner_id: '', - }, - { - id: '87b69c91-da9c-4174-8525-3dd75289c987', - bucket_id: 'mw', - name: 'forecasts/downscaled/KASUNGU.pdf', - owner: '', - created_at: '2024-10-14 18:11:08.448048+00', - updated_at: '2024-10-14 18:11:08.448048+00', - last_accessed_at: '2024-10-14 18:11:08.448048+00', - metadata: { - eTag: '9880fe170457a43396a5801c4ab57bd0-1', - size: 1961333, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:08.000Z', - contentLength: 1961333, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'KASUNGU.pdf'], - version: '0f43084c-1c53-40e8-a3f0-3c8729dc7c30', - owner_id: '', - }, - { - id: '40fc3ecb-2ae5-40db-afff-14dfe94335e4', - bucket_id: 'mw', - name: 'forecasts/downscaled/KIRONGA.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.567199+00', - updated_at: '2024-10-14 18:11:09.567199+00', - last_accessed_at: '2024-10-14 18:11:09.567199+00', - metadata: { - eTag: '6ac1e00472e9174853aa95f5ba39ac92-1', - size: 2275092, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:10.000Z', - contentLength: 2275092, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'KIRONGA.pdf'], - version: 'a9d74118-f963-410d-a08f-234f95c4e754', - owner_id: '', - }, - { - id: '6fc83453-a84d-4768-814e-8bb01af4a17e', - bucket_id: 'mw', - name: 'forecasts/downscaled/LIKOMA.pdf', - owner: '', - created_at: '2024-10-14 18:11:31.980442+00', - updated_at: '2024-10-14 18:11:31.980442+00', - last_accessed_at: '2024-10-14 18:11:31.980442+00', - metadata: { - eTag: '7a06cef7f13cf8496a67a1cb2794bec1-1', - size: 1695687, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1695687, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'LIKOMA.pdf'], - version: '1fba580c-b316-4f1a-adef-432347c578ae', - owner_id: '', - }, - { - id: 'abf3c291-20f8-4582-a9ad-488ce509988d', - bucket_id: 'mw', - name: 'forecasts/downscaled/LILONGWE.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.145823+00', - updated_at: '2024-10-14 18:11:23.145823+00', - last_accessed_at: '2024-10-14 18:11:23.145823+00', - metadata: { - eTag: '84b259e978c634fb23d7cce0477e2699-1', - size: 1958258, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1958258, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'LILONGWE.pdf'], - version: '3bb260c8-c339-4f10-a722-b4f752a024cb', - owner_id: '', - }, - { - id: 'e0b89068-a34f-4f8d-9a5a-6acfc58e22de', - bucket_id: 'mw', - name: 'forecasts/downscaled/MACHINGA.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.79181+00', - updated_at: '2024-10-14 18:11:09.79181+00', - last_accessed_at: '2024-10-14 18:11:09.79181+00', - metadata: { - eTag: '727268c311a29af94d65243a7fad923f-1', - size: 2238135, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:10.000Z', - contentLength: 2238135, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'MACHINGA.pdf'], - version: '2bf16b4e-a0c1-4883-90d3-e971ceb80d5c', - owner_id: '', - }, - { - id: '1ed3458c-b1bd-4524-a0c1-ad52ae6fe8d0', - bucket_id: 'mw', - name: 'forecasts/downscaled/MANGOCHI.pdf', - owner: '', - created_at: '2024-10-14 18:11:22.692276+00', - updated_at: '2024-10-14 18:11:22.692276+00', - last_accessed_at: '2024-10-14 18:11:22.692276+00', - metadata: { - eTag: '4a570cfd555cce2b0f73f0b93e8aa6bd-1', - size: 1858943, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1858943, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'MANGOCHI.pdf'], - version: 'b0289bfb-e4a7-46f0-92d5-bbcbc446af20', - owner_id: '', - }, - { - id: '000f3fd4-c3b4-414e-a004-490b0175d134', - bucket_id: 'mw', - name: 'forecasts/downscaled/MCHINJI.pdf', - owner: '', - created_at: '2024-10-14 18:11:08.844687+00', - updated_at: '2024-10-14 18:11:08.844687+00', - last_accessed_at: '2024-10-14 18:11:08.844687+00', - metadata: { - eTag: '09af8a1097d4c6c79c89e449f64a8e32-1', - size: 2032156, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:09.000Z', - contentLength: 2032156, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'MCHINJI.pdf'], - version: '8cbc0a4e-0c59-4c81-9f0f-fedf6af514f3', - owner_id: '', - }, - { - id: '687dada2-e368-4035-9219-1a082980c5ed', - bucket_id: 'mw', - name: 'forecasts/downscaled/MULANJE.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.173087+00', - updated_at: '2024-10-14 18:11:23.173087+00', - last_accessed_at: '2024-10-14 18:11:23.173087+00', - metadata: { - eTag: '05f87a52b99ebf8f665de379a5ea50f9-1', - size: 1857501, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1857501, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'MULANJE.pdf'], - version: '0add9aa3-990c-4343-840a-4fca6f65f18f', - owner_id: '', - }, - { - id: 'aa8c69f8-8ed9-46ac-958c-e15b125e9c8e', - bucket_id: 'mw', - name: 'forecasts/downscaled/MWANZA.pdf', - owner: '', - created_at: '2024-10-14 18:11:32.48908+00', - updated_at: '2024-10-14 18:11:32.48908+00', - last_accessed_at: '2024-10-14 18:11:32.48908+00', - metadata: { - eTag: '0f1cd3857e26dcafb47eb101928bd712-1', - size: 1779096, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1779096, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'MWANZA.pdf'], - version: '5e3f5ba4-0d53-40ce-a944-0a0af20d37ce', - owner_id: '', - }, - { - id: '244b069d-d2c5-4e3d-8ceb-3cda1c7957c8', - bucket_id: 'mw', - name: 'forecasts/downscaled/MZIMBA.pdf', - owner: '', - created_at: '2024-10-14 18:11:09.259207+00', - updated_at: '2024-10-14 18:11:09.259207+00', - last_accessed_at: '2024-10-14 18:11:09.259207+00', - metadata: { - eTag: 'fe53a38cf77039745c7d16484a9d7bc7-1', - size: 2040559, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:09.000Z', - contentLength: 2040559, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'MZIMBA.pdf'], - version: '948ed2d8-ddde-4181-8b48-16a1e855b72c', - owner_id: '', - }, - { - id: '9bf1bf53-3b44-435a-b949-c3ac2576e33d', - bucket_id: 'mw', - name: 'forecasts/downscaled/NENO.pdf', - owner: '', - created_at: '2024-10-14 18:11:22.877689+00', - updated_at: '2024-10-14 18:11:22.877689+00', - last_accessed_at: '2024-10-14 18:11:22.877689+00', - metadata: { - eTag: '832902e386ebf3059f57320deb09a835-1', - size: 1839791, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1839791, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'NENO.pdf'], - version: 'e6866c48-034c-4294-9ae6-5d2ecfb625e2', - owner_id: '', - }, - { - id: '39bb7f23-7dee-46e4-b051-e9c37bd4c8a2', - bucket_id: 'mw', - name: 'forecasts/downscaled/NKHATA BAY.pdf', - owner: '', - created_at: '2024-10-14 18:11:32.547321+00', - updated_at: '2024-10-14 18:11:32.547321+00', - last_accessed_at: '2024-10-14 18:11:32.547321+00', - metadata: { - eTag: 'fdb3b1c0e1534b0872ccfcf16cc830f4-1', - size: 1821167, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1821167, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'NKHATA BAY.pdf'], - version: 'b2f2a13c-ea55-43fa-9985-fd0ec18db9e7', - owner_id: '', - }, - { - id: '9352fabe-0586-48ef-9cd8-f2dac5ac9894', - bucket_id: 'mw', - name: 'forecasts/downscaled/NKHOTAKOTA.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.214239+00', - updated_at: '2024-10-14 18:11:23.214239+00', - last_accessed_at: '2024-10-14 18:11:23.214239+00', - metadata: { - eTag: '381f8dab5a196f532bdf8cafbafeada0-1', - size: 1959219, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1959219, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'NKHOTAKOTA.pdf'], - version: 'ac2ce35d-81f8-44c0-bc1c-262d1cebf316', - owner_id: '', - }, - { - id: 'e081519b-19f0-4e59-8f86-474670d6028f', - bucket_id: 'mw', - name: 'forecasts/downscaled/NSANJE.pdf', - owner: '', - created_at: '2024-10-14 18:11:32.403485+00', - updated_at: '2024-10-14 18:11:32.403485+00', - last_accessed_at: '2024-10-14 18:11:32.403485+00', - metadata: { - eTag: 'cc0c71d932a93d9919df182b09f5e652-1', - size: 1735406, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1735406, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'NSANJE.pdf'], - version: 'db731f5c-ef5d-4737-a976-c0372b89e048', - owner_id: '', - }, - { - id: '763869da-ffa1-467f-b8fe-0373710ca2df', - bucket_id: 'mw', - name: 'forecasts/downscaled/NTCHEU.pdf', - owner: '', - created_at: '2024-10-14 18:11:32.389443+00', - updated_at: '2024-10-14 18:11:32.389443+00', - last_accessed_at: '2024-10-14 18:11:32.389443+00', - metadata: { - eTag: 'c755a0fb3973faac4fec7cd4094f31cd-1', - size: 1737538, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1737538, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'NTCHEU.pdf'], - version: '0521ab98-644f-4712-a5e7-8c01a4f2d0ad', - owner_id: '', - }, - { - id: '3f0929de-b75e-4731-bf3f-da4f0d0ad825', - bucket_id: 'mw', - name: 'forecasts/downscaled/NTCHISI.pdf', - owner: '', - created_at: '2024-10-14 18:11:08.748628+00', - updated_at: '2024-10-14 18:11:08.748628+00', - last_accessed_at: '2024-10-14 18:11:08.748628+00', - metadata: { - eTag: '892b25032f774d845479a51a661dbd1b-1', - size: 1977360, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:09.000Z', - contentLength: 1977360, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'NTCHISI.pdf'], - version: 'fe6cbb05-3030-49aa-9d34-19f68b3c821f', - owner_id: '', - }, - { - id: 'c3aa2653-ac80-49f1-a899-b50c72ad4898', - bucket_id: 'mw', - name: 'forecasts/downscaled/PHALOMBE.pdf', - owner: '', - created_at: '2024-10-14 18:11:22.773196+00', - updated_at: '2024-10-14 18:11:22.773196+00', - last_accessed_at: '2024-10-14 18:11:22.773196+00', - metadata: { - eTag: 'e0ca6cd4cce5c51ed085ffdc512825eb-1', - size: 1862285, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1862285, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'PHALOMBE.pdf'], - version: 'fdbaa294-75f3-4ef4-a459-ac10d058e264', - owner_id: '', - }, - { - id: '64733f68-d958-4dd6-9a04-5dac5ce7fd2a', - bucket_id: 'mw', - name: 'forecasts/downscaled/RUMPHI.pdf', - owner: '', - created_at: '2024-10-14 18:11:32.507389+00', - updated_at: '2024-10-14 18:11:32.507389+00', - last_accessed_at: '2024-10-14 18:11:32.507389+00', - metadata: { - eTag: 'b16d1bf6376058b06d8955568de1209c-1', - size: 1743826, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1743826, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'RUMPHI.pdf'], - version: 'b38f0b9b-9b55-4466-bcb0-ef040cc69711', - owner_id: '', - }, - { - id: '1c204f75-5d7d-421f-830d-45261b82565a', - bucket_id: 'mw', - name: 'forecasts/downscaled/SALIMA.pdf', - owner: '', - created_at: '2024-10-14 18:11:31.637577+00', - updated_at: '2024-10-14 18:11:31.637577+00', - last_accessed_at: '2024-10-14 18:11:31.637577+00', - metadata: { - eTag: '0afb9450687df6a3222a732aab4c8aed-1', - size: 1556076, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:32.000Z', - contentLength: 1556076, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'SALIMA.pdf'], - version: 'b96c6966-a3d4-46e7-bd8e-e0b91655b5a9', - owner_id: '', - }, - { - id: '24f32ab0-20dd-4020-aa72-abf2ab79ef0a', - bucket_id: 'mw', - name: 'forecasts/downscaled/THYOLO.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.494319+00', - updated_at: '2024-10-14 18:11:23.494319+00', - last_accessed_at: '2024-10-14 18:11:23.494319+00', - metadata: { - eTag: '0c484044c1b73e1de5537946deea96d3-1', - size: 1918738, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1918738, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'THYOLO.pdf'], - version: '4b199129-73dc-4b67-bc46-f65c2148b915', - owner_id: '', - }, - { - id: '9274a223-3568-434f-91ea-40fd0e30084b', - bucket_id: 'mw', - name: 'forecasts/downscaled/ZOMBA.pdf', - owner: '', - created_at: '2024-10-14 18:11:23.13625+00', - updated_at: '2024-10-14 18:11:23.13625+00', - last_accessed_at: '2024-10-14 18:11:23.13625+00', - metadata: { - eTag: 'd356df2ec0e697a474cdcc3f4a4190b5-1', - size: 1916377, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:11:23.000Z', - contentLength: 1916377, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'ZOMBA.pdf'], - version: '36791e5c-1cd2-4e88-bd42-da411cb5cd41', - owner_id: '', - }, -]; - -export default { seasonal, downscaled }; diff --git a/libs/data/resources/forecasts/zm.ts b/libs/data/resources/forecasts/zm.ts deleted file mode 100644 index 68f9dd197..000000000 --- a/libs/data/resources/forecasts/zm.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { IForecastStorageEntry } from './types'; - -const seasonal: IForecastStorageEntry[] = [ - { - id: 'c139d571-723c-4013-8246-28b0a291becf', - bucket_id: 'zm', - name: 'forecasts/ZMD Seasonal forecast 2024-25.pdf', - owner: '', - created_at: '2024-10-14 18:12:29.879524+00', - updated_at: '2024-10-14 18:12:29.879524+00', - last_accessed_at: '2024-10-14 18:12:29.879524+00', - metadata: { - eTag: 'cc62ececec1d335da2fe7230c90f1a1e-1', - size: 2111455, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-14T18:12:30.000Z', - contentLength: 2111455, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'ZMD Seasonal forecast 2024-25.pdf'], - version: 'f5342a2a-55fb-48be-acd3-b2b82a581c5c', - owner_id: '', - }, -]; - -export const downscaled: IForecastStorageEntry[] = [ - { - id: '8067b33b-dca9-47cc-9296-fb42b0ec5f54', - bucket_id: 'zm', - name: 'forecasts/downscaled/CINYANJA SEASONAL RAINFALL FORECAST YA CHIPATA DISTRICT 2024.pdf', - owner: '', - created_at: '2024-10-25 09:59:27.62489+00', - updated_at: '2024-10-25 09:59:27.62489+00', - last_accessed_at: '2024-10-25 09:59:27.62489+00', - metadata: { - eTag: '73ebdbac756a8eb4e75cb3b2dea34a33-1', - size: 556821, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-25T09:59:28.000Z', - contentLength: 556821, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'CINYANJA SEASONAL RAINFALL FORECAST YA CHIPATA DISTRICT 2024.pdf'], - version: 'f66a3d8a-dee8-43f6-8715-4c3d5e2aba51', - owner_id: '', - }, - { - id: '23938706-cea7-4c9e-b199-961d17b4be9a', - bucket_id: 'zm', - name: 'forecasts/downscaled/CINYANJA SEASONAL RAINFALL FORECAST YA PETAUKE DISTRICT 2024.pdf', - owner: '', - created_at: '2024-10-25 09:59:30.722051+00', - updated_at: '2024-10-25 09:59:30.722051+00', - last_accessed_at: '2024-10-25 09:59:30.722051+00', - metadata: { - eTag: 'b8a95f80f88b3083193fd1de1d2c3dfb-1', - size: 565672, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-25T09:59:31.000Z', - contentLength: 565672, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'CINYANJA SEASONAL RAINFALL FORECAST YA PETAUKE DISTRICT 2024.pdf'], - version: '9a29fb0c-75b1-4612-a506-2508b2aab0ed', - owner_id: '', - }, - { - id: '37b86bd1-f8a1-4709-8fd2-d2e6b8dc7294', - bucket_id: 'zm', - name: 'forecasts/downscaled/SEASONAL RAINFALL FORECAST FOR CHIPATA DISTRICT 2024.pdf', - owner: '', - created_at: '2024-10-25 09:59:15.267263+00', - updated_at: '2024-10-25 09:59:15.267263+00', - last_accessed_at: '2024-10-25 09:59:15.267263+00', - metadata: { - eTag: '37d023ca77636f9baeb62ff425328553-1', - size: 250740, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-25T09:59:15.000Z', - contentLength: 250740, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'SEASONAL RAINFALL FORECAST FOR CHIPATA DISTRICT 2024.pdf'], - version: '7366cdd9-1749-4e99-a774-3ffea0da08b6', - owner_id: '', - }, - { - id: '9f4fd23f-d1c8-474f-aacc-f15d5aec4da9', - bucket_id: 'zm', - name: 'forecasts/downscaled/SEASONAL RAINFALL FORECAST FOR PETAUKE DISTRICT 2024.pdf', - owner: '', - created_at: '2024-10-25 09:59:17.786206+00', - updated_at: '2024-10-25 09:59:17.786206+00', - last_accessed_at: '2024-10-25 09:59:17.786206+00', - metadata: { - eTag: '3778409294e650524ee43a948f1feafe-1', - size: 260681, - mimetype: 'application/pdf', - cacheControl: 'max-age=3600', - lastModified: '2024-10-25T09:59:18.000Z', - contentLength: 260681, - httpStatusCode: 200, - }, - path_tokens: ['forecasts', 'downscaled', 'SEASONAL RAINFALL FORECAST FOR PETAUKE DISTRICT 2024.pdf'], - version: 'ec0d18d2-7e80-4670-925e-e4ddda49ea24', - owner_id: '', - }, -]; - -export default { seasonal, downscaled }; diff --git a/libs/shared/src/services/core/db_v2/db.types.ts b/libs/shared/src/services/core/db_v2/db.types.ts index 63e15b61f..fc7dae539 100644 --- a/libs/shared/src/services/core/db_v2/db.types.ts +++ b/libs/shared/src/services/core/db_v2/db.types.ts @@ -5,7 +5,7 @@ const DB_COLLECTION_NAMES = [ 'attachments', 'budget_cards', - 'climate_forecasts', + 'forecasts', 'monitoring_tool_forms', 'monitoring_tool_submissions', 'options_tool', From dfc096d4f2127bf1b99a0b057547b457cdeaabd5 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 09:49:31 -0800 Subject: [PATCH 32/44] chore: code tidying --- .../extension-app/src/app/components/layout.html | 2 +- .../extension-app/src/app/routes/tool-routes.ts | 2 +- .../{climate-forecast-db.ts => forecast-db.ts} | 0 ...mate-forecast-storage.ts => forecast-storage.ts} | 2 +- .../supabase/functions/dashboard/index.ts | 8 ++++---- ....sql => 20250127193000_forecast_update_cron.sql} | 13 ++++--------- 6 files changed, 11 insertions(+), 16 deletions(-) rename apps/picsa-server/supabase/functions/dashboard/{climate-forecast-db.ts => forecast-db.ts} (100%) rename apps/picsa-server/supabase/functions/dashboard/{climate-forecast-storage.ts => forecast-storage.ts} (98%) rename apps/picsa-server/supabase/migrations/{20250127193000_forecast_update_cron copy.sql => 20250127193000_forecast_update_cron.sql} (74%) diff --git a/apps/picsa-apps/extension-app/src/app/components/layout.html b/apps/picsa-apps/extension-app/src/app/components/layout.html index 2ce6be47c..7d36918d5 100644 --- a/apps/picsa-apps/extension-app/src/app/components/layout.html +++ b/apps/picsa-apps/extension-app/src/app/components/layout.html @@ -20,7 +20,7 @@
} - +
cloud {{ 'Forecasts' | translate}} diff --git a/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts b/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts index a7c8e5c7f..cbc62b644 100644 --- a/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts +++ b/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts @@ -17,7 +17,7 @@ export const TOOL_ROUTES: Routes = [ import('@picsa/crop-probability/src/app/app.module-embedded').then((mod) => mod.CropProbabilityToolModule), }, { - path: 'forecast', + path: 'forecasts', loadComponent: () => import('@picsa/forecasts/pages/forecast/forecast.page').then((mod) => mod.ForecastComponent), }, { diff --git a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts b/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts similarity index 100% rename from apps/picsa-server/supabase/functions/dashboard/climate-forecast-db.ts rename to apps/picsa-server/supabase/functions/dashboard/forecast-db.ts diff --git a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts b/apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts similarity index 98% rename from apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts rename to apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts index 4583bd6ff..187b24341 100644 --- a/apps/picsa-server/supabase/functions/dashboard/climate-forecast-storage.ts +++ b/apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts @@ -1,7 +1,7 @@ import { getClient } from '../_shared/client.ts'; import { getJsonData } from '../_shared/request.ts'; import { JSONResponse } from '../_shared/response.ts'; -import { apiClient } from './climate-forecast-db.ts'; +import { apiClient } from './forecast-db.ts'; import { IDBClimateForecastRow } from './types.ts'; interface IReqParams { diff --git a/apps/picsa-server/supabase/functions/dashboard/index.ts b/apps/picsa-server/supabase/functions/dashboard/index.ts index d8e850da3..eb337ca27 100644 --- a/apps/picsa-server/supabase/functions/dashboard/index.ts +++ b/apps/picsa-server/supabase/functions/dashboard/index.ts @@ -3,8 +3,8 @@ // This enables autocomplete, go to definition, etc. import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; -import { forecastStorage } from './climate-forecast-storage.ts'; -import { forecastDB } from './climate-forecast-db.ts'; +import { forecastStorage } from './forecast-storage.ts'; +import { forecastDB } from './forecast-db.ts'; import { corsHeaders } from '../_shared/cors.ts'; serve((req) => { @@ -19,9 +19,9 @@ serve((req) => { const endpoint = req.url.split('/').pop(); switch (endpoint) { - case 'climate-forecast-db': + case 'forecast-db': return forecastDB(req); - case 'climate-forecast-storage': + case 'forecast-storage': return forecastStorage(req); default: diff --git a/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql b/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron.sql similarity index 74% rename from apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql rename to apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron.sql index 22ecbaff4..1d8350ff9 100644 --- a/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron copy.sql +++ b/apps/picsa-server/supabase/migrations/20250127193000_forecast_update_cron.sql @@ -1,15 +1,13 @@ --- enable pg_cron extension create extension if not exists pg_cron with schema pg_catalog; - grant usage on schema cron to postgres; grant all privileges on all tables in schema cron to postgres; -- Trigger backend edge function every 30 minutes -- Adapted from https://supabase.com/docs/guides/functions/schedule-functions -select cron.schedule('forecasts_db', '30 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-db','{}'::jsonb); $$); +select cron.schedule('forecasts_db', '30 * * * *', $$ select public.call_edge_function('dashboard/forecast-db','{}'::jsonb); $$); -select cron.schedule('forecasts_storage', '35 * * * *', $$ select public.call_edge_function('dashboard/climate-forecast-storage','{}'::jsonb); $$); +select cron.schedule('forecasts_storage', '35 * * * *', $$ select public.call_edge_function('dashboard/forecast-storage','{}'::jsonb); $$); -- Alt implementation (intermediate function created to structure more complex requests, kept for future reference) @@ -27,12 +25,9 @@ select cron.schedule('forecasts_storage', '35 * * * *', $$ select public.call_ed -- begin -- foreach country_code in array country_codes loop -- body = format('{"country_code": "%s"}',country_code)::jsonb; --- select (public.call_edge_function('dashboard/climate-forecast-update',body)) into request_id; +-- select (public.call_edge_function('dashboard/forecast-update',body)) into request_id; -- request_ids = request_ids || request_id; -- end loop; -- return 'request_ids'; --- end $$; - - - ^ +-- end $$; ^ From 3c8cdb4a714c8e38bdb1eeb71b2268a2265506f9 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 09:54:22 -0800 Subject: [PATCH 33/44] chore: remove legacy forecast resources --- libs/data/resources/forecasts/index.ts | 81 -------------------------- libs/data/resources/forecasts/types.ts | 6 -- 2 files changed, 87 deletions(-) delete mode 100644 libs/data/resources/forecasts/index.ts delete mode 100644 libs/data/resources/forecasts/types.ts diff --git a/libs/data/resources/forecasts/index.ts b/libs/data/resources/forecasts/index.ts deleted file mode 100644 index 4ca34a874..000000000 --- a/libs/data/resources/forecasts/index.ts +++ /dev/null @@ -1,81 +0,0 @@ -import zm from './zm'; - -import mw from './mw'; - -import { IForecasts, IForecastStorageEntry } from './types'; -import { marker as translateMarker } from '@biesbjerg/ngx-translate-extract-marker'; -import { COUNTRIES_DATA_HASHMAP, ICountryCode } from '@picsa/data/deployments'; -import type { IResourceCollection, IResourceFile } from '@picsa/resources/src/app/schemas'; - -const CLIMATE_FORECASTS: { [country_code in ICountryCode]?: IForecasts } = { - zm, - mw, -}; - -/*********************************************************************************** - * Legacy - Resource Formats - * Used to (temporarily) display all forecasts within resource collection - ***********************************************************************************/ -const forecasts: IResourceCollection = { - id: 'forecasts', - title: translateMarker('Forecasts'), - childResources: { collections: ['forecasts_downscaled'], files: [], links: [] }, - type: 'collection', -}; -const forecasts_downscaled: IResourceCollection = { - id: 'forecasts_downscaled', - title: translateMarker('Downscaled Forecasts'), - childResources: { collections: [], files: [], links: [] }, - type: 'collection', - parentCollection: 'forecasts', - cover: { image: 'assets/resources/covers/downscaled-forecast.svg' }, -}; - -const files: Record = {}; - -for (const [country_code, { downscaled, seasonal }] of Object.entries(CLIMATE_FORECASTS)) { - // Add seasonal to main collection - for (const forecast of seasonal) { - const resource = hackGenerateLegacyResources(country_code as ICountryCode, forecast); - resource.title = translateMarker('Seasonal Forecast'); - resource.cover = { image: 'assets/resources/covers/seasonal-forecast.svg' }; - resource.description = `${COUNTRIES_DATA_HASHMAP[country_code].label} 2024-25`; - files[resource.id] = resource; - forecasts.childResources.files.push(resource.id); - } - // Add downscaled to collection - for (const forecast of downscaled) { - const resource = hackGenerateLegacyResources(country_code as ICountryCode, forecast); - files[resource.id] = resource; - forecasts_downscaled.childResources.files.push(resource.id); - } -} - -function hackGenerateLegacyResources(country_code: ICountryCode, forecast: IForecastStorageEntry): IResourceFile { - const { bucket_id, id, metadata, name, path_tokens, version } = forecast; - const { size } = metadata as any; - const filename = (path_tokens as string[]).pop() as string; - // HACK - assume all forecasts stored on production server - const url = `https://wpctacqpzxfzlucblowh.supabase.co/storage/v1/object/public/${bucket_id}/${name}`; - const entry: IResourceFile = { - filename, - id: id as string, - md5Checksum: version as string, - mimetype: 'application/pdf', - size_kb: size / 1000, - subtype: 'pdf', - title: filename.replace('.pdf', ''), - type: 'file', - url, - description: '', - filter: { countries: [country_code] }, - }; - return entry; -} - -export const FORECAST_FILES = files; - -export const FORECAST_COLLECTIONS = { - forecasts, - forecasts_downscaled, -}; diff --git a/libs/data/resources/forecasts/types.ts b/libs/data/resources/forecasts/types.ts deleted file mode 100644 index 6c26af8e3..000000000 --- a/libs/data/resources/forecasts/types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { Database } from '@picsa/server-types'; - -// TODO - use general storage entry -export type IForecastStorageEntry = Database['public']['Views']['storage_objects']['Row']; - -export type IForecasts = { seasonal: IForecastStorageEntry[]; downscaled: IForecastStorageEntry[] }; From e52567a39f2bc9184ce4984e9f697604f2dcf859 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 13:13:24 -0800 Subject: [PATCH 34/44] feat: backend function types --- .../pages/forecast/forecast.component.ts | 42 +- apps/picsa-server/project.json | 2 +- .../supabase/functions/_shared/response.ts | 20 +- .../functions/dashboard/forecast-db.ts | 28 +- .../supabase/functions/dashboard/types.ts | 8 +- ...ql => 20250115161100_forecasts_update.sql} | 2 +- apps/picsa-server/supabase/types/db.types.ts | 1006 +++++++++++++++++ .../supabase/types/functions.types.ts | 8 + apps/picsa-server/supabase/types/index.ts | 979 +--------------- 9 files changed, 1087 insertions(+), 1008 deletions(-) rename apps/picsa-server/supabase/migrations/{20250115161100_climate_forecasts_update.sql => 20250115161100_forecasts_update.sql} (96%) create mode 100644 apps/picsa-server/supabase/types/db.types.ts create mode 100644 apps/picsa-server/supabase/types/functions.types.ts diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts index 2f19b5f90..8fba1bc93 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts @@ -2,9 +2,11 @@ import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, computed, effect, signal } from '@angular/core'; import { RouterModule } from '@angular/router'; import { RefreshSpinnerComponent } from '@picsa/components'; +import { FunctionResponses } from '@picsa/server-types'; import { IDataTableOptions, PicsaDataTableComponent } from '@picsa/shared/features'; import { PicsaNotificationService } from '@picsa/shared/services/core/notification.service'; import { SupabaseService } from '@picsa/shared/services/core/supabase'; +import { FunctionsHttpError } from '@supabase/supabase-js'; import { DashboardMaterialModule } from '../../../../material.module'; import { DeploymentDashboardService } from '../../../deployment/deployment.service'; @@ -16,6 +18,8 @@ interface IForecastTableRow extends IForecastRow { file_name: string; } +type IForecastDBAPIResponse = { data: FunctionResponses['Dashboard']['forecast-db']; error?: any }; + const DISPLAY_COLUMNS: (keyof IForecastTableRow)[] = [ 'country_code', 'forecast_type', @@ -116,29 +120,31 @@ export class ClimateForecastPageComponent { /** Invoke backend function that fetches forecasts from climate api and updates db */ private async refreshAPIData() { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { country_code } = this.deploymentService.activeDeployment()!; - const formData = new FormData(); - formData.append('country_code', country_code); - formData.append('query_prefix', this.apiQueryPrefix()); - const { data, error } = await this.supabase.functions - .invoke('dashboard/climate-forecast-db', { - method: 'POST', - body: formData, - }) - .catch((error) => ({ data: [], error })); - if (error) { - console.error(error); + const country_code = this.countryCode() as string; + const query_prefix = this.apiQueryPrefix(); + + const { data, error } = await this.supabase.functions.invoke('dashboard/forecast-db', { + method: 'POST', + body: { country_code, query_prefix }, + }); + + // Errors thrown from functions in JS client need to wait for message + // https://github.com/supabase/functions-js/issues/45 + if (error && error instanceof FunctionsHttpError) { + const errorMessage = await error.context.json(); + console.error('refreshAPIData', JSON.parse(errorMessage)); this.notificationService.showErrorNotification('Forecast Update Failed. See console logs for details'); return []; } - if (data.length > 0) { - this.forecastData.update((v) => ([] as IForecastTableRow[]).concat(this.toTableData(data), v)); - } - console.log('[Api Data Updated]', data); - return data; + const forecasts = data?.[country_code] || []; + + this.forecastData.update((v) => ([] as IForecastTableRow[]).concat(this.toTableData(forecasts), v)); + console.log('[Api Data Updated]', { country_code, data, forecasts }); + + return forecasts; } - private toTableData(data: IForecastRow[]): IForecastTableRow[] { + private toTableData(data: IForecastRow[] = []): IForecastTableRow[] { return data .map((el) => { // compute file_name column from storage file path diff --git a/apps/picsa-server/project.json b/apps/picsa-server/project.json index 3ef36ecf7..a96cb9e7f 100644 --- a/apps/picsa-server/project.json +++ b/apps/picsa-server/project.json @@ -46,7 +46,7 @@ "dependsOn": [], "outputs": [], "options": { - "commands": ["npx supabase gen types typescript --local > supabase/types/index.ts"], + "commands": ["npx supabase gen types typescript --local > supabase/types/db.types.ts"], "cwd": "apps/picsa-server" } }, diff --git a/apps/picsa-server/supabase/functions/_shared/response.ts b/apps/picsa-server/supabase/functions/_shared/response.ts index bb2bcff4c..29d74e307 100644 --- a/apps/picsa-server/supabase/functions/_shared/response.ts +++ b/apps/picsa-server/supabase/functions/_shared/response.ts @@ -1,7 +1,23 @@ import { corsHeaders } from './cors.ts'; -export function ErrorResponse(msg: string, status = 400) { - return new Response(JSON.stringify({ msg }), { +/** + * Return an erorr response + * + * Note - if reading from js-client need to await error context body for message + * https://github.com/supabase/functions-js/issues/45 + * + * @example + * ```ts + * const {dat, error} = await invokeFunction(...) + * if (error && error instanceof FunctionsHttpError) { + * const errorMessage = await error.context.json(); + * const errorJson = JSON.parse(errorMessage) + * console.error(errorJson) + * } + * ``` + */ +export function ErrorResponse(msg: any, status = 400) { + return new Response(JSON.stringify(msg), { status, headers: { ...corsHeaders, 'Content-Type': 'application/json' }, }); diff --git a/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts b/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts index 59ccff78f..38691bc59 100644 --- a/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts +++ b/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts @@ -1,8 +1,14 @@ import { getClient } from '../_shared/client.ts'; import { getJsonData } from '../_shared/request.ts'; +import { ErrorResponse } from '../_shared/response.ts'; import { JSONResponse } from '../_shared/response.ts'; -import type { climateApiPaths, IApiClimateForecast, IDBClimateForecastInsert } from './types.ts'; +import type { + climateApiPaths, + IApiClimateForecast, + IDBClimateForecastInsert, + IForecastDBAPIResponse, +} from './types.ts'; /** * Read the endpoint from env. Note, if running climate api in local docker container update `.env` to: @@ -12,7 +18,7 @@ import type { climateApiPaths, IApiClimateForecast, IDBClimateForecastInsert } f * https://github.com/orgs/supabase/discussions/9837 */ export const CLIMATE_API_ENDPOINT = Deno.env.get('CLIMATE_API_ENDPOINT') || 'https://api.epicsa.idems.international'; -export const COUNTRY_CODES = ['mw', 'zm']; +export const ALL_COUNTRY_CODES = ['mw', 'zm']; // Create typed fetch client from open-api definition exported by climate api import createClient from 'openapi-fetch'; @@ -22,26 +28,32 @@ export const apiClient = createClient({ baseUrl: CLIMATE_API_EN * Update cliamte forecast db rows */ export const forecastDB = async (req: Request) => { - // Validate body formData // TODO - Improve validators and feedback - let { country_codes = COUNTRY_CODES, query_prefix } = await getJsonData(req); + let { country_code, query_prefix } = await getJsonData(req); + + // Retrieve single country if specified, default all + const country_codes = country_code ? [country_code] : ALL_COUNTRY_CODES; // Default query for documents stored in the current month, if (!query_prefix) { query_prefix = new Date().toISOString().replace(/-/, '').substring(0, 6); } - const responses = []; + const response: IForecastDBAPIResponse = {}; + const errors = []; for (const country_code of country_codes) { try { const data = await getCountryUpdates(country_code, query_prefix); - responses.push({ country_code, data }); + response[country_code] = data; } catch (error) { - responses.push({ country_code, error }); + errors.push(error); } } - return JSONResponse(responses); + if (errors.length > 0) { + return ErrorResponse(errors); + } + return JSONResponse(response); }; async function getCountryUpdates(country_code: string, query_prefix: string) { diff --git a/apps/picsa-server/supabase/functions/dashboard/types.ts b/apps/picsa-server/supabase/functions/dashboard/types.ts index 133b56d69..860d41c0c 100644 --- a/apps/picsa-server/supabase/functions/dashboard/types.ts +++ b/apps/picsa-server/supabase/functions/dashboard/types.ts @@ -1,4 +1,4 @@ -import type { Database } from '../../types/index.ts'; +import type { Database } from '../../types/db.types.ts'; import type { paths, components } from '../../../../picsa-apps/dashboard/src/app/modules/climate/types/api.d.ts'; export type climateApiPaths = paths; @@ -8,3 +8,9 @@ export type IDBClimateForecastRow = Database['public']['Tables']['forecasts']['R export type IDBClimateForecastInsert = Database['public']['Tables']['forecasts']['Insert']; export type IApiClimateForecast = climateApiComponents['schemas']['DocumentMetadata']; + +/********* Api Responses ************/ + +export type IForecastDBAPIResponse = { + [country_code: string]: IDBClimateForecastInsert[]; +}; diff --git a/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql b/apps/picsa-server/supabase/migrations/20250115161100_forecasts_update.sql similarity index 96% rename from apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql rename to apps/picsa-server/supabase/migrations/20250115161100_forecasts_update.sql index 17ce57358..86b2cfe27 100644 --- a/apps/picsa-server/supabase/migrations/20250115161100_climate_forecasts_update.sql +++ b/apps/picsa-server/supabase/migrations/20250115161100_forecasts_update.sql @@ -1,5 +1,5 @@ -- recreate table and data -drop table if exists public.forecasts; +drop table if exists public.climate_forecasts; -- -- Custom types create type public.forecast_type as enum ('daily','seasonal','downscaled'); diff --git a/apps/picsa-server/supabase/types/db.types.ts b/apps/picsa-server/supabase/types/db.types.ts new file mode 100644 index 000000000..0afaec5d1 --- /dev/null +++ b/apps/picsa-server/supabase/types/db.types.ts @@ -0,0 +1,1006 @@ +export type Json = string | number | boolean | null | { [key: string]: Json | undefined } | Json[]; + +export type Database = { + graphql_public: { + Tables: { + [_ in never]: never; + }; + Views: { + [_ in never]: never; + }; + Functions: { + graphql: { + Args: { + operationName?: string; + query?: string; + variables?: Json; + extensions?: Json; + }; + Returns: Json; + }; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; + public: { + Tables: { + climate_forecasts: { + Row: { + country_code: string | null; + date_modified: string; + district: string | null; + filename: string; + id: string; + language_code: string | null; + storage_file: string | null; + type: string | null; + }; + Insert: { + country_code?: string | null; + date_modified: string; + district?: string | null; + filename: string; + id: string; + language_code?: string | null; + storage_file?: string | null; + type?: string | null; + }; + Update: { + country_code?: string | null; + date_modified?: string; + district?: string | null; + filename?: string; + id?: string; + language_code?: string | null; + storage_file?: string | null; + type?: string | null; + }; + Relationships: [ + { + foreignKeyName: 'climate_forecasts_storage_file_fkey'; + columns: ['storage_file']; + isOneToOne: false; + referencedRelation: 'storage_objects'; + referencedColumns: ['id']; + } + ]; + }; + climate_stations: { + Row: { + country_code: string; + district: string | null; + elevation: number | null; + id: string | null; + latitude: number | null; + longitude: number | null; + station_id: string; + station_name: string | null; + }; + Insert: { + country_code: string; + district?: string | null; + elevation?: number | null; + id?: string | null; + latitude?: number | null; + longitude?: number | null; + station_id: string; + station_name?: string | null; + }; + Update: { + country_code?: string; + district?: string | null; + elevation?: number | null; + id?: string | null; + latitude?: number | null; + longitude?: number | null; + station_id?: string; + station_name?: string | null; + }; + Relationships: []; + }; + climate_summary_rainfall: { + Row: { + country_code: Database['public']['Enums']['country_code']; + created_at: string; + data: Json[]; + metadata: Json; + station_id: string; + updated_at: string; + }; + Insert: { + country_code: Database['public']['Enums']['country_code']; + created_at?: string; + data: Json[]; + metadata: Json; + station_id: string; + updated_at?: string; + }; + Update: { + country_code?: Database['public']['Enums']['country_code']; + created_at?: string; + data?: Json[]; + metadata?: Json; + station_id?: string; + updated_at?: string; + }; + Relationships: [ + { + foreignKeyName: 'climate_summary_rainfall_station_id_fkey'; + columns: ['station_id']; + isOneToOne: false; + referencedRelation: 'climate_stations'; + referencedColumns: ['id']; + } + ]; + }; + crop_data: { + Row: { + created_at: string; + crop: string; + id: string | null; + label: string | null; + variety: string; + }; + Insert: { + created_at?: string; + crop: string; + id?: string | null; + label?: string | null; + variety: string; + }; + Update: { + created_at?: string; + crop?: string; + id?: string | null; + label?: string | null; + variety?: string; + }; + Relationships: []; + }; + crop_station_data: { + Row: { + created_at: string; + crop_id: string; + days_lower: number; + days_upper: number; + probabilities: number[] | null; + station_id: string; + water_lower: number; + water_upper: number; + }; + Insert: { + created_at?: string; + crop_id: string; + days_lower: number; + days_upper: number; + probabilities?: number[] | null; + station_id: string; + water_lower: number; + water_upper: number; + }; + Update: { + created_at?: string; + crop_id?: string; + days_lower?: number; + days_upper?: number; + probabilities?: number[] | null; + station_id?: string; + water_lower?: number; + water_upper?: number; + }; + Relationships: [ + { + foreignKeyName: 'public_crop_station_data_crop_id_fkey'; + columns: ['crop_id']; + isOneToOne: false; + referencedRelation: 'crop_data'; + referencedColumns: ['id']; + }, + { + foreignKeyName: 'public_crop_station_data_station_id_fkey'; + columns: ['station_id']; + isOneToOne: false; + referencedRelation: 'climate_stations'; + referencedColumns: ['id']; + } + ]; + }; + deployments: { + Row: { + access_key_md5: string | null; + configuration: Json; + country_code: string; + icon_path: string | null; + id: string; + label: string; + public: boolean; + variant: string | null; + }; + Insert: { + access_key_md5?: string | null; + configuration?: Json; + country_code: string; + icon_path?: string | null; + id: string; + label: string; + public?: boolean; + variant?: string | null; + }; + Update: { + access_key_md5?: string | null; + configuration?: Json; + country_code?: string; + icon_path?: string | null; + id?: string; + label?: string; + public?: boolean; + variant?: string | null; + }; + Relationships: []; + }; + forecasts: { + Row: { + country_code: string; + created_at: string; + forecast_type: Database['public']['Enums']['forecast_type'] | null; + id: string; + language_code: string | null; + location: string[] | null; + mimetype: string | null; + storage_file: string | null; + updated_at: string; + }; + Insert: { + country_code: string; + created_at?: string; + forecast_type?: Database['public']['Enums']['forecast_type'] | null; + id: string; + language_code?: string | null; + location?: string[] | null; + mimetype?: string | null; + storage_file?: string | null; + updated_at?: string; + }; + Update: { + country_code?: string; + created_at?: string; + forecast_type?: Database['public']['Enums']['forecast_type'] | null; + id?: string; + language_code?: string | null; + location?: string[] | null; + mimetype?: string | null; + storage_file?: string | null; + updated_at?: string; + }; + Relationships: []; + }; + kobo_sync: { + Row: { + _created: string; + _id: string; + _modified: string; + enketo_entry: Json | null; + kobo_form_id: string | null; + kobo_sync_required: boolean | null; + kobo_sync_status: number | null; + kobo_sync_time: string | null; + kobo_uuid: string | null; + operation: string; + }; + Insert: { + _created?: string; + _id: string; + _modified?: string; + enketo_entry?: Json | null; + kobo_form_id?: string | null; + kobo_sync_required?: boolean | null; + kobo_sync_status?: number | null; + kobo_sync_time?: string | null; + kobo_uuid?: string | null; + operation: string; + }; + Update: { + _created?: string; + _id?: string; + _modified?: string; + enketo_entry?: Json | null; + kobo_form_id?: string | null; + kobo_sync_required?: boolean | null; + kobo_sync_status?: number | null; + kobo_sync_time?: string | null; + kobo_uuid?: string | null; + operation?: string; + }; + Relationships: []; + }; + monitoring_forms: { + Row: { + cover_image: string | null; + created_at: string; + description: string | null; + enketo_definition: Json | null; + enketo_form: string | null; + enketo_model: string | null; + form_xlsx: string | null; + id: string; + summary_fields: Json[] | null; + title: string; + }; + Insert: { + cover_image?: string | null; + created_at?: string; + description?: string | null; + enketo_definition?: Json | null; + enketo_form?: string | null; + enketo_model?: string | null; + form_xlsx?: string | null; + id: string; + summary_fields?: Json[] | null; + title: string; + }; + Update: { + cover_image?: string | null; + created_at?: string; + description?: string | null; + enketo_definition?: Json | null; + enketo_form?: string | null; + enketo_model?: string | null; + form_xlsx?: string | null; + id?: string; + summary_fields?: Json[] | null; + title?: string; + }; + Relationships: []; + }; + monitoring_tool_submissions: { + Row: { + _app_user_id: string; + _attachments: Json; + _created: string; + _deleted: boolean; + _id: string; + _modified: string; + enketoEntry: Json; + formId: string; + json: Json; + }; + Insert: { + _app_user_id: string; + _attachments: Json; + _created?: string; + _deleted?: boolean; + _id: string; + _modified?: string; + enketoEntry: Json; + formId: string; + json: Json; + }; + Update: { + _app_user_id?: string; + _attachments?: Json; + _created?: string; + _deleted?: boolean; + _id?: string; + _modified?: string; + enketoEntry?: Json; + formId?: string; + json?: Json; + }; + Relationships: []; + }; + resource_collections: { + Row: { + collection_parent: string | null; + cover_image: string | null; + created_at: string; + description: string | null; + id: string; + modified_at: string; + resource_collections: string[] | null; + resource_files: string[] | null; + resource_links: string[] | null; + sort_order: number; + title: string; + }; + Insert: { + collection_parent?: string | null; + cover_image?: string | null; + created_at?: string; + description?: string | null; + id?: string; + modified_at?: string; + resource_collections?: string[] | null; + resource_files?: string[] | null; + resource_links?: string[] | null; + sort_order?: number; + title: string; + }; + Update: { + collection_parent?: string | null; + cover_image?: string | null; + created_at?: string; + description?: string | null; + id?: string; + modified_at?: string; + resource_collections?: string[] | null; + resource_files?: string[] | null; + resource_links?: string[] | null; + sort_order?: number; + title?: string; + }; + Relationships: []; + }; + resource_files: { + Row: { + country_code: Database['public']['Enums']['country_code']; + cover_image: string | null; + created_at: string; + description: string | null; + external_url: string | null; + filename: string | null; + id: string; + language_code: string | null; + md5_checksum: string | null; + mimetype: string | null; + modified_at: string; + size_kb: number | null; + sort_order: number; + storage_file: string | null; + title: string | null; + }; + Insert: { + country_code?: Database['public']['Enums']['country_code']; + cover_image?: string | null; + created_at?: string; + description?: string | null; + external_url?: string | null; + filename?: string | null; + id?: string; + language_code?: string | null; + md5_checksum?: string | null; + mimetype?: string | null; + modified_at?: string; + size_kb?: number | null; + sort_order?: number; + storage_file?: string | null; + title?: string | null; + }; + Update: { + country_code?: Database['public']['Enums']['country_code']; + cover_image?: string | null; + created_at?: string; + description?: string | null; + external_url?: string | null; + filename?: string | null; + id?: string; + language_code?: string | null; + md5_checksum?: string | null; + mimetype?: string | null; + modified_at?: string; + size_kb?: number | null; + sort_order?: number; + storage_file?: string | null; + title?: string | null; + }; + Relationships: []; + }; + resource_files_child: { + Row: { + country_code: Database['public']['Enums']['country_code']; + cover_image: string | null; + created_at: string; + description: string | null; + external_url: string | null; + filename: string | null; + id: string; + language_code: string | null; + md5_checksum: string | null; + mimetype: string | null; + modified_at: string; + resource_file_id: string; + size_kb: number | null; + sort_order: number; + storage_file: string | null; + title: string | null; + }; + Insert: { + country_code?: Database['public']['Enums']['country_code']; + cover_image?: string | null; + created_at?: string; + description?: string | null; + external_url?: string | null; + filename?: string | null; + id?: string; + language_code?: string | null; + md5_checksum?: string | null; + mimetype?: string | null; + modified_at?: string; + resource_file_id: string; + size_kb?: number | null; + sort_order?: number; + storage_file?: string | null; + title?: string | null; + }; + Update: { + country_code?: Database['public']['Enums']['country_code']; + cover_image?: string | null; + created_at?: string; + description?: string | null; + external_url?: string | null; + filename?: string | null; + id?: string; + language_code?: string | null; + md5_checksum?: string | null; + mimetype?: string | null; + modified_at?: string; + resource_file_id?: string; + size_kb?: number | null; + sort_order?: number; + storage_file?: string | null; + title?: string | null; + }; + Relationships: [ + { + foreignKeyName: 'public_resource_files_child_resource_file_id_fkey'; + columns: ['resource_file_id']; + isOneToOne: false; + referencedRelation: 'resource_files'; + referencedColumns: ['id']; + } + ]; + }; + resource_links: { + Row: { + cover_image: string | null; + created_at: string; + description: string | null; + id: string; + modified_at: string; + sort_order: number; + title: string | null; + type: Database['public']['Enums']['resource_link_type']; + url: string; + }; + Insert: { + cover_image?: string | null; + created_at?: string; + description?: string | null; + id?: string; + modified_at?: string; + sort_order?: number; + title?: string | null; + type: Database['public']['Enums']['resource_link_type']; + url: string; + }; + Update: { + cover_image?: string | null; + created_at?: string; + description?: string | null; + id?: string; + modified_at?: string; + sort_order?: number; + title?: string | null; + type?: Database['public']['Enums']['resource_link_type']; + url?: string; + }; + Relationships: []; + }; + translations: { + Row: { + archived: boolean | null; + context: string | null; + created_at: string; + id: string; + ke_sw: string | null; + mw_ny: string | null; + text: string; + tj_tg: string | null; + tool: string; + zm_ny: string | null; + }; + Insert: { + archived?: boolean | null; + context?: string | null; + created_at?: string; + id: string; + ke_sw?: string | null; + mw_ny?: string | null; + text: string; + tj_tg?: string | null; + tool: string; + zm_ny?: string | null; + }; + Update: { + archived?: boolean | null; + context?: string | null; + created_at?: string; + id?: string; + ke_sw?: string | null; + mw_ny?: string | null; + text?: string; + tj_tg?: string | null; + tool?: string; + zm_ny?: string | null; + }; + Relationships: []; + }; + user_roles: { + Row: { + created_at: string; + deployment_id: string; + id: number; + roles: Database['public']['Enums']['app_role'][]; + user_id: string; + }; + Insert: { + created_at?: string; + deployment_id: string; + id?: number; + roles?: Database['public']['Enums']['app_role'][]; + user_id?: string; + }; + Update: { + created_at?: string; + deployment_id?: string; + id?: number; + roles?: Database['public']['Enums']['app_role'][]; + user_id?: string; + }; + Relationships: [ + { + foreignKeyName: 'public_user_roles_deployment_id_fkey'; + columns: ['deployment_id']; + isOneToOne: false; + referencedRelation: 'deployments'; + referencedColumns: ['id']; + } + ]; + }; + }; + Views: { + storage_objects: { + Row: { + bucket_id: string | null; + created_at: string | null; + id: string | null; + last_accessed_at: string | null; + metadata: Json | null; + name: string | null; + owner: string | null; + owner_id: string | null; + path_tokens: string[] | null; + updated_at: string | null; + version: string | null; + }; + Insert: { + bucket_id?: string | null; + created_at?: string | null; + id?: string | null; + last_accessed_at?: string | null; + metadata?: Json | null; + name?: string | null; + owner?: string | null; + owner_id?: string | null; + path_tokens?: string[] | null; + updated_at?: string | null; + version?: string | null; + }; + Update: { + bucket_id?: string | null; + created_at?: string | null; + id?: string | null; + last_accessed_at?: string | null; + metadata?: Json | null; + name?: string | null; + owner?: string | null; + owner_id?: string | null; + path_tokens?: string[] | null; + updated_at?: string | null; + version?: string | null; + }; + Relationships: []; + }; + }; + Functions: { + call_edge_function: { + Args: { + name: string; + body: Json; + }; + Returns: number; + }; + custom_access_token_hook: { + Args: { + event: Json; + }; + Returns: Json; + }; + }; + Enums: { + app_role: + | 'resources.viewer' + | 'resources.author' + | 'resources.admin' + | 'deployments.admin' + | 'translations.viewer'; + country_code: 'global' | 'mw' | 'zm' | 'tj'; + forecast_type: 'daily' | 'seasonal' | 'downscaled'; + locale_code: 'global_en' | 'mw_ny' | 'mw_tum' | 'zm_ny' | 'tj_tg'; + resource_link_type: 'app' | 'social' | 'web'; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; + storage: { + Tables: { + buckets: { + Row: { + allowed_mime_types: string[] | null; + avif_autodetection: boolean | null; + created_at: string | null; + file_size_limit: number | null; + id: string; + name: string; + owner: string | null; + owner_id: string | null; + public: boolean | null; + updated_at: string | null; + }; + Insert: { + allowed_mime_types?: string[] | null; + avif_autodetection?: boolean | null; + created_at?: string | null; + file_size_limit?: number | null; + id: string; + name: string; + owner?: string | null; + owner_id?: string | null; + public?: boolean | null; + updated_at?: string | null; + }; + Update: { + allowed_mime_types?: string[] | null; + avif_autodetection?: boolean | null; + created_at?: string | null; + file_size_limit?: number | null; + id?: string; + name?: string; + owner?: string | null; + owner_id?: string | null; + public?: boolean | null; + updated_at?: string | null; + }; + Relationships: []; + }; + migrations: { + Row: { + executed_at: string | null; + hash: string; + id: number; + name: string; + }; + Insert: { + executed_at?: string | null; + hash: string; + id: number; + name: string; + }; + Update: { + executed_at?: string | null; + hash?: string; + id?: number; + name?: string; + }; + Relationships: []; + }; + objects: { + Row: { + bucket_id: string | null; + created_at: string | null; + id: string; + last_accessed_at: string | null; + metadata: Json | null; + name: string | null; + owner: string | null; + owner_id: string | null; + path: string | null; + path_tokens: string[] | null; + updated_at: string | null; + version: string | null; + }; + Insert: { + bucket_id?: string | null; + created_at?: string | null; + id?: string; + last_accessed_at?: string | null; + metadata?: Json | null; + name?: string | null; + owner?: string | null; + owner_id?: string | null; + path?: string | null; + path_tokens?: string[] | null; + updated_at?: string | null; + version?: string | null; + }; + Update: { + bucket_id?: string | null; + created_at?: string | null; + id?: string; + last_accessed_at?: string | null; + metadata?: Json | null; + name?: string | null; + owner?: string | null; + owner_id?: string | null; + path?: string | null; + path_tokens?: string[] | null; + updated_at?: string | null; + version?: string | null; + }; + Relationships: [ + { + foreignKeyName: 'objects_bucketId_fkey'; + columns: ['bucket_id']; + isOneToOne: false; + referencedRelation: 'buckets'; + referencedColumns: ['id']; + } + ]; + }; + }; + Views: { + [_ in never]: never; + }; + Functions: { + can_insert_object: { + Args: { + bucketid: string; + name: string; + owner: string; + metadata: Json; + }; + Returns: undefined; + }; + extension: { + Args: { + name: string; + }; + Returns: string; + }; + filename: { + Args: { + name: string; + }; + Returns: string; + }; + foldername: { + Args: { + name: string; + }; + Returns: string[]; + }; + get_size_by_bucket: { + Args: Record; + Returns: { + size: number; + bucket_id: string; + }[]; + }; + search: { + Args: { + prefix: string; + bucketname: string; + limits?: number; + levels?: number; + offsets?: number; + search?: string; + sortcolumn?: string; + sortorder?: string; + }; + Returns: { + name: string; + id: string; + updated_at: string; + created_at: string; + last_accessed_at: string; + metadata: Json; + }[]; + }; + }; + Enums: { + [_ in never]: never; + }; + CompositeTypes: { + [_ in never]: never; + }; + }; +}; + +type PublicSchema = Database[Extract]; + +export type Tables< + PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & PublicSchema['Views']) | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & + Database[PublicTableNameOrOptions['schema']]['Views']) + : never = never +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & + Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { + Row: infer R; + } + ? R + : never + : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & PublicSchema['Views']) + ? (PublicSchema['Tables'] & PublicSchema['Views'])[PublicTableNameOrOptions] extends { + Row: infer R; + } + ? R + : never + : never; + +export type TablesInsert< + PublicTableNameOrOptions extends keyof PublicSchema['Tables'] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + : never = never +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + Insert: infer I; + } + ? I + : never + : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] + ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + Insert: infer I; + } + ? I + : never + : never; + +export type TablesUpdate< + PublicTableNameOrOptions extends keyof PublicSchema['Tables'] | { schema: keyof Database }, + TableName extends PublicTableNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + : never = never +> = PublicTableNameOrOptions extends { schema: keyof Database } + ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { + Update: infer U; + } + ? U + : never + : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] + ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + Update: infer U; + } + ? U + : never + : never; + +export type Enums< + PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] | { schema: keyof Database }, + EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } + ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + : never = never +> = PublicEnumNameOrOptions extends { schema: keyof Database } + ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] + : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] + ? PublicSchema['Enums'][PublicEnumNameOrOptions] + : never; + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes'] | { schema: keyof Database }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof Database; + } + ? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] + : never = never +> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } + ? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes'] + ? PublicSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] + : never; diff --git a/apps/picsa-server/supabase/types/functions.types.ts b/apps/picsa-server/supabase/types/functions.types.ts new file mode 100644 index 000000000..e6b348b86 --- /dev/null +++ b/apps/picsa-server/supabase/types/functions.types.ts @@ -0,0 +1,8 @@ +import type { IForecastDBAPIResponse } from '../functions/dashboard/types'; + +/** Manually generated list of supabase function responses */ +export type FunctionResponses = { + Dashboard: { + 'forecast-db': IForecastDBAPIResponse; + }; +}; diff --git a/apps/picsa-server/supabase/types/index.ts b/apps/picsa-server/supabase/types/index.ts index 084a1c0b4..35c8f3dd0 100644 --- a/apps/picsa-server/supabase/types/index.ts +++ b/apps/picsa-server/supabase/types/index.ts @@ -1,977 +1,2 @@ -export type Json = - | string - | number - | boolean - | null - | { [key: string]: Json | undefined } - | Json[] - -export type Database = { - graphql_public: { - Tables: { - [_ in never]: never - } - Views: { - [_ in never]: never - } - Functions: { - graphql: { - Args: { - operationName?: string - query?: string - variables?: Json - extensions?: Json - } - Returns: Json - } - } - Enums: { - [_ in never]: never - } - CompositeTypes: { - [_ in never]: never - } - } - public: { - Tables: { - forecasts: { - Row: { - country_code: string - created_at: string - forecast_type: Database["public"]["Enums"]["forecast_type"] | null - id: string - language_code: string | null - location: string[] | null - mimetype: string | null - storage_file: string | null - updated_at: string - } - Insert: { - country_code: string - created_at?: string - forecast_type?: Database["public"]["Enums"]["forecast_type"] | null - id: string - language_code?: string | null - location?: string[] | null - mimetype?: string | null - storage_file?: string | null - updated_at?: string - } - Update: { - country_code?: string - created_at?: string - forecast_type?: Database["public"]["Enums"]["forecast_type"] | null - id?: string - language_code?: string | null - location?: string[] | null - mimetype?: string | null - storage_file?: string | null - updated_at?: string - } - Relationships: [] - } - climate_stations: { - Row: { - country_code: string - district: string | null - elevation: number | null - id: string | null - latitude: number | null - longitude: number | null - station_id: string - station_name: string | null - } - Insert: { - country_code: string - district?: string | null - elevation?: number | null - id?: string | null - latitude?: number | null - longitude?: number | null - station_id: string - station_name?: string | null - } - Update: { - country_code?: string - district?: string | null - elevation?: number | null - id?: string | null - latitude?: number | null - longitude?: number | null - station_id?: string - station_name?: string | null - } - Relationships: [] - } - climate_summary_rainfall: { - Row: { - country_code: Database["public"]["Enums"]["country_code"] - created_at: string - data: Json[] - metadata: Json - station_id: string - updated_at: string - } - Insert: { - country_code: Database["public"]["Enums"]["country_code"] - created_at?: string - data: Json[] - metadata: Json - station_id: string - updated_at?: string - } - Update: { - country_code?: Database["public"]["Enums"]["country_code"] - created_at?: string - data?: Json[] - metadata?: Json - station_id?: string - updated_at?: string - } - Relationships: [ - { - foreignKeyName: "climate_summary_rainfall_station_id_fkey" - columns: ["station_id"] - isOneToOne: false - referencedRelation: "climate_stations" - referencedColumns: ["id"] - }, - ] - } - crop_data: { - Row: { - created_at: string - crop: string - id: string | null - label: string | null - variety: string - } - Insert: { - created_at?: string - crop: string - id?: string | null - label?: string | null - variety: string - } - Update: { - created_at?: string - crop?: string - id?: string | null - label?: string | null - variety?: string - } - Relationships: [] - } - crop_station_data: { - Row: { - created_at: string - crop_id: string - days_lower: number - days_upper: number - probabilities: number[] | null - station_id: string - water_lower: number - water_upper: number - } - Insert: { - created_at?: string - crop_id: string - days_lower: number - days_upper: number - probabilities?: number[] | null - station_id: string - water_lower: number - water_upper: number - } - Update: { - created_at?: string - crop_id?: string - days_lower?: number - days_upper?: number - probabilities?: number[] | null - station_id?: string - water_lower?: number - water_upper?: number - } - Relationships: [ - { - foreignKeyName: "public_crop_station_data_crop_id_fkey" - columns: ["crop_id"] - isOneToOne: false - referencedRelation: "crop_data" - referencedColumns: ["id"] - }, - { - foreignKeyName: "public_crop_station_data_station_id_fkey" - columns: ["station_id"] - isOneToOne: false - referencedRelation: "climate_stations" - referencedColumns: ["id"] - }, - ] - } - deployments: { - Row: { - access_key_md5: string | null - configuration: Json - country_code: string - icon_path: string | null - id: string - label: string - public: boolean - variant: string | null - } - Insert: { - access_key_md5?: string | null - configuration?: Json - country_code: string - icon_path?: string | null - id: string - label: string - public?: boolean - variant?: string | null - } - Update: { - access_key_md5?: string | null - configuration?: Json - country_code?: string - icon_path?: string | null - id?: string - label?: string - public?: boolean - variant?: string | null - } - Relationships: [] - } - kobo_sync: { - Row: { - _created: string - _id: string - _modified: string - enketo_entry: Json | null - kobo_form_id: string | null - kobo_sync_required: boolean | null - kobo_sync_status: number | null - kobo_sync_time: string | null - kobo_uuid: string | null - operation: string - } - Insert: { - _created?: string - _id: string - _modified?: string - enketo_entry?: Json | null - kobo_form_id?: string | null - kobo_sync_required?: boolean | null - kobo_sync_status?: number | null - kobo_sync_time?: string | null - kobo_uuid?: string | null - operation: string - } - Update: { - _created?: string - _id?: string - _modified?: string - enketo_entry?: Json | null - kobo_form_id?: string | null - kobo_sync_required?: boolean | null - kobo_sync_status?: number | null - kobo_sync_time?: string | null - kobo_uuid?: string | null - operation?: string - } - Relationships: [] - } - monitoring_forms: { - Row: { - cover_image: string | null - created_at: string - description: string | null - enketo_definition: Json | null - enketo_form: string | null - enketo_model: string | null - form_xlsx: string | null - id: string - summary_fields: Json[] | null - title: string - } - Insert: { - cover_image?: string | null - created_at?: string - description?: string | null - enketo_definition?: Json | null - enketo_form?: string | null - enketo_model?: string | null - form_xlsx?: string | null - id: string - summary_fields?: Json[] | null - title: string - } - Update: { - cover_image?: string | null - created_at?: string - description?: string | null - enketo_definition?: Json | null - enketo_form?: string | null - enketo_model?: string | null - form_xlsx?: string | null - id?: string - summary_fields?: Json[] | null - title?: string - } - Relationships: [] - } - monitoring_tool_submissions: { - Row: { - _app_user_id: string - _attachments: Json - _created: string - _deleted: boolean - _id: string - _modified: string - enketoEntry: Json - formId: string - json: Json - } - Insert: { - _app_user_id: string - _attachments: Json - _created?: string - _deleted?: boolean - _id: string - _modified?: string - enketoEntry: Json - formId: string - json: Json - } - Update: { - _app_user_id?: string - _attachments?: Json - _created?: string - _deleted?: boolean - _id?: string - _modified?: string - enketoEntry?: Json - formId?: string - json?: Json - } - Relationships: [] - } - resource_collections: { - Row: { - collection_parent: string | null - cover_image: string | null - created_at: string - description: string | null - id: string - modified_at: string - resource_collections: string[] | null - resource_files: string[] | null - resource_links: string[] | null - sort_order: number - title: string - } - Insert: { - collection_parent?: string | null - cover_image?: string | null - created_at?: string - description?: string | null - id?: string - modified_at?: string - resource_collections?: string[] | null - resource_files?: string[] | null - resource_links?: string[] | null - sort_order?: number - title: string - } - Update: { - collection_parent?: string | null - cover_image?: string | null - created_at?: string - description?: string | null - id?: string - modified_at?: string - resource_collections?: string[] | null - resource_files?: string[] | null - resource_links?: string[] | null - sort_order?: number - title?: string - } - Relationships: [] - } - resource_files: { - Row: { - country_code: Database["public"]["Enums"]["country_code"] - cover_image: string | null - created_at: string - description: string | null - external_url: string | null - filename: string | null - id: string - language_code: string | null - md5_checksum: string | null - mimetype: string | null - modified_at: string - size_kb: number | null - sort_order: number - storage_file: string | null - title: string | null - } - Insert: { - country_code?: Database["public"]["Enums"]["country_code"] - cover_image?: string | null - created_at?: string - description?: string | null - external_url?: string | null - filename?: string | null - id?: string - language_code?: string | null - md5_checksum?: string | null - mimetype?: string | null - modified_at?: string - size_kb?: number | null - sort_order?: number - storage_file?: string | null - title?: string | null - } - Update: { - country_code?: Database["public"]["Enums"]["country_code"] - cover_image?: string | null - created_at?: string - description?: string | null - external_url?: string | null - filename?: string | null - id?: string - language_code?: string | null - md5_checksum?: string | null - mimetype?: string | null - modified_at?: string - size_kb?: number | null - sort_order?: number - storage_file?: string | null - title?: string | null - } - Relationships: [] - } - resource_files_child: { - Row: { - country_code: Database["public"]["Enums"]["country_code"] - cover_image: string | null - created_at: string - description: string | null - external_url: string | null - filename: string | null - id: string - language_code: string | null - md5_checksum: string | null - mimetype: string | null - modified_at: string - resource_file_id: string - size_kb: number | null - sort_order: number - storage_file: string | null - title: string | null - } - Insert: { - country_code?: Database["public"]["Enums"]["country_code"] - cover_image?: string | null - created_at?: string - description?: string | null - external_url?: string | null - filename?: string | null - id?: string - language_code?: string | null - md5_checksum?: string | null - mimetype?: string | null - modified_at?: string - resource_file_id: string - size_kb?: number | null - sort_order?: number - storage_file?: string | null - title?: string | null - } - Update: { - country_code?: Database["public"]["Enums"]["country_code"] - cover_image?: string | null - created_at?: string - description?: string | null - external_url?: string | null - filename?: string | null - id?: string - language_code?: string | null - md5_checksum?: string | null - mimetype?: string | null - modified_at?: string - resource_file_id?: string - size_kb?: number | null - sort_order?: number - storage_file?: string | null - title?: string | null - } - Relationships: [ - { - foreignKeyName: "public_resource_files_child_resource_file_id_fkey" - columns: ["resource_file_id"] - isOneToOne: false - referencedRelation: "resource_files" - referencedColumns: ["id"] - }, - ] - } - resource_links: { - Row: { - cover_image: string | null - created_at: string - description: string | null - id: string - modified_at: string - sort_order: number - title: string | null - type: Database["public"]["Enums"]["resource_link_type"] - url: string - } - Insert: { - cover_image?: string | null - created_at?: string - description?: string | null - id?: string - modified_at?: string - sort_order?: number - title?: string | null - type: Database["public"]["Enums"]["resource_link_type"] - url: string - } - Update: { - cover_image?: string | null - created_at?: string - description?: string | null - id?: string - modified_at?: string - sort_order?: number - title?: string | null - type?: Database["public"]["Enums"]["resource_link_type"] - url?: string - } - Relationships: [] - } - translations: { - Row: { - archived: boolean | null - context: string | null - created_at: string - id: string - ke_sw: string | null - mw_ny: string | null - text: string - tj_tg: string | null - tool: string - zm_ny: string | null - } - Insert: { - archived?: boolean | null - context?: string | null - created_at?: string - id: string - ke_sw?: string | null - mw_ny?: string | null - text: string - tj_tg?: string | null - tool: string - zm_ny?: string | null - } - Update: { - archived?: boolean | null - context?: string | null - created_at?: string - id?: string - ke_sw?: string | null - mw_ny?: string | null - text?: string - tj_tg?: string | null - tool?: string - zm_ny?: string | null - } - Relationships: [] - } - user_roles: { - Row: { - created_at: string - deployment_id: string - id: number - roles: Database["public"]["Enums"]["app_role"][] - user_id: string - } - Insert: { - created_at?: string - deployment_id: string - id?: number - roles?: Database["public"]["Enums"]["app_role"][] - user_id?: string - } - Update: { - created_at?: string - deployment_id?: string - id?: number - roles?: Database["public"]["Enums"]["app_role"][] - user_id?: string - } - Relationships: [ - { - foreignKeyName: "public_user_roles_deployment_id_fkey" - columns: ["deployment_id"] - isOneToOne: false - referencedRelation: "deployments" - referencedColumns: ["id"] - }, - ] - } - } - Views: { - storage_objects: { - Row: { - bucket_id: string | null - created_at: string | null - id: string | null - last_accessed_at: string | null - metadata: Json | null - name: string | null - owner: string | null - owner_id: string | null - path_tokens: string[] | null - updated_at: string | null - version: string | null - } - Insert: { - bucket_id?: string | null - created_at?: string | null - id?: string | null - last_accessed_at?: string | null - metadata?: Json | null - name?: string | null - owner?: string | null - owner_id?: string | null - path_tokens?: string[] | null - updated_at?: string | null - version?: string | null - } - Update: { - bucket_id?: string | null - created_at?: string | null - id?: string | null - last_accessed_at?: string | null - metadata?: Json | null - name?: string | null - owner?: string | null - owner_id?: string | null - path_tokens?: string[] | null - updated_at?: string | null - version?: string | null - } - Relationships: [] - } - } - Functions: { - custom_access_token_hook: { - Args: { - event: Json - } - Returns: Json - } - } - Enums: { - app_role: - | "resources.viewer" - | "resources.author" - | "resources.admin" - | "deployments.admin" - | "translations.viewer" - country_code: "global" | "mw" | "zm" | "tj" - forecast_type: "daily" | "annual" | 'seasonal'| 'downscaled' - locale_code: "global_en" | "mw_ny" | "mw_tum" | "zm_ny" | "tj_tg" - resource_link_type: "app" | "social" | "web" - } - CompositeTypes: { - [_ in never]: never - } - } - storage: { - Tables: { - buckets: { - Row: { - allowed_mime_types: string[] | null - avif_autodetection: boolean | null - created_at: string | null - file_size_limit: number | null - id: string - name: string - owner: string | null - owner_id: string | null - public: boolean | null - updated_at: string | null - } - Insert: { - allowed_mime_types?: string[] | null - avif_autodetection?: boolean | null - created_at?: string | null - file_size_limit?: number | null - id: string - name: string - owner?: string | null - owner_id?: string | null - public?: boolean | null - updated_at?: string | null - } - Update: { - allowed_mime_types?: string[] | null - avif_autodetection?: boolean | null - created_at?: string | null - file_size_limit?: number | null - id?: string - name?: string - owner?: string | null - owner_id?: string | null - public?: boolean | null - updated_at?: string | null - } - Relationships: [] - } - migrations: { - Row: { - executed_at: string | null - hash: string - id: number - name: string - } - Insert: { - executed_at?: string | null - hash: string - id: number - name: string - } - Update: { - executed_at?: string | null - hash?: string - id?: number - name?: string - } - Relationships: [] - } - objects: { - Row: { - bucket_id: string | null - created_at: string | null - id: string - last_accessed_at: string | null - metadata: Json | null - name: string | null - owner: string | null - owner_id: string | null - path: string | null - path_tokens: string[] | null - updated_at: string | null - version: string | null - } - Insert: { - bucket_id?: string | null - created_at?: string | null - id?: string - last_accessed_at?: string | null - metadata?: Json | null - name?: string | null - owner?: string | null - owner_id?: string | null - path?: string | null - path_tokens?: string[] | null - updated_at?: string | null - version?: string | null - } - Update: { - bucket_id?: string | null - created_at?: string | null - id?: string - last_accessed_at?: string | null - metadata?: Json | null - name?: string | null - owner?: string | null - owner_id?: string | null - path?: string | null - path_tokens?: string[] | null - updated_at?: string | null - version?: string | null - } - Relationships: [ - { - foreignKeyName: "objects_bucketId_fkey" - columns: ["bucket_id"] - isOneToOne: false - referencedRelation: "buckets" - referencedColumns: ["id"] - }, - ] - } - } - Views: { - [_ in never]: never - } - Functions: { - can_insert_object: { - Args: { - bucketid: string - name: string - owner: string - metadata: Json - } - Returns: undefined - } - extension: { - Args: { - name: string - } - Returns: string - } - filename: { - Args: { - name: string - } - Returns: string - } - foldername: { - Args: { - name: string - } - Returns: string[] - } - get_size_by_bucket: { - Args: Record - Returns: { - size: number - bucket_id: string - }[] - } - search: { - Args: { - prefix: string - bucketname: string - limits?: number - levels?: number - offsets?: number - search?: string - sortcolumn?: string - sortorder?: string - } - Returns: { - name: string - id: string - updated_at: string - created_at: string - last_accessed_at: string - metadata: Json - }[] - } - } - Enums: { - [_ in never]: never - } - CompositeTypes: { - [_ in never]: never - } - } -} - -type PublicSchema = Database[Extract] - -export type Tables< - PublicTableNameOrOptions extends - | keyof (PublicSchema["Tables"] & PublicSchema["Views"]) - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof (Database[PublicTableNameOrOptions["schema"]]["Tables"] & - Database[PublicTableNameOrOptions["schema"]]["Views"]) - : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? (Database[PublicTableNameOrOptions["schema"]]["Tables"] & - Database[PublicTableNameOrOptions["schema"]]["Views"])[TableName] extends { - Row: infer R - } - ? R - : never - : PublicTableNameOrOptions extends keyof (PublicSchema["Tables"] & - PublicSchema["Views"]) - ? (PublicSchema["Tables"] & - PublicSchema["Views"])[PublicTableNameOrOptions] extends { - Row: infer R - } - ? R - : never - : never - -export type TablesInsert< - PublicTableNameOrOptions extends - | keyof PublicSchema["Tables"] - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] - : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Insert: infer I - } - ? I - : never - : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] - ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { - Insert: infer I - } - ? I - : never - : never - -export type TablesUpdate< - PublicTableNameOrOptions extends - | keyof PublicSchema["Tables"] - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions["schema"]]["Tables"] - : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions["schema"]]["Tables"][TableName] extends { - Update: infer U - } - ? U - : never - : PublicTableNameOrOptions extends keyof PublicSchema["Tables"] - ? PublicSchema["Tables"][PublicTableNameOrOptions] extends { - Update: infer U - } - ? U - : never - : never - -export type Enums< - PublicEnumNameOrOptions extends - | keyof PublicSchema["Enums"] - | { schema: keyof Database }, - EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicEnumNameOrOptions["schema"]]["Enums"] - : never = never, -> = PublicEnumNameOrOptions extends { schema: keyof Database } - ? Database[PublicEnumNameOrOptions["schema"]]["Enums"][EnumName] - : PublicEnumNameOrOptions extends keyof PublicSchema["Enums"] - ? PublicSchema["Enums"][PublicEnumNameOrOptions] - : never - -export type CompositeTypes< - PublicCompositeTypeNameOrOptions extends - | keyof PublicSchema["CompositeTypes"] - | { schema: keyof Database }, - CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof Database - } - ? keyof Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] - : never = never, -> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } - ? Database[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] - : PublicCompositeTypeNameOrOptions extends keyof PublicSchema["CompositeTypes"] - ? PublicSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] - : never - +export * from './db.types' +export * from './functions.types' \ No newline at end of file From 502f250e10c80860a7ce4071231e389ead50eedb Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 13:42:34 -0800 Subject: [PATCH 35/44] chore: add resources tool project --- .../src/app/routes/tool-routes.ts | 1 + .../picsa-tools/forecasts-tool/.eslintrc.json | 33 +++++++ .../picsa-tools/forecasts-tool/jest.config.ts | 21 ++++ apps/picsa-tools/forecasts-tool/project.json | 90 ++++++++++++++++++ .../forecasts-tool/public/favicon.ico | Bin 0 -> 15086 bytes .../forecasts-tool/src/app/app.component.html | 0 .../forecasts-tool/src/app/app.component.scss | 0 .../src/app/app.component.spec.ts | 25 +++++ .../forecasts-tool/src/app/app.component.ts | 11 +++ .../forecasts-tool/src/app/app.config.ts | 5 + .../location-select.component.html | 0 .../location-select.component.scss | 0 .../location-select.component.spec.ts | 0 .../location-select.component.ts | 0 .../app}/pages/forecast/forecast.page.html | 0 .../app}/pages/forecast/forecast.page.scss | 0 .../src/app}/pages/forecast/forecast.page.ts | 0 .../app}/pages/forecast/forecast.service.ts | 0 .../src/app}/pages/forecast/forecast.types.ts | 0 .../src/app}/pages/forecast/schemas/index.ts | 0 .../app}/pages/forecast/schemas/schema_v0.ts | 0 .../picsa-tools/forecasts-tool/src/index.html | 13 +++ apps/picsa-tools/forecasts-tool/src/main.ts | 6 ++ .../forecasts-tool/src/styles.scss | 1 + .../forecasts-tool/src/test-setup.ts | 6 ++ .../forecasts-tool/tsconfig.app.json | 10 ++ .../forecasts-tool/tsconfig.editor.json | 6 ++ apps/picsa-tools/forecasts-tool/tsconfig.json | 32 +++++++ .../forecasts-tool/tsconfig.spec.json | 11 +++ tsconfig.base.json | 2 +- 30 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 apps/picsa-tools/forecasts-tool/.eslintrc.json create mode 100644 apps/picsa-tools/forecasts-tool/jest.config.ts create mode 100644 apps/picsa-tools/forecasts-tool/project.json create mode 100644 apps/picsa-tools/forecasts-tool/public/favicon.ico create mode 100644 apps/picsa-tools/forecasts-tool/src/app/app.component.html create mode 100644 apps/picsa-tools/forecasts-tool/src/app/app.component.scss create mode 100644 apps/picsa-tools/forecasts-tool/src/app/app.component.spec.ts create mode 100644 apps/picsa-tools/forecasts-tool/src/app/app.component.ts create mode 100644 apps/picsa-tools/forecasts-tool/src/app/app.config.ts rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/components/location-select/location-select.component.html (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/components/location-select/location-select.component.scss (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/components/location-select/location-select.component.spec.ts (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/components/location-select/location-select.component.ts (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/forecast.page.html (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/forecast.page.scss (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/forecast.page.ts (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/forecast.service.ts (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/forecast.types.ts (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/schemas/index.ts (100%) rename apps/picsa-tools/{forecasts/src => forecasts-tool/src/app}/pages/forecast/schemas/schema_v0.ts (100%) create mode 100644 apps/picsa-tools/forecasts-tool/src/index.html create mode 100644 apps/picsa-tools/forecasts-tool/src/main.ts create mode 100644 apps/picsa-tools/forecasts-tool/src/styles.scss create mode 100644 apps/picsa-tools/forecasts-tool/src/test-setup.ts create mode 100644 apps/picsa-tools/forecasts-tool/tsconfig.app.json create mode 100644 apps/picsa-tools/forecasts-tool/tsconfig.editor.json create mode 100644 apps/picsa-tools/forecasts-tool/tsconfig.json create mode 100644 apps/picsa-tools/forecasts-tool/tsconfig.spec.json diff --git a/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts b/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts index cbc62b644..712e269ba 100644 --- a/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts +++ b/apps/picsa-apps/extension-app/src/app/routes/tool-routes.ts @@ -1,3 +1,4 @@ +/* eslint-disable @nx/enforce-module-boundaries */ import { Routes } from '@angular/router'; export const TOOL_ROUTES: Routes = [ diff --git a/apps/picsa-tools/forecasts-tool/.eslintrc.json b/apps/picsa-tools/forecasts-tool/.eslintrc.json new file mode 100644 index 000000000..6012af27e --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "forecast", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "forecast", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/apps/picsa-tools/forecasts-tool/jest.config.ts b/apps/picsa-tools/forecasts-tool/jest.config.ts new file mode 100644 index 000000000..63753acb0 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: 'forecasts-tool', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/apps/picsa-tools/forecasts-tool', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/apps/picsa-tools/forecasts-tool/project.json b/apps/picsa-tools/forecasts-tool/project.json new file mode 100644 index 000000000..541599bcb --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/project.json @@ -0,0 +1,90 @@ +{ + "name": "forecasts-tool", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/picsa-tools/forecasts-tool/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/picsa-tools/forecasts-tool", + "index": "apps/picsa-tools/forecasts-tool/src/index.html", + "browser": "apps/picsa-tools/forecasts-tool/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/picsa-tools/forecasts-tool/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "apps/picsa-tools/forecasts-tool/public" + } + ], + "styles": ["apps/picsa-tools/forecasts-tool/src/styles.scss"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kb", + "maximumError": "8kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "forecasts-tool:build:production" + }, + "development": { + "buildTarget": "forecasts-tool:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "forecasts-tool:build" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "apps/picsa-tools/forecasts-tool/jest.config.ts" + } + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "forecasts-tool:build", + "port": 4200, + "staticFilePath": "dist/apps/picsa-tools/forecasts-tool/browser", + "spa": true + } + } + } +} diff --git a/apps/picsa-tools/forecasts-tool/public/favicon.ico b/apps/picsa-tools/forecasts-tool/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppComponent, NxWelcomeComponent], + }).compileComponents(); + }); + + it('should render title', () => { + const fixture = TestBed.createComponent(AppComponent); + fixture.detectChanges(); + const compiled = fixture.nativeElement as HTMLElement; + expect(compiled.querySelector('h1')?.textContent).toContain('Welcome forecasts-tool'); + }); + + it(`should have as title 'forecasts-tool'`, () => { + const fixture = TestBed.createComponent(AppComponent); + const app = fixture.componentInstance; + expect(app.title).toEqual('forecasts-tool'); + }); +}); diff --git a/apps/picsa-tools/forecasts-tool/src/app/app.component.ts b/apps/picsa-tools/forecasts-tool/src/app/app.component.ts new file mode 100644 index 000000000..779c112b6 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/app/app.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + imports: [], + selector: 'forecast-app-root', + templateUrl: './app.component.html', + styleUrl: './app.component.scss', +}) +export class AppComponent { + title = 'forecasts-tool'; +} diff --git a/apps/picsa-tools/forecasts-tool/src/app/app.config.ts b/apps/picsa-tools/forecasts-tool/src/app/app.config.ts new file mode 100644 index 000000000..034603cfd --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/app/app.config.ts @@ -0,0 +1,5 @@ +import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; + +export const appConfig: ApplicationConfig = { + providers: [provideZoneChangeDetection({ eventCoalescing: true })], +}; diff --git a/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.html b/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.html similarity index 100% rename from apps/picsa-tools/forecasts/src/components/location-select/location-select.component.html rename to apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.html diff --git a/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.scss b/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.scss similarity index 100% rename from apps/picsa-tools/forecasts/src/components/location-select/location-select.component.scss rename to apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.scss diff --git a/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.spec.ts b/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.spec.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/components/location-select/location-select.component.spec.ts rename to apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.spec.ts diff --git a/apps/picsa-tools/forecasts/src/components/location-select/location-select.component.ts b/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/components/location-select/location-select.component.ts rename to apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.ts diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.html b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.html similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.html rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.html diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.scss b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.scss similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.scss rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.scss diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/forecast.page.ts rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.service.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/forecast.service.ts rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.service.ts diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.types.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/forecast.types.ts rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.types.ts diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/index.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/schemas/index.ts rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/index.ts diff --git a/apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/schema_v0.ts similarity index 100% rename from apps/picsa-tools/forecasts/src/pages/forecast/schemas/schema_v0.ts rename to apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/schema_v0.ts diff --git a/apps/picsa-tools/forecasts-tool/src/index.html b/apps/picsa-tools/forecasts-tool/src/index.html new file mode 100644 index 000000000..9ee0fbeef --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/index.html @@ -0,0 +1,13 @@ + + + + + forecasts-tool + + + + + + + + diff --git a/apps/picsa-tools/forecasts-tool/src/main.ts b/apps/picsa-tools/forecasts-tool/src/main.ts new file mode 100644 index 000000000..14afb2d0e --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; + +import { AppComponent } from './app/app.component'; +import { appConfig } from './app/app.config'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)); diff --git a/apps/picsa-tools/forecasts-tool/src/styles.scss b/apps/picsa-tools/forecasts-tool/src/styles.scss new file mode 100644 index 000000000..90d4ee007 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/styles.scss @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/picsa-tools/forecasts-tool/src/test-setup.ts b/apps/picsa-tools/forecasts-tool/src/test-setup.ts new file mode 100644 index 000000000..ea414013f --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/test-setup.ts @@ -0,0 +1,6 @@ +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + errorOnUnknownElements: true, + errorOnUnknownProperties: true, +}); diff --git a/apps/picsa-tools/forecasts-tool/tsconfig.app.json b/apps/picsa-tools/forecasts-tool/tsconfig.app.json new file mode 100644 index 000000000..58220429a --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/picsa-tools/forecasts-tool/tsconfig.editor.json b/apps/picsa-tools/forecasts-tool/tsconfig.editor.json new file mode 100644 index 000000000..a8ac182c0 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/tsconfig.editor.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": {}, + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/picsa-tools/forecasts-tool/tsconfig.json b/apps/picsa-tools/forecasts-tool/tsconfig.json new file mode 100644 index 000000000..ddb305021 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "es2022", + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/picsa-tools/forecasts-tool/tsconfig.spec.json b/apps/picsa-tools/forecasts-tool/tsconfig.spec.json new file mode 100644 index 000000000..e637bf83b --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/tsconfig.spec.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 07d32a8bf..f03ac6d59 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -33,8 +33,8 @@ "@picsa/extension-content/*": ["apps/picsa-tools/extension-content/*"], "@picsa/extension/*": ["apps/picsa-apps/extension-app/*"], "@picsa/farmer-content/*": ["apps/picsa-tools/farmer-content/*"], + "@picsa/forecasts/*": ["apps/picsa-tools/forecasts-tool/src/app/*"], "@picsa/forms": ["libs/forms"], - "@picsa/forecasts/*": ["apps/picsa-tools/forecasts/src/*"], "@picsa/i18n": ["libs/i18n/src/index.ts"], "@picsa/manual/*": ["apps/picsa-tools/manual-tool/*"], "@picsa/migrations": ["libs/migrations/index.ts"], From d08cea8d25a4989351b65f853cca8b693f938221 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 16:09:37 -0800 Subject: [PATCH 36/44] chore: code tidying --- .../app/components/location-select/location-select.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.ts b/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.ts index 2d9e5ce78..b22587d13 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/components/location-select/location-select.component.ts @@ -79,7 +79,6 @@ export class ForecastLocationSelectComponent { if (admin_level === 4) { update[5] = undefined; } - console.log('update location', update); this.configurationService.updateUserSettings({ location: update }); } From d8f427ba3ffdc402c2cbd4bd5f3bcadbe98c8c0b Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Wed, 26 Feb 2025 16:13:05 -0800 Subject: [PATCH 37/44] chore: remove legacy weather resources --- .../resources-tool/src/app/data/index.ts | 2 -- .../src/app/data/weather/files.ts | 16 ----------- .../src/app/data/weather/index.ts | 28 ++++--------------- 3 files changed, 5 insertions(+), 41 deletions(-) delete mode 100644 apps/picsa-tools/resources-tool/src/app/data/weather/files.ts diff --git a/apps/picsa-tools/resources-tool/src/app/data/index.ts b/apps/picsa-tools/resources-tool/src/app/data/index.ts index b67e475d7..2f5da300b 100644 --- a/apps/picsa-tools/resources-tool/src/app/data/index.ts +++ b/apps/picsa-tools/resources-tool/src/app/data/index.ts @@ -3,12 +3,10 @@ import { IResourceBase } from '../schemas/base'; import CROPS from './crops'; import { GENDER_RESOURCES } from './gender'; import PICSA_RESOURCES from './picsa'; -import WEATHER from './weather'; const byId: Record = { ...CROPS, ...GENDER_RESOURCES, - ...WEATHER, ...PICSA_RESOURCES, }; diff --git a/apps/picsa-tools/resources-tool/src/app/data/weather/files.ts b/apps/picsa-tools/resources-tool/src/app/data/weather/files.ts deleted file mode 100644 index 709c1cd4a..000000000 --- a/apps/picsa-tools/resources-tool/src/app/data/weather/files.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { IResourceFile } from '../../schemas'; - -interface IDownscaledForecast extends IResourceFile { - meta: { - locationIds: string[]; - }; -} - -// HACK - forecasts now populated from 'data' directory -// TODO - remove all legacy forecasts - -const downscaledForecasts: Record = {}; - -const otherForecasts: Record = {}; - -export default { downscaledForecasts, otherForecasts }; diff --git a/apps/picsa-tools/resources-tool/src/app/data/weather/index.ts b/apps/picsa-tools/resources-tool/src/app/data/weather/index.ts index edc6d2e3e..0f4961b2b 100644 --- a/apps/picsa-tools/resources-tool/src/app/data/weather/index.ts +++ b/apps/picsa-tools/resources-tool/src/app/data/weather/index.ts @@ -1,8 +1,4 @@ -import { FORECAST_COLLECTIONS, FORECAST_FILES } from '@picsa/data/resources/forecasts'; - -import { IResourceCollection, IResourceFile, IResourceLink } from '../../schemas'; -import { filterHashmap } from '../../utils/data.utils'; -import weatherFiles from './files'; +import { IResourceCollection, IResourceLink } from '../../schemas'; import { WEATHER_LINKS } from './links'; import { IWeatherLocation } from './locations'; import { MeteoBlueGenerator } from './meteoBlue'; @@ -29,15 +25,11 @@ const weatherResources: IResourceCollection = { id: 'weatherResources', type: 'collection', title: 'Weather Resources', + // TODO - add support for including direct link to app page instead of collection description: 'Local forecasts and meterological services', cover: { image: 'assets/resources/covers/weather.svg' }, priority: 6, - childResources: { - // collections: WEATHER_LOCATIONS.map((location) => `weatherResources_${location.id}`), - collections: [FORECAST_COLLECTIONS.forecasts_downscaled.id], - files: FORECAST_COLLECTIONS.forecasts.childResources.files, - links: Object.keys(WEATHER_LINKS), - }, + childResources: { collections: [], files: [], links: [] }, }; function generateLocationResources(location: IWeatherLocation) { @@ -45,10 +37,6 @@ function generateLocationResources(location: IWeatherLocation) { ...new WMOGenerator(location).links, ...new MeteoBlueGenerator(location).links, }; - const forecasts = { ...weatherFiles.downscaledForecasts, ...weatherFiles.otherForecasts }; - const files: Record = { - ...filterHashmap(forecasts, (r) => r.meta.locationIds.includes(location.id)), - }; const collection: IResourceCollection = { id: `weatherResources_${location.id}`, @@ -59,7 +47,7 @@ function generateLocationResources(location: IWeatherLocation) { parentCollection: 'weatherResources', childResources: { collections: [], - files: Object.keys(files), + files: [], links: Object.keys(links), }, filter: { countries: [location.countryCode] }, @@ -67,19 +55,13 @@ function generateLocationResources(location: IWeatherLocation) { return { [collection.id]: collection, ...links, - ...files, }; } // HACK - only included downscaled collection (files from main collection included in web) -const { forecasts_downscaled } = FORECAST_COLLECTIONS; +// const { forecasts_downscaled } = FORECAST_COLLECTIONS; export default { weatherResources, ...WEATHER_LINKS, - // ...localisedResources, - ...weatherFiles.downscaledForecasts, - ...weatherFiles.otherForecasts, - forecasts_downscaled, - ...FORECAST_FILES, }; From c253b1ae480ffe11a3c4faf95da25c4f67348e3a Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 27 Feb 2025 16:35:20 -0800 Subject: [PATCH 38/44] chore: climate functions tidying --- .../app/modules/climate/climate-api.mapping.ts | 2 +- .../pages/forecast/forecast.component.ts | 1 + .../functions/dashboard/forecast-db.ts | 4 ++-- .../functions/dashboard/forecast-storage.ts | 18 +++++++++++++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts index 560c779d2..91d304ed0 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/climate-api.mapping.ts @@ -110,7 +110,7 @@ export const ApiMapping = ( // setup metadata const fileBlob = data as any as Blob; const bucketId = country_code as string; - const folderPath = 'climate/forecasts'; + const folderPath = 'forecasts/daily'; // upload to storage const { fullPath } = await storage.putFile({ bucketId, fileBlob, filename: filepath, folderPath }); diff --git a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts index 8fba1bc93..f381581b4 100644 --- a/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts +++ b/apps/picsa-apps/dashboard/src/app/modules/climate/pages/forecast/forecast.component.ts @@ -155,6 +155,7 @@ export class ClimateForecastPageComponent { } private async downloadStorageFile(row: IForecastRow) { + // TODO - invoke cloud function instead of direct this.activeDownloads.update((v) => ({ ...v, [row.id]: 'pending' })); const storagePath = await this.service.loadFromAPI.forecast_file(row); this.activeDownloads.update((v) => ({ ...v, [row.id]: 'complete' })); diff --git a/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts b/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts index 38691bc59..aaa9b4849 100644 --- a/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts +++ b/apps/picsa-server/supabase/functions/dashboard/forecast-db.ts @@ -61,9 +61,9 @@ async function getCountryUpdates(country_code: string, query_prefix: string) { // filter results to only include api forecasts not present on db const apiForecasts = await getApiForecasts({ country_code, query_prefix }); const dbForecasts = await getDBForecasts({ country_code, query_prefix }); - const dbForecastIds = dbForecasts.map((v) => v.id); const newForecasts = apiForecasts.filter((v) => !dbForecastIds.includes(v.name)); + console.log(`${country_code}: ${newForecasts.length} New Forecasts`); if (newForecasts.length === 0) { return []; } @@ -92,12 +92,12 @@ async function getApiForecasts(query: { country_code: string; query_prefix?: str async function getDBForecasts(query: { country_code: string; query_prefix: string }) { const supabaseClient = getClient(); const { country_code, query_prefix } = query; - console.log('db query', query_prefix, country_code); const { data, error } = await supabaseClient .from('forecasts') .select('*') .like('id', `${query_prefix}%`) .eq('country_code', country_code) + .eq('forecast_type', 'daily') .order('id', { ascending: false }); if (error) { diff --git a/apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts b/apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts index 187b24341..46d538ed0 100644 --- a/apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts +++ b/apps/picsa-server/supabase/functions/dashboard/forecast-storage.ts @@ -32,13 +32,12 @@ class ForecastStorageUpdate { } async populateStorageFiles(params: IReqParams) { - const { limit = 5 } = params; + const { limit = 20 } = params; const pending = await this.listPendingFiles(limit); const updates: IDBClimateForecastRow[] = []; const errors: any[] = []; - // TODO - make parallel and allow failure - for (const { country_code, id } of pending) { + const promises = pending.map(async ({ country_code, id }) => { const { data, error } = await this.storeForecast(country_code, id); if (error) { errors.push(error); @@ -46,12 +45,17 @@ class ForecastStorageUpdate { if (data) { updates.push(data); } + }); + await Promise.allSettled(promises); + for (const error of errors) { + console.error(error); } + console.log(`[${updates.length}] storage files populates\n[${errors.length}] errors recorded`); return { data: updates, error: errors }; } /** Check all climate forecast db entries for any that are missing corresponding storage files */ - private async listPendingFiles(limit = 5) { + private async listPendingFiles(limit: number) { const query = this.table.select('*').is('storage_file', null).order('id', { ascending: false }).limit(limit); const { data, error } = await query; if (error) { @@ -78,9 +82,13 @@ class ForecastStorageUpdate { if (fileData) { // upload to supabase storage const contentType = apiResponse.headers.get('content-type') as string; + const year = id.substring(0, 4); + const month = id.substring(4, 6); + const day = id.substring(6, 8); + const filename = id.substring(9); const { data: uploadData, error: uploadError } = await supabaseClient.storage .from(country_code) - .upload(`climate/forecasts/${id}`, fileData, { contentType, upsert: true }); + .upload(`forecasts/daily/${year}/${month}/${day}/${filename}`, fileData, { contentType, upsert: true }); if (uploadError) { return { error: uploadError }; } From f0e44d6b967d20f93f5c47af3d3ba76599ac7435 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 27 Feb 2025 19:07:54 -0800 Subject: [PATCH 39/44] feat: forecast viewer component --- .../forecast-viewer.component.html | 18 ++++ .../forecast-viewer.component.scss | 3 + .../forecast-viewer.component.spec.ts | 22 +++++ .../forecast-viewer.component.ts | 96 +++++++++++++++++++ .../src/app/pages/forecast/forecast.page.html | 10 +- .../src/app/pages/forecast/forecast.page.scss | 32 ++++--- .../src/app/pages/forecast/forecast.page.ts | 31 ++---- 7 files changed, 168 insertions(+), 44 deletions(-) create mode 100644 apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html create mode 100644 apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.scss create mode 100644 apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.spec.ts create mode 100644 apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html new file mode 100644 index 000000000..80bff770e --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html @@ -0,0 +1,18 @@ +
+ +
+@if(errorMessage(); as errorMessage){ +
{{ errorMessage | translate }}
+} + +@if(pdfForecastData(); as pdfForecastData){ + +} + + +@if(htmlForecastData(); as htmlForecastData){ +
+} diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.scss b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.scss new file mode 100644 index 000000000..d7094f4b6 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.scss @@ -0,0 +1,3 @@ +:host { + @apply flex flex-col h-full bg-[white]; +} diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.spec.ts b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.spec.ts new file mode 100644 index 000000000..7ae665dc1 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ForecastViewerComponent } from './forecast-viewer.component'; + +describe('ForecastViewerComponent', () => { + let component: ForecastViewerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ForecastViewerComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(ForecastViewerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts new file mode 100644 index 000000000..8f50be369 --- /dev/null +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts @@ -0,0 +1,96 @@ +import { CommonModule } from '@angular/common'; +import { ChangeDetectionStrategy, Component, effect, input, OnDestroy, output, signal } from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; +import { IForecast } from '@picsa/forecasts/pages/forecast/schemas'; +import { PdfViewerComponent } from '@picsa/shared/features'; +import { PicsaTranslateModule } from '@picsa/shared/modules'; +import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; +import { RxDocument } from 'rxdb'; + +interface IViewerForecast { + _doc: RxDocument; + storage_file: string; +} + +@Component({ + selector: 'forecast-viewer', + imports: [CommonModule, MatButtonModule, MatIconModule, PdfViewerComponent, PicsaTranslateModule], + templateUrl: './forecast-viewer.component.html', + styleUrl: './forecast-viewer.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ForecastViewerComponent implements OnDestroy { + public forecast = input(); + + public closeClicked = output(); + + public errorMessage = signal(''); + + /** URI to forecast file data */ + private uri: string | null = null; + + /** Html forecasts will be parsed as SafeHtml for render in a div */ + public htmlForecastData = signal(undefined); + + /** PDF forecasts will be linked as URI for render in the component */ + public pdfForecastData = signal(undefined); + + constructor(private dbAttachmentService: PicsaDatabaseAttachmentService, private sanitizer: DomSanitizer) { + effect(async () => { + const forecast = this.forecast(); + this.clearForecastData(); + if (forecast) { + this.errorMessage.set(''); + this.openForecast(forecast); + } else { + this.errorMessage.set('Failed to open forecast'); + } + }); + } + + ngOnDestroy(): void { + this.clearForecastData(); + } + + private clearForecastData() { + this.pdfForecastData.set(undefined); + this.htmlForecastData.set(undefined); + if (this.uri) { + URL.revokeObjectURL(this.uri); + this.uri = null; + } + } + + /** Retrieve forecast attachment URI and call content render */ + private async openForecast(forecast: IViewerForecast) { + this.uri = await this.dbAttachmentService.getFileAttachmentURI(forecast._doc, forecast.storage_file); + const fileType = forecast.storage_file.split('.').pop()?.toLowerCase(); + if (this.uri && fileType) { + return this.renderForecastContent(this.uri, fileType as any); + } + } + + /** Handle rendering of forecast content from URI for different filetypes */ + private async renderForecastContent(uri: string, filetype: 'pdf' | 'html') { + // return pdf uri directly for render within picsa-pdf-reader component + if (filetype === 'pdf') { + this.pdfForecastData.set(uri); + return; + } + + // read html blob data directly and parse as safe-html + if (filetype === 'html') { + const res = await fetch(uri); + const html = await res.text(); + if (html) { + const safeHtml = this.sanitizer.bypassSecurityTrustHtml(html); + this.htmlForecastData.set(safeHtml); + } + return; + } + + this.errorMessage.set(`Forecast failed to open ${filetype}`); + } +} diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.html b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.html index 07772b674..75910470b 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.html +++ b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.html @@ -1,12 +1,6 @@
-
- @if(pdfSrc){ - - - - } +
+
diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.scss b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.scss index 55cb9c345..9b520bdc8 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.scss +++ b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.scss @@ -2,7 +2,20 @@ @apply border-solid capitalize p-2; } -.pdf-container { +.forecast-heading { + @apply border-solid border-0 border-b border-[var(--color-light)] text-center p-2 m-0 capitalize; +} +.download-container { + @apply pt-1 text-center bg-[var(--color-secondary-50)]; +} +.download-container[data-forecast-type='downscaled'] { + filter: hue-rotate(120deg); +} +.download-container[data-forecast-type='seasonal'] { + filter: hue-rotate(240deg); +} + +.viewer-container { position: fixed; z-index: 2; width: 100vw; @@ -10,23 +23,12 @@ top: 0; left: 0; } -.slide-in { + +.viewer-container.slide-in { transition: transform 0.3s ease-in-out; transform: translateY(100vh); } -.slide-in.active { +.viewer-container.slide-in.active { transform: translateY(0); } -.forecast-heading { - @apply border-solid border-0 border-b border-[var(--color-light)] text-center p-2 m-0 capitalize; -} -.download-container { - @apply pt-1 text-center bg-[var(--color-secondary-50)]; -} -.download-container[data-forecast-type='downscaled'] { - filter: hue-rotate(120deg); -} -.download-container[data-forecast-type='seasonal'] { - filter: hue-rotate(240deg); -} diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts index 0d05e239b..5511ba44d 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts @@ -1,9 +1,8 @@ import { CommonModule } from '@angular/common'; -import { Component, computed, OnDestroy, viewChildren } from '@angular/core'; +import { Component, computed, signal, viewChildren } from '@angular/core'; import { MatIcon } from '@angular/material/icon'; import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { ResourcesComponentsModule } from '@picsa/resources/src/app/components/components.module'; -import { PdfViewerComponent } from '@picsa/shared/features'; +import { ForecastViewerComponent } from '@picsa/forecasts/components/forecast-viewer/forecast-viewer.component'; import { PicsaTranslateModule } from '@picsa/shared/modules'; import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; @@ -28,16 +27,17 @@ interface IForecastSummary { imports: [ CommonModule, ForecastLocationSelectComponent, + ForecastViewerComponent, MatIcon, MatProgressBarModule, PicsaTranslateModule, - PdfViewerComponent, - ResourcesComponentsModule, SupabaseStorageDownloadComponent, ], }) -export class ForecastComponent implements OnDestroy { - public pdfSrc?: string; +export class ForecastComponent { + /** Forecast summary for display in forecast-viewer component */ + public viewerForecast = signal(undefined); + public viewerOpen = signal(false); public dailyForecasts = computed(() => this.generateForecastSummary(this.service.dailyForecastDocs())); public downscaledForecasts = computed(() => this.generateForecastSummary(this.service.downscaledForecastDocs())); @@ -51,10 +51,6 @@ export class ForecastComponent implements OnDestroy { constructor(private service: ForecastService, private dbAttachmentService: PicsaDatabaseAttachmentService) {} - ngOnDestroy() { - this.closeForecast(); - } - public async handleForecastClick(forecast: IForecastSummary) { // open downloaded forecast if (forecast.downloaded) { @@ -73,11 +69,9 @@ export class ForecastComponent implements OnDestroy { } } - public closeForecast() { - if (this.pdfSrc) { - URL.revokeObjectURL(this.pdfSrc); - } - this.pdfSrc = undefined; + private openForecast(forecast: IForecastSummary) { + this.viewerForecast.set(forecast); + this.viewerOpen.set(true); } private generateForecastSummary(docs: RxDocument[]): IForecastSummary[] { @@ -100,11 +94,6 @@ export class ForecastComponent implements OnDestroy { return summaries; } - private async openForecast(forecast: IForecastSummary) { - const uri = await this.dbAttachmentService.getFileAttachmentURI(forecast._doc, forecast.storage_file as string); - this.pdfSrc = uri || undefined; - } - private generateForecastLabel(storage_file: string) { const filename = storage_file.split('/').pop(); if (filename) { From b539fea1670c720f96daef5c05fa026c0d5be3ba Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 27 Feb 2025 19:25:36 -0800 Subject: [PATCH 40/44] chore: code tidying --- .../picsa-tools/forecasts-tool/src/app/app.component.spec.ts | 3 +-- .../components/forecast-viewer/forecast-viewer.component.ts | 2 +- .../forecasts-tool/src/app/pages/forecast/forecast.page.ts | 4 ++-- .../src/app/{pages/forecast => }/schemas/index.ts | 0 .../src/app/{pages/forecast => }/schemas/schema_v0.ts | 2 +- .../src/app/{pages/forecast => services}/forecast.service.ts | 5 +++-- .../src/app/{pages/forecast => types}/forecast.types.ts | 0 apps/picsa-tools/forecasts-tool/src/main.ts | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) rename apps/picsa-tools/forecasts-tool/src/app/{pages/forecast => }/schemas/index.ts (100%) rename apps/picsa-tools/forecasts-tool/src/app/{pages/forecast => }/schemas/schema_v0.ts (96%) rename apps/picsa-tools/forecasts-tool/src/app/{pages/forecast => services}/forecast.service.ts (97%) rename apps/picsa-tools/forecasts-tool/src/app/{pages/forecast => types}/forecast.types.ts (100%) diff --git a/apps/picsa-tools/forecasts-tool/src/app/app.component.spec.ts b/apps/picsa-tools/forecasts-tool/src/app/app.component.spec.ts index 04435226c..84542abd7 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/app.component.spec.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/app.component.spec.ts @@ -1,12 +1,11 @@ import { TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; -import { NxWelcomeComponent } from './nx-welcome.component'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [AppComponent, NxWelcomeComponent], + imports: [AppComponent], }).compileComponents(); }); diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts index 8f50be369..6dc8857db 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts @@ -3,7 +3,7 @@ import { ChangeDetectionStrategy, Component, effect, input, OnDestroy, output, s import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { IForecast } from '@picsa/forecasts/pages/forecast/schemas'; +import { IForecast } from '@picsa/forecasts/schemas'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts index 5511ba44d..538eaee85 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts @@ -9,8 +9,8 @@ import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/su import { RxDocument } from 'rxdb'; import { ForecastLocationSelectComponent } from '../../components/location-select/location-select.component'; -import { ForecastService } from './forecast.service'; -import { IForecast } from './schemas'; +import { IForecast } from '../../schemas'; +import { ForecastService } from '../../services/forecast.service'; interface IForecastSummary { _doc: RxDocument; diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/index.ts b/apps/picsa-tools/forecasts-tool/src/app/schemas/index.ts similarity index 100% rename from apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/index.ts rename to apps/picsa-tools/forecasts-tool/src/app/schemas/index.ts diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/schema_v0.ts b/apps/picsa-tools/forecasts-tool/src/app/schemas/schema_v0.ts similarity index 96% rename from apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/schema_v0.ts rename to apps/picsa-tools/forecasts-tool/src/app/schemas/schema_v0.ts index 357b48568..bcf917e56 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/schemas/schema_v0.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/schemas/schema_v0.ts @@ -2,7 +2,7 @@ import type { Database } from '@picsa/server-types'; import type { IPicsaCollectionCreator } from '@picsa/shared/services/core/db_v2'; import { RxJsonSchema } from 'rxdb'; -import { IForecastRow } from '../forecast.types'; +import { IForecastRow } from '../types/forecast.types'; const SCHEMA_VERSION = 0; diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.service.ts b/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts similarity index 97% rename from apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.service.ts rename to apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts index db2999c35..242489a80 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.service.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts @@ -8,8 +8,8 @@ import { SupabaseService, SupabaseStorageDownloadComponent } from '@picsa/shared import { isEqual } from '@picsa/utils/object.utils'; import { MangoQuerySelector, RxCollection, RxDocument } from 'rxdb'; -import { IForecastRow } from './forecast.types'; -import { FORECAST_COLLECTION, IForecast, SERVER_DB_MAPPING } from './schemas'; +import { FORECAST_COLLECTION, IForecast, SERVER_DB_MAPPING } from '../schemas'; +import { IForecastRow } from '../types/forecast.types'; @Injectable({ providedIn: 'root' }) export class ForecastService extends PicsaAsyncService { @@ -50,6 +50,7 @@ export class ForecastService extends PicsaAsyncService { effect(async () => { const { country_code, admin_4, admin_5 } = this.downscaledLocation(); + console.log('load downscaled forecasts', country_code, admin_4, admin_5); if (country_code && admin_4) { await this.ready(); this.loadDownscaledForecasts(country_code, admin_4, admin_5); diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.types.ts b/apps/picsa-tools/forecasts-tool/src/app/types/forecast.types.ts similarity index 100% rename from apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.types.ts rename to apps/picsa-tools/forecasts-tool/src/app/types/forecast.types.ts diff --git a/apps/picsa-tools/forecasts-tool/src/main.ts b/apps/picsa-tools/forecasts-tool/src/main.ts index 14afb2d0e..9dacd7f4c 100644 --- a/apps/picsa-tools/forecasts-tool/src/main.ts +++ b/apps/picsa-tools/forecasts-tool/src/main.ts @@ -1,6 +1,6 @@ import { bootstrapApplication } from '@angular/platform-browser'; -import { AppComponent } from './app/app.component'; import { appConfig } from './app/app.config'; +import { ForecastComponent } from './app/pages/forecast/forecast.page'; -bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err)); +bootstrapApplication(ForecastComponent, appConfig).catch((err) => console.error(err)); From 59e0a010b3291ded4c607ee518fd3add164d2bd7 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Thu, 27 Feb 2025 19:29:11 -0800 Subject: [PATCH 41/44] chore: code tidying --- .../forecasts-tool/src/app/services/forecast.service.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts b/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts index 242489a80..3a8782f0b 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts @@ -50,7 +50,6 @@ export class ForecastService extends PicsaAsyncService { effect(async () => { const { country_code, admin_4, admin_5 } = this.downscaledLocation(); - console.log('load downscaled forecasts', country_code, admin_4, admin_5); if (country_code && admin_4) { await this.ready(); this.loadDownscaledForecasts(country_code, admin_4, admin_5); @@ -70,11 +69,9 @@ export class ForecastService extends PicsaAsyncService { (v) => v.forecast_type === 'downscaled', (v) => v.country_code === country_code, (v) => v.location?.[0] === admin_4, + // if admin_5 not used will be undefined in both comparisons + (v) => v.location?.[1] === admin_5, ]; - // optional filter if admin_5 in specifed - if (admin_5) { - filters.push((v) => v.location?.[1] === admin_5); - } const forecasts = FORECASTS_DB.filter((v) => filters.every((fn) => fn(v))); const dbDocs = await this.hackStoreHardcodedData(forecasts); this.downscaledForecastDocs.set(dbDocs); From 35a3ff8a84b33cca3d30dfde1d0a590230bde12a Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 28 Feb 2025 09:58:29 -0800 Subject: [PATCH 42/44] perf: service optimisations --- .../forecast-viewer.component.ts | 3 +- .../src/app/pages/forecast/forecast.page.ts | 19 ++++++--- .../src/app/services/forecast.service.ts | 40 +++++++++++++------ .../picsa-tools/forecasts-tool/src/index.html | 2 +- 4 files changed, 45 insertions(+), 19 deletions(-) diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts index 6dc8857db..4c1cdc7f0 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.ts @@ -3,12 +3,13 @@ import { ChangeDetectionStrategy, Component, effect, input, OnDestroy, output, s import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; -import { IForecast } from '@picsa/forecasts/schemas'; import { PdfViewerComponent } from '@picsa/shared/features'; import { PicsaTranslateModule } from '@picsa/shared/modules'; import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { RxDocument } from 'rxdb'; +import { IForecast } from '../../schemas'; + interface IViewerForecast { _doc: RxDocument; storage_file: string; diff --git a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts index 538eaee85..9c1ed2d3d 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/pages/forecast/forecast.page.ts @@ -1,13 +1,13 @@ import { CommonModule } from '@angular/common'; -import { Component, computed, signal, viewChildren } from '@angular/core'; +import { Component, computed, effect, OnDestroy, signal, viewChildren } from '@angular/core'; import { MatIcon } from '@angular/material/icon'; import { MatProgressBarModule } from '@angular/material/progress-bar'; -import { ForecastViewerComponent } from '@picsa/forecasts/components/forecast-viewer/forecast-viewer.component'; +import { ConfigurationService } from '@picsa/configuration/src'; import { PicsaTranslateModule } from '@picsa/shared/modules'; -import { PicsaDatabaseAttachmentService } from '@picsa/shared/services/core/db_v2'; import { SupabaseStorageDownloadComponent } from '@picsa/shared/services/core/supabase'; import { RxDocument } from 'rxdb'; +import { ForecastViewerComponent } from '../../components/forecast-viewer/forecast-viewer.component'; import { ForecastLocationSelectComponent } from '../../components/location-select/location-select.component'; import { IForecast } from '../../schemas'; import { ForecastService } from '../../services/forecast.service'; @@ -34,7 +34,7 @@ interface IForecastSummary { SupabaseStorageDownloadComponent, ], }) -export class ForecastComponent { +export class ForecastComponent implements OnDestroy { /** Forecast summary for display in forecast-viewer component */ public viewerForecast = signal(undefined); public viewerOpen = signal(false); @@ -49,7 +49,16 @@ export class ForecastComponent { /** List of rendered SupabaseStorageDownload components for direct interaction */ private downloaders = viewChildren(SupabaseStorageDownloadComponent); - constructor(private service: ForecastService, private dbAttachmentService: PicsaDatabaseAttachmentService) {} + constructor(private service: ForecastService, configurationService: ConfigurationService) { + effect(() => { + const { location } = configurationService.userSettings(); + service.setForecastLocation(location); + }); + } + + ngOnDestroy() { + this.service.setForecastLocation(undefined); + } public async handleForecastClick(forecast: IForecastSummary) { // open downloaded forecast diff --git a/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts b/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts index 3a8782f0b..fc18b5f6d 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts +++ b/apps/picsa-tools/forecasts-tool/src/app/services/forecast.service.ts @@ -1,5 +1,5 @@ -import { computed, effect, Injectable, signal } from '@angular/core'; -import { ConfigurationService } from '@picsa/configuration/src'; +import { effect, Injectable, signal } from '@angular/core'; +import { IUserSettings } from '@picsa/configuration/src'; import { ICountryCode } from '@picsa/data'; import { FORECASTS_DB } from '@picsa/data/climate/forecasts'; import { PicsaAsyncService } from '@picsa/shared/services/asyncService.service'; @@ -11,19 +11,25 @@ import { MangoQuerySelector, RxCollection, RxDocument } from 'rxdb'; import { FORECAST_COLLECTION, IForecast, SERVER_DB_MAPPING } from '../schemas'; import { IForecastRow } from '../types/forecast.types'; +interface IDownscaledLocation { + country_code?: ICountryCode; + admin_4?: string; + admin_5?: string; +} + @Injectable({ providedIn: 'root' }) export class ForecastService extends PicsaAsyncService { + /** Toggle service effects on/off when pages are in view */ + public enabled = signal(false); + public dailyForecastDocs = signal[]>([], { equal: isEqual }); public seasonalForecastDocs = signal[]>([], { equal: isEqual }); public downscaledForecastDocs = signal[]>([], { equal: isEqual }); - private downscaledLocation = computed( - () => { - const { location } = this.configurationService.userSettings(); - return { country_code: location[2], admin_4: location[4], admin_5: location[5] }; - }, - { equal: isEqual } - ); + /** Track downscaled location for use in effects */ + private downscaledLocation = signal({}, { equal: isEqual }); + /** Track country location for use in effects */ + private countryLocation = signal(undefined); private get table() { return this.supabaseService.db.table('forecasts'); @@ -35,12 +41,11 @@ export class ForecastService extends PicsaAsyncService { constructor( private supabaseService: SupabaseService, private dbService: PicsaDatabase_V2_Service, - private dbAttachmentService: PicsaDatabaseAttachmentService, - private configurationService: ConfigurationService + private dbAttachmentService: PicsaDatabaseAttachmentService ) { super(); effect(async () => { - const { country_code } = this.configurationService.userSettings(); + const country_code = this.countryLocation(); if (country_code) { await this.ready(); this.loadDailyForecasts(country_code); @@ -64,6 +69,17 @@ export class ForecastService extends PicsaAsyncService { }); } + public setForecastLocation(location?: IUserSettings['location']) { + if (location) { + const country_code = location[2] as ICountryCode; + this.countryLocation.set(country_code); + this.downscaledLocation.set({ country_code, admin_4: location[4], admin_5: location[5] }); + } else { + this.countryLocation.set(undefined); + this.downscaledLocation.set({}); + } + } + private async loadDownscaledForecasts(country_code: string, admin_4: string, admin_5?: string) { const filters: ((v: IForecastRow) => boolean)[] = [ (v) => v.forecast_type === 'downscaled', diff --git a/apps/picsa-tools/forecasts-tool/src/index.html b/apps/picsa-tools/forecasts-tool/src/index.html index 9ee0fbeef..98fc7c810 100644 --- a/apps/picsa-tools/forecasts-tool/src/index.html +++ b/apps/picsa-tools/forecasts-tool/src/index.html @@ -8,6 +8,6 @@ - + From 715467517d58b98556a2df259d24973cc0d756a1 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 28 Feb 2025 10:06:43 -0800 Subject: [PATCH 43/44] chore: close button tidying --- .../forecast-viewer.component.html | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html index 80bff770e..85057cfd3 100644 --- a/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html +++ b/apps/picsa-tools/forecasts-tool/src/app/components/forecast-viewer/forecast-viewer.component.html @@ -1,18 +1,28 @@
- + + @if(!pdfForecastData()){ + + }
@if(errorMessage(); as errorMessage){
{{ errorMessage | translate }}
} @if(pdfForecastData(); as pdfForecastData){ - + + + } @if(htmlForecastData(); as htmlForecastData){
} + + + + + From 92a345d4a8a22e4887cc7bd839ac9577df9967e1 Mon Sep 17 00:00:00 2001 From: chrismclarke Date: Fri, 28 Feb 2025 10:32:37 -0800 Subject: [PATCH 44/44] chore: build fixes --- apps/picsa-tools/forecasts-tool/project.json | 2 +- apps/picsa-tools/forecasts-tool/tsconfig.json | 5 ++-- libs/i18n/assets/debug.json | 5 ---- libs/i18n/assets/global_en.json | 7 +---- libs/i18n/assets/ke_sw.json | 5 ---- libs/i18n/assets/mw_ny.json | 5 ---- libs/i18n/assets/tj_tg.json | 5 ---- libs/i18n/assets/zm_ny.json | 5 ---- libs/i18n/templates/_template.csv | 7 +---- libs/i18n/templates/_template.json | 28 +++---------------- libs/shared/tsconfig.lib.json | 1 + 11 files changed, 11 insertions(+), 64 deletions(-) diff --git a/apps/picsa-tools/forecasts-tool/project.json b/apps/picsa-tools/forecasts-tool/project.json index 541599bcb..a9b582a9d 100644 --- a/apps/picsa-tools/forecasts-tool/project.json +++ b/apps/picsa-tools/forecasts-tool/project.json @@ -31,7 +31,7 @@ { "type": "initial", "maximumWarning": "500kb", - "maximumError": "1mb" + "maximumError": "4mb" }, { "type": "anyComponentStyle", diff --git a/apps/picsa-tools/forecasts-tool/tsconfig.json b/apps/picsa-tools/forecasts-tool/tsconfig.json index ddb305021..2ffff8a9a 100644 --- a/apps/picsa-tools/forecasts-tool/tsconfig.json +++ b/apps/picsa-tools/forecasts-tool/tsconfig.json @@ -5,9 +5,10 @@ "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, + "noPropertyAccessFromIndexSignature": false, "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true + "noFallthroughCasesInSwitch": true, + "useDefineForClassFields": false }, "files": [], "include": [], diff --git a/libs/i18n/assets/debug.json b/libs/i18n/assets/debug.json index 5fdc95a15..5bf8d3c33 100644 --- a/libs/i18n/assets/debug.json +++ b/libs/i18n/assets/debug.json @@ -15,7 +15,6 @@ "All Submitted": "•All Submitted•", "Analyse": "•Analyse•", "and": "•and•", - "Annual Forecast": "•Annual Forecast•", "App": "•App•", "Apply Fertiliser": "•Apply Fertiliser•", "apply fertiliser": "•apply fertiliser•", @@ -99,8 +98,6 @@ "Download All": "•Download All•", "Download the PICSA Manual": "•Download the PICSA Manual•", "Downloaded": "•Downloaded•", - "Downscaled Forecast": "•Downscaled Forecast•", - "Downscaled Forecasts": "•Downscaled Forecasts•", "Draw Here": "•Draw Here•", "ducks": "•ducks•", "During the season": "•During the season•", @@ -136,7 +133,6 @@ "fish": "•fish•", "fodder for livestock": "•fodder for livestock•", "For Sale": "•For Sale•", - "Forecast": "•Forecast•", "Forecasts": "•Forecasts•", "Forms": "•Forms•", "Frequency of Extreme": "•Frequency of Extreme•", @@ -309,7 +305,6 @@ "Season Crops": "•Season Crops•", "Seasonal Calendar": "•Seasonal Calendar•", "Seasonal forecast": "•Seasonal forecast•", - "Seasonal Forecast": "•Seasonal Forecast•", "Seasonal Rainfall": "•Seasonal Rainfall•", "Seasonal rainfall is defined as the total rain recorded from the start of the season until the end of the season": "•Seasonal rainfall is defined as the total rain recorded from the start of the season until the end of the season•", "Seasonal Total Rainfall (mm)": "•Seasonal Total Rainfall (mm)•", diff --git a/libs/i18n/assets/global_en.json b/libs/i18n/assets/global_en.json index b4b6a5922..d5fe8c7d4 100644 --- a/libs/i18n/assets/global_en.json +++ b/libs/i18n/assets/global_en.json @@ -123,10 +123,7 @@ "Start of Season": "Start of Season", "Start of season is defined as the first occasion (from 1st October) with more than 25mm in a 3 day period and no dry spell of 10 days or more within the following 30 days": "Start of season is defined as the first occasion (from 1st October) with more than 25mm in a 3 day period and no dry spell of 10 days or more within the following 30 days", "Analyse": "Analyse", - "Annual Forecast": "Annual Forecast", "Chart": "Chart", - "Downscaled Forecast": "Downscaled Forecast", - "Forecast": "Forecast", "Line": "Line", "Print Version": "Print Version", "Select a site": "Select a site", @@ -158,13 +155,11 @@ "Climate": "Climate", "Demo": "Demo", "District": "District", - "Downscaled Forecasts": "Downscaled Forecasts", "Draw Here": "Draw Here", "Edit Profiles": "Edit Profiles", "Extension": "Extension", "Farmer": "Farmer", "First 3 days receiving rainfall amount of 20mm and not followed by 9-day dry spell for the next 21 days": "First 3 days receiving rainfall amount of 20mm and not followed by 9-day dry spell for the next 21 days", - "Forecasts": "Forecasts", "I'm a farmer": "I'm a farmer", "I'm an extension worker": "I'm an extension worker", "Name": "Name", @@ -176,7 +171,6 @@ "Redo": "Redo", "Resource Allocation Map": "Resource Allocation Map", "Seasonal Calendar": "Seasonal Calendar", - "Seasonal Forecast": "Seasonal Forecast", "Seasonal total rainfall calculated between the defined start and defined end of the season": "Seasonal total rainfall calculated between the defined start and defined end of the season", "Testimonials": "Testimonials", "Tool": "Tool", @@ -300,6 +294,7 @@ "Resources": "Resources", "Training": "Training", "Click on the button below to retry": "Click on the button below to retry", + "Forecasts": "Forecasts", "Privacy Policy": "Privacy Policy", "Reload": "Reload", "Something went wrong...": "Something went wrong...", diff --git a/libs/i18n/assets/ke_sw.json b/libs/i18n/assets/ke_sw.json index 6596ac167..43b35410b 100644 --- a/libs/i18n/assets/ke_sw.json +++ b/libs/i18n/assets/ke_sw.json @@ -15,7 +15,6 @@ "All Submitted": "•All Submitted•", "Analyse": "•Analyse•", "and": "•and•", - "Annual Forecast": "•Annual Forecast•", "App": "•App•", "Apply Fertiliser": "•Apply Fertiliser•", "apply fertiliser": "•apply fertiliser•", @@ -99,8 +98,6 @@ "Download All": "•Download All•", "Download the PICSA Manual": "•Download the PICSA Manual•", "Downloaded": "•Downloaded•", - "Downscaled Forecast": "•Downscaled Forecast•", - "Downscaled Forecasts": "•Downscaled Forecasts•", "Draw Here": "•Draw Here•", "ducks": "•ducks•", "During the season": "•During the season•", @@ -136,7 +133,6 @@ "fish": "•fish•", "fodder for livestock": "•fodder for livestock•", "For Sale": "•For Sale•", - "Forecast": "•Forecast•", "Forecasts": "•Forecasts•", "Forms": "•Forms•", "Frequency of Extreme": "•Frequency of Extreme•", @@ -309,7 +305,6 @@ "Season Crops": "•Season Crops•", "Seasonal Calendar": "•Seasonal Calendar•", "Seasonal forecast": "•Seasonal forecast•", - "Seasonal Forecast": "•Seasonal Forecast•", "Seasonal Rainfall": "Mvua ya msimu", "Seasonal rainfall is defined as the total rain recorded from the start of the season until the end of the season": "Mvua ya msimu hufafanuliwa kama mvua ya jumla iliyoandikwa tangu mwanzo wa msimu mpaka mwisho wa msimu", "Seasonal Total Rainfall (mm)": "•Seasonal Total Rainfall (mm)•", diff --git a/libs/i18n/assets/mw_ny.json b/libs/i18n/assets/mw_ny.json index 887ae69fc..c5894f291 100644 --- a/libs/i18n/assets/mw_ny.json +++ b/libs/i18n/assets/mw_ny.json @@ -15,7 +15,6 @@ "All Submitted": "Zonse Zotumizidwa", "Analyse": "Kuzukuta", "and": "ndi", - "Annual Forecast": "•Annual Forecast•", "App": "•App•", "Apply Fertiliser": "kuthira feteleza", "apply fertiliser": "kuthira feteleza", @@ -99,8 +98,6 @@ "Download All": "Tengani zonse kuchera pa intaneti", "Download the PICSA Manual": "Tengani Bukhu la PICSA kuchokera pa intaneti", "Downloaded": "Zotengedwa pa intaneti", - "Downscaled Forecast": "•Downscaled Forecast•", - "Downscaled Forecasts": "Ulosi wa dera laling'ono", "Draw Here": "Jambulani apa", "ducks": "abakha", "During the season": "Mkatikati mwa sizoni/nyengo", @@ -136,7 +133,6 @@ "fish": "nsomba", "fodder for livestock": "chakudya cha ziweto", "For Sale": "•For Sale•", - "Forecast": "Ulosi", "Forecasts": "Maulosi", "Forms": "mafomu", "Frequency of Extreme": "Kachulukidwe ka kupyola muyeso", @@ -309,7 +305,6 @@ "Season Crops": "Mbewu za pa chaka", "Seasonal Calendar": "Kalendala ya nyengo", "Seasonal forecast": "ulosi wa nyengo", - "Seasonal Forecast": "ulosi wa nyengo", "Seasonal Rainfall": "Mvula ya mu nyengo", "Seasonal rainfall is defined as the total rain recorded from the start of the season until the end of the season": "Mvula ya mu nyengo imatanthauza mvula yonse yomwe yalembedwa kuti yagwa kuyambira pachiyambi mpaka pa mapeto a nyengoyo", "Seasonal Total Rainfall (mm)": "Mvula yathu yathunthu ya nyengo yapadera (mm)", diff --git a/libs/i18n/assets/tj_tg.json b/libs/i18n/assets/tj_tg.json index 7d21ca28a..6c4f1e4e9 100644 --- a/libs/i18n/assets/tj_tg.json +++ b/libs/i18n/assets/tj_tg.json @@ -15,7 +15,6 @@ "All Submitted": "•All Submitted•", "Analyse": "•Analyse•", "and": "•and•", - "Annual Forecast": "•Annual Forecast•", "App": "•App•", "Apply Fertiliser": "•Apply Fertiliser•", "apply fertiliser": "Ба кор нуриҳо муроҷиат кунед", @@ -99,8 +98,6 @@ "Download All": "•Download All•", "Download the PICSA Manual": "•Download the PICSA Manual•", "Downloaded": "•Downloaded•", - "Downscaled Forecast": "•Downscaled Forecast•", - "Downscaled Forecasts": "•Downscaled Forecasts•", "Draw Here": "•Draw Here•", "ducks": "мурғ", "During the season": "•During the season•", @@ -136,7 +133,6 @@ "fish": "моҳӣ", "fodder for livestock": "хӯроки чорво", "For Sale": "•For Sale•", - "Forecast": "•Forecast•", "Forecasts": "•Forecasts•", "Forms": "•Forms•", "Frequency of Extreme": "•Frequency of Extreme•", @@ -309,7 +305,6 @@ "Season Crops": "•Season Crops•", "Seasonal Calendar": "•Seasonal Calendar•", "Seasonal forecast": "•Seasonal forecast•", - "Seasonal Forecast": "•Seasonal Forecast•", "Seasonal Rainfall": "Боришоти мавсимӣ", "Seasonal rainfall is defined as the total rain recorded from the start of the season until the end of the season": "Боришоти мавсимӣ ҳамчун борони умумии аз оғози мавсим то охири мавсим муайян карда мешавад", "Seasonal Total Rainfall (mm)": "•Seasonal Total Rainfall (mm)•", diff --git a/libs/i18n/assets/zm_ny.json b/libs/i18n/assets/zm_ny.json index 973857652..ee4aface8 100644 --- a/libs/i18n/assets/zm_ny.json +++ b/libs/i18n/assets/zm_ny.json @@ -15,7 +15,6 @@ "All Submitted": "Zonse Zaperekedwa", "Analyse": "Fufuza", "and": "ndipo", - "Annual Forecast": "•Annual Forecast•", "App": "•App•", "Apply Fertiliser": "thirani fatatleza", "apply fertiliser": "thirani fatatleza", @@ -99,8 +98,6 @@ "Download All": "Tsitsani Zonse", "Download the PICSA Manual": "Tsitsani Buku la PICSA", "Downloaded": "Zatsitsidwa", - "Downscaled Forecast": "•Downscaled Forecast•", - "Downscaled Forecasts": "Zolosera/zanyengo Zochepetsedwa", "Draw Here": "Jambulani Apa", "ducks": "abakha", "During the season": "Mkati mwa Nyengo", @@ -136,7 +133,6 @@ "fish": "nsomba", "fodder for livestock": "chakudya cha ziweto", "For Sale": "Zogullitsidwa", - "Forecast": "Chisonyezo cha nyengo", "Forecasts": "Zolosera/zanyengo", "Forms": "mafomu", "Frequency of Extreme": "Kuchuluka kopitilira muyeso", @@ -309,7 +305,6 @@ "Season Crops": "Mbeu Zanyengo", "Seasonal Calendar": "Kalenda ya Nyengo", "Seasonal forecast": "Uthenga wa zanyengo", - "Seasonal Forecast": "Uthenga wa zanyengo", "Seasonal Rainfall": "Mvula ya mu nyengo", "Seasonal rainfall is defined as the total rain recorded from the start of the season until the end of the season": "Mvula ya mu nyengo imatanthauza mvula yonse yomwe yalembedwa kuti yagwa kuyambira pachiyambi mpaka pa mapeto a nyengoyo", "Seasonal Total Rainfall (mm)": "Mvula yathu yathunthu ya nyengo yapadera (mm)", diff --git a/libs/i18n/templates/_template.csv b/libs/i18n/templates/_template.csv index d905c3126..b41877734 100644 --- a/libs/i18n/templates/_template.csv +++ b/libs/i18n/templates/_template.csv @@ -123,10 +123,7 @@ tool,context,text "climate","chart","Start of Season" "climate","chart","Start of season is defined as the first occasion (from 1st October) with more than 25mm in a 3 day period and no dry spell of 10 days or more within the following 30 days" "climate",,"Analyse" -"climate",,"Annual Forecast" "climate",,"Chart" -"climate",,"Downscaled Forecast" -"climate",,"Forecast" "climate",,"Line" "climate",,"Print Version" "climate",,"Select a site" @@ -158,13 +155,11 @@ tool,context,text "common",,"Climate" "common",,"Demo" "common",,"District" -"common",,"Downscaled Forecasts" "common",,"Draw Here" "common",,"Edit Profiles" "common",,"Extension" "common",,"Farmer" "common",,"First 3 days receiving rainfall amount of 20mm and not followed by 9-day dry spell for the next 21 days" -"common",,"Forecasts" "common",,"I'm a farmer" "common",,"I'm an extension worker" "common",,"Name" @@ -176,7 +171,6 @@ tool,context,text "common",,"Redo" "common",,"Resource Allocation Map" "common",,"Seasonal Calendar" -"common",,"Seasonal Forecast" "common",,"Seasonal total rainfall calculated between the defined start and defined end of the season" "common",,"Testimonials" "common",,"Tool" @@ -300,6 +294,7 @@ tool,context,text "extension-content",,"Resources" "extension-content",,"Training" "extension",,"Click on the button below to retry" +"extension",,"Forecasts" "extension",,"Privacy Policy" "extension",,"Reload" "extension",,"Something went wrong..." diff --git a/libs/i18n/templates/_template.json b/libs/i18n/templates/_template.json index 00384dfc2..0faf9ef7f 100644 --- a/libs/i18n/templates/_template.json +++ b/libs/i18n/templates/_template.json @@ -574,22 +574,10 @@ "text": "Analyse", "tool": "climate" }, - { - "text": "Annual Forecast", - "tool": "climate" - }, { "text": "Chart", "tool": "climate" }, - { - "text": "Downscaled Forecast", - "tool": "climate" - }, - { - "text": "Forecast", - "tool": "climate" - }, { "text": "Line", "tool": "climate" @@ -721,10 +709,6 @@ "text": "District", "tool": "common" }, - { - "text": "Downscaled Forecasts", - "tool": "common" - }, { "text": "Draw Here", "tool": "common" @@ -745,10 +729,6 @@ "text": "First 3 days receiving rainfall amount of 20mm and not followed by 9-day dry spell for the next 21 days", "tool": "common" }, - { - "text": "Forecasts", - "tool": "common" - }, { "text": "I'm a farmer", "tool": "common" @@ -793,10 +773,6 @@ "text": "Seasonal Calendar", "tool": "common" }, - { - "text": "Seasonal Forecast", - "tool": "common" - }, { "text": "Seasonal total rainfall calculated between the defined start and defined end of the season", "tool": "common" @@ -1326,6 +1302,10 @@ "text": "Click on the button below to retry", "tool": "extension" }, + { + "text": "Forecasts", + "tool": "extension" + }, { "text": "Privacy Policy", "tool": "extension" diff --git a/libs/shared/tsconfig.lib.json b/libs/shared/tsconfig.lib.json index b3f90c22f..388cffe8c 100644 --- a/libs/shared/tsconfig.lib.json +++ b/libs/shared/tsconfig.lib.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "../../dist/out-tsc", "declaration": true, + "noPropertyAccessFromIndexSignature": false, "types": [] }, "include": ["**/*.ts"],