Repository: dkaoster/taiwan-atlas Branch: master Commit: 60ac5fdae46c Files: 18 Total size: 55.7 KB Directory structure: gitextract_6wpgu_11/ ├── .eslintignore ├── .eslintrc.js ├── .github/ │ └── workflows/ │ ├── eslint.yml │ └── npm-publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── compBordersGeo.js ├── generateimg.sh ├── package.json ├── prepublish.sh ├── properties.js ├── rollup.config.js ├── src/ │ ├── bounds.js │ ├── fit.js │ ├── math.js │ └── mercatorTw.js └── utils/ └── districts.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintignore ================================================ node_modules *.cjs.js *.es.js ================================================ FILE: .eslintrc.js ================================================ module.exports = { parserOptions: { ecmaVersion: 2019, sourceType: 'module', }, env: { es6: true, }, extends: ['eslint-config-airbnb-base'], rules: { 'no-nested-ternary': 0, 'import/no-extraneous-dependencies': 0, 'no-param-reassign': 0, }, }; ================================================ FILE: .github/workflows/eslint.yml ================================================ name: Lint on: push jobs: lint: name: Lint runs-on: ubuntu-latest steps: - name: Check out Git repository uses: actions/checkout@v2 - name: Set up Node.js uses: actions/setup-node@v1 with: node-version: 14 # ESLint and Prettier must be in `package.json` - name: Install Node.js dependencies run: npm install - name: Run linters uses: wearerequired/lint-action@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} # Enable linters eslint: true ================================================ FILE: .github/workflows/npm-publish.yml ================================================ name: Publish to NPM on: push: tags: - '*' jobs: publish: name: Publish to NPM runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: node-version: 14 - run: npm install - uses: JS-DevTools/npm-publish@v1 with: token: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .gitignore ================================================ build/ node_modules *-10t.json base*.json *.es.js *.cjs.js *.svg ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 Daniel Kao Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Taiwan Atlas TopoJSON Similar to the [topojson/us-atlas](https://github.com/topojson/us-atlas) project, this repository provides a topojson redistribution of the shapefiles provided by Taiwan's Ministry of the Interior. See [the demo](https://observablehq.com/@dkaoster/taiwan-map) for usage example. All of these files are provided at a scale of 1:10 thousand. ## File Reference # villages-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/villages-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections villages, towns, counties, and nation. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [村里界圖(TWD97經緯度)](https://data.gov.tw/dataset/7438). The town boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) villages, the county boundaries by merging towns, and the nation boundary is computed by merging counties, ensuring a consistent topology. # villages-mercator-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/villages-mercator-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections villages, towns, counties, and nation. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [村里界圖(TWD97經緯度)](https://data.gov.tw/dataset/7438). The town boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) villages, the county boundaries by merging towns, and the nation boundary is computed by merging counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas. # towns-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/towns-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections towns, counties, and nation. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) towns and the nation boundaries by merging counties, ensuring a consistent topology. # towns-mercator-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/towns-mercator-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections towns, counties, and nation. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) towns and the nation boundaries by merging counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas. # districts-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/districts-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections districts specifying legislative districts, counties, and nation. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441) and combined via the districts specified in [this json file](https://github.com/dkaoster/taiwan-atlas/blob/master/utils/districts.json). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) districts and the nation boundaries by merging counties, ensuring a consistent topology. # districts-mercator-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/districts-mercator-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections districts specifying legislative districts, counties, and nation. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441) and combined via the districts specified in [this json file](https://github.com/dkaoster/taiwan-atlas/blob/master/utils/districts.json). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) districts and the nation boundaries by merging counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas. # counties-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/counties-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections counties, and nation. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). The nation boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) counties, ensuring a consistent topology. # counties-mercator-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/counties-mercator-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections counties and nation. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). The nation boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas. # nation-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/nation-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections nation. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). # nation-mercator-10t.json · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/nation-mercator-10t.json "Source") A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections nation. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). This file also contains a compBorders object for optionally drawing the borders of the composed areas. # tw.objects.nation The nation object has two fields: - nation.properties.ID - "TW" - nation.properties.NAME - "Taiwan" # tw.objects.counties The county object has the following fields: - county.properties.COUNTYNAME - The name of the county in Chinese - county.properties.COUNTYENG - The name of the county in English - county.properties.COUNTYID - The character specifying id - county.properties.COUNTYCODE - The five digit county code # tw.objects.towns The town object has the following fields in addition to the county fields: - town.properties.TOWNNAME - The name of the county in Chinese - town.properties.TOWNENG - The name of the county in English - town.properties.TOWNID - The character specifying id - town.properties.TOWNCODE - The eight digit county code # tw.objects.districts The district object has the following fields in addition to the county fields: - district.properties.DISTRICTCODE - The eight digit county code dash (-) the district number # tw.objects.villages The village object has the following fields in addition to the town and county fields: - village.properties.VILLNAME - The name of the village in Chinese - village.properties.VILLENG - The name of the village in English - village.properties.VILLID - The village specifying id - village.properties.VILLCODE - The 11 digit county code The compBorders object has the following fields: - compBorders.properties.BORDERLEVEL - The administrative level that this border encompasses. - compBorders.properties.NAME - The name in Chinese of the administrative area that this border encompasses. - compBorders.properties.ID - The id of the administrative area that this border encompasses. - compBorders.properties.CODE - The name of the administrative area that this border encompasses. - compBorders.properties.ENG - The name in English of the administrative area that this border encompasses. ## MercatorTw Projection `mercatorTw.js` uses a Taiwan-centric composite projection of four [d3.geoMercator](https://github.com/d3/d3-geo#geoMercator) projections: One for the main island, and one for each of Penghu, Kinmen, Lienchiang, and Wuqiu respectively. `mercatorTw.getCompositionBorders()` returns a svg path string of the borders, given the current scale and translation. This package exports the mercatorTw projection and can be used in your own projects. ```js import mercatorTw from 'taiwan-atlas'; ``` ## License MIT ================================================ FILE: compBordersGeo.js ================================================ // eslint-disable-next-line import/no-unresolved const mercatorTw = require('./mercatorTw.cjs.js'); // Initialize Projection let merc = mercatorTw(); // Read center from first argument or from defaultCenter const translate = process.argv[2] && JSON.parse(process.argv[2]); if (translate) merc = merc.translate(translate); // Read scale from second argument or from defaultScale const scale = process.argv[3] && parseInt(process.argv[3], 10); if (scale) merc = merc.scale(scale); // The properties that we will add to the box const properties = { lienchiang: { BORDERLEVEL: 'COUNTY', NAME: '連江縣', ID: 'Z', CODE: '09007', ENG: 'Lienchiang County', }, penghu: { BORDERLEVEL: 'COUNTY', NAME: '澎湖縣', ID: 'X', CODE: '10016', ENG: 'Penghu County', }, kinmen: { BORDERLEVEL: 'COUNTY', NAME: '金門縣', ID: 'W', CODE: '09020', ENG: 'Kinmen County', }, wuqiu: { BORDERLEVEL: 'TOWN', NAME: '烏坵鄉', ID: 'W06', CODE: '09020060', ENG: 'Wuqiu Township', }, }; // Generate the features const features = merc.compositionBorderPoints() .map((border) => ({ type: 'Feature', geometry: { type: 'Polygon', coordinates: [border.coords] }, properties: properties[border.name], })); // Print to stdout features.forEach((feature) => { process.stdout.write(JSON.stringify(feature)); process.stdout.write('\n'); }); ================================================ FILE: generateimg.sh ================================================ #!/bin/bash # Create the border json topo2geo compBorders=- < nation-mercator-10t.json > img/base-border.json # Villages topo2geo villages=- < villages-mercator-10t.json > img/base-villages.json geojson-merge img/base-villages.json img/base-border.json | geo2svg -o img/villages.svg -w 450 -h 600 svgexport img/villages.svg img/villages.png 2x "path {stroke-width: 0.3px;}" # Districts topo2geo districts=- < districts-mercator-10t.json > img/base-districts.json geojson-merge img/base-districts.json img/base-border.json | geo2svg -o img/districts.svg -w 450 -h 600 svgexport img/districts.svg img/districts.png 2x "path {stroke-width: 0.5px;}" # Towns topo2geo towns=- < towns-mercator-10t.json > img/base-towns.json geojson-merge img/base-towns.json img/base-border.json | geo2svg -o img/towns.svg -w 450 -h 600 svgexport img/towns.svg img/towns.png 2x "path {stroke-width: 0.5px;}" # Counties topo2geo counties=- < counties-mercator-10t.json > img/base-counties.json geojson-merge img/base-counties.json img/base-border.json | geo2svg -o img/counties.svg -w 450 -h 600 svgexport img/counties.svg img/counties.png 2x # Nation topo2geo nation=- < nation-mercator-10t.json > img/base-nation.json geojson-merge img/base-nation.json img/base-border.json | geo2svg -o img/nation.svg -w 450 -h 600 svgexport img/nation.svg img/nation.png 2x ================================================ FILE: package.json ================================================ { "name": "taiwan-atlas", "version": "2021.9.20", "description": "Pre-built TopoJSON from the Ministry of the Interior.", "main": "mercatorTw.cjs.js", "jsnext:main": "mercatorTw.es.js", "files": [ "*-10t.json", "mercatorTw.cjs.js", "mercatorTw.es.js", "README.md" ], "scripts": { "lint": "eslint .", "generate:img": "npm run build && bash prepublish.sh && bash generateimg.sh", "clean": "rimraf mercatorTw.cjs.js mercatorTw.es.js", "build": "npm run clean && npm run build:cjs && npm run build:es", "build:cjs": "rollup -c -o mercatorTw.cjs.js -f cjs", "build:es": "rollup -c -o mercatorTw.es.js -f es", "prepublishOnly": "npm run build && bash prepublish.sh" }, "repository": { "type": "git", "url": "git+https://github.com/dkaoster/taiwan-atlas.git" }, "author": { "name": "Daniel Kao", "url": "https://www.diplateevo.com/" }, "license": "MIT", "keywords": [ "topojson", "geojson", "shapefile" ], "bugs": { "url": "https://github.com/dkaoster/taiwan-atlas/issues" }, "homepage": "https://github.com/dkaoster/taiwan-atlas#readme", "devDependencies": { "@mapbox/geojson-merge": "^1.1.1", "d3-geo-projection": "^3.0.0", "eslint": "^7.14.0", "eslint-config-airbnb-base": "^14.2.1", "eslint-plugin-import": "^2.22.1", "globby": "^11.0.1", "mapshaper": "^0.6.44", "ndjson-cli": "^0.3.1", "rimraf": "^3.0.2", "rollup": "^2.33.3", "shapefile": "^0.6.6", "svgexport": "^0.4.1", "topojson-client": "^3.1.0", "topojson-server": "^3.0.1", "topojson-simplify": "^3.0.3" }, "dependencies": { "d3-geo": "^2.0.1", "d3-path": "^2.0.0" } } ================================================ FILE: prepublish.sh ================================================ #!/bin/bash set -e rm -rvf *-10t.json base.json mkdir -p build # Crawl the data pages for the download links # Village URL villageShpUrl=$(curl -Ls https://data.gov.tw/dataset/7438 | \ # Find the link that has the SHP tag grep -io '"SHP","contentUrl":[^}]*"}' | \ # get the href tag sed -E 's/.*contentUrl":"([^"]+).*/\1/g') # Town URL townShpUrl=$(curl -Ls https://data.gov.tw/dataset/7441 | \ # Find the link that has the SHP tag grep -io '"SHP","contentUrl":[^}]*"}' | \ # get the href tag sed -E 's/.*contentUrl":"([^"]+).*/\1/g') # County URL countyShpUrl=$(curl -Ls https://data.gov.tw/dataset/7442 | \ # Find the link that has the SHP tag grep -io '"SHP","contentUrl":[^}]*"}' | \ # get the href tag sed -E 's/.*contentUrl":"([^"]+).*/\1/g') # Download and extract the archives if [ ! -f build/village.zip ]; then curl -Lo build/village.zip "${villageShpUrl}" unzip -od build build/village.zip fi # Download and extract the archives if [ ! -f build/town.zip ]; then curl -Lo build/town.zip "${townShpUrl}" unzip -od build build/town.zip fi # Download and extract the archives if [ ! -f build/county.zip ]; then curl -Lo build/county.zip "${countyShpUrl}" unzip -od build build/county.zip fi ############################################################################### # Generate topojson files # Boundaries for everything we care about bbox=117.663,21.577,122.0202,26.671 # Village file geo2topo -q 1e10 -n villages=<( \ shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \ | ndjson-filter '!!d.properties.VILLNAME') \ | topomerge towns=villages -k 'd.properties.TOWNCODE' \ | topomerge counties=towns -k 'd.properties.COUNTYCODE' \ | topomerge nation=counties \ | toposimplify -f -s 1e-10 \ | node ./properties.js \ > villages-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i villages-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson villages-10t.json mapshaper -i villages-10t.json -clean target=* -o force format=topojson villages-10t.json # Town file geo2topo -q 1e10 -n towns=<( \ shp2json -n --encoding=UTF-8 build/TOWN*.shp \ | ndjson-filter '!!d.properties.TOWNNAME') \ | topomerge counties=towns -k 'd.properties.COUNTYCODE' \ | topomerge nation=counties \ | toposimplify -f -s 1e-10 \ | node ./properties.js \ > towns-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i towns-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson towns-10t.json mapshaper -i towns-10t.json -clean target=* -o force format=topojson towns-10t.json # County file geo2topo -q 1e10 -n counties=<( \ shp2json -n --encoding=UTF-8 build/COUNTY*.shp \ | ndjson-filter '!!d.properties.COUNTYNAME') \ | topomerge nation=counties \ | toposimplify -f -s 1e-10 \ | node ./properties.js \ > counties-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i counties-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson counties-10t.json mapshaper -i counties-10t.json -clean target=* -o force format=topojson counties-10t.json # Use mapshaper to remove layers of detail we don't want for nation mapshaper -i counties-10t.json -drop target=counties -o format=topojson target=* nation-10t.json # District file geo2topo -q 1e10 -n villages=<( \ shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \ | ndjson-filter '!!d.properties.VILLNAME') \ | DISTRICTS="true" node ./properties.js \ | topomerge districts=villages -k 'd.properties.DISTRICTCODE' \ | topomerge counties=districts -k 'd.properties.COUNTYCODE' \ | topomerge nation=counties \ | toposimplify -f -s 1e-10 \ > districts-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i districts-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson districts-10t.json mapshaper -i districts-10t.json -clean target=* -o force format=topojson districts-10t.json # Use mapshaper to remove layers of detail we don't want for district mapshaper -i districts-10t.json -drop target=villages -o force format=topojson target=* districts-10t.json # Village mercator projections geo2topo -q 1e7 -n \ villages=<(shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \ | ndjson-filter '!!d.properties.VILLNAME' \ | geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \ compBorders=<(node compBordersGeo.js) \ | topomerge towns=villages -k 'd.properties.TOWNCODE' \ | topomerge counties=towns -k 'd.properties.COUNTYCODE' \ | topomerge nation=counties \ | toposimplify -f -s 1e-6 \ | node ./properties.js \ > villages-mercator-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i villages-mercator-10t.json -filter-slivers -o force format=topojson villages-mercator-10t.json mapshaper -i villages-mercator-10t.json -clean target=* -o force format=topojson villages-mercator-10t.json # Town mercator projections geo2topo -q 1e7 -n \ towns=<(shp2json -n --encoding=UTF-8 build/TOWN*.shp \ | ndjson-filter '!!d.properties.TOWNNAME' \ | geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \ compBorders=<(node compBordersGeo.js) \ | topomerge counties=towns -k 'd.properties.COUNTYCODE' \ | topomerge nation=counties \ | toposimplify -f -s 1e-6 \ | node ./properties.js \ > towns-mercator-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i towns-mercator-10t.json -filter-slivers -o force format=topojson towns-mercator-10t.json mapshaper -i towns-mercator-10t.json -clean target=* -o force format=topojson towns-mercator-10t.json # County mercator projections geo2topo -q 1e7 -n \ counties=<(shp2json -n --encoding=UTF-8 build/COUNTY*.shp \ | ndjson-filter '!!d.properties.COUNTYNAME' \ | geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \ compBorders=<(node compBordersGeo.js) \ | topomerge nation=counties \ | toposimplify -f -s 1e-6 \ | node ./properties.js \ > counties-mercator-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i counties-mercator-10t.json -filter-slivers -o force format=topojson counties-mercator-10t.json mapshaper -i counties-mercator-10t.json -clean target=* -o force format=topojson counties-mercator-10t.json # Use mapshaper to remove layers of detail we don't want for nation mapshaper -i counties-mercator-10t.json -drop target=counties -o format=topojson target=* nation-mercator-10t.json # District mercator projections geo2topo -q 1e7 -n \ villages=<(shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \ | ndjson-filter '!!d.properties.VILLNAME' \ | geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \ compBorders=<(node compBordersGeo.js) \ | DISTRICTS="true" node ./properties.js \ | topomerge districts=villages -k 'd.properties.DISTRICTCODE' \ | topomerge counties=districts -k 'd.properties.COUNTYCODE' \ | topomerge nation=counties \ | toposimplify -f -s 1e-6 \ > districts-mercator-10t.json # Use mapshaper to remove extra slivers and islands outside of the boundaries. mapshaper -i districts-mercator-10t.json -filter-slivers -o force format=topojson districts-mercator-10t.json mapshaper -i districts-mercator-10t.json -clean target=* -o force format=topojson districts-mercator-10t.json # Use mapshaper to remove layers of detail we don't want for district mapshaper -i districts-mercator-10t.json -drop target=villages -o force format=topojson target=* districts-mercator-10t.json ================================================ FILE: properties.js ================================================ const shapefile = require('shapefile'); const globby = require('globby'); const districts = require('./utils/districts.json'); // Parse the piped in topojson function parseInput() { return new Promise((resolve, reject) => { const chunks = []; process.stdin .on('data', (chunk) => chunks.push(chunk)) .on('end', () => { try { resolve(JSON.parse(chunks.join(''))); } catch (error) { reject(error); } }) .setEncoding('utf8'); }); } // 臺 > 台 function fixTai(obj) { return { ...obj, COUNTYNAME: obj.COUNTYNAME.replace('臺', '台') }; } // Generated modified properties function output([topology, towns, counties]) { const townsMap = new Map( towns.features.map((d) => [d.properties.TOWNCODE, d.properties]), ); const countiesMap = new Map( counties.features.map((d) => [d.properties.COUNTYCODE, d.properties]), ); // Process village properties if (topology.objects.villages) { // eslint-disable-next-line no-restricted-syntax for (const village of topology.objects.villages.geometries) { village.properties = fixTai(village.properties); village.properties.TOWNENG = townsMap.get(village.properties.TOWNCODE).TOWNENG; village.properties.COUNTYENG = countiesMap.get(village.properties.COUNTYCODE).COUNTYENG; // If we are generating districts, add DISTRICTCODE into properties if (process.env.DISTRICTS === 'true') { Object.keys(districts).forEach((countyId) => { Object.keys(districts[countyId]).forEach((districtId) => { if ( districts[countyId][districtId].indexOf(village.properties.VILLCODE) >= 0 || districts[countyId][districtId].indexOf(village.properties.TOWNCODE) >= 0 || districts[countyId][districtId].indexOf(village.properties.COUNTYCODE) >= 0 ) village.properties.DISTRICTCODE = `${countyId}-${districtId}`; }); }); } delete village.properties.NOTE; } } // Process town properties if (topology.objects.towns) { // eslint-disable-next-line no-restricted-syntax for (const town of topology.objects.towns.geometries) { town.properties = fixTai(town.properties); town.properties.TOWNENG = townsMap.get(town.properties.TOWNCODE).TOWNENG; town.properties.COUNTYENG = countiesMap.get(town.properties.COUNTYCODE).COUNTYENG; delete town.properties.NOTE; } } // Process county properties if (topology.objects.counties) { // eslint-disable-next-line no-restricted-syntax for (const county of topology.objects.counties.geometries) { county.properties = fixTai(county.properties); county.properties.COUNTYENG = countiesMap.get(county.properties.COUNTYCODE).COUNTYENG; delete county.properties.NOTE; } } // Add nation properties if (topology.objects.nation && topology.objects.nation.geometries) { topology.objects.nation.geometries[0].properties = { ID: 'TW', NAME: 'Taiwan' }; } process.stdout.write(JSON.stringify(topology)); process.stdout.write('\n'); } // Read the data out of the shp files. Promise.all([ globby('build/TOWN*.shp'), globby('build/COUNTY*.shp'), ]).then(([townShp, countyShp]) => Promise.all([ parseInput(), shapefile.read(townShp[0]), shapefile.read(countyShp[0]), ]).then(output)); ================================================ FILE: rollup.config.js ================================================ export default { input: 'src/mercatorTw.js', }; ================================================ FILE: src/bounds.js ================================================ function noop() {} let x0 = Infinity; let y0 = x0; let x1 = -x0; let y1 = x1; function boundsPoint(x, y) { if (x < x0) x0 = x; if (x > x1) x1 = x; if (y < y0) y0 = y; if (y > y1) y1 = y; } const boundsStream = { point: boundsPoint, lineStart: noop, lineEnd: noop, polygonStart: noop, polygonEnd: noop, result() { const bounds = [[x0, y0], [x1, y1]]; // eslint-disable-next-line no-multi-assign x1 = y1 = -(y0 = x0 = Infinity); return bounds; }, }; export default boundsStream; ================================================ FILE: src/fit.js ================================================ import { geoStream } from 'd3-geo'; import boundsStream from './bounds'; export function fitExtent(projection, extent, object) { const w = extent[1][0] - extent[0][0]; const h = extent[1][1] - extent[0][1]; const clip = projection.clipExtent && projection.clipExtent(); projection .scale(150) .translate([0, 0]); if (clip != null) projection.clipExtent(null); geoStream(object, projection.stream(boundsStream)); const b = boundsStream.result(); const k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])); const x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2; const y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2; if (clip != null) projection.clipExtent(clip); return projection .scale(k * 150) .translate([x, y]); } export function fitSize(projection, size, object) { return fitExtent(projection, [[0, 0], size], object); } ================================================ FILE: src/math.js ================================================ // eslint-disable-next-line import/prefer-default-export export const epsilon = 1e-6; ================================================ FILE: src/mercatorTw.js ================================================ /* eslint-disable no-plusplus */ import { geoMercator } from 'd3-geo'; import { path } from 'd3-path'; import { epsilon } from './math'; import { fitExtent, fitSize } from './fit'; const defaultScale = 10000; const defaultCenter = [275, 300]; // Geo coordinates for projection boxes given defaultScale of 10000. const geoCoordinates = { mainland: { width: 360, height: 600, offsetX: 0, offsetY: 0, }, penghu: { width: 90, height: 130, offsetX: -210, offsetY: 200, }, kinmen: { width: 120, height: 60, offsetX: -195, offsetY: -110, }, lienchiang: { width: 120, height: 120, offsetX: -195, offsetY: -220, }, wuqiu: { width: 30, height: 30, offsetX: -150, offsetY: -125, }, }; // The projections must have mutually exclusive clip regions on the sphere, // as this will avoid emitting interleaving lines and polygons. function multiplex(streams) { const n = streams.length; return { point(x, y) { let i = -1; while (++i < n) streams[i].point(x, y); }, sphere() { let i = -1; while (++i < n) streams[i].sphere(); }, lineStart() { let i = -1; while (++i < n) streams[i].lineStart(); }, lineEnd() { let i = -1; while (++i < n) streams[i].lineEnd(); }, polygonStart() { let i = -1; while (++i < n) streams[i].polygonStart(); }, polygonEnd() { let i = -1; while (++i < n) streams[i].polygonEnd(); }, }; } // A composite projection for Taiwan, configured by default for 450x600. export default () => { let cache; let cacheStream; // Longitude and latitude coordinates of their centers const mainland = geoMercator().rotate([-120.97, -23.60]); let mainlandPoint; const penghu = geoMercator().rotate([-119.53, -23.47]); let penghuPoint; const kinmen = geoMercator().rotate([-118.38, -24.44]); let kinmenPoint; const lienchiang = geoMercator().rotate([-120.22, -26.16]); let lienchiangPoint; const wuqiu = geoMercator().rotate([-119.45, -24.98]); let wuqiuPoint; let point; const pointStream = { point(x, y) { point = [x, y]; } }; const mercatorTw = (coordinates) => { const x = coordinates[0]; const y = coordinates[1]; point = null; return (mainlandPoint.point(x, y), point) || (penghuPoint.point(x, y), point) || (kinmenPoint.point(x, y), point) || (lienchiangPoint.point(x, y), point) || (wuqiuPoint.point(x, y), point); }; const reset = () => { cache = null; cacheStream = null; return mercatorTw; }; mercatorTw.invert = (coordinates) => { const k = mainland.scale(); const t = mainland.translate(); const x = (coordinates[0] - t[0]) / k; const y = (coordinates[1] - t[1]) / k; const isInBounds = (obj) => y >= (obj.offsetY - obj.height / 2) / defaultScale && y < (obj.offsetY + obj.height / 2) / defaultScale && x >= (obj.offsetX - obj.width / 2) / defaultScale && x < (obj.offsetX + obj.width / 2) / defaultScale; if (isInBounds(geoCoordinates.wuqiu)) return wuqiu.invert(coordinates); if (isInBounds(geoCoordinates.kinmen)) return kinmen.invert(coordinates); if (isInBounds(geoCoordinates.lienchiang)) return lienchiang.invert(coordinates); if (isInBounds(geoCoordinates.penghu)) return penghu.invert(coordinates); return mainland.invert(coordinates); }; // eslint-disable-next-line no-return-assign mercatorTw.stream = (stream) => (cache && cacheStream === stream ? cache : cache = multiplex([ mainland.stream(cacheStream = stream), penghu.stream(stream), kinmen.stream(stream), lienchiang.stream(stream), wuqiu.stream(stream), ])); mercatorTw.precision = (...args) => { if (!args.length) return mainland.precision(); mainland.precision(args[0]); penghu.precision(args[0]); kinmen.precision(args[0]); lienchiang.precision(args[0]); wuqiu.precision(args[0]); return reset(); }; mercatorTw.scale = (...args) => { if (!args.length) return mainland.scale(); mainland.scale(args[0]); penghu.scale(args[0]); kinmen.scale(args[0]); lienchiang.scale(args[0]); wuqiu.scale(args[0]); return mercatorTw.translate(mainland.translate()); }; mercatorTw.translate = (...args) => { if (!args.length) return mainland.translate(); const k = mainland.scale(); const x = +args[0][0]; const y = +args[0][1]; const genTranslate = (obj) => [ x + (obj.offsetX / defaultScale) * k, y + (obj.offsetY / defaultScale) * k, ]; const genClipExtent = (obj) => [ [ x - (((obj.width / 2) - obj.offsetX) / defaultScale) * k + epsilon, y - (((obj.height / 2) - obj.offsetY) / defaultScale) * k + epsilon, ], [ x + (((obj.width / 2) + obj.offsetX) / defaultScale) * k - epsilon, y + (((obj.height / 2) + obj.offsetY) / defaultScale) * k - epsilon, ], ]; // Takes the bbox difference between the corner and the center to // determine where to clip. mainlandPoint = mainland .translate(genTranslate(geoCoordinates.mainland)) .clipExtent(genClipExtent(geoCoordinates.mainland)) .stream(pointStream); penghuPoint = penghu .translate(genTranslate(geoCoordinates.penghu)) .clipExtent(genClipExtent(geoCoordinates.penghu)) .stream(pointStream); kinmenPoint = kinmen .translate(genTranslate(geoCoordinates.kinmen)) .clipExtent(genClipExtent(geoCoordinates.kinmen)) .stream(pointStream); lienchiangPoint = lienchiang .translate(genTranslate(geoCoordinates.lienchiang)) .clipExtent(genClipExtent(geoCoordinates.lienchiang)) .stream(pointStream); wuqiuPoint = wuqiu .translate(genTranslate(geoCoordinates.wuqiu)) .clipExtent(genClipExtent(geoCoordinates.wuqiu)) .stream(pointStream); return reset(); }; mercatorTw.fitExtent = (extent, object) => fitExtent(mercatorTw, extent, object); mercatorTw.fitSize = (size, object) => fitSize(mercatorTw, size, object); // Get the compositionBorderPoints because we want to export these // for use as generating geojson. mercatorTw.compositionBorderPoints = () => { const k = mainland.scale(); const t = mainland.translate(); const x = t[0]; const y = t[1]; // Points from top left to bottom left, clockwise. const points = (areaKey) => { const areaCenterX = geoCoordinates[areaKey].offsetX; const areaCenterY = geoCoordinates[areaKey].offsetY; const dx = geoCoordinates[areaKey].width / 2; const dy = geoCoordinates[areaKey].height / 2; return [ [ x + ((areaCenterX - dx) / defaultScale) * k, y + ((areaCenterY - dy) / defaultScale) * k, ], [ x + ((areaCenterX + dx) / defaultScale) * k, y + ((areaCenterY - dy) / defaultScale) * k, ], [ x + ((areaCenterX + dx) / defaultScale) * k, y + ((areaCenterY + dy) / defaultScale) * k, ], [ x + ((areaCenterX - dx) / defaultScale) * k, y + ((areaCenterY + dy) / defaultScale) * k, ], ]; }; return ['penghu', 'lienchiang', 'kinmen', 'wuqiu'].map((areaKey) => { const areaPoints = points(areaKey); // Kinmen borders wrap under wuqiu borders. if (areaKey === 'kinmen') { const wuqiuPoints = points('wuqiu'); return { name: areaKey, coords: [ areaPoints[0], wuqiuPoints[0], wuqiuPoints[3], wuqiuPoints[2], areaPoints[2], areaPoints[3], areaPoints[0], ], }; } return { name: areaKey, coords: [...areaPoints, areaPoints[0]], }; }); }; // Given a context, draw the borders mercatorTw.drawCompositionBorders = (context) => { mercatorTw.compositionBorderPoints().forEach((areaBorder) => { areaBorder.coords.forEach((coords, i) => { if (i === 0) context.moveTo(...coords); else context.lineTo(...coords); }); }); }; // Returns the compositionBorders as an svg path. mercatorTw.getCompositionBorders = () => { const context = path(); mercatorTw.drawCompositionBorders(context); return context.toString(); }; return mercatorTw.scale(defaultScale).translate(defaultCenter); }; ================================================ FILE: utils/districts.json ================================================ { "10002": { "1": ["10002"] }, "10007": { "1": ["10007030", "10007040", "10007050", "10007070", "10007020", "10007060"], "2": ["10007010", "10007080", "10007090"], "3": ["10007110", "10007140", "10007150", "10007200", "10007220", "10007230", "10007240", "10007250", "10007260", "10007190"], "4": ["10007120", "10007170", "10007100", "10007130", "10007160", "10007180", "10007210"] }, "10010": { "1": ["10010010", "10010120", "10010090", "10010020", "10010080", "10010100", "10010110", "10010030"], "2": ["10010130", "10010160", "10010040", "10010050", "10010060", "10010070", "10010140", "10010150", "10010170", "10010180"] }, "10015": { "1": ["10015"] }, "10018": { "1": ["10018"] }, "64000": { "1": ["64000150", "64000160", "64000210", "64000220", "64000230", "64000300", "64000310", "64000320", "64000330", "64000340", "64000350", "64000360", "64000370", "64000380"], "2": ["64000190", "64000200", "64000240", "64000250", "64000260", "64000270", "64000280", "64000290"], "3": ["64000040", "64000030"], "4": ["64000140", "64000170", "64000180", "64000130"], "5": ["64000050", "64000080037", "64000080041", "64000080042", "64000080062", "64000080063", "64000080064", "64000080067", "64000080068"], "6": ["64000010", "64000060", "64000070", "64000020", "64000080S01", "64000080001", "64000080007", "64000080009", "64000080008", "64000080054", "64000080056", "64000080051", "64000080055", "64000080052", "64000080049", "64000080040", "64000080053", "64000080039", "64000080057", "64000080050", "64000080026", "64000080015", "64000080011", "64000080020", "64000080017", "64000080036", "64000080025", "64000080043", "64000080023", "64000080006", "64000080003", "64000080044", "64000080005", "64000080004", "64000080002", "64000080028", "64000080047", "64000080032", "64000080031", "64000080045", "64000080024", "64000080029", "64000080027", "64000080030", "64000080016", "64000080022", "64000080019", "64000080021", "64000080013", "64000080014", "64000080018", "64000080034", "64000080012", "64000080035", "64000080069", "64000080010", "64000080046", "64000080058", "64000080048", "64000080061", "64000080066", "64000080059", "64000080060", "64000080065", "64000080033", "64000080038"], "7": ["64000120"], "8": ["64000100", "64000110", "64000090"] }, "67000": { "1": ["67000010", "67000020", "67000030", "67000040", "67000050", "67000060", "67000080", "67000090", "67000130", "67000160", "67000170"], "2": ["67000070", "67000100", "67000110", "67000120", "67000140", "67000190", "67000210", "67000220", "67000230", "67000240", "67000250", "67000260", "67000150"], "3": ["67000340", "67000350"], "4": ["67000180", "67000200", "67000310"], "5": ["67000330", "67000360", "67000370", "67000320037", "67000320023", "67000320021", "67000320036", "67000320010", "67000320011", "67000320038", "67000320005", "67000320024", "67000320015", "67000320029", "67000320039", "67000320040", "67000320016", "67000320004", "67000320028"], "6": ["67000270", "67000280", "67000290", "67000300", "67000320022", "67000320027", "67000320007", "67000320031", "67000320008", "67000320030", "67000320002", "67000320020", "67000320034", "67000320044", "67000320018", "67000320009", "67000320001", "67000320017", "67000320013", "67000320045", "67000320042", "67000320043", "67000320025", "67000320019", "67000320014", "67000320032", "67000320012", "67000320035", "67000320041", "67000320006", "67000320026", "67000320033", "67000320003"] }, "09007": { "1": ["09007"] }, "10004": { "1": ["10004030", "10004040", "10004050", "10004070", "10004120", "10004060", "10004010020", "10004010018", "10004010017", "10004010019", "10004010016", "10004010015", "10004010013", "10004010012", "10004010023", "10004010014", "10004010022", "10004010011"], "2": ["10004110", "10004020", "10004080", "10004090", "10004100", "10004130", "10004010010", "10004010007", "10004010009", "10004010025", "10004010026", "10004010008", "10004010030", "10004010024", "10004010029", "10004010028", "10004010021", "10004010031", "10004010001", "10004010002", "10004010027", "10004010006", "10004010004", "10004010005", "10004010003"] }, "10008": { "1": ["10008020", "10008030", "10008080", "10008090", "10008100", "10008130"], "2": ["10008010", "10008040", "10008050", "10008060", "10008070", "10008110", "10008120"] }, "10013": { "1": ["10013010", "10013060", "10013070", "10013080", "10013090", "10013100", "10013110", "10013130", "10013260", "10013270", "10013280"], "2": ["10013210", "10013140", "10013050", "10013020", "10013120", "10013150", "10013180", "10013200", "10013220", "10013290", "10013300", "10013310", "10013320", "10013030", "10013040", "10013160", "10013170", "10013190", "10013230", "10013240", "10013250", "10013330"] }, "10016": { "1": ["10016"] }, "10020": { "1": ["10020"] }, "65000": { "1": ["65000100", "65000170", "65000210", "65000230", "65000160", "65000220"], "2": ["65000140", "65000150", "65000020108", "65000020101", "65000020098", "65000020102", "65000020100", "65000020099", "65000020103", "65000020107", "65000020105", "65000020106", "65000020118", "65000020096", "65000020104", "65000020089", "65000020090", "65000020114"], "3": ["65000020075", "65000020110", "65000020024", "65000020056", "65000020064", "65000020062", "65000020058", "65000020063", "65000020061", "65000020080", "65000020007", "65000020082", "65000020012", "65000020046", "65000020044", "65000020031", "65000020060", "65000020028", "65000020001", "65000020042", "65000020006", "65000020003", "65000020002", "65000020073", "65000020111", "65000020117", "65000020038", "65000020094", "65000020009", "65000020016", "65000020037", "65000020008", "65000020057", "65000020036", "65000020020", "65000020035", "65000020013", "65000020014", "65000020021", "65000020043", "65000020010", "65000020004", "65000020083", "65000020065", "65000020027", "65000020055", "65000020067", "65000020011", "65000020054", "65000020059", "65000020116", "65000020078", "65000020077", "65000020068", "65000020069", "65000020045", "65000020086", "65000020030", "65000020039", "65000020032", "65000020034", "65000020097", "65000020081", "65000020072", "65000020019", "65000020085", "65000020053", "65000020079", "65000020018", "65000020015", "65000020017", "65000020022", "65000020023", "65000020066", "65000020084", "65000020051", "65000020095", "65000020109", "65000020119", "65000020093", "65000020074", "65000020076", "65000020070", "65000020071", "65000020091", "65000020025", "65000020087", "65000020113", "65000020115", "65000020092", "65000020112", "65000020088", "65000020040", "65000020049", "65000020047", "65000020048", "65000020029", "65000020041", "65000020033", "65000020005", "65000020052", "65000020026", "65000020050", "65000020R01"], "4": ["65000050012", "65000050074", "65000050063", "65000050064", "65000050073", "65000050071", "65000050043", "65000050006", "65000050024", "65000050005", "65000050078", "65000050072", "65000050068", "65000050003", "65000050001", "65000050046", "65000050008", "65000050033", "65000050069", "65000050009", "65000050036", "65000050070", "65000050056", "65000050029", "65000050034", "65000050062", "65000050026", "65000050059", "65000050076", "65000050031", "65000050037", "65000050067", "65000050050", "65000050079", "65000050081", "65000050027", "65000050018", "65000050004", "65000050060", "65000050028", "65000050061", "65000050016", "65000050048", "65000050055", "65000050039", "65000050025", "65000050077", "65000050002", "65000050066", "65000050019", "65000050010", "65000050022", "65000050065", "65000050080", "65000050047", "65000050013", "65000050030", "65000050040", "65000050021", "65000050020", "65000050023", "65000050014", "65000050057", "65000050051", "65000050052", "65000050011", "65000050075", "65000050058", "65000050017", "65000050007", "65000050054", "65000050053", "65000050045", "65000050042", "65000050049"], "5": ["65000080", "65000070", "65000050084", "65000050038", "65000050044", "65000050041", "65000050083", "65000050032", "65000050035", "65000050082", "65000050015"], "6": ["65000010025", "65000010041", "65000010117", "65000010003", "65000010030", "65000010037", "65000010049", "65000010017", "65000010015", "65000010050", "65000010021", "65000010013", "65000010114", "65000010014", "65000010020", "65000010033", "65000010043", "65000010048", "65000010028", "65000010004", "65000010029", "65000010019", "65000010036", "65000010026", "65000010016", "65000010106", "65000010045", "65000010032", "65000010002", "65000010001", "65000010042", "65000010038", "65000010115", "65000010039", "65000010018", "65000010006", "65000010061", "65000010047", "65000010034", "65000010008", "65000010118", "65000010040", "65000010046", "65000010103", "65000010104", "65000010119", "65000010009", "65000010101", "65000010035", "65000010023", "65000010105", "65000010022", "65000010027", "65000010102", "65000010007", "65000010031", "65000010116", "65000010005", "65000010062", "65000010024", "65000010044", "65000010010", "65000010121", "65000010012", "65000010011"], "7": ["65000010069", "65000010055", "65000010113", "65000010080", "65000010094", "65000010079", "65000010125", "65000010122", "65000010068", "65000010095", "65000010074", "65000010107", "65000010071", "65000010070", "65000010056", "65000010093", "65000010076", "65000010089", "65000010078", "65000010083", "65000010053", "65000010060", "65000010064", "65000010073", "65000010057", "65000010082", "65000010110", "65000010086", "65000010087", "65000010111", "65000010085", "65000010084", "65000010090", "65000010075", "65000010058", "65000010096", "65000010120", "65000010098", "65000010097", "65000010109", "65000010072", "65000010054", "65000010091", "65000010081", "65000010065", "65000010063", "65000010112", "65000010123", "65000010067", "65000010066", "65000010077", "65000010100", "65000010124", "65000010088", "65000010099", "65000010059", "65000010108", "65000010051", "65000010052", "65000010092", "65000010126"], "8": ["65000030062", "65000030084", "65000030039", "65000030067", "65000030073", "65000030034", "65000030036", "65000030010", "65000030018", "65000030015", "65000030080", "65000030014", "65000030016", "65000030045", "65000030013", "65000030090", "65000030069", "65000030091", "65000030041", "65000030046", "65000030037", "65000030035", "65000030054", "65000030019", "65000030006", "65000030089", "65000030058", "65000030060", "65000030053", "65000030050", "65000030079", "65000030049", "65000030040", "65000030047", "65000030051", "65000030048", "65000030052", "65000030086", "65000030085", "65000030055", "65000030082", "65000030008", "65000030007", "65000030009", "65000030012", "65000030061", "65000030071", "65000030064", "65000030068", "65000030056", "65000030087", "65000030026", "65000030042", "65000030002", "65000030065", "65000030004", "65000030063", "65000030070", "65000030043", "65000030044", "65000030017", "65000030059", "65000030078", "65000030003", "65000030025", "65000030088", "65000030057", "65000030011", "65000030092", "65000030093", "65000030083", "65000030038", "65000030081", "65000030001", "65000030005", "65000030066"], "9": ["65000040", "65000030021", "65000030020", "65000030022", "65000030075", "65000030024", "65000030028", "65000030029", "65000030030", "65000030031", "65000030033", "65000030027", "65000030077", "65000030072", "65000030076", "65000030074", "65000030023", "65000030032"], "10": ["65000130", "65000090"], "11": ["65000060", "65000200", "65000290", "65000180", "65000190"], "12": ["65000240", "65000120", "65000250", "65000260", "65000110", "65000280", "65000270"] }, "68000": { "1": ["68000050", "68000070", "68000010010", "68000010047", "68000010006", "68000010057", "68000010058", "68000010046", "68000010078", "68000010005", "68000010079", "68000010076", "68000010038", "68000010045", "68000010015"], "2": ["68000120", "68000060", "68000110", "68000040"], "3": ["68000020006", "68000020069", "68000020021", "68000020058", "68000020056", "68000020033", "68000020007", "68000020043", "68000020059", "68000020042", "68000020076", "68000020079", "68000020085", "68000020045", "68000020084", "68000020002", "68000020082", "68000020065", "68000020039", "68000020029", "68000020001", "68000020011", "68000020062", "68000020051", "68000020027", "68000020005", "68000020061", "68000020053", "68000020016", "68000020017", "68000020060", "68000020022", "68000020032", "68000020072", "68000020012", "68000020070", "68000020048", "68000020049", "68000020038", "68000020031", "68000020034", "68000020064", "68000020044", "68000020073", "68000020035", "68000020054", "68000020041", "68000020080", "68000020014", "68000020024", "68000020025", "68000020037", "68000020074", "68000020055", "68000020004", "68000020047", "68000020066", "68000020052", "68000020046", "68000020063", "68000020036", "68000020040", "68000020028", "68000020050", "68000020057", "68000020081", "68000020015", "68000020018", "68000020026", "68000020077", "68000020008", "68000020083", "68000020078"], "4": ["68000010074", "68000010068", "68000010031", "68000010069", "68000010016", "68000010063", "68000010007", "68000010037", "68000010024", "68000010043", "68000010004", "68000010077", "68000010013", "68000010012", "68000010014", "68000010041", "68000010044", "68000010033", "68000010034", "68000010042", "68000010060", "68000010059", "68000010036", "68000010035", "68000010071", "68000010056", "68000010073", "68000010008", "68000010027", "68000010026", "68000010067", "68000010075", "68000010053", "68000010050", "68000010072", "68000010021", "68000010001", "68000010002", "68000010052", "68000010003", "68000010025", "68000010019", "68000010048", "68000010022", "68000010018", "68000010011", "68000010009", "68000010032", "68000010028", "68000010039", "68000010029", "68000010055", "68000010020", "68000010054", "68000010049", "68000010064", "68000010017", "68000010023", "68000010070", "68000010066", "68000010062", "68000010040", "68000010065", "68000010030", "68000010051", "68000010061"], "5": ["68000090", "68000100"], "6": ["68000130", "68000030", "68000080", "68000020020", "68000020020", "68000020019", "68000020068", "68000020023", "68000020013", "68000020075", "68000020030", "68000020071", "68000020003", "68000020010", "68000020067"] }, "09020": { "1": ["09020"] }, "10005": { "1": ["10005100", "10005130", "10005140", "10005150", "10005020", "10005030", "10005040", "10005060"], "2": ["10005160", "10005110", "10005010", "10005070", "10005080", "10005090", "10005120", "10005170", "10005180", "10005050"] }, "10009": { "1": ["10009130", "10009030", "10009050", "10009060", "10009140", "10009150", "10009170", "10009200", "10009160", "10009180", "10009190"], "2": ["10009010", "10009020", "10009040", "10009070", "10009080", "10009090", "10009100", "10009110", "10009120"] }, "10014": { "1": ["10014"] }, "10017": { "1": ["10017"] }, "63000": { "1": ["63000120", "63000110042", "63000110033", "63000110036", "63000110037", "63000110038", "63000110040", "63000110039", "63000110041", "63000110027", "63000110028", "63000110030", "63000110034", "63000110035"], "2": ["63000060", "63000110001", "63000110002", "63000110003", "63000110004", "63000110005", "63000110006", "63000110007", "63000110008", "63000110009", "63000110010", "63000110011", "63000110012", "63000110013", "63000110014", "63000110015", "63000110016", "63000110017", "63000110018", "63000110019", "63000110020", "63000110021", "63000110022", "63000110023", "63000110024", "63000110025", "63000110026", "63000110029", "63000110031", "63000110032", "63000110043", "63000110044", "63000110045", "63000110046", "63000110047", "63000110048", "63000110049", "63000110050", "63000110051"], "3": ["63000040", "63000010010", "63000010011", "63000010012", "63000010013", "63000010014", "63000010015", "63000010016", "63000010017", "63000010035", "63000010002", "63000010003", "63000010005", "63000010007", "63000010009", "63000010004", "63000010006", "63000010008", "63000010021", "63000010020", "63000010019"], "4": ["63000100", "63000090"], "5": ["63000070", "63000050017", "63000050021", "63000050020", "63000050019", "63000050016", "63000050015", "63000050014", "63000050011", "63000050012", "63000050013", "63000050018", "63000050024", "63000050023", "63000050022", "63000050028", "63000050026", "63000050025", "63000050027", "63000050029", "63000050030", "63000050031"], "6": ["63000030"], "7": ["63000020", "63000010018", "63000010022", "63000010024", "63000010025", "63000010026", "63000010027", "63000010028", "63000010029", "63000010030", "63000010031", "63000010032", "63000010033", "63000010034"], "8": ["63000080", "63000050001", "63000050002", "63000050003", "63000050004", "63000050005", "63000050009", "63000050007", "63000050008", "63000050006", "63000050010"] }, "66000": { "1": ["66000210", "66000110", "66000220", "66000120", "66000140"], "2": ["66000230", "66000130", "66000240", "66000260", "66000250"], "3": ["66000150", "66000160", "66000170", "66000180"], "4": ["66000070", "66000060"], "5": ["66000050", "66000080"], "6": ["66000010", "66000020", "66000030", "66000040"], "7": ["66000270", "66000280"], "8": ["66000090", "66000100", "66000190", "66000200", "66000290"] } }