From bedef43e130bef359446370a50fd7845bd77bff2 Mon Sep 17 00:00:00 2001 From: Corentin Date: Wed, 10 Sep 2025 00:22:48 +0900 Subject: [PATCH] Add osm-map-nano --- .gitattributes | 1 + .gitignore | 2 + .npmrc | 2 + data/shibuya.osm | 3 + data/test.png | 3 + eslint.config.js | 24 ++ kousen_home.osm | 34 +++ package.json | 28 ++ packages/osm-map-nano/index.js | 12 + packages/osm-map-nano/package.json | 13 + packages/osm-map-nano/src/Mapper.ts | 313 +++++++++++++++++++++ packages/osm-map-nano/src/index.ts | 5 + packages/osm-map-nano/tests/test.ts | 14 + packages/osm-map-nano/tsconfig.json | 3 + packages/osm-map-nano/tsconfig.tsbuildinfo | 1 + scripts/build.js | 78 +++++ scripts/server.js | 66 +++++ scripts/test.cjs | 67 +++++ scripts/test_template.html | 20 ++ scripts/tmpfs_dirs.sh | 12 + tsconfig.json | 37 +++ tsconfig.tsbuildinfo | 1 + 22 files changed, 739 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 data/shibuya.osm create mode 100644 data/test.png create mode 100644 eslint.config.js create mode 100644 kousen_home.osm create mode 100644 package.json create mode 100644 packages/osm-map-nano/index.js create mode 100644 packages/osm-map-nano/package.json create mode 100644 packages/osm-map-nano/src/Mapper.ts create mode 100644 packages/osm-map-nano/src/index.ts create mode 100644 packages/osm-map-nano/tests/test.ts create mode 100644 packages/osm-map-nano/tsconfig.json create mode 100644 packages/osm-map-nano/tsconfig.tsbuildinfo create mode 100644 scripts/build.js create mode 100644 scripts/server.js create mode 100644 scripts/test.cjs create mode 100644 scripts/test_template.html create mode 100755 scripts/tmpfs_dirs.sh create mode 100644 tsconfig.json create mode 100644 tsconfig.tsbuildinfo diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..a79f214 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +data/* filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48912d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +node_modules \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..7b4340d --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +omit[] = "optional" +package-lock = false \ No newline at end of file diff --git a/data/shibuya.osm b/data/shibuya.osm new file mode 100644 index 0000000..328c67d --- /dev/null +++ b/data/shibuya.osm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91171d850321cbb702a2c8eabfd981631c9e0ee2ec4fd2bc51118b5e414b283e +size 1644579 diff --git a/data/test.png b/data/test.png new file mode 100644 index 0000000..2c34856 --- /dev/null +++ b/data/test.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:81c53d6ee793b0f37c8d8a428f1de33dab5b92a789705c74bd90c04737d08464 +size 304728 diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..d0374dd --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from 'eslint/config'; +import tsparser from '@typescript-eslint/parser'; +import stylistic from '@stylistic/eslint-plugin'; + +export default defineConfig([ + { + files: ['**/*.js', '**/*.cjs', '**/*.ts'], + languageOptions: { + parser: tsparser, + sourceType: 'module', + }, + ignores: ['**/dist/*', '**/*.min.js'], + plugins: { + '@stylistic': stylistic + }, + rules: { + '@stylistic/array-bracket-spacing' : ['error', 'never'], + '@stylistic/arrow-spacing' : ['error', {'before': true, 'after': true}], + '@stylistic/block-spacing' : ['error', 'always'], + '@stylistic/quotes' : ['error', 'single'], + '@stylistic/semi' : ['error', 'always'] + } + } +]); diff --git a/kousen_home.osm b/kousen_home.osm new file mode 100644 index 0000000..f90673d --- /dev/null +++ b/kousen_home.osm @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..7465ed0 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "js-osm", + "version": "0.0.1", + "description": "", + "license": "LGPL-3.0-or-later", + "author": "", + "type": "module", + "scripts": { + "prebuild": "./scripts/tmpfs_dirs.sh", + "build": "tsc --build && node scripts/build.js", + "clean": "rm -rf build/*", + "test": "node scripts/test.cjs" + }, + "workspaces": [ + "packages/*" + ], + "devDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.50.1", + "@stylistic/eslint-plugin": "^5.3.1", + "@typescript-eslint/eslint-plugin": "^8.42.0", + "eslint": "^9.34.0", + "osm-map-nao": "./packages/osm-map-nano", + "rollup": "^4.50.1", + "selenium-webdriver": "^4.35.0", + "typescript": "^5.9.2", + "typescript-eslint": "^8.42.0" + } +} diff --git a/packages/osm-map-nano/index.js b/packages/osm-map-nano/index.js new file mode 100644 index 0000000..29d6203 --- /dev/null +++ b/packages/osm-map-nano/index.js @@ -0,0 +1,12 @@ +'use strict'; + +import { Mapper } from './src/Mapper.js'; + +module.exports = {Mapper}; + +// module.exports = require('./src/index.js'); + +// if(process.env.NODE_ENV === 'production') +// module.exports = require('./dist/index.min.cjs'); +// else +// module.exports = require('./dist/index.cjs'); \ No newline at end of file diff --git a/packages/osm-map-nano/package.json b/packages/osm-map-nano/package.json new file mode 100644 index 0000000..b39ff32 --- /dev/null +++ b/packages/osm-map-nano/package.json @@ -0,0 +1,13 @@ +{ + "name": "osm-map-nano", + "version": "0.0.1", + "description": "", + "license": "LGPL-3.0-or-later", + "author": "", + "type": "module", + "main": "src/index.js", + "scripts": { + "lint": "eslint packages/*", + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/packages/osm-map-nano/src/Mapper.ts b/packages/osm-map-nano/src/Mapper.ts new file mode 100644 index 0000000..05bbeea --- /dev/null +++ b/packages/osm-map-nano/src/Mapper.ts @@ -0,0 +1,313 @@ +namespace OSM +{ + export type Tags = { + [key: string]: string + }; + + export class Bounds { + constructor( + public max_lat: number, + public max_lon: number, + public min_lat: number, + public min_lon: number) {} + } + + export class Member { + constructor( + public ref: number, + public role: string, + public type: string) {} + } + + export class Node { + constructor( + public id: number, + public lat: number, + public lon: number, + public tags: Tags, + public uid: number, + public version: number, + public visible: boolean) {} + } + + export class Relation { + constructor( + public id: number, + public members: Member[], + public tags: Tags, + public uid: number, + public version: number, + public visible: boolean) {} + } + + export class Way { + constructor( + public id: number, + public nodes: Node[], + public tags: Tags, + public uid: number, + public version: number, + public visible: boolean) {} + } +} + +interface MapperOptions { + bounds?: OSM.Bounds, + canvas?: HTMLCanvasElement +} + +export class Mapper +{ + current_bounds: OSM.Bounds | null; + data_bounds: OSM.Bounds | null; + nodes: Map = new Map(); + relations: Map = new Map(); + ways: Map = new Map(); + + canvas: HTMLCanvasElement; + zoom_level: number = 0; + zoom_scale: number = 0; + + private readonly DEG2RAD: number = Math.PI / 180; + private readonly PI_4: number = Math.PI / 4; + + constructor({bounds, canvas}: MapperOptions = {}) + { + this.current_bounds = bounds || null; + this.data_bounds = bounds || null; + this.canvas = canvas || document.createElement('canvas'); + } + + private getXMLTags(element: Element): OSM.Tags + { + let tags: OSM.Tags = {}; + element.querySelectorAll('tag').forEach(tag => { + tags[tag.getAttribute('k') || ''] = tag.getAttribute('v') || ''; + }); + return tags; + } + + private getXMLVisible(element: Element): boolean + { + const visible: string = element.getAttribute('visible') || 'false'; + return visible === '1' || visible.toLowerCase() === 'true'; + } + + public loadXMLData(xml_data: string) + { + const parser = new DOMParser(); + const doc = parser.parseFromString(xml_data, 'application/xml'); + const doc_bounds = doc.querySelector('bounds'); + if(doc_bounds !== null) + { + this.data_bounds = new OSM.Bounds( + parseFloat(doc_bounds.getAttribute('maxlat') || '0'), + parseFloat(doc_bounds.getAttribute('maxlon') || '0'), + parseFloat(doc_bounds.getAttribute('minlat') || '0'), + parseFloat(doc_bounds.getAttribute('minlon') || '0') + ); + this.current_bounds = this.data_bounds; + } + doc.querySelectorAll('node').forEach(doc_node => { + const node_id: number = parseInt(doc_node.getAttribute('id') || '0'); + this.nodes.set(node_id, new OSM.Node( + node_id, + parseFloat(doc_node.getAttribute('lat') || '0'), + parseFloat(doc_node.getAttribute('lon') || '0'), + this.getXMLTags(doc_node), + parseFloat(doc_node.getAttribute('uid') || '0'), + parseFloat(doc_node.getAttribute('version') || '0'), + this.getXMLVisible(doc_node) + )); + }); + + doc.querySelectorAll('way').forEach(doc_way => { + const way_id: number = parseInt(doc_way.getAttribute('id') || '0'); + let nodes: OSM.Node[] = []; + doc_way.querySelectorAll('nd').forEach(way_nd => { + const node_id: number = parseInt(way_nd.getAttribute('ref') || '0'); + const node = this.nodes.get(node_id); + if(node === undefined) + throw `Invalid data : reference to non existent Node ${node_id} from Way ${way_id}`; + nodes.push(node); + }); + this.ways.set(way_id, new OSM.Way( + way_id, + nodes, + this.getXMLTags(doc_way), + parseFloat(doc_way.getAttribute('uid') || '0'), + parseFloat(doc_way.getAttribute('version') || '0'), + this.getXMLVisible(doc_way) + )); + }); + + doc.querySelectorAll('relation').forEach(doc_relation => { + const relation_id: number = parseInt(doc_relation.getAttribute('id') || '0'); + let members: OSM.Member[] = []; + doc_relation.querySelectorAll('member').forEach(member => { + members.push(new OSM.Member( + parseInt(member.getAttribute('ref') || '0'), + member.getAttribute('role') || '', + member.getAttribute('rype') || '')); + }); + this.relations.set(relation_id, new OSM.Relation( + relation_id, + members, + this.getXMLTags(doc_relation), + parseFloat(doc_relation.getAttribute('uid') || '0'), + parseFloat(doc_relation.getAttribute('version') || '0'), + this.getXMLVisible(doc_relation) + )); + }); + } + + private get_map_raw_coords(lon: number, lat: number): [number, number] + { + return [ + this.zoom_scale * lon * this.DEG2RAD, + this.zoom_scale * Math.log(Math.tan(this.PI_4 + (lat * this.DEG2RAD / 2))) + ]; + } + + + public draw(target_width: number, canvas?: HTMLCanvasElement) + { + if(canvas) + this.canvas = canvas; + if(this.current_bounds === null || this.data_bounds === null) + return; + + this.zoom_level = Math.ceil(-Math.log2( + ((this.current_bounds.max_lon - this.current_bounds.min_lon) * 2 * Math.PI) / target_width)); + this.zoom_scale = (2**this.zoom_level) * target_width / (2 * Math.PI); + const [min_x, min_y] = this.get_map_raw_coords(this.current_bounds.min_lon, this.current_bounds.min_lat); + const [max_x, max_y] = this.get_map_raw_coords(this.current_bounds.max_lon, this.current_bounds.max_lat); + const width = max_x - min_x; + const height = max_y - min_y; + + this.canvas.width = width; + this.canvas.height = height; + let ctx = this.canvas.getContext('2d', {alpha: false}) as CanvasRenderingContext2D; + + const get_map_coords: (lon: number, lat:number) => [number, number] = (lon: number, lat: number) => { + const [x, y] = this.get_map_raw_coords(lon, lat); + return [Math.floor(x - min_x), Math.floor(max_y - y)]; + }; + + const background_color = 'rgb(235, 235, 235)'; + ctx.fillStyle = background_color; + ctx.fillRect(0, 0, width, height); + + const draw_way_polygon = (way: OSM.Way, color: string, outline: string | null = null, + width: number = 1) => { + let path_len: number = 0; + let previous_coords: [number, number] | null = null; + let path = new Path2D(); + for(const node of way.nodes) + { + const coords = get_map_coords(node.lon, node.lat); + if(previous_coords === null || previous_coords[0] !== coords[0] || previous_coords[1] !== coords[1]) + { + if(previous_coords === null) + path.moveTo(coords[0], coords[1]); + else + path.lineTo(coords[0], coords[1]); + path_len += 1; + previous_coords = coords; + } + } + path.closePath(); + if(path_len > 2) + { + ctx.fillStyle = color; + ctx.fill(path); + if(outline !== null) + { + ctx.lineWidth = width; + ctx.stroke(path); + } + } + }; + + const draw_way_line = (way: OSM.Way, width: number, color: string) => { + let path_len: number = 0; + let previous_coords: [number, number] | null = null; + let path = new Path2D(); + for(const node of way.nodes) + { + const coords = get_map_coords(node.lon, node.lat); + if(previous_coords === null || previous_coords[0] !== coords[0] || previous_coords[1] !== coords[1]) + { + if(previous_coords === null) + path.moveTo(coords[0], coords[1]); + else + path.lineTo(coords[0], coords[1]); + path_len += 1; + previous_coords = coords; + } + } + if(path_len > 1) + { + ctx.lineWidth = width; + ctx.strokeStyle = color; + ctx.lineJoin = 'round'; + ctx.stroke(path); + } + }; + + const bridge_outline: string = 'rgb(80, 80, 80)'; + const thickest_stroke: number = Math.floor(Math.min(width, height) / 32); + + this.ways.forEach(way => { + if(way.tags['building'] !== undefined) + { + draw_way_polygon(way, 'rgb(190, 180, 160)', 'rgb(120, 120, 120)'); + } + }); + + this.ways.forEach(way => { + if(way.tags['highway'] !== undefined) + { + switch(way.tags['highway']) + { + case 'motorway': + case 'motorway_link': + draw_way_line(way, thickest_stroke, 'rgb(40, 20, 10)'); + draw_way_line(way, thickest_stroke * 0.9, 'rgb(220, 160, 160)'); + break; + case 'trunk': + case 'trunk_link': + draw_way_line(way, Math.floor(thickest_stroke * 0.9), + (way.tags['bridge'] !== undefined) ? bridge_outline : 'rgb(180, 120, 50)'); + draw_way_line(way, Math.floor(thickest_stroke * 0.8),'rgb(240, 170, 150)'); + break; + case 'primary': + case 'primary_link': + draw_way_line(way, Math.floor(thickest_stroke * 0.8), + (way.tags['bridge'] !== undefined) ? bridge_outline : 'rgb(150, 80, 60)'); + draw_way_line(way, Math.floor(thickest_stroke * 0.7),'rgb(245, 215, 150)'); + break; + case 'secondary': + case 'secondary_link': + draw_way_line(way, Math.floor(thickest_stroke * 0.6), + (way.tags['bridge'] !== undefined) ? bridge_outline : 'rgb(50, 40, 20)'); + draw_way_line(way, Math.floor(thickest_stroke * 0.5),'rgb(252, 250, 200)'); + break; + case 'tertiary': + case 'tertiary_link': + draw_way_line(way, Math.floor(thickest_stroke * 0.4), + (way.tags['bridge'] !== undefined) ? bridge_outline : 'rgb(160, 160, 160)'); + draw_way_line(way, Math.floor(thickest_stroke * 0.3),'rgb(245, 245, 245)'); + break; + case 'residential': + case 'unclassified': + case 'road': + draw_way_line(way, Math.floor(thickest_stroke * 0.35), + (way.tags['bridge'] !== undefined) ? bridge_outline : 'rgb(160, 160, 160)'); + draw_way_line(way, Math.floor(thickest_stroke * 0.25),'rgb(250, 250, 250)'); + break; + } + } + }); + } +} \ No newline at end of file diff --git a/packages/osm-map-nano/src/index.ts b/packages/osm-map-nano/src/index.ts new file mode 100644 index 0000000..34fbfd1 --- /dev/null +++ b/packages/osm-map-nano/src/index.ts @@ -0,0 +1,5 @@ +import { Mapper } from './Mapper.js'; + +export { + Mapper +}; \ No newline at end of file diff --git a/packages/osm-map-nano/tests/test.ts b/packages/osm-map-nano/tests/test.ts new file mode 100644 index 0000000..8118ece --- /dev/null +++ b/packages/osm-map-nano/tests/test.ts @@ -0,0 +1,14 @@ +import { Mapper } from 'osm-map-nano'; + +(globalThis as any).test = (canvas: HTMLCanvasElement, data: string) => { + const test = new Mapper({canvas: canvas}); + test.loadXMLData(data); + + console.log(JSON.stringify(test.data_bounds)); + console.log(`Nodes: ${test.nodes.size}`); + console.log(`Ways: ${test.ways.size}`); + console.log(`Relations: ${test.relations.size}`); + + test.draw(1600); + console.log('Draw done'); +}; \ No newline at end of file diff --git a/packages/osm-map-nano/tsconfig.json b/packages/osm-map-nano/tsconfig.json new file mode 100644 index 0000000..70ec21d --- /dev/null +++ b/packages/osm-map-nano/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" + } \ No newline at end of file diff --git a/packages/osm-map-nano/tsconfig.tsbuildinfo b/packages/osm-map-nano/tsconfig.tsbuildinfo new file mode 100644 index 0000000..8aa1811 --- /dev/null +++ b/packages/osm-map-nano/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["../../node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/typescript/lib/lib.es2022.d.ts","../../node_modules/typescript/lib/lib.es2023.d.ts","../../node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","./src/Mapper.ts","./src/index.ts","../../node_modules/@types/estree/index.d.ts","../../node_modules/@types/json-schema/index.d.ts"],"fileIdsList":[[63]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"6824f4e3b6e6cd9f634c57ffd2855f09612090736e0b87bfb49fcfa31bb4b7f3","signature":"bfc083260b9ede28688cbb8f656e59231850b646efc10ef865deff51ac5eaa2c","impliedFormat":99},{"version":"f1ea9fd441588b4899623a6b605952928bbc290f5e61cdee4c6dc5bf985541bc","signature":"4347470f9062bf1cf3c417ea74cd8056c9937cef083d56a0574fc7bf9d911de8","impliedFormat":99},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1}],"root":[63,64],"options":{"allowJs":false,"allowSyntheticDefaultImports":true,"alwaysStrict":true,"composite":true,"declaration":true,"exactOptionalPropertyTypes":true,"module":199,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitOverride":true,"noImplicitReturns":true,"noImplicitThis":true,"noPropertyAccessFromIndexSignature":true,"noUncheckedIndexedAccess":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"../../build","removeComments":false,"rootDir":"../../src","strictBindCallApply":true,"strictBuiltinIteratorReturn":true,"strictFunctionTypes":true,"strictNullChecks":true,"strictPropertyInitialization":true,"useUnknownInCatchVariables":false},"referencedMap":[[64,1]],"semanticDiagnosticsPerFile":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66],"latestChangedDtsFile":"./src/index.d.ts","version":"5.9.2"} \ No newline at end of file diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..9e2472f --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,78 @@ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +import { rollup } from 'rollup'; + +const root_dir = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); +const root_info = JSON.parse(fs.readFileSync(path.join(root_dir, 'package.json'))); + +async function build(options) +{ + let bundle; + let success = true; + try + { + bundle = await rollup(options.input); + await bundle.write(options.output); + } + catch(error) + { + success = false; + console.error(`Error building ${options}`); + console.error(error); + } + if(bundle) + { + await bundle.close(); + } + return success; +} + +for(const package_path of fs.globSync(root_info.workspaces)) +{ + const pkg_info = JSON.parse(fs.readFileSync(path.join(root_dir, package_path, 'package.json'))); + const build_dir = path.join('build', 'packages', pkg_info.name); + const dist_dir = path.join(build_dir, 'dist'); + + // Building main package + fs.mkdirSync(dist_dir, {recursive: true}); + + if(!await build({ + input: { + input: path.join(build_dir, 'src', 'index.js') + }, + output: { + compact: true, + extend: true, + file: `${dist_dir}/${pkg_info.name}.js`, + name: 'OSM', + format: 'iife' + }})) + process.exit(1); + + // Building tests + const html_test_template = fs.readFileSync(path.join(root_dir, 'scripts', 'test_template.html')).toString() + .replaceAll('{{bundle}}', `${pkg_info.name}.js`) + .replaceAll('{{data}}', '/data/shibuya.osm'); + for(const test_file of fs.globSync(path.join(build_dir, 'tests', '*.js'))) + { + const test_name = path.parse(test_file).name; + if(!await build({ + input: { + input: test_file, + external: ['osm-map-nano'], + }, + output: { + compact: true, + globals: { 'osm-map-nano': 'OSM' }, + extend: true, + file: `${dist_dir}/${test_name}.js`, + name: 'OSM', + format: 'iife' + }})) + process.exit(1); + fs.writeFileSync(`${dist_dir}/${test_name}.html`, + html_test_template.replaceAll('{{test_script}}', `${test_name}.js`).replaceAll('{{test_name}}', test_name)); + } +} \ No newline at end of file diff --git a/scripts/server.js b/scripts/server.js new file mode 100644 index 0000000..8a1a458 --- /dev/null +++ b/scripts/server.js @@ -0,0 +1,66 @@ +import fs from 'fs'; +import http from 'http'; +import path from 'path'; + +const port = 8080; + +const server = http.createServer((request, response) => { + const mimeType = { + '.html': 'text/html', + '.js': 'text/javascript', + '.gz': 'application/javascript', + }; + const mimeEncoding = { + '.gz': 'gzip', + }; + let pathname = path.join('.', request.url); + + if(!fs.existsSync(pathname)) + { + // If the file is not found, return 404 + response.statusCode = 404; + response.end(`File ${pathname} not found!`); + return; + } + // If is a directory, then look for index.html + if (fs.statSync(pathname).isDirectory()) { + pathname = path.join(pathname, 'index.html'); + } + // Read file from file system + fs.readFile(pathname, function(error, data){ + if(error) + { + response.statusCode = 500; + response.end(`Error getting the file: ${error}.`); + } + else + { + // Based on the URL path, extract the file extention. e.g. .js, .doc, ... + const extension = path.parse(pathname).ext; + // Set Content-Type + response.setHeader('Content-Type', mimeType[extension] || 'text/plain' ); + // If the file is found, set Content-Encoding + if(mimeEncoding[extension]) + { + response.setHeader('Content-Encoding', mimeEncoding[extension]); + } + response.end(data); + } + }); +}); + +server.listen(port, (error) => { + if (error) + return console.log(`Server cannot listen port ${port} :`, error); + console.log(`Server is listening on port ${port}`); +}); + +const exit = () => { + server.close(); + console.log('Server stopped'); +}; + +process.on('SIGINT', () => { + process.stdout.write('\r \r'); + exit(); +}); \ No newline at end of file diff --git a/scripts/test.cjs b/scripts/test.cjs new file mode 100644 index 0000000..fbaea51 --- /dev/null +++ b/scripts/test.cjs @@ -0,0 +1,67 @@ +const assert = require('node:assert'); +const { spawn } = require('node:child_process'); +const fs = require('node:fs'); + +const { Browser, Builder, By } = require('selenium-webdriver'); +const firefox = require('selenium-webdriver/firefox'); + +async function test() { + const generate_env_var = process.env.OSM_MAP_GENERATE_DATA || 'false'; + const generete_data = generate_env_var === '1' || generate_env_var.toLowerCase() === 'true'; + + const server = spawn('node', ['scripts/server.js'], {stdio: [null, null, 'inherit']}); // show stderr (stdout is read) + console.log('Creating selenium driver'); + const options = new firefox.Options(); + options.addArguments('--headless'); + const driver = await new Builder().forBrowser(Browser.FIREFOX).setFirefoxOptions(options).build(); + try + { + const max_try = 5; + let read_try = 0; + for(; read_try < max_try; read_try +=1) + { + const server_out = server.stdout.read(); + if(server_out != null) + { + assert.equal('Server is listening on port 8080\n', server_out.toString(), 'Server not starting properly'); + break; + } + await driver.sleep(50); + } + assert.notEqual(read_try, max_try, 'Timeout waiting for server starting'); + + const test_name = 'test'; + console.log('Fetching test html'); + await driver.get('http://localhost:8080/build/packages/osm-map-nano/dist/test.html'); + assert.equal(`OSM Map Test : ${test_name}`, await driver.getTitle(), 'Wrong HTML title'); + + let canvas = await driver.findElement(By.id('canvas-test')); + const image_url_prefix = 'data:image/png;base64,'; + const image_data = Buffer.from( + (await driver.executeScript('return arguments[0].toDataURL()', canvas)).substring(image_url_prefix.length), 'base64'); + const expected_data = fs.readFileSync('data/test.png'); + if(generete_data) + { + if(!expected_data.equals(image_data)) + { + console.log(`Generating image for test ${test_name}`); + fs.writeFileSync('data/test.png', image_data); + } + } + else + assert.ok(expected_data.equals(image_data)); + } + catch (error) + { + console.error('TEST FAILED'); + console.error(error); + } + finally + { + console.log('Exiting selenium driver'); + await driver.quit(); + server.kill('SIGINT'); + } +} + +test(); \ No newline at end of file diff --git a/scripts/test_template.html b/scripts/test_template.html new file mode 100644 index 0000000..8bfc2ce --- /dev/null +++ b/scripts/test_template.html @@ -0,0 +1,20 @@ + + + + + OSM Map Test : {{test_name}} + + + + + + + + + \ No newline at end of file diff --git a/scripts/tmpfs_dirs.sh b/scripts/tmpfs_dirs.sh new file mode 100755 index 0000000..3935648 --- /dev/null +++ b/scripts/tmpfs_dirs.sh @@ -0,0 +1,12 @@ +#! /bin/bash + +CWD=$(cd -P . && pwd) +readarray -t TMPFS_DIRS < <(df -lt tmpfs --output=target | tail -n +2) + + +if [[ " ${TMPFS_DIRS[*]} " =~ " ${CWD}/build " ]]; then + echo "build alread a tmpfs" +else + echo "Mounting build as tmpfs" + sudo mount -m -t tmpfs tmpfs build +fi \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5aea5ca --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "composite": true, + "declaration": true, + "removeComments": false, + "rootDir": ".", + + "lib": ["DOM", "ES2023"], + "module": "nodenext", + "moduleResolution": "nodenext", + "allowSyntheticDefaultImports": true, + + "alwaysStrict": true, + "allowJs": false, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strictBindCallApply": true, + "strictBuiltinIteratorReturn": true, + "strictFunctionTypes": true, + "strictNullChecks": true, + "strictPropertyInitialization": true, + "useUnknownInCatchVariables": false + }, + "references": [ + {"path": "packages/osm-map-nano"} + ] +} \ No newline at end of file diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo new file mode 100644 index 0000000..c938691 --- /dev/null +++ b/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./packages/osm-map-nano/src/Mapper.d.ts","./packages/osm-map-nano/src/index.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/json-schema/index.d.ts","./packages/osm-map-nano/src/Mapper.ts","./packages/osm-map-nano/src/index.ts"],"fileIdsList":[[63]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"bfc083260b9ede28688cbb8f656e59231850b646efc10ef865deff51ac5eaa2c","impliedFormat":99},{"version":"4347470f9062bf1cf3c417ea74cd8056c9937cef083d56a0574fc7bf9d911de8","impliedFormat":99},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1}],"root":[63,64],"resolvedRoot":[[63,67],[64,68]],"options":{"allowJs":false,"allowSyntheticDefaultImports":true,"alwaysStrict":true,"composite":true,"declaration":true,"exactOptionalPropertyTypes":true,"module":199,"noFallthroughCasesInSwitch":true,"noImplicitAny":true,"noImplicitOverride":true,"noImplicitReturns":true,"noImplicitThis":true,"noPropertyAccessFromIndexSignature":true,"noUncheckedIndexedAccess":true,"noUnusedLocals":true,"noUnusedParameters":true,"outDir":"./build","removeComments":false,"rootDir":"./src","strictBindCallApply":true,"strictBuiltinIteratorReturn":true,"strictFunctionTypes":true,"strictNullChecks":true,"strictPropertyInitialization":true,"useUnknownInCatchVariables":false},"referencedMap":[[64,1]],"version":"5.9.2"} \ No newline at end of file