├── .DS_Store ├── .circleci └── config.yml ├── .env.example ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md └── pull_request_template.md ├── .gitignore ├── Dockerfile ├── docker-compose.yml ├── package-lock.json ├── package.json ├── pm2_config.json ├── readme.md ├── scripts ├── deploy.sh └── docker_start.sh ├── src ├── blacklist.js ├── database.js ├── ethereum.js ├── ipfs.js ├── newrelic.js ├── server.js └── utils.js ├── test ├── blacklist.spec.js ├── ethereum.spec.js └── ipfs.spec.js └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/decentraland/ipfs-node/494a57284712880068a02c0ebade8c8c2ddd05bb/.DS_Store -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | ipfs: 4 | docker: 5 | - image: circleci/node:latest 6 | environment: 7 | NODE_ENV: "test" 8 | LAND_REGISTRY_CONTRACT_ADDRESS: "0x7a73483784ab79257bb11b96fd62a2c3ae4fb75b" 9 | steps: 10 | - checkout 11 | - run: sudo apt-get update && sudo apt install -y libusb-1.0-0 libusb-1.0-0-dev 12 | - run: wget https://dist.ipfs.io/go-ipfs/v0.4.11/go-ipfs_v0.4.11_linux-amd64.tar.gz 13 | - run: tar xvfz go-ipfs_v0.4.11_linux-amd64.tar.gz 14 | - run: sudo cp go-ipfs/ipfs /usr/local/bin 15 | - run: ipfs init 16 | - restore_cache: 17 | keys: 18 | - v1-dependencies-{{ checksum "package.json" }} 19 | - v1-dependencies- 20 | - run: npm i 21 | - save_cache: 22 | paths: 23 | - node_modules 24 | key: v1-dependencies-{{ checksum "package.json" }} 25 | - run: ipfs daemon --offline & npm run test 26 | 27 | workflows: 28 | version: 2 29 | build: 30 | jobs: 31 | - ipfs 32 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | #Ethereum 2 | LAND_REGISTRY_CONTRACT_ADDRESS=0x7a73483784ab79257bb11b96fd62a2c3ae4fb75b 3 | RPC_URL= 4 | 5 | #Blacklist 6 | BLACKLIST_URL=https://lens.decentraland.zone/api 7 | 8 | #REDIS 9 | REDIS_HOST=redis 10 | REDIS_PORT=6379 11 | REDIS_PASSWORD= 12 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @andresmijares @eordano @nachomazzara 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Context 2 | 3 | ## Objective 4 | 5 | ## Features 6 | 7 | ## Testing -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Context 2 | 3 | # Issues / Tickets 4 | 5 | # How to test 6 | 7 | # Notes -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | yarn.lock 4 | package-lock.json 5 | .env 6 | data 7 | logs 8 | redis-data 9 | /deployment 10 | .nyc_output 11 | 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | 3 | RUN apt-get update 4 | RUN apt-get upgrade -y 5 | RUN apt-get -y install \ 6 | libusb-dev \ 7 | libusb-1.0.0-dev \ 8 | libudev-dev 9 | RUN npm install node-hid 10 | 11 | WORKDIR /opt/ipfs 12 | RUN wget https://dist.ipfs.io/go-ipfs/v0.4.11/go-ipfs_v0.4.11_linux-amd64.tar.gz 13 | RUN tar xvfz go-ipfs_v0.4.11_linux-amd64.tar.gz 14 | RUN cp go-ipfs/ipfs /usr/local/bin 15 | RUN ipfs init 16 | RUN ipfs config Addresses.Gateway /ip4/0.0.0.0/tcp/8080 17 | 18 | WORKDIR /uploader 19 | COPY package.json . 20 | RUN npm install 21 | COPY . . 22 | 23 | EXPOSE 3000 24 | EXPOSE 4001 25 | EXPOSE 5001 26 | EXPOSE 8080 27 | 28 | CMD ./scripts/docker_start.sh 29 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | services: 4 | redis: 5 | image: redis:3.2-alpine 6 | volumes: 7 | - $PWD/redis_data:/data 8 | ports: 9 | - 6379:6379 10 | networks: 11 | - internal 12 | 13 | ipfs: 14 | container_name: ipfs-node 15 | build: 16 | context: . 17 | depends_on: 18 | - redis 19 | environment: 20 | - .env 21 | ports: 22 | - 3000:3000 23 | volumes: 24 | - $PWD:/uploader 25 | - $PWD/tmp:/uploader/tmp 26 | - $PWD/db:/uploader/db 27 | - $PWD/data:/root/.ipfs 28 | - ~/.ssh/id_rsa:/root/.ssh/id_rsa 29 | networks: 30 | - internal 31 | 32 | volumes: 33 | redis_data: 34 | 35 | networks: 36 | internal: 37 | driver: bridge 38 | 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "uploader", 3 | "version": "1.0.1", 4 | "description": "This is a node.js express app that uses the go-ipfs client (the js-ipfs client [doesn't support](https://github.com/ipfs/js-ipfs/pull/856) the DHT yet) to upload scenes to our IPFS node.", 5 | "main": "src/server.js", 6 | "scripts": { 7 | "start:prod": "pm2-docker start ./pm2_config.json", 8 | "test": "NODE_ENV=test nyc mocha --timeout 120000 --exit", 9 | "docker:run": "docker run --name=ipfs-node -v $PWD/db:/root/app/ipfs-node/db -v $PWD/data:/root/.ipfs -v ~/.ssh/id_rsa:/root/.ssh/id_rsa -p 3000:3000 -p 4001:4001 -p 5001:5001 -p 8080:8080 uploader:latest", 10 | "start": "nodemon src/server.js" 11 | }, 12 | "nyc": { 13 | "include": ["src"] 14 | }, 15 | "author": "The Decentraland Team", 16 | "license": "Apache-2.0", 17 | "dependencies": { 18 | "axios": "^0.18.0", 19 | "babel-cli": "^6.26.0", 20 | "babel-polyfill": "^6.26.0", 21 | "bluebird": "^3.5.1", 22 | "body-parser": "^1.18.2", 23 | "commander": "^2.15.1", 24 | "cors": "^2.8.4", 25 | "decentraland-eth": "^1.1.2", 26 | "dotenv": "^5.0.1", 27 | "express": "^4.16.2", 28 | "http-errors": "^1.6.2", 29 | "mkdirp": "^0.5.1", 30 | "morgan": "^1.9.0", 31 | "newrelic": "^3.3.0", 32 | "pm2": "^2.10.2", 33 | "redis": "^2.8.0", 34 | "standard": "^10.0.3", 35 | "tape": "^4.8.0", 36 | "tempy": "^0.2.1" 37 | }, 38 | "devDependencies": { 39 | "babel-cli": "^6.26.0", 40 | "babel-polyfill": "^6.26.0", 41 | "chai": "^4.1.2", 42 | "chai-as-promised": "^7.1.1", 43 | "chai-http": "^4.0.0", 44 | "mocha": "^5.0.5", 45 | "nodemailer": "^4.6.3", 46 | "nodemon": "^1.14.12", 47 | "nyc": "^11.6.0", 48 | "sinon": "^4.5.0", 49 | "tunnel-ssh": "^4.1.4" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /pm2_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "apps" : [{ 3 | "name" : "ipfs-gateway-prod", 4 | "script" : "./src/server.js", 5 | "watch" : false, 6 | "exec_interpreter" : "babel-node", 7 | "exec_mode" : "fork", 8 | "instances" : 1 9 | }] 10 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # IPFS Upload node 2 | 3 | This is a node.js express app that uses the go-ipfs client (the js-ipfs client [doesn't support](https://github.com/ipfs/js-ipfs/pull/856) the DHT yet) to upload scenes to our IPFS node. 4 | 5 | ## Public API 6 | 7 | | Endpoint| Method | Response | 8 | | ------------- |:-------------:|-------------| 9 | | api/pin/:peerId/:x/:y | POST | { data: object } | 10 | | api/resolve/:x/:y | GET | { url: { ipns: string, ipfs: string, dependencies: array } } | 11 | | api/get/:ipfs/:file* | GET | file | 12 | 13 | ## Debugging 14 | 15 | You can always check commands manually, get into the container: 16 | ``` 17 | docker exec it ipfs-node bash 18 | ``` 19 | The command api is documented [here](https://ipfs.io/docs/commands/). 20 | 21 | ## Test environment 22 | 23 | You need to create your own source of assets and publish it. Let's say to create a 2 level deep folder structure like: 24 | 25 | - sample 26 | * child1 27 | - text.txt 28 | * child2.txt 29 | 30 | You can upload publish your assets like: 31 | 32 | ``` 33 | ipfs add -r ./sample 34 | ``` 35 | This will return a list of hashes per element, take the main one from the parent directory. 36 | 37 | ```bash 38 | # output omitted for convenience... 39 | # added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH sample/child/text.txt 40 | # added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH sample/child2.txt 41 | # added QmNrDkNEovk19jPe1wQA9vXFwGwBE8t9uCGuaXukfR385g sample/child 42 | # added QmUt8guW4C7zDZ7WHociwudbfs83zMZ7Rkxrjkoeg3QupX sample 43 | 44 | ipfs name publish QmUt8guW4C7zDZ7WHociwudbfs83zMZ7Rkxrjkoeg3QupX 45 | #Published to QmNwrcEu5AiDdKZEWzFcGbWxP5j7E1z4eNC7xWaJaVjKMU: /ipfs/QmUt8guW4C7zDZ7WHociwudbfs83zMZ7Rkxrjkoeg3QupX 46 | ``` 47 | Et voila! votre ipfs hash is up. Now you can query ipns hashes and dependencies using the API. 48 | Assuming `QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK` is the node peerId 49 | and there is an IPNS inside the parcel (1,2) 50 | 51 | ```http 52 | POST api/pin/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK/1/2 53 | HTTP/1.1 200 OK 54 | Content-Type: application/json 55 | 56 | { 57 | "ok":true 58 | } 59 | 60 | ``` 61 | 62 | 63 | ```http 64 | POST api/pin/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK/1/2 65 | HTTP/1.1 404 Not found 66 | Content-Type: application/json 67 | 68 | { 69 | "error": "IPNS not found" 70 | } 71 | ``` 72 | 73 | ```http 74 | POST api/pin/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK/1/2 75 | HTTP/1.1 500 76 | Content-Type: application/json 77 | 78 | { 79 | "error": "Can not connect to peer: QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK" 80 | } 81 | ``` 82 | 83 | Get the hashes related to a parcel 84 | 85 | ```http 86 | GET api/resolve/-81,-108 87 | HTTP/1.1 200 OK 88 | Content-Type: application/json 89 | 90 | { 91 | "ok": true, 92 | "url": { 93 | "ipns": "Qmbu41fpDf2xp547AQz3uYYXCy81JqWAYU31KW4u7MQPB4", 94 | "ipfs": "QmSwTyffPvZt7cxdoGaQWrzQVus3ArqG7WFWct6LF4yCpD", 95 | "dependencies": [ 96 | { 97 | "src": "'QmSwTyffPvZt7cxdoGaQWrzQVus3ArqG7WFWct6LF4yCpD", 98 | "ipfs": "QmUziFsqDd72KUwYHcGCusY8PVMmgj6bRUFqYv8KL6NCej", 99 | "name": "minimap.png'" 100 | }, 101 | { 102 | "src": "'QmSwTyffPvZt7cxdoGaQWrzQVus3ArqG7WFWct6LF4yCpD", 103 | "ipfs": "QmQ7ixyMcQKyfrPG95pifJBs6qUA2YLkNmDboCq9KtAq9x", 104 | "name": "scene.html'" 105 | }, 106 | { 107 | "src": "'QmSwTyffPvZt7cxdoGaQWrzQVus3ArqG7WFWct6LF4yCpD", 108 | "ipfs": "QmSv553QHeod1fNn9BxaQjxnwQwbQqv2RmLEEyaF71WDuK", 109 | "name": "scene.json'" 110 | }, 111 | { 112 | "src": "'QmSwTyffPvZt7cxdoGaQWrzQVus3ArqG7WFWct6LF4yCpD", 113 | "ipfs": "QmdLYsV4qy3XUcJ1TQw2cHxd2JCUpvHwcEgfgWKzp2kxE6", 114 | "name": "scene.xml'" 115 | } 116 | ] 117 | } 118 | } 119 | ``` 120 | 121 | ```http 122 | GET api/resolve/-81,-108 123 | HTTP/1.1 403 FORBIDDEN 124 | Content-Type: application/json 125 | 126 | { 127 | "error": "Parcel (-81,-108) is blacklisted" 128 | } 129 | ``` 130 | 131 | ```http 132 | GET api/resolve/-81,-108 133 | HTTP/1.1 404 Not found 134 | Content-Type: application/json 135 | 136 | { 137 | "error": "IPNS not found" 138 | } 139 | ``` 140 | 141 | Get a file 142 | 143 | ```http 144 | GET api/get/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK 145 | HTTP/1.1 200 OK 146 | Content-Type: stream 147 | ``` 148 | 149 | ```http 150 | GET api/get/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK/filename 151 | HTTP/1.1 200 OK 152 | Content-Type: stream 153 | ``` 154 | 155 | ```http 156 | GET api/get/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK/subfolder/filename 157 | HTTP/1.1 200 OK 158 | Content-Type: stream 159 | ``` 160 | ```http 161 | GET api/get/QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK/subfolder/filename 162 | HTTP/1.1 403 FORBIDDEN 163 | Content-Type: application/json 164 | 165 | { 166 | "error": "IPFS QmexQCWwaEdEDWrMArR2T2g3V4RGvXXiXj6HgWfRBCumDK is blacklisted" 167 | } 168 | ``` 169 | 170 | Notice you cannot get node, only leaf. 171 | 172 | ## Usage with docker 173 | 174 | ### Development 175 | 176 | ``` 177 | npm run docker:build 178 | npm run docker:run 179 | ``` 180 | 181 | ### AWS 182 | 183 | ``` 184 | npm run docker:build 185 | npm run docker:aws:run 186 | ``` 187 | 188 | ## Version 189 | 2.0.0 - Refactor API gateways. 190 | -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | HOSTNAME="ec2-54-70-30-4.us-west-2.compute.amazonaws.com" 4 | USER="ubuntu" 5 | PEM_FILE="../ipfs-node-ami.pem" 6 | 7 | RELEASE=`date -u +"%Y-%m-%dT%H:%M:%SZ"` 8 | DESTINATION="~/ipfs-node" 9 | 10 | git archive master | gzip > /tmp/master.tar.gz 11 | scp -i $PEM_FILE /tmp/master.tar.gz $USER@$HOSTNAME:/tmp 12 | 13 | ssh -i $PEM_FILE $USER@$HOSTNAME < { 10 | try { 11 | const ipfs = req.params.ipfs 12 | const file = req.params[0] ? `${ipfs}/${req.params[0]}` : ipfs 13 | await Blacklist.checkIPFS(ipfs) 14 | request.get(`http://localhost:8080/ipfs/${file}`).pipe(res) 15 | } catch (error) { 16 | next(error) 17 | } 18 | } 19 | this.pin = async (req, res, next) => { 20 | try { 21 | const [x, y] = [req.params.x, req.params.y] 22 | const ipns = await Ethereum.getIPNS(x, y) 23 | await Download.connectPeer(req.params.peerId) 24 | const ipfs = await Download.resolveIPNS(ipns) 25 | await Download.publishHash(ipfs) 26 | const dependencies = await Download.resolveDependencies(ipfs) 27 | await DB.setIPFS(ipns, ipfs) 28 | await DB.setParcel({ x, y }, { ipns, ipfs, dependencies }) 29 | return res.json({ ok: true, message: 'Pinning Success' }) 30 | } catch (error) { 31 | next(error) 32 | } 33 | } 34 | this.resolve = async (req, res, next) => { 35 | try { 36 | const [x, y] = [req.params.x, req.params.y] 37 | if (!req.query.force) { 38 | // No cache 39 | await Blacklist.checkParcel(x, y) 40 | const cachedResponse = await DB.getParcel(x, y) 41 | if (cachedResponse) { 42 | return res.json({ ok: true, url: cachedResponse }) 43 | } 44 | } 45 | const ipns = await Ethereum.getIPNS(x, y) 46 | const ipfs = await Download.resolveIPNS(ipns) 47 | const dependencies = await Download.resolveDependencies(ipfs) 48 | const url = { ipns, ipfs, dependencies } 49 | await DB.setParcel({ x, y }, url) 50 | return res.json({ ok: true, url }) 51 | } catch (error) { 52 | next(error) 53 | } 54 | } 55 | } 56 | 57 | static publishHash(ipfs) { 58 | return new Promise((resolve, reject) => { 59 | execFile('ipfs', ['pin', 'add', ipfs], (err, stdout, stderr) => { 60 | if (err) { 61 | return reject(stderr) 62 | } 63 | const match = stdout.match( 64 | new RegExp('pinned ([a-zA-Z0-9]+) recursively') 65 | ) 66 | if (!match) { 67 | reject(new Error('Can not pin: ' + ipfs)) 68 | } 69 | return resolve() 70 | }) 71 | }) 72 | } 73 | 74 | static resolveIPNS(ipns) { 75 | return new Promise((resolve, reject) => { 76 | execFile( 77 | 'ipfs', 78 | ['name', 'resolve', '--nocache', ipns], 79 | async (err, stdout, stderr) => { 80 | let ipfs 81 | if (err) { 82 | // Check it with our dht 83 | ipfs = await DB.getIPFS(ipns) 84 | if (!ipfs) { 85 | return reject(new Error(stderr)) 86 | } else { 87 | return resolve(ipfs) 88 | } 89 | } 90 | ipfs = stdout.substr(6, stdout.length - 7) 91 | return resolve(ipfs) 92 | } 93 | ) 94 | }) 95 | } 96 | 97 | static resolveDependencies(ipfs) { 98 | return new Promise((resolve, reject) => { 99 | execFile( 100 | 'ipfs', 101 | ['refs', '-r', '--format= ', ipfs], 102 | { maxBuffer: 1024 * 500 }, 103 | (err, stdout, stderr) => { 104 | if (err) return reject(new Error(stderr)) 105 | const dependencies = stdout 106 | .split(/\r?\n/) 107 | .filter(row => row) 108 | .map(row => { 109 | const data = row 110 | .replace(/\s+/g, ' ') 111 | .trim() 112 | .split(' ') // row format: src | ipfsHash | name 113 | return { 114 | src: data[0], 115 | ipfs: data[1], 116 | name: data[2] 117 | } 118 | }) 119 | return resolve(dependencies) 120 | } 121 | ) 122 | }) 123 | } 124 | 125 | static connectPeer(peerId) { 126 | return new Promise((resolve, reject) => { 127 | execFile( 128 | 'ipfs', 129 | ['swarm', 'connect', `/p2p-circuit/ipfs/${peerId}`], 130 | (err, stdout, stderr) => { 131 | if (err) 132 | return reject(new Error('Could not connect to peer: ' + peerId)) 133 | return resolve() 134 | } 135 | ) 136 | }) 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/newrelic.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | /** 3 | * New Relic agent configuration. 4 | * 5 | * See lib/config/default.js in the agent distribution for a more complete 6 | * description of configuration variables and their potential values. 7 | */ 8 | exports.config = { 9 | /** 10 | * Array of application names. 11 | */ 12 | app_name: ['IPFS-Gateway'], 13 | /** 14 | * Your New Relic license key. 15 | */ 16 | license_key: process.env.newrelic, 17 | logging: { 18 | /** 19 | * Level at which to log. 'trace' is most useful to New Relic when diagnosing 20 | * issues with the agent, 'info' and higher will impose the least overhead on 21 | * production applications. 22 | */ 23 | level: 'info' 24 | }, 25 | /** 26 | * When true, all request headers except for those listed in attributes.exclude 27 | * will be captured for all traces, unless otherwise specified in a destination's 28 | * attributes include/exclude lists. 29 | */ 30 | allow_all_headers: true, 31 | attributes: { 32 | /** 33 | * Prefix of attributes to exclude from all destinations. Allows * as wildcard 34 | * at end. 35 | * 36 | * NOTE: If excluding headers, they must be in camelCase form to be filtered. 37 | * 38 | * @env NEW_RELIC_ATTRIBUTES_EXCLUDE 39 | */ 40 | exclude: [ 41 | 'request.headers.cookie', 42 | 'request.headers.authorization', 43 | 'request.headers.proxyAuthorization', 44 | 'request.headers.setCookie*', 45 | 'request.headers.x*', 46 | 'response.headers.cookie', 47 | 'response.headers.authorization', 48 | 'response.headers.proxyAuthorization', 49 | 'response.headers.setCookie*', 50 | 'response.headers.x*' 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | // require('babel-pollyfill') // needed for pm2 to work proper 2 | require('newrelic') 3 | const express = require('express') 4 | const bodyParser = require('body-parser') 5 | const cors = require('cors') 6 | const IPFS = require('./ipfs') 7 | const { setLogger, errorHandler, notFound } = require('./utils') 8 | const Ethereum = require('./ethereum') 9 | const DB = require('./database') 10 | 11 | const app = express() 12 | 13 | app.use(cors()) 14 | 15 | // Parse the huge uploads we may get, still 100mb limit 16 | // though since the VM may run out of memory 17 | app.use(bodyParser.json({ limit: '10kb' })) 18 | 19 | setLogger(app) 20 | 21 | // IPFS Handler 22 | const ipfs = new IPFS() 23 | 24 | app.post('/api/pin/:peerId/:x/:y', ipfs.pin) 25 | 26 | app.get('/api/get/:ipfs*?', ipfs.download) 27 | 28 | app.get('/api/resolve/:x/:y', ipfs.resolve) 29 | 30 | app.get('/ping', (req, res, next) => res.json({ message: 'pong' })) // Used for ELB to akc a healthy state 31 | 32 | app.use(notFound) 33 | 34 | app.use(errorHandler) 35 | 36 | const port = process.env.PORT || 3000 37 | app.listen(port, () => { 38 | if (process.env.NODE_ENV !== 'test') { 39 | Ethereum.connectBlockchain() 40 | DB.connect() 41 | } 42 | console.log(`Listening on port ${port}...`) 43 | }) 44 | 45 | module.exports = app 46 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const morgan = require('morgan') 4 | const createError = require('http-errors') 5 | 6 | function formatDate(date) { 7 | const monthNames = [ 8 | 'January', 9 | 'February', 10 | 'March', 11 | 'April', 12 | 'May', 13 | 'June', 14 | 'July', 15 | 'August', 16 | 'September', 17 | 'October', 18 | 'November', 19 | 'December' 20 | ] 21 | 22 | const day = date.getDate() 23 | const monthIndex = date.getMonth() 24 | const year = date.getFullYear() 25 | 26 | return day + '' + monthNames[monthIndex] + '' + year 27 | } 28 | 29 | module.exports = { 30 | setLogger: app => { 31 | let dir = './logs' 32 | if (!fs.existsSync(dir)) { 33 | fs.mkdirSync(dir) 34 | } 35 | const accessLogStream = fs.createWriteStream( 36 | path.join(__dirname, `../logs/${formatDate(new Date())}.log`), 37 | { flags: 'a' } 38 | ) 39 | app.use(morgan('combined', { stream: accessLogStream })) 40 | }, 41 | errorHandler: (err, req, res, next) => { 42 | if (!err.statusCode) { 43 | err.statusCode = 500 44 | } 45 | res.status(err.statusCode).json({ error: err.message }) 46 | }, 47 | notFound: (req, res, next) => { 48 | if (!req.route) { 49 | next(createError(404, `${req.originalUrl} not found`)) 50 | } 51 | next() 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/blacklist.spec.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const chaiAsPromised = require('chai-as-promised') 3 | const axios = require('axios') 4 | const { sandbox } = require('sinon') 5 | const Blacklist = require('../src/blacklist') 6 | 7 | chai.use(chaiAsPromised) 8 | 9 | const ctx = sandbox.create() 10 | const ipfs = 'hash' 11 | const x = 1 12 | const y = 1 13 | const expect = chai.expect 14 | let axiosGet 15 | 16 | describe('Blacklist', () => { 17 | beforeEach(() => { 18 | process.env.BLACKLIST_URL = 'http://blacklist.com/api' 19 | axiosGet = ctx.stub(axios, 'get').callsFake( 20 | () => 21 | new Promise(resolve => 22 | resolve({ 23 | data: { 24 | blacklisted: true 25 | } 26 | }) 27 | ) 28 | ) 29 | }) 30 | 31 | afterEach(() => { 32 | // completely restore all fakes created through the sandbox 33 | ctx.restore() 34 | }) 35 | describe('checkIPFS', () => { 36 | it('should fulfilled if env is not loaded', () => { 37 | process.env.BLACKLIST_URL = '' 38 | expect(Blacklist.checkIPFS(ipfs), 'expect isBlacklisted to be false').be 39 | .fulfilled 40 | expect(axiosGet.called, 'expect axios.get have not been called').to.be 41 | .false 42 | }) 43 | 44 | it('should throw 403 if ipfs is blacklisted', () => { 45 | expect( 46 | Blacklist.checkIPFS(ipfs), 47 | `expect IPFS ${ipfs} is blacklisted exception` 48 | ).be.rejectedWith(`IPFS ${ipfs} is blacklisted`) 49 | expect(axiosGet.called, 'expect axios.get have been called').to.be.true 50 | }) 51 | 52 | it('should fulfilled if ipfs it not blacklisted', () => { 53 | axiosGet.callsFake( 54 | () => 55 | new Promise(resolve => 56 | resolve({ 57 | data: { 58 | blacklisted: false 59 | } 60 | }) 61 | ) 62 | ) 63 | expect(Blacklist.checkIPFS(ipfs), 'expect isBlacklisted to be false').be 64 | .fulfilled 65 | expect(axiosGet.called, 'expect axios.get have not been called').to.be 66 | .true 67 | }) 68 | }) 69 | 70 | describe('checkParcel', () => { 71 | it('should fulfilled if env is not loaded', () => { 72 | process.env.BLACKLIST_URL = '' 73 | expect(Blacklist.checkParcel(x, y), 'expect isBlacklisted to be false').be 74 | .fulfilled 75 | expect(axiosGet.called, 'expect axios.get have not been called').to.be 76 | .false 77 | }) 78 | 79 | it('should throw 403 if parcel is blacklisted', () => { 80 | expect( 81 | Blacklist.checkParcel(x, y), 82 | `expect IPFS ${ipfs} is blacklisted exception` 83 | ).be.rejectedWith(`Parcel (${x},${y}) is blacklisted`) 84 | expect(axiosGet.called, 'expect axios.get have been called').to.be.true 85 | }) 86 | 87 | it('should fulfilled if parcel it not blacklisted', () => { 88 | axiosGet.callsFake( 89 | () => 90 | new Promise(resolve => 91 | resolve({ 92 | data: { 93 | blacklisted: false 94 | } 95 | }) 96 | ) 97 | ) 98 | expect(Blacklist.checkParcel(x, y), 'expect isBlacklisted to be false').be 99 | .fulfilled 100 | expect(axiosGet.called, 'expect axios.get have not been called').to.be 101 | .true 102 | }) 103 | }) 104 | }) 105 | -------------------------------------------------------------------------------- /test/ethereum.spec.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const chaiAsPromised = require('chai-as-promised') 3 | const { sandbox } = require('sinon') 4 | const { eth, contracts } = require('decentraland-eth') 5 | const Ethereum = require('../src/ethereum') 6 | 7 | const web3Eth = eth 8 | const { LANDRegistry } = contracts 9 | 10 | chai.use(chaiAsPromised) 11 | 12 | const ctx = sandbox.create() 13 | const x = 1 14 | const y = 1 15 | const ipns = 'IPNS' 16 | const expect = chai.expect 17 | let decodeLandData 18 | 19 | describe('Ethereum', () => { 20 | beforeEach(() => { 21 | process.env.BLACKLIST_URL = 'http://blacklist.com/api' 22 | getContracts = ctx.stub(web3Eth, 'getContract').callsFake(() => ({ 23 | landData: () => 'metadata' 24 | })) 25 | decodeLandData = ctx 26 | .stub(LANDRegistry, 'decodeLandData') 27 | .callsFake(() => ({ ipns: `ipns:${ipns}` })) 28 | }) 29 | 30 | afterEach(() => { 31 | // completely restore all fakes created through the sandbox 32 | ctx.restore() 33 | }) 34 | describe('connectBlockchain', () => { 35 | it('should connect', async () => { 36 | process.env.RPC_URL = 'https://ropsten.infura.io/' 37 | expect(Ethereum.connectBlockchain(), `expect connectBlockchain`).to.be.fulfilled 38 | }) 39 | 40 | it('should retry to connect', async () => { 41 | const web3Connect = ctx.stub(web3Eth, 'connect') 42 | process.env.RPC_URL = '' 43 | Ethereum.connectBlockchain() 44 | process.env.RPC_URL = 'https://ropsten.infura.io/' 45 | await new Promise(r => 46 | setTimeout(() => { 47 | expect( 48 | web3Connect.calledTwice, 49 | `expect web3Eth.connect to be called twice` 50 | ).be.true 51 | r() 52 | }, 4000) 53 | ) 54 | }) 55 | }) 56 | describe('getIPNS', () => { 57 | it('should return IPNS from parcel', async () => { 58 | const res = await Ethereum.getIPNS(x, y) 59 | expect(res, `expect response to be equal to ${ipns}`).to.be.equal(ipns) 60 | }) 61 | 62 | it('should return IPNS not found if parcel has not IPNS', async () => { 63 | decodeLandData.callsFake(() => '') 64 | expect( 65 | Ethereum.getIPNS(x, y), 66 | `expect IPNS not found exception` 67 | ).be.rejectedWith(`IPNS not found`) 68 | }) 69 | }) 70 | }) 71 | -------------------------------------------------------------------------------- /test/ipfs.spec.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai') 2 | const chaiAsPromised = require('chai-as-promised') 3 | const chaiHttp = require('chai-http') 4 | const fs = require('fs') 5 | const axios = require('axios') 6 | const execFile = require('child_process').execFile 7 | const { sandbox } = require('sinon') 8 | const DB = require('../src/database') 9 | const Ethereum = require('../src/ethereum') 10 | const Blacklist = require('../src/blacklist') 11 | const server = require('../src/server') 12 | const IPFS = require('../src/ipfs') 13 | 14 | chai.use(chaiAsPromised) 15 | chai.use(chaiHttp) 16 | process.env.BLACKLIST_URL = 'http://blacklist.com/api' 17 | 18 | const ctx = sandbox.create() 19 | const expect = chai.expect 20 | const x = 1 21 | const y = 1 22 | let ipfs 23 | let ipns 24 | let url 25 | let getIPNS 26 | let connectPeer 27 | let checkParcel 28 | let checkIPFS 29 | let getParcel 30 | let setParcel 31 | 32 | const addFile = () => { 33 | fs.writeFileSync('test/test.txt', 'I am using for testing!') 34 | return new Promise((resolve, reject) => { 35 | execFile( 36 | 'ipfs', 37 | ['add', '-r', `${process.cwd()}/test/test.txt`], 38 | (err, stdout, stderr) => { 39 | if (err) return reject(new Error(`Can not add the file: ${stderr}`)) 40 | return resolve(stdout.split(' ')[1]) 41 | } 42 | ) 43 | }) 44 | } 45 | 46 | const publishFile = () => { 47 | return new Promise((resolve, reject) => { 48 | execFile('ipfs', ['name', 'publish', `${ipfs}`], (err, stdout, stderr) => { 49 | if (err) return reject(new Error(`Can not publish ${ipfs}: ${stderr}`)) 50 | return resolve(stdout.split(' ')[2].slice(0, -1)) 51 | }) 52 | }) 53 | } 54 | 55 | const removeFile = () => { 56 | fs.unlinkSync('test/test.txt') 57 | return new Promise((resolve, reject) => { 58 | execFile('ipfs', ['pin', 'rm', `${ipfs}`], (err, stdout, stderr) => { 59 | if (err) return reject(new Error(`Can not remove the file: ${stderr}`)) 60 | return resolve() 61 | }) 62 | }) 63 | } 64 | 65 | describe('IPFS', () => { 66 | beforeEach(async () => { 67 | ipfs = await addFile() 68 | ipns = await publishFile() 69 | url = { 70 | ipns, 71 | ipfs, 72 | dependencies: [] 73 | } 74 | getIPNS = ctx.stub(Ethereum, 'getIPNS').callsFake(() => ipns) 75 | checkParcel = ctx.stub(Blacklist, 'checkParcel').callsFake(() => true) 76 | checkIPFS = ctx.stub(Blacklist, 'checkIPFS').callsFake(() => true) 77 | connectPeer = ctx.stub(IPFS, 'connectPeer').callsFake(() => true) 78 | ctx.stub(DB, 'setIPFS').callsFake(() => true) 79 | setParcel = ctx.stub(DB, 'setParcel').callsFake(() => true) 80 | ctx.stub(DB, 'getIPFS').callsFake(() => null) 81 | getParcel = ctx.stub(DB, 'getParcel').callsFake(() => null) 82 | ctx.stub(axios, 'get').callsFake( 83 | () => 84 | new Promise(resolve => 85 | resolve({ 86 | data: { 87 | blacklisted: true 88 | } 89 | }) 90 | ) 91 | ) 92 | }) 93 | 94 | afterEach(async () => { 95 | // completely restore all fakes created through the sanDBox 96 | ctx.restore() 97 | await removeFile() 98 | }) 99 | describe('Pin', () => { 100 | it('should pin files', async () => { 101 | const resExpected = JSON.stringify({ 102 | ok: true, 103 | message: 'Pinning Success' 104 | }) 105 | const res = await chai.request(server).post(`/api/pin/peerId/${x}/${y}`) 106 | expect(res.status, 'Expect status 200').to.be.equal(200) 107 | expect( 108 | JSON.stringify(res.body), 109 | 'Expect body to pinning success' 110 | ).to.be.equal(resExpected) 111 | }) 112 | 113 | it('should not pin files because peer is down', async () => { 114 | connectPeer.restore() 115 | const resExpected = JSON.stringify({ 116 | error: 'Could not connect to peer: peerId' 117 | }) 118 | const res = await chai.request(server).post(`/api/pin/peerId/${x}/${y}`) 119 | expect( 120 | res.status, 121 | 'Expect status 500: could not connect to peer' 122 | ).to.be.equal(500) 123 | expect( 124 | JSON.stringify(res.body), 125 | 'Expect body to be could not resolve name' 126 | ).to.be.equal(resExpected) 127 | }) 128 | 129 | it('should not pin files because IPNS does not exist', async () => { 130 | getIPNS.callsFake(() => null) 131 | const resExpected = JSON.stringify({ 132 | error: 'Error: Could not resolve name.\n' 133 | }) 134 | const res = await chai.request(server).post(`/api/pin/peerId/${x}/${y}`) 135 | expect( 136 | res.status, 137 | 'Expect status 500: could not resolve name' 138 | ).to.be.equal(500) 139 | expect( 140 | JSON.stringify(res.body), 141 | 'Expect body to be could not resolve name' 142 | ).to.be.equal(resExpected) 143 | }) 144 | 145 | it('should not pin files because parcel has not IPNS', async () => { 146 | getIPNS.restore() 147 | const resExpected = JSON.stringify({ error: 'IPNS not found' }) 148 | const res = await chai.request(server).post(`/api/pin/peerId/${x}/${y}`) 149 | expect(res.status, 'Expect status 404').to.be.equal(404) 150 | expect( 151 | JSON.stringify(res.body), 152 | 'Expect body to be IPNS not found' 153 | ).to.be.equal(resExpected) 154 | }) 155 | }) 156 | 157 | describe('Resolve', () => { 158 | it('should resolve without cache', async () => { 159 | const resExpected = JSON.stringify({ ok: true, url }) 160 | const res = await chai.request(server).get(`/api/resolve/${x}/${y}`) 161 | expect(res.status, 'Expect status 200').to.be.equal(200) 162 | expect(getParcel.called, 'Expect getParcel to be called').to.be.true 163 | expect(setParcel.called, 'Expect setParcel to be called').to.be.true 164 | expect( 165 | JSON.stringify(res.body), 166 | 'Expect body to have the ipfs data' 167 | ).to.be.equal(resExpected) 168 | }) 169 | 170 | it('should resolve with cache', async () => { 171 | getParcel.callsFake(() => url) 172 | const resExpected = JSON.stringify({ ok: true, url }) 173 | const res = await chai.request(server).get(`/api/resolve/${x}/${y}`) 174 | expect(res.status, 'Expect status 200').to.be.equal(200) 175 | expect(getParcel.called, 'Expect getParcel to be called').to.be.true 176 | expect(setParcel.called, 'Expect setParcel not to be called').to.be.false 177 | expect( 178 | JSON.stringify(res.body), 179 | 'Expect body to have the ipfs data' 180 | ).to.be.equal(resExpected) 181 | }) 182 | 183 | it('should resolve without cache when is forced', async () => { 184 | getParcel.callsFake(() => url) 185 | const resExpected = JSON.stringify({ ok: true, url }) 186 | const res = await chai 187 | .request(server) 188 | .get(`/api/resolve/${x}/${y}?force=true`) 189 | expect(res.status, 'Expect status 200').to.be.equal(200) 190 | expect(getParcel.called, 'Expect getParcel not to be called').to.be.false 191 | expect(setParcel.called, 'Expect setParcel to be called').to.be.true 192 | expect( 193 | JSON.stringify(res.body), 194 | 'Expect body to have the ipfs data' 195 | ).to.be.equal(resExpected) 196 | }) 197 | 198 | it('should not check if IPNS is blacklisted', async () => { 199 | checkParcel.restore() 200 | getParcel.callsFake(() => url) 201 | const resExpected = JSON.stringify({ ok: true, url }) 202 | const res = await chai 203 | .request(server) 204 | .get(`/api/resolve/${x}/${y}?force=true`) 205 | expect( 206 | res.status, 207 | 'Expect status 200: unless parcel is blacklisted' 208 | ).to.be.equal(200) 209 | expect(checkParcel.called, 'Expect checkParcel not to be called').to.be 210 | .false 211 | expect( 212 | JSON.stringify(res.body), 213 | `Expect body to have the ipfs data` 214 | ).to.be.equal(resExpected) 215 | }) 216 | 217 | it('should not resolve because IPNS is blacklisted', async () => { 218 | checkParcel.restore() 219 | const resExpected = JSON.stringify({ 220 | error: `Parcel (${x},${y}) is blacklisted` 221 | }) 222 | const res = await chai.request(server).get(`/api/resolve/${x}/${y}`) 223 | expect( 224 | res.status, 225 | 'Expect status 403: parcel is blacklisted' 226 | ).to.be.equal(403) 227 | expect( 228 | JSON.stringify(res.body), 229 | `Expect body to be Parcel (${x},${y}) is blacklisted` 230 | ).to.be.equal(resExpected) 231 | }) 232 | 233 | it('should not resolve because IPNS not found', async () => { 234 | getIPNS.restore() 235 | const resExpected = JSON.stringify({ error: 'IPNS not found' }) 236 | const res = await chai.request(server).get(`/api/resolve/${x}/${y}`) 237 | expect(res.status, 'Expect status 404').to.be.equal(404) 238 | expect( 239 | JSON.stringify(res.body), 240 | 'Expect body to be IPNS not found' 241 | ).to.be.equal(resExpected) 242 | }) 243 | }) 244 | 245 | describe('Download', () => { 246 | it('should download', async () => { 247 | const resExpected = '"I am using for testing!"' 248 | const res = await chai.request(server).get(`/api/get/${ipfs}`) 249 | expect(res.status, 'Expect status 200').to.be.equal(200) 250 | expect( 251 | JSON.stringify(res.text), 252 | `Expect body to be the file content` 253 | ).to.be.equal(resExpected) 254 | }) 255 | 256 | it('should not download because hash is blacklisted', async () => { 257 | checkIPFS.restore() 258 | const resExpected = JSON.stringify({ 259 | error: `IPFS ${ipfs} is blacklisted` 260 | }) 261 | const res = await chai.request(server).get(`/api/get/${ipfs}`) 262 | expect(res.status, 'Expect status 403: IPFS is blacklisted').to.be.equal( 263 | 403 264 | ) 265 | expect( 266 | JSON.stringify(res.body), 267 | `Expect body to be IPFS ${ipfs} is blacklisted` 268 | ).to.be.equal(resExpected) 269 | }) 270 | }) 271 | }) 272 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.4: 6 | version "1.3.4" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" 8 | dependencies: 9 | mime-types "~2.1.16" 10 | negotiator "0.6.1" 11 | 12 | acorn-jsx@^3.0.0: 13 | version "3.0.1" 14 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" 15 | dependencies: 16 | acorn "^3.0.4" 17 | 18 | acorn@^3.0.4: 19 | version "3.3.0" 20 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" 21 | 22 | acorn@^5.1.1: 23 | version "5.1.2" 24 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" 25 | 26 | ajv-keywords@^1.0.0: 27 | version "1.5.1" 28 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" 29 | 30 | ajv@^4.7.0: 31 | version "4.11.8" 32 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 33 | dependencies: 34 | co "^4.6.0" 35 | json-stable-stringify "^1.0.1" 36 | 37 | ansi-escapes@^1.1.0: 38 | version "1.4.0" 39 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" 40 | 41 | ansi-regex@^2.0.0: 42 | version "2.1.1" 43 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 44 | 45 | ansi-regex@^3.0.0: 46 | version "3.0.0" 47 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 48 | 49 | ansi-styles@^2.2.1: 50 | version "2.2.1" 51 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 52 | 53 | argparse@^1.0.7: 54 | version "1.0.9" 55 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 56 | dependencies: 57 | sprintf-js "~1.0.2" 58 | 59 | array-flatten@1.1.1: 60 | version "1.1.1" 61 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 62 | 63 | array-union@^1.0.1: 64 | version "1.0.2" 65 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 66 | dependencies: 67 | array-uniq "^1.0.1" 68 | 69 | array-uniq@^1.0.1: 70 | version "1.0.3" 71 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 72 | 73 | array.prototype.find@^2.0.1: 74 | version "2.0.4" 75 | resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" 76 | dependencies: 77 | define-properties "^1.1.2" 78 | es-abstract "^1.7.0" 79 | 80 | arrify@^1.0.0: 81 | version "1.0.1" 82 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 83 | 84 | babel-code-frame@^6.16.0: 85 | version "6.26.0" 86 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" 87 | dependencies: 88 | chalk "^1.1.3" 89 | esutils "^2.0.2" 90 | js-tokens "^3.0.2" 91 | 92 | balanced-match@^1.0.0: 93 | version "1.0.0" 94 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 95 | 96 | body-parser@1.18.2, body-parser@^1.18.2: 97 | version "1.18.2" 98 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.2.tgz#87678a19d84b47d859b83199bd59bce222b10454" 99 | dependencies: 100 | bytes "3.0.0" 101 | content-type "~1.0.4" 102 | debug "2.6.9" 103 | depd "~1.1.1" 104 | http-errors "~1.6.2" 105 | iconv-lite "0.4.19" 106 | on-finished "~2.3.0" 107 | qs "6.5.1" 108 | raw-body "2.3.2" 109 | type-is "~1.6.15" 110 | 111 | brace-expansion@^1.1.7: 112 | version "1.1.8" 113 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 114 | dependencies: 115 | balanced-match "^1.0.0" 116 | concat-map "0.0.1" 117 | 118 | builtin-modules@^1.1.1: 119 | version "1.1.1" 120 | resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" 121 | 122 | bytes@3.0.0: 123 | version "3.0.0" 124 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 125 | 126 | caller-path@^0.1.0: 127 | version "0.1.0" 128 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" 129 | dependencies: 130 | callsites "^0.2.0" 131 | 132 | callsites@^0.2.0: 133 | version "0.2.0" 134 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" 135 | 136 | chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: 137 | version "1.1.3" 138 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 139 | dependencies: 140 | ansi-styles "^2.2.1" 141 | escape-string-regexp "^1.0.2" 142 | has-ansi "^2.0.0" 143 | strip-ansi "^3.0.0" 144 | supports-color "^2.0.0" 145 | 146 | circular-json@^0.3.1: 147 | version "0.3.3" 148 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" 149 | 150 | cli-cursor@^1.0.1: 151 | version "1.0.2" 152 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" 153 | dependencies: 154 | restore-cursor "^1.0.1" 155 | 156 | cli-width@^2.0.0: 157 | version "2.2.0" 158 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" 159 | 160 | co@^4.6.0: 161 | version "4.6.0" 162 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 163 | 164 | code-point-at@^1.0.0: 165 | version "1.1.0" 166 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 167 | 168 | concat-map@0.0.1: 169 | version "0.0.1" 170 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 171 | 172 | concat-stream@^1.5.2: 173 | version "1.6.0" 174 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" 175 | dependencies: 176 | inherits "^2.0.3" 177 | readable-stream "^2.2.2" 178 | typedarray "^0.0.6" 179 | 180 | contains-path@^0.1.0: 181 | version "0.1.0" 182 | resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" 183 | 184 | content-disposition@0.5.2: 185 | version "0.5.2" 186 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 187 | 188 | content-type@~1.0.4: 189 | version "1.0.4" 190 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 191 | 192 | cookie-signature@1.0.6: 193 | version "1.0.6" 194 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 195 | 196 | cookie@0.3.1: 197 | version "0.3.1" 198 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 199 | 200 | core-util-is@~1.0.0: 201 | version "1.0.2" 202 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 203 | 204 | cors@^2.8.4: 205 | version "2.8.4" 206 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.4.tgz#2bd381f2eb201020105cd50ea59da63090694686" 207 | dependencies: 208 | object-assign "^4" 209 | vary "^1" 210 | 211 | crypto-random-string@^1.0.0: 212 | version "1.0.0" 213 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" 214 | 215 | d@1: 216 | version "1.0.0" 217 | resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" 218 | dependencies: 219 | es5-ext "^0.10.9" 220 | 221 | debug-log@^1.0.0: 222 | version "1.0.1" 223 | resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" 224 | 225 | debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.8: 226 | version "2.6.9" 227 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 228 | dependencies: 229 | ms "2.0.0" 230 | 231 | deep-equal@~1.0.1: 232 | version "1.0.1" 233 | resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" 234 | 235 | deep-is@~0.1.3: 236 | version "0.1.3" 237 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 238 | 239 | define-properties@^1.1.2: 240 | version "1.1.2" 241 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" 242 | dependencies: 243 | foreach "^2.0.5" 244 | object-keys "^1.0.8" 245 | 246 | defined@~1.0.0: 247 | version "1.0.0" 248 | resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" 249 | 250 | deglob@^2.1.0: 251 | version "2.1.0" 252 | resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.0.tgz#4d44abe16ef32c779b4972bd141a80325029a14a" 253 | dependencies: 254 | find-root "^1.0.0" 255 | glob "^7.0.5" 256 | ignore "^3.0.9" 257 | pkg-config "^1.1.0" 258 | run-parallel "^1.1.2" 259 | uniq "^1.0.1" 260 | 261 | del@^2.0.2: 262 | version "2.2.2" 263 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" 264 | dependencies: 265 | globby "^5.0.0" 266 | is-path-cwd "^1.0.0" 267 | is-path-in-cwd "^1.0.0" 268 | object-assign "^4.0.1" 269 | pify "^2.0.0" 270 | pinkie-promise "^2.0.0" 271 | rimraf "^2.2.8" 272 | 273 | depd@1.1.1, depd@~1.1.1: 274 | version "1.1.1" 275 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 276 | 277 | destroy@~1.0.4: 278 | version "1.0.4" 279 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 280 | 281 | doctrine@1.5.0, doctrine@^1.2.2: 282 | version "1.5.0" 283 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" 284 | dependencies: 285 | esutils "^2.0.2" 286 | isarray "^1.0.0" 287 | 288 | doctrine@^2.0.0: 289 | version "2.0.0" 290 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" 291 | dependencies: 292 | esutils "^2.0.2" 293 | isarray "^1.0.0" 294 | 295 | ee-first@1.1.1: 296 | version "1.1.1" 297 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 298 | 299 | encodeurl@~1.0.1: 300 | version "1.0.1" 301 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" 302 | 303 | error-ex@^1.2.0: 304 | version "1.3.1" 305 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" 306 | dependencies: 307 | is-arrayish "^0.2.1" 308 | 309 | es-abstract@^1.5.0, es-abstract@^1.7.0: 310 | version "1.9.0" 311 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" 312 | dependencies: 313 | es-to-primitive "^1.1.1" 314 | function-bind "^1.1.1" 315 | has "^1.0.1" 316 | is-callable "^1.1.3" 317 | is-regex "^1.0.4" 318 | 319 | es-to-primitive@^1.1.1: 320 | version "1.1.1" 321 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" 322 | dependencies: 323 | is-callable "^1.1.1" 324 | is-date-object "^1.0.1" 325 | is-symbol "^1.0.1" 326 | 327 | es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: 328 | version "0.10.35" 329 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.35.tgz#18ee858ce6a3c45c7d79e91c15fcca9ec568494f" 330 | dependencies: 331 | es6-iterator "~2.0.1" 332 | es6-symbol "~3.1.1" 333 | 334 | es6-iterator@^2.0.1, es6-iterator@~2.0.1: 335 | version "2.0.3" 336 | resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" 337 | dependencies: 338 | d "1" 339 | es5-ext "^0.10.35" 340 | es6-symbol "^3.1.1" 341 | 342 | es6-map@^0.1.3: 343 | version "0.1.5" 344 | resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" 345 | dependencies: 346 | d "1" 347 | es5-ext "~0.10.14" 348 | es6-iterator "~2.0.1" 349 | es6-set "~0.1.5" 350 | es6-symbol "~3.1.1" 351 | event-emitter "~0.3.5" 352 | 353 | es6-set@~0.1.5: 354 | version "0.1.5" 355 | resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" 356 | dependencies: 357 | d "1" 358 | es5-ext "~0.10.14" 359 | es6-iterator "~2.0.1" 360 | es6-symbol "3.1.1" 361 | event-emitter "~0.3.5" 362 | 363 | es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: 364 | version "3.1.1" 365 | resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" 366 | dependencies: 367 | d "1" 368 | es5-ext "~0.10.14" 369 | 370 | es6-weak-map@^2.0.1: 371 | version "2.0.2" 372 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" 373 | dependencies: 374 | d "1" 375 | es5-ext "^0.10.14" 376 | es6-iterator "^2.0.1" 377 | es6-symbol "^3.1.1" 378 | 379 | escape-html@~1.0.3: 380 | version "1.0.3" 381 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 382 | 383 | escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 384 | version "1.0.5" 385 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 386 | 387 | escope@^3.6.0: 388 | version "3.6.0" 389 | resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" 390 | dependencies: 391 | es6-map "^0.1.3" 392 | es6-weak-map "^2.0.1" 393 | esrecurse "^4.1.0" 394 | estraverse "^4.1.1" 395 | 396 | eslint-config-standard-jsx@4.0.2: 397 | version "4.0.2" 398 | resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz#009e53c4ddb1e9ee70b4650ffe63a7f39f8836e1" 399 | 400 | eslint-config-standard@10.2.1: 401 | version "10.2.1" 402 | resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" 403 | 404 | eslint-import-resolver-node@^0.2.0: 405 | version "0.2.3" 406 | resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" 407 | dependencies: 408 | debug "^2.2.0" 409 | object-assign "^4.0.1" 410 | resolve "^1.1.6" 411 | 412 | eslint-module-utils@^2.0.0: 413 | version "2.1.1" 414 | resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" 415 | dependencies: 416 | debug "^2.6.8" 417 | pkg-dir "^1.0.0" 418 | 419 | eslint-plugin-import@~2.2.0: 420 | version "2.2.0" 421 | resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" 422 | dependencies: 423 | builtin-modules "^1.1.1" 424 | contains-path "^0.1.0" 425 | debug "^2.2.0" 426 | doctrine "1.5.0" 427 | eslint-import-resolver-node "^0.2.0" 428 | eslint-module-utils "^2.0.0" 429 | has "^1.0.1" 430 | lodash.cond "^4.3.0" 431 | minimatch "^3.0.3" 432 | pkg-up "^1.0.0" 433 | 434 | eslint-plugin-node@~4.2.2: 435 | version "4.2.3" 436 | resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz#c04390ab8dbcbb6887174023d6f3a72769e63b97" 437 | dependencies: 438 | ignore "^3.0.11" 439 | minimatch "^3.0.2" 440 | object-assign "^4.0.1" 441 | resolve "^1.1.7" 442 | semver "5.3.0" 443 | 444 | eslint-plugin-promise@~3.5.0: 445 | version "3.5.0" 446 | resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" 447 | 448 | eslint-plugin-react@~6.10.0: 449 | version "6.10.3" 450 | resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78" 451 | dependencies: 452 | array.prototype.find "^2.0.1" 453 | doctrine "^1.2.2" 454 | has "^1.0.1" 455 | jsx-ast-utils "^1.3.4" 456 | object.assign "^4.0.4" 457 | 458 | eslint-plugin-standard@~3.0.1: 459 | version "3.0.1" 460 | resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" 461 | 462 | eslint@~3.19.0: 463 | version "3.19.0" 464 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" 465 | dependencies: 466 | babel-code-frame "^6.16.0" 467 | chalk "^1.1.3" 468 | concat-stream "^1.5.2" 469 | debug "^2.1.1" 470 | doctrine "^2.0.0" 471 | escope "^3.6.0" 472 | espree "^3.4.0" 473 | esquery "^1.0.0" 474 | estraverse "^4.2.0" 475 | esutils "^2.0.2" 476 | file-entry-cache "^2.0.0" 477 | glob "^7.0.3" 478 | globals "^9.14.0" 479 | ignore "^3.2.0" 480 | imurmurhash "^0.1.4" 481 | inquirer "^0.12.0" 482 | is-my-json-valid "^2.10.0" 483 | is-resolvable "^1.0.0" 484 | js-yaml "^3.5.1" 485 | json-stable-stringify "^1.0.0" 486 | levn "^0.3.0" 487 | lodash "^4.0.0" 488 | mkdirp "^0.5.0" 489 | natural-compare "^1.4.0" 490 | optionator "^0.8.2" 491 | path-is-inside "^1.0.1" 492 | pluralize "^1.2.1" 493 | progress "^1.1.8" 494 | require-uncached "^1.0.2" 495 | shelljs "^0.7.5" 496 | strip-bom "^3.0.0" 497 | strip-json-comments "~2.0.1" 498 | table "^3.7.8" 499 | text-table "~0.2.0" 500 | user-home "^2.0.0" 501 | 502 | espree@^3.4.0: 503 | version "3.5.1" 504 | resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" 505 | dependencies: 506 | acorn "^5.1.1" 507 | acorn-jsx "^3.0.0" 508 | 509 | esprima@^4.0.0: 510 | version "4.0.0" 511 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" 512 | 513 | esquery@^1.0.0: 514 | version "1.0.0" 515 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" 516 | dependencies: 517 | estraverse "^4.0.0" 518 | 519 | esrecurse@^4.1.0: 520 | version "4.2.0" 521 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" 522 | dependencies: 523 | estraverse "^4.1.0" 524 | object-assign "^4.0.1" 525 | 526 | estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: 527 | version "4.2.0" 528 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 529 | 530 | esutils@^2.0.2: 531 | version "2.0.2" 532 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 533 | 534 | etag@~1.8.1: 535 | version "1.8.1" 536 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 537 | 538 | event-emitter@~0.3.5: 539 | version "0.3.5" 540 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" 541 | dependencies: 542 | d "1" 543 | es5-ext "~0.10.14" 544 | 545 | exit-hook@^1.0.0: 546 | version "1.1.1" 547 | resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" 548 | 549 | express@^4.16.2: 550 | version "4.16.2" 551 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" 552 | dependencies: 553 | accepts "~1.3.4" 554 | array-flatten "1.1.1" 555 | body-parser "1.18.2" 556 | content-disposition "0.5.2" 557 | content-type "~1.0.4" 558 | cookie "0.3.1" 559 | cookie-signature "1.0.6" 560 | debug "2.6.9" 561 | depd "~1.1.1" 562 | encodeurl "~1.0.1" 563 | escape-html "~1.0.3" 564 | etag "~1.8.1" 565 | finalhandler "1.1.0" 566 | fresh "0.5.2" 567 | merge-descriptors "1.0.1" 568 | methods "~1.1.2" 569 | on-finished "~2.3.0" 570 | parseurl "~1.3.2" 571 | path-to-regexp "0.1.7" 572 | proxy-addr "~2.0.2" 573 | qs "6.5.1" 574 | range-parser "~1.2.0" 575 | safe-buffer "5.1.1" 576 | send "0.16.1" 577 | serve-static "1.13.1" 578 | setprototypeof "1.1.0" 579 | statuses "~1.3.1" 580 | type-is "~1.6.15" 581 | utils-merge "1.0.1" 582 | vary "~1.1.2" 583 | 584 | fast-levenshtein@~2.0.4: 585 | version "2.0.6" 586 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 587 | 588 | figures@^1.3.5: 589 | version "1.7.0" 590 | resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" 591 | dependencies: 592 | escape-string-regexp "^1.0.5" 593 | object-assign "^4.1.0" 594 | 595 | file-entry-cache@^2.0.0: 596 | version "2.0.0" 597 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" 598 | dependencies: 599 | flat-cache "^1.2.1" 600 | object-assign "^4.0.1" 601 | 602 | finalhandler@1.1.0: 603 | version "1.1.0" 604 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" 605 | dependencies: 606 | debug "2.6.9" 607 | encodeurl "~1.0.1" 608 | escape-html "~1.0.3" 609 | on-finished "~2.3.0" 610 | parseurl "~1.3.2" 611 | statuses "~1.3.1" 612 | unpipe "~1.0.0" 613 | 614 | find-root@^1.0.0: 615 | version "1.1.0" 616 | resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" 617 | 618 | find-up@^1.0.0: 619 | version "1.1.2" 620 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 621 | dependencies: 622 | path-exists "^2.0.0" 623 | pinkie-promise "^2.0.0" 624 | 625 | find-up@^2.0.0: 626 | version "2.1.0" 627 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" 628 | dependencies: 629 | locate-path "^2.0.0" 630 | 631 | flat-cache@^1.2.1: 632 | version "1.3.0" 633 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" 634 | dependencies: 635 | circular-json "^0.3.1" 636 | del "^2.0.2" 637 | graceful-fs "^4.1.2" 638 | write "^0.2.1" 639 | 640 | for-each@~0.3.2: 641 | version "0.3.2" 642 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" 643 | dependencies: 644 | is-function "~1.0.0" 645 | 646 | foreach@^2.0.5: 647 | version "2.0.5" 648 | resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" 649 | 650 | forwarded@~0.1.2: 651 | version "0.1.2" 652 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 653 | 654 | fresh@0.5.2: 655 | version "0.5.2" 656 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 657 | 658 | fs.realpath@^1.0.0: 659 | version "1.0.0" 660 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 661 | 662 | function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1, function-bind@~1.1.0: 663 | version "1.1.1" 664 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 665 | 666 | generate-function@^2.0.0: 667 | version "2.0.0" 668 | resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" 669 | 670 | generate-object-property@^1.1.0: 671 | version "1.2.0" 672 | resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" 673 | dependencies: 674 | is-property "^1.0.0" 675 | 676 | get-stdin@^5.0.1: 677 | version "5.0.1" 678 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" 679 | 680 | glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.2: 681 | version "7.1.2" 682 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 683 | dependencies: 684 | fs.realpath "^1.0.0" 685 | inflight "^1.0.4" 686 | inherits "2" 687 | minimatch "^3.0.4" 688 | once "^1.3.0" 689 | path-is-absolute "^1.0.0" 690 | 691 | globals@^9.14.0: 692 | version "9.18.0" 693 | resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" 694 | 695 | globby@^5.0.0: 696 | version "5.0.0" 697 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" 698 | dependencies: 699 | array-union "^1.0.1" 700 | arrify "^1.0.0" 701 | glob "^7.0.3" 702 | object-assign "^4.0.1" 703 | pify "^2.0.0" 704 | pinkie-promise "^2.0.0" 705 | 706 | graceful-fs@^4.1.2: 707 | version "4.1.11" 708 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 709 | 710 | has-ansi@^2.0.0: 711 | version "2.0.0" 712 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 713 | dependencies: 714 | ansi-regex "^2.0.0" 715 | 716 | has@^1.0.1, has@~1.0.1: 717 | version "1.0.1" 718 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" 719 | dependencies: 720 | function-bind "^1.0.2" 721 | 722 | http-errors@1.6.2, http-errors@~1.6.2: 723 | version "1.6.2" 724 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 725 | dependencies: 726 | depd "1.1.1" 727 | inherits "2.0.3" 728 | setprototypeof "1.0.3" 729 | statuses ">= 1.3.1 < 2" 730 | 731 | iconv-lite@0.4.19: 732 | version "0.4.19" 733 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" 734 | 735 | ignore@^3.0.11, ignore@^3.0.9, ignore@^3.2.0: 736 | version "3.3.6" 737 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.6.tgz#b6f3196b38ed92f0c86e52f6f79b7fc4c8266c8d" 738 | 739 | imurmurhash@^0.1.4: 740 | version "0.1.4" 741 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 742 | 743 | inflight@^1.0.4: 744 | version "1.0.6" 745 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 746 | dependencies: 747 | once "^1.3.0" 748 | wrappy "1" 749 | 750 | inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.3: 751 | version "2.0.3" 752 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 753 | 754 | inquirer@^0.12.0: 755 | version "0.12.0" 756 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" 757 | dependencies: 758 | ansi-escapes "^1.1.0" 759 | ansi-regex "^2.0.0" 760 | chalk "^1.0.0" 761 | cli-cursor "^1.0.1" 762 | cli-width "^2.0.0" 763 | figures "^1.3.5" 764 | lodash "^4.3.0" 765 | readline2 "^1.0.1" 766 | run-async "^0.1.0" 767 | rx-lite "^3.1.2" 768 | string-width "^1.0.1" 769 | strip-ansi "^3.0.0" 770 | through "^2.3.6" 771 | 772 | interpret@^1.0.0: 773 | version "1.0.4" 774 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" 775 | 776 | ipaddr.js@1.5.2: 777 | version "1.5.2" 778 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.5.2.tgz#d4b505bde9946987ccf0fc58d9010ff9607e3fa0" 779 | 780 | is-arrayish@^0.2.1: 781 | version "0.2.1" 782 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 783 | 784 | is-callable@^1.1.1, is-callable@^1.1.3: 785 | version "1.1.3" 786 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" 787 | 788 | is-date-object@^1.0.1: 789 | version "1.0.1" 790 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" 791 | 792 | is-fullwidth-code-point@^1.0.0: 793 | version "1.0.0" 794 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 795 | dependencies: 796 | number-is-nan "^1.0.0" 797 | 798 | is-fullwidth-code-point@^2.0.0: 799 | version "2.0.0" 800 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 801 | 802 | is-function@~1.0.0: 803 | version "1.0.1" 804 | resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" 805 | 806 | is-my-json-valid@^2.10.0: 807 | version "2.16.1" 808 | resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" 809 | dependencies: 810 | generate-function "^2.0.0" 811 | generate-object-property "^1.1.0" 812 | jsonpointer "^4.0.0" 813 | xtend "^4.0.0" 814 | 815 | is-path-cwd@^1.0.0: 816 | version "1.0.0" 817 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 818 | 819 | is-path-in-cwd@^1.0.0: 820 | version "1.0.0" 821 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" 822 | dependencies: 823 | is-path-inside "^1.0.0" 824 | 825 | is-path-inside@^1.0.0: 826 | version "1.0.0" 827 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" 828 | dependencies: 829 | path-is-inside "^1.0.1" 830 | 831 | is-property@^1.0.0: 832 | version "1.0.2" 833 | resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" 834 | 835 | is-regex@^1.0.4: 836 | version "1.0.4" 837 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" 838 | dependencies: 839 | has "^1.0.1" 840 | 841 | is-resolvable@^1.0.0: 842 | version "1.0.0" 843 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" 844 | dependencies: 845 | tryit "^1.0.1" 846 | 847 | is-symbol@^1.0.1: 848 | version "1.0.1" 849 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" 850 | 851 | isarray@^1.0.0, isarray@~1.0.0: 852 | version "1.0.0" 853 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 854 | 855 | js-tokens@^3.0.2: 856 | version "3.0.2" 857 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 858 | 859 | js-yaml@^3.5.1: 860 | version "3.10.0" 861 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" 862 | dependencies: 863 | argparse "^1.0.7" 864 | esprima "^4.0.0" 865 | 866 | json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: 867 | version "1.0.1" 868 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 869 | dependencies: 870 | jsonify "~0.0.0" 871 | 872 | jsonify@~0.0.0: 873 | version "0.0.0" 874 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 875 | 876 | jsonpointer@^4.0.0: 877 | version "4.0.1" 878 | resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" 879 | 880 | jsx-ast-utils@^1.3.4: 881 | version "1.4.1" 882 | resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" 883 | 884 | levn@^0.3.0, levn@~0.3.0: 885 | version "0.3.0" 886 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 887 | dependencies: 888 | prelude-ls "~1.1.2" 889 | type-check "~0.3.2" 890 | 891 | load-json-file@^2.0.0: 892 | version "2.0.0" 893 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" 894 | dependencies: 895 | graceful-fs "^4.1.2" 896 | parse-json "^2.2.0" 897 | pify "^2.0.0" 898 | strip-bom "^3.0.0" 899 | 900 | locate-path@^2.0.0: 901 | version "2.0.0" 902 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" 903 | dependencies: 904 | p-locate "^2.0.0" 905 | path-exists "^3.0.0" 906 | 907 | lodash.cond@^4.3.0: 908 | version "4.5.2" 909 | resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" 910 | 911 | lodash@^4.0.0, lodash@^4.3.0: 912 | version "4.17.4" 913 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 914 | 915 | media-typer@0.3.0: 916 | version "0.3.0" 917 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 918 | 919 | merge-descriptors@1.0.1: 920 | version "1.0.1" 921 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 922 | 923 | methods@~1.1.2: 924 | version "1.1.2" 925 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 926 | 927 | mime-db@~1.30.0: 928 | version "1.30.0" 929 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" 930 | 931 | mime-types@~2.1.15, mime-types@~2.1.16: 932 | version "2.1.17" 933 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" 934 | dependencies: 935 | mime-db "~1.30.0" 936 | 937 | mime@1.4.1: 938 | version "1.4.1" 939 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" 940 | 941 | minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: 942 | version "3.0.4" 943 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 944 | dependencies: 945 | brace-expansion "^1.1.7" 946 | 947 | minimist@0.0.8: 948 | version "0.0.8" 949 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 950 | 951 | minimist@^1.1.0, minimist@~1.2.0: 952 | version "1.2.0" 953 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 954 | 955 | mkdirp@^0.5.0, mkdirp@^0.5.1: 956 | version "0.5.1" 957 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 958 | dependencies: 959 | minimist "0.0.8" 960 | 961 | ms@2.0.0: 962 | version "2.0.0" 963 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 964 | 965 | mute-stream@0.0.5: 966 | version "0.0.5" 967 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" 968 | 969 | natural-compare@^1.4.0: 970 | version "1.4.0" 971 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 972 | 973 | negotiator@0.6.1: 974 | version "0.6.1" 975 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 976 | 977 | number-is-nan@^1.0.0: 978 | version "1.0.1" 979 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 980 | 981 | object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0: 982 | version "4.1.1" 983 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 984 | 985 | object-inspect@~1.3.0: 986 | version "1.3.0" 987 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.3.0.tgz#5b1eb8e6742e2ee83342a637034d844928ba2f6d" 988 | 989 | object-keys@^1.0.10, object-keys@^1.0.8: 990 | version "1.0.11" 991 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" 992 | 993 | object.assign@^4.0.4: 994 | version "4.0.4" 995 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" 996 | dependencies: 997 | define-properties "^1.1.2" 998 | function-bind "^1.1.0" 999 | object-keys "^1.0.10" 1000 | 1001 | on-finished@~2.3.0: 1002 | version "2.3.0" 1003 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1004 | dependencies: 1005 | ee-first "1.1.1" 1006 | 1007 | once@^1.3.0: 1008 | version "1.4.0" 1009 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1010 | dependencies: 1011 | wrappy "1" 1012 | 1013 | onetime@^1.0.0: 1014 | version "1.1.0" 1015 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" 1016 | 1017 | optionator@^0.8.2: 1018 | version "0.8.2" 1019 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 1020 | dependencies: 1021 | deep-is "~0.1.3" 1022 | fast-levenshtein "~2.0.4" 1023 | levn "~0.3.0" 1024 | prelude-ls "~1.1.2" 1025 | type-check "~0.3.2" 1026 | wordwrap "~1.0.0" 1027 | 1028 | os-homedir@^1.0.0: 1029 | version "1.0.2" 1030 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 1031 | 1032 | p-limit@^1.1.0: 1033 | version "1.1.0" 1034 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" 1035 | 1036 | p-locate@^2.0.0: 1037 | version "2.0.0" 1038 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" 1039 | dependencies: 1040 | p-limit "^1.1.0" 1041 | 1042 | parse-json@^2.2.0: 1043 | version "2.2.0" 1044 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 1045 | dependencies: 1046 | error-ex "^1.2.0" 1047 | 1048 | parseurl@~1.3.2: 1049 | version "1.3.2" 1050 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" 1051 | 1052 | path-exists@^2.0.0: 1053 | version "2.1.0" 1054 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 1055 | dependencies: 1056 | pinkie-promise "^2.0.0" 1057 | 1058 | path-exists@^3.0.0: 1059 | version "3.0.0" 1060 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 1061 | 1062 | path-is-absolute@^1.0.0: 1063 | version "1.0.1" 1064 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1065 | 1066 | path-is-inside@^1.0.1: 1067 | version "1.0.2" 1068 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 1069 | 1070 | path-parse@^1.0.5: 1071 | version "1.0.5" 1072 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" 1073 | 1074 | path-to-regexp@0.1.7: 1075 | version "0.1.7" 1076 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 1077 | 1078 | pify@^2.0.0: 1079 | version "2.3.0" 1080 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 1081 | 1082 | pinkie-promise@^2.0.0: 1083 | version "2.0.1" 1084 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 1085 | dependencies: 1086 | pinkie "^2.0.0" 1087 | 1088 | pinkie@^2.0.0: 1089 | version "2.0.4" 1090 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 1091 | 1092 | pkg-conf@^2.0.0: 1093 | version "2.0.0" 1094 | resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.0.0.tgz#071c87650403bccfb9c627f58751bfe47c067279" 1095 | dependencies: 1096 | find-up "^2.0.0" 1097 | load-json-file "^2.0.0" 1098 | 1099 | pkg-config@^1.1.0: 1100 | version "1.1.1" 1101 | resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" 1102 | dependencies: 1103 | debug-log "^1.0.0" 1104 | find-root "^1.0.0" 1105 | xtend "^4.0.1" 1106 | 1107 | pkg-dir@^1.0.0: 1108 | version "1.0.0" 1109 | resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" 1110 | dependencies: 1111 | find-up "^1.0.0" 1112 | 1113 | pkg-up@^1.0.0: 1114 | version "1.0.0" 1115 | resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" 1116 | dependencies: 1117 | find-up "^1.0.0" 1118 | 1119 | pluralize@^1.2.1: 1120 | version "1.2.1" 1121 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" 1122 | 1123 | prelude-ls@~1.1.2: 1124 | version "1.1.2" 1125 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 1126 | 1127 | process-nextick-args@~1.0.6: 1128 | version "1.0.7" 1129 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 1130 | 1131 | progress@^1.1.8: 1132 | version "1.1.8" 1133 | resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" 1134 | 1135 | proxy-addr@~2.0.2: 1136 | version "2.0.2" 1137 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec" 1138 | dependencies: 1139 | forwarded "~0.1.2" 1140 | ipaddr.js "1.5.2" 1141 | 1142 | qs@6.5.1: 1143 | version "6.5.1" 1144 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" 1145 | 1146 | range-parser@~1.2.0: 1147 | version "1.2.0" 1148 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 1149 | 1150 | raw-body@2.3.2: 1151 | version "2.3.2" 1152 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" 1153 | dependencies: 1154 | bytes "3.0.0" 1155 | http-errors "1.6.2" 1156 | iconv-lite "0.4.19" 1157 | unpipe "1.0.0" 1158 | 1159 | readable-stream@^2.2.2: 1160 | version "2.3.3" 1161 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" 1162 | dependencies: 1163 | core-util-is "~1.0.0" 1164 | inherits "~2.0.3" 1165 | isarray "~1.0.0" 1166 | process-nextick-args "~1.0.6" 1167 | safe-buffer "~5.1.1" 1168 | string_decoder "~1.0.3" 1169 | util-deprecate "~1.0.1" 1170 | 1171 | readline2@^1.0.1: 1172 | version "1.0.1" 1173 | resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" 1174 | dependencies: 1175 | code-point-at "^1.0.0" 1176 | is-fullwidth-code-point "^1.0.0" 1177 | mute-stream "0.0.5" 1178 | 1179 | rechoir@^0.6.2: 1180 | version "0.6.2" 1181 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 1182 | dependencies: 1183 | resolve "^1.1.6" 1184 | 1185 | require-uncached@^1.0.2: 1186 | version "1.0.3" 1187 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" 1188 | dependencies: 1189 | caller-path "^0.1.0" 1190 | resolve-from "^1.0.0" 1191 | 1192 | resolve-from@^1.0.0: 1193 | version "1.0.1" 1194 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" 1195 | 1196 | resolve@^1.1.6, resolve@^1.1.7, resolve@~1.4.0: 1197 | version "1.4.0" 1198 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" 1199 | dependencies: 1200 | path-parse "^1.0.5" 1201 | 1202 | restore-cursor@^1.0.1: 1203 | version "1.0.1" 1204 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" 1205 | dependencies: 1206 | exit-hook "^1.0.0" 1207 | onetime "^1.0.0" 1208 | 1209 | resumer@~0.0.0: 1210 | version "0.0.0" 1211 | resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" 1212 | dependencies: 1213 | through "~2.3.4" 1214 | 1215 | rimraf@^2.2.8: 1216 | version "2.6.2" 1217 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" 1218 | dependencies: 1219 | glob "^7.0.5" 1220 | 1221 | run-async@^0.1.0: 1222 | version "0.1.0" 1223 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" 1224 | dependencies: 1225 | once "^1.3.0" 1226 | 1227 | run-parallel@^1.1.2: 1228 | version "1.1.6" 1229 | resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039" 1230 | 1231 | rx-lite@^3.1.2: 1232 | version "3.1.2" 1233 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" 1234 | 1235 | safe-buffer@5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1236 | version "5.1.1" 1237 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 1238 | 1239 | semver@5.3.0: 1240 | version "5.3.0" 1241 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 1242 | 1243 | send@0.16.1: 1244 | version "0.16.1" 1245 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" 1246 | dependencies: 1247 | debug "2.6.9" 1248 | depd "~1.1.1" 1249 | destroy "~1.0.4" 1250 | encodeurl "~1.0.1" 1251 | escape-html "~1.0.3" 1252 | etag "~1.8.1" 1253 | fresh "0.5.2" 1254 | http-errors "~1.6.2" 1255 | mime "1.4.1" 1256 | ms "2.0.0" 1257 | on-finished "~2.3.0" 1258 | range-parser "~1.2.0" 1259 | statuses "~1.3.1" 1260 | 1261 | serve-static@1.13.1: 1262 | version "1.13.1" 1263 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719" 1264 | dependencies: 1265 | encodeurl "~1.0.1" 1266 | escape-html "~1.0.3" 1267 | parseurl "~1.3.2" 1268 | send "0.16.1" 1269 | 1270 | setprototypeof@1.0.3: 1271 | version "1.0.3" 1272 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 1273 | 1274 | setprototypeof@1.1.0: 1275 | version "1.1.0" 1276 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 1277 | 1278 | shelljs@^0.7.5: 1279 | version "0.7.8" 1280 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" 1281 | dependencies: 1282 | glob "^7.0.0" 1283 | interpret "^1.0.0" 1284 | rechoir "^0.6.2" 1285 | 1286 | slice-ansi@0.0.4: 1287 | version "0.0.4" 1288 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" 1289 | 1290 | sprintf-js@~1.0.2: 1291 | version "1.0.3" 1292 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1293 | 1294 | standard-engine@~7.0.0: 1295 | version "7.0.0" 1296 | resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-7.0.0.tgz#ebb77b9c8fc2c8165ffa353bd91ba0dff41af690" 1297 | dependencies: 1298 | deglob "^2.1.0" 1299 | get-stdin "^5.0.1" 1300 | minimist "^1.1.0" 1301 | pkg-conf "^2.0.0" 1302 | 1303 | standard@^10.0.3: 1304 | version "10.0.3" 1305 | resolved "https://registry.yarnpkg.com/standard/-/standard-10.0.3.tgz#7869bcbf422bdeeaab689a1ffb1fea9677dd50ea" 1306 | dependencies: 1307 | eslint "~3.19.0" 1308 | eslint-config-standard "10.2.1" 1309 | eslint-config-standard-jsx "4.0.2" 1310 | eslint-plugin-import "~2.2.0" 1311 | eslint-plugin-node "~4.2.2" 1312 | eslint-plugin-promise "~3.5.0" 1313 | eslint-plugin-react "~6.10.0" 1314 | eslint-plugin-standard "~3.0.1" 1315 | standard-engine "~7.0.0" 1316 | 1317 | "statuses@>= 1.3.1 < 2", statuses@~1.3.1: 1318 | version "1.3.1" 1319 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 1320 | 1321 | string-width@^1.0.1: 1322 | version "1.0.2" 1323 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1324 | dependencies: 1325 | code-point-at "^1.0.0" 1326 | is-fullwidth-code-point "^1.0.0" 1327 | strip-ansi "^3.0.0" 1328 | 1329 | string-width@^2.0.0: 1330 | version "2.1.1" 1331 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1332 | dependencies: 1333 | is-fullwidth-code-point "^2.0.0" 1334 | strip-ansi "^4.0.0" 1335 | 1336 | string.prototype.trim@~1.1.2: 1337 | version "1.1.2" 1338 | resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" 1339 | dependencies: 1340 | define-properties "^1.1.2" 1341 | es-abstract "^1.5.0" 1342 | function-bind "^1.0.2" 1343 | 1344 | string_decoder@~1.0.3: 1345 | version "1.0.3" 1346 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" 1347 | dependencies: 1348 | safe-buffer "~5.1.0" 1349 | 1350 | strip-ansi@^3.0.0: 1351 | version "3.0.1" 1352 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1353 | dependencies: 1354 | ansi-regex "^2.0.0" 1355 | 1356 | strip-ansi@^4.0.0: 1357 | version "4.0.0" 1358 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1359 | dependencies: 1360 | ansi-regex "^3.0.0" 1361 | 1362 | strip-bom@^3.0.0: 1363 | version "3.0.0" 1364 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1365 | 1366 | strip-json-comments@~2.0.1: 1367 | version "2.0.1" 1368 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1369 | 1370 | supports-color@^2.0.0: 1371 | version "2.0.0" 1372 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1373 | 1374 | table@^3.7.8: 1375 | version "3.8.3" 1376 | resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" 1377 | dependencies: 1378 | ajv "^4.7.0" 1379 | ajv-keywords "^1.0.0" 1380 | chalk "^1.1.1" 1381 | lodash "^4.0.0" 1382 | slice-ansi "0.0.4" 1383 | string-width "^2.0.0" 1384 | 1385 | tape@^4.8.0: 1386 | version "4.8.0" 1387 | resolved "https://registry.yarnpkg.com/tape/-/tape-4.8.0.tgz#f6a9fec41cc50a1de50fa33603ab580991f6068e" 1388 | dependencies: 1389 | deep-equal "~1.0.1" 1390 | defined "~1.0.0" 1391 | for-each "~0.3.2" 1392 | function-bind "~1.1.0" 1393 | glob "~7.1.2" 1394 | has "~1.0.1" 1395 | inherits "~2.0.3" 1396 | minimist "~1.2.0" 1397 | object-inspect "~1.3.0" 1398 | resolve "~1.4.0" 1399 | resumer "~0.0.0" 1400 | string.prototype.trim "~1.1.2" 1401 | through "~2.3.8" 1402 | 1403 | temp-dir@^1.0.0: 1404 | version "1.0.0" 1405 | resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" 1406 | 1407 | tempy@^0.2.1: 1408 | version "0.2.1" 1409 | resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.2.1.tgz#9038e4dbd1c201b74472214179bc2c6f7776e54c" 1410 | dependencies: 1411 | temp-dir "^1.0.0" 1412 | unique-string "^1.0.0" 1413 | 1414 | text-table@~0.2.0: 1415 | version "0.2.0" 1416 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1417 | 1418 | through@^2.3.6, through@~2.3.4, through@~2.3.8: 1419 | version "2.3.8" 1420 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1421 | 1422 | tryit@^1.0.1: 1423 | version "1.0.3" 1424 | resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" 1425 | 1426 | type-check@~0.3.2: 1427 | version "0.3.2" 1428 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1429 | dependencies: 1430 | prelude-ls "~1.1.2" 1431 | 1432 | type-is@~1.6.15: 1433 | version "1.6.15" 1434 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" 1435 | dependencies: 1436 | media-typer "0.3.0" 1437 | mime-types "~2.1.15" 1438 | 1439 | typedarray@^0.0.6: 1440 | version "0.0.6" 1441 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1442 | 1443 | uniq@^1.0.1: 1444 | version "1.0.1" 1445 | resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" 1446 | 1447 | unique-string@^1.0.0: 1448 | version "1.0.0" 1449 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" 1450 | dependencies: 1451 | crypto-random-string "^1.0.0" 1452 | 1453 | unpipe@1.0.0, unpipe@~1.0.0: 1454 | version "1.0.0" 1455 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1456 | 1457 | user-home@^2.0.0: 1458 | version "2.0.0" 1459 | resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" 1460 | dependencies: 1461 | os-homedir "^1.0.0" 1462 | 1463 | util-deprecate@~1.0.1: 1464 | version "1.0.2" 1465 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1466 | 1467 | utils-merge@1.0.1: 1468 | version "1.0.1" 1469 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1470 | 1471 | vary@^1, vary@~1.1.2: 1472 | version "1.1.2" 1473 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1474 | 1475 | wordwrap@~1.0.0: 1476 | version "1.0.0" 1477 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1478 | 1479 | wrappy@1: 1480 | version "1.0.2" 1481 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1482 | 1483 | write@^0.2.1: 1484 | version "0.2.1" 1485 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" 1486 | dependencies: 1487 | mkdirp "^0.5.1" 1488 | 1489 | xtend@^4.0.0, xtend@^4.0.1: 1490 | version "4.0.1" 1491 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 1492 | --------------------------------------------------------------------------------