├── .circleci └── config.yml ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bin ├── help └── mapbox-tile-copy.js ├── cloudformation └── travis.template ├── index.js ├── lib ├── get-uri.js ├── migration-stream.js ├── serialtilescopy.js ├── tile-stat-stream.js ├── tilelive-mapbox.js ├── tilelivecopy.js └── utils.js ├── package-lock.json ├── package.json └── test ├── copy.serialtiles.test.js ├── copy.tilelive.test.js ├── executable.test.js ├── fixtures ├── fortythree.mbtiles ├── invalid-zxy.mbtiles ├── invalid.coords-out-of-range.geojson ├── invalid.corrupt.mbtiles ├── invalid.null-tile.mbtiles ├── invalid.serialtiles.gzipped.gz ├── invalid.serialtiles.noinfo.gz ├── invalid.tile-with-no-geometry.mbtiles ├── invalid.tilejson ├── reprojection │ ├── data.cpg │ ├── data.dbf │ ├── data.prj │ ├── data.qpj │ ├── data.shp │ └── data.shx ├── threenine.mbtiles ├── v2-throw.mbtiles ├── valid-v2.mbtiles ├── valid-v2.serialtiles.gzip.vector.gz ├── valid.bigtiff.tif ├── valid.bigtiff.tif.aux.xml ├── valid.bundle-layer-1.geojson ├── valid.bundle-layer-2.geojson ├── valid.geojson ├── valid.geotiff.tif ├── valid.mbtiles ├── valid.mini.geojson ├── valid.serialtiles.gz ├── valid.serialtiles.gzip.vector.gz ├── valid.tilejson └── valid.tm2z ├── get-uri.test.js └── index.test.js /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | step-library: 4 | - &install-node 5 | run: 6 | name: Install node 7 | command: | 8 | set +e 9 | curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash 10 | [ -s "${NVM_DIR}/nvm.sh" ] && \. "${NVM_DIR}/nvm.sh" 11 | nvm install v4 12 | nvm alias default v4 13 | echo "[ -s \"${NVM_DIR}/nvm.sh\" ] && . \"${NVM_DIR}/nvm.sh\"" >> $BASH_ENV 14 | 15 | - &build-and-test 16 | run: 17 | name: Build and test 18 | command: | 19 | node -v 20 | npm -v 21 | npm install 22 | npm test 23 | 24 | jobs: 25 | build-osx: 26 | macos: 27 | xcode: "9.0" 28 | steps: 29 | - checkout 30 | - run: echo 'export NVM_DIR=${HOME}/.nvm' >> $BASH_ENV 31 | - *install-node 32 | - *build-and-test 33 | 34 | build-linux-machine: 35 | machine: true 36 | steps: 37 | - checkout 38 | - run: 39 | name: libstdc++ upgrade 40 | command: | 41 | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 42 | sudo apt-get update -y 43 | sudo apt-get install -y libstdc++6 44 | - run: echo 'export NVM_DIR=${HOME}/.nvm' >> $BASH_ENV 45 | - *install-node 46 | - *build-and-test 47 | 48 | build-linux-docker: 49 | docker: 50 | - image: ubuntu:trusty 51 | steps: 52 | - checkout 53 | - run: 54 | name: libstdc++ upgrade 55 | command: | 56 | apt-get update -y 57 | apt-get install -y software-properties-common python-software-properties || true 58 | add-apt-repository -y ppa:ubuntu-toolchain-r/test 59 | apt-get update -y 60 | apt-get install -y libstdc++6 curl bash git 61 | - run: echo 'export NVM_DIR=/opt/circleci/.nvm' >> $BASH_ENV 62 | - *install-node 63 | - *build-and-test 64 | 65 | 66 | workflows: 67 | version: 2 68 | build-and-deploy: 69 | jobs: 70 | - build-osx 71 | - build-linux-docker 72 | - build-linux-machine -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | /node_modules 3 | test/fixtures/valid.geotiff.tif.aux.xml 4 | v1-stats.json 5 | vt-invalid.json 6 | npm-debug.log 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /test 2 | node_modules 3 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "10" 5 | 6 | sudo: false 7 | 8 | before_install: 9 | - nvm install-latest-npm 10 | 11 | addons: 12 | apt: 13 | sources: [ 'ubuntu-toolchain-r-test' ] 14 | packages: [ 'libstdc++-5-dev' ] 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 7.8.0 4 | - Move tile-stat-stream as a vendored library into this repostiory [#159](https://github.com/mapbox/mapbox-tile-copy/pull/159) 5 | - Update all tests to mock S3 and HTTP operations. Tests no longer require AWS credentials to run properly [#159](https://github.com/mapbox/mapbox-tile-copy/pull/159) 6 | 7 | ## 7.7.0 8 | - Update tilelive-omnivore to 4.3.0 9 | 10 | ## 7.6.0 11 | - Update mapnik dependencies to support node10 12 | 13 | ## 7.5.1 14 | - fix a bug with tile property 15 | 16 | ## 7.5.0 17 | - tile km2 area stats for serialtiles [#148](https://github.com/mapbox/mapbox-tile-copy/pull/149) 18 | 19 | ## 7.4.0 20 | - stats for serialtiles [#148](https://github.com/mapbox/mapbox-tile-copy/pull/148) 21 | 22 | ## 7.3.1 23 | 24 | - Update MBTiles migration stream to throw error when ZXY range is invalid [#132](https://github.com/mapbox/mapbox-tile-copy/pull/132) 25 | 26 | ## 7.3.0 27 | 28 | - Add `bypassValdation` & `--bypass-validation` options to bypass the MBTiles migration stream during copy [#130](https://github.com/mapbox/mapbox-tile-copy/pull/130) 29 | 30 | ## 7.2.0 31 | 32 | - Update tilelive-omnivore 4.1.0 33 | 34 | ## 7.1.0 35 | 36 | - Update vtvalidate with gzip-hpp 37 | 38 | ## 7.0.0 39 | 40 | - Updated to mapnik 3.7.0 41 | - Updated to tilelive-omnivore 3.6.0 42 | - Updated to tilelive-vector 3.11.0 43 | - Drops windows support 44 | 45 | ## 6.8.0 46 | 47 | - Update tilelive-omnivore@3.5.0 48 | 49 | ## 6.7.0 50 | 51 | - Adds x out of range error handler. See #113 52 | - Adds file writer for invalid VT stats object & vtvalidate library for additional VT validation. See #113 & mapbox/unpacker#1458 (comment) 53 | 54 | ## 6.6.0 55 | 56 | - Remove duplicate mapnik.VectorTile.info call in migration stream for v2 tiles [#102](https://github.com/mapbox/mapbox-tile-copy/pull/102) 57 | - Catch tile size errors from tilelive-bridge and exit with `EINVALID` 58 | 59 | ## 6.5.0 60 | 61 | - Add support for s3 KMS encryption [#108](https://github.com/mapbox/mapbox-tile-copy/pull/108) and update test user credentials [#109](https://github.com/mapbox/mapbox-tile-copy/pull/109) 62 | - Catch reprojection errors from mapnik [#110](https://github.com/mapbox/mapbox-tile-copy/pull/110) 63 | 64 | ## 6.4.0 65 | 66 | - Add V1 tile tracker. 67 | 68 | ## N/A 69 | 70 | - Update tests per https://github.com/mapbox/mapnik-omnivore/pull/172 71 | 72 | ## 6.3.0 73 | 74 | - Upgrade tilelive-omnivore to 3.4.0 75 | 76 | ## 6.2.1 77 | 78 | - Upgrade tilelive, tilejson, tiletype, mbtiles, and s3urls deps to their new @mapbox namespace 79 | 80 | ## 6.2.0 81 | 82 | - Upgraded to use mapnik 3.6.0, along with relevant deps: 83 | - tilelive-omnivore@3.3.0 84 | - tilelive-vector@3.10.0 85 | 86 | ## 6.1.0 87 | 88 | - Upgrade to tilelive-omnivore@3.2.0 89 | 90 | ## 6.0.2 91 | 92 | - Add namespaced tilelive-s3@6.5.1 93 | 94 | ## 6.0.1 95 | 96 | - Add namespaced omnivores and add z23 bump 97 | 98 | ## 6.0.0 99 | 100 | - Change default tiling scheme to `scanline` for the omnivore protocol, which resolves an issue where z0 tiles were being simplified away and no tiles were counted further down the pyramid. 101 | 102 | ## 5.1.1 103 | 104 | - Add error handling for missing `{z}/{x}/{y}` template in the destination URL. 105 | - test to make sure that zero-indexing is happening correctly (all tiles copied to a single part) 106 | 107 | ## 5.1.0 108 | 109 | - Upgrade mapnik-omnivore#8.1.0, tilelive-omnivore@3.1.0, mapbox-file-sniff@0.5.2, mbtiles@0.9.0 110 | - Add tests for Node 6 111 | - Update tests using aws-sdk region param per https://github.com/mapbox/mapbox-tile-copy/pull/81 112 | 113 | ## 5.0.0 114 | 115 | - Output tilesets will never have a max zoom level less than 6 116 | 117 | ## 4.8.1 118 | 119 | - Bump to tilelive-s3@6.4.1 120 | 121 | ## 4.8.0 122 | 123 | - Can specify the region for the destination bucket by providing a `region` query param 124 | 125 | ## 4.7.1 126 | 127 | - Add explicit error to the `copy` operation for coordinates out of bounds. 128 | 129 | ## 4.7.0 130 | 131 | - For tilejson copy operations, migrate each tile to vt2 132 | 133 | ## 4.6.2 134 | 135 | - Validate mbtiles uploads after migrating the tiles to v2 136 | 137 | ## 4.6.1 138 | 139 | - Only [log the error message](https://github.com/mapbox/mapbox-tile-copy/pull/70) from `bin/mapbox-tile-copy.js` instead of the full stack trace 140 | 141 | ## 4.6.0 142 | 143 | - Bundle support: Ability to handle multiple files for a single tileset 144 | 145 | ## 4.5.0 146 | 147 | - Upgraded to tilelive-omnivore@2.4.0. 148 | 149 | ## 4.4.0 150 | 151 | - Allow layerName to be set on source uris 152 | 153 | ## 4.3.2 154 | 155 | - Upgraded to latest node-mapnik v3.5.x release: v3.5.9 156 | 157 | ## 4.3.1 158 | 159 | - Correctly extracts tile and layer parsing errors 160 | 161 | ## 4.3.0 162 | 163 | - Add a transform for mbtiles copy operations to migrate V1 vector tiles to V2 164 | 165 | ## 4.2.2 166 | 167 | - Upgraded to tilelive-s3@6.2.0 - [support for `$AWS_S3_ENDPOINT` variable](https://github.com/mapbox/tilelive-s3/pull/79) 168 | 169 | ## 4.1.2 170 | 171 | - [Add filesize validation](https://github.com/mapbox/mapbox-upload-limits/pull/5) for `max_filesize` for `mbtiles`, `tm2z`, and `serialtiles` 172 | - [Increased filesize for GeoJSON and CSV to 1GB](https://github.com/mapbox/mapbox-upload-limits/pull/7) 173 | - [Fixed csv-detection bug](https://github.com/mapbox/mapbox-file-sniff/pull/37/files) 174 | 175 | ## 4.1.1 176 | 177 | - Upgraded to mapbox-upload-validate@3.1.0 178 | 179 | ## 4.1.0 180 | 181 | - Upgraded to tilelive-omnivore@2.1.0. 182 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2016, Mapbox 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mapbox-tile-copy 2 | 3 | A shortcut from local geodata files to tiles on S3 or to the local filesystem. 4 | 5 | [![Build Status](https://travis-ci.com/mapbox/mapbox-tile-copy.svg?branch=master)](https://travis-ci.com/mapbox/mapbox-tile-copy) 6 | 7 | ## Installation 8 | 9 | ```sh 10 | $ npm install -g @mapbox/mapbox-tile-copy 11 | ``` 12 | 13 | ## Configuration 14 | 15 | If writing to S3 you'll need to make sure that your shell environment is [configured with appropriate credentials](http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/node-configuring.html). 16 | 17 | ## Usage 18 | 19 | ```sh 20 | $ mapbox-tile-copy 21 | ``` 22 | 23 | Your s3 url template must include a `{z}/{x}/{y}` scheme for writing and distributing tiles. File extensions are not required. 24 | 25 | #### Examples: 26 | 27 | Copy tiles from an mbtiles file to a folder in `my-bucket`: 28 | ```sh 29 | $ mapbox-tile-copy ~/data/my-tiles.mbtiles s3://my-bucket/folder/mbtiles/{z}/{x}/{y} 30 | ``` 31 | 32 | Copy tiles from an mbtiles file to a relative folder in the current working directory named 'tiles': 33 | ```sh 34 | $ mapbox-tile-copy ~/data/my-tiles.mbtiles file://./tiles 35 | ``` 36 | 37 | Convert a GeoJSON file into vector tiles: 38 | ```sh 39 | $ mapbox-tile-copy ~/data/my-data.geojson s3://my-bucket/folder/geojson/{z}/{x}/{y} 40 | ``` 41 | 42 | Copy tiles from one S3 location to another via tilejson describing the source: 43 | ```sh 44 | $ mapbox-tile-copy ~/data/online-data.tilejson s3://my-bucket/folder/tilejson/{z}/{x}/{y} 45 | ``` 46 | 47 | Render image tiles from vector tiles, using custom fonts from a location on your computer: 48 | ```sh 49 | $ MapboxTileCopyFonts=/path/to/font/dir mapbox-tile-copy ~/style.tm2z s3://my-bucket/pngs/{z}/{x}/{y} 50 | ``` 51 | 52 | Perform a part of a copy operation. [Useful for parallel processing a large file](https://github.com/mapbox/tilelive.js#parallel-read-streams): 53 | ```sh 54 | $ mapbox-tile-copy ~/data/my-tiles.mbtiles s3://my-bucket/parallel/{z}/{x}/{y} --part 2 --parts 12 55 | ``` 56 | 57 | The `--part` operation is explicitly _zero-indexed_ because this gives tilelive's stream processors a predictable way to segment tiles per part. For example, the following will distribute all tiles among a single part. So all tiles will be rendered by this single part: 58 | ```sh 59 | $ mapbox-tile-copy ~/data/my-tiles.mbtiles s3://my-bucket/parallel/{z}/{x}/{y} --part 0 --parts 1 60 | ``` 61 | 62 | The following example will distribute tiles to the second part out of 4 total parts: 63 | ```sh 64 | $ mapbox-tile-copy ~/data/my-tiles.mbtiles s3://my-bucket/parallel/{z}/{x}/{y} --part 1 --parts 4 65 | ``` 66 | 67 | You can add extra parameters supported by [tilelive-s3](https://github.com/mapbox/tilelive-s3) onto the end of the S3 URL. For instance, to extend the default HTTP timeout of 2000ms: 68 | ```sh 69 | $ mapbox-tile-copy ~/data/my-tiles.mbtiles s3://my-bucket//{z}/{x}/{y}?timeout=10000 70 | ``` 71 | 72 | Collect tile size statistics and dump to your local tmp dir named `/tmp//tilelive-bridge-stats.json` 73 | ```sh 74 | $ BRIDGE_LOG_MAX_VTILE_BYTES_COMPRESSED=1 mapbox-tile-copy ~/data/my-tiles.mbtiles s3://my-bucket/folder/mbtiles/{z}/{x}/{y} 75 | ``` 76 | 77 | ## Supported file types 78 | 79 | - .mbtiles 80 | - .tilejson 81 | - .tm2z 82 | - .kml 83 | - .geojson 84 | - .gpx 85 | - .csv 86 | - .shp 87 | - .tif 88 | - .vrt 89 | - serialtiles 90 | 91 | ## Running tests 92 | 93 | ```sh 94 | $ npm test 95 | ``` -------------------------------------------------------------------------------- /bin/help: -------------------------------------------------------------------------------- 1 | Usage: 2 | mapbox-tile-copy [--options] 3 | 4 | Description: 5 | mapbox-tile-copy takes a source that can be an MBTiles file, 6 | serialtiles, vector datasource, or others, generates or extracts 7 | tiles from it, and pushes the result to an S3 bucket. 8 | 9 | Example: 10 | mapbox-tile-copy orig.mbtiles s3://bucket/prefix/{z}/{x}/{y} 11 | 12 | Options: 13 | --parts=[number] 14 | --part=[number] 15 | --stats=[filename] 16 | --retry=[number] Retry get/put operations on failure 17 | --progressinterval=[number of seconds] If not included, shows progress by default 18 | --timeout=[number] Timeout for copy operation, default=60000 19 | -------------------------------------------------------------------------------- /bin/mapbox-tile-copy.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* eslint no-process-exit: 0, no-path-concat: 0, no-octal-escape: 0 */ 4 | 5 | // Our goal is a command that can be invoked something like this: 6 | // $ mapbox-tile-copy /path/to/some/file s3://bucket/folder/{z}/{x}/{y} --part=1 --parts=12 7 | // 8 | // We should use exit codes to determine next-steps in case of an error 9 | // - exit 0: success! 10 | // - exit 1: unexpected failure -> retry 11 | // - exit 3: invalid data -> do no retry 12 | 13 | // Perform some performance adjustments early on 14 | var maxThreads = Math.ceil(Math.max(4, require('os').cpus().length * 1.5)); 15 | process.env.UV_THREADPOOL_SIZE = maxThreads; 16 | 17 | var util = require('util'); 18 | var fs = require('fs'); 19 | var http = require('http'); 20 | var https = require('https'); 21 | http.globalAgent.maxSockets = 30; 22 | https.globalAgent.maxSockets = 30; 23 | 24 | var mapboxTileCopy = require('../index.js'); 25 | var argv = require('minimist')(process.argv.slice(2)); 26 | 27 | if (!argv._[0]) { 28 | process.stdout.write(fs.readFileSync(__dirname + '/help', 'utf8')); 29 | process.exit(1); 30 | } 31 | 32 | var srcfile = argv._[0]; 33 | var dsturi = argv._[1]; 34 | var options = {}; 35 | 36 | options.progress = getProgress; 37 | 38 | options.stats = !!argv.stats; 39 | 40 | ['minzoom','maxzoom'].forEach(function(zoomopt) { 41 | if (!!argv[zoomopt]) { 42 | if (isNumeric(argv[zoomopt])) { 43 | options[zoomopt] = argv[zoomopt]; 44 | } 45 | else { 46 | console.error('You must provide a valid zoom level integer'); 47 | process.exit(1); 48 | } 49 | } 50 | }); 51 | 52 | if (argv.layerName) options.layerName = argv.layerName; 53 | 54 | var interval = argv.progressinterval === undefined ? -1 : Number(argv.progressinterval); 55 | 56 | if (interval > 0) { 57 | setInterval(report, interval * 1000); 58 | } 59 | 60 | if (isNumeric(argv.part) && isNumeric(argv.parts)) options.job = { 61 | total: argv.parts, 62 | num: argv.part 63 | }; 64 | 65 | if (isNumeric(argv.retry)) options.retry = parseInt(argv.retry, 10); 66 | if (isNumeric(argv.timeout)) options.timeout = parseInt(argv.timeout, 10); 67 | if (argv.bundle === 'true') options.bundle = true; 68 | if (argv['bypass-validation'] === 'true') options.bypassValidation = true; 69 | if (process.env.BRIDGE_LOG_MAX_VTILE_BYTES_COMPRESSED) options.tileSizeStats = true; 70 | 71 | if (!dsturi) { 72 | console.error('You must provide a valid s3:// or file:// url'); 73 | process.exit(1); 74 | } 75 | 76 | var srcfile0 = srcfile.split(',')[0]; 77 | fs.exists(srcfile0, function(exists) { 78 | if (!exists) { 79 | console.error('The file specified does not exist: %s', srcfile); 80 | process.exit(1); 81 | } 82 | 83 | if (options.bundle === true) { srcfile = 'omnivore://' + srcfile }; 84 | mapboxTileCopy(srcfile, dsturi, options, function(err, stats) { 85 | if (err) { 86 | console.error(err.message); 87 | process.exit(err.code === 'EINVALID' ? 3 : 1); 88 | } 89 | 90 | if (argv.stats) { 91 | fs.writeFile(argv.stats, JSON.stringify(stats), done); 92 | } else { 93 | done(); 94 | } 95 | 96 | function done() { 97 | if (interval !== 0) report(true); 98 | process.exit(0); 99 | } 100 | }); 101 | }); 102 | 103 | var stats, p; 104 | 105 | function getProgress(statistics, prog) { 106 | stats = statistics; 107 | p = prog; 108 | if (interval < 0) report(); 109 | } 110 | 111 | function report(final) { 112 | if (!stats || !p) return; 113 | console.log(util.format('%s%s tiles @ %s/s, %s% complete [%ss]%s', 114 | interval > 0 ? '' : '\r\033[K', 115 | p.transferred, 116 | Math.round(p.speed), 117 | Math.round(p.percentage), 118 | p.runtime, 119 | interval > 0 || final ? '\n' : '' 120 | )); 121 | } 122 | 123 | function isNumeric(num) { 124 | return !isNaN(parseFloat(num)); 125 | } 126 | -------------------------------------------------------------------------------- /cloudformation/travis.template: -------------------------------------------------------------------------------- 1 | { 2 | "AWSTemplateFormatVersion": "2010-09-09", 3 | "Description": "Travis user for testing mapbox-tile-copy", 4 | "Resources": { 5 | "TestUser": { 6 | "Type": "AWS::IAM::User", 7 | "Properties": { 8 | "Path": "/service/", 9 | "Policies": [ 10 | { 11 | "PolicyName": "mapbox-tile-copy-test", 12 | "PolicyDocument": { 13 | "Statement": [ 14 | { 15 | "Effect": "Allow", 16 | "Action": [ "*" ], 17 | "Resource": [ 18 | { "Fn::Sub": "arn:aws:kms::${AWS::AccountId}:alias/mapbox-tile-copy-test-kms" } 19 | ] 20 | }, 21 | { 22 | "Resource": [ 23 | "arn:aws:s3:::tilestream-tilesets-development/*", 24 | "arn:aws:s3:::mapbox-eu-central-1/test/mapbox-tile-copy/*" 25 | ], 26 | "Action": [ 27 | "s3:GetObject", 28 | "s3:PutObject", 29 | "s3:PutObjectAcl" 30 | ], 31 | "Effect": "Allow" 32 | }, 33 | { 34 | "Resource": [ 35 | "arn:aws:s3:::tilestream-tilesets-development" 36 | ], 37 | "Action": [ 38 | "s3:ListBucket" 39 | ], 40 | "Effect": "Allow" 41 | }, 42 | { 43 | "Resource": [ 44 | "arn:aws:s3:::mapbox-eu-central-1" 45 | ], 46 | "Action": [ 47 | "s3:ListBucket" 48 | ], 49 | "Effect": "Allow", 50 | "Condition": { 51 | "StringLike": { 52 | "s3:prefix": "test/mapbox-tile-copy/*" 53 | } 54 | } 55 | } 56 | ] 57 | } 58 | 59 | } 60 | ] 61 | } 62 | }, 63 | "AccessKey": { 64 | "Type": "AWS::IAM::AccessKey", 65 | "Properties": { 66 | "UserName": { "Ref": "TestUser" } 67 | } 68 | }, 69 | "KMSKey": { 70 | "Type" : "AWS::KMS::Key", 71 | "Properties" : { 72 | "Description": "KMS key for mapbox-tile-copy test user", 73 | "Enabled": true, 74 | "KeyPolicy" : { 75 | "Version": "2012-10-17", 76 | "Id": "test-user-kms", 77 | "Statement": [{ 78 | "Effect": "Allow", 79 | "Principal": { 80 | "AWS": [ 81 | { "Fn::Sub": "arn:aws:iam::${AWS::AccountId}:root" }, 82 | { "Fn::Sub": [ 83 | "arn:aws:iam::${AWS::AccountId}:user/service/${User}", 84 | { "User": { "Ref" : "TestUser" } } 85 | ]} 86 | ] 87 | }, 88 | "Action": "kms:*", 89 | "Resource": "*" 90 | }] 91 | } 92 | } 93 | }, 94 | "KMSAlias": { 95 | "Type" : "AWS::KMS::Alias", 96 | "Properties" : { 97 | "AliasName" : "alias/mapbox-tile-copy-test-kms", 98 | "TargetKeyId" : { "Ref":"KMSKey" } 99 | } 100 | } 101 | }, 102 | "Outputs": { 103 | "TestAccessKeyId": { 104 | "Value": { 105 | "Ref": "AccessKey" 106 | } 107 | }, 108 | "TestSecretAccessKey": { 109 | "Value": { 110 | "Fn::GetAtt": [ 111 | "AccessKey", 112 | "SecretAccessKey" 113 | ] 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var url = require('url'); 2 | var getUri = require('./lib/get-uri'); 3 | var tilelivecopy = require('./lib/tilelivecopy'); 4 | var serialtilescopy = require('./lib/serialtilescopy'); 5 | 6 | var s3urls = require('@mapbox/s3urls'); 7 | var tilelive = require('@mapbox/tilelive'); 8 | var Vector = require('@mapbox/tilelive-vector'); 9 | var MBTiles = require('@mapbox/mbtiles'); 10 | var Omnivore = require('@mapbox/tilelive-omnivore'); 11 | var TileJSON = require('@mapbox/tilejson'); 12 | var Mapbox = require('./lib/tilelive-mapbox'); 13 | var S3 = require('@mapbox/tilelive-s3'); 14 | var tl_file = require('tilelive-file'); 15 | var path = require('path'); 16 | 17 | // Note: tilelive-vector is needed for `tm2z` protocol (https://github.com/mapbox/tilelive-vector/issues/124) 18 | Vector.registerProtocols(tilelive); 19 | MBTiles.registerProtocols(tilelive); 20 | Omnivore.registerProtocols(tilelive); 21 | TileJSON.registerProtocols(tilelive); 22 | Mapbox.registerProtocols(tilelive); 23 | S3.registerProtocols(tilelive); 24 | tl_file.registerProtocols(tilelive); 25 | 26 | var mapnik = require('mapnik'); 27 | mapnik.Logger.setSeverity(mapnik.Logger.NONE); 28 | 29 | mapnik.register_fonts(path.dirname(require.resolve('mapbox-studio-default-fonts')), { recurse: true }); 30 | mapnik.register_fonts(path.dirname(require.resolve('mapbox-studio-pro-fonts')), { recurse: true }); 31 | if (process.env.MapboxTileCopyFonts) 32 | mapnik.register_fonts(process.env.MapboxTileCopyFonts, { recurse: true }); 33 | 34 | module.exports = function(filepath, dsturi, options, callback) { 35 | 36 | if (s3urls.valid(dsturi)) { 37 | // Make sure the s3url is of type s3://bucket/key 38 | var query = url.parse(dsturi).query; 39 | dsturi = s3urls.convert(dsturi, 's3'); 40 | if (query) dsturi += '?' + query; 41 | 42 | if (dsturi.indexOf('{z}') == -1 || 43 | dsturi.indexOf('{x}') == -1 || 44 | dsturi.indexOf('{y}') == -1) return callback(new Error('Destination URL does not include a {z}/{x}/{y} template.')); 45 | 46 | } else if (dsturi.indexOf('file://') == -1) { 47 | return callback(new Error('Invalid output protocol: ' + dsturi)); 48 | } 49 | 50 | if (options.bundle === true) { 51 | tilelivecopy(filepath, dsturi, options, copied); 52 | } else { 53 | getUri(filepath, options.layerName, function(err, srcUri) { 54 | if (err) return callback(err); 55 | if (url.parse(srcUri).protocol === 'serialtiles:') { 56 | serialtilescopy(srcUri, dsturi, options, copied); 57 | } else { 58 | tilelivecopy(srcUri, dsturi, options, copied); 59 | } 60 | }); 61 | } 62 | 63 | function copied(err, stats) { 64 | if (!err) return callback(err, stats); 65 | var fatal = { SQLITE_CORRUPT: true, EINVALIDTILE: true }; 66 | if (fatal[err.code]) err.code = 'EINVALID'; 67 | return callback(err); 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /lib/get-uri.js: -------------------------------------------------------------------------------- 1 | var sniffer = require('@mapbox/mapbox-file-sniff'); 2 | var path = require('path'); 3 | 4 | module.exports = function(filepath, layerName, callback) { 5 | sniffer.fromFile(filepath, function(err, info) { 6 | if (err) return callback(err); 7 | var uri = info.protocol + '//' + path.resolve(filepath); 8 | if (layerName) uri += '?layerName=' + layerName; 9 | callback(null, uri); 10 | }); 11 | }; 12 | -------------------------------------------------------------------------------- /lib/migration-stream.js: -------------------------------------------------------------------------------- 1 | var stream = require('stream'); 2 | var tiletype = require('@mapbox/tiletype'); 3 | var mapnik = require('mapnik'); 4 | var fs = require('fs'); 5 | var vtvalidate = require('@mapbox/vtvalidate'); 6 | var zlib = require('zlib'); 7 | var os = require('os'); 8 | 9 | process.env.LOG_INVALID_VT = true; 10 | module.exports = MigrationStream; 11 | module.exports.migrate = migrate; 12 | 13 | function MigrationStream() { 14 | var migrationStream = new stream.Transform({ objectMode: true }); 15 | var v1TileDataLogged = false; 16 | 17 | migrationStream._transform = function(tile, enc, callback) { 18 | if (!tile.buffer) { 19 | migrationStream.push(tile); 20 | return callback(); 21 | } 22 | 23 | var format = tiletype.type(tile.buffer); 24 | if (format !== 'pbf') { 25 | migrationStream.push(tile); 26 | return callback(); 27 | } 28 | 29 | var info = mapnik.VectorTile.info(tile.buffer); 30 | 31 | var v2 = info.layers.every(function(layer) { 32 | return layer.version === 2; 33 | }); 34 | 35 | if (v2 === true) { 36 | vtvalidate.isValid(tile.buffer, function(err, result) { 37 | // returns empty string if it's a valid tile 38 | // if invalid tile - string that specifies why the tile is invalid 39 | var newValidatorErrors; 40 | 41 | if (err) { 42 | err.code = 'EINVALID'; 43 | return callback(err); 44 | } 45 | 46 | if (result === 'ClosePath command count is not 1' || result === 'Max count too large') { 47 | var error = new Error("Invalid tile based on the Mapbox Vector Tile spec: " + result); 48 | error.code = 'EINVALID'; 49 | return callback(error); 50 | } else if (result) { 51 | newValidatorErrors = result; 52 | } 53 | 54 | // Check for errors on the v2 tile 55 | var data = {}; 56 | var error = checkForErrors(info); 57 | 58 | if (newValidatorErrors || error) { 59 | data['vtValidate'] = newValidatorErrors; 60 | data['mapnikVectorTile'] = error ? error.message : ''; 61 | 62 | if (process.env.LOG_INVALID_VT){ 63 | fs.writeFileSync(os.tmpdir() + '/vt-invalid.json', JSON.stringify(data)); 64 | } 65 | 66 | if (error) { 67 | error.code = 'EINVALID'; 68 | return callback(error); 69 | } 70 | } 71 | 72 | migrationStream.push(tile); 73 | 74 | return callback(); 75 | }); 76 | } else { 77 | if (!v1TileDataLogged && process.env.LOG_V1_TILES) { 78 | fs.writeFileSync(os.tmpdir() + '/v1-stats.json', JSON.stringify({ 'tileVersion': '1' })); 79 | v1TileDataLogged = true; 80 | }; 81 | 82 | migrate(tile, function(err, new_tile) { 83 | if (err) return callback(err); 84 | 85 | // Check for errors on newly-minted v2 tile 86 | var err = checkForErrors(mapnik.VectorTile.info(new_tile.buffer)); 87 | if (err) return callback(err); 88 | 89 | migrationStream.push(new_tile); 90 | return callback(); 91 | }); 92 | }; 93 | }; 94 | return migrationStream; 95 | } 96 | 97 | function migrate(tile, callback) { 98 | var vtile; 99 | try { 100 | vtile = new mapnik.VectorTile(tile.z, tile.x, tile.y); 101 | } catch (err) { 102 | if (err && err.message.indexOf('required parameter y is out of range') != -1 || err && err.message.indexOf('required parameter x is out of range') != -1) { 103 | err.code = 'EINVALID'; 104 | err.message = `Tile ${tile.z}/${tile.x}/${tile.y} is an invalid ZXY range.`; 105 | } 106 | return callback(err); 107 | } 108 | 109 | vtile.setData(tile.buffer, {upgrade:true}, function(err) { 110 | if (err) { 111 | err.code = 'EINVALID'; 112 | return callback(err); 113 | } 114 | vtile.getData({compression:'gzip'},function(err, data) { 115 | if (err) return callback(err); 116 | tile.buffer = data; 117 | return callback(null, tile); 118 | }); 119 | }); 120 | } 121 | 122 | function checkForErrors(info) { 123 | var err = null; 124 | if (info.errors) { 125 | if (info.tile_errors) { 126 | err = new Error(info.tile_errors[0].replace(' message', '')); 127 | } else if (info.layers) { 128 | for (var i = 0; i < info.layers.length; i++) { 129 | var layer = info.layers[i]; 130 | if (layer.errors) { 131 | err = new Error(layer.errors[0].replace(' message', '')); 132 | break; 133 | } 134 | } 135 | } else { 136 | err = new Error('Invalid data'); 137 | } 138 | err.code = 'EINVALID'; 139 | } 140 | return err; 141 | } 142 | -------------------------------------------------------------------------------- /lib/serialtilescopy.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var os = require('os'); 3 | var util = require('util'); 4 | var TileStatStream = require('./tile-stat-stream'); 5 | var tilelive = require('@mapbox/tilelive'); 6 | var zlib = require('zlib'); 7 | var url = require('url'); 8 | var progress = require('progress-stream'); 9 | var MigrationStream = require('./migration-stream'); 10 | var S3 = require('@mapbox/tilelive-s3'); 11 | var utils = require('./utils.js'); 12 | 13 | function serialtiles(srcUri, s3urlTemplate, options, callback) { 14 | if (!callback) { 15 | callback = options; 16 | options = {}; 17 | } 18 | 19 | if (options.tileSizeStats) { 20 | var tileSizeStats = { total: 0, count: 0, max: 0 }; 21 | } 22 | 23 | var statStream = new TileStatStream(); 24 | 25 | var max_tilesize = options.limits && options.limits.max_tilesize ? 26 | options.limits.max_tilesize : 500 * 1024; 27 | var once; 28 | 29 | var source = fs.createReadStream(url.parse(srcUri).pathname) 30 | .on('error', done); 31 | 32 | var prog = progress({ 33 | objectMode: true, 34 | time: 100 35 | }); 36 | 37 | var stats = { 38 | skipped: 0, 39 | done: 0 40 | }; 41 | 42 | new S3({ 43 | data: { tiles: [ s3urlTemplate ] }, 44 | sse: 'AES256' 45 | }, function(err, dst) { 46 | if (err) return callback(err); 47 | copy(dst); 48 | }); 49 | 50 | function copy(dst) { 51 | var gunzip = zlib.createGunzip() 52 | .on('error', done); 53 | 54 | var s3 = tilelive.createWriteStream(dst, {retry:options.retry}) 55 | .on('error', done) 56 | .on('stop', done); 57 | 58 | var migrate = MigrationStream() 59 | .on('error', done); 60 | 61 | var deserialize = tilelive.deserialize(options) 62 | .on('error', done) 63 | .on('tile', function(tile) { 64 | if (!tile.buffer) return; 65 | stats.done++; 66 | if (options.tileSizeStats) { 67 | tileSizeStats.count++; 68 | tileSizeStats.total = tileSizeStats.total + (tile.buffer.length * 0.001); 69 | if (tileSizeStats.max < tile.buffer.length) { 70 | tileSizeStats.max = tile.buffer.length; 71 | } 72 | var area = tileSizeStats.hasOwnProperty(tile.z) 73 | ? tileSizeStats[tile.z] + utils.calculateTileArea(tile.z, tile.x, tile.y) 74 | : utils.calculateTileArea(tile.z, tile.x, tile.y); 75 | 76 | tileSizeStats = { 77 | ...tileSizeStats, 78 | [tile.z]: area 79 | }; 80 | 81 | } 82 | if (tile.buffer.length <= max_tilesize) return; 83 | var err = new Error(util.format('Tile exceeds maximum size of %sk at z %s. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.', Math.round(max_tilesize / 1024), tile.z)); 84 | err.code = 'EINVALID'; 85 | done(err); 86 | }); 87 | 88 | if (options.progress) prog.on('progress', function(p) { options.progress(stats, p); }); 89 | 90 | if (options.stats) { 91 | source 92 | .pipe(gunzip) 93 | .pipe(deserialize) 94 | .pipe(migrate) 95 | .pipe(statStream) 96 | .pipe(prog) 97 | .pipe(s3); 98 | } else { 99 | source 100 | .pipe(gunzip) 101 | .pipe(deserialize) 102 | .pipe(migrate) 103 | .pipe(prog) 104 | .pipe(s3); 105 | } 106 | } 107 | 108 | function done(err) { 109 | if (once) return; 110 | once = true; 111 | 112 | if (err) source.unpipe(); 113 | 114 | if (options.tileSizeStats) { 115 | // dump file to tmp dir 116 | tileSizeStats.avg = tileSizeStats.total / tileSizeStats.count; 117 | if (tileSizeStats.count > 0) { 118 | var file = os.tmpdir() + '/tilelive-bridge-stats.json'; 119 | fs.writeFileSync(file, JSON.stringify(tileSizeStats)); 120 | } 121 | } 122 | 123 | if (options.stats) { 124 | callback(err, statStream.getStatistics()); 125 | } else { 126 | callback(err); 127 | } 128 | } 129 | } 130 | 131 | module.exports = serialtiles; 132 | -------------------------------------------------------------------------------- /lib/tile-stat-stream.js: -------------------------------------------------------------------------------- 1 | var Transform = require('stream').Transform; 2 | var util = require('util'); 3 | var tiletype = require('@mapbox/tiletype'); 4 | var zlib = require('zlib'); 5 | var mapboxVectorTile = require('@mapbox/vector-tile'); 6 | var Protobuf = require('pbf'); 7 | var VectorTile = mapboxVectorTile.VectorTile; 8 | var vectorTileGeometryTypes = mapboxVectorTile.VectorTileFeature.types; 9 | 10 | /** 11 | * TileStatStream is the exported functionality of this module: it is a 12 | * writable stream that collects statistics from vector tiles. 13 | */ 14 | function TileStatStream(options) { 15 | this.options = options; 16 | this.vectorLayers = {}; 17 | Transform.call(this, { readableObjectMode: true, objectMode: true }); 18 | } 19 | 20 | util.inherits(TileStatStream, Transform); 21 | 22 | TileStatStream.prototype._transform = function(data, enc, callback) { 23 | // duck-type tile detection to avoid requiring tilelive 24 | if (data.x !== undefined && 25 | data.y !== undefined && 26 | data.z !== undefined && 27 | data.buffer !== undefined && 28 | tiletype.type(data.buffer) === 'pbf') { 29 | zlib.gunzip(data.buffer, function(err, inflatedBuffer) { 30 | this.push(data); 31 | if (err) return callback(); 32 | var vectorTile = new VectorTile(new Protobuf(inflatedBuffer)); 33 | for (var layerName in vectorTile.layers) { 34 | if (this.vectorLayers[layerName] === undefined) { 35 | this.vectorLayers[layerName] = new VectorLayerStats(this.options); 36 | } 37 | var layer = vectorTile.layers[layerName]; 38 | for (var i = 0; i < layer.length; i++) { 39 | this.vectorLayers[layerName].analyzeFeature(layer.feature(i)); 40 | } 41 | } 42 | callback(); 43 | }.bind(this)); 44 | } else { 45 | this.push(data); 46 | callback(); 47 | } 48 | }; 49 | 50 | TileStatStream.prototype.getStatistics = function() { 51 | var stats = {}; 52 | for (var layer in this.vectorLayers) { 53 | stats[layer] = this.vectorLayers[layer].getStatistics(); 54 | } 55 | return stats; 56 | }; 57 | 58 | /** 59 | * VectorLayer collects statistics from a single vector_layer within 60 | * a vector tile. 61 | */ 62 | function VectorLayerStats(options) { 63 | options = options || {}; 64 | this.UNIQUE_VALUES_MAX = options.maxValues || 100; 65 | this.count = 0; 66 | this.fields = {}; 67 | this.geometryTypeCounts = [0, 0, 0, 0]; 68 | } 69 | 70 | VectorLayerStats.prototype.analyzeFeature = function(feature) { 71 | this.count++; 72 | this.geometryTypeCounts[feature.type]++; 73 | for (var name in feature.properties) { 74 | this.analyzeProperty(name, feature.properties[name]); 75 | } 76 | }; 77 | 78 | VectorLayerStats.prototype.analyzeProperty = function(name, value) { 79 | if (this.fields[name] === undefined) { 80 | this.fields[name] = { 81 | min: null, 82 | max: null, 83 | uniqueValues: new Set() 84 | }; 85 | } 86 | var field = this.fields[name]; 87 | 88 | if (typeof value === 'string' && value.length > 256) { 89 | return; 90 | } 91 | 92 | if (field.max === null || value > field.max) { 93 | field.max = value; 94 | } 95 | 96 | if (field.min === null || value < field.min) { 97 | field.min = value; 98 | } 99 | 100 | if (field.uniqueValues && field.uniqueValues.size < this.UNIQUE_VALUES_MAX && 101 | field.uniqueValues[value] === undefined) { 102 | field.uniqueValues.add(value); 103 | } 104 | }; 105 | 106 | function setToArray(set) { 107 | var values = []; 108 | set.forEach(function(value) { values.push(value); }); 109 | return values; 110 | } 111 | 112 | VectorLayerStats.prototype.getStatistics = function() { 113 | var fields = {}; 114 | 115 | for (var field in this.fields) { 116 | fields[field] = { 117 | min: this.fields[field].min, 118 | max: this.fields[field].max, 119 | values: setToArray(this.fields[field].uniqueValues) 120 | }; 121 | } 122 | 123 | return { 124 | geometryTypes: this.geometryTypeCounts.reduce(function(memo, count, i) { 125 | memo[vectorTileGeometryTypes[i]] = count; 126 | return memo; 127 | }, {}), 128 | count: this.count, 129 | fields: fields 130 | }; 131 | }; 132 | 133 | module.exports = TileStatStream; 134 | -------------------------------------------------------------------------------- /lib/tilelive-mapbox.js: -------------------------------------------------------------------------------- 1 | var TileJSON = require('@mapbox/tilejson'); 2 | var url = require('url'); 3 | 4 | module.exports = Mapbox; 5 | 6 | function Mapbox(uri, callback) { 7 | uri = url.parse(uri); 8 | 9 | if (!process.env.MapboxAPIMaps) 10 | return callback(new Error('env var MapboxAPIMaps is required')); 11 | if (!process.env.MapboxAccessToken) 12 | return callback(new Error('env var MapboxAccessToken is required')); 13 | 14 | uri = process.env.MapboxAPIMaps + '/v4' + uri.pathname + '.json?secure=1&access_token=' + process.env.MapboxAccessToken; 15 | return new TileJSON(uri, callback); 16 | } 17 | 18 | Mapbox.registerProtocols = function(tilelive) { 19 | tilelive.protocols['mapbox:'] = Mapbox; 20 | }; 21 | -------------------------------------------------------------------------------- /lib/tilelivecopy.js: -------------------------------------------------------------------------------- 1 | var url = require('url'); 2 | var tilelive = require('@mapbox/tilelive'); 3 | var tileliveOmivore = require('@mapbox/tilelive-omnivore'); 4 | var TileStatStream = require('./tile-stat-stream'); 5 | var queue = require('queue-async'); 6 | var combiner = require('stream-combiner'); 7 | var MigrationStream = require('./migration-stream'); 8 | 9 | function tilelivecopy(srcUri, s3url, options, callback) { 10 | var scheme = 'scanline'; 11 | var protocol = url.parse(srcUri).protocol; 12 | var bypass = options.bypassValidation || false; // bypass the MBTiles migration stream with "false" 13 | if (protocol === 'mbtiles:') scheme = 'list'; 14 | if (protocol === 'omnivore:') scheme = 'scanline'; 15 | options.type = scheme; 16 | 17 | var stats = new TileStatStream(); 18 | 19 | queue() 20 | .defer(tilelive.load, srcUri) 21 | .defer(tilelive.load, s3url) 22 | .await(function(err, src, dst) { 23 | function done(err) { 24 | // invalid geojson 25 | if (err && err.message.indexOf('Failed to parse geojson feature') != -1) { 26 | err.code = 'EINVALID'; 27 | } 28 | 29 | // web mercator out of range 30 | if (err && err.message.indexOf('required parameter y is out of range') != -1 || err && err.message.indexOf('required parameter x is out of range') != -1) { 31 | err.code = 'EINVALID'; 32 | err.message = 'Coordinates beyond web mercator range. Please check projection and lat/lon values.' 33 | } 34 | 35 | // reprojection error from mapnik-vector-tile 36 | if (err && err.message.indexOf('vector_tile_processor:') != -1) { 37 | err.code = 'EINVALID'; 38 | err.message = 'Unable to reproject data. Please reproject to Web Mercator (EPSG:3857) and try again.' 39 | } 40 | 41 | // tile size limits from tilelive-bridge 42 | if (err && err.message.indexOf('Tile >= max allowed size') != -1 && process.env.BRIDGE_MAX_VTILE_BYTES_COMPRESSED) { 43 | err.code = 'EINVALID'; 44 | err.message = `Tile size exceeds limit. At least one vector tile is larger than ${process.env.BRIDGE_MAX_VTILE_BYTES_COMPRESSED/1000000}MB.`; 45 | } 46 | 47 | if (options.stats) { 48 | callback(err, stats.getStatistics()); 49 | } else { 50 | callback(err); 51 | } 52 | } 53 | 54 | if (err) { 55 | err.code = 'EINVALID'; 56 | return done(err); 57 | } 58 | 59 | src.getInfo(function(err, info) { 60 | if (err) { 61 | err.code = 'EINVALID'; 62 | return done(err); 63 | } 64 | 65 | options.minzoom = options.minzoom || info.minzoom; 66 | options.maxzoom = options.maxzoom || info.maxzoom; 67 | options.bounds = options.bounds || info.bounds; 68 | options.close = true; 69 | if (scheme === 'list') options.listStream = src.createZXYStream(); 70 | 71 | var transforms = []; 72 | 73 | if (options.stats) transforms.push(stats); 74 | if ((protocol === 'mbtiles:' || protocol === 'tilejson:') && !bypass) transforms.push(MigrationStream()); 75 | if (transforms.length > 0) options.transform = combiner(transforms); 76 | 77 | if (!dst.sse) dst.sse = 'AES256'; 78 | tilelive.copy(src, dst, options, done); 79 | }); 80 | }); 81 | } 82 | 83 | module.exports = tilelivecopy; 84 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var EARTH_RADIUS = 6371.0088; 4 | 5 | function degToRad(degrees) { 6 | return degrees * (Math.PI / 180); 7 | } 8 | 9 | function tileToLon(tileX, zoom) { 10 | return ((tileX / 2**zoom) * 360.0) - 180.0; 11 | } 12 | 13 | function tileToLat(tileY, zoom) { 14 | var n = Math.PI - 2 * Math.PI * tileY / 2**zoom; 15 | return (180.0 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))); 16 | } 17 | 18 | /** 19 | * 20 | * @param {Number} zoom 21 | * @param {Number} tileX 22 | * @param {Number} tileY 23 | * @returns {Number} SqKM of a given tile 24 | */ 25 | function calculateTileArea(zoom, tileX, tileY) { 26 | var left = degToRad(tileToLon(tileX, zoom)); 27 | var top = degToRad(tileToLat(tileY, zoom)); 28 | var right = degToRad(tileToLon(tileX + 1, zoom)); 29 | var bottom = degToRad(tileToLat(tileY + 1, zoom)); 30 | return (Math.PI / degToRad(180)) * EARTH_RADIUS**2 * Math.abs(Math.sin(top) - Math.sin(bottom)) * Math.abs(left - right); 31 | } 32 | 33 | module.exports = { 34 | calculateTileArea 35 | }; 36 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mapbox/mapbox-tile-copy", 3 | "version": "7.8.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@mapbox/detect-geocsv": { 8 | "version": "0.1.0", 9 | "resolved": "https://registry.npmjs.org/@mapbox/detect-geocsv/-/detect-geocsv-0.1.0.tgz", 10 | "integrity": "sha1-3KHc0ZAFSnDhHliFx4tvsy5hvaA=" 11 | }, 12 | "@mapbox/duplicate-module-test": { 13 | "version": "0.2.0", 14 | "resolved": "https://registry.npmjs.org/@mapbox/duplicate-module-test/-/duplicate-module-test-0.2.0.tgz", 15 | "integrity": "sha512-uO1uZP3CyY7N87Y0qVWfBkSAQjcNUCWhWJe34NgnfrRXSGir4E8gZAJ8rkq8V4uOiLP5lx2LuYNf6vTBtJniTA==", 16 | "dev": true, 17 | "requires": { 18 | "minimist": "^1.2.0" 19 | }, 20 | "dependencies": { 21 | "minimist": { 22 | "version": "1.2.8", 23 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 24 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 25 | "dev": true 26 | } 27 | } 28 | }, 29 | "@mapbox/eslint-config-mapbox": { 30 | "version": "1.2.1", 31 | "resolved": "https://registry.npmjs.org/@mapbox/eslint-config-mapbox/-/eslint-config-mapbox-1.2.1.tgz", 32 | "integrity": "sha512-hhE2sN7L/RO+MhdHIhmpL0KLhA/sWxV1WWH998fmGimI40XDbBgG1Z4d8nTlfuf9jaRDJ88/uklSBvFRhvMeDA==" 33 | }, 34 | "@mapbox/mapbox-file-sniff": { 35 | "version": "1.0.4", 36 | "resolved": "https://registry.npmjs.org/@mapbox/mapbox-file-sniff/-/mapbox-file-sniff-1.0.4.tgz", 37 | "integrity": "sha512-kZ9eK5IIyaqwbh9C1ccJ6B1CYAojA3LG+OHlThs5cq1fgh+W7pnPAjkK41r4YvwHwqEeUhCwGiajEk1+gsdI0Q==", 38 | "requires": { 39 | "@mapbox/detect-geocsv": "0.1.0", 40 | "buffer": "^3.2.2", 41 | "semver": "~5.3.0", 42 | "yargs": "^6.5.0" 43 | } 44 | }, 45 | "@mapbox/mapnik-omnivore": { 46 | "version": "10.0.0", 47 | "resolved": "https://registry.npmjs.org/@mapbox/mapnik-omnivore/-/mapnik-omnivore-10.0.0.tgz", 48 | "integrity": "sha512-R2EVt+JKm2yB9EVkcrlx7/l8qCSaP0IbPFyICXJW1CwD9S6Benum++bmPwxLNo9X2fpVWXQFXN3pa867XZXjBw==", 49 | "requires": { 50 | "@mapbox/mapbox-file-sniff": "~1.0.0", 51 | "@mapbox/sphericalmercator": "~1.0.5", 52 | "gdal": "~0.9.3", 53 | "mapnik": "4.x || 3.x", 54 | "queue-async": "~1.2.0", 55 | "srs": "~1.2.0" 56 | }, 57 | "dependencies": { 58 | "@mapbox/sphericalmercator": { 59 | "version": "1.0.5", 60 | "resolved": "https://registry.npmjs.org/@mapbox/sphericalmercator/-/sphericalmercator-1.0.5.tgz", 61 | "integrity": "sha1-cCN7l3QJXtHP286nqP0fyCsmkfI=" 62 | } 63 | } 64 | }, 65 | "@mapbox/mbtiles": { 66 | "version": "0.10.0", 67 | "resolved": "https://registry.npmjs.org/@mapbox/mbtiles/-/mbtiles-0.10.0.tgz", 68 | "integrity": "sha512-U86xMaUOlBKUt6W92twIE03nsXesPY0TtpSOA7SRMFkKx+mw5HKY38V6fLuo+c6NRSyXaQIAo1X2IsnwVK5B9w==", 69 | "requires": { 70 | "@mapbox/sphericalmercator": "~1.1.0", 71 | "@mapbox/tiletype": "0.3.x", 72 | "d3-queue": "~2.0.3", 73 | "sqlite3": "4.x" 74 | } 75 | }, 76 | "@mapbox/mock-aws-sdk-js": { 77 | "version": "1.0.1", 78 | "resolved": "https://registry.npmjs.org/@mapbox/mock-aws-sdk-js/-/mock-aws-sdk-js-1.0.1.tgz", 79 | "integrity": "sha512-y/asWmrviUyRbEZt46wSMjdyzeVWYPfolFg2lpU6Fqzu0svVJv+nxWm6dvQGWUnuye89l+mGLMwQDkOkbfWNUQ==", 80 | "dev": true, 81 | "requires": { 82 | "aws-sdk": "^2.84.0", 83 | "sinon": "^4.4.9", 84 | "traverse": "^0.6.6" 85 | }, 86 | "dependencies": { 87 | "@sinonjs/formatio": { 88 | "version": "2.0.0", 89 | "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", 90 | "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", 91 | "dev": true, 92 | "requires": { 93 | "samsam": "1.3.0" 94 | } 95 | }, 96 | "lolex": { 97 | "version": "2.7.5", 98 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", 99 | "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", 100 | "dev": true 101 | }, 102 | "sinon": { 103 | "version": "4.5.0", 104 | "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.5.0.tgz", 105 | "integrity": "sha512-trdx+mB0VBBgoYucy6a9L7/jfQOmvGeaKZT4OOJ+lPAtI8623xyGr8wLiE4eojzBS8G9yXbhx42GHUOVLr4X2w==", 106 | "dev": true, 107 | "requires": { 108 | "@sinonjs/formatio": "^2.0.0", 109 | "diff": "^3.1.0", 110 | "lodash.get": "^4.4.2", 111 | "lolex": "^2.2.0", 112 | "nise": "^1.2.0", 113 | "supports-color": "^5.1.0", 114 | "type-detect": "^4.0.5" 115 | } 116 | } 117 | } 118 | }, 119 | "@mapbox/mvt-fixtures": { 120 | "version": "3.6.0", 121 | "resolved": "https://registry.npmjs.org/@mapbox/mvt-fixtures/-/mvt-fixtures-3.6.0.tgz", 122 | "integrity": "sha512-YgaODBQdutOcCnOiRJzbJO3lRejuaeuwfYk0XxfVlAi6L+UDXVHzi7NlpAa6GAYGzQm1V1KLk+2Io8+aSv8I+w==", 123 | "dev": true, 124 | "requires": { 125 | "@mapbox/sphericalmercator": "^1.0.5", 126 | "@mapbox/vector-tile": "^1.3.0", 127 | "d3-queue": "^3.0.7", 128 | "pbf": "^3.0.5", 129 | "protocol-buffers-schema": "^3.3.2" 130 | }, 131 | "dependencies": { 132 | "d3-queue": { 133 | "version": "3.0.7", 134 | "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-3.0.7.tgz", 135 | "integrity": "sha1-yTouVLQXwJWRKdfXP2z31Ckudhg=", 136 | "dev": true 137 | }, 138 | "pbf": { 139 | "version": "3.2.1", 140 | "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", 141 | "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", 142 | "dev": true, 143 | "requires": { 144 | "ieee754": "^1.1.12", 145 | "resolve-protobuf-schema": "^2.1.0" 146 | } 147 | } 148 | } 149 | }, 150 | "@mapbox/point-geometry": { 151 | "version": "0.1.0", 152 | "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", 153 | "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" 154 | }, 155 | "@mapbox/s3urls": { 156 | "version": "1.5.3", 157 | "resolved": "https://registry.npmjs.org/@mapbox/s3urls/-/s3urls-1.5.3.tgz", 158 | "integrity": "sha1-hXj1GUGvK6g2Yj9JQadhUVzpL/E=", 159 | "requires": { 160 | "@mapbox/eslint-config-mapbox": "^1.0.0", 161 | "minimist": "^1.1.0", 162 | "s3signed": "^0.1.0" 163 | }, 164 | "dependencies": { 165 | "minimist": { 166 | "version": "1.2.0", 167 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 168 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 169 | } 170 | } 171 | }, 172 | "@mapbox/sphericalmercator": { 173 | "version": "1.1.0", 174 | "resolved": "https://registry.npmjs.org/@mapbox/sphericalmercator/-/sphericalmercator-1.1.0.tgz", 175 | "integrity": "sha512-pEsfZyG4OMThlfFQbCte4gegvHUjxXCjz0KZ4Xk8NdOYTQBLflj6U8PL05RPAiuRAMAQNUUKJuL6qYZ5Y4kAWA==" 176 | }, 177 | "@mapbox/tilejson": { 178 | "version": "1.1.0", 179 | "resolved": "https://registry.npmjs.org/@mapbox/tilejson/-/tilejson-1.1.0.tgz", 180 | "integrity": "sha1-cot6KtmBSEFfA3AkMZUOIXTLqcc=", 181 | "requires": { 182 | "@mapbox/tiletype": "~0.3.1", 183 | "agentkeepalive": "2.0.2", 184 | "requestretry": "^1.12.0" 185 | } 186 | }, 187 | "@mapbox/tilelive": { 188 | "version": "5.12.6", 189 | "resolved": "https://registry.npmjs.org/@mapbox/tilelive/-/tilelive-5.12.6.tgz", 190 | "integrity": "sha1-ALPv4LmZ6DB7wcwJnLdw2nZ2aQs=", 191 | "requires": { 192 | "@mapbox/sphericalmercator": "~1.0.1", 193 | "minimist": "~0.2.0", 194 | "progress-stream": "~0.5.x", 195 | "queue-async": "~1.0.7" 196 | }, 197 | "dependencies": { 198 | "@mapbox/sphericalmercator": { 199 | "version": "1.0.5", 200 | "resolved": "https://registry.npmjs.org/@mapbox/sphericalmercator/-/sphericalmercator-1.0.5.tgz", 201 | "integrity": "sha1-cCN7l3QJXtHP286nqP0fyCsmkfI=" 202 | }, 203 | "queue-async": { 204 | "version": "1.0.7", 205 | "resolved": "https://registry.npmjs.org/queue-async/-/queue-async-1.0.7.tgz", 206 | "integrity": "sha1-Iq4KHaxKkvW81GNPmTxoKiqBCUU=" 207 | } 208 | } 209 | }, 210 | "@mapbox/tilelive-bridge": { 211 | "version": "3.2.1", 212 | "resolved": "https://registry.npmjs.org/@mapbox/tilelive-bridge/-/tilelive-bridge-3.2.1.tgz", 213 | "integrity": "sha512-sOHHHVIxlFPBw6r0zqfNfZeadaM7h7PU+Bu2V98deboa09URNT2wvgNQqNMEQ1vNBa0ZR7NqZ7PP9IyvepADeA==", 214 | "requires": { 215 | "@mapbox/sphericalmercator": "~1.0.1", 216 | "mapnik": "4.x || 3.x", 217 | "mapnik-pool": "~0.1.3" 218 | }, 219 | "dependencies": { 220 | "@mapbox/sphericalmercator": { 221 | "version": "1.0.5", 222 | "resolved": "https://registry.npmjs.org/@mapbox/sphericalmercator/-/sphericalmercator-1.0.5.tgz", 223 | "integrity": "sha1-cCN7l3QJXtHP286nqP0fyCsmkfI=" 224 | } 225 | } 226 | }, 227 | "@mapbox/tilelive-omnivore": { 228 | "version": "4.3.0", 229 | "resolved": "https://registry.npmjs.org/@mapbox/tilelive-omnivore/-/tilelive-omnivore-4.3.0.tgz", 230 | "integrity": "sha512-u8kYa8J5hpVYUsWZkCrZg4DLqkTsDZl5VAjGlwftovTRTP/l+iwoG38RG97f5RWhanNskniYBoHcv/w8d+aLUw==", 231 | "requires": { 232 | "@mapbox/mapnik-omnivore": "10.0.0", 233 | "@mapbox/tilelive-bridge": "^3.2.0", 234 | "queue-async": "^1.0.7", 235 | "underscore": "^1.7.0" 236 | } 237 | }, 238 | "@mapbox/tilelive-s3": { 239 | "version": "6.5.1", 240 | "resolved": "https://registry.npmjs.org/@mapbox/tilelive-s3/-/tilelive-s3-6.5.1.tgz", 241 | "integrity": "sha1-0ul/03Bfdi+6ylQB/nB/xUsJHDU=", 242 | "requires": { 243 | "@mapbox/tiletype": "^0.3.0", 244 | "agentkeepalive": "^2.0.3", 245 | "aws-sdk": "^2.6.0", 246 | "s3urls": "^1.4.0" 247 | }, 248 | "dependencies": { 249 | "agentkeepalive": { 250 | "version": "2.2.0", 251 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.2.0.tgz", 252 | "integrity": "sha1-xdG9SxKQCPEWPyNvhuX66iAm4u8=" 253 | }, 254 | "minimist": { 255 | "version": "1.2.0", 256 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 257 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 258 | }, 259 | "s3urls": { 260 | "version": "1.5.2", 261 | "resolved": "https://registry.npmjs.org/s3urls/-/s3urls-1.5.2.tgz", 262 | "integrity": "sha1-GCqZEgj8GrUhREPrJQ/I9TtLyeo=", 263 | "requires": { 264 | "minimist": "^1.1.0", 265 | "s3signed": "^0.1.0" 266 | } 267 | } 268 | } 269 | }, 270 | "@mapbox/tilelive-vector": { 271 | "version": "4.2.0", 272 | "resolved": "https://registry.npmjs.org/@mapbox/tilelive-vector/-/tilelive-vector-4.2.0.tgz", 273 | "integrity": "sha512-pWWMoK4emiCLqypAGFTIlAkM2sQtfRxjtnrzJkXTAY6BNo6GIKGMBT/yLTjqJNmQT11NQ10OkqfhW9XzyFkOzw==", 274 | "requires": { 275 | "@mapbox/sphericalmercator": "~1.0.5", 276 | "@mapbox/tilelive": "~5.12.0", 277 | "@mapbox/tiletype": "0.3.x", 278 | "aws-sdk": "^2.2.30", 279 | "mapnik": "3.x || 4.x", 280 | "numeral": "~1.5.3", 281 | "request": "~2.83.0", 282 | "s3urls": "^1.3.0", 283 | "spherical": "~0.1.0", 284 | "tar": "~2.2.1", 285 | "underscore": "~1.8.0" 286 | }, 287 | "dependencies": { 288 | "@mapbox/sphericalmercator": { 289 | "version": "1.0.5", 290 | "resolved": "https://registry.npmjs.org/@mapbox/sphericalmercator/-/sphericalmercator-1.0.5.tgz", 291 | "integrity": "sha1-cCN7l3QJXtHP286nqP0fyCsmkfI=" 292 | }, 293 | "ajv": { 294 | "version": "5.5.2", 295 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", 296 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", 297 | "requires": { 298 | "co": "^4.6.0", 299 | "fast-deep-equal": "^1.0.0", 300 | "fast-json-stable-stringify": "^2.0.0", 301 | "json-schema-traverse": "^0.3.0" 302 | } 303 | }, 304 | "fast-deep-equal": { 305 | "version": "1.1.0", 306 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", 307 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" 308 | }, 309 | "har-validator": { 310 | "version": "5.0.3", 311 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", 312 | "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", 313 | "requires": { 314 | "ajv": "^5.1.0", 315 | "har-schema": "^2.0.0" 316 | } 317 | }, 318 | "json-schema-traverse": { 319 | "version": "0.3.1", 320 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", 321 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" 322 | }, 323 | "minimist": { 324 | "version": "1.2.0", 325 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 326 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 327 | }, 328 | "oauth-sign": { 329 | "version": "0.8.2", 330 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 331 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" 332 | }, 333 | "punycode": { 334 | "version": "1.4.1", 335 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 336 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 337 | }, 338 | "request": { 339 | "version": "2.83.0", 340 | "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", 341 | "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", 342 | "requires": { 343 | "aws-sign2": "~0.7.0", 344 | "aws4": "^1.6.0", 345 | "caseless": "~0.12.0", 346 | "combined-stream": "~1.0.5", 347 | "extend": "~3.0.1", 348 | "forever-agent": "~0.6.1", 349 | "form-data": "~2.3.1", 350 | "har-validator": "~5.0.3", 351 | "hawk": "~6.0.2", 352 | "http-signature": "~1.2.0", 353 | "is-typedarray": "~1.0.0", 354 | "isstream": "~0.1.2", 355 | "json-stringify-safe": "~5.0.1", 356 | "mime-types": "~2.1.17", 357 | "oauth-sign": "~0.8.2", 358 | "performance-now": "^2.1.0", 359 | "qs": "~6.5.1", 360 | "safe-buffer": "^5.1.1", 361 | "stringstream": "~0.0.5", 362 | "tough-cookie": "~2.3.3", 363 | "tunnel-agent": "^0.6.0", 364 | "uuid": "^3.1.0" 365 | } 366 | }, 367 | "s3urls": { 368 | "version": "1.5.2", 369 | "resolved": "https://registry.npmjs.org/s3urls/-/s3urls-1.5.2.tgz", 370 | "integrity": "sha1-GCqZEgj8GrUhREPrJQ/I9TtLyeo=", 371 | "requires": { 372 | "minimist": "^1.1.0", 373 | "s3signed": "^0.1.0" 374 | } 375 | }, 376 | "tar": { 377 | "version": "2.2.2", 378 | "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", 379 | "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", 380 | "requires": { 381 | "block-stream": "*", 382 | "fstream": "^1.0.12", 383 | "inherits": "2" 384 | } 385 | }, 386 | "tough-cookie": { 387 | "version": "2.3.4", 388 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 389 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 390 | "requires": { 391 | "punycode": "^1.4.1" 392 | } 393 | }, 394 | "underscore": { 395 | "version": "1.8.3", 396 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", 397 | "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" 398 | } 399 | } 400 | }, 401 | "@mapbox/tiletype": { 402 | "version": "0.3.1", 403 | "resolved": "https://registry.npmjs.org/@mapbox/tiletype/-/tiletype-0.3.1.tgz", 404 | "integrity": "sha1-GhSY9qG3d2MOC006L+2dlJWVYMw=" 405 | }, 406 | "@mapbox/vector-tile": { 407 | "version": "1.3.1", 408 | "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-1.3.1.tgz", 409 | "integrity": "sha512-MCEddb8u44/xfQ3oD+Srl/tNcQoqTw3goGk2oLsrFxOTc3dUp+kAnby3PvAeeBYSMSjSPD1nd1AJA6W49WnoUw==", 410 | "requires": { 411 | "@mapbox/point-geometry": "~0.1.0" 412 | } 413 | }, 414 | "@mapbox/vtvalidate": { 415 | "version": "0.2.3", 416 | "resolved": "https://registry.npmjs.org/@mapbox/vtvalidate/-/vtvalidate-0.2.3.tgz", 417 | "integrity": "sha512-i9hf+1osHf+uBvBk+HeFmFT6puqo/h2Lo1wj1DViDusoKpPxQcfU0iRqotTr2hZiyqKk2vHHc5mw29lTcKDNAw==", 418 | "requires": { 419 | "nan": "~2.10.0", 420 | "node-pre-gyp": "~0.10.1" 421 | }, 422 | "dependencies": { 423 | "nan": { 424 | "version": "2.10.0", 425 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", 426 | "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" 427 | }, 428 | "node-pre-gyp": { 429 | "version": "0.10.3", 430 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", 431 | "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", 432 | "requires": { 433 | "detect-libc": "^1.0.2", 434 | "mkdirp": "^0.5.1", 435 | "needle": "^2.2.1", 436 | "nopt": "^4.0.1", 437 | "npm-packlist": "^1.1.6", 438 | "npmlog": "^4.0.2", 439 | "rc": "^1.2.7", 440 | "rimraf": "^2.6.1", 441 | "semver": "^5.3.0", 442 | "tar": "^4" 443 | } 444 | } 445 | } 446 | }, 447 | "@sinonjs/commons": { 448 | "version": "1.7.0", 449 | "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.0.tgz", 450 | "integrity": "sha512-qbk9AP+cZUsKdW1GJsBpxPKFmCJ0T8swwzVje3qFd+AkQb74Q/tiuzrdfFg8AD2g5HH/XbE/I8Uc1KYHVYWfhg==", 451 | "dev": true, 452 | "requires": { 453 | "type-detect": "4.0.8" 454 | } 455 | }, 456 | "@sinonjs/formatio": { 457 | "version": "3.2.2", 458 | "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.2.2.tgz", 459 | "integrity": "sha512-B8SEsgd8gArBLMD6zpRw3juQ2FVSsmdd7qlevyDqzS9WTCtvF55/gAL+h6gue8ZvPYcdiPdvueM/qm//9XzyTQ==", 460 | "dev": true, 461 | "requires": { 462 | "@sinonjs/commons": "^1", 463 | "@sinonjs/samsam": "^3.1.0" 464 | } 465 | }, 466 | "@sinonjs/samsam": { 467 | "version": "3.3.3", 468 | "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.3.3.tgz", 469 | "integrity": "sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ==", 470 | "dev": true, 471 | "requires": { 472 | "@sinonjs/commons": "^1.3.0", 473 | "array-from": "^2.1.1", 474 | "lodash": "^4.17.15" 475 | } 476 | }, 477 | "@sinonjs/text-encoding": { 478 | "version": "0.7.1", 479 | "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", 480 | "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", 481 | "dev": true 482 | }, 483 | "abbrev": { 484 | "version": "1.1.1", 485 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 486 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" 487 | }, 488 | "agentkeepalive": { 489 | "version": "2.0.2", 490 | "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-2.0.2.tgz", 491 | "integrity": "sha1-o2YcQG7RILsRykiNZ7MnbGBMz+c=" 492 | }, 493 | "ajv": { 494 | "version": "6.10.2", 495 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", 496 | "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", 497 | "requires": { 498 | "fast-deep-equal": "^2.0.1", 499 | "fast-json-stable-stringify": "^2.0.0", 500 | "json-schema-traverse": "^0.4.1", 501 | "uri-js": "^4.2.2" 502 | } 503 | }, 504 | "ansi-regex": { 505 | "version": "2.1.1", 506 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 507 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 508 | }, 509 | "aproba": { 510 | "version": "1.2.0", 511 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 512 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" 513 | }, 514 | "are-we-there-yet": { 515 | "version": "1.1.5", 516 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", 517 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", 518 | "requires": { 519 | "delegates": "^1.0.0", 520 | "readable-stream": "^2.0.6" 521 | } 522 | }, 523 | "array-from": { 524 | "version": "2.1.1", 525 | "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", 526 | "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", 527 | "dev": true 528 | }, 529 | "asn1": { 530 | "version": "0.2.4", 531 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 532 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 533 | "requires": { 534 | "safer-buffer": "~2.1.0" 535 | } 536 | }, 537 | "assert-plus": { 538 | "version": "1.0.0", 539 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 540 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 541 | }, 542 | "asynckit": { 543 | "version": "0.4.0", 544 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 545 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 546 | }, 547 | "aws-sdk": { 548 | "version": "2.597.0", 549 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.597.0.tgz", 550 | "integrity": "sha512-xdhm1bYnh46b7pEOmIsptQcPAJmq9MT31cUsn3WzOr6IPtiRLz5XIHIusFFsJYpyjiFB99b1n8SabRR7j6H1AA==", 551 | "requires": { 552 | "buffer": "4.9.1", 553 | "events": "1.1.1", 554 | "ieee754": "1.1.13", 555 | "jmespath": "0.15.0", 556 | "querystring": "0.2.0", 557 | "sax": "1.2.1", 558 | "url": "0.10.3", 559 | "uuid": "3.3.2", 560 | "xml2js": "0.4.19" 561 | }, 562 | "dependencies": { 563 | "base64-js": { 564 | "version": "1.3.1", 565 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", 566 | "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" 567 | }, 568 | "buffer": { 569 | "version": "4.9.1", 570 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", 571 | "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", 572 | "requires": { 573 | "base64-js": "^1.0.2", 574 | "ieee754": "^1.1.4", 575 | "isarray": "^1.0.0" 576 | } 577 | }, 578 | "sax": { 579 | "version": "1.2.1", 580 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 581 | "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" 582 | }, 583 | "uuid": { 584 | "version": "3.3.2", 585 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 586 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 587 | } 588 | } 589 | }, 590 | "aws-sign2": { 591 | "version": "0.7.0", 592 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 593 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 594 | }, 595 | "aws4": { 596 | "version": "1.9.0", 597 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", 598 | "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" 599 | }, 600 | "balanced-match": { 601 | "version": "1.0.0", 602 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 603 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 604 | }, 605 | "base64-js": { 606 | "version": "0.0.8", 607 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", 608 | "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=" 609 | }, 610 | "bcrypt-pbkdf": { 611 | "version": "1.0.2", 612 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 613 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 614 | "requires": { 615 | "tweetnacl": "^0.14.3" 616 | } 617 | }, 618 | "block-stream": { 619 | "version": "0.0.9", 620 | "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", 621 | "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", 622 | "requires": { 623 | "inherits": "~2.0.0" 624 | } 625 | }, 626 | "boom": { 627 | "version": "4.3.1", 628 | "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", 629 | "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", 630 | "requires": { 631 | "hoek": "4.x.x" 632 | } 633 | }, 634 | "brace-expansion": { 635 | "version": "1.1.11", 636 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 637 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 638 | "requires": { 639 | "balanced-match": "^1.0.0", 640 | "concat-map": "0.0.1" 641 | } 642 | }, 643 | "buffer": { 644 | "version": "3.6.2", 645 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.2.tgz", 646 | "integrity": "sha512-c3M77NkHJxS0zx/ErxXhDLr1v3y2MDXPeTJPvLNOaIYJ4ymHBUFQ9EXzt9HYuqAJllMoNb/EZ8hIiulnQFAUuQ==", 647 | "requires": { 648 | "base64-js": "0.0.8", 649 | "ieee754": "^1.1.4", 650 | "isarray": "^1.0.0" 651 | } 652 | }, 653 | "camelcase": { 654 | "version": "3.0.0", 655 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", 656 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" 657 | }, 658 | "caseless": { 659 | "version": "0.12.0", 660 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 661 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 662 | }, 663 | "chownr": { 664 | "version": "1.1.3", 665 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", 666 | "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==" 667 | }, 668 | "cliui": { 669 | "version": "3.2.0", 670 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", 671 | "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", 672 | "requires": { 673 | "string-width": "^1.0.1", 674 | "strip-ansi": "^3.0.1", 675 | "wrap-ansi": "^2.0.0" 676 | } 677 | }, 678 | "co": { 679 | "version": "4.6.0", 680 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 681 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" 682 | }, 683 | "code-point-at": { 684 | "version": "1.1.0", 685 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 686 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 687 | }, 688 | "combined-stream": { 689 | "version": "1.0.8", 690 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 691 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 692 | "requires": { 693 | "delayed-stream": "~1.0.0" 694 | } 695 | }, 696 | "concat-map": { 697 | "version": "0.0.1", 698 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 699 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 700 | }, 701 | "console-control-strings": { 702 | "version": "1.1.0", 703 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 704 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" 705 | }, 706 | "core-util-is": { 707 | "version": "1.0.2", 708 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 709 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 710 | }, 711 | "cryptiles": { 712 | "version": "3.1.4", 713 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.4.tgz", 714 | "integrity": "sha512-8I1sgZHfVwcSOY6mSGpVU3lw/GSIZvusg8dD2+OGehCJpOhQRLNcH0qb9upQnOH4XhgxxFJSg6E2kx95deb1Tw==", 715 | "requires": { 716 | "boom": "5.x.x" 717 | }, 718 | "dependencies": { 719 | "boom": { 720 | "version": "5.2.0", 721 | "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", 722 | "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", 723 | "requires": { 724 | "hoek": "4.x.x" 725 | } 726 | } 727 | } 728 | }, 729 | "d3-queue": { 730 | "version": "2.0.3", 731 | "resolved": "https://registry.npmjs.org/d3-queue/-/d3-queue-2.0.3.tgz", 732 | "integrity": "sha1-B/vaOsrlNYqcUpmq+ICt8JU+0sI=" 733 | }, 734 | "dashdash": { 735 | "version": "1.14.1", 736 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 737 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 738 | "requires": { 739 | "assert-plus": "^1.0.0" 740 | } 741 | }, 742 | "debug": { 743 | "version": "3.2.6", 744 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 745 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 746 | "requires": { 747 | "ms": "^2.1.1" 748 | } 749 | }, 750 | "decamelize": { 751 | "version": "1.2.0", 752 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 753 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" 754 | }, 755 | "deep-equal": { 756 | "version": "1.1.1", 757 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", 758 | "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", 759 | "dev": true, 760 | "requires": { 761 | "is-arguments": "^1.0.4", 762 | "is-date-object": "^1.0.1", 763 | "is-regex": "^1.0.4", 764 | "object-is": "^1.0.1", 765 | "object-keys": "^1.1.1", 766 | "regexp.prototype.flags": "^1.2.0" 767 | }, 768 | "dependencies": { 769 | "object-keys": { 770 | "version": "1.1.1", 771 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 772 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 773 | "dev": true 774 | } 775 | } 776 | }, 777 | "deep-extend": { 778 | "version": "0.6.0", 779 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 780 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 781 | }, 782 | "define-properties": { 783 | "version": "1.1.3", 784 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 785 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 786 | "dev": true, 787 | "requires": { 788 | "object-keys": "^1.0.12" 789 | }, 790 | "dependencies": { 791 | "object-keys": { 792 | "version": "1.1.1", 793 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 794 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 795 | "dev": true 796 | } 797 | } 798 | }, 799 | "defined": { 800 | "version": "1.0.0", 801 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 802 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 803 | "dev": true 804 | }, 805 | "delayed-stream": { 806 | "version": "1.0.0", 807 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 808 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 809 | }, 810 | "delegates": { 811 | "version": "1.0.0", 812 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 813 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 814 | }, 815 | "detect-libc": { 816 | "version": "1.0.3", 817 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 818 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" 819 | }, 820 | "diff": { 821 | "version": "3.5.0", 822 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 823 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 824 | "dev": true 825 | }, 826 | "duplexer": { 827 | "version": "0.1.1", 828 | "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", 829 | "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=" 830 | }, 831 | "ecc-jsbn": { 832 | "version": "0.1.2", 833 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 834 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 835 | "requires": { 836 | "jsbn": "~0.1.0", 837 | "safer-buffer": "^2.1.0" 838 | } 839 | }, 840 | "error-ex": { 841 | "version": "1.3.2", 842 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 843 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 844 | "requires": { 845 | "is-arrayish": "^0.2.1" 846 | } 847 | }, 848 | "es-abstract": { 849 | "version": "1.17.0", 850 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz", 851 | "integrity": "sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==", 852 | "dev": true, 853 | "requires": { 854 | "es-to-primitive": "^1.2.1", 855 | "function-bind": "^1.1.1", 856 | "has": "^1.0.3", 857 | "has-symbols": "^1.0.1", 858 | "is-callable": "^1.1.5", 859 | "is-regex": "^1.0.5", 860 | "object-inspect": "^1.7.0", 861 | "object-keys": "^1.1.1", 862 | "object.assign": "^4.1.0", 863 | "string.prototype.trimleft": "^2.1.1", 864 | "string.prototype.trimright": "^2.1.1" 865 | }, 866 | "dependencies": { 867 | "object-keys": { 868 | "version": "1.1.1", 869 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 870 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 871 | "dev": true 872 | } 873 | } 874 | }, 875 | "es-to-primitive": { 876 | "version": "1.2.1", 877 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", 878 | "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", 879 | "dev": true, 880 | "requires": { 881 | "is-callable": "^1.1.4", 882 | "is-date-object": "^1.0.1", 883 | "is-symbol": "^1.0.2" 884 | } 885 | }, 886 | "events": { 887 | "version": "1.1.1", 888 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 889 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" 890 | }, 891 | "extend": { 892 | "version": "3.0.2", 893 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 894 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 895 | }, 896 | "extsprintf": { 897 | "version": "1.3.0", 898 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 899 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 900 | }, 901 | "fast-deep-equal": { 902 | "version": "2.0.1", 903 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 904 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 905 | }, 906 | "fast-json-stable-stringify": { 907 | "version": "2.1.0", 908 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 909 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 910 | }, 911 | "find-up": { 912 | "version": "1.1.2", 913 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 914 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 915 | "requires": { 916 | "path-exists": "^2.0.0", 917 | "pinkie-promise": "^2.0.0" 918 | } 919 | }, 920 | "for-each": { 921 | "version": "0.3.3", 922 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 923 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 924 | "dev": true, 925 | "requires": { 926 | "is-callable": "^1.1.3" 927 | } 928 | }, 929 | "forever-agent": { 930 | "version": "0.6.1", 931 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 932 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 933 | }, 934 | "form-data": { 935 | "version": "2.3.3", 936 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 937 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 938 | "requires": { 939 | "asynckit": "^0.4.0", 940 | "combined-stream": "^1.0.6", 941 | "mime-types": "^2.1.12" 942 | } 943 | }, 944 | "fs-minipass": { 945 | "version": "1.2.7", 946 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", 947 | "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", 948 | "requires": { 949 | "minipass": "^2.6.0" 950 | } 951 | }, 952 | "fs.realpath": { 953 | "version": "1.0.0", 954 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 955 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 956 | }, 957 | "fstream": { 958 | "version": "1.0.12", 959 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", 960 | "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", 961 | "requires": { 962 | "graceful-fs": "^4.1.2", 963 | "inherits": "~2.0.0", 964 | "mkdirp": ">=0.5 0", 965 | "rimraf": "2" 966 | } 967 | }, 968 | "function-bind": { 969 | "version": "1.1.1", 970 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 971 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 972 | "dev": true 973 | }, 974 | "gauge": { 975 | "version": "2.7.4", 976 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 977 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 978 | "requires": { 979 | "aproba": "^1.0.3", 980 | "console-control-strings": "^1.0.0", 981 | "has-unicode": "^2.0.0", 982 | "object-assign": "^4.1.0", 983 | "signal-exit": "^3.0.0", 984 | "string-width": "^1.0.1", 985 | "strip-ansi": "^3.0.1", 986 | "wide-align": "^1.1.0" 987 | } 988 | }, 989 | "gdal": { 990 | "version": "0.9.9", 991 | "resolved": "https://registry.npmjs.org/gdal/-/gdal-0.9.9.tgz", 992 | "integrity": "sha512-YlFal25vTaN/tdLg8Irz0pxP+sTY69F0IIdD3fnkjcNaOnM04CoT2aMYUurdDByIVXnAWRHaFYcsxVQMVWptxg==", 993 | "requires": { 994 | "nan": "~2.10.0", 995 | "node-pre-gyp": "^0.13.0" 996 | }, 997 | "dependencies": { 998 | "abbrev": { 999 | "version": "1.1.1", 1000 | "bundled": true 1001 | }, 1002 | "ansi-regex": { 1003 | "version": "2.1.1", 1004 | "bundled": true 1005 | }, 1006 | "aproba": { 1007 | "version": "1.2.0", 1008 | "bundled": true 1009 | }, 1010 | "are-we-there-yet": { 1011 | "version": "1.1.5", 1012 | "bundled": true, 1013 | "requires": { 1014 | "delegates": "^1.0.0", 1015 | "readable-stream": "^2.0.6" 1016 | } 1017 | }, 1018 | "balanced-match": { 1019 | "version": "1.0.0", 1020 | "bundled": true 1021 | }, 1022 | "brace-expansion": { 1023 | "version": "1.1.11", 1024 | "bundled": true, 1025 | "requires": { 1026 | "balanced-match": "^1.0.0", 1027 | "concat-map": "0.0.1" 1028 | } 1029 | }, 1030 | "chownr": { 1031 | "version": "1.1.2", 1032 | "bundled": true 1033 | }, 1034 | "code-point-at": { 1035 | "version": "1.1.0", 1036 | "bundled": true 1037 | }, 1038 | "concat-map": { 1039 | "version": "0.0.1", 1040 | "bundled": true 1041 | }, 1042 | "console-control-strings": { 1043 | "version": "1.1.0", 1044 | "bundled": true 1045 | }, 1046 | "core-util-is": { 1047 | "version": "1.0.2", 1048 | "bundled": true 1049 | }, 1050 | "debug": { 1051 | "version": "3.2.6", 1052 | "bundled": true, 1053 | "requires": { 1054 | "ms": "^2.1.1" 1055 | } 1056 | }, 1057 | "deep-extend": { 1058 | "version": "0.6.0", 1059 | "bundled": true 1060 | }, 1061 | "delegates": { 1062 | "version": "1.0.0", 1063 | "bundled": true 1064 | }, 1065 | "detect-libc": { 1066 | "version": "1.0.3", 1067 | "bundled": true 1068 | }, 1069 | "fs-minipass": { 1070 | "version": "1.2.6", 1071 | "bundled": true, 1072 | "requires": { 1073 | "minipass": "^2.2.1" 1074 | } 1075 | }, 1076 | "fs.realpath": { 1077 | "version": "1.0.0", 1078 | "bundled": true 1079 | }, 1080 | "gauge": { 1081 | "version": "2.7.4", 1082 | "bundled": true, 1083 | "requires": { 1084 | "aproba": "^1.0.3", 1085 | "console-control-strings": "^1.0.0", 1086 | "has-unicode": "^2.0.0", 1087 | "object-assign": "^4.1.0", 1088 | "signal-exit": "^3.0.0", 1089 | "string-width": "^1.0.1", 1090 | "strip-ansi": "^3.0.1", 1091 | "wide-align": "^1.1.0" 1092 | } 1093 | }, 1094 | "glob": { 1095 | "version": "7.1.4", 1096 | "bundled": true, 1097 | "requires": { 1098 | "fs.realpath": "^1.0.0", 1099 | "inflight": "^1.0.4", 1100 | "inherits": "2", 1101 | "minimatch": "^3.0.4", 1102 | "once": "^1.3.0", 1103 | "path-is-absolute": "^1.0.0" 1104 | } 1105 | }, 1106 | "has-unicode": { 1107 | "version": "2.0.1", 1108 | "bundled": true 1109 | }, 1110 | "iconv-lite": { 1111 | "version": "0.4.24", 1112 | "bundled": true, 1113 | "requires": { 1114 | "safer-buffer": ">= 2.1.2 < 3" 1115 | } 1116 | }, 1117 | "ignore-walk": { 1118 | "version": "3.0.1", 1119 | "bundled": true, 1120 | "requires": { 1121 | "minimatch": "^3.0.4" 1122 | } 1123 | }, 1124 | "inflight": { 1125 | "version": "1.0.6", 1126 | "bundled": true, 1127 | "requires": { 1128 | "once": "^1.3.0", 1129 | "wrappy": "1" 1130 | } 1131 | }, 1132 | "inherits": { 1133 | "version": "2.0.4", 1134 | "bundled": true 1135 | }, 1136 | "ini": { 1137 | "version": "1.3.5", 1138 | "bundled": true 1139 | }, 1140 | "is-fullwidth-code-point": { 1141 | "version": "1.0.0", 1142 | "bundled": true, 1143 | "requires": { 1144 | "number-is-nan": "^1.0.0" 1145 | } 1146 | }, 1147 | "isarray": { 1148 | "version": "1.0.0", 1149 | "bundled": true 1150 | }, 1151 | "minimatch": { 1152 | "version": "3.0.4", 1153 | "bundled": true, 1154 | "requires": { 1155 | "brace-expansion": "^1.1.7" 1156 | } 1157 | }, 1158 | "minimist": { 1159 | "version": "0.0.8", 1160 | "bundled": true 1161 | }, 1162 | "minipass": { 1163 | "version": "2.3.5", 1164 | "bundled": true, 1165 | "requires": { 1166 | "safe-buffer": "^5.1.2", 1167 | "yallist": "^3.0.0" 1168 | } 1169 | }, 1170 | "minizlib": { 1171 | "version": "1.2.1", 1172 | "bundled": true, 1173 | "requires": { 1174 | "minipass": "^2.2.1" 1175 | } 1176 | }, 1177 | "mkdirp": { 1178 | "version": "0.5.1", 1179 | "bundled": true, 1180 | "requires": { 1181 | "minimist": "0.0.8" 1182 | } 1183 | }, 1184 | "ms": { 1185 | "version": "2.1.2", 1186 | "bundled": true 1187 | }, 1188 | "nan": { 1189 | "version": "2.10.0", 1190 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", 1191 | "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" 1192 | }, 1193 | "needle": { 1194 | "version": "2.4.0", 1195 | "bundled": true, 1196 | "requires": { 1197 | "debug": "^3.2.6", 1198 | "iconv-lite": "^0.4.4", 1199 | "sax": "^1.2.4" 1200 | } 1201 | }, 1202 | "node-pre-gyp": { 1203 | "version": "0.13.0", 1204 | "bundled": true, 1205 | "requires": { 1206 | "detect-libc": "^1.0.2", 1207 | "mkdirp": "^0.5.1", 1208 | "needle": "^2.2.1", 1209 | "nopt": "^4.0.1", 1210 | "npm-packlist": "^1.1.6", 1211 | "npmlog": "^4.0.2", 1212 | "rc": "^1.2.7", 1213 | "rimraf": "^2.6.1", 1214 | "semver": "^5.3.0", 1215 | "tar": "^4" 1216 | } 1217 | }, 1218 | "nopt": { 1219 | "version": "4.0.1", 1220 | "bundled": true, 1221 | "requires": { 1222 | "abbrev": "1", 1223 | "osenv": "^0.1.4" 1224 | } 1225 | }, 1226 | "npm-bundled": { 1227 | "version": "1.0.6", 1228 | "bundled": true 1229 | }, 1230 | "npm-packlist": { 1231 | "version": "1.4.4", 1232 | "bundled": true, 1233 | "requires": { 1234 | "ignore-walk": "^3.0.1", 1235 | "npm-bundled": "^1.0.1" 1236 | } 1237 | }, 1238 | "npmlog": { 1239 | "version": "4.1.2", 1240 | "bundled": true, 1241 | "requires": { 1242 | "are-we-there-yet": "~1.1.2", 1243 | "console-control-strings": "~1.1.0", 1244 | "gauge": "~2.7.3", 1245 | "set-blocking": "~2.0.0" 1246 | } 1247 | }, 1248 | "number-is-nan": { 1249 | "version": "1.0.1", 1250 | "bundled": true 1251 | }, 1252 | "object-assign": { 1253 | "version": "4.1.1", 1254 | "bundled": true 1255 | }, 1256 | "once": { 1257 | "version": "1.4.0", 1258 | "bundled": true, 1259 | "requires": { 1260 | "wrappy": "1" 1261 | } 1262 | }, 1263 | "os-homedir": { 1264 | "version": "1.0.2", 1265 | "bundled": true 1266 | }, 1267 | "os-tmpdir": { 1268 | "version": "1.0.2", 1269 | "bundled": true 1270 | }, 1271 | "osenv": { 1272 | "version": "0.1.5", 1273 | "bundled": true, 1274 | "requires": { 1275 | "os-homedir": "^1.0.0", 1276 | "os-tmpdir": "^1.0.0" 1277 | } 1278 | }, 1279 | "path-is-absolute": { 1280 | "version": "1.0.1", 1281 | "bundled": true 1282 | }, 1283 | "process-nextick-args": { 1284 | "version": "2.0.1", 1285 | "bundled": true 1286 | }, 1287 | "rc": { 1288 | "version": "1.2.8", 1289 | "bundled": true, 1290 | "requires": { 1291 | "deep-extend": "^0.6.0", 1292 | "ini": "~1.3.0", 1293 | "minimist": "^1.2.0", 1294 | "strip-json-comments": "~2.0.1" 1295 | }, 1296 | "dependencies": { 1297 | "minimist": { 1298 | "version": "1.2.0", 1299 | "bundled": true 1300 | } 1301 | } 1302 | }, 1303 | "readable-stream": { 1304 | "version": "2.3.6", 1305 | "bundled": true, 1306 | "requires": { 1307 | "core-util-is": "~1.0.0", 1308 | "inherits": "~2.0.3", 1309 | "isarray": "~1.0.0", 1310 | "process-nextick-args": "~2.0.0", 1311 | "safe-buffer": "~5.1.1", 1312 | "string_decoder": "~1.1.1", 1313 | "util-deprecate": "~1.0.1" 1314 | } 1315 | }, 1316 | "rimraf": { 1317 | "version": "2.6.3", 1318 | "bundled": true, 1319 | "requires": { 1320 | "glob": "^7.1.3" 1321 | } 1322 | }, 1323 | "safe-buffer": { 1324 | "version": "5.1.2", 1325 | "bundled": true 1326 | }, 1327 | "safer-buffer": { 1328 | "version": "2.1.2", 1329 | "bundled": true 1330 | }, 1331 | "sax": { 1332 | "version": "1.2.4", 1333 | "bundled": true 1334 | }, 1335 | "semver": { 1336 | "version": "5.7.1", 1337 | "bundled": true 1338 | }, 1339 | "set-blocking": { 1340 | "version": "2.0.0", 1341 | "bundled": true 1342 | }, 1343 | "signal-exit": { 1344 | "version": "3.0.2", 1345 | "bundled": true 1346 | }, 1347 | "string-width": { 1348 | "version": "1.0.2", 1349 | "bundled": true, 1350 | "requires": { 1351 | "code-point-at": "^1.0.0", 1352 | "is-fullwidth-code-point": "^1.0.0", 1353 | "strip-ansi": "^3.0.0" 1354 | } 1355 | }, 1356 | "string_decoder": { 1357 | "version": "1.1.1", 1358 | "bundled": true, 1359 | "requires": { 1360 | "safe-buffer": "~5.1.0" 1361 | } 1362 | }, 1363 | "strip-ansi": { 1364 | "version": "3.0.1", 1365 | "bundled": true, 1366 | "requires": { 1367 | "ansi-regex": "^2.0.0" 1368 | } 1369 | }, 1370 | "strip-json-comments": { 1371 | "version": "2.0.1", 1372 | "bundled": true 1373 | }, 1374 | "tar": { 1375 | "version": "4.4.10", 1376 | "bundled": true, 1377 | "requires": { 1378 | "chownr": "^1.1.1", 1379 | "fs-minipass": "^1.2.5", 1380 | "minipass": "^2.3.5", 1381 | "minizlib": "^1.2.1", 1382 | "mkdirp": "^0.5.0", 1383 | "safe-buffer": "^5.1.2", 1384 | "yallist": "^3.0.3" 1385 | } 1386 | }, 1387 | "util-deprecate": { 1388 | "version": "1.0.2", 1389 | "bundled": true 1390 | }, 1391 | "wide-align": { 1392 | "version": "1.1.3", 1393 | "bundled": true, 1394 | "requires": { 1395 | "string-width": "^1.0.2 || 2" 1396 | } 1397 | }, 1398 | "wrappy": { 1399 | "version": "1.0.2", 1400 | "bundled": true 1401 | }, 1402 | "yallist": { 1403 | "version": "3.0.3", 1404 | "bundled": true 1405 | } 1406 | } 1407 | }, 1408 | "generic-pool": { 1409 | "version": "2.2.2", 1410 | "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-2.2.2.tgz", 1411 | "integrity": "sha1-eon0kdV1tC+fBpoOjixtuqPCQb4=" 1412 | }, 1413 | "get-caller-file": { 1414 | "version": "1.0.3", 1415 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 1416 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" 1417 | }, 1418 | "getpass": { 1419 | "version": "0.1.7", 1420 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 1421 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 1422 | "requires": { 1423 | "assert-plus": "^1.0.0" 1424 | } 1425 | }, 1426 | "glob": { 1427 | "version": "7.1.6", 1428 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 1429 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 1430 | "requires": { 1431 | "fs.realpath": "^1.0.0", 1432 | "inflight": "^1.0.4", 1433 | "inherits": "2", 1434 | "minimatch": "^3.0.4", 1435 | "once": "^1.3.0", 1436 | "path-is-absolute": "^1.0.0" 1437 | } 1438 | }, 1439 | "graceful-fs": { 1440 | "version": "4.2.3", 1441 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", 1442 | "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" 1443 | }, 1444 | "har-schema": { 1445 | "version": "2.0.0", 1446 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 1447 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 1448 | }, 1449 | "har-validator": { 1450 | "version": "5.1.3", 1451 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 1452 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 1453 | "requires": { 1454 | "ajv": "^6.5.5", 1455 | "har-schema": "^2.0.0" 1456 | } 1457 | }, 1458 | "has": { 1459 | "version": "1.0.3", 1460 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1461 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1462 | "dev": true, 1463 | "requires": { 1464 | "function-bind": "^1.1.1" 1465 | } 1466 | }, 1467 | "has-flag": { 1468 | "version": "3.0.0", 1469 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1470 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1471 | "dev": true 1472 | }, 1473 | "has-symbols": { 1474 | "version": "1.0.1", 1475 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", 1476 | "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", 1477 | "dev": true 1478 | }, 1479 | "has-unicode": { 1480 | "version": "2.0.1", 1481 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 1482 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" 1483 | }, 1484 | "hawk": { 1485 | "version": "6.0.2", 1486 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", 1487 | "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", 1488 | "requires": { 1489 | "boom": "4.x.x", 1490 | "cryptiles": "3.x.x", 1491 | "hoek": "4.x.x", 1492 | "sntp": "2.x.x" 1493 | } 1494 | }, 1495 | "hoek": { 1496 | "version": "4.2.1", 1497 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", 1498 | "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" 1499 | }, 1500 | "hosted-git-info": { 1501 | "version": "2.8.5", 1502 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", 1503 | "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==" 1504 | }, 1505 | "http-signature": { 1506 | "version": "1.2.0", 1507 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 1508 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 1509 | "requires": { 1510 | "assert-plus": "^1.0.0", 1511 | "jsprim": "^1.2.2", 1512 | "sshpk": "^1.7.0" 1513 | } 1514 | }, 1515 | "iconv-lite": { 1516 | "version": "0.4.24", 1517 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1518 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1519 | "requires": { 1520 | "safer-buffer": ">= 2.1.2 < 3" 1521 | } 1522 | }, 1523 | "ieee754": { 1524 | "version": "1.1.13", 1525 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 1526 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" 1527 | }, 1528 | "ignore-walk": { 1529 | "version": "3.0.3", 1530 | "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", 1531 | "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", 1532 | "requires": { 1533 | "minimatch": "^3.0.4" 1534 | } 1535 | }, 1536 | "inflight": { 1537 | "version": "1.0.6", 1538 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1539 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1540 | "requires": { 1541 | "once": "^1.3.0", 1542 | "wrappy": "1" 1543 | } 1544 | }, 1545 | "inherits": { 1546 | "version": "2.0.4", 1547 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1548 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1549 | }, 1550 | "ini": { 1551 | "version": "1.3.5", 1552 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 1553 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" 1554 | }, 1555 | "invert-kv": { 1556 | "version": "1.0.0", 1557 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 1558 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" 1559 | }, 1560 | "is-arguments": { 1561 | "version": "1.0.4", 1562 | "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", 1563 | "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", 1564 | "dev": true 1565 | }, 1566 | "is-arrayish": { 1567 | "version": "0.2.1", 1568 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1569 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" 1570 | }, 1571 | "is-callable": { 1572 | "version": "1.1.5", 1573 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", 1574 | "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", 1575 | "dev": true 1576 | }, 1577 | "is-date-object": { 1578 | "version": "1.0.2", 1579 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", 1580 | "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", 1581 | "dev": true 1582 | }, 1583 | "is-fullwidth-code-point": { 1584 | "version": "1.0.0", 1585 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1586 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1587 | "requires": { 1588 | "number-is-nan": "^1.0.0" 1589 | } 1590 | }, 1591 | "is-regex": { 1592 | "version": "1.0.5", 1593 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", 1594 | "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", 1595 | "dev": true, 1596 | "requires": { 1597 | "has": "^1.0.3" 1598 | } 1599 | }, 1600 | "is-symbol": { 1601 | "version": "1.0.3", 1602 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", 1603 | "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", 1604 | "dev": true, 1605 | "requires": { 1606 | "has-symbols": "^1.0.1" 1607 | } 1608 | }, 1609 | "is-typedarray": { 1610 | "version": "1.0.0", 1611 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 1612 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 1613 | }, 1614 | "is-utf8": { 1615 | "version": "0.2.1", 1616 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 1617 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" 1618 | }, 1619 | "isarray": { 1620 | "version": "1.0.0", 1621 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1622 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1623 | }, 1624 | "isstream": { 1625 | "version": "0.1.2", 1626 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 1627 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 1628 | }, 1629 | "jmespath": { 1630 | "version": "0.15.0", 1631 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", 1632 | "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" 1633 | }, 1634 | "jsbn": { 1635 | "version": "0.1.1", 1636 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 1637 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 1638 | }, 1639 | "json-schema": { 1640 | "version": "0.2.3", 1641 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 1642 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 1643 | }, 1644 | "json-schema-traverse": { 1645 | "version": "0.4.1", 1646 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1647 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 1648 | }, 1649 | "json-stringify-safe": { 1650 | "version": "5.0.1", 1651 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 1652 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 1653 | }, 1654 | "jsprim": { 1655 | "version": "1.4.1", 1656 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 1657 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 1658 | "requires": { 1659 | "assert-plus": "1.0.0", 1660 | "extsprintf": "1.3.0", 1661 | "json-schema": "0.2.3", 1662 | "verror": "1.10.0" 1663 | } 1664 | }, 1665 | "just-extend": { 1666 | "version": "4.0.2", 1667 | "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", 1668 | "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", 1669 | "dev": true 1670 | }, 1671 | "lcid": { 1672 | "version": "1.0.0", 1673 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 1674 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 1675 | "requires": { 1676 | "invert-kv": "^1.0.0" 1677 | } 1678 | }, 1679 | "load-json-file": { 1680 | "version": "1.1.0", 1681 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 1682 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 1683 | "requires": { 1684 | "graceful-fs": "^4.1.2", 1685 | "parse-json": "^2.2.0", 1686 | "pify": "^2.0.0", 1687 | "pinkie-promise": "^2.0.0", 1688 | "strip-bom": "^2.0.0" 1689 | } 1690 | }, 1691 | "lodash": { 1692 | "version": "4.17.15", 1693 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 1694 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" 1695 | }, 1696 | "lodash.get": { 1697 | "version": "4.4.2", 1698 | "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", 1699 | "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", 1700 | "dev": true 1701 | }, 1702 | "lolex": { 1703 | "version": "4.2.0", 1704 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.2.0.tgz", 1705 | "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", 1706 | "dev": true 1707 | }, 1708 | "mapbox-studio-default-fonts": { 1709 | "version": "https://mapbox-npm.s3.amazonaws.com/package/mapbox-studio-default-fonts-0.0.4-4afb5235f457bd1c1a5a70fce6c2aa83bf7a851e.tgz", 1710 | "integrity": "sha512-az5fpExK8qkK7qHRnqkJN8cCA4v0KD8X40H5aI8HoxfpF82XqSClrzYZ3MlxBoiAyRRKiGLq+6axt+Wib85sSQ==" 1711 | }, 1712 | "mapbox-studio-pro-fonts": { 1713 | "version": "https://mapbox-npm.s3.amazonaws.com/package/mapbox-studio-pro-fonts-1.0.0-9870a90b713f307b9391829602f4d5857e419615.tgz", 1714 | "integrity": "sha512-35u0aOHEkZPtA8nBBqZNLj2tjhTsn/yUndvSWvXqYzHe2ljf0PztZlppAsf3dKP0VNjCydxxwzO0MYGxhm86AQ==" 1715 | }, 1716 | "mapnik": { 1717 | "version": "4.3.1", 1718 | "resolved": "https://registry.npmjs.org/mapnik/-/mapnik-4.3.1.tgz", 1719 | "integrity": "sha512-ialXG9fqjR/M+c7Duq6kRI5CAU2L/YWYNYOjW+tatwgZeU9hTqyZkuXhDAL7G3Kk5vE/SqDRaQ9Cxe3N+bOUXA==", 1720 | "requires": { 1721 | "mapnik-vector-tile": "2.2.1", 1722 | "nan": "~2.14.0", 1723 | "node-pre-gyp": "~0.13.0" 1724 | }, 1725 | "dependencies": { 1726 | "node-pre-gyp": { 1727 | "version": "0.13.0", 1728 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz", 1729 | "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==", 1730 | "requires": { 1731 | "detect-libc": "^1.0.2", 1732 | "mkdirp": "^0.5.1", 1733 | "needle": "^2.2.1", 1734 | "nopt": "^4.0.1", 1735 | "npm-packlist": "^1.1.6", 1736 | "npmlog": "^4.0.2", 1737 | "rc": "^1.2.7", 1738 | "rimraf": "^2.6.1", 1739 | "semver": "^5.3.0", 1740 | "tar": "^4" 1741 | } 1742 | } 1743 | } 1744 | }, 1745 | "mapnik-pool": { 1746 | "version": "0.1.3", 1747 | "resolved": "https://registry.npmjs.org/mapnik-pool/-/mapnik-pool-0.1.3.tgz", 1748 | "integrity": "sha1-m9rRyzTYehm8eOy0y/uqIDsvPys=", 1749 | "requires": { 1750 | "generic-pool": "~2.2.1", 1751 | "xtend": "~4.0.0" 1752 | }, 1753 | "dependencies": { 1754 | "xtend": { 1755 | "version": "4.0.2", 1756 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1757 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 1758 | } 1759 | } 1760 | }, 1761 | "mapnik-vector-tile": { 1762 | "version": "2.2.1", 1763 | "resolved": "https://registry.npmjs.org/mapnik-vector-tile/-/mapnik-vector-tile-2.2.1.tgz", 1764 | "integrity": "sha512-+oasa2DfqArIMC7F71ca8CXpDt0rEcq9sJDv+AuhBCZJg+3m2ikDAs/oskEpPpUOwta1hH48Qr+0deCkyB/0Jg==" 1765 | }, 1766 | "mime-db": { 1767 | "version": "1.42.0", 1768 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", 1769 | "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" 1770 | }, 1771 | "mime-types": { 1772 | "version": "2.1.25", 1773 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", 1774 | "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", 1775 | "requires": { 1776 | "mime-db": "1.42.0" 1777 | } 1778 | }, 1779 | "minimatch": { 1780 | "version": "3.0.4", 1781 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1782 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1783 | "requires": { 1784 | "brace-expansion": "^1.1.7" 1785 | } 1786 | }, 1787 | "minimist": { 1788 | "version": "0.2.0", 1789 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz", 1790 | "integrity": "sha1-Tf/lJdriuGTGbC4jxicdev3s784=" 1791 | }, 1792 | "minipass": { 1793 | "version": "2.9.0", 1794 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", 1795 | "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", 1796 | "requires": { 1797 | "safe-buffer": "^5.1.2", 1798 | "yallist": "^3.0.0" 1799 | } 1800 | }, 1801 | "minizlib": { 1802 | "version": "1.3.3", 1803 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", 1804 | "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", 1805 | "requires": { 1806 | "minipass": "^2.9.0" 1807 | } 1808 | }, 1809 | "mkdirp": { 1810 | "version": "0.5.1", 1811 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1812 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1813 | "requires": { 1814 | "minimist": "0.0.8" 1815 | }, 1816 | "dependencies": { 1817 | "minimist": { 1818 | "version": "0.0.8", 1819 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1820 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 1821 | } 1822 | } 1823 | }, 1824 | "ms": { 1825 | "version": "2.1.2", 1826 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1827 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1828 | }, 1829 | "nan": { 1830 | "version": "2.14.0", 1831 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 1832 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" 1833 | }, 1834 | "needle": { 1835 | "version": "2.4.0", 1836 | "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", 1837 | "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", 1838 | "requires": { 1839 | "debug": "^3.2.6", 1840 | "iconv-lite": "^0.4.4", 1841 | "sax": "^1.2.4" 1842 | } 1843 | }, 1844 | "nise": { 1845 | "version": "1.5.3", 1846 | "resolved": "https://registry.npmjs.org/nise/-/nise-1.5.3.tgz", 1847 | "integrity": "sha512-Ymbac/94xeIrMf59REBPOv0thr+CJVFMhrlAkW/gjCIE58BGQdCj0x7KRCb3yz+Ga2Rz3E9XXSvUyyxqqhjQAQ==", 1848 | "dev": true, 1849 | "requires": { 1850 | "@sinonjs/formatio": "^3.2.1", 1851 | "@sinonjs/text-encoding": "^0.7.1", 1852 | "just-extend": "^4.0.2", 1853 | "lolex": "^5.0.1", 1854 | "path-to-regexp": "^1.7.0" 1855 | }, 1856 | "dependencies": { 1857 | "lolex": { 1858 | "version": "5.1.2", 1859 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz", 1860 | "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==", 1861 | "dev": true, 1862 | "requires": { 1863 | "@sinonjs/commons": "^1.7.0" 1864 | } 1865 | } 1866 | } 1867 | }, 1868 | "nock": { 1869 | "version": "13.3.1", 1870 | "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.1.tgz", 1871 | "integrity": "sha512-vHnopocZuI93p2ccivFyGuUfzjq2fxNyNurp7816mlT5V5HF4SzXu8lvLrVzBbNqzs+ODooZ6OksuSUNM7Njkw==", 1872 | "dev": true, 1873 | "requires": { 1874 | "debug": "^4.1.0", 1875 | "json-stringify-safe": "^5.0.1", 1876 | "lodash": "^4.17.21", 1877 | "propagate": "^2.0.0" 1878 | }, 1879 | "dependencies": { 1880 | "debug": { 1881 | "version": "4.3.4", 1882 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1883 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1884 | "dev": true, 1885 | "requires": { 1886 | "ms": "2.1.2" 1887 | } 1888 | }, 1889 | "lodash": { 1890 | "version": "4.17.21", 1891 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 1892 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", 1893 | "dev": true 1894 | } 1895 | } 1896 | }, 1897 | "node-pre-gyp": { 1898 | "version": "0.11.0", 1899 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", 1900 | "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", 1901 | "requires": { 1902 | "detect-libc": "^1.0.2", 1903 | "mkdirp": "^0.5.1", 1904 | "needle": "^2.2.1", 1905 | "nopt": "^4.0.1", 1906 | "npm-packlist": "^1.1.6", 1907 | "npmlog": "^4.0.2", 1908 | "rc": "^1.2.7", 1909 | "rimraf": "^2.6.1", 1910 | "semver": "^5.3.0", 1911 | "tar": "^4" 1912 | } 1913 | }, 1914 | "nopt": { 1915 | "version": "4.0.1", 1916 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", 1917 | "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", 1918 | "requires": { 1919 | "abbrev": "1", 1920 | "osenv": "^0.1.4" 1921 | } 1922 | }, 1923 | "normalize-package-data": { 1924 | "version": "2.5.0", 1925 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", 1926 | "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", 1927 | "requires": { 1928 | "hosted-git-info": "^2.1.4", 1929 | "resolve": "^1.10.0", 1930 | "semver": "2 || 3 || 4 || 5", 1931 | "validate-npm-package-license": "^3.0.1" 1932 | } 1933 | }, 1934 | "npm-bundled": { 1935 | "version": "1.1.1", 1936 | "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", 1937 | "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", 1938 | "requires": { 1939 | "npm-normalize-package-bin": "^1.0.1" 1940 | } 1941 | }, 1942 | "npm-normalize-package-bin": { 1943 | "version": "1.0.1", 1944 | "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", 1945 | "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" 1946 | }, 1947 | "npm-packlist": { 1948 | "version": "1.4.7", 1949 | "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.7.tgz", 1950 | "integrity": "sha512-vAj7dIkp5NhieaGZxBJB8fF4R0078rqsmhJcAfXZ6O7JJhjhPK96n5Ry1oZcfLXgfun0GWTZPOxaEyqv8GBykQ==", 1951 | "requires": { 1952 | "ignore-walk": "^3.0.1", 1953 | "npm-bundled": "^1.0.1" 1954 | } 1955 | }, 1956 | "npmlog": { 1957 | "version": "4.1.2", 1958 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 1959 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 1960 | "requires": { 1961 | "are-we-there-yet": "~1.1.2", 1962 | "console-control-strings": "~1.1.0", 1963 | "gauge": "~2.7.3", 1964 | "set-blocking": "~2.0.0" 1965 | } 1966 | }, 1967 | "number-is-nan": { 1968 | "version": "1.0.1", 1969 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1970 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 1971 | }, 1972 | "numeral": { 1973 | "version": "1.5.6", 1974 | "resolved": "https://registry.npmjs.org/numeral/-/numeral-1.5.6.tgz", 1975 | "integrity": "sha1-ODHbloRRuc9q/5v5WSXx7443sz8=" 1976 | }, 1977 | "oauth-sign": { 1978 | "version": "0.9.0", 1979 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 1980 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 1981 | }, 1982 | "object-assign": { 1983 | "version": "4.1.1", 1984 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1985 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 1986 | }, 1987 | "object-inspect": { 1988 | "version": "1.7.0", 1989 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", 1990 | "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", 1991 | "dev": true 1992 | }, 1993 | "object-is": { 1994 | "version": "1.0.2", 1995 | "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.0.2.tgz", 1996 | "integrity": "sha512-Epah+btZd5wrrfjkJZq1AOB9O6OxUQto45hzFd7lXGrpHPGE0W1k+426yrZV+k6NJOzLNNW/nVsmZdIWsAqoOQ==", 1997 | "dev": true 1998 | }, 1999 | "object-keys": { 2000 | "version": "0.4.0", 2001 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", 2002 | "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=" 2003 | }, 2004 | "object.assign": { 2005 | "version": "4.1.0", 2006 | "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", 2007 | "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", 2008 | "dev": true, 2009 | "requires": { 2010 | "define-properties": "^1.1.2", 2011 | "function-bind": "^1.1.1", 2012 | "has-symbols": "^1.0.0", 2013 | "object-keys": "^1.0.11" 2014 | }, 2015 | "dependencies": { 2016 | "object-keys": { 2017 | "version": "1.1.1", 2018 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 2019 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 2020 | "dev": true 2021 | } 2022 | } 2023 | }, 2024 | "once": { 2025 | "version": "1.4.0", 2026 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2027 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 2028 | "requires": { 2029 | "wrappy": "1" 2030 | } 2031 | }, 2032 | "os-homedir": { 2033 | "version": "1.0.2", 2034 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 2035 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" 2036 | }, 2037 | "os-locale": { 2038 | "version": "1.4.0", 2039 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", 2040 | "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", 2041 | "requires": { 2042 | "lcid": "^1.0.0" 2043 | } 2044 | }, 2045 | "os-tmpdir": { 2046 | "version": "1.0.2", 2047 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 2048 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 2049 | }, 2050 | "osenv": { 2051 | "version": "0.1.5", 2052 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", 2053 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", 2054 | "requires": { 2055 | "os-homedir": "^1.0.0", 2056 | "os-tmpdir": "^1.0.0" 2057 | } 2058 | }, 2059 | "parse-json": { 2060 | "version": "2.2.0", 2061 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 2062 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 2063 | "requires": { 2064 | "error-ex": "^1.2.0" 2065 | } 2066 | }, 2067 | "path-exists": { 2068 | "version": "2.1.0", 2069 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 2070 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 2071 | "requires": { 2072 | "pinkie-promise": "^2.0.0" 2073 | } 2074 | }, 2075 | "path-is-absolute": { 2076 | "version": "1.0.1", 2077 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2078 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 2079 | }, 2080 | "path-parse": { 2081 | "version": "1.0.6", 2082 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 2083 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" 2084 | }, 2085 | "path-to-regexp": { 2086 | "version": "1.8.0", 2087 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", 2088 | "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", 2089 | "dev": true, 2090 | "requires": { 2091 | "isarray": "0.0.1" 2092 | }, 2093 | "dependencies": { 2094 | "isarray": { 2095 | "version": "0.0.1", 2096 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 2097 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 2098 | "dev": true 2099 | } 2100 | } 2101 | }, 2102 | "path-type": { 2103 | "version": "1.1.0", 2104 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 2105 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 2106 | "requires": { 2107 | "graceful-fs": "^4.1.2", 2108 | "pify": "^2.0.0", 2109 | "pinkie-promise": "^2.0.0" 2110 | } 2111 | }, 2112 | "pbf": { 2113 | "version": "1.3.2", 2114 | "resolved": "https://registry.npmjs.org/pbf/-/pbf-1.3.2.tgz", 2115 | "integrity": "sha512-uvisDHLTDFbPkQHHcGuSWYKiVD3OZ3IPnr/UyGV4OAT7UJr5FH784uS5MckyMPDMhsrOFr6NDfAQRGXyy9C1pA==", 2116 | "requires": { 2117 | "ieee754": "~1.1.4", 2118 | "resolve-protobuf-schema": "^1.0.2" 2119 | }, 2120 | "dependencies": { 2121 | "resolve-protobuf-schema": { 2122 | "version": "1.0.2", 2123 | "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-1.0.2.tgz", 2124 | "integrity": "sha512-x9optLjaRApo9b/CKahouGGpkUYbsBfEp3TpmwQCZUcu4t7c6hTXPWVwpDdy4Y4e5wKtg/G15rp1btIAQG2waA==", 2125 | "requires": { 2126 | "protobuf-schema": "^1.2.0" 2127 | } 2128 | } 2129 | } 2130 | }, 2131 | "performance-now": { 2132 | "version": "2.1.0", 2133 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 2134 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 2135 | }, 2136 | "pify": { 2137 | "version": "2.3.0", 2138 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 2139 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" 2140 | }, 2141 | "pinkie": { 2142 | "version": "2.0.4", 2143 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 2144 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" 2145 | }, 2146 | "pinkie-promise": { 2147 | "version": "2.0.1", 2148 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 2149 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 2150 | "requires": { 2151 | "pinkie": "^2.0.0" 2152 | } 2153 | }, 2154 | "process-nextick-args": { 2155 | "version": "2.0.1", 2156 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 2157 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 2158 | }, 2159 | "progress-stream": { 2160 | "version": "0.5.0", 2161 | "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-0.5.0.tgz", 2162 | "integrity": "sha1-zEdZFnpv9PBYdheThPC2rg0ddYc=", 2163 | "requires": { 2164 | "single-line-log": "~0.3.1", 2165 | "speedometer": "~0.1.2", 2166 | "through2": "~0.2.3" 2167 | } 2168 | }, 2169 | "propagate": { 2170 | "version": "2.0.1", 2171 | "resolved": "https://registry.npmjs.org/propagate/-/propagate-2.0.1.tgz", 2172 | "integrity": "sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag==", 2173 | "dev": true 2174 | }, 2175 | "protobuf-schema": { 2176 | "version": "1.5.1", 2177 | "resolved": "https://registry.npmjs.org/protobuf-schema/-/protobuf-schema-1.5.1.tgz", 2178 | "integrity": "sha512-jPi6WrJQeqr717Fd42bY9L+rKb6VwGA3ZMAe9X3hwaIrCqW+bM+K+wu+DlVnP5MY2QoS6mqNIiOf9elymWdT6A==" 2179 | }, 2180 | "protocol-buffers-schema": { 2181 | "version": "3.3.2", 2182 | "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz", 2183 | "integrity": "sha512-Xdayp8sB/mU+sUV4G7ws8xtYMGdQnxbeIfLjyO9TZZRJdztBGhlmbI5x1qcY4TG5hBkIKGnc28i7nXxaugu88w==", 2184 | "dev": true 2185 | }, 2186 | "psl": { 2187 | "version": "1.7.0", 2188 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", 2189 | "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" 2190 | }, 2191 | "punycode": { 2192 | "version": "2.1.1", 2193 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 2194 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 2195 | }, 2196 | "qs": { 2197 | "version": "6.5.2", 2198 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 2199 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 2200 | }, 2201 | "querystring": { 2202 | "version": "0.2.0", 2203 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 2204 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" 2205 | }, 2206 | "queue-async": { 2207 | "version": "1.2.1", 2208 | "resolved": "https://registry.npmjs.org/queue-async/-/queue-async-1.2.1.tgz", 2209 | "integrity": "sha1-BYLgHa4lMljPV2/Co125b8qEf28=" 2210 | }, 2211 | "rc": { 2212 | "version": "1.2.8", 2213 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 2214 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 2215 | "requires": { 2216 | "deep-extend": "^0.6.0", 2217 | "ini": "~1.3.0", 2218 | "minimist": "^1.2.0", 2219 | "strip-json-comments": "~2.0.1" 2220 | }, 2221 | "dependencies": { 2222 | "minimist": { 2223 | "version": "1.2.0", 2224 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 2225 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 2226 | } 2227 | } 2228 | }, 2229 | "read-pkg": { 2230 | "version": "1.1.0", 2231 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 2232 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 2233 | "requires": { 2234 | "load-json-file": "^1.0.0", 2235 | "normalize-package-data": "^2.3.2", 2236 | "path-type": "^1.0.0" 2237 | } 2238 | }, 2239 | "read-pkg-up": { 2240 | "version": "1.0.1", 2241 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 2242 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 2243 | "requires": { 2244 | "find-up": "^1.0.0", 2245 | "read-pkg": "^1.0.0" 2246 | } 2247 | }, 2248 | "readable-stream": { 2249 | "version": "2.3.6", 2250 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 2251 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 2252 | "requires": { 2253 | "core-util-is": "~1.0.0", 2254 | "inherits": "~2.0.3", 2255 | "isarray": "~1.0.0", 2256 | "process-nextick-args": "~2.0.0", 2257 | "safe-buffer": "~5.1.1", 2258 | "string_decoder": "~1.1.1", 2259 | "util-deprecate": "~1.0.1" 2260 | } 2261 | }, 2262 | "regexp.prototype.flags": { 2263 | "version": "1.3.0", 2264 | "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", 2265 | "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", 2266 | "dev": true, 2267 | "requires": { 2268 | "define-properties": "^1.1.3", 2269 | "es-abstract": "^1.17.0-next.1" 2270 | } 2271 | }, 2272 | "request": { 2273 | "version": "2.88.0", 2274 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 2275 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 2276 | "requires": { 2277 | "aws-sign2": "~0.7.0", 2278 | "aws4": "^1.8.0", 2279 | "caseless": "~0.12.0", 2280 | "combined-stream": "~1.0.6", 2281 | "extend": "~3.0.2", 2282 | "forever-agent": "~0.6.1", 2283 | "form-data": "~2.3.2", 2284 | "har-validator": "~5.1.0", 2285 | "http-signature": "~1.2.0", 2286 | "is-typedarray": "~1.0.0", 2287 | "isstream": "~0.1.2", 2288 | "json-stringify-safe": "~5.0.1", 2289 | "mime-types": "~2.1.19", 2290 | "oauth-sign": "~0.9.0", 2291 | "performance-now": "^2.1.0", 2292 | "qs": "~6.5.2", 2293 | "safe-buffer": "^5.1.2", 2294 | "tough-cookie": "~2.4.3", 2295 | "tunnel-agent": "^0.6.0", 2296 | "uuid": "^3.3.2" 2297 | } 2298 | }, 2299 | "requestretry": { 2300 | "version": "1.13.0", 2301 | "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", 2302 | "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", 2303 | "requires": { 2304 | "extend": "^3.0.0", 2305 | "lodash": "^4.15.0", 2306 | "request": "^2.74.0", 2307 | "when": "^3.7.7" 2308 | } 2309 | }, 2310 | "require-directory": { 2311 | "version": "2.1.1", 2312 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 2313 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" 2314 | }, 2315 | "require-main-filename": { 2316 | "version": "1.0.1", 2317 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 2318 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" 2319 | }, 2320 | "resolve": { 2321 | "version": "1.14.1", 2322 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.14.1.tgz", 2323 | "integrity": "sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==", 2324 | "requires": { 2325 | "path-parse": "^1.0.6" 2326 | } 2327 | }, 2328 | "resolve-protobuf-schema": { 2329 | "version": "2.1.0", 2330 | "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", 2331 | "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", 2332 | "dev": true, 2333 | "requires": { 2334 | "protocol-buffers-schema": "^3.3.1" 2335 | } 2336 | }, 2337 | "resumer": { 2338 | "version": "0.0.0", 2339 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 2340 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 2341 | "dev": true, 2342 | "requires": { 2343 | "through": "~2.3.4" 2344 | } 2345 | }, 2346 | "rimraf": { 2347 | "version": "2.7.1", 2348 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 2349 | "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", 2350 | "requires": { 2351 | "glob": "^7.1.3" 2352 | } 2353 | }, 2354 | "s3signed": { 2355 | "version": "0.1.0", 2356 | "resolved": "https://registry.npmjs.org/s3signed/-/s3signed-0.1.0.tgz", 2357 | "integrity": "sha1-rgO4YllBMhXtQ+mShcjDR1eXNfs=", 2358 | "requires": { 2359 | "aws-sdk": "^2.0.4" 2360 | } 2361 | }, 2362 | "safe-buffer": { 2363 | "version": "5.1.2", 2364 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 2365 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 2366 | }, 2367 | "safer-buffer": { 2368 | "version": "2.1.2", 2369 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2370 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 2371 | }, 2372 | "samsam": { 2373 | "version": "1.3.0", 2374 | "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", 2375 | "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", 2376 | "dev": true 2377 | }, 2378 | "sax": { 2379 | "version": "1.2.4", 2380 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 2381 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 2382 | }, 2383 | "semver": { 2384 | "version": "5.3.0", 2385 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 2386 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" 2387 | }, 2388 | "set-blocking": { 2389 | "version": "2.0.0", 2390 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 2391 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" 2392 | }, 2393 | "signal-exit": { 2394 | "version": "3.0.2", 2395 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 2396 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 2397 | }, 2398 | "single-line-log": { 2399 | "version": "0.3.1", 2400 | "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.3.1.tgz", 2401 | "integrity": "sha1-p61lB/IYzl3+FsS/LWWSRkGeegY=" 2402 | }, 2403 | "sinon": { 2404 | "version": "7.5.0", 2405 | "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", 2406 | "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", 2407 | "dev": true, 2408 | "requires": { 2409 | "@sinonjs/commons": "^1.4.0", 2410 | "@sinonjs/formatio": "^3.2.1", 2411 | "@sinonjs/samsam": "^3.3.3", 2412 | "diff": "^3.5.0", 2413 | "lolex": "^4.2.0", 2414 | "nise": "^1.5.2", 2415 | "supports-color": "^5.5.0" 2416 | } 2417 | }, 2418 | "sntp": { 2419 | "version": "2.1.0", 2420 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", 2421 | "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", 2422 | "requires": { 2423 | "hoek": "4.x.x" 2424 | } 2425 | }, 2426 | "spdx-correct": { 2427 | "version": "3.1.0", 2428 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", 2429 | "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", 2430 | "requires": { 2431 | "spdx-expression-parse": "^3.0.0", 2432 | "spdx-license-ids": "^3.0.0" 2433 | } 2434 | }, 2435 | "spdx-exceptions": { 2436 | "version": "2.2.0", 2437 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", 2438 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==" 2439 | }, 2440 | "spdx-expression-parse": { 2441 | "version": "3.0.0", 2442 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 2443 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 2444 | "requires": { 2445 | "spdx-exceptions": "^2.1.0", 2446 | "spdx-license-ids": "^3.0.0" 2447 | } 2448 | }, 2449 | "spdx-license-ids": { 2450 | "version": "3.0.5", 2451 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", 2452 | "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" 2453 | }, 2454 | "speedometer": { 2455 | "version": "0.1.4", 2456 | "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", 2457 | "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=" 2458 | }, 2459 | "spherical": { 2460 | "version": "0.1.0", 2461 | "resolved": "https://registry.npmjs.org/spherical/-/spherical-0.1.0.tgz", 2462 | "integrity": "sha1-H+rMS4O80NwtiV74rbhfil7FQ8I=", 2463 | "requires": { 2464 | "wgs84": "0.0.0" 2465 | } 2466 | }, 2467 | "sqlite3": { 2468 | "version": "4.1.1", 2469 | "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz", 2470 | "integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==", 2471 | "requires": { 2472 | "nan": "^2.12.1", 2473 | "node-pre-gyp": "^0.11.0", 2474 | "request": "^2.87.0" 2475 | } 2476 | }, 2477 | "srs": { 2478 | "version": "1.2.0", 2479 | "resolved": "https://registry.npmjs.org/srs/-/srs-1.2.0.tgz", 2480 | "integrity": "sha1-7LRHhU33bOsStFKQMr4j6eGO7Nw=", 2481 | "requires": { 2482 | "gdal": "~0.9.2" 2483 | } 2484 | }, 2485 | "sshpk": { 2486 | "version": "1.16.1", 2487 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 2488 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 2489 | "requires": { 2490 | "asn1": "~0.2.3", 2491 | "assert-plus": "^1.0.0", 2492 | "bcrypt-pbkdf": "^1.0.0", 2493 | "dashdash": "^1.12.0", 2494 | "ecc-jsbn": "~0.1.1", 2495 | "getpass": "^0.1.1", 2496 | "jsbn": "~0.1.0", 2497 | "safer-buffer": "^2.0.2", 2498 | "tweetnacl": "~0.14.0" 2499 | } 2500 | }, 2501 | "stream-combiner": { 2502 | "version": "0.2.2", 2503 | "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", 2504 | "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", 2505 | "requires": { 2506 | "duplexer": "~0.1.1", 2507 | "through": "~2.3.4" 2508 | } 2509 | }, 2510 | "string-width": { 2511 | "version": "1.0.2", 2512 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 2513 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 2514 | "requires": { 2515 | "code-point-at": "^1.0.0", 2516 | "is-fullwidth-code-point": "^1.0.0", 2517 | "strip-ansi": "^3.0.0" 2518 | } 2519 | }, 2520 | "string.prototype.trim": { 2521 | "version": "1.2.1", 2522 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz", 2523 | "integrity": "sha512-MjGFEeqixw47dAMFMtgUro/I0+wNqZB5GKXGt1fFr24u3TzDXCPu7J9Buppzoe3r/LqkSDLDDJzE15RGWDGAVw==", 2524 | "dev": true, 2525 | "requires": { 2526 | "define-properties": "^1.1.3", 2527 | "es-abstract": "^1.17.0-next.1", 2528 | "function-bind": "^1.1.1" 2529 | } 2530 | }, 2531 | "string.prototype.trimleft": { 2532 | "version": "2.1.1", 2533 | "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", 2534 | "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", 2535 | "dev": true, 2536 | "requires": { 2537 | "define-properties": "^1.1.3", 2538 | "function-bind": "^1.1.1" 2539 | } 2540 | }, 2541 | "string.prototype.trimright": { 2542 | "version": "2.1.1", 2543 | "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", 2544 | "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", 2545 | "dev": true, 2546 | "requires": { 2547 | "define-properties": "^1.1.3", 2548 | "function-bind": "^1.1.1" 2549 | } 2550 | }, 2551 | "string_decoder": { 2552 | "version": "1.1.1", 2553 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 2554 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 2555 | "requires": { 2556 | "safe-buffer": "~5.1.0" 2557 | } 2558 | }, 2559 | "stringstream": { 2560 | "version": "0.0.6", 2561 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", 2562 | "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==" 2563 | }, 2564 | "strip-ansi": { 2565 | "version": "3.0.1", 2566 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 2567 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 2568 | "requires": { 2569 | "ansi-regex": "^2.0.0" 2570 | } 2571 | }, 2572 | "strip-bom": { 2573 | "version": "2.0.0", 2574 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 2575 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 2576 | "requires": { 2577 | "is-utf8": "^0.2.0" 2578 | } 2579 | }, 2580 | "strip-json-comments": { 2581 | "version": "2.0.1", 2582 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 2583 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 2584 | }, 2585 | "supports-color": { 2586 | "version": "5.5.0", 2587 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2588 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2589 | "dev": true, 2590 | "requires": { 2591 | "has-flag": "^3.0.0" 2592 | } 2593 | }, 2594 | "tape": { 2595 | "version": "4.12.1", 2596 | "resolved": "https://registry.npmjs.org/tape/-/tape-4.12.1.tgz", 2597 | "integrity": "sha512-xoK2ariLmdGxqyXhhxfIZlr0czNB8hNJeVQmHN4D7ZyBn30GUoa4q2oM4cX8jNhnj1mtILXn1ugbfxc0tTDKtA==", 2598 | "dev": true, 2599 | "requires": { 2600 | "deep-equal": "~1.1.1", 2601 | "defined": "~1.0.0", 2602 | "for-each": "~0.3.3", 2603 | "function-bind": "~1.1.1", 2604 | "glob": "~7.1.6", 2605 | "has": "~1.0.3", 2606 | "inherits": "~2.0.4", 2607 | "is-regex": "~1.0.5", 2608 | "minimist": "~1.2.0", 2609 | "object-inspect": "~1.7.0", 2610 | "resolve": "~1.14.1", 2611 | "resumer": "~0.0.0", 2612 | "string.prototype.trim": "~1.2.1", 2613 | "through": "~2.3.8" 2614 | }, 2615 | "dependencies": { 2616 | "minimist": { 2617 | "version": "1.2.0", 2618 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 2619 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 2620 | "dev": true 2621 | } 2622 | } 2623 | }, 2624 | "tar": { 2625 | "version": "4.4.13", 2626 | "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", 2627 | "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", 2628 | "requires": { 2629 | "chownr": "^1.1.1", 2630 | "fs-minipass": "^1.2.5", 2631 | "minipass": "^2.8.6", 2632 | "minizlib": "^1.2.1", 2633 | "mkdirp": "^0.5.0", 2634 | "safe-buffer": "^5.1.2", 2635 | "yallist": "^3.0.3" 2636 | } 2637 | }, 2638 | "through": { 2639 | "version": "2.3.8", 2640 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 2641 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 2642 | }, 2643 | "through2": { 2644 | "version": "0.2.3", 2645 | "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", 2646 | "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", 2647 | "requires": { 2648 | "readable-stream": "~1.1.9", 2649 | "xtend": "~2.1.1" 2650 | }, 2651 | "dependencies": { 2652 | "isarray": { 2653 | "version": "0.0.1", 2654 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 2655 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 2656 | }, 2657 | "readable-stream": { 2658 | "version": "1.1.14", 2659 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 2660 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 2661 | "requires": { 2662 | "core-util-is": "~1.0.0", 2663 | "inherits": "~2.0.1", 2664 | "isarray": "0.0.1", 2665 | "string_decoder": "~0.10.x" 2666 | } 2667 | }, 2668 | "string_decoder": { 2669 | "version": "0.10.31", 2670 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 2671 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 2672 | } 2673 | } 2674 | }, 2675 | "tilelive-file": { 2676 | "version": "0.0.3", 2677 | "resolved": "https://registry.npmjs.org/tilelive-file/-/tilelive-file-0.0.3.tgz", 2678 | "integrity": "sha1-+4Bt2P/nyGoLbUDNSoT0GYdlMak=", 2679 | "requires": { 2680 | "mkdirp": "~0.3.4" 2681 | }, 2682 | "dependencies": { 2683 | "mkdirp": { 2684 | "version": "0.3.5", 2685 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", 2686 | "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=" 2687 | } 2688 | } 2689 | }, 2690 | "tough-cookie": { 2691 | "version": "2.4.3", 2692 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 2693 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 2694 | "requires": { 2695 | "psl": "^1.1.24", 2696 | "punycode": "^1.4.1" 2697 | }, 2698 | "dependencies": { 2699 | "punycode": { 2700 | "version": "1.4.1", 2701 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 2702 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 2703 | } 2704 | } 2705 | }, 2706 | "traverse": { 2707 | "version": "0.6.7", 2708 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", 2709 | "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", 2710 | "dev": true 2711 | }, 2712 | "tunnel-agent": { 2713 | "version": "0.6.0", 2714 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 2715 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 2716 | "requires": { 2717 | "safe-buffer": "^5.0.1" 2718 | } 2719 | }, 2720 | "tweetnacl": { 2721 | "version": "0.14.5", 2722 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 2723 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 2724 | }, 2725 | "type-detect": { 2726 | "version": "4.0.8", 2727 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 2728 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 2729 | "dev": true 2730 | }, 2731 | "underscore": { 2732 | "version": "1.11.0", 2733 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz", 2734 | "integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==" 2735 | }, 2736 | "uri-js": { 2737 | "version": "4.2.2", 2738 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 2739 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 2740 | "requires": { 2741 | "punycode": "^2.1.0" 2742 | } 2743 | }, 2744 | "url": { 2745 | "version": "0.10.3", 2746 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 2747 | "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", 2748 | "requires": { 2749 | "punycode": "1.3.2", 2750 | "querystring": "0.2.0" 2751 | }, 2752 | "dependencies": { 2753 | "punycode": { 2754 | "version": "1.3.2", 2755 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 2756 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" 2757 | } 2758 | } 2759 | }, 2760 | "util-deprecate": { 2761 | "version": "1.0.2", 2762 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2763 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 2764 | }, 2765 | "uuid": { 2766 | "version": "3.3.3", 2767 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", 2768 | "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" 2769 | }, 2770 | "validate-npm-package-license": { 2771 | "version": "3.0.4", 2772 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 2773 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 2774 | "requires": { 2775 | "spdx-correct": "^3.0.0", 2776 | "spdx-expression-parse": "^3.0.0" 2777 | } 2778 | }, 2779 | "verror": { 2780 | "version": "1.10.0", 2781 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 2782 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 2783 | "requires": { 2784 | "assert-plus": "^1.0.0", 2785 | "core-util-is": "1.0.2", 2786 | "extsprintf": "^1.2.0" 2787 | } 2788 | }, 2789 | "wgs84": { 2790 | "version": "0.0.0", 2791 | "resolved": "https://registry.npmjs.org/wgs84/-/wgs84-0.0.0.tgz", 2792 | "integrity": "sha1-NP3FVZF7blfPKigu0ENxDASc3HY=" 2793 | }, 2794 | "when": { 2795 | "version": "3.7.8", 2796 | "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", 2797 | "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=" 2798 | }, 2799 | "which-module": { 2800 | "version": "1.0.0", 2801 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", 2802 | "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" 2803 | }, 2804 | "wide-align": { 2805 | "version": "1.1.3", 2806 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 2807 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 2808 | "requires": { 2809 | "string-width": "^1.0.2 || 2" 2810 | } 2811 | }, 2812 | "wrap-ansi": { 2813 | "version": "2.1.0", 2814 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 2815 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 2816 | "requires": { 2817 | "string-width": "^1.0.1", 2818 | "strip-ansi": "^3.0.1" 2819 | } 2820 | }, 2821 | "wrappy": { 2822 | "version": "1.0.2", 2823 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2824 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 2825 | }, 2826 | "xml2js": { 2827 | "version": "0.4.19", 2828 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", 2829 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", 2830 | "requires": { 2831 | "sax": ">=0.6.0", 2832 | "xmlbuilder": "~9.0.1" 2833 | } 2834 | }, 2835 | "xmlbuilder": { 2836 | "version": "9.0.7", 2837 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", 2838 | "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" 2839 | }, 2840 | "xtend": { 2841 | "version": "2.1.2", 2842 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", 2843 | "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", 2844 | "requires": { 2845 | "object-keys": "~0.4.0" 2846 | } 2847 | }, 2848 | "y18n": { 2849 | "version": "3.2.1", 2850 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 2851 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" 2852 | }, 2853 | "yallist": { 2854 | "version": "3.1.1", 2855 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 2856 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 2857 | }, 2858 | "yargs": { 2859 | "version": "6.6.0", 2860 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", 2861 | "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", 2862 | "requires": { 2863 | "camelcase": "^3.0.0", 2864 | "cliui": "^3.2.0", 2865 | "decamelize": "^1.1.1", 2866 | "get-caller-file": "^1.0.1", 2867 | "os-locale": "^1.4.0", 2868 | "read-pkg-up": "^1.0.1", 2869 | "require-directory": "^2.1.1", 2870 | "require-main-filename": "^1.0.1", 2871 | "set-blocking": "^2.0.0", 2872 | "string-width": "^1.0.2", 2873 | "which-module": "^1.0.0", 2874 | "y18n": "^3.2.1", 2875 | "yargs-parser": "^4.2.0" 2876 | } 2877 | }, 2878 | "yargs-parser": { 2879 | "version": "4.2.1", 2880 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", 2881 | "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", 2882 | "requires": { 2883 | "camelcase": "^3.0.0" 2884 | } 2885 | } 2886 | } 2887 | } 2888 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mapbox/mapbox-tile-copy", 3 | "version": "7.8.0", 4 | "description": "From geodata files to tiles on S3", 5 | "main": "index.js", 6 | "scripts": { 7 | "pretest": "duplicate-module-test mapnik @mapbox/tilelive gdal sqlite3", 8 | "test": "tape test/*.test.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/mapbox/mapbox-tile-copy.git" 13 | }, 14 | "author": "Mapbox", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/mapbox/mapbox-tile-copy/issues" 18 | }, 19 | "homepage": "https://github.com/mapbox/mapbox-tile-copy", 20 | "dependencies": { 21 | "@mapbox/mapbox-file-sniff": "~1.0.0", 22 | "@mapbox/mbtiles": "^0.10.0", 23 | "@mapbox/s3urls": "^1.5.3", 24 | "@mapbox/tilejson": "^1.0.1", 25 | "@mapbox/tilelive": "~5.12.2", 26 | "@mapbox/tilelive-omnivore": "^4.3.0", 27 | "@mapbox/tilelive-s3": "6.5.1", 28 | "@mapbox/tilelive-vector": "^4.2.0", 29 | "@mapbox/tiletype": "^0.3.0", 30 | "@mapbox/vector-tile": "^1.3.1", 31 | "@mapbox/vtvalidate": "^0.2.2", 32 | "mapbox-studio-default-fonts": "https://mapbox-npm.s3.amazonaws.com/package/mapbox-studio-default-fonts-0.0.4-4afb5235f457bd1c1a5a70fce6c2aa83bf7a851e.tgz", 33 | "mapbox-studio-pro-fonts": "https://mapbox-npm.s3.amazonaws.com/package/mapbox-studio-pro-fonts-1.0.0-9870a90b713f307b9391829602f4d5857e419615.tgz", 34 | "mapnik": "4.x || 3.x", 35 | "minimist": "~0.2.0", 36 | "pbf": "^1.3.2", 37 | "progress-stream": "^0.5.0", 38 | "queue-async": "^1.0.7", 39 | "stream-combiner": "^0.2.2", 40 | "tilelive-file": "0.0.3" 41 | }, 42 | "devDependencies": { 43 | "@mapbox/duplicate-module-test": "^0.2.0", 44 | "@mapbox/mock-aws-sdk-js": "^1.0.1", 45 | "@mapbox/mvt-fixtures": "^3.1.0", 46 | "aws-sdk": "^2.400.0", 47 | "nock": "^13.3.1", 48 | "request": "^2.88.0", 49 | "sinon": "^7.2.3", 50 | "tape": "^4.10.0" 51 | }, 52 | "bin": { 53 | "mapbox-tile-copy": "./bin/mapbox-tile-copy.js" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/copy.serialtiles.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape').test; 4 | var sinon = require('sinon'); 5 | var path = require('path'); 6 | var mapnik = require('mapnik'); 7 | var AWS = require('@mapbox/mock-aws-sdk-js'); 8 | var tilelive = require('@mapbox/tilelive'); 9 | var copy = require('../lib/serialtilescopy'); 10 | var migrationStream = require('../lib/migration-stream'); 11 | 12 | function setupS3Stubs() { 13 | return { 14 | get: AWS.stub('S3', 'getObject', function(params, callback) { 15 | return callback(null, { Body: Buffer.from('test') }); 16 | }), 17 | put: AWS.stub('S3', 'putObject', function(params, callback) { 18 | return callback(null); 19 | }) 20 | } 21 | } 22 | 23 | test('serialtiles-copy: gzipped vector tiles', function(t) { 24 | var uri = [ 25 | 'serialtiles:', 26 | path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gzip.vector.gz') 27 | ].join('//'); 28 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.valid-gzip/{z}/{x}/{y}'; 29 | 30 | sinon.spy(tilelive, 'createWriteStream'); 31 | var s3 = setupS3Stubs(); 32 | 33 | copy(uri, dst, function(err) { 34 | t.ifError(err, 'copied'); 35 | t.equal(s3.put.args[0][0].ContentEncoding, 'gzip'); 36 | t.equal(s3.put.args[0][0].ContentType, 'application/x-protobuf'); 37 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 38 | t.equal(tilelive.createWriteStream.getCall(0).args[1].retry, undefined, 'passes options.retry to tilelive.createWriteStream'); 39 | tilelive.createWriteStream.restore(); 40 | AWS.S3.restore(); 41 | t.end(); 42 | }); 43 | }); 44 | 45 | test('serialtiles-copy: options.retry', function(t) { 46 | var uri = [ 47 | 'serialtiles:', 48 | path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gzip.vector.gz') 49 | ].join('//'); 50 | 51 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.retry/{z}/{x}/{y}'; 52 | 53 | sinon.spy(tilelive, 'createWriteStream'); 54 | var s3 = setupS3Stubs(); 55 | 56 | copy(uri, dst, { retry: 5 }, function(err) { 57 | t.ifError(err, 'copied'); 58 | t.equal(s3.put.args[0][0].ContentEncoding, 'gzip'); 59 | t.equal(s3.put.args[0][0].ContentType, 'application/x-protobuf'); 60 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 61 | t.equal(tilelive.createWriteStream.getCall(0).args[1].retry, 5, 'passes options.retry to tilelive.createWriteStream'); 62 | tilelive.createWriteStream.restore(); 63 | AWS.S3.restore(); 64 | t.end(); 65 | }); 66 | }); 67 | 68 | test('serialtiles-copy: gzipped vector tiles, v2', function(t) { 69 | var uri = [ 70 | 'serialtiles:', 71 | path.resolve(__dirname, 'fixtures', 'valid-v2.serialtiles.gzip.vector.gz') 72 | ].join('//'); 73 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.valid-v2-gzip/{z}/{x}/{y}'; 74 | 75 | sinon.spy(tilelive, 'createWriteStream'); 76 | sinon.spy(migrationStream, 'migrate'); 77 | var s3 = setupS3Stubs(); 78 | 79 | copy(uri, dst, function(err) { 80 | t.ifError(err, 'copied'); 81 | t.equal(s3.put.args[0][0].ContentEncoding, 'gzip'); 82 | t.equal(s3.put.args[0][0].ContentType, 'application/x-protobuf'); 83 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 84 | t.equal(tilelive.createWriteStream.getCall(0).args[1].retry, undefined, 'passes options.retry to tilelive.createWriteStream'); 85 | t.equal(migrationStream.migrate.notCalled, true, 'doesn\t migrate a v2 mbtiles file'); 86 | tilelive.createWriteStream.restore(); 87 | migrationStream.migrate.restore(); 88 | AWS.S3.restore(); 89 | t.end(); 90 | }); 91 | }); 92 | 93 | test('serialtiles-copy: parallel processing', function(t) { 94 | var uri = [ 95 | 'serialtiles:', 96 | path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gzip.vector.gz') 97 | ].join('//'); 98 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.valid-parallel/{z}/{x}/{y}'; 99 | 100 | var s3 = setupS3Stubs(); 101 | 102 | copy(uri, dst, { job: { num: 0, total: 10 }}, function(err) { 103 | t.ifError(err, 'copied'); 104 | t.ok(s3.put.callCount < 21, 'should not render the entire dataset'); 105 | AWS.S3.restore(); 106 | t.end(); 107 | }); 108 | }); 109 | 110 | test('serialtiles-copy: stats', function(t) { 111 | var uri = [ 112 | 'serialtiles:', 113 | path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gzip.vector.gz') 114 | ].join('//'); 115 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.valid-parallel/{z}/{x}/{y}'; 116 | 117 | setupS3Stubs(); 118 | 119 | copy(uri, dst, { stats: true, job: { num: 0, total: 10 } }, function(err, stats) { 120 | t.ifError(err, 'no error'); 121 | t.equal(stats.world_merc.count, 223); 122 | AWS.S3.restore(); 123 | t.end(); 124 | }); 125 | }); 126 | 127 | test('serialtiles-copy: tiles too big', function(t) { 128 | var uri = [ 129 | 'serialtiles:', 130 | path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gzip.vector.gz') 131 | ].join('//'); 132 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.invalid-tilesize/{z}/{x}/{y}'; 133 | setupS3Stubs(); 134 | 135 | copy(uri, dst, { limits: { max_tilesize: 10 } }, function(err) { 136 | t.ok(err, 'expected error'); 137 | t.equal(err.code, 'EINVALID', 'expected error code'); 138 | t.equal(err.message, 'Tile exceeds maximum size of 0k at z 0. Reduce the detail of data at this zoom level or omit it by adjusting your minzoom.', 'expected error message'); 139 | AWS.S3.restore(); 140 | t.end(); 141 | }); 142 | }); 143 | 144 | test('serialtiles-copy: vector tile invalid', function(t) { 145 | var uri = [ 146 | 'serialtiles:', 147 | path.resolve(__dirname, 'fixtures', 'invalid.serialtiles.gzipped.gz') 148 | ].join('//'); 149 | var dst = 'http://test-bucket.s3.amazonaws.com/_pending/test/test.invalid-vector-tile/{z}/{x}/{y}'; 150 | setupS3Stubs(); 151 | 152 | copy(uri, dst, function(err) { 153 | t.ok(err, 'expected error'); 154 | t.equal(err.code, 'EINVALID', 'expected error code'); 155 | t.equal(err.message, 'Buffer is not encoded as a valid PBF', 'expected error message'); 156 | t.ok(err.stack, 'error has stacktrace'); 157 | AWS.S3.restore(); 158 | t.end(); 159 | }); 160 | }); 161 | -------------------------------------------------------------------------------- /test/copy.tilelive.test.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var sinon = require('sinon'); 3 | var nock = require('nock'); 4 | var path = require('path'); 5 | var mvtf = require('@mapbox/mvt-fixtures'); 6 | var mapnik = require('mapnik'); 7 | var mapnikVT = mapnik.VectorTile; // required for spying 8 | var tileliveCopy = require('../lib/tilelivecopy'); 9 | var tilelive = require('@mapbox/tilelive'); 10 | var migrationStream = require('../lib/migration-stream'); 11 | var AWS = require('@mapbox/mock-aws-sdk-js'); 12 | var fs = require('fs'); 13 | var mtc = require('..'); // just to get protocols registered 14 | 15 | function setupS3Stubs() { 16 | return { 17 | get: AWS.stub('S3', 'getObject', function(params, callback) { 18 | return callback(null, { Body: Buffer.from('test') }); 19 | }), 20 | put: AWS.stub('S3', 'putObject', function(params, callback) { 21 | return callback(null); 22 | }) 23 | } 24 | } 25 | 26 | test('copy mbtiles with v1 tile logging', function(t) { 27 | process.env.LOG_V1_TILES = true; 28 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mbtiles'); 29 | var src = 'mbtiles://' + fixture; 30 | var dst = 's3://test-bucket/valid.mbtiles/{z}/{x}/{y}'; 31 | sinon.spy(tilelive, 'copy'); 32 | var s3 = setupS3Stubs(); 33 | 34 | tileliveCopy(src, dst, {}, function(err) { 35 | t.ifError(err, 'copied'); 36 | t.equal(s3.put.callCount, 21); 37 | t.equal(tilelive.copy.getCall(0).args[2].type, 'list', 'uses list scheme for mbtiles'); 38 | t.equal(tilelive.copy.getCall(0).args[2].retry, undefined, 'passes options.retry to tilelive.copy'); 39 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 40 | 41 | var path = require('os').tmpdir() + '/v1-stats.json'; 42 | t.ok(fs.existsSync(path)); 43 | fs.unlinkSync(path); 44 | 45 | process.env.LOG_V1_TILES = false; 46 | AWS.S3.restore(); 47 | tilelive.copy.restore(); 48 | t.end(); 49 | }); 50 | }); 51 | 52 | test('copy invalid mbtiles with v2 invalid tile logging', function(t) { 53 | process.env.LOG_INVALID_VT = true; 54 | var fixture = path.resolve(__dirname, 'fixtures', 'v2-throw.mbtiles'); 55 | var src = 'mbtiles://' + fixture; 56 | var dst = 's3://test-bucket/v2-throw.mbtiles/{z}/{x}/{y}'; 57 | sinon.spy(tilelive, 'copy'); 58 | var s3 = setupS3Stubs(); 59 | 60 | tileliveCopy(src, dst, {}, function(err) { 61 | t.ok(err); 62 | t.equal(s3.put.callCount, 0); 63 | t.equal(tilelive.copy.getCall(0).args[2].type, 'list', 'uses list scheme for mbtiles'); 64 | t.equal(tilelive.copy.getCall(0).args[2].retry, undefined, 'passes options.retry to tilelive.copy'); 65 | 66 | var path = require('os').tmpdir() + '/vt-invalid.json'; 67 | t.ok(fs.existsSync(path)); 68 | fs.unlinkSync(path); 69 | 70 | process.env.LOG_INVALID_VT = false; 71 | AWS.S3.restore(); 72 | tilelive.copy.restore(); 73 | t.end(); 74 | }); 75 | }); 76 | 77 | test('copy mbtiles without v1 tile logging', function(t) { 78 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mbtiles'); 79 | var src = 'mbtiles://' + fixture; 80 | var dst = 's3://test-bucket/valid.mbtiles/{z}/{x}/{y}'; 81 | sinon.spy(tilelive, 'copy'); 82 | var s3 = setupS3Stubs(); 83 | 84 | tileliveCopy(src, dst, {}, function(err) { 85 | t.ifError(err, 'copied'); 86 | t.equal(s3.put.callCount, 21); 87 | t.equal(tilelive.copy.getCall(0).args[2].type, 'list', 'uses list scheme for mbtiles'); 88 | t.equal(tilelive.copy.getCall(0).args[2].retry, undefined, 'passes options.retry to tilelive.copy'); 89 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 90 | 91 | AWS.S3.restore(); 92 | tilelive.copy.restore(); 93 | t.end(); 94 | }); 95 | }); 96 | 97 | test('copy invalid mbtiles with bypassValidation option', function(t) { 98 | process.env.LOG_INVALID_VT = true; 99 | var fixture = path.resolve(__dirname, 'fixtures', 'v2-throw.mbtiles'); 100 | var src = 'mbtiles://' + fixture; 101 | var dst = 's3://test-bucket/v2-throw.mbtiles/{z}/{x}/{y}'; 102 | var s3 = setupS3Stubs(); 103 | 104 | tileliveCopy(src, dst, { bypassValidation: true }, function(err) { 105 | t.ifError(err, 'copied'); 106 | t.equal(s3.put.callCount, 341); 107 | AWS.S3.restore(); 108 | t.end(); 109 | }); 110 | }); 111 | 112 | test('fails with invalid ZXY from mbtiles in v1 tiles', function(t) { 113 | process.env.LOG_INVALID_VT = true; 114 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid-zxy.mbtiles'); 115 | var src = 'mbtiles://' + fixture; 116 | var dst = 's3://test-bucket/invalid-zxy.mbtiles/{z}/{x}/{y}'; 117 | setupS3Stubs(); 118 | 119 | tileliveCopy(src, dst, {}, function(err) { 120 | t.ok(err); 121 | t.equal(err.code, 'EINVALID', 'expected code'); 122 | t.equal(err.message, 'Tile 0/99/99 is an invalid ZXY range.', 'expected error message'); 123 | AWS.S3.restore(); 124 | t.end(); 125 | }); 126 | }); 127 | 128 | test('copy retry', function(t) { 129 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mbtiles'); 130 | var src = 'mbtiles://' + fixture; 131 | var dst = 's3://test-bucket/retry/{z}/{x}/{y}'; 132 | sinon.spy(tilelive, 'copy'); 133 | var s3 = setupS3Stubs(); 134 | 135 | tileliveCopy(src, dst, { retry: 5 }, function(err) { 136 | t.ifError(err, 'copied'); 137 | t.equal(s3.put.callCount, 21); 138 | t.equal(tilelive.copy.getCall(0).args[2].type, 'list', 'uses list scheme for mbtiles'); 139 | t.equal(tilelive.copy.getCall(0).args[2].retry, 5, 'passes options.retry to tilelive.copy'); 140 | tilelive.copy.restore(); 141 | AWS.S3.restore(); 142 | t.end(); 143 | }); 144 | }); 145 | 146 | test('copy v2 mbtiles', function(t) { 147 | var fixture = path.resolve(__dirname, 'fixtures', 'valid-v2.mbtiles'); 148 | var src = 'mbtiles://' + fixture; 149 | var dst = 's3://test-bucket/valid-v2.mbtiles/{z}/{x}/{y}'; 150 | sinon.spy(tilelive, 'copy'); 151 | sinon.spy(migrationStream, 'migrate'); 152 | sinon.spy(mapnikVT, 'info'); 153 | var s3 = setupS3Stubs(); 154 | 155 | tileliveCopy(src, dst, {}, function(err) { 156 | t.ifError(err, 'copied'); 157 | t.equal(s3.put.callCount, 21); 158 | t.equal(tilelive.copy.getCall(0).args[2].type, 'list', 'uses list scheme for mbtiles'); 159 | t.equal(tilelive.copy.getCall(0).args[2].retry, undefined, 'passes options.retry to tilelive.copy'); 160 | t.equal(mapnikVT.info.callCount, 21, 'called mapnik info as many times as there are tiles (should only be once per v2 tile)'); 161 | t.equal(migrationStream.migrate.notCalled, true, 'doesn\t migrate a v2 mbtiles file'); 162 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 163 | 164 | tilelive.copy.restore(); 165 | mapnikVT.info.restore(); 166 | migrationStream.migrate.restore(); 167 | AWS.S3.restore(); 168 | t.end(); 169 | }); 170 | }); 171 | 172 | test('copy omnivore', function(t) { 173 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 174 | var src = 'omnivore://' + fixture; 175 | var dst = 's3://test-bucket/valid.geojson/{z}/{x}/{y}'; 176 | var s3 = setupS3Stubs(); 177 | sinon.spy(tilelive, 'copy'); 178 | 179 | tileliveCopy(src, dst, { maxzoom: 5 }, function(err) { 180 | t.ifError(err, 'copied'); 181 | t.equal(s3.put.callCount, 35); 182 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for geojson'); 183 | 184 | AWS.S3.restore(); 185 | tilelive.copy.restore(); 186 | t.end(); 187 | }); 188 | }); 189 | 190 | test('copy omnivore stats', function(t) { 191 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 192 | var src = 'omnivore://' + fixture; 193 | var dst = 's3://test-bucket/valid.geojson/{z}/{x}/{y}'; 194 | setupS3Stubs(); 195 | sinon.spy(tilelive, 'copy'); 196 | 197 | tileliveCopy(src, dst, { maxzoom: 5, stats: true }, function(err, stats) { 198 | t.ifError(err, 'copied'); 199 | t.ok(stats, 'has stats'); 200 | t.equal(stats.valid.geometryTypes.Polygon, 452, 'Counts polygons'); 201 | 202 | AWS.S3.restore(); 203 | tilelive.copy.restore(); 204 | t.end(); 205 | }); 206 | }); 207 | 208 | test('copy tilejson (mocks the GET request from the tilelive-tilejson module)', function(t) { 209 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.tilejson'); 210 | var src = 'tilejson://' + fixture; 211 | var dst = 's3://test-bucket/valid.tilejson/{z}/{x}/{y}'; 212 | 213 | var s3 = setupS3Stubs(); 214 | sinon.spy(tilelive, 'copy'); 215 | var requestCount = 0; 216 | nock('http://test-bucket.s3.amazonaws.com') 217 | .get(function() { 218 | requestCount++; 219 | return true; 220 | }).reply(200, mvtf.get('043').buffer) 221 | .persist(); 222 | 223 | tileliveCopy(src, dst, {}, function(err) { 224 | t.ifError(err, 'copied'); 225 | t.equal(requestCount, 36 * 2, '34 GET requests to tilejson s3 location, doubled because tilelive-s3 makes a get request as well'); 226 | t.equal(s3.put.callCount, 36, '34 tiles put to s3'); 227 | t.equal(mapnik.VectorTile.info(s3.put.args[0][0].Body).layers[0].version, 2, 'vector tile is version 2'); 228 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for tilejson'); 229 | 230 | AWS.S3.restore(); 231 | tilelive.copy.restore(); 232 | nock.cleanAll(); 233 | t.end(); 234 | }); 235 | }); 236 | 237 | test('copy tm2z', function(t) { 238 | process.env.MapboxAPIMaps = 'https://api.example.com'; 239 | process.env.MapboxAccessToken = 'pk.test'; 240 | nock(/\./) 241 | .get(() => true).reply(200, {}).persist(); 242 | 243 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.tm2z'); 244 | var src = 'tm2z://' + fixture; 245 | var dst = 's3://test-bucket/valid.tm2z/{z}/{x}/{y}'; 246 | var s3 = setupS3Stubs(); 247 | sinon.spy(tilelive, 'copy'); 248 | 249 | tileliveCopy(src, dst, { maxzoom: 3 }, function(err) { 250 | t.ifError(err, 'copied'); 251 | t.equal(s3.put.callCount, 85, 'expected number of tiles'); 252 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for tm2z'); 253 | 254 | AWS.S3.restore(); 255 | tilelive.copy.restore(); 256 | nock.cleanAll(); 257 | t.end(); 258 | }); 259 | }); 260 | 261 | test('copy in parallel', function(t) { 262 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mbtiles'); 263 | var src = 'mbtiles://' + fixture; 264 | var dst = 's3://test-bucket/valid.mbtiles/{z}/{x}/{y}'; 265 | var s3 = setupS3Stubs(); 266 | 267 | tileliveCopy(src, dst, { job: { total: 10, num: 2 } }, function(err) { 268 | t.ifError(err, 'copied'); 269 | t.equal(s3.put.callCount, 4); 270 | AWS.S3.restore(); 271 | t.end(); 272 | }); 273 | }); 274 | 275 | test('copy invalid source', function(t) { 276 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.tilejson'); 277 | var src = 'tilejson://' + fixture; 278 | var dst = 's3://test-bucket/invalid.tilejson/{z}/{x}/{y}'; 279 | var s3 = setupS3Stubs(); 280 | 281 | tileliveCopy(src, dst, {}, function(err) { 282 | t.ok(err, 'expected error'); 283 | t.equal(err.code, 'EINVALID', 'marked invalid when cannot load source'); 284 | t.equal(s3.put.callCount, 0); 285 | AWS.S3.restore(); 286 | t.end(); 287 | }); 288 | }); 289 | 290 | test('copy corrupt mbtiles', function(t) { 291 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.corrupt.mbtiles'); 292 | var src = 'mbtiles://' + fixture; 293 | var dst = 's3://test-bucket/invalid.mbtiles/{z}/{x}/{y}'; 294 | var s3 = setupS3Stubs(); 295 | 296 | tileliveCopy(src, dst, {}, function(err) { 297 | t.ok(err, 'expected error'); 298 | t.equal(err.code, 'SQLITE_CORRUPT', 'pass-through errors encountered during copy'); 299 | t.equal(s3.put.callCount, 0); 300 | AWS.S3.restore(); 301 | t.end(); 302 | }); 303 | }); 304 | 305 | test('passes through invalid tile in mbtiles', function(t) { 306 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.tile-with-no-geometry.mbtiles'); 307 | var src = 'mbtiles://' + fixture; 308 | var dst = 's3://test-bucket/invalid.tile-with-no-geometry.mbtiles/{z}/{x}/{y}'; 309 | var s3 = setupS3Stubs(); 310 | 311 | tileliveCopy(src, dst, {}, function(err, stats) { 312 | t.ifError(err, 'passes through invalid.tile-with-no-geometry.mbtiles'); 313 | t.equal(s3.put.callCount, 1); 314 | AWS.S3.restore(); 315 | t.end(); 316 | }); 317 | }); 318 | 319 | test('copy null-tile mbtiles', function(t) { 320 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.null-tile.mbtiles'); 321 | var src = 'mbtiles://' + fixture; 322 | var dst = 's3://test-bucket/invalid.mbtiles/{z}/{x}/{y}'; 323 | var s3 = setupS3Stubs(); 324 | 325 | tileliveCopy(src, dst, {}, function(err) { 326 | t.ok(err, 'expected error'); 327 | t.equal(err.code, 'EINVALIDTILE', 'pass-through errors encountered during copy'); 328 | t.equal(s3.put.callCount, 0); 329 | AWS.S3.restore(); 330 | t.end(); 331 | }); 332 | }); 333 | 334 | test('copy coordinates exceed spherical mercator', function(t) { 335 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.coords-out-of-range.geojson'); 336 | var src = 'omnivore://' + fixture; 337 | var dst = 's3://test-bucket/invalid.geojson/{z}/{x}/{y}'; 338 | sinon.spy(tilelive, 'copy'); 339 | var s3 = setupS3Stubs(); 340 | 341 | tileliveCopy(src, dst, {}, function(err) { 342 | t.ok(err, 'expect an error for out of bounds coordinates'); 343 | t.ok(err.message.indexOf('Coordinates beyond web mercator range') > -1); 344 | t.equal(err.code, 'EINVALID', 'error code encountered'); 345 | t.equal(s3.put.callCount, 0); 346 | AWS.S3.restore(); 347 | tilelive.copy.restore(); 348 | t.end(); 349 | }); 350 | }); 351 | 352 | test('successfully copy a bigtiff', function(t) { 353 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.bigtiff.tif'); 354 | var src = 'omnivore://' + fixture; 355 | var dst = 's3://test-bucket/valid.bigtiff/{z}/{x}/{y}'; 356 | sinon.spy(tilelive, 'copy'); 357 | var s3 = setupS3Stubs(); 358 | 359 | tileliveCopy(src, dst, {}, function(err) { 360 | t.ifError(err, 'copied tiles'); 361 | t.equal(s3.put.callCount, 126); 362 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for tifs'); 363 | tilelive.copy.restore(); 364 | AWS.S3.restore(); 365 | t.end(); 366 | }); 367 | }); 368 | 369 | test('copy omnivore to Frankfurt', function(t) { 370 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 371 | var src = 'omnivore://' + fixture; 372 | var dst = 's3://test-bucket/valid.geojson/{z}/{x}/{y}?region=eu-central-1'; 373 | sinon.spy(tilelive, 'copy'); 374 | var s3 = setupS3Stubs(); 375 | 376 | tileliveCopy(src, dst, { maxzoom: 5 }, function(err) { 377 | t.ifError(err, 'copied'); 378 | t.equal(s3.put.callCount, 35); 379 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for tifs'); 380 | t.equal(tilelive.copy.getCall(0).args[1].client.config.region, 'eu-central-1', 'uses eu-central-1 region'); 381 | tilelive.copy.restore(); 382 | AWS.S3.restore(); 383 | t.end(); 384 | }); 385 | }); 386 | 387 | test('copy omnivore to s3 encrypted with AWS KMS', function(t) { 388 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 389 | var src = 'omnivore://' + fixture; 390 | var dst = 's3://test-bucket/valid.geojson/{z}/{x}/{y}?sse=aws:kms&sseKmsId=alias/mapbox-tile-copy-test-kms'; 391 | sinon.spy(tilelive, 'copy'); 392 | var s3 = setupS3Stubs(); 393 | 394 | tileliveCopy(src, dst, { maxzoom: 5 }, function(err) { 395 | t.ifError(err, 'copied'); 396 | t.equal(s3.put.callCount, 35); 397 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for geojson'); 398 | t.equal(s3.put.args[0][0].SSEKMSKeyId, 'alias/mapbox-tile-copy-test-kms'); 399 | t.equal(s3.put.args[0][0].ServerSideEncryption, 'aws:kms'); 400 | t.equal(s3.put.args[0][0].ACL, 'private'); 401 | AWS.S3.restore(); 402 | tilelive.copy.restore(); 403 | t.end(); 404 | }); 405 | }); 406 | 407 | test('handles vector data reprojection', function(t) { 408 | var fixture = path.resolve(__dirname, 'fixtures', 'reprojection/data.shp'); 409 | var src = 'omnivore://' + fixture; 410 | var dst = 's3://test-bucket/reprojection.shp/{z}/{x}/{y}'; 411 | sinon.spy(tilelive, 'copy'); 412 | var s3 = setupS3Stubs(); 413 | 414 | tileliveCopy(src, dst, {}, function(err) { 415 | t.ifError(err, 'copied'); 416 | t.equal(s3.put.callCount, 35); 417 | t.equal(tilelive.copy.getCall(0).args[2].type, 'scanline', 'uses scanline scheme for shp reprojection'); 418 | AWS.S3.restore(); 419 | tilelive.copy.restore(); 420 | t.end(); 421 | }); 422 | }); 423 | -------------------------------------------------------------------------------- /test/executable.test.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var exec = require('child_process').exec; 3 | var os = require('os'); 4 | var fs = require('fs'); 5 | var crypto = require('crypto'); 6 | var path = require('path'); 7 | 8 | process.env.MapboxAPIMaps = 'https://api.tiles.mapbox.com'; 9 | var copy = path.resolve(__dirname, '..', 'bin', 'mapbox-tile-copy.js'); 10 | var bucket = process.env.TestBucket || 'tilestream-tilesets-development'; 11 | var runid = crypto.randomBytes(16).toString('hex'); 12 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gz'); 13 | var s3urls = require('@mapbox/s3urls'); 14 | var AWS = require('aws-sdk'); 15 | 16 | 17 | console.log('---> mapbox-tile-copy executable %s', runid); 18 | 19 | function dsturi(name) { 20 | return [ 21 | 's3:/', 22 | bucket, 23 | 'test/mapbox-tile-copy', 24 | runid, 25 | name, 26 | '{z}/{x}/{y}' 27 | ].join('/'); 28 | } 29 | 30 | function tileCount(dst, callback) { 31 | var s3 = new AWS.S3(); 32 | var count = 0; 33 | 34 | var params = s3urls.fromUrl(dst.replace('{z}/{x}/{y}', '')); 35 | params.Prefix = params.Key; 36 | delete params.Key; 37 | 38 | function list(marker) { 39 | if (marker) params.Marker = marker; 40 | 41 | s3.listObjects(params, function(err, data) { 42 | if (err) return callback(err); 43 | count += data.Contents.length; 44 | if (data.IsTruncated) return list(data.Contents.pop().Key); 45 | callback(null, count); 46 | }); 47 | } 48 | 49 | list(); 50 | } 51 | 52 | test('invalid s3 url', function(t) { 53 | var dst = 'http://www.google.com'; 54 | var cmd = [ copy, fixture, dst ].join(' '); 55 | exec(cmd, function(err, stdout, stderr) { 56 | t.ok(err, 'expected error'); 57 | t.equal(stderr, 'Invalid output protocol: http://www.google.com\n', 'expected message'); 58 | t.equal(err.code, 1, 'exit code 1'); 59 | t.end(); 60 | }); 61 | }); 62 | 63 | test('file does not exist', function(t) { 64 | var dst = dsturi('invalid.file'); 65 | var cmd = [ copy, '/w/t/f', dst ].join(' '); 66 | exec(cmd, function(err, stdout, stderr) { 67 | t.ok(err, 'expected error'); 68 | t.equal(stderr, 'The file specified does not exist: /w/t/f\n', 'expected message'); 69 | t.equal(err.code, 1, 'exit code 1'); 70 | t.end(); 71 | }); 72 | }); 73 | 74 | test('invalid source file', function(t) { 75 | var dst = dsturi('invalid.source'); 76 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.tilejson'); 77 | var cmd = [ copy, fixture, dst ].join(' '); 78 | exec(cmd, function(err, stdout, stderr) { 79 | t.ok(err, 'expected error'); 80 | t.ok(/Unknown filetype/.test(stderr), 'expected message'); 81 | t.equal(err.code, 3, 'exit code 3'); 82 | t.end(); 83 | }); 84 | }); 85 | 86 | // test('handles mbtile with missing geometry', function(t) { 87 | // var fixture = path.resolve(__dirname, 'fixtures', 'invalid.tile-with-no-geometry.mbtiles'); 88 | // var dst = dsturi('invalid.tile-with-no-geometry.mbtiles'); 89 | // var cmd = [ copy, fixture, dst ].join(' '); 90 | // exec(cmd, function(err, stdout, stderr) { 91 | // t.ifError(err, 'no error'); 92 | // tileCount(dst, function(err, count) { 93 | // t.ifError(err, 'counted tiles'); 94 | // t.equal(count, 1, 'expected number of tiles'); 95 | // t.end(); 96 | // }); 97 | // }); 98 | // }); 99 | 100 | // test('stats flag', function(t) { 101 | // var dst = dsturi('valid.geojson'); 102 | // var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 103 | // var tmpfile = path.join(os.tmpdir(), crypto.randomBytes(8).toString('hex')); 104 | // var cmd = [ copy, fixture, '--stats=' + tmpfile, dst ].join(' '); 105 | // exec(cmd, function(err, stdout, stderr) { 106 | // t.ifError(err, 'no error'); 107 | // t.pass(tmpfile); 108 | // var stats = JSON.parse(fs.readFileSync(tmpfile)); 109 | // t.ok(stats); 110 | // t.equal(Math.abs(15800 - stats.valid.geometryTypes.Polygon) < 200, true, 'Counts polygons (+/-15800)'); 111 | // t.end(); 112 | // }); 113 | // }); 114 | 115 | // test('minzoom flag valid', function(t) { 116 | // var dst = dsturi('valid.mini.geojson'); 117 | // var fixture = path.resolve(__dirname, 'fixtures', 'valid.mini.geojson'); 118 | // var cmd = [ copy, fixture, dst, '--minzoom', '5' ].join(' '); 119 | // exec(cmd, function(err, stdout, stderr) { 120 | // t.ifError(err, 'no error'); 121 | // tileCount(dst, function(err, count) { 122 | // t.ifError(err, 'counted tiles'); 123 | // t.equal(count, 2, 'expected number of tiles'); 124 | // t.end(); 125 | // }); 126 | // }); 127 | // }); 128 | 129 | test('minzoom flag nullval', function(t) { 130 | var dst = dsturi('valid.geojson'); 131 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 132 | var cmd = [ copy, fixture, dst, '--minzoom' ].join(' '); 133 | exec(cmd, function(err, stdout, stderr) { 134 | t.ok(err, 'expected error'); 135 | t.ok(/You must provide a valid zoom level integer/.test(stderr), 'expected message'); 136 | t.equal(err.code, 1, 'exit code 1'); 137 | t.end(); 138 | }); 139 | }); 140 | 141 | test('minzoom flag badval', function(t) { 142 | var dst = dsturi('valid.geojson'); 143 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 144 | var cmd = [ copy, fixture, dst, '--minzoom q' ].join(' '); 145 | exec(cmd, function(err, stdout, stderr) { 146 | t.ok(err, 'expected error'); 147 | t.ok(/You must provide a valid zoom level integer/.test(stderr), 'expected message'); 148 | t.equal(err.code, 1, 'exit code 1'); 149 | t.end(); 150 | }); 151 | }); 152 | 153 | // test('maxzoom flag valid', function(t) { 154 | // var dst = dsturi('valid.mini.geojson'); 155 | // var fixture = path.resolve(__dirname, 'fixtures', 'valid.mini.geojson'); 156 | // var cmd = [ copy, fixture, dst, '--maxzoom', '4' ].join(' '); 157 | // exec(cmd, function(err, stdout, stderr) { 158 | // t.ifError(err, 'no error'); 159 | // tileCount(dst, function(err, count) { 160 | // t.ifError(err, 'counted tiles'); 161 | // t.equal(count, 5, 'expected number of tiles'); 162 | // t.end(); 163 | // }); 164 | // }); 165 | // }); 166 | 167 | test('maxzoom flag nullval', function(t) { 168 | var dst = dsturi('valid.geojson'); 169 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 170 | var cmd = [ copy, fixture, dst, '--maxzoom' ].join(' '); 171 | exec(cmd, function(err, stdout, stderr) { 172 | t.ok(err, 'expected error'); 173 | t.ok(/You must provide a valid zoom level integer/.test(stderr), 'expected message'); 174 | t.equal(err.code, 1, 'exit code 1'); 175 | t.end(); 176 | }); 177 | }); 178 | 179 | test('maxzoom flag badval', function(t) { 180 | var dst = dsturi('valid.geojson'); 181 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.geojson'); 182 | var cmd = [ copy, fixture, dst, '--maxzoom q' ].join(' '); 183 | exec(cmd, function(err, stdout, stderr) { 184 | t.ok(err, 'expected error'); 185 | t.ok(/You must provide a valid zoom level integer/.test(stderr), 'expected message'); 186 | t.equal(err.code, 1, 'exit code 1'); 187 | t.end(); 188 | }); 189 | }); 190 | 191 | // test('s3 url', function(t) { 192 | // var dst = dsturi('valid.s3url'); 193 | // var cmd = [ copy, fixture, dst ].join(' '); 194 | // exec(cmd, function(err, stdout, stderr) { 195 | // t.ifError(err, 'copied'); 196 | // t.ok(stdout.length > 0, 'logs something'); 197 | // tileCount(dst, function(err, count) { 198 | // t.ifError(err, 'counted tiles'); 199 | // t.equal(count, 4, 'expected number of tiles'); 200 | // t.end(); 201 | // }); 202 | // }); 203 | // }); 204 | 205 | // test('https s3 url', function(t) { 206 | // var dst = dsturi('valid.httpurl'); 207 | // var cmd = [ copy, fixture, s3urls.convert(dst, 'bucket-in-host') ].join(' '); 208 | // exec(cmd, function(err, stdout, stderr) { 209 | // t.ifError(err, 'copied'); 210 | // t.ok(stdout.length > 0, 'logs something'); 211 | // tileCount(dst, function(err, count) { 212 | // t.ifError(err, 'counted tiles'); 213 | // t.equal(count, 4, 'expected number of tiles'); 214 | // t.end(); 215 | // }); 216 | // }); 217 | // }); 218 | 219 | // test('no progress', function(t) { 220 | // var dst = dsturi('valid.noprogress'); 221 | // var cmd = [ copy, fixture, dst, '--progressinterval', '0' ].join(' '); 222 | // exec(cmd, function(err, stdout, stderr) { 223 | // t.ifError(err, 'copied'); 224 | // t.equal(stdout.length, 0, 'expected stdout.length'); 225 | // tileCount(dst, function(err, count) { 226 | // t.ifError(err, 'counted tiles'); 227 | // t.equal(count, 4, 'expected number of tiles'); 228 | // t.end(); 229 | // }); 230 | // }); 231 | // }); 232 | 233 | // test('progress interval', function(t) { 234 | // var dst = dsturi('valid.interval'); 235 | // var fixture = path.resolve(__dirname, 'fixtures', 'valid.geotiff.tif'); 236 | // var cmd = [ copy, fixture, dst, '--progressinterval', '1' ].join(' '); 237 | // var proc = exec(cmd, function(err, stdout, stderr) { 238 | // t.ifError(err, 'copies'); 239 | // t.ok(stdout.length > 0, 'logs something'); 240 | // t.end(); 241 | // }); 242 | // }); 243 | 244 | // test('parallel', function(t) { 245 | // var dst = dsturi('valid.parallel'); 246 | // var cmd = [ copy, fixture, dst, '--part', '1', '--parts', '10' ].join(' '); 247 | // exec(cmd, function(err, stdout, stderr) { 248 | // t.ifError(err, 'copied'); 249 | // t.ok(stdout.length > 0, 'logs something'); 250 | // tileCount(dst, function(err, count) { 251 | // t.ifError(err, 'counted tiles'); 252 | // t.ok(count < 4, 'did not render all tiles'); 253 | // t.end(); 254 | // }); 255 | // }); 256 | // }); 257 | 258 | // test('part zero', function(t) { 259 | // var dst = dsturi('valid.part.zero'); 260 | // var cmd = [ copy, fixture, dst, '--part', '0', '--parts', '10' ].join(' '); 261 | // exec(cmd, function(err, stdout, stderr) { 262 | // t.ifError(err, 'copied'); 263 | // t.ok(stdout.length > 0, 'logs something'); 264 | // tileCount(dst, function(err, count) { 265 | // t.ifError(err, 'counted tiles'); 266 | // t.ok(count < 4, 'did not render all tiles'); 267 | // t.end(); 268 | // }); 269 | // }); 270 | // }); 271 | 272 | // test('single part', function(t) { 273 | // var dst = dsturi('valid.single.zero'); 274 | // var cmd = [ copy, fixture, dst, '--part', '0', '--parts', '1' ].join(' '); 275 | // exec(cmd, function(err, stdout, stderr) { 276 | // t.ifError(err, 'copied'); 277 | // t.ok(stdout.length > 0, 'logs something'); 278 | // tileCount(dst, function(err, count) { 279 | // t.ifError(err, 'counted tiles'); 280 | // t.ok(count == 4, 'rendered all tiles'); 281 | // t.end(); 282 | // }); 283 | // }); 284 | // }); 285 | 286 | // test('retry', function(t) { 287 | // var dst = dsturi('valid.retry'); 288 | // var cmd = [ copy, fixture, dst, '--retry', '5' ].join(' '); 289 | // exec(cmd, function(err, stdout, stderr) { 290 | // t.ifError(err, 'copied'); 291 | // t.ok(stdout.length > 0, 'logs something'); 292 | // tileCount(dst, function(err, count) { 293 | // t.ifError(err, 'counted tiles'); 294 | // t.equal(count, 4, 'expected number of tiles'); 295 | // t.end(); 296 | // }); 297 | // }); 298 | // }); 299 | 300 | // test('bundle true', function(t) { 301 | // var dst = dsturi('valid.bundle.true'); 302 | // var fixture = path.resolve(__dirname, 'fixtures', 'valid.bundle-layer-1.geojson') + ',' + path.resolve(__dirname, 'fixtures', 'valid.bundle-layer-2.geojson'); 303 | // var cmd = [ copy, fixture, dst, '--bundle', true ].join(' '); 304 | // exec(cmd, function(err, stdout, stderr) { 305 | // t.ifError(err, 'copied'); 306 | // tileCount(dst, function(err, count) { 307 | // t.ifError(err, 'counted tiles'); 308 | // t.equal(count, 167, 'expected number of tiles'); 309 | // t.end(); 310 | // }); 311 | // }); 312 | // }); 313 | 314 | // test('layerName', function(t) { 315 | // var dst = dsturi('valid.mini.geojson'); 316 | // var fixture = path.resolve(__dirname, 'fixtures', 'valid.mini.geojson'); 317 | // var cmd = [ copy, fixture, dst, '--layerName', 'named' ].join(' '); 318 | // exec(cmd, function(err, stdout, stderr) { 319 | // t.ifError(err, 'copied'); 320 | // t.ok(stdout.length > 0, 'logs something'); 321 | // tileCount(dst, function(err, count) { 322 | // t.ifError(err, 'counted tiles'); 323 | // t.equal(count, 5, 'expected number of tiles'); 324 | // t.end(); 325 | // }); 326 | // }); 327 | // }); 328 | 329 | test('size limit environment variable', function(t) { 330 | var dst = dsturi('valid.mini.geojson'); 331 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mini.geojson'); 332 | var cmd = [ 'BRIDGE_MAX_VTILE_BYTES_COMPRESSED=10', copy, fixture, dst ].join(' '); 333 | exec(cmd, function(err, stdout, stderr) { 334 | t.ok(stderr.indexOf('Tile size exceeds limit. At least one vector tile is larger than') > -1, 'expected error'); 335 | t.end(); 336 | }); 337 | }); 338 | -------------------------------------------------------------------------------- /test/fixtures/fortythree.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/fortythree.mbtiles -------------------------------------------------------------------------------- /test/fixtures/invalid-zxy.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/invalid-zxy.mbtiles -------------------------------------------------------------------------------- /test/fixtures/invalid.coords-out-of-range.geojson: -------------------------------------------------------------------------------- 1 | {"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-179.9957849085331,-86.05051996740607],[-179.99577283859253,-85.05049682597036],[-179.99553009867665,-85.0504978673373],[-179.99554619193077,-85.05052112447504],[-179.9957849085331,-85.05051996740607]]]}} 2 | -------------------------------------------------------------------------------- /test/fixtures/invalid.corrupt.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/invalid.corrupt.mbtiles -------------------------------------------------------------------------------- /test/fixtures/invalid.null-tile.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/invalid.null-tile.mbtiles -------------------------------------------------------------------------------- /test/fixtures/invalid.serialtiles.gzipped.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/invalid.serialtiles.gzipped.gz -------------------------------------------------------------------------------- /test/fixtures/invalid.serialtiles.noinfo.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/invalid.serialtiles.noinfo.gz -------------------------------------------------------------------------------- /test/fixtures/invalid.tile-with-no-geometry.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/invalid.tile-with-no-geometry.mbtiles -------------------------------------------------------------------------------- /test/fixtures/invalid.tilejson: -------------------------------------------------------------------------------- 1 | .__ .__ .__ .___ 2 | |__| _______ _______ | | |__| __| _/ 3 | | |/ \ \/ /\__ \ | | | |/ __ | 4 | | | | \ / / __ \| |_| / /_/ | 5 | |__|___| /\_/ (____ /____/__\____ | 6 | \/ \/ \/ 7 | -------------------------------------------------------------------------------- /test/fixtures/reprojection/data.cpg: -------------------------------------------------------------------------------- 1 | UTF-8 -------------------------------------------------------------------------------- /test/fixtures/reprojection/data.dbf: -------------------------------------------------------------------------------- 1 | _A OBJECTIDN 2 | 2699 3771 -------------------------------------------------------------------------------- /test/fixtures/reprojection/data.prj: -------------------------------------------------------------------------------- 1 | PROJCS["NAD27_Wisconsin_South",GEOGCS["GCS_North_American_1927",DATUM["D_North_American_1927",SPHEROID["Clarke_1866",6378206.4,294.9786982]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["standard_parallel_1",42.73333333333333],PARAMETER["standard_parallel_2",44.06666666666667],PARAMETER["latitude_of_origin",42],PARAMETER["central_meridian",-90],PARAMETER["false_easting",2000000],PARAMETER["false_northing",0],UNIT["Foot_US",0.30480060960121924]] -------------------------------------------------------------------------------- /test/fixtures/reprojection/data.qpj: -------------------------------------------------------------------------------- 1 | PROJCS["NAD27 / Wisconsin South",GEOGCS["NAD27",DATUM["North_American_Datum_1927",SPHEROID["Clarke 1866",6378206.4,294.9786982139006,AUTHORITY["EPSG","7008"]],AUTHORITY["EPSG","6267"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4267"]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",42.73333333333333],PARAMETER["standard_parallel_2",44.06666666666667],PARAMETER["latitude_of_origin",42],PARAMETER["central_meridian",-90],PARAMETER["false_easting",2000000],PARAMETER["false_northing",0],UNIT["US survey foot",0.3048006096012192,AUTHORITY["EPSG","9003"]],AXIS["X",EAST],AXIS["Y",NORTH],AUTHORITY["EPSG","32054"]] 2 | -------------------------------------------------------------------------------- /test/fixtures/reprojection/data.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/reprojection/data.shp -------------------------------------------------------------------------------- /test/fixtures/reprojection/data.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/reprojection/data.shx -------------------------------------------------------------------------------- /test/fixtures/threenine.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/threenine.mbtiles -------------------------------------------------------------------------------- /test/fixtures/v2-throw.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/v2-throw.mbtiles -------------------------------------------------------------------------------- /test/fixtures/valid-v2.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid-v2.mbtiles -------------------------------------------------------------------------------- /test/fixtures/valid-v2.serialtiles.gzip.vector.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid-v2.serialtiles.gzip.vector.gz -------------------------------------------------------------------------------- /test/fixtures/valid.bigtiff.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid.bigtiff.tif -------------------------------------------------------------------------------- /test/fixtures/valid.bigtiff.tif.aux.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 100 5 | 26.779955478126 6 | 0 7 | 36.171959300567 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/valid.geotiff.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid.geotiff.tif -------------------------------------------------------------------------------- /test/fixtures/valid.mbtiles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid.mbtiles -------------------------------------------------------------------------------- /test/fixtures/valid.mini.geojson: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","properties":{"kind":"state","state":"DC"},"features":[ 2 | {"type":"Feature","properties":{"kind":"county","name":"District of Columbia","state":"DC"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-77.0353,38.9939],[-77.0024,38.9665],[-76.9093,38.8953],[-77.0407,38.7912],[-77.0462,38.8405],[-77.0407,38.8734],[-77.1174,38.9336]]]]}} 3 | ]} -------------------------------------------------------------------------------- /test/fixtures/valid.serialtiles.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid.serialtiles.gz -------------------------------------------------------------------------------- /test/fixtures/valid.serialtiles.gzip.vector.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid.serialtiles.gzip.vector.gz -------------------------------------------------------------------------------- /test/fixtures/valid.tilejson: -------------------------------------------------------------------------------- 1 | { 2 | "tilejson": "1.0.0", 3 | "name": "Bright TileJSON", 4 | "scheme": "xyz", 5 | "minzoom": 4, 6 | "maxzoom": 5, 7 | "bounds": [ 8 | -124.76214599609375, 9 | 24.54521942138596, 10 | -66.95780181884764, 11 | 49.3717422485226 12 | ], 13 | "tiles": [ 14 | "http://test-bucket.s3.amazonaws.com/test-tiles/{z}/{x}/{y}" 15 | ], 16 | "center": [ 0, 0, 3 ] 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/valid.tm2z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mapbox/mapbox-tile-copy/d82039446e7cebdf3995a2a8ec35b6078a952895/test/fixtures/valid.tm2z -------------------------------------------------------------------------------- /test/get-uri.test.js: -------------------------------------------------------------------------------- 1 | var test = require('tape').test; 2 | var path = require('path'); 3 | var getUri = require('../lib/get-uri'); 4 | 5 | [ 6 | 'valid.geojson', 7 | 'valid.mbtiles', 8 | 'valid.serialtiles.gz', 9 | 'valid.tilejson', 10 | 'valid.tm2z' 11 | ].forEach(function(filename) { 12 | test('get-uri: ' + filename, function(t) { 13 | var filepath = path.resolve(__dirname, 'fixtures', filename); 14 | var expected = { 15 | geojson: 'omnivore://' + filepath, 16 | mbtiles: 'mbtiles://' + filepath, 17 | serialtiles: 'serialtiles://' + filepath, 18 | tilejson: 'tilejson://' + filepath, 19 | tm2z: 'tm2z://' + filepath 20 | }[filename.split('.')[1]]; 21 | 22 | getUri(filepath, null, function(err, uri) { 23 | t.ifError(err, 'got uri'); 24 | t.equal(uri, expected, 'got expected uri'); 25 | t.end(); 26 | }); 27 | }); 28 | }); 29 | 30 | test('get-uri: invalid.tilejson', function(t) { 31 | var filepath = path.resolve(__dirname, 'fixtures', 'invalid.tilejson'); 32 | getUri(filepath, null, function(err, uri) { 33 | t.ok(err, 'expected error'); 34 | t.equal(err.code, 'EINVALID', 'expected error code'); 35 | t.equal(err.message, 'Unknown filetype', 'expected error message'); 36 | t.end(); 37 | }); 38 | }); 39 | 40 | test('get-uri: bunk filepath', function(t) { 41 | getUri('the cheese is old and moldy', null, function(err, uri) { 42 | t.ok(err, 'expected error'); 43 | t.equal(err.code, 'ENOENT', 'expected error'); 44 | t.end(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tape').test; 4 | var path = require('path'); 5 | var AWS = require('@mapbox/mock-aws-sdk-js'); 6 | var copy = require('../index.js'); 7 | 8 | function setupS3Stubs() { 9 | return { 10 | get: AWS.stub('S3', 'getObject', function(params, callback) { 11 | return callback(null, { Body: Buffer.from('test') }); 12 | }), 13 | put: AWS.stub('S3', 'putObject', function(params, callback) { 14 | return callback(null); 15 | }) 16 | } 17 | } 18 | 19 | test('serialtiles', function(t) { 20 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.serialtiles.gz'); 21 | var dst = 's3://test-bucket/valid.serialtiles/{z}/{x}/{y}'; 22 | var s3 = setupS3Stubs(); 23 | 24 | copy(fixture, dst, {}, function(err) { 25 | t.ifError(err, 'copied'); 26 | t.equal(AWS.S3.callCount, 1, '1 s3 client'); 27 | t.equal(s3.get.callCount, 4, '4 tiles retrieved'); 28 | t.equal(s3.put.callCount, 4, '4 tiles put to s3'); 29 | t.deepEqual(s3.put.args.map(function(call) { 30 | return call[0].Key; 31 | }).sort(), [ 32 | 'valid.serialtiles/1/0/0', 33 | 'valid.serialtiles/1/0/1', 34 | 'valid.serialtiles/1/1/0', 35 | 'valid.serialtiles/1/1/1' 36 | ]); 37 | AWS.S3.restore(); 38 | t.end(); 39 | }); 40 | }); 41 | 42 | test('mbtiles', function(t) { 43 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mbtiles'); 44 | var dst = 's3://test-bucket/valid.mbtiles/{z}/{x}/{y}'; 45 | var s3 = setupS3Stubs(); 46 | 47 | copy(fixture, dst, {}, function(err) { 48 | t.ifError(err, 'copied'); 49 | t.equal(AWS.S3.callCount, 1, '1 s3 client'); 50 | t.equal(s3.get.callCount, 21, '21 tiles retrieved'); 51 | t.equal(s3.put.callCount, 21, '21 tiles put to s3'); 52 | t.deepEqual(s3.put.args.map(function(call) { 53 | return call[0].Key; 54 | }).sort(), [ 55 | 'valid.mbtiles/0/0/0', 56 | 'valid.mbtiles/1/0/0', 57 | 'valid.mbtiles/1/0/1', 58 | 'valid.mbtiles/1/1/0', 59 | 'valid.mbtiles/1/1/1', 60 | 'valid.mbtiles/2/0/0', 61 | 'valid.mbtiles/2/0/1', 62 | 'valid.mbtiles/2/0/2', 63 | 'valid.mbtiles/2/0/3', 64 | 'valid.mbtiles/2/1/0', 65 | 'valid.mbtiles/2/1/1', 66 | 'valid.mbtiles/2/1/2', 67 | 'valid.mbtiles/2/1/3', 68 | 'valid.mbtiles/2/2/0', 69 | 'valid.mbtiles/2/2/1', 70 | 'valid.mbtiles/2/2/2', 71 | 'valid.mbtiles/2/2/3', 72 | 'valid.mbtiles/2/3/0', 73 | 'valid.mbtiles/2/3/1', 74 | 'valid.mbtiles/2/3/2', 75 | 'valid.mbtiles/2/3/3' 76 | ]); 77 | AWS.S3.restore(); 78 | t.end(); 79 | }); 80 | }); 81 | 82 | test('corrupt mbtiles', function(t) { 83 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.corrupt.mbtiles'); 84 | var dst = 's3://test-bucket/invalid.corrupt.mbtiles/{z}/{x}/{y}'; 85 | var s3 = setupS3Stubs(); 86 | 87 | copy(fixture, dst, {}, function(err) { 88 | t.ok(err, 'expected error'); 89 | t.equal(err.code, 'EINVALID', 'marked invalid'); 90 | t.equal(s3.put.callCount, 0, '0 tiles put to s3'); 91 | AWS.S3.restore(); 92 | t.end(); 93 | }); 94 | }); 95 | 96 | test('null mbtiles', function(t) { 97 | var fixture = path.resolve(__dirname, 'fixtures', 'invalid.null-tile.mbtiles'); 98 | var dst = 's3://test-bucket/invalid.null-tile.mbtiles/{z}/{x}/{y}'; 99 | var s3 = setupS3Stubs(); 100 | 101 | copy(fixture, dst, {}, function(err) { 102 | t.ok(err, 'expected error'); 103 | t.equal(err.code, 'EINVALID', 'marked invalid'); 104 | t.equal(s3.put.callCount, 0, '0 tiles put to s3'); 105 | AWS.S3.restore(); 106 | t.end(); 107 | }); 108 | }); 109 | 110 | test('fails with missing {z}/{x}/{y} template', function(t) { 111 | var fixture = path.resolve(__dirname, 'fixtures', 'valid.mbtiles'); 112 | var dst = 's3://test-bucket/valid.mbtiles/{z}/{x}/{y}'; 113 | var dst = dst.slice(0, dst.indexOf('{z}')); 114 | var s3 = setupS3Stubs(); 115 | 116 | copy(fixture, dst, {}, function(err) { 117 | t.ok(err); 118 | t.equal(err.message, 'Destination URL does not include a {z}/{x}/{y} template.'); 119 | t.equal(s3.put.callCount, 0, '0 tiles put to s3'); 120 | AWS.S3.restore(); 121 | t.end(); 122 | }); 123 | }); 124 | --------------------------------------------------------------------------------